Route / developers

Track and recover

Documentation revision 2026-09-27. Every URL below is relative to /v1. Keep the business order, network, quote ID, payment ID, preparation version, authorization ID, request key, exact request body and response request ID together. Keep signatures and secrets out of application logs.

Read GET /payments/{id}/next-action for the normalized next step and responsible actor. It observes saved state; it does not perform reconciliation or refresh provider/chain evidence itself. review-required pauses automatic execution. Preserve any in-flight operation and its original request identity before acting on a newer snapshot.

A transport error does not tell you whether a mutation committed. Read the existing payment and transaction before deciding to retry. sourceHash can be calculated when signing; its presence is not proof of broadcast. Once a transaction is submitted or uncertain, quote/review expiry is no reason to fund again.

Payment states#

paymentState is the normalized observed state alongside the existing draft status. This vocabulary is shared by single-transfer, composed and testnet payments. Draft status, provider tracking.status and composed workflow.state remain available as detailed, backward-compatible fields; use paymentState for your payment-level display. A provider success message alone cannot mark settlement complete.

Payment state Meaning
DRAFT / ARCHIVED / CANCELLED Unprepared, archived, or safely closed payment.
PREPARING / AWAITING_ACTION Preparation is running, or the next wallet action is available.
WALLET_SUBMISSION_UNKNOWN Route handed an action to the wallet but has not verified its transaction hash. It may already be broadcast; recover and report the existing hash, never send again automatically.
INTERMEDIATE_HELD Earlier transfers are final and the composed payment is ready for its next transfer; funds are in the intermediate wallet.
REQUIRES_ATTENTION / FAILED Evidence or readiness needs review, or a source transfer provably reverted. Any other tracking error, such as a receipt that does not prove the saved action or a removed provider connection, is kept in preparation.lastError and reads as this state until a later observation succeeds; a temporary outage in between does not replace it. Follow next-action.
SOURCE_PENDING A source submission is recorded; source confirmation or finality is pending, with no verified delivery or refund yet.
DESTINATION_PENDING The source is verified and final; destination verification is still pending.
VERIFICATION_PENDING Receipt verification is incomplete, including temporarily unavailable chain data. A temporary receipt, provider-status or destination-lookup outage (preparation.lastError.code TRACKING_UNAVAILABLE, PROVIDER_TRACKING_UNAVAILABLE or DESTINATION_DISCOVERY_UNAVAILABLE) shows this state instead of a pending source or destination while tracking retries, and emits no webhook. An uncertain send, a wallet handoff or a required wallet action keeps its own state. Read preparation.tracking.message or preparation.lastError.message for the reason.
DELIVERED_PENDING_FINALITY Exact source and recipient receipts are verified, but at least one chain has not reached finality. Display “Delivered — awaiting finality.”
REFUND_PENDING_FINALITY Exact source and refund receipts are verified, but finality is still pending.
COMPLETED / REFUNDED Both required receipts are verified and final.

For example, Stellar can have a final recipient receipt while Ethereum's source receipt still awaits finality. This is delivery awaiting finality, not a missing source transfer. Continue tracking the same payment without requesting another signature or sending again. preparation.tracking.status remains verification-pending until finality; the individual sourceVerified, sourceFinalized, destinationVerified, destinationFinalized, refundVerified and refundFinalized flags give the precise evidence state. NEAR EVM receipt reads use reviewed fallback endpoints after temporary transport, rate-limit, access or lagging-finality observations. Route re-verifies the complete receipt, or corroborates an already verified receipt’s exact canonical block hash on the same chain against a current finalized checkpoint. Invalid or mismatched chain evidence never permits completion.

Bitcoin confirmation and delivery#

Track these observations separately:

  1. Submitted: Route has recorded the Bitcoin transaction ID. This is not proof of inclusion.
  2. Source verified: the exact deposit is included in a canonical Bitcoin block. NEAR may still report PENDING_DEPOSIT until it recognizes the funding; the initial confirmation is not an end-to-end delivery estimate.
  3. Delivery verified: Route has verified the destination transaction, exact asset, recipient and amount. paymentState: "DELIVERED_PENDING_FINALITY" means that delivery is proven but source or destination finality is still pending.
  4. Completed: both receipts are verified and final. Route requires six Bitcoin confirmations for Bitcoin source or destination finality. Its wallet builder can spend a confirmed canonical UTXO before six confirmations; that does not change the tracking rule. The composed-payment API separately requires finalized intermediate settlement.

Read the same payment and refresh its existing preparation. A quote or signing-review expiry after submission does not undo the transaction or authorize another deposit. Provider estimates start after deposit confirmation and do not guarantee Bitcoin block timing. No additional source transfer is needed simply because provider recognition or finality is pending.

For Bitcoin destinations, ordinary delivery verification compares the canonical recipient net credit with NEAR's reported amount exactly. Ethereum ERC-20 → native Bitcoin fee-reserve returns can also settle when Route verifies the complete intent/withdrawal/output proof. Every new BTC delivery completion requires a persisted exclusive payout claim. Read tracking.bitcoinPayout and tracking.received for the actual receipt; the original provider amount remains unchanged. Other unresolved amount mismatches stay VERIFICATION_PENDING. Preserve the same payment and use normal refresh; neither provider success nor a wallet balance increase establishes settlement. See Bitcoin payout reconciliation and the funded example.

Read saved recovery evidence#

Use GET /payments/{id}/recovery with payments:read. It is available on both networks; select the correct network key and Route-Network header. The report belongs to the authenticated project and policy. A composed report names the root paymentId and activePaymentId, and can reference the next step on the active child.

For a composed payment, completion of one child does not establish completion of the whole route. Follow the root payment's next action; it may require refreshing the workflow or advancing to another leg. A verified refund of a later leg returns funds on that leg's source network, not necessarily the original source network or asset. The root recovery report identifies this as intermediate-held with operator review, while the workflow shows needs-review. Inspect evidence.refund and the child payment's asset and refund instructions before arranging any further transfer. Do not resend the original source payment. A first-leg refund is reported as refunded once its source and refund receipts are verified and final.

import {createRouteSDK} from './route-sdk.mjs';

const route = createRouteSDK({
  baseUrl: 'https://route.click/v1',
  apiKey: process.env.ROUTE_API_KEY,
  network: 'mainnet'
});
const report = await route.getRecovery(savedPaymentId);
// Present report.summary, report.owner and report.requiredEvidence for review.
// This GET does not execute report.nextStep.operation.

savedPaymentId is your existing payment ID. The SDK validates response identity, network, schema version, nested types and the report's closed set of safe fields. An unsupported or inconsistent report throws INVALID_RECOVERY_REPORT; keep the original payment and request review. See the complete PaymentRecoveryReport schema in mainnet OpenAPI and testnet OpenAPI, and the generated response examples.

Report field Meaning
outcome, owner, summary Saved recovery classification, responsible party and explanation
paymentId, activePaymentId, preparationId, authorizationId References to preserve; preparation or authorization may be null
generatedAt, evidence.lastObservedAt Report creation time versus the last saved tracking observation; neither guarantees fresh chain data
nextStep An action reference without a wallet payload. Read current next-action and detailed transaction checks before authorizing it
evidence.source, destination, refund Saved hash, verification, finality and inclusion time for each stage
evidence.transactions Saved action identity, state, submission-attempt flag and receipt observation. Testnet includes its latest action, not full history
evidence.settlementDiscrepancies Exact provider and recipient amounts, associated transaction and canonical block evidence
requiredEvidence What still needs to be verified before the issue can be resolved
reservations Existing wallet sequence/Bitcoin input, API spending-limit and Route-credit accounting observations
safety automaticReplacementAllowed and reservationReleaseAllowed are always false

An unobserved transaction receipt has receipt.observed: false and nullable flags. Null means the saved view lacks that evidence; it does not prove that a transaction was absent or failed. Separate source/destination tracking can already contain verified evidence. Similarly, submissionAttempted: null is unknown rather than proof that nothing was broadcast.

Mainnet reads existing reservation records and returns up to 150 items per group, with truncated: true when more were omitted. Testnet returns observed: false, items: [] and truncated: false for all three groups. Do not interpret an unobserved empty list as proof that a wallet nonce or input is available. Reading the report cannot release a reservation or adjust billing. API-limit commitment records source funding; it is separate from verified destination completion and Route usage credits.

Outcome Interpretation
no-action-issued No wallet action or provider preparation is recorded for this draft
awaiting-wallet-action Continue only with the saved next step and its current checks
unsigned-review-expired Renew only through a same-payment operation explicitly offered for that action
signed-not-submitted A signature is saved without recorded submission or verified receipt evidence; the hash alone is insufficient
submission-uncertain Track the exact saved action; submission may have reached the network
source-confirmed Source funding is verified but awaits finality
destination-pending Source funding is final; final destination delivery is not yet verified
settlement-discrepancy Provider and chain evidence conflict; exact attribution needs operator review
intermediate-held A composed workflow's first leg is final; the next leg still needs preparation and authorization
completed, refunded, closed Respectively finalized delivery, finalized refund, or a closed unused payment
operator-review The saved state cannot be continued safely; preserve its evidence

Saved report and refresh are different operations. This GET makes no provider or chain request and does not mint, submit, allocate a deposit, replace a payment or release reservations. POST /payments/{id}/refresh requests fresh evidence and may also perform previously authorized managed destination minting. Do not invoke refresh merely to generate a support report.

Decide the recovery action#

