# Execute a protocol payment

Start with the [next-action and authorization tables](/docs/#next-action). For ambiguous results, use the [recovery playbook](recovery.md); check [wallet and path compatibility](compatibility.md) before implementing signing.

Use the same Route API key and `/v1` endpoints for Circle CCTP, Allbridge, LayerZero OFT, Axelar ITS and supported SwapKit or Rift deposits. Your app selects assets and amount, receives a comparison, saves its chosen candidate, then prepares and signs each action. Route submits the signed action once and tracks settlement. A provider report alone does not establish verified delivery. Route does not hold the customer's signing keys.

## Provider fee ceilings

Circle, Allbridge, LayerZero and Axelar comparisons include a disclosed 10% reserve on the applicable provider fee (`details.providerFeeHeadroomBps: "1000"` in `view=full`), including Stellar CCTP, LayerZero and Axelar paths. This reserve is part of the displayed cost and minimum receipt in every view; it is not a Route service charge. Informational Stellar Allbridge comparisons carry no reserve because Route does not execute that path. Network gas remains a separate estimate. The complete estimate must fit the owner's policy before execution.

Once an action is saved, its provider fee becomes a ceiling. Fresh checks may accept a lower required fee or an increase within that ceiling while preserving the saved transaction and the customer's accepted minimum. Allbridge service fees are recalculated from the reserved relay fee. LayerZero and Allbridge settlement uses the canonical source amount and matching destination credit, so a verified higher payout can complete normally. Any refund of prepaid native fees follows the provider's rules.

If fresh requirements exceed the saved ceiling, Route refuses signing or submission with `TRANSACTION_FEE_CHANGED`; it does not silently increase the charge or lower the recipient minimum. Review the saved action and follow the recovery instructions. An unused EVM action can be closed after its review expires with [a finalized wallet transaction that used its nonce](recovery.md#close-an-unused-evm-protocol-action) before a new payment safely replaces it.

## Current mainnet coverage

| Adapter | Execution paths | Destination action |
| --- | --- | --- |
| Circle | Native USDC between Ethereum, Base, Arbitrum and Stellar; Fast only where Circle supports it | Circle hosted forwarding on supported EVM destinations. Stellar uses managed OpenZeppelin Channels minting by default; customer-funded minting is also available. |
| Allbridge | Native USDC via the current legacy Allbridge CCTP V1 path between Ethereum, Base and Arbitrum | Allbridge relays the mint. Current registry, fee and contract availability are required. No active Allbridge Stellar path is advertised. |
| LayerZero | Verified OFT token pairs on Ethereum, Base, Arbitrum and Stellar, including registered Stellar USDT0 paths | The configured LayerZero executor delivers the message; Route verifies its GUID and exact recipient credit. |
| Axelar | Exact verified ITS registrations on those networks, including Stellar directions | ITS hub routing and destination execution; Route verifies both hub correlation and recipient credit. Native USDC and USDC.ITS are separate assets. |
| SwapKit | Simple deposits from Ethereum, Base, Arbitrum or single-key native SegWit/Taproot Bitcoin to reviewed EVM ERC-20, Stellar classic/native and native BTC assets; valid deposit channel deadline required | Underlying provider fulfills delivery or refund. Route independently verifies the recipient receipt. Contract-call and memo routes remain quote-only. |
| Rift | Reviewed assets on Ethereum, Base, Arbitrum, Ink and Robinhood, plus native Bitcoin, including distinct assets on the same EVM chain | Direct deposits require `acceptVariableOutput: true`. Output is an estimate with no guaranteed minimum. Route reports Rift’s delivered/refunded status separately from independently verified chain settlement. HyperCore and composed Rift funding remain unavailable. |
| NEAR | ERC-20/native assets on Ethereum, Base, Arbitrum, Optimism (`op`), Polygon (`pol`), BNB Chain (`bsc`), Avalanche (`avax`), Berachain (`bera`), Monad, Gnosis, X Layer (`xlayer`), Plasma, Scroll and Robinhood (`hood`), plus classic Stellar assets and XLM. Native BTC, Solana SOL/original SPL tokens and Fogo FOGO are supported sources and destinations, where 1Click offers the exact pair | Use the [NEAR preparation and intent-approval flow](customer-api.md#prepare-a-near-deposit-and-follow-its-outcome). |

Availability depends on the exact asset pair and current provider conditions. Read each candidate's `execution` and each prepared action's live flags. EVM sources require an externally owned account; Stellar actions currently support single-key G accounts. Reviewed NEAR/OFT compositions use the [two-step execution workflow](composed-payments.md). Other unsupported source wallet families, smart wallets, muxed recipients and automatic replacement transactions are not included. WBTC is an EVM token and does not imply native BTC execution.

## 1. Save a candidate

Obtain catalog IDs from `GET /assets`; request a comparison with `POST /quotes`. Your app can use `executionSelection.candidateId` when it is present. A candidate with unresolved checks may be prepared for further review but must not be presented as an executable recommendation.

Create the payment with a saved UUID `Idempotency-Key`:

```json
{"mode":"prepare","quoteId":"QUOTE_UUID","candidateId":"CANDIDATE_ID"}
```

## 2. Prepare the payment

`POST /payments/{id}/prepare`, with another saved UUID `Idempotency-Key`:

```json
{"version":1,"sender":"SOURCE_PUBLIC_ADDRESS","recipient":"DESTINATION_PUBLIC_ADDRESS"}
```

`version` is the payment draft version. For Circle **to Stellar**, managed destination execution is the default:

```json
{"version":1,"sender":"SOURCE_PUBLIC_ADDRESS","recipient":"STELLAR_RECIPIENT_G_ADDRESS","destinationExecution":"managed"}
```

Route verifies the finalized source burn and Circle attestation, then asks **OpenZeppelin Channels** to submit `mint_and_forward`. Channels pays the destination XLM fee. Your app signs only the source actions; it does not need a destination signing wallet, XLM fee budget, Channels key or provider integration. The recipient still needs an active account and the exact native USDC trustline. Account reserves and trustline creation are not sponsored by this flow.

To use your own destination fee payer instead, select `customer` on first preparation:

```json
{"version":1,"sender":"SOURCE_PUBLIC_ADDRESS","recipient":"STELLAR_RECIPIENT_G_ADDRESS","destinationExecution":"customer","destinationFeePayer":"STELLAR_SIGNING_G_ADDRESS","destinationFeeBudget":"0.1"}
```

The `0.1` XLM budget is an example, not Route's cap or a guaranteed fee. Your app/owner chooses the ceiling. Route checks spendable XLM, simulates the mint after attestation, and refuses fees above that ceiling. Existing requests that provide a fee payer without a mode continue to use customer execution. A prepared payment's mode is immutable; existing payments are not silently converted to managed delivery.

Managed execution uses the [hosted OpenZeppelin Channels service](https://docs.openzeppelin.com/relayer/1.5.x/guides/stellar-channels-guide), subject to its availability and fee quota. Read `stellarDestinationExecution` in `GET /adapters`; new managed preparations fail with `DESTINATION_EXECUTION_UNAVAILABLE` when sponsorship is disabled. Route holds no customer private keys and runs no Stellar signing server or XLM treasury. Circle's Stellar forwarder is the contract being called; Circle hosted forwarding is a different service.

Both modes wait for finalized source evidence, including Fast burns. Circle Fast attestation time is not an end-to-end arrival guarantee.

The response has `deposit.kind: "protocol"`, `walletApproval.required: false`, `actions`, `transaction`, `readiness`, `version` and `nextAction`. The exact transaction signature authorizes these protocols; do not request the NEAR wallet-intent challenge. Preparation performs read-only checks and reserves applicable API-key USD budget. It does not submit a transaction.

## 3. Request, sign and submit each action

The sequence below uses Route submission. EVM wallets that only sign and send can choose the [wallet submission handoff](next-actions.md#evm-wallet-submission) after creating the action. Reserve the handoff before opening the wallet; confirm its hash through Route instead of calling signature/execute. Once review evidence for a burn or transfer is on record (a wallet-altered copy of its call, the same payment sent or queued at another nonce, re-quoted or not, or any other transaction the wallet signed that was reported for it and is neither the saved transaction nor a recognized cancellation, whether recovery, confirmation, a cancellation or a `/transaction/close` observed it), Route refuses both a new handoff and `/execute`, even after a review refresh and a new signature, with `409 WALLET_TRANSACTION_REVIEW_REQUIRED` before any network read, and the action reports `walletBroadcastAvailable`, `signingEnabled` and `submissionEnabled` as `false` with `actionBlocker.code: "WALLET_TRANSACTION_REVIEW_REQUIRED"`; an existing handoff no longer presents its `params` (see [wallet handoff recovery](recovery.md#wallet-handoff-with-a-missing-response)). A signed approval with a recorded altered copy is not submitted either (`submissionEnabled: false`), though the unsigned approval can still be closed with a finalized nonce proof, and an approval's byte-identical call in any envelope (including a set-code upgrade) is that exempt altered copy; any other recorded transaction blocks an approval as it blocks a transfer. Evidence is kept per payment: a transaction reported against the approval (for example the burn itself, sent by the wallet at the next nonce) blocks the burn too. Route then refuses `POST /transaction` for the next action, and the handoff and `/execute` of every action, with the same `409`, and an action with no evidence of its own shows the payment's evidence as its `lastError`. Every reported hash is recorded before Route reads it, whoever signed it (a relayer, bundler or L2 system deposit included); one the network does not show yet stays recorded as `reported-transaction` and blocks until a later check (see [freeze on report](recovery.md#wallet-handoff-with-a-missing-response)). While such a check is reading the network, `/execute` and a new handoff return `409 WALLET_EVIDENCE_CHECK_IN_PROGRESS` (retryable).

**Resolve source-token approval before the final transfer review.** If Route returns `approval-reset` (EVM only) or `approval`, complete that action and wait for its verified confirmation (one successful canonical block inclusion on EVM, a finalized ledger on Stellar) before requesting the burn or transfer. Approval waiting time must not be treated as part of a locked quote. Route refreshes the selected route's terms when building the next action on the same payment. Read [source wallet readiness and quote expiry](source-wallet-readiness.md) before implementing this sequence.

1. Read `GET /payments/{id}/preparation` for the current **preparation** version.
2. `POST /payments/{id}/transaction` with `{"version":CURRENT_PREPARATION_VERSION}` and a UUID `Idempotency-Key` saved for this action.
3. Display the returned `kind`, `network`, `sender`, `transaction`, fee budget and assessment. Require `signingEnabled: true` and an unexpired action.
4. Have that action's sender sign its exact transaction, then `POST /payments/{id}/transaction/signature` with `{"authorizationId":"ACTION_UUID","signedTransaction":"SIGNED_BYTES"}`.
5. After the user authorizes submission, call `POST /payments/{id}/execute` with `{"authorizationId":"ACTION_UUID"}`. Read the returned hash and state.
6. Track with `POST /payments/{id}/refresh` and read the preparation again. After the approval reports `canContinue: true`, request the next action with a new saved UUID and the current preparation version. Review its refreshed fees, minimum receipt and expiry before requesting the transfer signature. Do not reuse the approval signature or its review deadline for the transfer.

Actions are `approval-reset`, `approval`, `burn`, `transfer` or `mint`. EVM token approvals reset an insufficient nonzero allowance first and then approve the exact required amount. Stellar token approval overwrites any existing allowance, so Stellar issues one exact `approval` and never a new reset. Approvals never grant an unlimited allowance. Approval completion is not payment completion. Use `canContinue: true` for the approval continuation gate; an EVM approval’s `receipt.finalized` can still be `false`. Stellar approvals require a successful finalized ledger receipt proving the exact allowance. Route rechecks unfinalized approval receipts, current allowance and simulation before subsequent source actions. Burns, transfers and destination settlement retain their finality checks. With managed Stellar delivery, continue tracking after the burn: `nextAction` is `track`, and `destinationExecution` reports the relay state and `customerSignatureRequired: false`. Do not request a mint signature: a mint action request in managed mode returns `DESTINATION_MANAGED`. Customer mode returns `nextAction: "prepare-mint"` after finality and attestation; repeat the transaction/signature/execute steps using the **destination fee payer**.

### Stellar-source CCTP approval

Sending native USDC from Stellar through CCTP requires allowance for Circle’s TokenMessengerMinter contract. A USDC trustline alone does not grant that permission. Route reads the current on-chain allowance and the lifetime of its ledger entry. Route builds the burn directly only when the allowance covers the amount the burn debits and stays live through the burn’s own expiry plus a safety margin. That margin assumes ledgers close no faster than every 4 seconds, plus 12 ledgers: about 87 ledgers for a five-minute burn. Otherwise Route returns one `approval` action, including when a smaller allowance exists: Stellar `approve` replaces it.

Stellar USDC has 7 decimals and CCTP carries 6. The burn transfers and burns the amount minus its sub-6-decimal remainder, so the approval covers exactly that debited amount, while the burn call keeps the requested amount. For example, `10.0000003` USDC approves `10.0000000`; the `0.0000003` remainder stays in the wallet. An amount below one 6-decimal unit returns `AMOUNT_TOO_SMALL`.

Sign and submit each returned Stellar XDR using the normal action sequence above. Route verifies the successful committed `approve` event, including sender, spender, amount and expiration ledger, before returning `canContinue: true`. Then request the next action on the same payment. Route rechecks the allowance and its lifetime, then gets fresh burn terms; the approval itself does not transfer USDC across chains. If a saved burn’s allowance would lapse before its expiry, signature and submission return `APPROVAL_STATE_CHANGED`.

The allowance expires 720 ledgers (about one hour) after the approval is built. This ledger deadline is separate from the action’s 15-minute signing window. Every Stellar action carries a bounded resource reserve (20% plus 1,000 stroops on the resource fee, and 2% plus 20,000 instructions). Its size comes from simulating the assembled, authorized transaction, and it is included in the fee checked against spendable XLM and the owner’s fee policy. Signature and submission re-simulate the exact saved envelope; they fail with `TRANSACTION_FEE_CHANGED` only if current resources or fees exceed what that envelope declares. Subsequent burn checks include fees already paid for approval.

Stellar approvals cannot use the EVM `/transaction/review` renewal. An approval whose signed time bound passed without an included receipt, whether unsigned, signed or submitted, offers [`renew-approval`](recovery.md#renew-an-expired-stellar-cctp-approval). Route proves it can no longer execute and then prepares a fresh action at the same wallet sequence. An expired burn that was never signed offers [`renew-source`](recovery.md#renew-or-close-an-expired-stellar-burn-or-transfer) in the same way. A signed, submitted or uncertain burn that was never included cannot be renewed; [`close-payment`](recovery.md#close-an-expired-stellar-payment) proves it can no longer execute and closes the unfunded payment, releasing its wallet sequence and holds. `close-payment` is also suggested for an approval or never-signed burn whose renewal cannot run, because execution is paused or the payment's saved settings changed. A wallet can broadcast a returned XDR itself without returning the signature; because a Stellar hash excludes signatures, renewal and closure first look up the saved hash. An exact landed envelope is adopted as the submitted action and tracked, and a used sequence is recorded for review; see [wallet-broadcast Stellar actions](recovery.md#a-wallet-broadcast-the-saved-stellar-action-itself). Older saved burns may fail the stricter recheck; once expired, eligible unsigned actions offer `renew-source`, while signed actions require proof-gated closure or tracking.

Protocol transactions use a common action wrapper:

- EVM: `action.transaction.family === "evm"`. Sign `action.transaction.transaction` exactly. It is an EIP-155 legacy transaction for Ethereum (1), Base (8453) or Arbitrum (42161).
- Stellar: `action.transaction.family === "stellar"`. Sign `action.transaction.transaction.xdr` with its saved public-network passphrase. Return the signed XDR. Route checks the exact invocation, resources, fee, sequence, lifetime and sender signature.

The nested protocol wrapper differs from the older NEAR Stellar transaction object; branch on `authorization: "transaction-signature"` and the returned shape. The downloadable client exposes `prepareProtocolAction(id, version, idempotencyKey)`, `refreshApprovalReview(id, authorizationId, idempotencyKey)`, `saveTransactionSignature` and `executePayment`. Keep the Route API key on your backend; deliver only the reviewed wallet payload to the frontend. Never send a private key to Route.

## Review windows

New payment actions use a **five-minute review window** across Circle CCTP, Allbridge, LayerZero and Axelar. This covers EVM burns/transfers and supported customer-signed Stellar transfers or mints. NEAR uses the same maximum, bounded by its signed provider and refund deadlines. CCTP testnet uses the same action windows.

| Action | Review window |
| --- | --- |
| Payment transfer, burn or customer-signed mint | Up to five minutes |
| EVM token approval/reset or Stellar CCTP token approval | 15 minutes |

Use each action's returned `expiresAt`. The window starts when the wallet action is built; checks and network latency consume part of it. For Stellar, the transaction's signed time bounds match that deadline. Existing saved actions keep their original deadline and signed payload; reloading or retrying does not restart the clock.

The review period does not reserve a market price or change quote expiration. Route rechecks the selected provider, exact transaction, current fees, wallet and policy before accepting a signature or claiming submission. Changed terms or insufficient saved fees can still block an action during its review window. After submission, continue tracking regardless of review expiry. Review renewal remains limited to the recovery capabilities advertised for that action; this common window does not add renewal for protocol transfers, burns or mints.

## Tracking and recovery

Unsubmitted mainnet EVM token approvals can receive a fresh review through `POST /payments/{id}/transaction/review` with `{"authorizationId":"ACTION_UUID"}` and a saved UUID `Idempotency-Key`. This retains the exact transaction and signature and performs no submission. Read `reviewRefreshEnabled` and follow the [approval review recovery sequence](source-wallet-readiness.md#refresh-an-expired-approval-review). New approval reviews last 15 minutes; submitted approvals continue tracking without a finality deadline. Transfer quotes and transfer actions are refreshed separately after approval.

`GET /payments/{id}/transaction` returns the current action plus the action history. Background checks and `/refresh` verify hashes using fixed provider/network endpoints. Background checks run every minute while a receipt is included but not yet final. A submitted hash without a receipt, or a confirmed source whose destination delivery is pending, is checked every minute for an hour after the latest new evidence. Checks then slow gradually to hourly, and they never stop while funds may be moving. A managed mint paused by the service is checked at least every five minutes. Checks of a failed destination, or of a signed EVM or Bitcoin action that was never submitted, slow to every six hours. A signed Stellar action that was never submitted is no longer checked an hour after its time bounds expire. A payment with nothing left to observe, including a prepared payment with no signed action, waits for its next action. A new signature, a submission, a review refresh or a wallet confirmation resumes checks immediately. `/refresh` checks at once and restores the one-minute cadence when it finds new evidence. A check that cannot complete is retried after 5 minutes, doubling up to an hour. You can supply `{"destinationHash":"HASH"}` to `/refresh` when a provider lookup has not discovered the destination transaction; that hash must still prove the exact saved source message and recipient credit. For SwapKit, a supplied destination hash must match the final delivery leg SwapKit reports for the saved source transfer, then pass chain verification of the recipient, destination asset, reported amount, minimum and time. Reconnect the original SwapKit connection if its key was removed; a supplied hash cannot bypass provider attribution. SwapKit also accepts `{"refundHash":"HASH"}`, but only for the refund leg SwapKit itself reports; see [removing a provider key](providers.md#removing-a-provider-key-with-payments-in-flight). A refund SwapKit cannot confirm can be confirmed only by a workspace member in the dashboard, with on-chain checks; see [confirming a refund in the dashboard](providers.md#confirm-a-swapkit-refund-in-the-dashboard).

Managed mint states are `waiting-for-source`, `paused`, `submitting`, `submitted`, `submission-unknown`, `failed` and `completed`. Route records its submission claim before contacting Channels, then polls the same relay transaction by its Channels relay ID until the destination receipt is verified or Channels reports it `failed` or `expired`. Polling continues after a relay hash is known and while new managed execution is paused. `destinationExecution.transactionHash` is the latest hash Channels reported for the current relay attempt. If Channels resubmits the relay under a new hash, the first hash stays saved, `relayHashes` lists every reported hash oldest first, and tracking verifies the latest one. A failed Stellar receipt for that hash sets the payment to `REQUIRES_ATTENTION` (`destination-failed`) until Channels reports a replacement hash. A verified final destination receipt still completes the payment.

Neither state below is final by itself:

- `failed` means Channels reported the relay `failed` or `expired`, or replaced it more than 16 times (`DESTINATION_RELAY_UNSTABLE`). `lastError` keeps the provider status, relay ID, every relay hash and the observation time.
- `submission-unknown` means Route has no saved relay ID. The first Channels response was lost, or the submitter stopped for more than a minute after claiming the mint. Without a relay ID, Route cannot poll the attempt. `lastError.reason` is `timeout`, `http-<status>`, `invalid-response`, `unavailable`, `no-response` or `response-not-recorded` (Channels answered but saving its relay ID failed; `lastError.transactionId` then holds that ID). `lastError.attemptedAt` is when the attempt was claimed.

Both states set the payment to `REQUIRES_ATTENTION`, the next action to `review-required` and emit `payment.requires_attention`.

**One guarded automatic re-mint.** When the first relay is `failed` because Channels reported it `failed` or `expired`, or is `submission-unknown` with no Channels relay ID at all, `lastError.retryAllowed` is `true` and `lastError.remintAfter` is 15 minutes after the attempt. That wait is several times Channels' 25-second request timeout, the one-minute submitter window, Route's one-minute tracking cycle and five-minute error backoff, and the seven-minute tracking lease, so a relay Channels accepted has normally landed or been reported by then. While the re-mint is scheduled the payment stays `REQUIRES_ATTENTION`, and `tracking.status` stays `destination-pending` because the failure is not final yet. After the wait, the next background check or `/refresh` sends the same saved mint call to Channels once more, only when all of these hold:

- managed execution and Channels sponsorship are enabled (otherwise the re-mint waits);
- Stellar RPC reports the expected network and a ledger closed within the last two minutes, and every simulation below answers at or after that ledger (otherwise nothing is decided or sent, and a later check tries again);
- the Circle attestation's expiry (`expirationBlock`, when set) is more than 180 ledgers away;
- the saved mint call still simulates without new authorization entries or archived state to restore;
- the transmitter reports the CCTP nonce unused (`is_nonce_used`), read last, immediately before the re-mint is claimed and sent.

CCTP accepts each message nonce once, so a duplicate relay can fail on chain but can never mint twice. If the nonce is already used, nothing is sent and Route reconciles the existing mint. If the attestation expires too soon or the call no longer simulates cleanly, nothing is sent. `lastError.remint` records why (`MINT_ALREADY_PROCESSED`, `DESTINATION_ATTESTATION_EXPIRED`, `DESTINATION_REMINT_REJECTED` or `DESTINATION_AUTHORIZATION_REQUIRED`), `retryAllowed` becomes `false` and the payment stays in review. The claim's database constraints and row lock allow exactly one re-mint, never before the wait, even when background tracking and `/refresh` run together. The re-mint starts a new relay attempt (`submitting`, then `submitted`), and the payment returns to `DESTINATION_PENDING`. The earlier attempt, with its relay ID, hashes, state and evidence, is listed in `destinationExecution.relayAttempts`. A Channels answer about the earlier attempt is never recorded on the new one. A lost response or `failed`/`expired` report for the re-mint, a lost response whose relay ID Channels did return (`response-not-recorded`) and `DESTINATION_RELAY_UNSTABLE` have no automatic recovery (`retryAllowed: false`). Each claimed attempt and each skipped re-mint is written to the workspace audit log (`managed_mint.relay_claimed`, `managed_mint.remint_claimed`, `managed_mint.remint_skipped`).

Completion always follows the on-chain mint, whichever recorded relay landed. When the tracked hash failed on chain, or the relay is under review, Route reads `is_nonce_used`; if the message is minted it verifies every recorded relay hash of every attempt and completes from the one whose receipt proves the exact mint and recipient credit. A duplicate that failed because the nonce was already used is therefore not a delivery failure. If none of the recorded hashes proves the mint (for example, a lost first relay landed after all), the payment stays `REQUIRES_ATTENTION` with `destinationExecution.state` `submission-unknown` and `lastError.code` `DESTINATION_MINTED_UNRECORDED`: find the Stellar mint of this CCTP message and supply its hash to `/refresh` as `destinationHash`; Route verifies it like any other receipt. Without a mint and without an automatic re-mint left, an operator decides the recovery. A customer-signed mint is refused with `DESTINATION_MANAGED`. Never repeat the source transfer.

For Circle forwarding to an EVM destination, `tracking.forwardState` records Circle's reported forwarding state as a hint; only the destination receipt proves delivery. If Circle has attested the burn (`tracking.message` and `tracking.attestation`, first seen at `tracking.attestedAt`) but reports no forwarding transaction after 30 minutes, tracking becomes `needs-review` and the payment appears as `REQUIRES_ATTENTION`. The attested message is permissionless: anyone can call `receiveMessage(message, attestation)` on the destination MessageTransmitterV2 named in `tracking.selfRelay`, then supply that transaction hash to `/refresh` for full verification. Route keeps checking Circle and completes the payment if Circle's forwarding lands first. Never repeat the source burn.

For LayerZero deliveries to Stellar, Route first searches committed OFT events from the saved Stellar ledger, matching the source message GUID, contract, source endpoint, recipient and amount. It then verifies the transaction receipt and exact net token credit. LayerZero Scan remains an independent discovery source when RPC event history is unavailable. Direct event discovery is limited by the RPC provider’s retained history; an existing destination hash can be supplied for receipt verification.

If neither source can perform the lookup, `/refresh` returns `503 DESTINATION_DISCOVERY_UNAVAILABLE`. Automatic tracking records the error in `preparation.lastError` and the payment appears as `VERIFICATION_PENDING` while tracking retries; this does not mean the destination transfer failed or is still in flight, and it emits no webhook. Retry tracking or supply the destination hash. Never resend solely because discovery is unavailable. Saved or supplied destination hashes still undergo full chain verification; Axelar additionally requires its verified hub proof.

Automatic tracking records the same error code and message that `/refresh` returns when evidence contradicts the saved action, such as `SOURCE_EVENT_MISMATCH`, `RECEIPT_MISMATCH`, `MESSAGE_MISMATCH` or `HUB_RECEIPT_MISMATCH`, or when a required provider connection is missing. `lastError.attempts` counts the consecutive checks that returned that same error code. These rarely resolve by waiting, so rechecks back off from five minutes, doubling while the same code repeats, to at most six hours, and the payment reads `REQUIRES_ATTENTION`. Other refusals also keep their code and make the payment `REQUIRES_ATTENTION`, but are rechecked on the regular retry schedule. `DESTINATION_DISCOVERY_UNAVAILABLE` and `PROVIDER_TRACKING_UNAVAILABLE` keep their code and message; an unavailable network read or an internal failure is recorded as `TRACKING_UNAVAILABLE`. These temporary outages are retried after five minutes, doubling per failure up to an hour; meanwhile a pending payment reads `VERIFICATION_PENDING`, and an outage never replaces a saved refusal or its count. A successful check clears the recorded error.

Completion requires finalized matching source and destination receipts. Route verifies Circle message fields and nonce, LayerZero GUID, Allbridge's CCTP message, or Axelar's source → hub → destination evidence. An explorer status, source success or provider success alone is insufficient. Final receipt evidence is immutable, and the existing payment events/webhook outbox carry the resulting state.

Reuse identical request IDs after an HTTP timeout. Each saved action gets at most one Route broadcast attempt. `submitting` or `submission-unknown` means track the existing hash; never automatically fund a replacement. Source funding is never repeated to fix a destination delay. `/submission` is NEAR-only on mainnet: protocol payments return `SIGNED_ACTION_REQUIRED` there and use the saved signature → execute flow or the explicit EVM wallet handoff. Signed Ethereum transactions do not expire on-chain, even when the Route review expires. Expired or reverted attempts and uncertain wallet slots require reconciliation; automatic replacement/retry and slot release are not implemented. The explicit exceptions are for Stellar-source protocol payments, only after proving the original cannot execute: `renew-approval` and `renew-source` move an expired, never-included action’s wallet sequence to its fresh replacement, and `close-payment` releases that sequence when it closes the unfunded standalone payment.

Owner policy and inherited API-key restrictions are checked again around external reads. Owners choose USD limits. Source and destination fees retain their currencies and precision; fresh USD prices are required where policy needs them. Missing arrival evidence remains unknown. An owner can choose cost priority with `maxSeconds: null`; Route does not invent a complete ETA or change that policy automatically.

Allbridge currently uses the documented legacy CCTP V1 registry paths. Axelar execution requires valid USD representation pricing when the policy uses USD limits; missing valuation blocks execution. ITS transfers and their source events use the chain names from Axelar's mainnet registry, exposed in `view=full` as `details.sourceChain` and `details.destinationChain` after checking ITS trust for them. They can differ from Route network IDs: Ethereum is `Ethereum`. Route verifies those names before determining execution support. Mainnet defaults to `view=best`; accept its saved recommendation using `quoteId`. Optional `compact`/`full` views expose candidate `execution` and `executionSelection.candidateId`. Omission of chain diagnostics from a summary does not mean the path is quote-only. Fresh wallet preparation and authorization are still required.

Axelar ITS and Allbridge CCTP execution use independently reviewed contract addresses. An unknown or changed deployment is refused with `DEPLOYMENT_CHANGED`, including for saved approvals and transfers. A saved action with this blocker offers no signing, submission or new wallet handoff; an existing handoff withholds its send parameters. Keep the payment record and reconcile any transaction already sent. Tracking and receipt verification remain available.

## Garden

Garden is temporarily paused for new quotes and execution. Saved asset identities, credentials and order records are retained. Its order creation, wallet actions, refund handling and chain receipt verifiers are not released through Route. `garden` candidates return `execution.supported: false`. Do not submit Garden wallet actions through another provider’s execution path. See [Garden coverage and connection options](garden.md).

## SwapKit

SwapKit supports simple EVM and native Bitcoin deposits within its exact execution coverage. Bitcoin sources use a finalized PSBT or raw transaction signature; see [Bitcoin wallet actions](providers.md#bitcoin-wallet-actions). Route saves the build attempt, reserving the payment’s credits and API-key budget in the same transaction, before requesting a deposit channel. It then reconstructs the wallet action, submits it once and independently verifies delivery or refund. Contract-call, memo-bearing and unsupported chain paths remain quote-only. Read the candidate’s `execution` flags and [provider recovery rules](providers.md#failure-and-execution-boundaries).

## SwapKit quote changes before funding

A saved build may return a lower minimum receipt than the comparison. Use the [explicit quote review](providers.md#reviewing-changed-swapkit-terms) on the same payment. Acceptance preserves its deposit channel and original evidence; it does not send funds or extend an expired provider deadline.

Expired customer CCTP Stellar mints may offer [`renew-mint`](recovery.md#renew-an-expired-customer-stellar-mint) when no submission was recorded. Renewal verifies ledger expiry and an unused wallet sequence, then returns the same mint for a fresh signature within the existing fee budget. Submitted or uncertain mints continue reconciliation. Expired Stellar-source CCTP approvals with no included receipt may instead offer [`renew-approval`](recovery.md#renew-an-expired-stellar-cctp-approval), even when signed or submitted. Expired Stellar-source burns and transfers offer [`renew-source`](recovery.md#renew-or-close-an-expired-stellar-burn-or-transfer) while unsigned, or [`close-payment`](recovery.md#close-an-expired-stellar-payment) once signed or when renewal cannot run.

## Renew an unsigned EVM source review

An expired EVM burn or transfer with `reviewRefreshEnabled: true` can use `POST /payments/{id}/transaction/review` with `{"authorizationId":"SAVED_AUTHORIZATION_ID"}` and a UUID `Idempotency-Key`. Route retains the exact transaction bytes and nonce, checks current network state and simulation, and rechecks wallet balances and owner/key limits. No source signature, transaction hash, submission attempt or browser-wallet handoff may exist. Review the returned action before signing it. Existing approval review renewal also supports unsubmitted signed approvals.

For composed payments, refresh expired remaining-route estimates on the parent first; see [unfunded continuation](composed-payments.md#refresh-an-unfunded-transfer). A source transaction already signed or handed to a wallet requires reconciliation rather than replacement.

To abandon an eligible unsigned standalone EVM action, follow [closing an unused EVM protocol action](recovery.md#close-an-unused-evm-protocol-action). `closeEnabled` with `closureRequirement: "finalized-nonce-cancellation"` appears only after the action's review expires. It requires the hash of a finalized transaction from the same wallet at the saved nonce: another transaction that already used the nonce and does not touch the payment's provider, or an owner-authorized zero-value self-transfer. Any other transaction the wallet signed that you report (one at another nonce, or one that touches the provider) is recorded as review evidence (`unclassified-sender-transaction`), and the payment stays in review. Route also searches the sender's provider events for the same payment sent at another nonce; a match, or a payment that cannot be searched (SwapKit native deposits), stays in review. Allbridge payments are searched through the source token's transfers to the bridge. Where Route cannot search or its search cannot complete, `manualCloseEnabled: true` lets a signed-in workspace member [close the payment after a manual check](recovery.md#close-after-manual-check) in the dashboard; API keys cannot. An expired review cannot release an EVM nonce by itself. A cancellation costs native gas; Route does not create or send it automatically.

## Rift variable-output orders

Choose the exact stock, ETF, vault share or crypto asset from `/v1/assets`. Issuer and chain identify its representation; a ticker does not select a token contract or establish its USD price. Fresh exact-asset prices and the saved owner policy are still required before signing.

Use the same quote → payment → prepare → transaction → signature → execute → refresh flow, adding `acceptVariableOutput: true` to `/prepare` alongside `version`, `sender` and `recipient`. This explicitly accepts that Rift chooses its route after funding and has no enforceable output floor or slippage guarantee. The refund wallet is the sender. `minimumReceived` stays null in the quote; the internal preparation marker `0` never denotes a guaranteed receipt.

Route reserves the quote and payment budget before creating the order, captures the provider response, then builds an exact transfer to its deposit address. A timeout retains that reservation. Resume the same payment with the original wallets; any provider retry uses the identical quote and addresses. Captured invalid instructions require review and cannot be replaced automatically.

The funding review lasts five minutes from order creation, even though Rift’s deposit deadline is seven days. Route stops signing and submission when its review expires. Do not send to an expired review or create a replacement for an uncertain transaction.

The documented REST status response has no payout transaction hash. Rift’s `delivered` or `refunded` outcome and actual reported amount remain visible as provider reports. Route marks completion or refund verified only after finalized chain evidence can be attributed to the saved order, recipient and exact asset, with an exclusive payout claim. An arbitrary matching recipient transfer is insufficient. Supply a candidate hash to `/refresh` when available; it is a verification hint, not permission to complete the payment. Some provider payout paths will remain `VERIFICATION_PENDING` until stronger evidence is available.
