Skip to main content
Every ONRAMP and OFFRAMP order includes an FX conversion leg that exchanges the source asset for the destination asset. That embedded leg runs automatically after the source leg settles — you do not create it directly. This page explains how to drive conversion failure outcomes for it in sandbox. A crypto-to-crypto conversion is its own standalone order, though: POST /v2/orders with a wallet source and a wallet destination resolves to type: conversion and moves a customer’s balance from one chain to another. It is documented in The standalone crypto conversion order below.
This page applies to both order shapes. An order that names a source is funded from a balance the customer already holds; an order created with no source — sending sourceAsset instead — is funded at an address Conduit publishes on the order, by a real testnet transfer. Both then run the same conversion leg and fail the same way. See Deposit-Funded Orders and the deposit-funded walkthrough.
The reason field is optional (max 500 chars). When supplied, it is recorded as the note on the cancelled source transfer, not on the order — order.failed.failureMessage and the polled GET /v2/orders/:id response carry the standard text for the failure code, exactly as in production. Do not expect your reason text to appear on the order today; a later update will surface it on order.failed.failureMessage, matching the transaction-level failure levers.

The standalone crypto conversion order

To move a customer’s crypto balance from one chain to another — for example USDC on Ethereum to USDC on Polygon — create an order with a wallet source and a wallet destination, each naming its own chain. Conduit resolves it to type: conversion. There is no type field to send; the source/destination shapes determine it.
202 Accepted with the order pending. It runs two on-chain legs: wallet_to_ops moves the source asset out of the customer’s wallet, and ops_to_wallet delivers the destination asset. Terminal status arrives on order.succeeded / order.failed.
On the real-testnet sandbox this conversion is real on-chain and a non-custodial source needs a signature. The wallet_to_ops source leg leaves the customer’s non-custodial wallet, so it parks at transaction.awaiting_signature — approve with a real passkey or a machine stamp at POST /v2/signing-requests/:id/approve (the simulate/cosign lever returns 409 SANDBOX_SIGNING_SIMULATION_UNAVAILABLE). Both legs broadcast real testnet txHashes you can verify on each chain’s explorer, and finality takes minutes. Fund the source wallet from a faucet — a deposits/simulate balance cannot be broadcast. A wallet provisioned before real testnet was enabled is refused with 422 LEGACY_MOCK_WALLET_UNSUPPORTED. See Use a real testnet and Machine-signer stamping.
Crypto conversions are not available to US customers — the order is refused at creation. Provision a non-US customer to test this flow.

How to fail a conversion

Use the orders/:id/simulate/conversion-failed endpoint to force a conversion to a failed terminal state. The endpoint is timing-independent: call it at any point after order creation. If the conversion is already running, it is driven to failed immediately; otherwise the failure is armed and applied as soon as the conversion starts. The order is driven to failed and order.failed is emitted.
Returns 200 OK with the order at its current state. Returns 404 if the order is not found. Replays against an already-terminal order return 200 with the current resource (idempotent).
Rate-lock expiry SLA. POST /v2/sandbox/orders/:id/simulate/rate-lock-expired returns 200 OK with the order at its current state and the order reaches cancelled (expired) within about 3 seconds via an immediate background sweep tick. No polling backoff needed; no need to wait for the scheduled 30-second sweep.
There is no create-time outcome locking for conversions. This endpoint is the only way to force a conversion failure on demand, and it works at any point after the order exists. A conversion can also fail on its own when the transfer that delivers the destination asset does not complete; the order reaches failed the same way, with a failureMessage Conduit writes.

Webhook events

Conversion outcomes surface on the order’s webhook topic. There is no standalone conversion webhook. Intermediate state (conversion in progress, source settled, etc.) is not conveyed via webhooks. Poll GET /v2/orders/:id to observe the current order state between terminal events. See the Webhooks reference for full payload schemas.

Errors

Conversion failures produce order.failed on the order. The payload carries reasonCode (insufficient_funds / provider_unavailable / provider_rejected / internal_error / cancelled) describing the failure category. See Error codes for the broader catalog used by other event types. A cross-chain conversion delivers its destination asset from sandbox’s shared testnet liquidity, so it draws on the same per-chain, per-UTC-day cap an onramp does. A conversion whose destination leg would carry the customer’s net draw for the day over the cap on the destination chain returns 422 SANDBOX_ONRAMP_DAILY_CAP_EXCEEDED at creation or execution. The default is small, so the examples above use "amount": "1.00" — an amount a new customer can execute. See ONRAMP orders — Errors for the full cap semantics, how the cap resets at UTC midnight, and how a settled offramp frees headroom sooner.

See also