Route / developers

NEAR execution reference

This reference covers NEAR 1Click preparation, wallet intent proofs and source transaction signatures. Start with Execute a payment for the shared workflow. Circle, Allbridge, LayerZero and Axelar instead use the protocol execution reference; they do not use the NEAR intent challenge.

Use a supported wallet submission mode and the exact assets offered for this direction. Check compatibility before building signing. The API keeps your provider integration inside Route; your app remains responsible for user authorization and the wallet signer.

Prepare a NEAR deposit and follow its outcome#

This section describes the NEAR preparation flow for supported EVM assets, Stellar classic assets/XLM, native Bitcoin, Solana SOL/original SPL tokens, Fogo FOGO, NEAR NEP-141, TRON TRX/TRC-20, Sui coins, Aptos fungible assets, native Litecoin/Dogecoin and native XRP in both directions. Bitcoin sources require native SegWit or Taproot single-key addresses. See transaction signing for the chain-specific wallet payloads. Use protocol execution for Circle, Allbridge, LayerZero and Axelar. Read /adapters for separate prepareTransaction, preparationCoverage, trackTransfer, walletIntentApproval and walletAuthorization capabilities; preparePayment means saving a review draft, not signing a transfer.

Choose a direct NEAR candidate, save a fresh draft, then call POST /payments/{id}/prepare with another UUID Idempotency-Key and:

{
  "version": 1,
  "sender": "SOURCE_CHAIN_PUBLIC_ADDRESS",
  "recipient": "DESTINATION_CHAIN_PUBLIC_ADDRESS",
  "refundTo": "SOURCE_CHAIN_REFUND_ADDRESS",
  "refundDeadline": "FUTURE_ISO_TIMESTAMP"
}

Use actual public addresses in your application; never submit signing keys. Stellar uses G accounts and an authorized trustline for the selected issued asset; XLM needs no trustline. Muxed/contract wallets need separate builders. The refund deadline must be five minutes to one day ahead. Omit minimumReceived and slippageBps to inherit the selected quote's minimum and tolerance. An explicit minimum may be higher, never lower. An explicit tolerance must match the saved quote; a mismatch returns 409 QUOTE_TERMS_CHANGED before Route reserves an attempt or calls NEAR. To change tolerance, create a fresh quote with slippageBps (an integer from 0–1,000; default 10; any other value, including null, returns 400 INVALID_SLIPPAGE), then create a new payment from that quote. This quote field applies to NEAR (up to 1,000 bps), including its composed legs. Garden is paused and cannot produce new quotes or execute payments. Other adapters retain their protocol-specific minimum rules. The draft, policy and provider connection must still be current.

This is an off-chain executable quote, not a dry quote, but Route does not fund it. Mainnet keys receive mainnet provider instructions. The response has object: "payment_preparation", id, paymentId, state, version, intent, deposit, readiness, sourceHash, tracking, events and lastError. A valid quote's signature binds its request, token amounts, deposit address and any Stellar memo. The full signed quote is retained. deposit.transaction is a chain-specific plan: an EVM transfer, Stellar classic payment, Bitcoin deposit, Solana-family transfer, or NEAR/TRON/Sui/Aptos/Litecoin/Dogecoin/XRP deposit. The later /transaction response contains the actual signable payload; do not sign the deposit plan. The Stellar memo must be used as Memo ID, not memo text.

readiness checks source asset/native balance, actual EVM transfer simulation and gas budget, or Stellar sequence, spendable XLM after reserves, trustline authorization/capacity and transaction fee. Stellar recipient/refund trustlines are checked separately. When those checks pass, readiness.unsignedTransaction contains the chain-specific review payload (EVM fields, Stellar XDR, Bitcoin PSBT or Solana-family serialized transaction) with a bounded review expiry. Preparation does not fund a payment. On a supported path, use wallet intent approval and then the transaction execution sequence to sign, validate and submit the exact transaction. Read the current action flags and blockers.

Policy evaluation uses the fresh executable receipt/minimum, live USD prices and source fee budget. It never assumes a stablecoin equals one USD or substitutes the old comparison fees. Provider ETA starts after deposit confirmation, so the end-to-end delivery policy can remain unknown. Account balances, gas, sequence and pricing can change after observation; a later authorization release must revalidate them. Unsigned transaction preparation does not reserve a wallet nonce or sequence.

The attempt is committed before the provider POST. Identical retries, including after key rotation, return the same attempt. Even a different request key cannot allocate a second deposit for that draft. If the provider times out, rejects or returns invalid instructions, state becomes needs-review (HTTP 202); the attempt and any captured response remain saved. A crashed attempt older than one minute also reads as needs-review. A retry never creates another quote automatically. Ambiguous preparation outcomes still require manual reconciliation; do not automatically create a replacement draft or deposit. Changed request terms on an existing attempt return 409 PREPARATION_EXISTS. Identical omitted or explicit default terms resolve to the same attempt.

