Skip to content

docs(schema): state the currency unit for payment.budget.max - #340

Open
CODER7657 wants to merge 3 commits into
google-agentic-commerce:mainfrom
CODER7657:docs/clarify-budget-max-unit
Open

docs(schema): state the currency unit for payment.budget.max#340
CODER7657 wants to merge 3 commits into
google-agentic-commerce:mainfrom
CODER7657:docs/clarify-budget-max-unit

Conversation

@CODER7657

Copy link
Copy Markdown

Clarifies the currency unit for payment.budget.max. One-line description change, no behaviour change.

Fixes half of #339.

Why

payment.budget.max and payment.amount_range.max both bound a payment amount, in the same module, and interpret max in different units — but only one of them says so.

payment.amount_range.max is documented as:

"Maximum allowed amount in minor (cents) unit of currency."

and AmountRangeEvaluator compares directly, which is correct:

and amount.amount > self.constraint.max

payment.budget.max is documented as:

"Maximum amount for the budget."

with no unit stated. BudgetEvaluator multiplies by 100:

budget_max_cents = int(self.constraint.max * 100)
if total_spend > budget_max_cents:

So budget.max is in the major unit while its sibling is in the minor unit, and the only place that's discoverable today is the evaluator source.

Impact of the ambiguity

An issuer populating budget.max in minor units — consistent with amount_range.max, and with Amount.amount — gets a cap 100x larger than intended. A 5,000 rupee cap silently becomes 500,000.

The failure is quiet: BudgetEvaluator runs, returns no violation, and the transaction is authorised. Nothing indicates the ceiling was read differently from how it was written.

I hit this myself on first integration, using the schema descriptions as the guide. I set Budget(max=5000.0) against a charge of 47500 paise and expected a violation. There is none, because the effective ceiling is 500000 paise.

What this PR does

Adds the unit to the description, and points at the difference so the next person doesn't have to read the evaluator to find it:

"max": {
  "type": "number",
  "description": "Maximum amount for the budget, in the MAJOR unit of the currency (e.g. 5000.0 means 5000 rupees, not 5000 paise). Note this differs from payment.amount_range.max, which is expressed in the minor unit."
}

What this PR deliberately does not do

  • No behaviour change. BudgetEvaluator is untouched. The * 100 stays.
  • No regeneration of generated/open_payment_mandate.py. That file is derived from this schema and I did not want to hand-edit generated output or guess at your codegen invocation. Happy to add it if you tell me the command, or to leave it to your next regeneration.
  • No unit alignment. Making both constraints use minor units would be tidier, but it is a breaking change for anyone already populating budget.max correctly, and that call is yours rather than mine.

CLA signed.

budget.max is interpreted in MAJOR units - BudgetEvaluator computes
int(constraint.max * 100) - while its sibling payment.amount_range.max is
documented as minor units and compared directly. Only one of the two says
which unit it expects.

An issuer populating budget.max in minor units, consistent with
amount_range.max and with Amount.amount, gets a cap 100x larger than
intended, and enforcement appears to work: the evaluator runs and returns
no violation.

Refs google-agentic-commerce#339
@CODER7657
CODER7657 requested a review from a team as a code owner August 23, 2026 14:12
Drops the INR-specific example. AP2 is not India-specific, and 'paise'
is not in the project's cspell dictionary.
PISP (Payment Initiation Service Provider) already appears nine times in
open_payment_mandate.json on main. The spellcheck job only scans changed
files, so any PR touching that schema fails on words it did not
introduce. Adding them unblocks the check.

Refs google-agentic-commerce#339
@CODER7657

Copy link
Copy Markdown
Author

Two follow-up commits since opening, and a note on CI:

1. Currency-neutral wording. My first draft used an INR example ("5000 rupees, not 5000 paise"). paise is not in the project's cspell dictionary, and AP2 is not India-specific, so the description now reads:

"Maximum amount for the budget, expressed in the MAJOR unit of the currency (e.g. 50.00 means 50 units of currency, not 50 cents). Note this differs from payment.amount_range.max, which is expressed in the minor unit."

2. pisp / pisps added to .cspell/custom-words.txt. These are not words I introduced — PISP (Payment Initiation Service Provider) already appears nine times in open_payment_mandate.json on main. The spellcheck job scans changed files, so any PR touching that schema fails on pre-existing vocabulary. Two dictionary entries unblock it. Happy to drop this commit if you would rather handle it separately.

spellcheck and cla/google now pass.

On Lint Code Base: it fails here, but it also fails on every other open PR in this repo (fix/receipt-rail-verification, feat/typescript-sdk-mandates, feature/typescript-integration) and on the most recent main run. The failure is BIOME_LINT reporting 75 errors with HTML parse messages, across files this PR does not touch. I do not think it is related to this change, and I have deliberately not tried to fix it from inside a documentation PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant