Yanez Agent Authorization

Terms

terms is the object the human approves and the relying party enforces. The server validates its shape on create and answers 422 when a field is missing, blank, or the wrong type. Every field is also a promise to the approver, because the YID app renders them on the approval screen — and now because the approver’s own key signs it. See user-signed approvals.

Required string fields must hold at least one non-whitespace character. The whole object is capped at 4 KB of compact JSON, and the server answers 413 above that.

Field Required Type Meaning
schema_version yes integer Exactly 1. An absent, non-integer, or different value is a 422
action yes string What kind of action this is, such as purchase. Keep it short, lowercase, and identical across identical operations so a relying party can branch on it
approval_title yes string The headline the YID app shows the approver. Name the action, not your product
summary yes string One sentence stating the whole action, including the amount when one exists
merchant yes string The seller, counterparty, or service name the approver recognizes
details yes array The rows the app renders as a table, described below
currency no string ISO 4217 alpha-3 code from the server’s configured allowlist. Required whenever amount is present
amount no object What gets charged. Omit for non-financial actions

For an action such as signing a document, granting access, or publishing content, omit both amount and currency. YanezYID then omits the Amount row entirely. Do not send a zero-dollar placeholder.

Extra keys are allowed at every level. Domain fields the relying party matches on, such as an item id, a resource id, or a scope list, go alongside the required ones; the server stores them untouched, the approver’s signature covers them, and they are compared with everything else at enforcement time. Any number among them is subject to the same integer rule and the same bound as minor_units. details is for what the human reads, extra keys are for what the executor checks.

amount

amount is optional. When it is present, top-level currency is required and must match amount.currency.

Field Type Meaning
minor_units integer The amount as a whole number of the currency’s minor unit, which is the smallest denomination the currency charges in. Under USD the minor unit is the cent, so 18000 is $180.00. Under a zero-decimal currency such as JPY the minor unit is the yen, so 18000 is ¥18,000. Must be a non-negative integer no greater than 9007199254740991, which is 2^53 - 1. Never a float and never a decimal string
currency string Must equal the top-level currency exactly

display was removed. The app formats the amount itself, from minor_units and the currency’s own exponent. Two fields describing one amount can disagree, and the one the human read was the one that could lie — the server had no way to tell you. Send the number; let the app render it.

The 2^53 - 1 bound is the largest integer a double round-trips exactly, so a JavaScript verifier and a Python one cannot disagree about the value they are comparing. The same bound applies to every number anywhere in terms, and every one of them must be an integer.

details

Each entry requires label and value as non-blank strings. emphasized is optional; set it to true to render a row with visual emphasis, or omit it for standard emphasis. When supplied, it must be a boolean. The app renders the entries as a two-column table in array order, so the array order is the reading order. The app doesn’t sort, merge, or drop rows.

The array can be empty, but give it rows. The table is where the approver checks the specifics of what they’re agreeing to, and a screen carrying only a title and a summary leaves them less to check.

agent_name

agent_name names the agent doing the asking, and the YID app shows it on the approval screen:

{"agent_name": "Shopping agent"}

Omit it, or send null, and the app falls back to the label on the agent key. A blank string is a 422 rather than a fallback, because the app reads null as “use the key’s label” and a blank string as “show nothing”, so the server refuses the one that renders an empty name. Any non-string value is a 422 as well.

Financial example

{
  "schema_version": 1,
  "action": "purchase",
  "approval_title": "Purchase running shoes",
  "summary": "Buy running shoes for $180.00 at Example Store",
  "merchant": "Example Store",
  "currency": "USD",
  "amount": {"minor_units": 18000, "currency": "USD"},
  "details": [
    {"label": "Merchant", "value": "Example Store", "emphasized": false},
    {"label": "Item", "value": "Running shoes, model X, size 10", "emphasized": false},
    {"label": "Amount", "value": "$180.00", "emphasized": true}
  ]
}

Non-financial example

Omit amount, currency, and unnecessary presentation hints for an action with no monetary component:

{
  "schema_version": 1,
  "action": "document.signature.authorize",
  "approval_title": "Sign mutual NDA",
  "summary": "Authorize your signature on the mutual NDA with Yanez Pulse.",
  "merchant": "Documenso",
  "details": [
    {"label": "Document", "value": "Mutual Non-Disclosure Agreement"},
    {"label": "Counterparty", "value": "Yanez Pulse"},
    {"label": "Signing as", "value": "Yanez AI"},
    {"label": "Agreement ID", "value": "NDA-2026-0914"},
    {"label": "Governing law", "value": "California"}
  ]
}

terms travels in the create body next to decision_window_seconds, which is how long the approver has to answer and is not part of the terms: HTTP quickstart.

Profiles per action type (purchase, disclosure, permission): terms guidance.

Terms are compared whole

Every field travels into the receipt as yanez_terms, and the same object travels inside the bytes the approver signed. Both are compared structurally at enforcement time. Re-titling an approval screen produces terms that no longer match what the action executor expects, so build the object once and hand the same object to both the create call and the executor: receipts.

“Structurally” has precise rules — a boolean is never a number, -0 equals 0, and array order matters. Use the SDK’s terms_equal / termsEqual rather than a stock deep -equality helper, which will disagree with the other language on at least one of those: comparing terms.

If any material field changes after approval — counterparty, resource, amount, currency, destination, scope, deadline — the old receipt must not be used. New terms mean a new authorization request.