Recover a rejected recipient minimum#

An executable quote can move after the dry quote. If its guaranteed recipient amount falls below the saved minimum, preparation returns 202, state: "needs-review", deposit: null and lastError.code: "MINIMUM_OUTPUT_NOT_MET". lastError.details includes requiredMinimum, providerMinimum, providerExpected, asset and slippageBps. Route retains the signed response, blocks funding and never lowers the minimum automatically. Historical captured minimum failures also expose these details when read.

If quoteReviewAvailable is true, read GET /payments/{id}/quote-review. Show the previous and revised minimum, estimated cost and expiry. After explicit payer acceptance, send POST to the same endpoint with a new idempotency key and { "reviewHash": "<returned hash>", "minimumReceived": "<returned minimum>", "maxEstimatedTotalFeeUsd": "<payer-approved USD ceiling>" }. This reuses the original signed allocation and checks that it remains unfunded. Standalone EVM- or Aptos-source payments can accept the revised minimum; later composed legs must also satisfy the original final recipient minimum. No wallet action may already exist. A previously released payment-credit hold is restored at its original rate; insufficient credits leave the review unaccepted. Read the payment again, then obtain separate wallet intent consent and transaction signatures. Aptos review verifies an empty allocation at a fresh committed ledger before any wallet action exists; it does not renew an already signed Aptos transaction. Acceptance never moves funds. The accepted cost ceiling remains enforced at signing and submission.

If canReconcile is true, send POST /payments/{id}/reconcile with {} using payments:write. This performs a read-only status check against the saved signed provider quote. No idempotency key is required and no deposit is allocated. Inspect recovery:

  • canRequote: true, nextAction: "requote": NEAR reports PENDING_DEPOSIT with no funding or transfer evidence, and Route has issued no funding instructions or wallet action. Your app can explicitly request a fresh quote and create a new payment after checking that no transfer was sent outside Route. Use new idempotency keys for those new operations. This is an observation at observedAt, not a guarantee against later external funding.
  • canRequote: false, nextAction: "contact-support": funding or transfer activity is reported. Keep the existing payment for reconciliation; do not fund a replacement.
  • 409 RECONCILIATION_REQUIRED: Route could not verify the saved quote or current status, or the failure is not eligible. Keep the attempt and retry the check later or seek support. ACTION_EXISTS or COMPOSED_RECOVERY_REQUIRED requires recovery of the existing wallet action or parent workflow.

The old attempt remains needs-review. This check does not cancel the provider address, release an existing USD budget reservation, move funds or automatically retry preparation. Multi-step child payments and uncertain/time-out preparations still require manual reconciliation.

If a source transaction already exists outside Route, register it with POST /payments/{id}/submission:

{"version": 3, "sourceHash": "EXACT_SOURCE_TRANSACTION_HASH"}

Use the current preparation version. EVM hashes use 0x plus 64 hex digits; Stellar accepts 64 hex digits (an optional 0x prefix is normalized away). Bitcoin uses its 64-digit hex transaction ID; Solana and Fogo use the base58 transaction signature. NEAR and Sui use base58 transaction hashes; TRON uses 64 lowercase hex digits and Aptos uses 0x plus 64 hex digits. Litecoin, Dogecoin and XRP use 64 hex digits, normalized to lowercase. Repeating the same hash is safe; replacing it is rejected. Registering a hash is metadata only: it does not prove funds were sent. Registration remains possible after quote expiry for recovery. The same source-network hash cannot be assigned to another payment within that project. Provider-verified deposit identities are globally unique, so a caller’s unverified hash cannot block a different customer’s payment.

Call POST /payments/{id}/refresh with {} for a manual NEAR status refresh. Stellar status requests include both the deposit address and memo. Route verifies the signed quote association, exact source sender/deposit/asset, Stellar memo, amount, recipient receipt or refund, and chain finality. A provider SUCCESS becomes completed only with verified source and recipient receipts; a provider REFUNDED needs the original asset's refund receipt. Partial/excess deposits and unverified receipts remain unresolved. Missing RPC data never causes a resubmission. Stellar classic payment/path-payment receipts and committed Soroban token events are verified against the exact asset, envelope, ledger, recipient and net credit. Unsupported or unverified receipt forms remain unresolved.

A provider or policy can be disabled after funds are sent without preventing tracking using a still-valid saved credential. Access is checked on every request and again before returning observations. GET /payments/{id} includes the same nested preparation; draft status stays draft/cancelled, while preparation.tracking.status carries the observed transfer stage.

Release and readiness#

Complete source wallet setup before the final send review. NEAR's direct EVM deposits do not require an ERC-20 spender allowance. For the other protocol routes, handle any required token approval and one successful block confirmation first, then review fresh transfer terms; do not hold a short-lived transfer review open while waiting for approval.