Condition Could payment funds have moved? Next endpoint / action Request identity Retry or escalation rule
Quote creation times out Quote itself moves no funds Retry POST /quotes Same key and identical body Back off; a fresh comparison uses a new key, explicitly linked to the same business order
Draft creation times out Draft itself moves no funds Retry POST /payments Same key and identical body Recover the original draft ID before considering a replacement
Preparation times out or returns 202 needs-review It can allocate instructions or reserve a wallet slot; existing funding must be checked GET /payments/{id}/preparation; NEAR POST /reconcile with {} only when canReconcile: true Mainnet preparation retry: same key/body. Testnet /prepare: saved version/body, no request key contract If existing activity or an ambiguous allocation remains, retain this payment and escalate
MINIMUM_OUTPUT_NOT_MET Do not assume the allocated deposit is unfunded Read preparation, then supported /reconcile Same payment; reconciliation has no new creation key Requote only when returned recovery.canRequote: true; do not infer that permission from a lower output alone
Transaction creation response lost Creation itself does not submit; another worker might have progressed GET /payments/{id}/transaction, then matching POST /transaction if needed Same key and original body/version Recover the saved authorization; do not choose a new nonce
Signature acceptance response lost Signed bytes exist; external submission may be possible Read /transaction; retry /transaction/signature only for the same authorization Same authorization and exact bytes; no idempotency header required If already signed, proceed according to current flags. If submitted/uncertain, track
/execute times out Yes Read /transaction, then POST /refresh Same payment and authorization submitting, submitted, submission-unknown: track only. Retry execute only if it is still signed, current, submission-enabled, and authorized
TRANSACTION_NOT_READY / TRANSACTION_PRICE_EXPIRED The rejected preflight does not start a new send; check saved submission state Read /transaction and preparation; display error.details.blockers or saved diagnostics Preserve authorization, signed bytes and nonce Resolve the specific failed/unknown check; retry same execute only while signed, current and enabled. Persistent unavailable evidence needs support
Mainnet EVM approval review expired Allowance may exist if someone broadcast the bytes Read transaction; if reviewRefreshEnabled, POST /transaction/review with authorization ID New saved key for a new review; same key/body on retry Recheck the existing approval, then sign or submit that action as allowed. Submitted actions are tracked
Stellar CCTP approval expired without an included receipt (unsigned, signed or submitted) No. An approval moves no funds itself. A wallet may still have broadcast it without returning its signature, so renewal checks the network first When next-action is renew-approval, POST /transaction/renew with the authorization ID. When it is close-payment (renewal cannot run), POST /transaction/close Save a new renewal or close key; same key and body on retry Route proves ledger expiry, no receipt and an unused sequence, then prepares a fresh action at the same sequence for a new signature. A found transaction is adopted and tracked; a used sequence is recorded for review. Any other APPROVAL_RECONCILIATION_REQUIRED changes nothing: refresh and retry later, or escalate
APPROVAL_STATE_CHANGED on a saved Stellar approval or burn No new send starts. Only a submitted action could have moved anything Refresh, then read next-action Keep all IDs; do not sign or submit the saved action The allowance changed: an approval is no longer needed, or a burn's allowance would lapse before the burn expires. Let the saved action expire. An expired approval or unsigned burn can then be renewed; a signed burn offers close-payment
Stellar burn or transfer expired without an included receipt Possibly. Route may have no signature, but a wallet can broadcast the returned envelope itself before its signed time bound. After that bound it cannot execute Unsigned: when next-action is renew-source, POST /transaction/renew. Signed, submitted or uncertain, or unsigned when renewal cannot run: when it is close-payment, POST /transaction/close Save a new renewal or close key; same key and body on retry Renewal prepares a fresh action at the same sequence with fresh terms. Closing ends the unfunded payment and releases its wallet sequence and holds. Both first check the saved hash: a found transaction is adopted and tracked and a used sequence is recorded for review. Any other SOURCE_RECONCILIATION_REQUIRED or CLOSE_UNAVAILABLE changes nothing
WALLET_SLOT_RESERVED from a Stellar wallet No. Another Route action holds the same wallet sequence Find the other payment's current action: renew it, finish it, or close it when closeEnabled is true Keep this payment unchanged Only renewal, inclusion, closure or an unrelated wallet transaction that advances the sequence frees it. Route never releases another project's reservation
Allowance expiring under a Stellar burn Not before submission. A submitted burn can fail on-chain and still charge its fee Refresh before signing; Route rechecks allowance lifetime at signature and submission Same payment and authorization Route builds a burn only when the allowance stays live through the burn expiry plus 12 ledgers. Otherwise it returns an approval, or rejects a saved burn with APPROVAL_STATE_CHANGED
Stellar approval sequence consumed (submissionObservation.state: "sequence-consumed" or "sequence-gap") Possibly: this or another transaction used or skipped the wallet sequence Refresh the same payment; recover the original receipt Keep all IDs; the wallet sequence stays reserved Renewal and closing are refused. A renewal or close check that finds a used sequence records it, also for a never-signed action, with lastError.code: "STELLAR_SEQUENCE_REVIEW", and moves the preparation to state: "needs-review": paymentState stays REQUIRES_ATTENTION and payment.requires_attention is emitted once. Operator review establishes what used the sequence before any new action
Native NEAR-chain allocation review expired; no transaction exists No Route transaction was constructed When reviewRefreshEnabled, POST /transaction/review with current preparation version Save a new review key and reuse it on retry Confirm the new NEP-413 intent approval, then build the first transaction. Existing actions require reconciliation
Mainnet NEAR EVM deposit review expired Signed bytes remain valid on-chain Read preparation/transaction; when enabled, POST /transaction/review with current preparation version and saved authorization ID New saved review key; preserve payment and transaction Confirm the new payment intent approval, then use the existing transaction. Original provider/refund deadlines still apply
Testnet unsigned action review expired Route has no accepted signature, but reconcile any external wallet attempt Read payment/transaction; POST /prepare with current payment version Same payment; no idempotency key on testnet prepare Server permits only a valid same-nonce unsigned refresh; sign only the new authorization
Signed testnet action or unsupported protocol transfer review expired Yes: signed EVM bytes do not expire on-chain Read transaction and refresh its evidence Keep all original IDs; no replacement key Stop automatic execution; operator reconciliation is required. Do not reuse the approval-renewal endpoint for a burn
VERSION_CONFLICT / IDEMPOTENCY_CONFLICT Existing work may have advanced Read payment/preparation and saved transaction Preserve the key for its original body; never reuse it with changed data Adopt verified existing progress. A genuinely new authorized operation gets a new key and current version
DEPOSIT_ALREADY_ACTIVE / DEPOSIT_NONCE_CHANGED Possibly Refresh deposit/transaction and reconcile the wallet Same payment; no automatic new deposit Active funding is tracked. A changed wallet nonce needs reconciliation
Destination discovery unavailable / VERIFICATION_PENDING Yes; recipient may already be paid POST /refresh; optionally supply the exact known destinationHash Same payment; no new source action Route still verifies binding and credit. Persistent mismatch, missing proof or unavailable history needs support
SwapKit key removed, or SwapKit tracking cannot find the swap (PROVIDER_CREDENTIAL_REQUIRED, PROVIDER_TRACKING_UNAVAILABLE) Yes; delivery or a refund may already have happened Delivery: reconnect the original SwapKit connection, then POST /refresh, optionally with {"destinationHash":"HASH"}. Refund: reconnect the original connection, then POST /refresh with {"refundHash":"HASH"}, or a workspace member confirms it in the dashboard Same payment; no new source action A destination hash must match the delivery leg SwapKit reports for the saved source transfer, then pass chain verification of the recipient, asset, reported amount, minimum, time and finality before an exclusive payout claim. Without provider attribution the payment stays unsettled and its reservations remain. A refund hash settles only when SwapKit reports that exact transaction as the refund leg, because any wallet can credit the refund address. A dashboard confirmation is still verified on chain and bounded by the deposit; see confirming a refund in the dashboard
BITCOIN_SETTLEMENT_AMOUNT_MISMATCH in tracking.settlementDiscrepancies[] Yes; a canonical recipient credit exists Read the saved discrepancy; use the same-payment refresh or scheduled tracking for supported allocation verification; escalate if proof is missing or conflicting Same payment, source hash and associated payout hash Compare reported/net observed satoshis, minimum, canonical block and confirmations. A larger output does not establish payment-specific attribution; do not fund again or mark complete locally
Managed mint failed / submission-unknown (REQUIRES_ATTENTION, review-required) Source funds already moved; destination outcome may be uncertain Read the preparation's destinationExecution.lastError evidence (relay ID and hashes, or the lost-response reason and attempt time) and any earlier relayAttempts. If the Stellar mint exists, supply its hash to /refresh as destinationHash Same source message and payment With lastError.retryAllowed: true, Route re-mints the same saved call once after lastError.remintAfter, only while the CCTP nonce is unused and the attestation and call still simulate; a duplicate can only fail on chain. After that, or when retryAllowed is false (including DESTINATION_MINTED_UNRECORDED), Route verifies a supplied receipt but does not re-mint; without a mint an operator decides the recovery. Never repeat the source burn
429, transient 5xx, unavailable network read Depends on which operation failed Read/replay only the original operation where safe Same mutation key/body or authorization Honor Retry-After; bounded backoff. Stop after repeated failures; no blind chain rebroadcast
401 / 403 Prior transactions can still exist Correct key scope, network or owner access; reread saved payment No replacement payment Do not weaken owner policy to bypass a rejection

Mainnet review capabilities are limited to the approval and NEAR deposit cases described above. Stellar CCTP approvals cannot refresh a review; they use approval renewal. A suggested next action never overrides signingEnabled, submissionEnabled, actual blockers or expiry. Unknown future states require a pause, continued safe reads and an updated integration.

For testnet, authorizationPrepared: false means the prepared unsigned action has not yet received a persisted signing authorization. Save and submit a POST /transaction request before requesting a signature; then require authorizationPrepared and signingEnabled. This is not a reason to create another payment or change its nonce.

Worked recoveries#

A draft response was lost#

Save request key K1 and {"mode":"prepare","quoteId":"Q1","candidateId":"C1"} before sending. If the connection closes, resend exactly that body with K1. The response returns the same payment P1. Store P1 before starting preparation. Generating K2 after the timeout could create a second draft for the same order.

An approval expires before submission#

Read its authorization A1. If it is submitted or uncertain, refresh; expiry does not undo the transaction. If this is a supported mainnet EVM approval with renewal enabled, save review key R1, renew A1, and inspect the returned checks and expiry. A saved signature is reused only for the unchanged payload. After a successful canonical approval block, prepare the transfer with a new action key and current preparation version. Review its fresh terms separately.

