Skip to content
Logo

POST /quotes/:id/accept

Turn a snapshot into an order.

Request body

All fields are optional, as is the body itself: a bodyless POST accepts the snapshot's best-ranked quote. Two fields become required for specific inline sources: from_address for a blockchain source whose quote has no sending wallet (unless the payment is funded through a deposit address), and source_account_number when the chosen quote's acceptance_requirements.source_account_number_required is true.

FieldTypeNotes
quote_idstringThe exact rail to accept. Omit (or pass {}) and the snapshot's best_quote_id is used.
referencestringMessage to be included in the transaction. Commonly set to invoice IDs. Echoed back on the resulting RampOrder.reference. At most 128 characters, limited to letters, numbers, spaces, dashes, and colons — see Reference format.
commentstringFree-form note for the order, surfaced on every read of RampOrder.comment. For audit logs / dashboards.
filesobject[]Compliance attachments documenting the purpose of the payment. Send each entry as an object with a type (one of the Supporting document types) and a file, the document as a base64 data URI: data:<mime>;base64,<contents>. An object without a type is rejected. A bare data-URI string entry is still accepted but deprecated: from November 1, 2026, every file must be an object with a type. Check the chosen quote's acceptance_requirements.files_required before accepting: when true, attach at least one document. Additional documents may be requested during processing. When a required attachment is absent the accept fails with a typed violation, see Document required. The recipient never sees these files. PDF / JPEG / PNG. Minimum 200×200 px for images, maximum 5 MB per file, at most 4 files.
from_addressstringSending wallet for a blockchain-sourced payment with no attached source account. Overrides the source address captured when the quote was created. Required when neither the quote nor an attached account identifies the source, unless the payment is funded through a deposit address (the order comes back awaiting_funds with funding_instructions.toAddress), where it is optional. Rejected for fiat sources and attached source accounts.
return_addressstringRefund address for stablecoin-sourced payments. If the payment fails or expires, the funds are returned to this address on the source chain. When omitted, it defaults to the sending wallet when one is known. Only valid when the source leg is a stablecoin. Rejected with a 400 for fiat-sourced payments.
source_account_numberstringBank account number the payment will be funded from. Required when the chosen quote's acceptance_requirements.source_account_number_required is true: the local network needs the originating account declared before funds are sent. Rejected with a 400 when it is false.
expired_quote_behaviorenumWhat happens to a payment funded after the quote expired. Defaults to "refund_payment". Only values listed on the chosen quote's supported_expired_quote_behaviors are accepted. Anything else fails with a typed violation, see Expired-quote behavior.
expired_quote_tolerance_bpsintegerWith refund_payment: how far a payment priced again after the quote expired may fall short of the accepted amount, in basis points (0–500) of what the recipient receives after fees, and still be sent. Defaults to your org's expired_quote_tolerance_bps. Rejected alongside a flexible_* behavior. See Expired-quote behavior.
payment_reasonenumWhy the payment is being made. Settlement networks require one of these fixed categories — banks key compliance decisions off it — so supply one on every payment. It is not shown to the recipient. Currently optional for backwards compatibility (when omitted, the payment is settled under a default reason), but the seismic-orchestration client already requires it and it will become required here. One of the values under Payment reasons.
source_of_fundsenumWhere the money being sent came from. Defaults to the source of funds recorded on the sender's verification profile; set it here to declare a different one for this payment only — the profile is left unchanged. Settlement networks require one of these fixed categories, so a payment with neither is declared as other. One of the values under Sources of funds.

Reference format

reference travels with the payment and can land on the beneficiary's bank statement, so it is capped at 128 characters and restricted to the set every settlement network accepts:

  • letters A–Z and a–z
  • digits 0–9
  • spaces
  • dashes (-)
  • colons (:)

Anything else — underscores, periods, commas, slashes, #, @, accented letters — fails with an InvalidRequest whose violations array pins the reference field and names the first offending character:

{
  "ok": false,
  "error": {
    "code": "InvalidRequest",
    "message": "1 field needs attention",
    "violations": [
      {
        "field": "reference",
        "reason": "invalid_format",
        "description": "`reference` may only contain letters, numbers, spaces, dashes, and colons. Remove '_'."
      }
    ]
  }
}

A reference longer than 128 characters is rejected the same way, with a too_long reason instead:

{
  "ok": false,
  "error": {
    "code": "InvalidRequest",
    "message": "1 field needs attention",
    "violations": [
      {
        "field": "reference",
        "reason": "too_long",
        "description": "`reference` may be at most 128 characters; this one is 135."
      }
    ]
  }
}