GET /v1/payments/{id}/transaction returns {transaction: OBJECT_OR_NULL, executionEnabled: BOOLEAN, reviewRefreshEnabled: BOOLEAN}. Read this live flag; the service can pause submission. The adapter catalog advertises transactionHandoff for NEAR to distinguish implemented code from enabled execution. Do not use that capability alone to show a send button. Mutating transaction endpoints return 409 EXECUTION_UNAVAILABLE while the release gate is closed.

All wallet, exact-asset, fee, USD amount, provider, capacity and owner-selected delivery checks must pass. NEAR reports timing after deposit confirmation. That partial timing cannot satisfy a saved delivery limit. An owner may explicitly save maxSeconds: null with priority: "cost"; this removes the deadline without presenting partial timing as full arrival. Speed ranking still requires comparable full-arrival timing. Existing saved policies are never modified by activation.

PAYMENT_EXECUTION_ENABLED is an operational pause switch. Enabling it does not bypass an unsupported adapter, policy, wallet approval, signature or fresh transaction check. There is no operator-selected project allowlist or dollar cap. Owners choose project and API-key limits.

Wallet intent approvals#

NEAR requires an off-chain proof of the reviewed payment terms before a separate transaction signature. It is not an ERC-20 token allowance.

Integrate through your backend#

Keep the Route API key on your server. Authenticate your own customer and bind their order to the correct payment before exposing a challenge to their browser. The signing domain identifies the Route application origin. Customers should review that origin and the exact payment details in their wallet.

  1. Save a quote draft and prepare its deposit using the customer API. Use the returned preparation version below.
  2. Request a challenge with POST /v1/payments/{id}/wallet-approval, a UUID Idempotency-Key and {"version": 1}. Scope: payments:write. The response is the approval object directly; HTTP 201 means created and 200 means an identical retry.
  3. Send its unmodified challenge.signing payload to the sender's wallet. The sender must match the preparation. Do not ask the wallet to sign an unsigned transaction at this stage.
  4. Send POST /v1/payments/{id}/wallet-approval/confirm with {"approvalId":"UUID","signature":"WALLET_RESULT"}. Scope: payments:write. Route verifies the saved challenge, rechecks access and restrictions, reads current readiness and records proof and that assessment atomically.
  5. Read GET /v1/payments/{id}/wallet-approval with payments:read. It returns {"approval": OBJECT_OR_NULL}. Payment/preparation reads also include walletApproval. Revoke with POST /v1/payments/{id}/wallet-approval/revoke and {"approvalId":"UUID"} using payments:write.

The server-side example client includes getWalletApproval, requestWalletApproval, confirmWalletApproval and revokeWalletApproval.

Signing methods#

Source Payload Returned signature
Supported EVM networks eth_signTypedData_v4, params [challenge.signer, JSON.stringify(challenge.signing.typedData)]; use the returned typedData.domain.chainId 65-byte 0x hexadecimal signature
Bitcoin bip322_signMessage with the exact UTF-8 challenge.signing.message Base64 BIP322 simple witness proof; optional smp prefix
Solana / Fogo solana_signMessage with the exact UTF-8 message Base64 encoding of the 64-byte Ed25519 signature
Stellar Freighter signMessage(challenge.signing.message, {address: challenge.signer, networkPassphrase: challenge.signing.networkPassphrase}); public Stellar network Canonical base64 encoding of the 64-byte signature; encode a returned byte array once

EVM networks use EIP-712. Stellar follows SEP-53 through Freighter message signing. Pass the Stellar message exactly as provided: Freighter adds the standard prefix itself. Do not add that prefix a second time, decode the message as transaction XDR, or sign its digest as a transaction.

The signed details bind the project, payment, preparation, networks, exact assets, amount, minimum receipt, sender, recipient, refund details, deposit address/memo, policy version, random nonce and expiry. An intent digest also binds the signed provider quote, transaction plan, provider connection version and saved API-key restrictions. The server accepts only the immutable challenge it issued; caller-defined challenge fields are rejected.

Status, expiry and retries#

status is awaiting-signature, approved, revoked, expired or stale. Inspect the current status rather than treating signatureVerified as permission to proceed. That boolean records historical proof and can remain true after expiry or revocation. assessment is the most recently saved confirmation assessment, or the original assessment before confirmation; it is not continuously refreshed. Proof responses omit the raw stored signature.

Challenges expire at the earlier of five minutes after creation and the deposit's existing review expiry, rounded down to a whole second. New NEAR deposit reviews allow up to five minutes, within the provider/refund deadlines; always use the returned deadline. A challenge never extends a deposit's lifetime. Changes to policy/provider configuration, a submitted source transaction or an unresolved preparation invalidate further approval. A signed but unsubmitted EVM transaction can receive new consent through deposit review renewal.

