Skip to content
PricingDocsKO

Intents and mandates

An intent is the JSON a service hands to the wallet: the calls to run now, what they spend, and the mandate they run under. The user approves the mandate once. Later intents and merchant charges inside it run without a prompt. The structure follows AP2 intents and mandates.

action Mandate Example
purchase One run. Item and price pinned with eq. No later charges One cinema ticket
mandate Many runs. Per-run, total, runs, validity, period limits Subscriptions, reservations, metered search, savings
mandate.update Raises limits, runs or days of the same mandate. Scope unchanged Renewing a subscription
{
"type": "agentpay.intent",
"version": 1,
"id": "int_8cVd0Hq3pTzR1b2N",
"service": "acme-news",
"action": "mandate",
"summary": "Monthly plan 9,900 KRW, up to 12 months",
"spend_okrw": 9900,
"prefund_okrw": 9900,
"expires_at": 1792051200,
"calls": [
{ "target": "0x…token", "value": "0", "data": "0x095ea7b3…" },
{ "target": "0x…merchant", "value": "0", "data": "0x…" }
],
"mandate": {
"key": "acme-news:plan",
"label": "Acme News monthly",
"total_okrw": 118800,
"per_okrw": 9900,
"approve_cap_okrw": 9900,
"calls": 12,
"days": 360,
"merchant_charges": true,
"period": { "seconds": 2592000, "max_runs": 1 },
"permissions": [{
"target": "0x…merchant",
"signature": "pay(bytes32,uint256,uint256)",
"predicates": [{ "arg": 1, "op": "eq", "uint": "2" }, { "arg": 2, "op": "lte", "okrw": 9900 }]
}]
}
}
Field Type Rule
type, version "agentpay.intent", 1 Fixed
id int_ + 8 to 64 chars Set by the kit
service Service id Must match the service of the origin it was fetched from
summary String Up to 160 chars. Shown on approval and in history
spend_okrw Integer What the calls spend now. At most per_okrw
prefund_okrw Integer, optional Balance the wallet should hold for this mandate (top-up hint)
expires_at Unix seconds Within one hour. The kit uses 15 minutes
calls 0 to 8 { target, value: "0", data }. All must fit the mandate

Amounts (*_okrw) are whole payment-token units; the wallet scales them by the token decimals.

Field Default Rule
key Starts with <service id>:. A live mandate with the same key is reused
label Up to 80 chars. The approval title
total_okrw, per_okrw Total and per-run limit. per_okrw ≤ total_okrw
approve_cap_okrw Most one payment-token approve may allow. At most total_okrw
calls 100 Runs, 1 to 1000
days 30 Validity, 1 to 365 days
valid_after Approval time Start time (reservations). At most 300 days ahead
merchant_charges false The service may charge later. Only for services allowed in the registry
period None { seconds, max_runs?, max_spend_okrw? }. Fixed windows from validAfter
permissions 1 to 16. Only functions on the service’s own registered contracts

permissions[].predicates constrain one 32-byte argument word each, up to 4 per permission.

Field Meaning
arg Zero-based argument index
op eq or lte
One value okrw (token units, scaled by decimals), uint, bytes32 or address

A purchase must pin its item with at least one eq predicate.

{ "action": "mandate.update", "spend_okrw": 0, "calls": [],
"mandate": { "key": "acme-news:plan" },
"update": { "add_total_okrw": 29700, "add_calls": 3, "add_days": 90 } }

No calls run during this update. add_total_okrw, add_calls and add_days increase the corresponding limits; optional per_okrw raises the per-run limit. Target contracts, functions, argument predicates and period limits do not change, and the current period usage is not reset. A different scope or period needs a new mandate. The user reviews and approves changes with change_mandate.

A payment with no user present. The service sends POST /merchant/charges to the gateway.

{ "mandate_id": "mnd_…", "charge_id": "sub_123-w1", "summary": "Monthly plan, month 2",
"spend_okrw": 9900, "calls": [ … ] }
Authorization: AgentPay-Mandate-HMAC id=mcr_…,ts=1792051200,sig=…

The signature is HMAC-SHA256 over METHOD\npath\nts\nsha256(body), and the request timestamp may differ from the verification time by at most 300 seconds (five minutes) in either direction. kit.merchant.charge does this for you.

Code Meaning
INTENT_SERVICE_MISMATCH The intent’s service differs from the origin’s service
CONTRACT_NOT_REGISTERED A permission targets a contract not registered to the service
INTENT_CALL_OUTSIDE_MANDATE A call to run now is outside the mandate
MERCHANT_CHARGES_NOT_ALLOWED The service may not charge later
INTENT_EXPIRED Expired, or set to live longer than an hour
OUTSIDE_MANDATE, OVER_LIMIT, PERIOD_LIMIT A charge exceeds the scope, limits or window
MANDATE_REVOKED, MANDATE_RELEASED, MANDATE_EXPIRED The mandate is off or over
CHARGE_ID_REUSED The same charge_id was sent with different content