Dispatch on the field + reason pair ("reference" + "invalid_format" or "too_long"), never on the description text. Nothing is charged or dispatched — the accept is rejected before the snapshot is consumed, so the snapshot stays acceptable and a corrected retry works until the quote expires.

UUIDs and typical invoice ids (invoice-2026-04-001) satisfy this as-is. If your ids use other separators, strip or substitute them before sending; comment is free-form and is a better home for anything that doesn't need to travel with the payment.

Supporting document types

Each files entry declares its type, one of:

  • invoice
  • purchase_order
  • delivery_slip
  • contract
  • customs_declaration
  • bill_of_lading
  • other

Compliance review reads the document as its declared type, so a payment held for review clears faster when the type matches the document. Use other only when no other type describes it. A bare data-URI string entry declares no type; it is deprecated and rejected from November 1, 2026.

{
  "files": [
    {
      "type": "invoice",
      "file": "data:application/pdf;base64,JVBERi0xLjcK…"
    }
  ]
}

Payment reasons

payment_reason is one of:

  • charitable_contributions
  • education_fees
  • employee_salaries_or_wages
  • gifts
  • investments
  • dividend
  • purchase_of_goods
  • purchase_of_services
  • personal_transfers
  • rent
  • loans
  • utility_bills
  • family_support
  • friends_support
  • real_estate
  • insurance
  • intercompany_transfer
  • taxes
  • travel

Both family_support and friends_support remain accepted, but each is settled under a single consolidated "family and friends support" category.

dividend is settled under the investments category.

Sources of funds

source_of_funds is one of:

  • salary
  • savings
  • business_revenue
  • company_capital
  • investment_returns
  • inheritance
  • trust
  • gift
  • grant
  • sale_of_assets
  • real_estate
  • loan
  • private_capital
  • marital
  • winnings
  • other

The same set the sender's verification profile records, so a payment-level declaration and a profile one are directly comparable.

Request headers

HeaderNotes
Idempotency-KeyOptional. Any unique string up to 256 characters, generally a UUID. Replays of the same snapshot id + same Idempotency-Key resolve to the same order instead of returning AlreadyAccepted. Echoed onto RampOrder.idempotency_key. Recommended for any caller doing automatic retries.

Response 200

The full order is returned inline. No follow-up GET /v0/orders/:id needed to read funding_instructions or lifecycle status.

{
  "id": "f01e…",
  "status": "awaiting_funds",
  "source": {
    "amount": "100.00",
    "currency": "EUR",
    "rail": "sepa",
    "account_id": "5d8a…"
  },
  "destination": {
    "amount": "108.42",
    "currency": "USDC",
    "rail": "base",
    "account_id": "9b2f…"
  },
  "funding_instructions": {
    "iban": "GB29NWBK60161331926819",
    "reference": "REF-8A3C"
  },
  "reference": "invoice-2026-04-001",
  "comment": "Off-ramp for Acme March payroll",
  "payment_reason": "employee_salaries_or_wages",
  "idempotency_key": "8b3c4d5e-…",
  "created_at": "2026-04-12T14:23:01.000Z"
}

Fields

FieldTypeNotes
idstringLocal order id. Stable forever.
statusenumawaiting_funds | pending | under_review | processing | sent | completed | expired | failed | canceled | refunded | unknown.
status_reasonstringOptional. Why the payment reached its current status, present when the payment settles into a terminal failure: a refunded or failed order carries the settlement network's reason code. An under_review order held for a supporting document carries documents_required, documents_under_review, documents_rejected, or documents_approved. documents_approved stays on the order once it returns to processing. Omitted for healthy orders and when no reason was reported. See Status reasons for the known codes.
sourceobjectResolved source leg: amount, currency, rail, and account_id when the quote's source was an attached account. account_id is absent when the source was an inline { currency, rails? } descriptor, i.e. the payment is funded by following funding_instructions or from an external crypto wallet. For a payment funded from an external crypto wallet, also carries from_address (the sending wallet) and chain once Seismic observes the settlement.
destinationobjectResolved destination leg: amount, currency, rail, account_id. account_id is always present: a quote's destination is always a registered account, and an accept whose destination can't be resolved to one is rejected rather than returning an order. Never carries from_address or chain.
funding_instructionsobjectOptional. Settlement details: IBAN/account/reference for fiat-funded onramps. Omitted when the chosen rail doesn't require pre-funding (e.g. crypto→crypto), or when Seismic hadn't received them yet at insert time (refreshed asynchronously via webhook).
referencestringOptional. Echoes the request's reference.
commentstringOptional. Echoes the request's comment.
payment_reasonenumOptional. Echoes the request's payment_reason (see Payment reasons). Omitted when the caller didn't supply one.
transaction_hashstringOptional. On-chain settlement hash for the order's crypto leg, present once the order settles over a blockchain rail. Absent for fiat-only orders and until settlement is observed.
uetrstringOptional. SWIFT Unique End-to-end Transaction Reference (UETR) of the order's fiat leg, present once the settlement network reports it for a wire payout. Give it to the beneficiary's bank to trace the payment. Absent for other rails and until the network reports it.
idempotency_keystringEchoes the Idempotency-Key header (or a server-minted UUID if absent).
created_atstringISO-8601 timestamp.

