17471747 </ ul >
17481748 </ nav >
17491749
1750+ </ li >
1751+
1752+ < li class ="md-nav__item ">
1753+ < a href ="#offline-cumulative-exposure " class ="md-nav__link ">
1754+ < span class ="md-ellipsis ">
1755+
1756+ Offline cumulative exposure
1757+
1758+ </ span >
1759+ </ a >
1760+
1761+ < nav class ="md-nav " aria-label ="Offline cumulative exposure ">
1762+ < ul class ="md-nav__list ">
1763+
1764+ < li class ="md-nav__item ">
1765+ < a href ="#risk " class ="md-nav__link ">
1766+ < span class ="md-ellipsis ">
1767+
1768+ Risk
1769+
1770+ </ span >
1771+ </ a >
1772+
1773+ </ li >
1774+
1775+ < li class ="md-nav__item ">
1776+ < a href ="#mitigation-offlinemaxcumulativepayment " class ="md-nav__link ">
1777+ < span class ="md-ellipsis ">
1778+
1779+ Mitigation: offlineMaxCumulativePayment
1780+
1781+ </ span >
1782+ </ a >
1783+
1784+ </ li >
1785+
1786+ < li class ="md-nav__item ">
1787+ < a href ="#per-verifier-scope " class ="md-nav__link ">
1788+ < span class ="md-ellipsis ">
1789+
1790+ Per-verifier scope
1791+
1792+ </ span >
1793+ </ a >
1794+
1795+ </ li >
1796+
1797+ < li class ="md-nav__item ">
1798+ < a href ="#error-code_2 " class ="md-nav__link ">
1799+ < span class ="md-ellipsis ">
1800+
1801+ Error code
1802+
1803+ </ span >
1804+ </ a >
1805+
1806+ </ li >
1807+
1808+ </ ul >
1809+ </ nav >
1810+
17501811</ li >
17511812
17521813 < li class ="md-nav__item ">
27932854 </ ul >
27942855 </ nav >
27952856
2857+ </ li >
2858+
2859+ < li class ="md-nav__item ">
2860+ < a href ="#offline-cumulative-exposure " class ="md-nav__link ">
2861+ < span class ="md-ellipsis ">
2862+
2863+ Offline cumulative exposure
2864+
2865+ </ span >
2866+ </ a >
2867+
2868+ < nav class ="md-nav " aria-label ="Offline cumulative exposure ">
2869+ < ul class ="md-nav__list ">
2870+
2871+ < li class ="md-nav__item ">
2872+ < a href ="#risk " class ="md-nav__link ">
2873+ < span class ="md-ellipsis ">
2874+
2875+ Risk
2876+
2877+ </ span >
2878+ </ a >
2879+
2880+ </ li >
2881+
2882+ < li class ="md-nav__item ">
2883+ < a href ="#mitigation-offlinemaxcumulativepayment " class ="md-nav__link ">
2884+ < span class ="md-ellipsis ">
2885+
2886+ Mitigation: offlineMaxCumulativePayment
2887+
2888+ </ span >
2889+ </ a >
2890+
2891+ </ li >
2892+
2893+ < li class ="md-nav__item ">
2894+ < a href ="#per-verifier-scope " class ="md-nav__link ">
2895+ < span class ="md-ellipsis ">
2896+
2897+ Per-verifier scope
2898+
2899+ </ span >
2900+ </ a >
2901+
2902+ </ li >
2903+
2904+ < li class ="md-nav__item ">
2905+ < a href ="#error-code_2 " class ="md-nav__link ">
2906+ < span class ="md-ellipsis ">
2907+
2908+ Error code
2909+
2910+ </ span >
2911+ </ a >
2912+
2913+ </ li >
2914+
2915+ </ ul >
2916+ </ nav >
2917+
27962918</ li >
27972919
27982920 < li class ="md-nav__item ">
@@ -3053,14 +3175,26 @@ <h3 id="policygrant-payload">PolicyGrant (payload)</h3>
30533175< td > offlineMaxSinglePayment</ td >
30543176< td > string</ td >
30553177< td > optional</ td >
3056- < td > PA-signed per-transaction cap (in < code > offlineMaxSinglePaymentCurrency</ code > minor units) for offline merchant acceptance. Offline merchants MUST reject SBAs whose < code > maxAmountMinor</ code > exceeds this value. Cumulative budget is not enforced offline .</ td >
3178+ < td > PA-signed per-transaction cap (in < code > offlineMaxSinglePaymentCurrency</ code > minor units) for offline merchant acceptance. Offline merchants MUST reject SBAs whose < code > maxAmountMinor</ code > exceeds this value. Cumulative offline exposure across merchants is only bounded when < code > offlineMaxCumulativePayment </ code > is present; see < strong > Offline cumulative exposure </ strong > below .</ td >
30573179</ tr >
30583180< tr >
30593181< td > offlineMaxSinglePaymentCurrency</ td >
30603182< td > string</ td >
30613183< td > optional</ td >
30623184< td > Currency of < code > offlineMaxSinglePayment</ code > (e.g. < code > "XRP"</ code > ).</ td >
30633185</ tr >
3186+ < tr >
3187+ < td > offlineMaxCumulativePayment</ td >
3188+ < td > string</ td >
3189+ < td > optional</ td >
3190+ < td > PA-signed maximum total amount (in < code > offlineMaxCumulativePaymentCurrency</ code > minor units) that offline verifiers MAY cumulatively accept for this grant across all offline transactions at this verifier. Merchants SHOULD sum accepted amounts per < code > grantId</ code > and reject when the next acceptance would exceed this cap. See < strong > Offline cumulative exposure</ strong > below.</ td >
3191+ </ tr >
3192+ < tr >
3193+ < td > offlineMaxCumulativePaymentCurrency</ td >
3194+ < td > string</ td >
3195+ < td > optional</ td >
3196+ < td > Currency of < code > offlineMaxCumulativePayment</ code > (e.g. < code > "XRP"</ code > ). If absent while < code > offlineMaxCumulativePayment</ code > is present, implementations SHOULD use < code > offlineMaxSinglePaymentCurrency</ code > .</ td >
3197+ </ tr >
30643198</ tbody >
30653199</ table >
30663200< hr />
@@ -3078,6 +3212,10 @@ <h2 id="example">Example</h2>
30783212< span class ="w "> </ span > < span class ="nt "> "destinationAllowlist"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="p "> [</ span > < span class ="s2 "> "rChargingStation1"</ span > < span class ="p "> ,</ span > < span class ="w "> </ span > < span class ="s2 "> "rTollBooth42"</ span > < span class ="p "> ],</ span >
30793213< span class ="w "> </ span > < span class ="nt "> "merchantCredentialIssuer"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="s2 "> "rPAMerchantRegistry"</ span > < span class ="p "> ,</ span >
30803214< span class ="w "> </ span > < span class ="nt "> "merchantCredentialType"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="s2 "> "6D7063703A617070726F7665642D6D65726368616E74"</ span > < span class ="p "> ,</ span >
3215+ < span class ="w "> </ span > < span class ="nt "> "offlineMaxSinglePayment"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="s2 "> "5000000"</ span > < span class ="p "> ,</ span >
3216+ < span class ="w "> </ span > < span class ="nt "> "offlineMaxSinglePaymentCurrency"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="s2 "> "XRP"</ span > < span class ="p "> ,</ span >
3217+ < span class ="w "> </ span > < span class ="nt "> "offlineMaxCumulativePayment"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="s2 "> "15000000"</ span > < span class ="p "> ,</ span >
3218+ < span class ="w "> </ span > < span class ="nt "> "offlineMaxCumulativePaymentCurrency"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="s2 "> "XRP"</ span > < span class ="p "> ,</ span >
30813219< span class ="w "> </ span > < span class ="nt "> "maxSpend"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="p "> {</ span >
30823220< span class ="w "> </ span > < span class ="nt "> "perTxMinor"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="s2 "> "5000"</ span > < span class ="p "> ,</ span >
30833221< span class ="w "> </ span > < span class ="nt "> "perSessionMinor"</ span > < span class ="p "> :</ span > < span class ="w "> </ span > < span class ="s2 "> "20000"</ span >
@@ -3525,6 +3663,43 @@ <h3 id="error-code_1">Error Code</h3>
35253663</ tbody >
35263664</ table >
35273665< hr />
3666+ < h2 id ="offline-cumulative-exposure "> Offline cumulative exposure</ h2 >
3667+ < h3 id ="risk "> Risk</ h3 >
3668+ < p > Without a cumulative offline cap, an agent can present SBAs to many offline merchants in
3669+ sequence. Each merchant enforces only < code > offlineMaxSinglePayment</ code > per transaction. The < strong > total</ strong >
3670+ offline spend can therefore exceed < code > budgetMinor</ code > until the gateway reconciles on-chain.</ p >
3671+ < h3 id ="mitigation-offlinemaxcumulativepayment "> Mitigation: < code > offlineMaxCumulativePayment</ code > </ h3 >
3672+ < p > When the PA includes < code > offlineMaxCumulativePayment</ code > , offline verifiers that enforce this field
3673+ MUST maintain a running total of amounts already accepted for each < code > grantId</ code > (in the grant's
3674+ offline minor units) and MUST reject a new SBA if accepting it would make the cumulative total
3675+ exceed < code > offlineMaxCumulativePayment</ code > .</ p >
3676+ < p > Currency for the cumulative cap is < code > offlineMaxCumulativePaymentCurrency</ code > , or
3677+ < code > offlineMaxSinglePaymentCurrency</ code > if the former is absent.</ p >
3678+ < p > Operators SHOULD set < code > offlineMaxCumulativePayment</ code > ≤ < code > budgetMinor</ code > (or lower, to reflect risk
3679+ tolerance). Operators SHOULD size < code > offlineMaxSinglePayment</ code > with the < strong > expected number of
3680+ offline touchpoints</ strong > per grant in mind — a small per-tx cap with many merchants can still
3681+ produce large aggregate exposure if no cumulative field is used.</ p >
3682+ < h3 id ="per-verifier-scope "> Per-verifier scope</ h3 >
3683+ < p > The cumulative total is tracked < strong > per offline verifier</ strong > (per device). Distinct merchants do
3684+ not share state; a fleet-wide cumulative bound requires synchronized infrastructure outside
3685+ the scope of this specification. The PA SHOULD set < code > offlineMaxCumulativePayment</ code > assuming
3686+ worst-case fan-out across independent verifiers when modeling exposure.</ p >
3687+ < h3 id ="error-code_2 "> Error code</ h3 >
3688+ < table >
3689+ < thead >
3690+ < tr >
3691+ < th > Code</ th >
3692+ < th > Meaning</ th >
3693+ </ tr >
3694+ </ thead >
3695+ < tbody >
3696+ < tr >
3697+ < td > < code > OFFLINE_CUMULATIVE_EXCEEDED</ code > </ td >
3698+ < td > Acceptance would exceed < code > PolicyGrant.offlineMaxCumulativePayment</ code > </ td >
3699+ </ tr >
3700+ </ tbody >
3701+ </ table >
3702+ < hr />
35283703< h2 id ="summary "> Summary</ h2 >
35293704< p > PolicyGrant establishes the < strong > policy boundary</ strong > for machine payments.</ p >
35303705< p > It ensures that downstream SBA artifacts are always derived from a < strong > validated policy evaluation</ strong > .</ p >
0 commit comments