The approval decides on one prepared payload, and the signature that follows covers that payload and nothing else.
One approval covers one prepared payload. Where the platform broadcasts, it compares the signed bytes with the prepared request on six fields and stops the transaction on any difference. Where the provider broadcasts, the provider's own policy is the only check.
With a custody provider, a hardware module or a wallet contract, the key holder enforces the decision and does not sign what the policy has not cleared. The platform enforces the wallet checker, and the platform key store has no external policy.
A waiting transaction is a visible state that ends approved, declined, expired or cancelled.
Why a signature needs a decision first
Custody Approval lets you require a decision from your own named approvers before a key signs a payload. That decision belongs to people your organisation chose, under a policy your organisation set. The decision comes from the approval policy held by the custody provider, the hardware module or the wallet contract, plus the platform's own wallet checker. The Approvals settings in General are maker-checker, a separate control.
Banks already run this maker-checker discipline, the rule that the person who prepares a payment cannot be the one who authorises it, over payment instructions. Custody Approval moves the same discipline onto the step where a private key turns an instruction into an irreversible on-chain transfer. A conventional payment can sometimes be reversed after it leaves the bank. A signed on-chain transfer cannot: once it is broadcast, nothing undoes it.
The platform sits on the requesting side. It resolves the sender, builds the call, and asks the key holder to sign. The approval policy lives with the party that holds the key: a custody provider, a hardware security module in your own data centre, or the wallet contract itself on chain. With an external custody provider or a hardware security module, the platform never holds the key material and cannot obtain a signature that the policy has not cleared. With the platform key store, the platform holds the key and signs itself, so no external policy applies.
The record shows who prepared the instruction, who cleared it and when.
What an approval authorises and what it does not
An approval policy requires a decision beyond the instruction itself. A request subject to that policy waits for the configured approvers before signing can proceed. Role permissions still govern who may submit the request.
The approval is bounded in two ways. It authorises one prepared payload and grants no ongoing permission to move assets. It is also not a settlement guarantee: the signed transaction still has to reach the chain and still has to satisfy the asset's own transfer restrictions, a separate control described under Transfer-Path Compliance.
Working a pending approval
A transaction that meets an approval rule stops in a pending-approval state and moves nowhere until someone decides. It appears in Actions for the participant whose wallet sent it, the investor or organisation account, with the operation it is waiting to perform. The platform records the pending state. A multi-signature approval can already contain signatures while it waits for the remaining weight.
Where the decision is taken depends on the wallet. On a platform multi-signature wallet, the approval is a record you work inside the platform. It shows the weight required, the weight collected and every signature so far, and each signer co-signs from the pending item. Each signer holds a weight, a share of signing authority counted toward the wallet's threshold. On a wallet held at a custody provider or inside a hardware security module, the platform shows the transaction as waiting, with the approvals the provider has counted against the number it needs when the provider reports them, and the decision belongs to the provider's own console, approval app, or hardware quorum ceremony.
The platform adds one approval of its own, the wallet checker. The owner of a key wallet that the platform signs for names one other member of the organisation as the wallet's checker. Every transaction from that wallet then waits in the checker's Actions list until the checker approves or rejects it there. A transaction the checker starts from that wallet fails at once, because the checker cannot approve their own transaction. A rejection fails the transaction, and a checker who does not decide within the approval window lets it expire. A wallet checker is optional on every wallet. The wallet's owner names, replaces or removes the checker alone, and removing the checker cancels every transaction waiting for that checker. Treat the checker as a control the owner can switch off, and pair it with a provider policy where the owner must not be able to remove it. If the checker leaves the organisation, the wallet refuses every transaction until its owner removes the checker or names a new one, and an account that is still a wallet's checker cannot be deleted.
Your approvers do not read raw transaction bytes. Where the provider supports it, the approval screen names the operation and its arguments, decoded from the same prepared call the approver is authorising. It therefore cannot describe something the payload does not do, and an undecodable call falls back to the contract and the function selector.
Do not resubmit the instruction while it waits. The platform is holding that wallet's next sequence number for the payload under review, so a second submission could queue a second movement of assets instead of hurrying the first. Follow the original operation's status or let the platform's own recovery resume it. Repeat an API request only when its route documents replay safety.
A pending approval ends in one of four ways:
- Approved: the key holder releases the signature.
- Declined: the platform records a failure with a rejected-signature reason.
- Expired: nobody decides in time, and the platform records a failure with an expired-approval reason.
- Cancelled: the platform withdraws the request at the provider first, and the transaction moves to cancelled only after the provider confirms the withdrawal.
When the provider cannot withdraw requests, does not confirm the withdrawal, or the request has already ended, the cancel is refused with 409 TRANSACTION_, code DALP-14035, and the approval stays pending until an approver decides in the provider's own console or the deadline passes. A decline or a lapse is a final outcome. Nothing reopens a declined, expired, or cancelled approval, so prepare and submit a fresh instruction if the movement is still needed.
Cancelling a transaction that was already broadcast works differently. The platform signs a zero-value replacement at the same sequence number. A cancel cannot wait for an approver. When a policy holds that replacement for approval, the platform withdraws the held request, and the cancel answers with the same TRANSACTION_ refusal. Such a cancel succeeds only when the provider's policy lets the replacement sign without approval. Each new attempt files its own request. When the provider cannot withdraw requests, the approver rejects the held replacement in the provider's approval console.
A prepared transaction either signs directly or waits for a decision, and approved work continues to broadcast while a decline, lapse or withdrawal ends it.
Allow for the wait in your design. Another write from the same wallet cannot take that wallet's sequence number while an approval is pending, so it waits behind the held transaction. A slow approver therefore delays that wallet's other work. Route routine high-volume work and approval-bearing work through different wallets when both have to keep moving.
What this approval covers
Custody Approval is a gate on signature release, and the platform sits on the requesting side of it. The platform resolves the sender, builds the call, reserves the sequence number, simulates the asset's compliance rules, and then asks the key holder to sign. An external custody policy decides provider-side approvals. A weighted wallet enforces its own signature threshold. Platform-managed signing has no external approval policy, as Does the platform hold the keys? explains.
Two approval planes exist, and neither substitutes for the other. The custody-provider plane gates one external signature: the provider's policy engine or the hardware module's quorum holds the key operation until a rule, an approver, or a quorum of key custodians clears it. On the multi-signature wallet plane the approval is the signature, because several signers each contribute weight to one operation. The threshold is enforced by the wallet contract itself, for operations validated by the weighted validator. It validates the collected weight when the operation reaches the chain and rejects an operation whose weight falls short, so the platform holding submission is a convenience and the wallet contract is the control. Check the wallet's other installed validators, as Maker-checker explains. The contract counts weight per key, not per person. In managed mode the platform signs for each custodied signer the caller controls, so check that no one person controls signers whose weights reach the threshold.
A provider hold does not clear through the wallet's approval calls, and a wallet threshold does not stand in for provider policy. Use that split to place a new rule. One that is naturally a threshold over the platform's own signers belongs on the wallet plane, where the contract enforces it on chain. One that needs a named individual, an external amount or destination check, or a hardware quorum belongs on the provider plane, where its policy engine or the module enforces it.
The split, plane by plane:
An approval binds to one payload, and the platform checks that binding instead of trusting it. Where the provider signs but the platform broadcasts, the platform parses the returned signed bytes and compares them against the prepared request. A difference in any one of six fields stops the transaction before broadcast, and the platform releases that wallet's reserved sequence number the same way it would for a declined or expired approval. An approval is permission to sign one specific payload, and the platform broadcasts only bytes that match it. Where the provider broadcasts the transaction itself, the platform compares nothing before it goes out.
The six fields that must match:
- Sequence number
- Destination address
- Call data
- Chain identifier
- Native value
- The recovered signer address
The platform trusts no unsigned provider notification. An inbound message about an approval counts only when it verifies. Fireblocks and Utila messages verify against the provider's published key, and DFNS and Ripple Custody messages against an HMAC-SHA256 secret the operator configures. The platform checks that before it reads the message. Ripple Custody messages without a signature count only when a non-production deployment explicitly allows them. A verified message ends the wait at once. Without one, the platform keeps polling the provider until the approvers decide or the deadline passes.
The sequence-number reservation makes the payload binding hold over human time. The prepared payload fixes a specific next sequence number for the sending wallet, and an approval can take hours. The platform keeps that slot reserved throughout, so a concurrent write waits instead of consuming the number and invalidating the approved payload. A decline, a lapse, or a cancellation releases the reservation.
The integration contract
In the v2 API, Custody Approval appears in two shapes that match the two control planes. A provider-side hold is a state that a write can enter. A multi-signature approval is an object that you create, read, and sign until its policy reaches a decision.
A write that meets a provider policy does not fail. It stays in flight and reports a pending-approval state whose reason names a pending custody approval. Treat that as a wait, and let recovery resume the work when the provider clears it. The queue deduplicates a matching submission under the same key, but the API route may do work before queue admission. A rule that blocks outright is different: it fails the transaction outright, and no approver decision reopens it. Fix what the rule objects to, such as the amount or the destination, and submit a new instruction. Retrying the same one fails again against the same rule.
A multi-signature approval is a record of its own on the wallet. You create one at POST /api/ with the prepared user operation the wallet is to execute, including its operation hash. The wallet must hold a positive multisig threshold. A wallet without one refuses creation with 409 MULTISIG_. The platform recomputes the operation hash from the wallet, the network and the prepared operation, and refuses a preview addressed to another wallet or network, or one whose hash does not match, with the same 409. It stores that preview, which fixes the sequence number, the gas limits, the fees and the call data, opens the approval with no weight collected, and mails the wallet's other signers. Every signature is taken over the hash of that stored preview, so no signer is asked to sign terms that drifted.
An approval opened through this route is not tied to a queued transaction, so it does not execute on its own. A write that a multisig wallet starts through the platform opens its approval together with a queued transaction. The signature that brings the collected weight to the threshold resumes that transaction. POST /api/ resumes it explicitly once the threshold is met, for a transaction that did not resume. Submitting an approval below the threshold, past its deadline or without a queued transaction is refused with 409 MULTISIG_.
A co-signer signs at POST /api/ in one of two modes. In external mode the signer sends its address, its signature and the operation hash, and the platform verifies the signature against the stored preview. In managed mode the signer names its address and the platform signs with that signer's custodied key. Either way the signer must be an active signer on the wallet that the caller controls, and its weight is added once. A second signature from the same signer, a signature over another hash, an approval that is no longer collecting, and an approval whose window has closed are each refused with 409 MULTISIG_. A signer whose key sits under a wallet checker policy cannot sign in external mode. In managed mode the platform asks the checker first and signs once the checker approves.
Reading the record at GET /api/ gives you the required weight, the weight collected, the stored preview, the deadline, the signers still waiting on a checker, and every collected signature with its signer and the weight it added.
Create the approval, collect co-signatures until the weight meets the threshold, then read the terminal status.
Read the approval's status instead of inferring one. It reads pending while more weight is needed and threshold-reached once the collected weight meets the threshold. It reads submitted when the operation goes out and landed when the operation executes. An approval that runs past its deadline reads expired. An approval whose submission or execution fails, or whose transaction is cancelled before it goes out, reads rejected. submitted does not mean executed: the operation is still on its way, and its own outcome is recorded as a Settlement Verdict. A sign call against an approval that no longer collects signatures fails instead of reopening it, so a stale client cannot revive an approval that has expired or been rejected.
A signer whose key carries a checker policy does not co-sign alone. The platform holds that signer's co-signature until the named checker approves it within the approval's own deadline, and the other signers see which signer is waiting for a checker.
Controls and evidence
For a control function, Custody Approval is a preventive control at the point of signature release: an unapproved payload is never signed, so there is no unauthorised transaction to detect or reverse. With an external provider, a hardware module or a wallet contract, the party holding the key enforces the decision before signing, so the platform is not the single point of trust for this control.
Keep it separate from transfer compliance, because the two answer different questions and both must pass. Transfer compliance decides whether an address, a claim, or a movement is permitted under the asset's own rules, and it is enforced on chain when the transfer executes. Custody Approval decides whether the key may sign the prepared transaction at all. An approval creates no eligibility claim and overrides no transfer restriction: an approved transfer that fails the asset's rules still reverts on chain.
Evidence is split by design, and an audit needs both pieces. The platform holds the request record: what was requested, by whom, when it entered pending approval, how long it waited, the terminal outcome with its reason, and the resulting on-chain transaction. The custody provider or hardware module holds the other piece: which approvers the policy named, who decided, and when. On the multi-signature wallet plane both pieces sit on the platform and on the chain, because the approval record names each signer, their weight, and their signing time, and the wallet contract enforced the threshold in public.
An external provider's policy lives at the provider, so no platform role can widen it, and on the provider and hardware paths the key operation waits for the key holder's answer. Three things sit inside the platform:
- the wallet checker, which the wallet's owner can remove
- the platform key store, where the platform signs itself
- a Smart Wallet's code, which follows the implementation the platform directory names, and which the directory administrator can replace for every account.
What happens when no rule matches is therefore decided by the provider's default, not by the platform. Configure a catch-all deny or manual-review rule, so nothing is left to that default. For a Fireblocks workspace, Fireblocks policy for DALP vaults lists the rules each vault needs in each signing mode. For a Ripple Custody domain, Ripple policy for DALP intents lists the properties that a policy can match and the operation names it must use.
Frequently asked questions
Which happens first, the compliance check or the approval?
The compliance check. The platform simulates the asset's transfer rules against the prepared transaction before it asks anyone to approve, so an operation the asset would reject never reaches your approvers. Those rules then run again for real when the transaction executes on chain, which is what catches an eligibility change that landed while the approval was pending.
Who are the approvers?
The approvers are whoever your own policy names. On a custody provider, the approvers are the people and rules configured in that provider's own policy engine: named individuals, amount thresholds, destination restrictions, or a required quorum. On a hardware security module, they are the key custodians who must jointly activate the partition. On a platform multi-signature wallet, they are the signers on that wallet, each carrying a weight you set. On a key wallet with a wallet checker, the approver is the one member of your organisation that the wallet's owner named. The platform appoints approvers in none of these models.
Can both approval planes run at once?
Yes. Clearing one plane never clears the other, because each is a separate authority: the wallet contract enforces its threshold on chain regardless of what the provider decided, and the provider's policy engine runs regardless of the wallet's collected signer weight. A movement that needs both keeps waiting until each has cleared on its own timeline, so the slower plane sets the pace for the whole request.
Does the platform hold the keys?
Only if you choose that model. With a custody provider or a hardware security module, the key material never leaves the provider or the module. The platform holds provider configuration and workflow state. The platform key store keeps keys in the deployment's own secret store, for development and for deployments that accept platform-managed key material. That path has no external custody policy engine. Select it only when platform-managed key storage meets your deployment's signing requirements.
Can a platform administrator bypass the approval?
Not at an external custody provider or a hardware module, because the key operation waits for their policy. A weighted Smart Wallet checks its installed validators on chain while its code is unchanged, and the platform directory administrator can replace that code for every account. On the platform key store there is no external policy, so platform approvals and the wallet checker are the only gates, and a wallet's owner can remove its checker alone. Check which validators are installed on each wallet and who can change them.
How long can an approval stay open?
A request that waits at a custody provider or in a hardware security module has one deadline. The platform sets it once, when the request starts to wait, and records it with the request together with the limit that set it. The earliest of these limits applies:
- The approval window: 24 hours by default, set by
CUSTODY_. A deployment can make it shorter. The platform does not start with a value above 24 hours.APPROVAL_ DEADLINE_ MS - The gas sponsorship ticket, for a Smart Wallet operation whose gas is sponsored: the approval must finish 60 seconds before the ticket expires. The ticket lasts 300 seconds by default, so an approver has about four minutes. To give approvers more time, raise
PAYMASTER_, up to 3600 seconds.TICKET_ DEADLINE_ SECONDS - The signature's own deadline, for typed data that expires by itself.
- The quorum window of a hardware security module that collects its approvals as a quorum.
- The custody provider's own expiry of the request, where the provider reports one: the expiry the platform sets on a Ripple Custody intent, the expiry of a DFNS approval, and the expiry Fireblocks sets on a transaction that waits for approval.
A restart does not move the deadline, because the platform reads the recorded deadline and not the current configuration. When the deadline passes with no decision, the platform withdraws the request at the custody provider and records the approval as expired. A hardware security module keeps no request of its own, so nothing stays open there. Some providers cannot withdraw a request. For those, the transaction stays pending, the platform says the request is still open at the provider with the provider's reference, and it keeps reading the provider for up to CUSTODY_ after the deadline (seven days by default, at most 30). A decision at the provider ends the transaction. If none comes, the transaction then fails and names the open request. An operator can reject the request in the provider's own console.
When the provider ends the request at its own expiry first, the platform records the approval as expired.
A platform multi-signature approval and a wallet checker decision expire on the same approval window, counted from when the approval opens. A co-signature that waits for a signer's checker expires with the multi-signature approval it belongs to. Whichever plane is waiting, the wait is durable, so a restart on either side does not lose a pending approval or the signatures already collected toward it.