Creation retries require the same UUID and version and return the original record, even if it has since expired. Reusing that UUID with different input returns IDEMPOTENCY_CONFLICT. Confirmation retries with the same signature return the existing proof; a different signature cannot replace it. Revocation is repeatable. One non-revoked record is allowed per preparation: revoke it explicitly before creating a replacement, and only while the original deposit review is still valid. For an expired unsubmitted EVM deposit, use deposit review renewal. It creates a new bound challenge and preserves any existing transaction; confirm that challenge instead of creating another. Native NEAR allocations without an existing transaction action can also renew through that endpoint; other source families require their documented recovery flow. Requesting approval never allocates a replacement provider deposit.

Invalid signatures, wrong projects, insufficient scope and stale preparation versions are rejected. Mutation attempts are limited to 30 per payment per minute, including invalid signatures, in addition to customer API limits. Access, provider/policy state, key restrictions and expiry are checked again after external readiness reads so revocation during those reads takes effect.

Limits of an approval#

mode is intent-only; transactionSigningEnabled and executionEnabled are always false. An approval can record consent while wallet balance, gas, delivery estimates or policy readiness remain blocked. Those blockers stay visible and are not waived by a signature. Key allowlists and applicable USD payment limits still reject prohibited approvals.

The proof establishes possession of the selected supported wallet key. It does not establish current multisig thresholds, smart-wallet authority, sufficient balances or a usable transaction. No wallet nonce/sequence is reserved, no token permit is granted and no budget reservation is increased or released. Existing preparation-time budget holds remain in place.

The transaction handoff implements fresh state/pricing checks, budget increases, wallet-sequence coordination, exact signature verification and one saved submission attempt. It is enabled for supported mainnet paths. Automatic transaction replacement is not supported. Use the recovery playbook for uncertain or expired actions. Circle, Allbridge, LayerZero and Axelar use exact transaction authorization instead of this NEAR intent challenge.

API sequence#

Keep the Route API key on your backend. All mutations below require payments:write; reads require payments:read. Bind each payment to the authenticated customer in your own application. Route keys must never be put in the browser.

Method Path Body / result
GET /v1/payments/{id}/transaction Latest saved transaction and release flag
POST /v1/payments/{id}/transaction {"approvalId":"UUID","version":3} plus UUID Idempotency-Key; version is the current preparation version
POST /v1/payments/{id}/transaction/signature {"authorizationId":"UUID","signedTransaction":"SIGNED_BYTES"}
POST /v1/payments/{id}/transaction/review Current preparation version, optional saved authorizationId, UUID Idempotency-Key; returns a new wallet intent challenge
POST /v1/payments/{id}/execute {"authorizationId":"UUID"}; requests one submission of the already verified bytes

Creation returns the transaction object directly (201, or 200 for a matching retry). It contains id, approvalId, state, expiresAt, expired, transaction, transactionDigest, sourceHash, signingEnabled, submissionEnabled, assessment, submissionAssessment, lastError, createdAt, submittedAt and executionEnabled. Read the current flags and expiry before interacting with a wallet. The raw saved signature/envelope is never returned by reads.

The server-side client adds getTransaction, prepareTransaction, saveTransactionSignature and executePayment. The dashboard separates transaction review, signing and submission, with Route-styled consent controls and network/account checks. Reopening a saved transaction reads it before offering another action.

Refresh an expired NEAR deposit review#

All released providers now use a maximum five-minute payment review; see protocol review windows. New NEAR preparations allow up to five minutes for review, bounded by the signed provider deadlines and the payment’s refund deadline. Always read the returned expiresAt; wallet or provider limits can shorten the window.

For a native NEAR-chain source before any transaction action exists, use this same endpoint with the current preparation version and omit authorizationId. Route must verify a pending, empty provider allocation, zero token balance at both final and optimistic chain state, and fresh wallet, fee, USD and policy checks. The new challenge uses NEP-413 (near_signMessage). Confirm it before building the first transaction. Original provider/refund deadlines still apply. Once a NEAR transaction action has been created, this endpoint cannot renew it—even if its signature has not reached Route; preserve that action for reconciliation.