A Stellar CCTP approval has no review refresh. When next-action returns renew-approval, save renewal key R1 and call POST /transaction/renew with {"authorizationId":"A1"}. Route replaces A1 only after proving it can no longer execute. The response is replacement A2, at the same wallet sequence, which needs a new signature; A1 and any signature for it are retained. If a live allowance already covers the burn through its expiry, A2 is the burn itself. Otherwise sign and submit A2, wait for a finalized ledger, then prepare the burn with a new action key.

A signed deposit fails current readiness checks#

Keep A1 and the exact signed transaction. Display each returned blocker, such as an unavailable price feed or insufficient gas balance. Read the transaction after the error. If it is still signed and current, retry the same authorization only after the blocker is resolved and submission is authorized. If its NEAR EVM review expired, renew the review and confirm the new intent challenge. If renewal is unavailable, pause; do not request a replacement signature as a workaround.

Execution returned no response#

Read A1. If walletBroadcast.state is awaiting-transaction, follow wallet handoff recovery. For the sign-only/Route submission flow, submitting or submission-unknown means Route has recorded its broadcast attempt. Refresh P1; the stored hash is the tracking reference. Do not call a wallet's send method, start another provider deposit or change the gas price. If the chain cannot establish the outcome, escalate with the original evidence. At-most-once Route submission prevents duplicate Route broadcasts; it cannot erase signed bytes or prevent an external party from broadcasting them.

Polling and retry schedule#

Use GET /payments/{id} for saved state; POST /refresh requests new provider/chain evidence and may advance managed delivery. After submission, poll refresh at 15 seconds, then 30, then 60, adding 0–20% jitter. Honor a longer Retry-After. Keep one active tracker per payment, stop on completion, and switch unresolved errors to an operator queue after five consecutive transient failures. A worker restart uses the same durable state.

These are recommended client intervals, not rate limits or an arrival promise. Some limits apply across a project: staggering a large number of payments matters. Read response rate-limit headers and the API limits; a maximum allowed request rate is not a recommended polling frequency. Webhook delivery must be enabled for your approved HTTPS origin; until then, use controlled polling. Even with webhooks, deduplicate events and reread payment state before acting.

Support bundle#

In the dashboard, open a payment's Recovery details, then Download support details. The JSON contains the allowlisted report described above. It omits credentials, signatures, signing challenges, transaction payloads and raw provider responses. Wallet addresses, transaction hashes and public record IDs remain necessary evidence; share the bundle only with authorized support staff. Downloading it does not refresh or modify the payment.

Provide network, business-order reference, payment/preparation/authorization IDs, request ID, endpoint, timestamp, error code, redacted blocker messages, source/destination hashes and the last known state. Include both provider-reported and on-chain amounts for a receipt mismatch. Never include Route/provider credentials, private keys, raw signatures or signed transaction bytes. Preserve the private operation record until reconciliation is complete.

Bitcoin fee-adjustment discrepancies#

A BTC payout can exceed the provider-reported amount when a bridge returns unused network-fee reserve. In the investigated payout, withdrawal-bound bridge events show a 1,500-satoshi network-fee reserve but 376 satoshis actually spent. The 1,124-satoshi difference explains a reported 9,784 versus received 10,908. See the bound transfer evidence and release verification.

For supported Ethereum ERC-20 → native Bitcoin deliveries through NEAR 1Click, Route now verifies the exact source deposit, NEAR intent and withdrawal, bridge nonce, connector submission, successful withdrawal verification and canonical recipient output. Both chains must satisfy finality, and the received amount must satisfy the saved minimum. The provider/indexer status alone is insufficient. Route persists an exclusive payout claim in the same database transaction as completion; retries cannot count that payout twice. Other unresolved delivery or refund amount mismatches remain pending for review; ordinary exactly verified refunds keep their existing completion rules.

Read preparation.tracking.bitcoinPayout for the proof method and claimId after persistence. exact-recipient-net means the canonical recipient net credit equals the provider report; it claims that transaction/recipient combination without claiming a single output. near-omni-output includes a withdrawal-bound allocation with an exact outputIndex and fee amounts. tracking.received is the verified actual BTC amount in decimal units; bitcoinPayout.amountMinor is in satoshis. provider.receivedAmount and bitcoinPayout.providerAmountMinor preserve the original provider report. A resolved adjustment is no longer listed in settlementDiscrepancies.

Existing eligible nonterminal payments use the same scheduled or manual refresh. Missing evidence or a conflicting/legacy payout claim keeps the existing payment pending; never fund a replacement to clear it. Terminal historical records are not rewritten. This release covers one withdrawal and one winning payout through the known connector path. Replacement (RBF) transactions and multiple withdrawals in one batch remain pending. It covers delivery claims, not global refund attribution or monitoring for deep reorganizations after completion.

Refresh an expired approval review#

New mainnet EVM approval and approval-reset actions have a 15-minute review window. This is the window to review, sign and submit the permission transaction, not a deadline for it to reach finality. Once submitted, keep tracking its hash even if that review window has elapsed. New transfer, burn and customer-signed mint actions have a separate five-minute review window across the released providers. CCTP testnet uses the same windows. Existing saved actions retain their original expiry; always use the returned expiresAt.

For a saved approval in ready or signed state, inspect reviewRefreshEnabled. If it is true, your backend may request a fresh review on the same payment:

POST /v1/payments/{id}/transaction/review
Authorization: Bearer YOUR_ROUTE_API_KEY
Idempotency-Key: SAVED_UUID_FOR_THIS_REVIEW
Content-Type: application/json

{"authorizationId":"SAVED_APPROVAL_ACTION_UUID"}

Required scope: payments:write. The example client exposes refreshApprovalReview(paymentId, authorizationId, idempotencyKey). Reuse the same key if the request times out; use a new key for a later review.

Route checks whether the saved hash is known to the network, both confirmed and pending wallet nonces, the exact token/spender/amount, current allowance, transaction simulation, gas balance, saved fee budget, owner policy and inherited API-key limits. RPC failures block the review. The permission check does not depend on the old transfer quote or its ETA.

A successful response keeps the same action ID, transaction bytes, signature, hash and reserved nonce, and returns a new review, assessment and effective expiresAt. originalExpiresAt preserves the original deadline. It does not broadcast, change the gas price, relax a minimum output or create another payment. Show the refreshed assessment. If already signed, require confirmation before /execute; if ready, sign and save the exact action first. A saved EVM signature remains valid only for those unchanged transaction bytes.

nextAction: "refresh-approval-review" identifies an expired approval eligible for these checks. Eligibility is not a guarantee of success. If the hash is already known (APPROVAL_ALREADY_BROADCAST), use /refresh to track it. If the nonce changed (APPROVAL_NONCE_CHANGED), permission changed (APPROVAL_STATE_CHANGED) or the saved gas budget no longer suffices (TRANSACTION_FEE_CHANGED), reconcile the wallet; do not create a replacement automatically. Unsigned EVM burn/transfer actions also support the same endpoint when reviewRefreshEnabled is true and nextAction is refresh-source-review; no source signature, hash, submission or wallet handoff may exist. The transaction bytes remain unchanged and fresh simulation and policy checks must pass. Stellar source actions, signed protocol funding actions, submitted approvals and uncertain submission attempts require reconciliation. This is a mainnet endpoint.

After one successful canonical approval confirmation, request the next action on the same payment. Route obtains fresh terms from the selected provider and checks the saved recipient minimum and policy again. Worse terms are blocked; a different provider or explicitly changed payment terms require a new comparison and review.

Unused drafts and payment history#

Mainnet GET /payments?view=active&limit=50 returns top-level payments, with nextCursor and hasMore. Pass the returned cursor to retrieve the next page. view accepts active (default), archived, or all; limit accepts 1–100. A composed payment appears once; inspect its workflow for the individual transfers.

POST /payments/{id}/archive takes { "version": CURRENT_PAYMENT_VERSION }. Only unused standalone drafts are eligible. Inspect canArchive; a prepared payment, composed parent or composed leg cannot be archived. Archived records return archivedAt, archiveReason and archivedBy. Automatic cleanup archives eligible drafts 24 hours after quote expiry; it may run shortly after that threshold. It retains the record, quote evidence and retry history. Archived drafts cannot be prepared; request a fresh quote for a new payment.

Archival never cancels a provider deposit, removes a signed action, releases a spending reservation or stops tracking. These filters and archive operations currently apply to mainnet payment records; the isolated testnet contract is unchanged.

See usage and payment reporting for processed-USD totals, logical operation metering and stablecoin credit purchases.

Retries, limits and errors#

Persist an operation UUID with your order before sending a quote or payment request. Retry identical input with that same Idempotency-Key after an interrupted connection. Matching retries return the original record, including after key rotation; conflicting input returns 409 IDEMPOTENCY_CONFLICT. A missing or non-UUID key returns 400 IDEMPOTENCY_REQUIRED and changes nothing; persist a UUID and retry. The exceptions are NEAR source renewal, NEAR deposit review and NEAR captured quote-review acceptance (/transaction/renew, /transaction/review and POST /quote-review on a NEAR payment), which still answer a missing or non-UUID key with 404 NOT_FOUND; that 404 does not mean the payment is gone. A new quote needs a new UUID. A replayed expired quote is returned with expired: true, not silently refreshed. Keys are namespaced by project and operation, separately from dashboard requests.

The preview allows 120 customer requests per project per minute. Each API key can also create 12 quotes and 12 payments per minute, separately from its issuer's other keys and dashboard use. A quote counts only once it passes validation and the policy and key allow an enabled provider. NEAR provider preparation allows six attempts per project per minute; status refresh allows 12 per payment per minute. Authenticated customer responses carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds until the window resets) for the project budget. A rate-limited 429 carries Retry-After: the seconds until the limit that refused it resets. Other limits can still refuse the retry. Ordinary JSON bodies are limited to 8,192 bytes. PUT /policy accepts up to 131,072 bytes (see routing policies). POST /payments/{id}/transaction/signature accepts up to 110,000 bytes; its signedTransaction string is limited to 100,000 characters. Errors have { "error": { "code": "…", "message": "…", "details": {} } } and an X-Request-Id header. details is optional. Preserve it when forwarding errors to your frontend; NEAR readiness errors include named blockers, checkedAt and a recovery action. See signed-transaction recovery. Responses are never cacheable. Use the request ID when reporting failures; do not log keys or credential bodies. Typical statuses: 400 invalid input, 401 invalid/expired/revoked key, 402 insufficient available Route credits, 403 missing scope, 404 inaccessible record, 409 state/expiry conflict, 415 JSON required, 429 rate limit, 503 temporarily unavailable.

