Skip to main content
RAVN spans three execution models. POST /execute returns exactly one of them, tagged by executionType. Your integration reads that single field and branches. Nothing else about the flow changes. One more value appears only if you ask for it: a Hinkal private swap, on a quote sent with authorizeSteps: true, first answers AUTHORIZE, a signature to collect from the paying wallet, before its TRANSACTION. See AUTHORIZE steps.

TRANSACTION

Sign and broadcast the returned transaction.
Across, Relay, Mayan, Eco Routes, THORChain, Jupiter, 0x Swap, 0x Solana, Nordstern, Fly Trade, KyberSwap, OKX DEX, Bebop (self-executed), Layerswap (EVM into BTC and Robinhood Chain stocks; Solana memo with broadcastViaRavn), Hinkal (after its AUTHORIZE steps)

SIGNATURE

Sign typed data, with no gas and no send. RAVN submits it.
0x Gasless, Bebop (gasless), CoW, Relay (gasless permit)

DEPOSIT

Send the origin asset to an address.
NEAR Intents, Chainflip, Rift, Houdini Swap, Layerswap, Relay (BTC source)
A few venues return different types depending on the source chain or execution mode. See the Execution column on Supported Chains & Venues for exactly which.

The payloads

Every payload carries a quoteToken. Pass that one, not the token from /quote, to /submit-signature, /submit-transaction, and /status: a two-hop RAVN route is rebound to its second hop at execute, and /submit-signature refuses its original token.

TRANSACTION with submit

Only on quotes made with broadcastViaRavn: true (see /quote). A TRANSACTION that carries submit: { "url": "/api/v1/submit-transaction" } is a Solana payment to Layerswap that RAVN checks before it is sent, or a Jupiter order that Jupiter lands (its market maker or gas sponsor signs some of them too). Don’t broadcast it: sign transaction.serialized without sending, post it to /submit-transaction with this payload’s quoteToken, and poll /status with its statusRef, or with the txHash /submit-transaction returns when there is none (Jupiter). A Jupiter order carrying your fee under 50 bps comes without submit: broadcast it like any other. Without broadcastViaRavn on the quote, submit never appears on a TRANSACTION.

AUTHORIZE steps (Hinkal)

Only on a private quote you sent with authorizeSteps: true (or onlyVenues naming hinkal) that Hinkal won. Before Hinkal’s swap can be built, the paying wallet (the quote’s userAddress) signs twice, and /execute asks for each signature with an AUTHORIZE answer. Signing moves no funds: the TRANSACTION that follows does.
AUTHORIZE
Have the paying wallet sign sign, then call /execute again with the same quoteToken, this authorization, and the wallet’s signature, before expiresAt, with a new Idempotency-Key (each answer is a request of its own). Repeat until a TRANSACTION comes back. Check each step before your user signs it:
  1. Step 1, personal_sign: opens a read-only Hinkal session for the wallet. message must read exactly Authorize Hinkal session, Session ID: …, Public Key: … on three lines. Refuse to sign one that adds This signature can also be used to submit transactions.: that is Hinkal’s other session mode, whose key could move the wallet’s funds.
  2. Step 2, eth_signTypedData_v4: Hinkal’s PrivateSendBridge order, signed with the wallet on the input chain. It places the order. Its domain is only { name: "Hinkal Enclave", chainId } on the input chain, it is for the input token (the zero address for the chain’s coin) and at most the input amount, and recipients holds exactly one entry: your destinationAddress.
  3. The TRANSACTION: the approval on a token sell, then the deposit into Hinkal’s contract (prooflessDeposit on 0x7cb60446d7635C68EDf1c568cac74A1f98c1Cfa4, the same address on every chain), RAVN’s fee beside it when your key sets one, and a statusRef (Hinkal’s order id) to poll /status with and to recover with. Handle it like any other TRANSACTION.
Send the deposit within 10 minutes of receiving the step-2 AUTHORIZE. Hinkal prices its route as RAVN builds step 2, and a deposit sent later is likely to fail at the bridge, leaving the funds at Hinkal until your user recovers them. The TRANSACTION has no deadline field, so note the time step 2 arrived. Have the wallet sign step 2 within about 6 minutes: an order signed with under 4 of those minutes left is refused before it is placed (400 INVALID_REQUEST), so start the swap again from /execute.
Each authorization is single-use and lasts until its expiresAt. Up to 12 Hinkal swaps can be started (step 1) an hour per IP, or 120 per API key; past that /execute answers 502 BUILD_FAILED (“too many private swap attempts”). Calls without an API key share their server’s IP, so send your key. Hinkal’s deposit is a heavy call, 450k to 670k gas measured. When its TRANSACTION comes with batch: true (a token sell, with its approval or RAVN’s fee beside the deposit), batch its calls only if your wallet lets you give the batch about 800k gas (above the ~400k the general rule under Paying a fee in one confirmation allows), and otherwise send them one by one. A sale of the chain’s coin comes with batch: false: send its calls one by one. The order’s typed data embeds Hinkal’s route, several to tens of kilobytes; how hardware wallets show or accept it is untested. A sandbox Hinkal quote skips the steps and returns a stand-in DEPOSIT. On JavaScript or TypeScript, executeAndTrack (SDK 0.4.1) checks and signs the steps, then sends the deposit.

