POST
Draft the policy document

Authorizations

Authorization
string
header
required

An API key minted in the console (ctd_…). Authenticates; never authorizes funds. A key carries scopes (read, wallets.write, transactions.write, events.write, webhooks.write, policy.write) and may be limited to vaults, to IP addresses, and in lifetime — see Authentication.

Body

application/json

The whole policy document, less what Citadel stamps (version, each chain's chain_module_version).

chains
object
required

The address-bound rules of each chain you use, keyed by chain: tron, evm, solana, ton.

ceiling
object
required

The most one transaction may move, per asset key (SYMBOL/decimals), in base units. An asset with no ceiling cannot be sent.

references
object
required

Limits per end_user_ref, each one listed by name — never matched by a pattern. {} for none. Payouts to your whitelist go without a request signature, so your engine counts them all under the reserved reference system:whitelisted, not under their end_user_ref: limit them there. With allow_unregistered_reference off, list it, or those payouts are refused.

allow_unregistered_reference
boolean
default:false

Accept an end_user_ref that references does not list. Leave it off when you set per-reference limits.

Response

These rules already wait for approval — the change that carries them. Nothing to sign.

version
integer
required
status
enum<string>
required

draft — to sign and publish; pending — signed, waits for approval; published — sent to your engine; rejected — never sent.

Available options:
draft,
pending,
published,
rejected
document
string
required

The YAML document: the exact bytes your policy key signs.

key_id
string | null
required

The policy key that signed. null for a draft.

signature
string | null
required

Your policy key's signature over document, in standard base64. null for a draft.

approval
null | object
required

The approval a change published through the API waits for, or waited for. null for a draft, and for a version published in the console.

rejected_reason
enum<string> | null
required

Why a rejected change was never sent: an approver declined it, it was not approved in time, or a newer change replaced it or a newer version came into force first.

Available options:
approval_rejected,
approval_expired,
superseded,
null
created_at
string<date-time>
required
updated_at
string<date-time>
required