The machine-readable OpenAPI contract is available at /docs/openapi.json. Additional quote evidence fields can be added; clients should ignore fields they do not recognize.

Wallet handoff with a missing response#

A pending transaction report (lastError.reason: "reported-transaction") keeps normalized next-action guidance at review-required with no automatic operation. Preserve the authorizationId and transactionHash from the original report and use that pair when retrying recovery. The current action can display evidence from an earlier action of the payment; do not substitute its authorization ID. A pending cancellation needs another recovery check after finality, not payment confirmation. Explicit confirmation retries for an original wallet transaction still use that original handoff's authorization ID and hash.

If walletBroadcast.state is awaiting-transaction, Route has reserved wallet submission but has no verified transaction hash. Recover the hash from wallet activity and call /transaction/broadcast-confirm for the same authorization. A transient WALLET_TRANSACTION_NOT_FOUND permits retrying confirmation, not sending again. An expired review does not prevent confirmation.

If the hash was lost, call:

POST /v1/payments/PAYMENT_ID/transaction/broadcast-recover
Authorization: Bearer YOUR_ROUTE_KEY
Content-Type: application/json

{"authorizationId":"SAVED_ACTION_ID"}

An optional transactionHash lets Route inspect a known original or cancellation transaction. Keep Route-Network: testnet for testnet. Both recovery operations require payments:write and the same project/policy access. The SDK methods are recoverWalletBroadcast(id, authorizationId, transactionHash?) and cancelWalletBroadcast(id, authorizationId, cancellationHash).

