POST
Send a transaction

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.

Headers

Idempotency-Key
string

Makes a retry safe. The same key with the same body returns the first result; with a different body (on /events/{name}: other inputs or another network), 409 idempotency_conflict. Also accepted as idempotency_key in the body. Without one, POST /transactions answers with an idempotency_key of its own, intent:<uuid>.

Maximum string length: 255
X-Citadel-Request-Signature
string<byte>

Your key-A Ed25519 signature over the canonical request (see Authentication): the 64 signature bytes in standard, padded base64 (88 characters). Stored with the operation and verified by your own policy engine before anything is signed. A value that is not base64 of 64 bytes (hex, for one) is refused with 422 invalid_request_signature. A signed request names wallet by id or address; by reference it is refused with 422.

Required string length: 88

Body

application/json
wallet
string
required

Wallet id, reference, or address on network; a wallet id must live on network. A signed request (X-Citadel-Request-Signature) names it by id or address only.

network
enum<string>
required

The network the data lives on. Required wherever it appears in a request — there is no default network. One your installation does not serve: 422 network_not_served.

Available options:
mainnet,
testnet
actions
(transfer · object | approve · object | swap · object | call · object)[]
required
Minimum array length: 1
end_user_ref
string

The user the payout is for; policy limits count per user.

idempotency_key
string

Same as the Idempotency-Key header.

queue
boolean
default:false

true records the payout for a workflow to send later in a batch, instead of sending it now. Exactly one transfer action.

At the door nothing is reserved, no network fee is estimated, and your approval rules are not asked. The funds stay spendable until a workflow's batch payout picks the payout up by its tags and reserves them for the batch. The answer is 202 with status: created and queued: true.

Once a batch carries it, the transaction reads final when the batch landed and failed when it did not. It has no tx_hash of its own, and these changes come without operation.* webhooks: read them with GET /transactions/{id}. Until a batch carries it, POST /transactions/{id}/cancel withdraws it, with operation.failed.

tags
string[]

Selects a queued payout in a workflow.

Response

Accepted. Status moves on asynchronously.

A transaction. A field with nothing to say is absent, except actions and tags.

operation_id
string<uuid>
required
status
enum<string>
required
Available options:
created,
aml_pending,
awaiting_approval,
authorized,
signing,
signed,
broadcasting,
broadcast,
confirmed,
final,
failed,
rejected,
expired
actions
object[]
required

What it does, in order — the actions you sent, each asset named as balances name it.

tags
string[]
required
created_at
string<date-time>
required

When Citadel accepted it.

updated_at
string<date-time>
required

Its last change of state.

network
enum<string>

The network the data lives on. Required wherever it appears in a request — there is no default network. One your installation does not serve: 422 network_not_served.

Available options:
mainnet,
testnet
chain
enum<string>
Available options:
tron,
evm,
solana,
ton
wallet
object

The wallet it leaves from.

end_user_ref
string
tx_hash
string

Known from broadcasting on.

fee
object

The network fee the landed transaction cost, in the native coin of the chain it landed on. Absent until it lands.

idempotency_key
string

The key the request was sent with. A request sent without one gets intent:<uuid>, unique to this transaction; GET /transactions/{id} takes it too.

queued
boolean

true while a queued payout (queue: true) waits for its workflow; absent otherwise.

failure
object
corrected
object

The transaction was declared expired, then landed after all (the chain index served it late). The earlier verdict is withdrawn — if you resubmitted on it, that payout is a second one.

stuck
object

An EVM transaction waits behind its nonce: no node has taken its signed bytes for 5 minutes (the operation.stuck webhook). It keeps its holds and is sent again and again, and new transactions from the wallet are refused until it moves. Absent once a node takes it. POST /transactions/{id}/speedup signs it again at a higher fee.

speedup
object

The latest POST /transactions/{id}/speedup of this transaction, and what came of it.

approval
object

Present when your approval rules held the transaction for a passkey quorum — on the 202 and on every read after it. Absent when it went out without waiting for people.