Register the client's agentic policy (ALPHA)
Alpha — early access.
Registers (or fully replaces) this client’s client_policy — the ONLY way to set one. A client declares its vocabulary once, and every drafting turn and every accept then resolve it from here.
Registration is deliberately the only path. The policy was once also accepted in the POST /payment-agents/{payment_agent_id}/proposals and POST /instructions bodies, and that made a two-call conversation able to disagree with itself: a proposal drafted under one policy and accepted without it is judged by different rules, so a legal draft was refused at the customer’s approval click. A policy is a property of the CLIENT, not of a request, and it now lives in exactly one place.
A full replace, not a merge: send the whole policy every time. Changing one takes effect on the next turn — there is no cache — so this is also how you TEST a policy. Register, run a conversation, register something else. Validation happens HERE: an unknown key, an unknown value, or a label for a concept the server does not implement is a 400 at registration, not a surprise on a customer’s first conversation.
FULL REPLACE, not a merge: the registration IS the client’s declared vocabulary, so an omitted field means the client no longer wants it. An empty body ({}) therefore clears the registration back to platform defaults.
Authorizations
Headers
Unique key to ensure request idempotency. If the same key is used within a certain time window, the original response will be returned instead of executing the request again.
Body
ALPHA — how THIS client's product speaks, and what the agent may propose for it. It reshapes what the drafting model SEES (tool results, tool descriptions, prompt sections) and constrains what it may PROPOSE, so the agent narrates in the client's own nouns instead of platform ones.
SCOPE: this is a per-CLIENT policy — it belongs to the client_id behind the API key, never to a key (api keys are N:1 to clients, so a per-key policy would fragment for a client running one service key per deployment). REGISTER IT at PUT /agentic-policy, which resolves the client from the API key: there is no id to pass and no other client's policy to address.
DELIVERY: registration only. A request body never carries this object — a conversation is two calls (draft, then accept) judged independently, and a per-request policy let them disagree, so a draft that was legal under one could be refused at the customer's approval click.
STRICT: an unknown key, an unknown value, or a label for a concept the server does not implement is a 400 — "accepted" always means "enforced". Absent (or every field empty) ⇒ platform defaults, byte-for-byte the behaviour of a request that never mentioned it.
How payees are shaped in tool results. nested (the default, and what an absent policy means) returns ONE payee carrying N payout methods. flat returns one entry PER payout method — a payee is a name plus one way of being paid — each with payee_ref (the id to pass straight through wherever a payout method is referenced), entity_ref (the person behind the entry; several entries can share one, and it is what binds a new payout method to an existing person instead of duplicating them), name, and paid_by (a rendered human phrase such as bank account at Chase ****4321 or base-sepolia 0x1234…cdef). A payout method never pins an asset, so paid_by never names one.
, nested, flat "flat"
The assets a PAYEE may receive — what a conversion may output, and what a direct payment may send. Absent or empty means unrestricted, which is the platform default.
State it when your product's FUNDING asset is not something a payee is ever paid in. Platform's asset registry only knows which assets settle on which chain, so it cannot tell that your funding stablecoin is a category error as a payout — it will happily draft one if a customer names it, and because that route needs no conversion account it also creates a duplicate payee for someone already saved. Declaring the allowlist turns both into a refusal the model sees before the customer does.
Case-insensitive and de-duplicated; the order you send is the order quoted back to the customer.
Platform concept → the noun THIS client's customers use for it. The noun replaces the platform word in the tool results the agent reads AND in what it writes to the customer. Implemented concepts: limit (the spending limit; platform calls it a mandate), payee (the person being paid), and limit_unit (the UNIT the limit's amounts are quoted in, e.g. USD). Any other key is a 400 — a label for a concept the server does not implement would be accepted and then ignored.
limit and payee are nouns and must match ^[a-z][a-z0-9 _-]{0,30}$. limit_unit is a unit code and must match ^[A-Za-z][A-Za-z0-9]{0,9}$, so it may be uppercase. Never a phrase, never a sentence.
limit_unit matters most under a payout_route that forces a conversion account: the limit governs the DEPOSIT leg, so its own asset is the funding asset the customer has never heard of. With the unit set the agent quotes the caps and remaining budget in it ("your spending limit is 10 USD per month, 0.98 left") instead of reaching for the funding asset.
Labelling payee also renames the flat view's keys: the container becomes the label plus s and each entry's ref becomes the label plus _ref — so {"payee": "recipient"} yields recipients[] with recipient_ref. entity_ref is NOT renamed; it is an opaque handle to the person behind the entry, not the labelled concept. The plural is a literal +s (the charset restricts labels to simple lowercase nouns), so an irregular noun gets an odd but harmless plural.
external_only: spending limits live entirely OUTSIDE this conversation — the client creates and amends them in its own limit editor through the customer-signed amend API. The agent never drafts one; a drafted payment must fit an existing active limit's remaining budget, and when nothing covers it the agent says so and points the customer at the app instead of proposing a limit. Absent ⇒ the agent drafts limits as usual.
, external_only "external_only"
Restricts how the money may leave. conversion_account_only: every scheduled payment must fund a conversion account — no direct wallet-to-address send. bank_only: on top of that the payout must land in a bank account — an outbound bank rail is required and no crypto payout method may be created. Absent ⇒ any supported route.
Either value also makes the FUNDING leg system-chosen, which changes two things. The payment has two legs and the customer only names one: what they ask for is what ARRIVES (the conversion's output), while what LEAVES the wallet is the conversion deposit. The spending limit governs the DEPOSIT leg, so (a) the asset or chain the customer names can never put a payment outside the limit — coverage is judged on the per-payment cap and the remaining budget alone — and (b) the deposit's asset and network move out of the limit's rule into a funding_leg_internal block in the active_mandates result, which the agent copies into the conversion account and never says out loud. Pair this with labels.limit_unit so the agent has a unit to quote the limit in.
, conversion_account_only, bank_only "conversion_account_only"
Response
The registered policy, normalized as it will be applied.
A client's registered client_policy (ALPHA) with its registration timestamps.
policy is the NORMALIZED form — what the server will actually apply, not an echo of what was sent. Values that mean "the default" are normalized away (payee_model: nested becomes absent, because an explicit nested and an absent policy have to be the same value rather than two values that merely behave alike today).
ALPHA — how THIS client's product speaks, and what the agent may propose for it. It reshapes what the drafting model SEES (tool results, tool descriptions, prompt sections) and constrains what it may PROPOSE, so the agent narrates in the client's own nouns instead of platform ones.
SCOPE: this is a per-CLIENT policy — it belongs to the client_id behind the API key, never to a key (api keys are N:1 to clients, so a per-key policy would fragment for a client running one service key per deployment). REGISTER IT at PUT /agentic-policy, which resolves the client from the API key: there is no id to pass and no other client's policy to address.
DELIVERY: registration only. A request body never carries this object — a conversation is two calls (draft, then accept) judged independently, and a per-request policy let them disagree, so a draft that was legal under one could be refused at the customer's approval click.
STRICT: an unknown key, an unknown value, or a label for a concept the server does not implement is a 400 — "accepted" always means "enforced". Absent (or every field empty) ⇒ platform defaults, byte-for-byte the behaviour of a request that never mentioned it.
Unix time this client first registered a policy.
Unix time the registration was last replaced.