Recovery state Next step
original-verified Route registered the exact original transaction. Read next-action and track normal receipt/finality/delivery
altered-payment The transaction is the exact payment call (sender, contract, calldata, value and chain) with a changed nonce, fee or transaction type. Route records it for review and returns its hash, but never attaches it or releases the nonce, credits or API-limit holds. canClose stays false. Review the recorded hash; never resend
equivalent-execution The hash is a transaction this wallet signed, sent or still queued at any nonce, that is the same payment without being the saved call: the call re-quoted (another fee or finality threshold, the same token, amount, destination and recipient), another value, another envelope type (including blob and set-code transactions), a call to the payment contract Route cannot decode, or any call to the payment's provider contracts or deposit address. For a NEAR source transaction the rule reads the preparation's 1Click deposit: any transfer of the source token, or native send, to the deposit address. Route records it for review exactly like an altered payment: it is never attached, nothing is released, canClose stays false and the saved call is never submitted or handed to the wallet again
unclassified-sender-transaction The hash is a transaction this wallet signed (its signature recovers to the sender), at any nonce (the saved one, a later one, or an earlier one still pending), sent or still queued, in any envelope (including set-code transactions and legacy transactions signed without replay protection), that is neither the saved transaction nor a recognized cancellation, and that Route cannot classify as the same payment: for example the saved call wrapped in the wallet's own delegated or batched execution, the payment sent through another contract of the provider or another bridge, or an unrelated transfer. Route cannot establish that it is not this payment, so it records it for review exactly like equivalent-execution (reason: "unclassified-sender-transaction"): it is never attached, nothing is released, canClose stays false, and the saved call is never submitted or handed to the wallet again
unclassified-transaction The network shows the reported transaction, but Route cannot verify that this wallet signed it: another account sent it (a relayer or bundler executing through the wallet's delegated EIP-7702 or ERC-4337 code), or its envelope carries no sender signature Route can rebuild (an OP-stack deposit 0x7e, an Arbitrum system type, an unsigned or unknown type). Who signed it does not matter: it may be this payment executed from the wallet's account. Route records it (reason: "unclassified-transaction", with observedFrom, signer, contract, observedType and transactionData) and it blocks the payment exactly like unclassified-sender-transaction
reported-transaction Route recorded the hash you reported for review before reading it, and the network does not show it yet (or it is the saved call sent without a handoff). It blocks the payment until a later check classifies it (the same record is updated) or shows it is this action's own transaction or a finalized recognized cancellation (the record is then cleared). Retry recovery with the same hash; never resend
not-observed Returned only when no hash was supplied: no transaction was established. Preserve the action and reservations; this does not prove that the wallet never sent
pending-nonce The node reports pending nonce use. Obtain the hash from wallet activity, then recover or confirm it
cancellation-pending A cancellation was observed but is not final. Wait and recheck the same hash; the original transaction can still win. Until a check sees it finalized, the report of its hash keeps blocking the payment
cancellation-verified A finalized cancellation invalidated the action. If canClose is true, explicitly close it below
closed The unfunded payment is cancelled. Its immutable history remains; use a fresh quote and new payment for a later attempt

POST /transaction/broadcast-confirm reports the same case as 409 WALLET_TRANSACTION_REVIEW_REQUIRED, with the evidence in error.details (transactionHash, saved nonce, observedNonce, observedType, observed gas and fee fields, checkedAt, automaticAttachmentAllowed: false). A reported hash that is the same payment in another transaction, or any other transaction the wallet signed that is not the recognized self-cancellation of the saved nonce (the equivalent-execution and unclassified-sender-transaction cases above), returns the same 409 with reason: "equivalent-execution" or reason: "unclassified-sender-transaction" and is recorded the same way; an existing handoff then no longer presents its params. Either way the evidence is kept permanently and saved as the transaction's lastError. paymentState is REQUIRES_ATTENTION and next-action is review-required until a verified terminal receipt. Confirming the exact original later registers it for tracking but keeps the review, because both transactions may have executed. Route also never sends a saved call again for any action of that payment (payment scope, below), neither by submitting a saved signature nor by handing it to the wallet, for protocol actions, NEAR source transactions and testnet actions alike and whatever the account nonce shows (the altered copy may be queued at a later nonce while the saved one is still next): POST /execute and a new POST /transaction/broadcast handoff return 409 WALLET_TRANSACTION_REVIEW_REQUIRED with the recorded evidence before any network read or send, the action keeps its state and lastError, the handoff returns no eth_sendTransaction params, and the database refuses the same submission or handoff. An existing handoff is still returned and nothing is sent, but with walletBroadcast.method: null, empty params and a review notice. The transaction views stop offering these steps: walletBroadcastAvailable, signingEnabled and submissionEnabled are false, and mainnet protocol actions and GET NEAR transaction carry actionBlocker.code: "WALLET_TRANSACTION_REVIEW_REQUIRED" with the evidence in details. The handoff of an altered spending approval is not refused and keeps its params, because that approval moves no funds; its saved signature is still never submitted (submissionEnabled: false). A recovery running at the same time either commits first, so the submission or handoff is refused, or waits until it is saved. If the evidence is recorded while Route's own send of the saved transaction is in flight and that send's outcome is uncertain, the evidence still becomes the lastError, so next-action stays review-required, and it carries the send's SUBMISSION_UNKNOWN diagnostic as lastError.submission.

Route freezes a payment on every transaction reported for it. The threat model: Route never itself submits a saved signature, or starts a new wallet handoff, for any action of a payment (the same preparation: its approval and burn or transfer, a NEAR source transaction, the testnet actions of one payment) once any transaction has been reported for any action of that payment that is not (a) exactly that action's own saved transaction, (b) a recognized cancellation at its saved nonce, or (c) for a spending approval, a copy with byte-identical calldata to the same spender, in any envelope (an approval moves no funds). "Reported" means a hash given to broadcast-recover, broadcast-cancel, broadcast-confirm, the unused-action close, close after manual check or a saved-signature or composed source cancellation, on mainnet or testnet, for NEAR source transactions, protocol actions and testnet actions alike, on every EVM network the action allows. Who signed the transaction does not matter (the sender, a relayer or bundler, an L2 system deposit, an unsigned or unknown envelope), nor does the network or the flow.

The report is recorded first, for the whole payment, before Route reads the network or checks whether the payment could be closed, and only an authorized caller of the payment can report. The hash is then inspected: it becomes altered-payment for the byte-identical call, equivalent-execution when the payment's same-payment rule matches, unclassified-sender-transaction for anything else the wallet signed and unclassified-transaction for anything it did not verifiably sign; or it is cleared, because it is the action's own saved or wallet-confirmed transaction (registering the wallet's exact original still works) or a finalized recognized cancellation. A recognized cancellation is the zero-value, empty-data self-transfer at the saved nonce and, for the unused-action close only, a finalized transaction at the saved nonce that neither calls, is logged by nor pays the payment's provider contracts or deposit address. Only a finalized one clears a report: its receipt is on a finalized block and the finality, provider-log and code checks passed (the database also refuses any other clearance). A cancellation or nonce proof that is not final yet (cancellation-pending, or the close's observedState: "nonce-consumed-pending") clears nothing, because a queued transaction at the saved nonce may be the payment itself (for example the payment batched through the wallet's delegated code to its own address); the report keeps blocking until a later check with the same hash sees it finalized. broadcast-confirm reads no receipt, so it never clears a report. If the network read fails, or the transaction is not visible yet, the report stays recorded as reported-transaction evidence and keeps blocking; a later check with the same hash classifies or clears that same record. Mistyped hashes block too: report only hashes the wallet shows. A testnet action takes reports from /prepare on, before /transaction has requested its authorization: broadcast-recover inspects and records the hash (nothing closes), and while it is open /transaction is refused with 409 WALLET_TRANSACTION_REVIEW_REQUIRED and the database refuses the authorization. On every flow, broadcast-confirm for an action without a handoff returns 409 WALLET_TRANSACTION_REVIEW_REQUIRED with the recorded report in error.details (instead of 404 WALLET_BROADCAST_NOT_FOUND) when the hash is on record for review.

While such evidence is open for any action of the payment, /execute of any saved signature, a new /transaction/broadcast handoff and a new action (POST /transaction; testnet /prepare and /transaction) return 409 WALLET_TRANSACTION_REVIEW_REQUIRED with the evidence, and the database refuses the same submission, handoff or new action. No cancellation or closure of any action releases the payment's holds. The action views read the payment's evidence: walletBroadcastAvailable, signingEnabled and submissionEnabled are false, and an action with no evidence of its own shows the payment's evidence as its lastError, so next-action is review-required. Only case (c) is exempt: a spending approval's wallet-altered copy refuses only that approval's own submission. The only way to lift the block is Route's audited attribution of that exact transaction to another of the project's payments with matching terms (its saved signed or wallet-confirmed hash, from the same wallet and network), which runs before a protocol close or cancellation. NEAR and testnet evidence has no attribution path: an operator reviews those payments (see the operations notes in the audit research). A legacy signature without replay protection (v 27 or 28) is accepted as evidence only, never to attach a transaction or prove a cancellation.

What remains outside this rule is a same-payment copy that nobody reports to Route: one broadcast from another wallet, or one this wallet signed but never reported at any of these endpoints. Route cannot see it unless its provider search finds it (for protocol payments at closure or cancellation), and it cannot see a transaction queued behind a nonce gap in the wallet's own pool until it reaches the network. Report every hash the wallet shows before you close or resubmit.

Two more cases are outside this rule and are known limits. First, each attempt of a composed payment is its own draft: a report for a cancelled attempt's action after that attempt was closed is not recorded (a closed action takes no evidence, and the parent's routes report to the latest attempt), and a new attempt on the parent is prepared and handed to the wallet normally; a NEAR leg is not searched at cancellation. Report every hash before you close an attempt. Second, Route's own submission is serialized at its reservation: a report that is recorded after Route reserved the submission of a saved signature (the action moved to submitting) but before its single broadcast attempt does not stop that broadcast. The report is still recorded and blocks every later submission, handoff and action of the payment.

Two guarantees hold for every check that reads the network for an action (the in-progress state below applies to every action of the payment) (the unused-action close and close after manual check, broadcast-recover, broadcast-cancel and the saved-signature or composed source cancellation). First, while the check runs, submission and a new wallet handoff of that action return 409 WALLET_EVIDENCE_CHECK_IN_PROGRESS with details.retryable: true and details.retryAfterSeconds, before any network read, and the database refuses them too. The check clears this state in the same database transaction that records what it found, or as soon as it finds nothing or fails; it also lapses on its own after 2 minutes, so a request that never finishes cannot block the payment for longer. Retry after the check returns. A check that runs longer than those 2 minutes still records what it found, even if a submission or a wallet handoff (or the registration of the wallet's own original) started in between, so the payment then reads review-required; it clears only its own state, never a newer check's. A close or cancellation whose check ran longer than 2 minutes closes nothing: it returns 409 WALLET_EVIDENCE_CHECK_EXPIRED with details.retryable: true; retry the same request. Second, what the check observed is recorded even if the caller's API key is revoked, or the member loses access, while it runs: Route records the evidence for the action, audits it as the member who started the check, and only then returns the authorization error. Another credential then finds the evidence and cannot send the payment.

Without a hash, Route searches backwards from recent canonical blocks, then narrows the sender/nonce transition. This avoids requiring years-old archive state to recover a recent transaction. The search is bounded to 40 historical count reads. Pending transactions, pruned history for an older action and unavailable or oversized block responses may still prevent discovery. An incomplete lookup never releases reservations. Supply the wallet hash when available and respect 429 backoff; new recovery checks are limited to five per action per minute. Reading the saved GET /recovery report remains separate and makes no chain request.

Rejected prompts and confirmed cancellation#

A wallet rejection, closed tab or elapsed review does not establish an on-chain cancellation. If you choose to abandon the action, the wallet owner may explicitly authorize a cancellation at the saved source account, chain and nonce: a zero-value native self-transfer with empty data. This costs network fees and races any existing transaction at that nonce. Route does not create, sign or broadcast that cancellation. Do not send another provider deposit as a cancellation.

Route accepts a cancellation only after independently verifying the signature and hash, successful canonical receipt, empty code and logs, 21,000 execution gas used (excluding separately reported Arbitrum L1 posting gas), and chain finality. Legacy and type-2 self-transfers are supported for this cancellation proof. This does not enable type-2 payment funding or fee-edited payment transactions. A cancellation on a chain whose finality cannot be established remains unresolved.

Once the cancellation is final, call POST /payments/{id}/transaction/broadcast-cancel with {"authorizationId":"SAVED_ACTION_ID","transactionHash":"CANCELLATION_HASH"}. This operation verifies the evidence again, closes the unfunded standalone payment, and releases unused payment-credit and rolling API-limit reservations in one database transaction.

A cancellation consumes only the saved nonce, and the wallet may have sent the payment itself at another nonce. For a mainnet protocol payment, Route first searches the sender's provider events for the same payment at any other nonce, exactly as for an unused EVM protocol action, and stores that search with the cancellation. A match returns EVM_CLOSURE_REVIEW_REQUIRED and is recorded for the action as review evidence (below): from then on Route never submits the saved signature or hands the saved call to the wallet. If Route already recorded that the wallet sent the payment call at another nonce, with changed fees or in another transaction it signed (lastError.code: "WALLET_TRANSACTION_REVIEW_REQUIRED"), for a protocol payment or a NEAR source transaction, or the provider cannot be searched by sender (SwapKit native deposits, or a payment call Route cannot decode), recovery returns canClose: false and closing returns WALLET_CANCELLATION_REVIEW_REQUIRED. The same recorded evidence blocks a hosted-testnet handoff cancellation. In every case the payment and its reservations are kept for review; do not send replacement funds. Repeating it with the same proof cannot release credits twice. Quote charges and network fees are not refunded; cancelled payments add no processed USD volume. The consumed nonce stays recorded and cannot be reused. Old payment/deposit instructions must no longer be used.

Destination mint actions and transfers with verified execution evidence require separate review. A recorded wallet-altered burn or transfer (altered-payment or WALLET_TRANSACTION_REVIEW_REQUIRED) also blocks closure of that action: canClose is false and closing returns 409 WALLET_CANCELLATION_REVIEW_REQUIRED (SOURCE_CANCELLATION_REVIEW_REQUIRED or COMPOSED_CANCELLATION_REVIEW_REQUIRED for saved-signature and composed sources), with all reservations kept. An altered spending approval moves no funds, so it stays flagged for review but does not block closing an otherwise unfunded payment. Report every hash the wallet shows to /transaction/broadcast-confirm before you close with a cancellation. An original transaction confirmed through a browser-wallet handoff prevents that handoff’s cancellation closure. A hash saved with a signature alone is not proof of submission; supported saved signatures use the recovery flow below. For a cancelled first composed EVM source leg, verified closure ends the unfunded parent and releases unused payment holds; obtain a fresh quote for a new payment. See first-transfer cancellation. For the active second or third EVM source leg of a composed payment, a saved signature/hash can be superseded only by a verified finalized cancellation at that exact nonce; see intermediate cancellation recovery. The funded parent remains open with its reservations retained. If the original transaction won the race, recovery registers it for tracking instead of declaring the payment cancelled. Original signatures, hashes, spending approvals and provider deposit records are never erased. See EVM wallet submission.

SwapKit changed terms before preparation#

For SWAPKIT_BUILD_REFUSED, SwapKit refused the build before opening a channel and the payment's holds are already released. Fix the cause and call /prepare again with the same wallets before providerAllocation.expiresAt, or cancel the payment. For SWAPKIT_ALLOCATION_NEEDS_REVIEW, keep the saved payment. Read and explicitly accept the captured quote review when Route can verify the same live deposit channel. The original quote and the accepted revision are retained. Unknown build outcomes, invalid identities, expired channels and existing wallet actions are not eligible for this automatic recovery. Never create another channel merely because preparation returned an error. A failure after the SwapKit claim keeps the payment’s credit and API-key holds and reports REQUIRES_ATTENTION. A validated channel resumes with the same wallets only until providerAllocation.expiresAt; see SwapKit failure boundaries.

Renew an expired customer Stellar mint#

When next-action returns renew-mint, call POST /payments/{id}/transaction/renew with the current authorizationId and a persisted UUID Idempotency-Key. This applies to customer-signed Circle CCTP destination mints on Stellar mainnet and testnet. This mint flow does not renew a source burn or approval; expired Stellar CCTP approvals have their own approval renewal. NEAR Stellar source deposits have the separate source renewal flow below.

Route first verifies the old signed transaction, a fresh closed Stellar ledger past its finite expiry, and the fee payer's unchanged sequence. It then checks that the CCTP message is still unminted and rebuilds the same invocation within the existing destination fee ceiling. The recipient, mint message, fee payer and sequence stay fixed. A timeout or a missing transaction lookup alone is insufficient.

const renewed = await sdk.renewMint(paymentId, authorizationId, renewalRequestKey);
const next = await sdk.getNextAction(paymentId);
// Present next.action.payload to the wallet for a fresh signature.

The endpoint prepares a new authorization; it does not send funds. Retain the original action and store the replacement ID and new signed payload separately. Repeat the same request key if the response is lost. Mainnet returns the replacement transaction directly; testnet returns it under transaction. The normal signature and execute operations apply to the replacement.

MINT_RECONCILIATION_REQUIRED means the old action is ineligible or chain evidence is insufficient. Already-submitted or uncertain actions, observed receipts and consumed wallet sequences stay in reconciliation. A changed fee estimate must fit the original fee ceiling; renewal cannot raise the customer's budget. Never repeat the source transfer to recover destination minting.

Renew an expired Stellar CCTP approval#

When next-action returns renew-approval, call POST /payments/{id}/transaction/renew with the current authorizationId and a persisted UUID Idempotency-Key. This applies to a mainnet Stellar-source Circle CCTP approval or legacy approval-reset whose signed time bound has passed without an included receipt, whether it was unsigned, signed, submitted or uncertain. approvalRenewalEnabled: true on the action marks eligibility; it is not permission to replace or send.

Route first verifies the saved envelope and any saved signature. It then checks that the network reports no receipt for the saved hash. A fresh closed ledger must be past the signed maxTime, and the wallet's account sequence must still be just below the saved nonce. Only then does it build a fresh action at the same wallet sequence, with the ordinary POST /transaction checks: fresh wallet, fee, policy and API-key limits. The replacement is one exact approval or, when a live allowance already covers the burn through its expiry, the burn itself. The wallet sequence reservation moves from the old action to the replacement in the same database transaction. Renewal keeps the payment open; to abandon it instead, see closing an expired Stellar payment.

const renewed = await sdk.renewApproval(paymentId, authorizationId, renewalRequestKey);
const next = await sdk.getNextAction(paymentId);
// Present next.action.payload to the wallet for a fresh signature.

Renewal sends no funds. The expired action, its signature, credit and API-key holds are retained, and the payment history shows both actions with an approval.renewed event. Repeat the same request key if the response is lost; a different key for the same old action returns APPROVAL_RECONCILIATION_REQUIRED. APPROVAL_RECONCILIATION_REQUIRED also means renewal is not possible. If the saved approval is already on the network or its sequence was used, Route records that; see below. Otherwise the evidence was insufficient: the sequence was skipped, the chain evidence was unavailable or unverifiable, or the ledger was not yet past the time bound, and nothing changes. In every case, refresh, then follow next-action. Never re-sign or rebroadcast the expired approval outside Route.

Renew or close an expired Stellar burn or transfer#

This applies to a mainnet Stellar-source protocol payment (Circle CCTP, LayerZero or Axelar) whose current burn or transfer passed its signed time bound without an included receipt.

  • Never signed (state: "ready", sourceRenewalEnabled: true): next-action returns renew-source. Call POST /payments/{id}/transaction/renew with the authorizationId and a persisted UUID Idempotency-Key. Route performs the same proof as approval renewal, then builds a fresh action at the same wallet sequence with fresh terms and the ordinary checks. For CCTP that is the burn, or an approval first if the allowance no longer covers the burn through its expiry. Sign the replacement; the renewed action stays in the history and is never tracked as the payment's source. A source.renewed event records the renewal.
  • Signed, submitted or uncertain: the payment's source hash is already registered, so renewal is refused with SOURCE_RECONCILIATION_REQUIRED. next-action returns close-payment; see below.
  • Renewal cannot run: while execution is paused, or after the owner policy or provider settings changed since the payment was saved (permanent for that payment), renewal is refused. When closeEnabled is true, next-action returns close-payment for an expired approval or never-signed burn or transfer too, and error hints point to /transaction/close instead of /transaction/renew.

Older saved burns may fail the stricter signature recheck. Once expired, eligible unsigned actions offer renew-source; signed actions require proof-gated closure or tracking.

const renewed = await sdk.renewSource(paymentId, authorizationId, renewalRequestKey);

A wallet broadcast the saved Stellar action itself#

Route returns the unsigned XDR and expects the signed transaction back at /transaction/signature. A wallet can instead sign and broadcast it itself, so a transaction Route never saw may have executed. A Stellar transaction hash excludes signatures, so the saved envelope hash is the landed hash. Before any renewal or closure, Route checks that hash:

  • Found, exactly the saved envelope with the sender's single signature: the request is refused (SOURCE_RECONCILIATION_REQUIRED, APPROVAL_RECONCILIATION_REQUIRED or CLOSE_UNAVAILABLE). Route then adopts the transaction as the submitted action: state: "submitted" with that hash and the landed envelope, a receipt with included: true and finalized: false until tracking attaches its verified evidence, a registered source hash for a burn or transfer, and a wallet.broadcast_verified event. next-action becomes track; delivery proceeds as for any submitted transfer.
  • Found but not adoptable (a fee-bump wrapper, signatures Route cannot hold, or an envelope or result that is not verifiably the saved one) with the account sequence independently used, or not found with the sequence used: the request is refused and the observation is saved on the action (receipt.submissionObservation.state: "sequence-consumed", bound to the saved envelope hash) with lastError.code: "STELLAR_SEQUENCE_REVIEW". The preparation moves to state: "needs-review", so paymentState is REQUIRES_ATTENTION and the webhook outbox receives payment.requires_attention once. The review is permanent: a later refresh can clear lastError, but not the review state or the saved observation. next-action returns review-required; renewal and closure are no longer offered.
  • Anything else unverifiable (a found receipt whose account sequence is still unused, unavailable RPC or account evidence, or a sequence gap): nothing is written.

None of these sends, renews or releases anything. Recovery reports never state that such an action moved no funds before this check.

Close an expired Stellar payment#

POST /payments/{id}/transaction/close with the current authorizationId and a persisted UUID Idempotency-Key closes an unfunded standalone Stellar-source protocol payment whose current approval, burn or transfer passed its signed time bound without an included receipt. closeEnabled: true marks eligibility. next-action suggests it as close-payment only when renewal is impossible: the action is signed, submitted or uncertain, or renewal cannot run because execution is paused or the payment's saved settings changed. The app may also offer it to abandon an expired approval or unsigned transfer.

Route proves the transaction can never execute: the saved envelope and any signature match, the network reports no receipt for its hash, a fresh closed ledger is past its maxTime, and the account sequence is still just below its nonce. In one database transaction it then:

  • records the proof on the action (closure), which becomes immutable;
  • releases the action's wallet sequence reservation, so other payments from the same wallet no longer receive WALLET_SLOT_RESERVED;
  • releases unused API-key spending holds and the payment credit hold exactly once;
  • marks the payment cancelled (nextAction: "cancelled", lastError.code: "STELLAR_ACTION_EXPIRED") with transaction.closed and draft.cancelled events;
  • sets the terminal tracking.status: "closed" (sourceVerified: false), because no receipt is awaited any more. The webhook outbox receives payment.cancelled, never a later payment.requires_attention.
const closed = await sdk.closePayment(paymentId, authorizationId, closeRequestKey);
// closed.nextAction === 'cancelled'; obtain a fresh quote for a new payment.

Closing sends and signs nothing. Execution does not need to be enabled. A closed payment cannot be resumed. An allowance granted by an earlier approval is not revoked: the messenger can only spend it inside a burn the wallet itself authorizes, and it expires at its own ledger. Repeat the same key if the response is lost; a missing or non-UUID Idempotency-Key returns 400 IDEMPOTENCY_REQUIRED. CLOSE_UNAVAILABLE means the payment cannot be closed. If the saved transaction is on the network or its sequence was used, Route records that as described above. Otherwise nothing changes: the payment is a composed leg, the sequence was skipped, the source was verified, or the ledger evidence was unavailable, stale or not yet past the time bound. A consumed or skipped sequence still needs operator review, like any missing receipt.

Missing Stellar receipts#

Refresh the existing payment to check its saved transaction hash. For NEAR Stellar source payments, Route-built Stellar protocol actions on mainnet and customer-signed CCTP mints on testnet, missing receipts include submissionObservation. NEAR preparations expose it under tracking.submissionObservation. The recovery report exposes it under evidence.transactions[]; protocol transaction receipts also include it. Testnet payment tracking includes it directly.

State Meaning Next step
not-observed The receipt was not found; the account sequence is immediately before this transaction and its network expiry has not passed. This does not establish mempool acceptance. Continue refreshing the same payment.
expired-unobserved A fresh closed ledger is past the envelope’s finite expiry and its sequence remains unused. Follow next-action. An eligible customer mint may offer renew-mint, an expired Stellar CCTP approval renew-approval, an unsigned Stellar protocol burn or transfer or an eligible NEAR Stellar deposit renew-source, and a signed Stellar protocol burn or transfer close-payment. Other actions require recovery review.
sequence-consumed The account sequence has reached or passed the saved transaction sequence, but its receipt is unavailable. A Stellar renewal or close check also records it for a never-signed action, bound to the saved envelope hash. Recover the original receipt before continuing. Sequence use alone does not establish success, failure or a refund.
sequence-gap The account sequence is behind the sequence immediately preceding this transaction. Review earlier wallet actions without creating a replacement payment.
unavailable Fresh network or account evidence could not be verified. Retry refresh. Do not treat the missing evidence as expiration or failure.

checkedAt dates the observation. closedAt is the verified ledger close time used for expiry; ledger identifies the account-read ledger. expiresAt comes from the Stellar envelope, independently of Route’s review deadline. Observations are saved evidence and may become stale.

Stellar RPC retains a bounded transaction history, so a missing receipt alone cannot establish that a transaction never executed. See Stellar’s transaction lookup reference.

These observations do not resend transactions, close payments, release wallet sequences or credit/spending reservations, or change processed payment totals. Keep the original payment and authorization IDs. Only an explicitly offered recovery operation can authorize a continuation; it performs its own fresh checks.

Bitcoin and Solana source recovery#

Refresh the existing payment to update preparation.tracking.sourceSubmissionObservation. For transactions signed by your wallet and saved in Route, the recovery report also exposes this as evidence.transactions[].sourceSubmissionObservation. This covers NEAR Bitcoin, Solana and Fogo sources and SwapKit Bitcoin sources. Route does not hold the wallet key: the saved signature is the one your wallet previously supplied.

State Meaning Next step
not-observed The original transaction is not visible in the queried evidence. Refresh the same payment. Absence is not proof that it never executed.
pending The original transaction or signature is reported, without a verified final source receipt. Wait and refresh; do not sign or send again.
receipt-reported A transaction receipt or spend by the original hash is reported. Continue receipt verification. This observation alone does not establish funding or delivery.
inputs-conflicted Another Bitcoin transaction references a reserved input. conflictingHashes identifies the observed candidates. Use the explicit Bitcoin recovery operation below to verify the outcome. This observation alone cannot adopt a hash or release holds.
blockhash-expired The Solana/Fogo signature was not found, the blockhash is invalid at finalized commitment, and finalized height is past the saved last-valid height. Follow next-action; eligible NEAR sources offer renew-source. Retain the original payment and signatures.
failure-reported Solana/Fogo reports an error for the saved signature. Verify the finalized transaction result and fees before deciding how to recover.
unavailable Network, freshness or transaction evidence could not be verified. Retry refresh. Outages and restricted reads never establish expiry or failure.

checkedAt records when Route observed the evidence; it is not a guarantee of current mempool state. Bitcoin reports are tied to the saved signed transaction and exact input references. A conflicting transaction might still be unconfirmed or later disappear. Solana history lookups can be incomplete even with searchTransactionHistory: true; expiry does not establish a past refund or non-execution.

next-action returns review-required for conflicts, blockhash expiry or reported errors. Existing verified source/destination receipts take precedence. These checks do not rebroadcast, replace hashes, cancel payments, release credit or spending holds, or increment processed USD totals. Keep refreshing the original payment while its receipts are reconciled.

References: Esplora transaction and outspend API, Solana signature status, Solana blockhash validity.

Intermediate funds in a composed route#

Read the parent payment's workflow.recovery.intermediates for the exact received asset, amount, network, wallet and receipt hash. These records do not assert a current spendable balance. If the parent offers advance, use continuation preview and review before preparing the next transfer. If a child already exists, continue or reconcile that saved child. Do not create another root payment to retry an uncertain intermediate transfer.

For a composed route with an expired remaining preview or a finalized intermediate refund, follow reviewed continuation. Refreshing estimates never authorizes replacing an uncertain signed transaction.

Close an unused EVM protocol action#

An EVM transaction has no on-chain expiry. An expired Route review, a missing receipt, or the absence of a saved signature does not prove that the wallet cannot submit the transaction later. To abandon an unfunded standalone protocol payment, read its current transaction. This workflow is available only when closeEnabled: true and closureRequirement: "finalized-nonce-cancellation" are returned, with no saved signature, submission attempt or wallet handoff. Both appear only after the action's review expires (expired: true); until then the next step is signing, and an early close returns EVM_CLOSURE_UNAVAILABLE with details.expiresAt. It covers the current approval, approval reset, burn or transfer; it does not close a destination mint or a composed payment. The dashboard offers the same workflow as Close this unused payment.

  1. Review the saved transaction's network, sender and nonce with the wallet owner. Closure needs one finalized transaction from that sender, on that network, at that exact nonce, other than the payment itself:

    • If the wallet already used the nonce for another transaction, such as an ordinary transfer after the payment was abandoned, use that transaction. It may have succeeded or reverted.
    • Otherwise the owner may send a zero-value transfer to its own address with no call data at that nonce. This separate transaction consumes native gas and needs the owner's explicit authorization. Route does not build, sign or send it automatically.

    Do not send the original payment as part of this recovery. A transaction that repeats the payment call with changed fees, or that calls, is logged by or pays the payment's provider contracts or deposit address (for example a token transfer to a SwapKit deposit address), is never accepted: it may be the payment itself. Keep the payment and its reservations for review, preserve that hash and do not send replacement funds.

  2. Wait for the transaction's canonical finality. A pending transaction, one confirmation alone or a wallet's success label is insufficient. Preserve its transaction hash.

  3. Call POST /payments/{id}/transaction/close with payments:write, a persisted UUID Idempotency-Key, and the saved authorization ID plus that hash:

{"authorizationId":"SAVED_AUTHORIZATION_ID","cancellationHash":"0xFINALIZED_TRANSACTION_HASH"}
const closed = await sdk.closePayment(paymentId, authorizationId, closeRequestKey, finalizedTransactionHash);

Route rebuilds the transaction from its signed fields and recovers the sender, then verifies the network, exact nonce, finalized receipt, the sender's finalized nonce count and, for anything other than a zero-value self-transfer, that it does not touch the payment's provider contracts or deposit address. It rechecks that the original payment has no funding evidence.

A consumed nonce proves only that the payload signed at that nonce can never execute. The wallet owner may have sent the same payment at another nonce, and many wallets choose their own nonce. Before closing a burn or transfer, Route therefore searches the sender's own provider events, from a block before the payment was first revealed (the preparation, which already returns the deposit instructions, a SwapKit build attempt's deposit address, or the action itself, whichever is earliest, less a 10-minute clock margin) through the current block, for the same token, amount, destination and recipient:

Provider Searched event Match
Circle CCTP DepositForBurn from the saved messenger, by depositor and burn token Amount, destination domain and mint recipient; for Stellar, the recipient declared in the forwarder hook
LayerZero OFT OFTSent from the saved OFT, by fromAddress Destination endpoint, then that transaction's own send calldata for the recipient and the amount after dust removal at the OFT's conversion rate from the saved quote (a dust-free re-send is the same payment; another amount is not). A send that cannot be decoded counts as a match
Axelar ITS InterchainTransfer from the saved service, by token ID and sourceAddress Destination chain, destination address and amount
Allbridge Source-token Transfer from the sender to the saved bridge contract That transaction's own bridge calldata: amount, destination chain and recipient (the relayer fee may differ). A transaction that is not a direct, decodable bridge call counts as a match
SwapKit ERC-20 deposit Token Transfer from the sender to the saved deposit address Any nonzero amount, since the address belongs to this swap

A transaction Route already saved for another of the project's payments (its signed or wallet-confirmed hash from the same wallet), or a Stellar burn whose forwarder hook names another of the project's payments, belongs to that payment and does not block closure. A hook's payment ID counts only when that payment is the same one: a Stellar-destination Circle payment with the same amount and payee from the same source network and sender, or a payment with a saved action whose calldata is exactly the found transaction's. A hook naming any other payment, or one Route never prepared, attributes nothing; the search lists it in equivalentScan.attributedTransactions. Recorded equivalent-execution evidence is re-attributed on every later close or cancellation attempt: if Route has since tied that transaction to another of its payments, the evidence is resolved and the search runs again. The database checks that attribution itself and records it with the evidence, which stays on record; the resolution is audited. The action's lastError then shows any other evidence still unresolved, or otherwise code: "EQUIVALENT_EVIDENCE_SUPERSEDED". A wallet-altered copy of the saved call is never resolved. Any other match returns EVM_CLOSURE_REVIEW_REQUIRED with details.observedState: "equivalent-execution" and details.evidence. Route records the evidence in its append-only evidence journal and saves it on the action as lastError with code WALLET_TRANSACTION_REVIEW_REQUIRED, as for an altered payment, in one transaction. The payment reads REQUIRES_ATTENTION, closure is withdrawn (a later close returns observedState: "review-recorded"), and its wallet reservation, API-limit holds and payment credit stay reserved for review. Route also never submits the saved call or hands it to the wallet afterwards, whatever the account nonces show: after a review refresh and a new signature, /execute and a new /transaction/broadcast still return 409 WALLET_TRANSACTION_REVIEW_REQUIRED (see payment transactions), because a copy the wallet queued at a later nonce could execute as soon as the saved nonce is used. A SwapKit native-asset deposit emits no event, and a saved payment call Route cannot decode cannot be matched, so those payments cannot be searched: closeEnabled stays false, and a close request returns EVM_CLOSURE_REVIEW_REQUIRED with equivalent-scan-unsupported. A workspace member can still close them after a manual check. If the search cannot complete, Route returns equivalent-scan-incomplete, records no evidence and releases nothing. Causes include pending wallet transactions, a transaction the wallet sent or queued while the search ran, a head block that changed during the search (these three carry details.retryable: true: retry once the wallet is idle), and an RPC failure or provider limit. An attempt that saved progress (below) also carries details.retryable: true. One attempt reads at most 256 log pages (2,000 blocks per page; 50,000 on Arbitrum) and, for LayerZero, 96 candidate transactions (192 for the oldest unsearched blocks) in 45 seconds. For an older action or a busy wallet, Route saves the contiguous searched range through the block that was finalized when the attempt started, and the message names the block it reached; retry the same request and the search continues from there until it reaches the current block. Approvals move no payment funds and need no search.

The search cannot see a transaction queued behind a nonce gap in the wallet's own pool until it reaches the network, nor a token transfer that another account makes later from this wallet's allowance. Keep the wallet idle while closing.

Success returns the closed preparation; payment reads report paymentState: "CANCELLED", transaction reads preserve closure.proof (proofType self-cancellation or nonce-consumed, with equivalentScan naming the searched contract, sender and block range), and next-action returns cancelled. Only that payment's unused wallet reservation, API-limit holds and payment-credit hold are released. Existing quote charges, network fees, token allowances and transaction history are retained.

Retry a lost response with the same request key and body. EVM_CANCELLATION_REQUIRED means a qualifying finalized transaction has not been established. Without cancellationHash, its details name the network, sender and nonce to use; with one, details.observedState reports what Route found and the message says what to do: nonce-consumed-pending or cancellation-pending means the transaction is not final yet, so retry the same hash later; not-observed means the network does not report it; original-verified means it is the payment itself, so keep the payment for review and do not send replacement funds. EVM_CLOSURE_REVIEW_REQUIRED means the same payment was found, or could not be ruled out, at another nonce, as described above. With observedState: "altered-payment", the hash repeats the payment call with changed fees, even if it is only queued behind the unused saved nonce; that evidence is recorded like a match, with the same refusals of submission and handoff. With observedState: "equivalent-execution" and a hash you supplied, the hash is the same payment signed by the wallet in another transaction (re-quoted, another value or envelope type, or a call to the payment's provider contracts), sent or still queued at any nonce; it is recorded the same way. With observedState: "unclassified-sender-transaction", the hash is another transaction the wallet signed that is not a nonce proof (it calls, is logged by or pays the payment's provider contracts or deposit address at the saved nonce, or it is at another nonce); it is recorded the same way, for an approval too. An altered spending approval moves no funds: it is recorded and its saved signature is never submitted, but the approval can still be closed with a finalized transaction at its saved nonce (closeEnabled stays true once its review expires); the same payment found at another nonce still blocks it. EVM_CLOSURE_UNAVAILABLE means the saved action does not qualify, or its review has not expired yet. None of these errors permits releasing holds, recreating the payment or sending replacement funds. Read and reconcile the existing payment first. A fresh quote and payment may be created after verified closure. Actions with a saved signature or wallet handoff use their separate recovery below; never submit them through this unsigned-action workflow.

Close after manual check#

When Route cannot close an unused EVM payment on its own, because it cannot search the wallet for the same payment at another nonce (for example a SwapKit native-coin deposit) or its search cannot complete (for example when the network provider keeps failing on the same blocks), next-action says so. Transaction reads report manualCloseEnabled: true for every expired unsigned burn or transfer, since Route learns whether its search completes only when it runs. A workspace member can then close it in the dashboard only with Close after manual check on the payment detail. It is not available to API keys: POST /api/projects/{projectId}/routing/payment-drafts/{paymentId}/transaction/close-attested refuses API-key requests with 403 DASHBOARD_SESSION_REQUIRED, and the /v1 API does not expose it.

The request needs a session with the payments.prepare permission and a sign-in within the last 15 minutes (otherwise 403 FRESH_SIGN_IN_REQUIRED), a UUID Idempotency-Key, and {authorizationId, cancellationHash, confirmNoEquivalentPayment: true, reason}, where reason (10–500 characters) says how the member checked. Route still requires the finalized transaction that consumed the saved nonce, exactly as above, and still refuses a payment for which it recorded evidence that the payment may have executed (an altered payment or the same payment at another nonce). Where it can, Route runs its own search first: a clear search closes the payment on Route's own proof, a match is recorded and refuses, and a search that a retry may complete (retryable, including an older payment's search that saved progress and continues on the next attempt) refuses. Only otherwise does the member's attestation close the payment.