Status reasons

When a payment settles into a terminal refunded or failed status, status_reason carries the settlement network's reason code, forwarded verbatim. These are the codes observed so far:

CodeMeaning
FUNDING_RECEIVED_AFTER_QUOTE_EXPIREDFunds arrived after the quote expired. Refunded unless the order opted into flexible_destination_amount.
AMOUNT_TOO_LOW_FOR_CURRENCY_PAIR_AND_RAILThe received amount is below the corridor's minimum.
AMOUNT_TOO_HIGH_FOR_CURRENCY_PAIR_AND_RAILThe received amount is above the corridor's maximum.
INVALID_EXTERNAL_ACCOUNT_DETAILSThe destination account's details failed validation at settlement.
INVALID_EXTERNAL_ACCOUNT_NUMBERThe destination account number was rejected.
INVALID_ROUTING_CODEThe destination's routing code was rejected.
INVALID_EXTERNAL_ACCOUNT_HOLDER_NAMEThe destination account holder's name was rejected.
INVALID_EXTERNAL_ACCOUNT_HOLDER_ADDRESSThe destination account holder's address was rejected.
EXTERNAL_ACCOUNT_HOLDER_ADDRESS_IS_PMB_OR_PO_BOXThe destination account holder's address is a PO box or private mailbox, which the rail doesn't accept.
EXTERNAL_ACCOUNT_DEPOSIT_LIMIT_EXCEEDEDThe payment would exceed the destination account's deposit limit.
FUNDS_RETURNED_BY_RECEIVING_BANKThe receiving bank returned the payment.
BLOCKED_BY_INTERMEDIARY_BANKAn intermediary bank blocked the payment.
RETURNED_AT_BENEFICIARY_REQUESTThe beneficiary asked for the payment to be returned.
RFI_NOT_ANSWERED_IN_TIMEA compliance request for information went unanswered before its deadline.
BLOCKED_BY_COMPLIANCEThe payment was blocked by a compliance review.
COMPLIANCE_BLOCKEDSame as BLOCKED_BY_COMPLIANCE. Some rails report this spelling.
NO_GAS_IN_WALLET_TO_PAY_TRANSACTION_FEEA crypto-leg settlement could not cover the network fee.
payment_returned_<code>The receiving bank returned the payment; <code> is the network's return code (for example ac01, an incorrect account number).
fiat_payment_failedThe fiat leg could not be completed and the funds went back to the source.

The set is open: settlement networks add codes, so treat any unrecognized value as an opaque string rather than failing on it. Use status for control flow and status_reason for surfacing the explanation.

An under_review order can also carry one of these codes of Seismic's own while the payment is held for a supporting document:

CodeMeaning
documents_requiredThe payment is waiting for a supporting document. Submit one with POST /customers/orders/:id/documents.
documents_under_reviewA submitted document is under review.
documents_rejectedThe submitted document was turned down. Submit another with POST /customers/orders/:id/documents.
documents_approvedThe review passed and the payment continues: the order returns to processing.

A payment can also be held for a compliance review before anything is sent, right after the accept. Such an order reads under_review with no status_reason until the review clears, then moves to the status the settlement reports (processing, awaiting_funds, …); a payment the review blocks ends failed with BLOCKED_BY_COMPLIANCE, like any compliance block. Each change fires an order.status_changed webhook.

Errors

See the Errors reference for the full code enum:

CodeStatusMeaning
QuoteIdInvalid400quote_id isn't in the snapshot. On a snapshot created with ?named=1, an option that isn't named isn't in it either.
QuoteNotFound404Snapshot id unknown.
AlreadyAccepted409Snapshot has already been turned into an order with a different Idempotency-Key (or no key). With a matching key, the prior order is returned instead — or, while that first accept is still in progress, this same 409; retry with the key to receive the order.
QuoteNotReady422Snapshot is still pending, or it finished with nothing priced and no failure to report.
QuoteExpired422The chosen quote's expires_at has passed.
NoNamedQuote422The snapshot was created with ?named=1 and no named route priced. Create a new quote. A named route that failed returns its own error instead.
InvalidRequest400Malformed body: a files object has no type or an unknown one, the corridor requires a compliance attachment and files was empty (see Document required), the chosen quote doesn't support the requested expired_quote_behavior (see Expired-quote behavior), expired_quote_tolerance_bps is above 500 or sent with a flexible_* behavior, or reference carries an unsupported character or exceeds 128 characters (see Reference format).

