POST /dapi/v1/payouts, sign approval.payload, and post the signature to the confirm route.
Prepare
Call the prepare route. The response has
quote, approval and debit.Check
Compare
debit with the payment in your system and stop if they differ. debit is decoded from the operation you sign and returns that operation (Debit contents).Sign
Base64-decode
approval.payload and sign the decoded bytes in the signature format.Confirm
Post the signature to the confirm route before
approval.expiresAt. HEVN verifies it against the stored bytes, co-signs and submits.Routes
On the signed routes, omit
X-Hevn-Account or send your cl_…. See Who can spend and Acting as a client.
Authorization values
authorization in the response of POST /dapi/v1/payouts and POST /dapi/v1/swaps names who authorizes the payment. Branch on it before you read status.
With
debit and intent, the payload bytes, the confirm route and the retry rules are the same. With client and wallet, the confirm route is not used. A confirm on a wallet payout returns 400 invalid_request with details.reason = "funded_by_wallet_transfer".
status is awaitingSignature after booking for each value. With wallet it means the transfer has not been seen yet.
Which value a payout or a swap returns is on Create an outgoing transfer and Create a transfer between the client’s own accounts.
The confirm body:
403.
Payload
approval.payload is base64 of a canonical JSON document. A decoded payout payload, formatted for reading (the real bytes have no whitespace):
base64decode(payload) unchanged. Do not parse and re-serialize the JSON. Reordered keys, a space after :, different escaping or a trailing newline return 400 signature_invalid.
HEVN builds the operation from the booking: one token transfer from the wallet in debit.sourceAddress. The approval is bound to your account, the target, the wallet and your signer.
Prepare refuses a target that is not in a fundable state, a wallet whose on-chain owner is not your signer (409 signer_not_attached) and a balance below the transfer (409 insufficient_funds). See Errors.
Debit contents
Withauthorization: "debit", the approval covers one ERC-4337 v0.6 user operation, returned as debit.operation.
The
hash in the decoded payload is the hash of that operation:
chainId is debit.chainId. The packed operation is the ABI encoding of sender, nonce, keccak256(initCode), keccak256(callData), the five gas fields in the order above and keccak256(paymasterAndData).
callData is the wallet’s executeBatch with one call: ERC-20 transfer(address, amountAtomic) on the token contract, with no native value. A payout, a swap and a move have the same shape, with no fee transfer and no token approval. initCode is 0x, or the factory call that deploys the wallet when the operation is its first.
Check these before you sign:
The Node package hevn-inc/dapi-sdk runs these checks and refuses a
debit that has no operation. nonce, the gas fields and paymasterAndData are bound by the hash and have no check of their own.
An escrow action returns approval with no authorization, debit or operation.
Signature format
A signature that breaks a rule returns
400 signature_invalid and does not consume the approval. Sign on your server and not in a browser.
Approval lifetime
An approval is single-use and ends atapproval.expiresAt. The windows are in Routes.
- Run the steps in one pass. A payload queued for a person to approve later expires.
- To re-open, call the prepare route again with the same
Idempotency-Key. While the payment has not moved, it returns an approval on the same booked payment, at the same price. A replay while the approval is still open returns the same approval and the same operation. A payout that already moved comes back with noapproval. - Re-opening has no attempt limit. Each new approval uses the same on-chain slot. See Why a retry cannot pay twice.
Retrying a confirm
The first confirm with a valid signature uses the approval. A second confirm on the same approval is refused, so read the payout or swap instead of confirming again. A payout confirm returns200 when the operation lands within the request, and 202 with pollUrl otherwise. A swap confirm, and a payout confirm with authorization: intent, always return 202. An escrow confirm repeated with the same path key returns the first result.
Each approval for one payment uses the same on-chain slot. If an earlier operation lands after a re-open, the new one returns
payment_slot_consumed. The loop as code is in HTTP client.