Route does not verify the manual check. The closure proof has proofType: "manual-attestation", the verified nonceProofType, equivalentScan.status unsupported or incomplete with Route's reason, and attestation (member, session, time, reason and statement). The database accepts it only for a member with the permission, a session signed in within 15 minutes, and a fresh attestation. Holds are released and events emitted exactly as for any other closure; the preparation's lastError.code is EVM_ACTION_CLOSED_AFTER_MANUAL_CHECK, and the audit log records payment.evm_action_closed_after_manual_check naming the member. If the check was wrong and the payment executed, it is no longer tracked as open: check carefully, and never send replacement funds for a payment that may have executed.

Close a cancelled signed source transfer#

For a standalone mainnet payment with a saved EVM source signature on Ethereum, Base or Arbitrum, use the same recovery endpoints as wallet handoffs. This covers signed actions that were never submitted and actions with an uncertain submission result. Route preserves the original signature, hash, provider allocation and consumed nonce; it does not reset the action or sign a cancellation.

  1. Call POST /payments/{id}/transaction/broadcast-recover with authorizationId and the cancellation transactionHash. Route verifies the exact source account, network and nonce against a finalized, zero-value self-transfer with no call data. If the original transaction won instead, continue tracking its saved hash.
  2. When canClose: true, explicitly call POST /payments/{id}/transaction/broadcast-cancel with the same authorization ID and hash. The cancellation fee and its USD valuation must be available for the saved evidence. Route also searches for the same payment sent from the wallet at another nonce, as in the handoff cancellation; a match, recorded evidence or an unsearchable provider keeps the payment for review.
  3. Closure returns state: "closed" and paymentClosed: true. Unused payment-credit and rolling API-limit holds are released once. /next-action returns cancelled and /recovery returns closed. Quote charges and network fees remain unchanged.
  4. If a new transfer is needed, obtain a fresh quote and create a new payment with a new request key and wallet authorization. Never reuse the old signed action or deposit instructions.