A finished snapshot with nothing priced returns the same error as GET /quotes/:id, whether or not the body names a quote_id.

Document required

Every priced quote includes acceptance_requirements.files_required. When true, collect a supporting document and include it in files before accepting that quote. This signal describes payment acceptance, separately from the external-account registration requirements.

Documents are required for destinations in INR, CNY, and GHS at any amount, and BRL when the quote's out.amount is at least 50,000. The signal uses each quote's destination amount for both exact-in and exact-out requests. Some routes also require one at any amount when the beneficiary is not the customer, such as certain payouts over swift; GET /quotes/requirements lists them as route_conditions. Check the selected quote rather than hardcoding these rules; they can change.

On such a route, the first file in files is submitted for review with the order. The document must show the relationship between the customer and the beneficiary. While it is reviewed, the order reads under_review with status_reason: documents_under_review; if it is turned down, the order reads documents_rejected and takes a new one through POST /customers/orders/:id/documents (see Status reasons).

A payment funded by sending stablecoins to a deposit address, with no source account, is placed only once the deposit arrives, so files cannot travel with it. Its quote leaves such a route out of files_required, and the order asks for the document with status_reason: documents_required instead.

Known requirements are checked before an order is dispatched. Additional document requirements may be encountered during processing, so keep handling the typed rejection. When a required attachment is absent, the accept fails with an InvalidRequest whose violations array pins the files field:

{
  "ok": false,
  "error": {
    "code": "InvalidRequest",
    "message": "1 field needs attention",
    "violations": [
      {
        "field": "files",
        "reason": "missing",
        "description": "Please upload an invoice for the payment."
      }
    ]
  }
}

Dispatch on the field + reason pair ("files" + "missing"), never by matching the description text, which is free-form and may change. Collect a document from your user and retry the accept with files populated. The snapshot stays acceptable until the quote expires. The TypeScript client ships this check as acceptRequiresFiles.

Expired-quote behavior

A quote is only good for a short window. expired_quote_behavior decides what happens when the funds land after it lapsed:

  • refund_payment — the funds are returned. The default when the field is omitted.
  • flexible_destination_amount — the payment is re-quoted at the market rate and settled, so the recipient's amount moves.
  • flexible_source_amount — the payment is re-quoted at the market rate and settled, so the amount pulled from the sender moves. Requires a registered account on the source leg: a manually funded payment has nothing to re-debit.

A payment funded by sending stablecoins to a deposit address (the order comes back awaiting_funds with funding_instructions.toAddress) is priced again when the deposit arrives:

  • With refund_payment (or no value), the payout goes ahead only if it pays the out.amount you accepted, less your tolerance, or more. Otherwise the order ends expired with nothing sent, and the funds remain in the customer's wallet.
  • With flexible_destination_amount, the payout goes ahead at the new price, so the recipient's amount can move.

A payment held for a compliance review whose quote expires before the review clears is priced again the same way when it is released: sent if the new price is within your tolerance, otherwise ended expired with nothing sent.

Tolerance. expired_quote_tolerance_bps is measured on what the recipient receives after fees, for the same amount sent, so it compares the effective rate of the accepted quote with the new one. 0 sends only at the accepted price or better; 500 accepts up to a 5% worse price. When the accept omits it, your org's expired_quote_tolerance_bps applies (1 unless you change it with PATCH /org).

Each quote lists the behaviors it can honor in its supported_expired_quote_behaviors field. Check it before setting expired_quote_behavior. When the request carries a value the chosen quote doesn't support, the accept fails with an InvalidRequest whose violations array pins the field and echoes the supported set in allowed:

{
  "ok": false,
  "error": {
    "code": "InvalidRequest",
    "message": "1 field needs attention",
    "violations": [
      {
        "field": "expired_quote_behavior",
        "reason": "not_in_allowed_set",
        "description": "This quote does not support the requested expired-quote behavior; see the quote's `supported_expired_quote_behaviors`.",
        "allowed": []
      }
    ]
  }
}

Dispatch on the field + reason pair ("expired_quote_behavior" + "not_in_allowed_set"). Retry without the field to accept with the default behavior (refund_payment).

Examples

curl -X POST "$SEISMIC_ORCHESTRATION_URL/v0/quotes/9d8c…/accept" \
  -H "Api-Key: $SEISMIC_ORCHESTRATION_API_KEY" \
  -H "content-type: application/json" \
  -d '{}'