For an unsubmitted EVM-source NEAR deposit:

  1. Retrieve both GET /v1/payments/{id}/preparation and GET /v1/payments/{id}/transaction. A failed signature request does not mean there is no saved transaction. Keep its ID, bytes and reserved nonce.
  2. When preparation returns reviewRefreshEnabled: true, call POST /v1/payments/{id}/transaction/review with {"version": CURRENT_PREPARATION_VERSION, "authorizationId": "SAVED_TRANSACTION_ID"} and a new UUID Idempotency-Key. Omit authorizationId only if no transaction exists. Reuse the same body and key after a timeout.
  3. The deposit_review response contains a fresh walletApproval, expiresAt, current preparation version, and the existing transaction when present. Review and sign the new wallet intent challenge, then confirm it through /wallet-approval/confirm. The previous approval is revoked atomically; it cannot authorize the renewed review.
  4. Retrieve the transaction again. If one already exists, use that same ID and payload. If none exists, request /transaction with the new approval ID and preparation version. Respect the current signingEnabled and submissionEnabled flags. A saved signature remains unchanged; submit it only after fresh consent and checks. A locally held signature may be sent to /transaction/signature only if it exactly matches the saved transaction.

Renewal checks the provider’s current status and original signed quote, deposit balance, any known source hash, latest/pending wallet nonce, recipient, balances, fees, fresh USD prices and owner/key policy. Provider status and source activity are checked again before signing/submission. It preserves the original provider quote timestamp, minimum, recipient, deposit address, transaction bytes, signature and nonce reservation. It is a renewed review of the same terms, not a new quote or deposit, and it never submits a transaction.

Renewal stops at the original provider/refund deadlines. Funding activity, a known source transaction, nonce changes, insufficient saved gas budget, changed settings or failed policy checks block recovery. submitting, submitted and submission-unknown attempts must be tracked. Stellar, Bitcoin and Solana-source deposit renewal is not supported by this endpoint; their transaction validity rules require separate recovery. Do not create a replacement payment while an existing action remains unresolved.

TRANSACTION_EXPIRED includes details.action: "refresh-deposit-review"; eligibility is confirmed by the preparation. DEPOSIT_ALREADY_ACTIVE means track existing activity; DEPOSIT_NONCE_CHANGED requires wallet reconciliation. VERSION_CONFLICT requires reloading preparation. For reviewed transactions, the outer transaction object’s expiresAt is the current Route review deadline. The nested original unsigned envelope and its historical metadata remain immutable.

The example client exposes refreshDepositReview(id, version, authorizationId, idempotencyKey). Review creation returns 201; identical retries return 200 without extending that review again.

When submission checks block a signed transaction#

signed means Route has verified and saved the transaction signature. It does not prove a network submission. Route performs fresh wallet, gas, price and policy checks before claiming the submission. A refusal at that stage leaves the transaction signed and unsubmitted.

For NEAR, TRANSACTION_NOT_READY and TRANSACTION_PRICE_EXPIRED include error.details.blockers: an array of {id, status, message}, plus checkedAt and a suggested action. Display the individual messages. unknown means required evidence is unavailable; fail means a check did not pass. Neither permits submission. For example, an unavailable source-wallet read can also leave the cost check incomplete. Do not interpret every blocker as an insufficient balance or change the owner's policy automatically.

When an existing transaction fails this readiness assessment, Route retains the latest diagnostic in transaction.lastError, including its phase and observation time. It does not change the signed bytes, reserved nonce or submission evidence. Historical failures from before this diagnostic support may have no saved detail. Successful review renewal, signature acceptance or submission preflight clears the previous diagnostic, except unresolved review evidence (below), which the database keeps as lastError. lastError is a last observation, not continuous provider health.

