Skip to main content

Diagram

A request that is refused before it is created never enters this machine and locks nothing: it gets a 4xx error, or a 201 body with status: "rejected" and a code (compliance refusal, for example wallet_banned or aml_blocked), or status: "REJECTED" with an empty id and the reason in reason (for example insufficient balance).

States

The status enum also contains REVERTED. No current transition produces it; if you see it, treat it as terminal and refunded.

Cancellation rules

Users can cancel while status is PENDING, MLRO_REVIEW, or CO_SIGNED:
Cancel needs vault:write even though POST /api/withdrawals/request also accepts the narrower withdraw:write. A key you create in your account settings with the Withdraw permission carries only withdraw:write, so it can request a withdrawal but cannot cancel one. After SUBMITTED the tx is already in the mempool — cancel is not possible. Response (409, standard error envelope):

Audit trail

Every status transition is recorded in an append-only event log. GET /api/me/withdrawals/{id}/events (portfolio:read) returns it, oldest first:
kind is one of created, auto_approved, flagged_for_review:<reason>, mlro_approved, mlro_rejected, broadcast, rebroadcast:… / rebroadcast_unstamped:… (status unchanged, another txHash for the same withdrawal), confirmed, cancelled, expired:<reason>, broadcast_failed:<error>, broadcast_blocked:<reason>. Match on the part before the first :. actor is the user’s wallet (lowercase) for created and cancelled, system for automatic transitions, mlro:<reviewer> for compliance decisions, or chain for the on-chain confirmation that flips SUBMITTED → CONFIRMED. Use this endpoint for any compliance audit trail — GET /api/me/withdrawals/{id} only returns the head state.