The SDK methods are recoverWalletBroadcast(paymentId, authorizationId, transactionHash) and cancelWalletBroadcast(paymentId, authorizationId, transactionHash), including when your backend owns the signing key. These calls do not require a browser wallet.

A pending cancellation, missing receipt, expired review, conflicting funding evidence or committed spending limit retains the existing payment and holds. SOURCE_CANCELLATION_REVIEW_REQUIRED means this saved source cannot yet be closed. Destination mints, token-approval cancellation, non-EVM signed sources and other mainnet networks are outside this extension. Cancelling a funding transaction does not revoke existing token approvals.

Renew an expired NEAR Stellar source#

For native XLM and supported Stellar classic assets, next-action can return renew-source after the saved source envelope expires. This covers a saved signature and an uncertain submission. A missing receipt or an expired Route review alone does not permit replacement.

Call POST /payments/{id}/transaction/renew with the current authorizationId and a persisted UUID Idempotency-Key, or use sdk.renewSource(paymentId, authorizationId, requestKey).

Route verifies the original signature and transaction identity, a fresh closed Stellar ledger beyond the envelope’s finite time bound, and the sender’s unused sequence. NEAR must still report the same unfunded deposit within its original funding and refund deadlines. Current wallet authority, balances, receiving capacity, fees, policy and API-key restrictions must pass.