Branch logic

On TRANSACTION, the ref is the transaction hash you broadcast, unless /execute returned a statusRef: then use that. Poll /status with it until a terminal state. This is not optional if you charge a fee: on same-chain venues (0x Swap, 0x Solana, Nordstern, Fly Trade, KyberSwap, OKX DEX, Jupiter, Mayan same-chain) RAVN only marks a swap settled, and only pays you on it, after it has verified that hash on-chain. A swap you never report never becomes payable. See Settlement.
On JavaScript or TypeScript, @ravnexchange/sdk’s executeAndTrack already sequences all of this, including the approval wait below and, from SDK 0.1.15, a TRANSACTION’s fee payment (0.2.5 recommended: it never loses a sent swap, and batches the fee whenever /execute says batch), given your own sign/send functions. For a DEPOSIT fee, depositFeePayment says what to pay; with sendDeposit: true (SDK 0.2.4) executeAndTrack sends the deposit and the fee itself. The raw flow above is still the full contract for every other language.

The approval step

Both TRANSACTION and SIGNATURE payloads can carry an optional approval, a ready-to-send ERC-20 approve() call.
On TRANSACTION: send approval, wait for it to be mined, then send transaction. The swap moves your tokens with transferFrom, so an allowance that is merely broadcast, and not yet in a block, still reverts, and the user pays gas for a failed transaction. On SIGNATURE: land the allowance before you submit the signed order. Gasless does not mean allowance-free: CoW settles through its vault relayer and Bebop through Permit2. Skip it and the order is accepted and then silently never fills, with no error to debug. RAVN reads your user’s allowance for spender on-chain when you call /execute (the wallet you quoted as userAddress) and leaves approval out when it already covers amount. If that read fails, approval is included anyway, so a token you have already approved can still carry one: skip it when your own allowance read covers amount. The read sees the latest block only, so a swap still pending that spends the same allowance isn’t counted: run one swap per token and spender at a time. approval.reset: some tokens (Ethereum USDT) refuse to change one non-zero allowance into another. When your user holds a partial allowance on one, approval carries a reset, a ready-to-send approve(spender, 0): send it, wait for it to be mined, then send the approval.
unlimitedRecommended: true means the venue would rather you approve once for a large amount than per swap. It is set for CoW, whose relayer needs an on-chain allowance for every token regardless, so an exact approval costs gas on every single swap and cancels out the gasless route. data still encodes the exact amount; raising it to an unlimited approval is your call. Both work.
Do not assume the spender is transaction.to, and do not decode the quoteToken to find it. The quoteToken is opaque and its internals change without notice. If approval is absent, no allowance is needed.
A DEPOSIT can be fulfilled automatically, by building a wallet transfer to the address as an EVM or Solana wallet does, or manually, by showing the address and a QR code as a native-BTC send does. Both are the same execution type, so you choose the UX. RAVN’s own app does the former for NEAR Intents, Rift, and Houdini Swap on EVM and Solana sources, so the user confirms one wallet transfer: native coin straight to the address, or an ERC-20 or SPL transfer of exactly deposit.amount, with no approval needed. With a fee-bearing key, a Rift or private-swap DEPOSIT adds fee, a second payment (see Pricing), which the next section shows how to fold into the same confirmation.

Paying a fee in one confirmation

On a route where RAVN collects your fee beside the swap (an execution carrying fee with a transaction: Rift, private swaps, Eco Routes, Layerswap, Mayan routes paying no referrer, Fly Trade’s coin sells outside Ethereum, Base and Polygon), a wallet that batches can take the swap and the fee in one confirmation when /execute says batch: true: an ERC-20 fee, or a Fly Trade coin sell’s fee on Robinhood Chain and Arbitrum, which RAVN takes as WETH minted to it. Send calls (fee.transaction last, exactly as given) in one batch:
  • Report the on-chain hash of the transaction that carried the fee as txHash on /status: never the EIP-5792 batch id or a 4337 userOpHash. On a TRANSACTION with no statusRef, the swap’s own hash as ref is enough. A relayed or smart-account wallet (EIP-7702, ERC-4337) works the same way.
  • One fee-bearing swap per batch. A batch carrying two fees proves only one of them.
  • Any other native-coin fee (ETH, for example) is a plain transaction of its own, from a regular wallet (batch: false): RAVN proves it from the transaction’s own value. The one exception is a fee beside a NEAR Intents deposit (a private swap) on Ethereum, Base or Polygon: it may ride in the same batch as the deposit, as RAVN reads those chains’ internal transfers. A WETH fee’s fee.transaction carries a value too (the coin it mints from); batch is what says it may ride in the batch.
  • Batch a token deposit, or a native-coin deposit to NEAR Intents (it credits coin a smart account moves). Send any other native-coin deposit to a deposit address as a plain transfer: an exchange may not credit coin a contract moved.
  • Wallets without batching send the fee as a second transaction, as in the example above. From Bitcoin, or a Solana deposit, the fee goes in the deposit’s own transaction, and a Solana transaction RAVN builds already carries it, so there’s nothing to batch.