If Route has recorded evidence that the saved EVM payment call may already have executed, it never submits the saved signature and never hands the saved call to the wallet, because both transfers could execute. That evidence is a wallet-altered copy of the call (altered-payment, observed by wallet handoff recovery, a source cancellation, or the close of an unused EVM action, including a close after manual check), or the same payment sent or queued at another nonce (reason: "equivalent-execution", found by the search those closes and cancellations run, or reported to any of them as a hash: a copy the wallet signed with other fees, another value or envelope type, or a call to the payment's provider contracts, even if it is still queued behind the unused saved nonce; for a NEAR source, any transfer to its 1Click deposit address), or any other transaction the wallet signed that was reported for the payment and is neither the saved transaction nor a recognized cancellation (reason: "unclassified-sender-transaction", at any nonce and in any envelope: Route fails closed because it cannot establish that it is not this payment). A reported transaction the wallet did not verifiably sign (a relayed or sponsored smart-account execution, an L2 system or deposit transaction, an unsigned or unknown envelope, another key) is evidence too (reason: "unclassified-transaction"), and every reported hash is recorded before Route reads it: one the network does not show yet, or cannot read, stays recorded as reported-transaction and blocks until a later check with the same hash classifies or clears it (freeze on report, see recovery). This holds on every EVM network a NEAR source allows (Optimism, Polygon, BNB Chain, Avalanche, Gnosis and the others), not only Ethereum, Base and Arbitrum, where a saved-signature cancellation can close; a report on another network is inspected and recorded, but never closes. NEAR evidence has no attribution path: an operator reviews these payments. Every observation is recorded in an append-only evidence journal with the action's lastError, in one transaction, and the database reads that journal. Only same-payment evidence (not a wallet-altered copy) of a protocol payment that Route later attributes to another of its payments is resolved (see re-attribution). /execute and a new wallet handoff at /transaction/broadcast return 409 WALLET_TRANSACTION_REVIEW_REQUIRED with the evidence in error.details before any network read or send, whatever the account nonce shows: the altered copy can be queued at a later nonce while the saved nonce is still next. The handoff reserves nothing and returns no eth_sendTransaction params. An existing handoff is kept and replayed, and nothing is sent, but with walletBroadcast.method: null, empty params and a review notice. The transaction stays ready or signed, keeps the evidence as lastError, reports walletBroadcastAvailable, signingEnabled and submissionEnabled as false (GET transaction adds actionBlocker.code: "WALLET_TRANSACTION_REVIEW_REQUIRED"), and next-action is review-required. A recovery running at the same time either commits first, so the submission or handoff is refused, or waits until it is saved. Evidence recorded while Route's own send of the saved transaction is in flight stays the lastError; if that send's outcome is uncertain, the transaction is submission-unknown and the evidence carries the send's SUBMISSION_UNKNOWN diagnostic as lastError.submission. Track the saved hash; never resend. The database refuses the same submission or handoff. Confirming the exact original of an earlier wallet handoff at /transaction/broadcast-confirm still registers it for tracking; that is not a Route send, and the review remains. While a recovery, cancellation or close check for the action is reading the network, /execute and a new handoff return 409 WALLET_EVIDENCE_CHECK_IN_PROGRESS (details.retryable: true, details.retryAfterSeconds) before any network read, so nothing is sent between what the check observes and its record; the state lapses after 2 minutes. An observation is recorded even if the caller's access ended during the check, or if the check outlived that 2-minute state and a submission or handoff started meanwhile (see recovery). A same-payment copy that nobody reports to Route (broadcast from another wallet, or never reported at recovery, confirmation, cancellation or close) cannot be seen, as for a transaction queued behind a nonce gap.

Retrieve the saved transaction after a refusal or interrupted request. If it remains signed and its review is current, resolve the reported blocker and retry /execute with the same authorizationId after backoff and explicit user consent. If the review has expired, follow deposit review recovery: request a new review, sign and confirm the new wallet intent, then submit the existing transaction. Do not request another transaction signature when Route already has it. GET transaction preserves recovery instructions in transaction.actionBlocker.details, including action: "refresh-deposit-review".

If the state is submitting, submitted or submission-unknown, track the existing hash; do not create or submit a replacement. NEAR EVM wallet reads can use reviewed fallback RPC endpoints after transient errors, with chain and observed-block verification. This fallback applies to reads and simulations only; broadcasts remain single-attempt.

Chain-specific signing#

  • Stellar: transaction.family is stellar. Ask Freighter to signTransaction(transaction.xdr, {address: APPROVED_SENDER, networkPassphrase: transaction.networkPassphrase}). Send its signedTxXdr to the signature endpoint. Route requires the exact classic-payment body, asset, deposit account, Memo ID, amount, fee, sequence and time bounds, with one valid sender signature. The current account signer weight must satisfy its medium threshold. Multisig collection, fee bumps, muxed accounts and contract-wallet signing need separate flows.
  • EVM networks: transaction.family is evm. A compatible external signer signs transaction.transaction and returns the serialized transaction. Current preparation uses an EIP-155-protected legacy transaction on the exact chain ID returned by Route. Route checks recovered sender, token calldata, destination, value, nonce, gas limit and gas price exactly. Other transaction types require their own reviewed builder. For the separate wallet submission handoff, a wallet may lower the gas limit within the saved ceiling; gas price and all payment fields remain exact.

The browser helper uses eth_signTransaction only when the connected wallet supports returning a signed transaction without broadcasting. Many wallet integrations require a different signing workflow; unsupported methods produce an explicit error. There is no fallback to eth_sendTransaction because that would broadcast before Route verified and recorded the signed payment. Apps that need wallet submission must choose the explicit EVM wallet handoff before opening the wallet. The dashboard browser helper remains sign-only. A backend/HSM signer may supply the signed transaction through the same API. Route never accepts private keys.

Freighter reference: signTransaction. The saved transaction contains mainnet network identifiers. Use a mainnet key for this flow; the separate testnet API prepares test-network transactions.

Bitcoin and Solana signing#

For Bitcoin, sign the approval challenge’s UTF-8 message using BIP322 simple (bip322_signMessage). Return the base64 witness proof, optionally with the standard smp prefix. transaction.family is bitcoin; give the base64 transaction.psbt to the wallet. Submit a finalized/signed base64 PSBT or raw transaction hex as signedTransaction. Route independently checks every signature, input, deposit output, change output and fee. Only SIGHASH_ALL or Taproot SIGHASH_DEFAULT is accepted. The dashboard supports UniSat’s sign-only PSBT flow. Native SegWit and Taproot single-key sources are supported; legacy, multisig and script-path spends need separate builders.

For Solana and Fogo, sign the challenge’s UTF-8 message using solana_signMessage and return the 64-byte signature as base64. transaction.family is solana; deserialize transaction.serialized (base64), sign without broadcasting and return the signed transaction as base64. Route binds the full message, sole signer/fee payer, mainnet blockhash and expiry. Fees include priority fees and any required destination associated-token-account rent. The saved blockhash cannot be replaced after signing. SOL and original SPL transfers from the sender’s associated token account are supported. Token-2022 extensions are rejected pending a dedicated builder. Fogo uses the same transaction family with network: "fogo", its own pinned mainnet RPC/genesis and FOGO fees. Sign with a compatible SVM wallet or external signer; Fogo Sessions and session/paymaster signatures are not supported.

Both families use the same approval → transaction → signature → execute endpoints. The caller chooses the assets, amount and recipient; the API key selects its assigned routing policy. The Route API never receives a private key. feeMinor uses feeDecimals (8 for BTC, 9 for SOL and FOGO).

NEAR, TRON, Sui and Aptos signing#

Use the exact challenge.signing method and return the proof in the existing signature string. These flows use sign-only external signers; Route submits the saved transaction once after verification. No private keys are sent to Route.

Family Intent proof (signature) Transaction proof (signedTransaction)
near JSON string with publicKey (ed25519:…) and base64 signature, signing the NEP-413 message, base64 nonce and recipient supplied by Route Base64 Borsh SignedTransaction, built from transaction.unsignedBase64
tron 0x-prefixed TIP-191 signature over the supplied message JSON string containing the exact transaction.transaction plus its single owner signature
sui Serialized Sui personal-message signature JSON string { "bytes": "UNCHANGED_UNSIGNED_BASE64", "signature": "SUI_SERIALIZED_SIGNATURE" }
aptos JSON string with hex publicKey and hex signature over the exact UTF-8 message Base64 legacy Ed25519 signed BCS transaction built from transaction.unsignedBase64

For NEAR, the source needs one full-access Ed25519 key, sufficient token balance and spendable NEAR. Route includes storage_deposit before ft_transfer when the provider deposit address needs token storage registration; the review's fee reserve includes this deposit. Destination and refund wallets need existing accounts and token registration. NEP-145 defines the registration cost.

TRON checks owner permissions, token balance, simulated transfer energy, bandwidth and the signed canonical block reference. Sui simulates the exact transfer, verifies object ownership/version, and reserves each selected object version across Route projects. Aptos checks the current authentication key, sequence and fee reserve and simulates the transfer. Aptos raw-message proof is a backend signer format; ordinary Aptos browser-wallet signMessage adds an envelope and cannot be substituted.

Expiry never authorizes a replacement. These four families do not yet support automatic source-action renewal: preserve the saved bytes/hash and use tracking and recovery. An uncertain submission must be reconciled before any new action. Source and recipient verification requires NEAR final outcomes, TRON solidified receipts, Sui checkpointed transactions or committed Aptos transactions plus exact token credit.

Fresh checks and payment limits#

Route checks the current approval, project access, provider/policy versions, exact recipient and inherited API-key restrictions before and after external reads. It rechecks balances, signer authority, nonce/sequence, fees and USD prices before handoff, signature acceptance and submission. Normal fee movements within the saved maximum preserve the exact transaction, with its full maximum revalued against policy. Insufficient saved gas or changed wallet sequences block the attempt; Route does not silently rebuild a transaction for another signature.

Rolling USD holds are adjusted in the same database transaction as the accepted step. New applicable keys reserve capacity, and existing holds can increase to cover a higher source valuation. Increases have append-only evidence. Holds do not automatically decrease when prices fall, on expiry or on a failed request. An over-limit increase rolls back the entire step. These remain source-value risk limits, not final accounting valuations.

One active source-deposit authorization is allowed per NEAR provider preparation. An eligible expired NEAR Stellar source can be renewed against the same provider deposit after verified expiry and an unused sequence; the previous signed authorization remains in history. Protocol preparations instead hold separately authorized approval, transfer and mint actions. A globally unique (network, sender, nonce/sequence) prevents two Route projects using the same wallet slot. Bitcoin additionally reserves every (txid, outputIndex) across projects. Sui reserves every selected (objectId, version), including its gas coin, across projects. Solana reserves the immutable message identity; it does not have an EVM-style account nonce. Reservations are not released automatically on expiry. A verified customer Stellar mint renewal or NEAR Stellar source renewal transfers its existing sequence reservation to the replacement action while preserving both actions. This is coordination inside Route; it cannot prevent the wallet being used outside Route. Route does not reserve liquidity or an on-chain nonce. An expired/ambiguous attempt does not automatically release its wallet slot or budget holds.

Retries and uncertain outcomes#

States are ready, signed, submitting, submitted and submission-unknown. These describe the source submission attempt; final delivery/refund still comes from the payment's verified tracking evidence. submitted means the endpoint acknowledged the matching hash, not that the recipient was paid.

  • Matching creation retries return the same transaction. Changed approval/version cannot replace it. A project request key cannot be reused for a different attempt.
  • Signature acceptance fixes the exact bytes and expected hash, and registers that hash for existing source tracking. A signature alone does not prove the transaction reached the network. Matching signature retries return the saved result; a different signature cannot replace it.
  • Submission commits submitting, the signed bytes, expected hash and fresh assessment before making one network request. Concurrent calls and later retries return the existing attempt instead of making another send.
  • Timeout, malformed response, error or a mismatched returned hash produces submission-unknown. If the process stops after claiming the attempt, it may remain submitting. In either case use the existing hash and /refresh or scheduled tracking. Never allocate another deposit or send a replacement automatically.
  • Revocation before the submission claim prevents the send. Revocation after that committed claim cannot recall an in-flight request. Expiry/revocation cannot invalidate a signed Ethereum transaction that somebody already possesses; Ethereum legacy transactions have no built-in expiry. Keep signed bytes private.

These are deliberately conservative recovery rules. Automated resubmission, replacement transactions, fee bumps and operator release of uncertain wallet slots/holds are not implemented. An unacknowledged send that never reached the network may require manual reconciliation; the app must not call it completed or failed from a timeout alone. See Stellar's submission error handling for why a timeout is not proof of failure.

Acceptance and coverage#

EVM sources support a compatible sign-only wallet/backend signer or the explicit wallet submission handoff; Freighter can sign Stellar XDR. Automatic replacement transactions are not released. Review renewal is limited to the unsubmitted EVM deposits described above. The other four adapters have their own protocol actions and settlement verification. Read GET /adapters and each quote's execution object instead of assuming quote coverage implies execution coverage.

NEAR can also deliver from the supported sources to native Bitcoin or Solana catalog assets. Bitcoin uses checksum-validated mainnet addresses, exact net outputs and six confirmations against the canonical block. Solana uses the mainnet genesis identity, finalized transaction metadata and exact recipient/mint net credit. Bitcoin and Solana now also have source builders, exact-signature checks, fixed-endpoint submission and source receipt verification. Bitcoin sources accept P2WPKH and Taproot key-path single-key signing. Solana sources accept SOL and original SPL tokens using the sender’s associated token account; Token-2022 extensions and multisig require separate builders.

Litecoin, Dogecoin and XRP signing#

Your app supplies a network-specific sign-only signer. These source families use the same approval → transaction → signature → execute flow. Always check the returned readiness and signing flags.

Network Source account Intent proof Signed transaction
Litecoin (ltc) Native SegWit P2WPKH, single compressed key utxo_signMessage: base64 compact signature using the Litecoin signed-message prefix and BIP137 native-SegWit header Sign transaction.psbt; return signed/finalized base64 PSBT or raw hex.
Dogecoin (doge) P2PKH, single compressed key utxo_signMessage: base64 compact signature using the Dogecoin signed-message prefix and compressed P2PKH header Sign transaction.psbt; return signed/finalized base64 PSBT or raw hex.
XRP (xrp) Existing classic account with enabled master key xrp_signMessage: sign UTF-8 Route XRP intent:\n followed by the exact supplied message. Return a JSON string containing publicKey and hex signature. Sign the supplied transaction.transaction JSON without autofilling or changing it. Return canonical signed hex.

For Litecoin and Dogecoin, every signature must commit to all inputs and outputs (SIGHASH_ALL). Route verifies each previous output, exact deposit, sender change and mining-fee budget. Inputs remain reserved to their saved action even after review expiry or an uncertain submission. Both source and destination require six canonical confirmations. Mining-reward inputs and Litecoin MWEB are outside this signing flow.

For XRP, Route preserves the payment amount in drops, fee, sequence and LastLedgerSequence. Native XRP delivery is verified from a validated ledger and the actual delivered_amount. Partial payments, issued currencies, destination tags, deposit authorization, account activation, regular-key signing and multisig are outside this flow. Recipients and refund accounts must already exist and accept untagged native XRP. The sender must retain its account reserve.

Do not broadcast from the signer or replace an expired action. Preserve saved signatures and hashes and use tracking/recovery; automatic source-action renewal is not supported for these three families. Endpoint unavailability keeps the relevant readiness checks unavailable and prevents signing.

Links from earlier guides

This section is now in NEAR execution.

This section is now in Track and recover.