A successful response has object: "source_renewal", the old and new authorization IDs, and a new walletApproval. Retrieve next-action, sign the new intent message, confirm it, then sign and submit the new transaction through the normal API. Renewal itself sends no funds. The new transaction keeps the original payment, provider deposit, memo, amount, asset, recipient and sequence; its fee and expiry are reviewed again.

Persist the renewal request key. Repeating it returns the same replacement authorization even if the payment has since advanced; always read next-action before continuing. Old authorization IDs cannot sign or submit the replacement. preparation.renewalHistory exposes the newest twenty renewal proofs and previous source hashes, without signed payloads.

Unused credit and API-limit holds stay attached to the same payment. Renewal does not count as delivery, charge another payment fee or release those holds. If the old transaction executed, its sequence is consumed, evidence is unavailable, or the provider deposit deadline passed, retain the existing payment and reconcile it. This section covers NEAR Stellar classic source payments; it does not renew Soroban source calls or an already funded transfer. Solana and Fogo use the proof described below.

Renew an expired NEAR Solana or Fogo source#

When next-action offers renew-source, call sdk.renewSource(paymentId, authorizationId, requestKey) with a saved UUID request key. This uses the same endpoint and response as Stellar source renewal. It supports the released NEAR SOL/original SPL-token and native FOGO source builders.

Route verifies that the old blockhash has expired at finalized commitment, checks the exact saved signature and receipt, and examines linked finalized blocks back to the original blockhash. The scan is bounded to 512 blocks within the most recent 2,048 slots. Missing, inconsistent or older history requires reconciliation and leaves the action unchanged. A missing signature in an RPC index alone is insufficient.

The original provider deposit must still be unfunded and within its funding deadlines. The replacement preserves its asset, amount, sender and destination, with a fresh blockhash and reviewed network fee. Read next-action, approve the new wallet intent, then sign the new transaction. Old signatures remain in history and cannot be submitted through Route after renewal. Credits and API-limit holds remain attached to the same payment.

Reconcile a Bitcoin replacement#

For NEAR or SwapKit native Bitcoin sources, submit a replacement hash only after the wallet has created and broadcast that transaction. Route verifies the outcome; this endpoint does not construct a replacement or increase its fee.

const recovery = await sdk.recoverBitcoinSource(
  paymentId, authorizationId, replacementHash,
  'funding', // or 'cancellation' to explicitly close an unfunded action
  recoveryRequestKey,
);
const next = await sdk.getNextAction(paymentId);

POST /payments/{id}/transaction/bitcoin-recover requires payments:write, a UUID Idempotency-Key, and the exact same request body on retries. Route checks at least six canonical confirmations, every original input and signature, and each output. Supported replacements spend exactly the saved ordered input set. A funding replacement pays the original deposit its exact amount; any change returns to the source wallet. A cancellation returns funds only to that wallet, and the provider deposit must have no confirmed or mempool funding. Additional inputs, unrelated outputs or changed deposit amounts require separate reconciliation.

Verified funding becomes the tracked source hash on the existing payment. transaction.sourceRecovery preserves its link to the original hash; delivery still requires independent destination verification. Original signatures and spent-input reservations remain in history. No second payment credit hold is created.

A verified cancellation closes an unfunded standalone payment or unfunded first composed transfer, releasing unused payment credits and API-limit holds once. A later composed transfer closes only that attempt, retaining the funded parent and accounting for the cancellation fee; preview a fresh continuation on the parent. BTC pricing must be fresh to record that fee. Quote charges and network fees remain payable. Unconfirmed, missing or conflicting evidence leaves the payment and holds unchanged.

For an EVM- or Aptos-source NEAR payment reporting MINIMUM_OUTPUT_NOT_MET and quoteReviewAvailable: true, review the same captured allocation before requesting wallet authorization. Standalone payments require explicit acceptance of the revised minimum and cost ceiling. Composed continuations cannot reduce the parent’s final minimum. Acceptance does not submit funds.

TRON settlement amount differences#

TRON_SETTLEMENT_AMOUNT_MISMATCH means the solidified recipient credit differs from the provider report. Keep tracking the same payment; do not send another deposit. Route may reconcile Ethereum ERC-20 → TRON USDT payouts using linked source funding, NEAR withdrawal, actual bridge fees and the exact TRON recipient credit. Completion requires finalized evidence, the accepted recipient minimum and an exclusive payout claim. A larger balance alone is insufficient. Unexplained differences remain pending for investigation.

Recover an expired Stellar protocol source#

For Circle CCTP, LayerZero and Axelar Stellar sources, follow the payment's next-action. An expired unsigned burn or transfer may offer renew-source. Call POST /payments/{id}/transaction/renew with its authorizationId and a new UUID Idempotency-Key. Route verifies non-execution and the unused wallet sequence, then builds a replacement with fresh wallet, fee, policy and amount checks. Sign only the newly returned action.

An expired signed source cannot be renewed. When close-payment is offered, call POST /payments/{id}/transaction/close with its authorizationId and an idempotency key. Route requires proof that the saved transaction can no longer execute and its sequence remains unused. It closes the unfunded standalone payment and releases its sequence and unused holds; it retains all signatures and transaction evidence. Obtain a new quote to start a new payment.

An abandoned approval may also expose transaction.closeEnabled as an explicit alternative to renewal. Missing receipts alone never permit closure. Included transactions and composed payments are excluded; CLOSE_UNAVAILABLE preserves the existing payment and reservations. These operations submit no funds. The SDK exposes renewSource, renewApproval and closePayment. For Stellar, call closePayment(id, authorizationId, key). An expired unsigned EVM action also needs the finalized transaction hash as a fourth argument; see closing an unused EVM protocol action.

Links from earlier guides

This section is now in Track and recover.