Skip to main content
This API allows you to integrate crypto on/off ramps into your application. Your customers can buy crypto with fiat (onramp) or sell crypto for fiat (offramp).

Integration Flow

The typical integration follows this pattern:
  1. Onboard Customer
  2. Get Assets
  3. Create Quote
  4. Create Order
  5. Monitor Order via Webhooks

1. Onboard Customer

Generate a presigned URL and have your customer complete KYC verification.
POST /ramp/onboarding-url
{
  "customerId": "34fcc67a-2454-4578-8435-e2bf03b4dc30",
  "bankAccountId": "a1b2c3d4-5678-9abc-def0-1234567890ab",
  "publicKey": "GDUKMGUGD3V6VXTU2RLAUM7A2FABLMHCPWTMDHKP7HHJ6FCZKEY4PVWL",
  "blockchain": "stellar"
}
ID Consistency is CriticalThe customerId, bankAccountId, and publicKey you provide during onboarding are linked together on Etherfuse’s side. You must use these same values when creating quotes and orders for that customer:
  • customerId — You generate this UUID. Use the same value when creating quotes.
  • bankAccountId — You generate this UUID. Use the same value when creating orders.
  • publicKey — The customer’s wallet address. This wallet is registered with Etherfuse during onboarding. Use the same value when creating orders.
Setup checklist:
  1. Generate a UUID for customerId — store it in your system
  2. Generate a UUID for bankAccountId — store it in your system
  3. Call POST /ramp/onboarding-url with both IDs and the customer’s publicKey
  4. Have the customer complete onboarding (KYC + bank account linking)
  5. Never change these IDs after onboarding — they are permanently bound
All three are linked during onboarding and must be used together. Each customer should have their own unique customerId and bankAccountId. You cannot mix and match IDs across different customers — for example, using a bankAccountId that was onboarded with a different customerId and publicKey will cause order creation to fail.The customer’s wallet (publicKey) is registered with Etherfuse as part of onboarding. The customer must complete the full onboarding flow (including KYC verification) before their wallet can be used for orders.
The customer must complete KYC verification before they can transact. There are two options:
  • Presigned URL flow: The customer visits the returned presigned_url to complete identity verification and link their bank account in the Etherfuse UI.
  • Programmatic KYC: You collect identity data in your own UI and submit it via API, allowing you to pre-populate the KYC data on behalf of the customer. See the Testing KYC guide.
After all data is submitted, Etherfuse reviews the information for accuracy before approving the customer. You’ll receive a customer_updated webhook when verification is complete.

2. Get Available Assets

Call /ramp/assets to show your user which assets they can buy or sell.
GET /ramp/assets?blockchain=stellar&currency=mxn&wallet=GDUKMGUGD3V6...
Response:
{
  "assets": [
    {
      "symbol": "USDC",
      "identifier": "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
      "name": "USD Coin",
      "currency": "mxn",
      "balance": "100.50",
      "image": "https://example.com/usdc.png"
    },
    {
      "symbol": "CETES",
      "identifier": "CETES:GCRYUGD5NVARGXT56XEZI5CIFCQETYHAPQQTHO203IQZTHDHH4LATMYWC",
      "name": "CETES",
      "currency": "mxn",
      "balance": "50.00",
      "image": "https://example.com/cetes.png"
    }
  ]
}
Use the identifier field when creating quotes.
Exchange RatesFor raw USD exchange rates (e.g., USD to MXN), use the public GET /lookup/exchange_rate endpoint — no authentication required. The /ramp/assets endpoint is for discovering rampable assets and their identifiers, not exchange rates.

3. Create Quote

Get pricing for the conversion. Quotes expire after 2 minutes.
POST /ramp/quote
Onramp (buying USDC with MXN): Use the same customerId from onboarding:
{
  "quoteId": "844393ca-be57-4817-a58a-5b60e2792c10",
  "customerId": "34fcc67a-2454-4578-8435-e2bf03b4dc30",
  "blockchain": "stellar",
  "quoteAssets": {
    "type": "onramp",
    "sourceAsset": "MXN",
    "targetAsset": "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
  },
  "sourceAmount": "1000"
}
Offramp (selling USDC for MXN):
{
  "quoteId": "a44393ca-be57-4817-a58a-5b60e2792c12",
  "customerId": "34fcc67a-2454-4578-8435-e2bf03b4dc30",
  "blockchain": "stellar",
  "quoteAssets": {
    "type": "offramp",
    "sourceAsset": "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
    "targetAsset": "MXN"
  },
  "sourceAmount": "50"
}
Quote Response:
{
  "quoteId": "844393ca-be57-4817-a58a-5b60e2792c10",
  "blockchain": "stellar",
  "quoteAssets": {
    "type": "onramp",
    "sourceAsset": "MXN",
    "targetAsset": "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
  },
  "sourceAmount": "1000",
  "destinationAmount": "49.50",
  "destinationAmountAfterFee": "49.40",
  "feeBps": "20",
  "feeAmount": "2.00",
  "exchangeRate": "0.0495",
  "expiresAt": "2025-12-17T18:31:46.195307961Z"
}

4. Create Order

Execute the order using the quote. The bankAccountId and publicKey must match the values used when this customer was onboarded. The order inherits the direction and amounts from the quote.
POST /ramp/order
{
  "orderId": "f7e8d9c0-1234-5678-9abc-def012345678",
  "bankAccountId": "a1b2c3d4-5678-9abc-def0-1234567890ab",
  "publicKey": "GDUKMGUGD3V6VXTU2RLAUM7A2FABLMHCPWTMDHKP7HHJ6FCZKEY4PVWL",
  "quoteId": "844393ca-be57-4817-a58a-5b60e2792c10"
}
Response (Onramp):
{
  "onramp": {
    "orderId": "f7e8d9c0-1234-5678-9abc-def012345678",
    "depositClabe": "646180157034567890",
    "depositAmount": 1000.00
  }
}
Response (Offramp):
{
  "offramp": {
    "orderId": "f7e8d9c0-1234-5678-9abc-def012345678"
  }
}
For onramps, the customer deposits MXN to the depositClabe. For offramps, see the Offramp Signing section below.

5. Monitor Order via Webhooks

After creating an order, monitor its progress via webhooks. Onramp:
  1. The customer must send MXN to the depositClabe returned in the create order response
  2. Once we confirm receipt of the fiat, you receive order_funded
  3. We mint/transfer crypto and send it to the customer’s wallet
  4. You receive order_completed with confirmedTxSignature containing the blockchain transaction hash
Offramp:
  1. You receive order_created with burnTransaction containing a partially signed, encoded transaction
  2. Have the customer sign the burnTransaction using a wallet adapter and submit it to the blockchain (see Offramp Signing)
  3. Once confirmed on-chain, you receive order_funded
  4. We send MXN to the customer’s bank account
  5. You receive order_completed
Swap (crypto to crypto):
  1. Create a quote with type: "swap" specifying source and target crypto assets
  2. Call /ramp/swap with the quoteId to initiate the swap
  3. You receive swap_updated webhook with transaction to sign
  4. Have the customer sign and submit the transaction
  5. You receive swap_updated when completed
If a transaction expires before submission, use /ramp/order/{order_id}/regenerate_tx or /ramp/swap/{order_id}/regenerate_tx to get a new transaction. See the Webhooks section below for detailed payload examples.
Use webhooks for order tracking. Webhooks deliver order updates as soon as they happen. If you poll the list orders endpoint instead, be aware there may be a brief indexing delay before newly created orders appear. We recommend using webhooks as the primary mechanism for tracking order progress, and storing the orderId from the create order response for immediate reference.

Offramp Signing

When an offramp order is created, the order_updated webhook includes a burnTransaction field containing a partially signed, encoded transaction. To complete the offramp:
  1. Take the burnTransaction from the webhook payload
  2. Sign it using a wallet adapter (e.g., Stellar SDK, Solana wallet adapter) with the wallet specified during onboarding
  3. Submit the signed transaction to the blockchain
Do not build your own transaction. Always use the burnTransaction provided in the webhook. This transaction is pre-built by Etherfuse with the correct parameters.
Alternative: Hosted signing page If you don’t want to handle transaction signing in your application, the webhook payload includes a statusPage URL (e.g., https://status.etherfuse.com/order/{orderId}). You can redirect the customer to this Etherfuse-branded page where they can review and sign the transaction directly.

Fees

Fees for onramps and offramps are based on your rolling 30-day transaction volume. Higher volume means lower fees.
30-Day Volume (USD)Fee
0 - 5 million20 bps (0.20%)
5 - 10 million15 bps (0.15%)
10 - 50 million10 bps (0.10%)
50 - 100 million8 bps (0.08%)
100 million+5 bps (0.05%)
The fee is calculated on the output amount and included in the quote response (feeBps, feeAmount, destinationAmountAfterFee). Your current fee tier is applied automatically when you create a quote.

Quote Types

TypeSourceTargetUse Case
onrampFiat (MXN)Crypto (USDC, CETES)Customer buys crypto
offrampCrypto (USDC, CETES)Fiat (MXN)Customer sells crypto
swapCryptoCryptoCustomer exchanges one crypto for another

Webhooks

Subscribe to webhooks to receive real-time updates. Webhook payloads are signed with HMAC-SHA256 using your webhook secret. The signature is in the X-Signature header as sha256={hex_signature}.

Event Types

Event TypeDescription
customer_updatedKYC verification status changed
bank_account_updatedBank account verification status changed
order_updatedOrder status changed
swap_updatedSwap transaction status changed
kyc_updatedKYC submission status changed (for programmatic KYC)

Webhook Status Values

Each webhook includes a status field indicating what triggered the event: Order statuses (order_updated):
  • order_created - Order has been created
  • order_funded - Order has been funded (fiat received for onramp, crypto confirmed for offramp)
  • order_completed - Order completed successfully
  • order_failed - Order failed
  • order_refunded - Order was refunded (onramp only)
  • order_canceled - Order was canceled
Customer statuses (customer_updated):
  • customer_pending - Customer verification in progress
  • customer_verified - Customer successfully verified
  • customer_failed - Customer verification failed
Bank account statuses (bank_account_updated):
  • bank_account_pending - Bank account verification pending
  • bank_account_awaiting_deposit_verification - Waiting for deposit verification
  • bank_account_active - Bank account is active and ready to use
  • bank_account_inactive - Bank account is inactive
Swap statuses (swap_updated):
  • swap_created - Swap has been created
  • swap_completed - Swap completed successfully
  • swap_failed - Swap failed
KYC statuses (kyc_updated):
  • kyc_proposed - KYC data submitted, awaiting admin review
  • kyc_approved - KYC approved (on-chain marking will follow for Solana)
  • kyc_rejected - KYC rejected (includes updateReason with rejection details)

Order Status Flow

Orders progress through different statuses. You’ll receive an order_updated webhook at each transition. Onramp Order Flow (customer buys crypto with MXN):
created → funded → completed
    ↓        ↓
  failed   refunded

 canceled
  1. created - Order created, waiting for customer to deposit MXN to the depositClabe
  2. funded - MXN deposit received and confirmed
  3. completed - Crypto sent to customer’s wallet (confirmedTxSignature contains the tx hash)
Offramp Order Flow (customer sells crypto for MXN):
created → funded → completed
    ↓        ↓
  failed   failed

 canceled
  1. created - Order created, burnTransaction contains the transaction for the customer to sign
  2. funded - Customer’s crypto transaction confirmed on-chain
  3. completed - MXN sent to customer’s bank account
Swap Flow (customer exchanges crypto for crypto):
created → funded → completed
    ↓        ↓
  failed   failed
  1. created - Swap created, transaction ready for customer to sign
  2. funded - Customer’s crypto transaction confirmed on-chain
  3. completed - Target crypto sent to customer’s wallet
Alternative Statuses:
  • failed - Order/swap failed (timeout, error, etc.)
  • refunded - Funds returned to customer (onramp only)
  • canceled - Order canceled before funding

Webhook Payload Examples

Order Created (Onramp):
{
  "order_updated": {
    "orderId": "123e4567-e89b-12d3-a456-426614174000",
    "customerId": "123e4567-e89b-12d3-a456-426614174001",
    "walletId": "223e4567-e89b-12d3-a456-426614174002",
    "bankAccountId": "323e4567-e89b-12d3-a456-426614174003",
    "orderType": "onramp",
    "status": "created",
    "amountInFiat": 1000.00,
    "depositClabe": "646180157034567890",
    "createdAt": "2025-01-15T10:00:00Z",
    "updatedAt": "2025-01-15T10:00:00Z",
    "statusPage": "https://status.etherfuse.com/order/123e4567-e89b-12d3-a456-426614174000"
  }
}
Order Funded (Onramp):
{
  "order_updated": {
    "orderId": "123e4567-e89b-12d3-a456-426614174000",
    "customerId": "123e4567-e89b-12d3-a456-426614174001",
    "walletId": "223e4567-e89b-12d3-a456-426614174002",
    "bankAccountId": "323e4567-e89b-12d3-a456-426614174003",
    "orderType": "onramp",
    "status": "funded",
    "amountInFiat": 1000.00,
    "amountInTokens": 49.50,
    "depositClabe": "646180157034567890",
    "feeBps": 20,
    "feeAmountInFiat": 2.00,
    "createdAt": "2025-01-15T10:00:00Z",
    "updatedAt": "2025-01-15T10:05:00Z",
    "statusPage": "https://status.etherfuse.com/order/123e4567-e89b-12d3-a456-426614174000"
  }
}
Order Completed (Onramp):
{
  "order_updated": {
    "orderId": "123e4567-e89b-12d3-a456-426614174000",
    "customerId": "123e4567-e89b-12d3-a456-426614174001",
    "walletId": "223e4567-e89b-12d3-a456-426614174002",
    "bankAccountId": "323e4567-e89b-12d3-a456-426614174003",
    "orderType": "onramp",
    "status": "completed",
    "amountInFiat": 1000.00,
    "amountInTokens": 49.50,
    "confirmedTxSignature": "3Kz8V2xYm9...abc123",
    "depositClabe": "646180157034567890",
    "feeBps": 20,
    "feeAmountInFiat": 2.00,
    "createdAt": "2025-01-15T10:00:00Z",
    "updatedAt": "2025-01-15T10:10:00Z",
    "completedAt": "2025-01-15T10:10:00Z",
    "statusPage": "https://status.etherfuse.com/order/123e4567-e89b-12d3-a456-426614174000"
  }
}
Order Created (Offramp):
{
  "order_updated": {
    "orderId": "423e4567-e89b-12d3-a456-426614174000",
    "customerId": "123e4567-e89b-12d3-a456-426614174001",
    "walletId": "223e4567-e89b-12d3-a456-426614174002",
    "bankAccountId": "323e4567-e89b-12d3-a456-426614174003",
    "orderType": "offramp",
    "status": "created",
    "amountInTokens": 50.00,
    "burnTransaction": "AQAAAA...encoded_transaction_for_user_to_sign",
    "createdAt": "2025-01-15T10:00:00Z",
    "updatedAt": "2025-01-15T10:00:00Z",
    "statusPage": "https://status.etherfuse.com/order/423e4567-e89b-12d3-a456-426614174000"
  }
}
Order Completed (Offramp):
{
  "order_updated": {
    "orderId": "423e4567-e89b-12d3-a456-426614174000",
    "customerId": "123e4567-e89b-12d3-a456-426614174001",
    "walletId": "223e4567-e89b-12d3-a456-426614174002",
    "bankAccountId": "323e4567-e89b-12d3-a456-426614174003",
    "orderType": "offramp",
    "status": "completed",
    "amountInTokens": 50.00,
    "amountInFiat": 1000.00,
    "confirmedTxSignature": "5Mz9X3yAn1...ghi789",
    "feeBps": 20,
    "feeAmountInFiat": 2.00,
    "createdAt": "2025-01-15T10:00:00Z",
    "updatedAt": "2025-01-15T10:15:00Z",
    "completedAt": "2025-01-15T10:15:00Z",
    "statusPage": "https://status.etherfuse.com/order/423e4567-e89b-12d3-a456-426614174000"
  }
}
Swap Created:
{
  "swap_updated": {
    "orderId": "523e4567-e89b-12d3-a456-426614174000",
    "customerId": "123e4567-e89b-12d3-a456-426614174001",
    "sendTransaction": "AQAAAA...encoded_transaction_for_user_to_sign",
    "sendTransactionHash": "",
    "status": "created",
    "createdAt": "2025-01-15T10:00:00Z",
    "updatedAt": "2025-01-15T10:00:00Z"
  }
}
Swap Completed:
{
  "swap_updated": {
    "orderId": "523e4567-e89b-12d3-a456-426614174000",
    "customerId": "123e4567-e89b-12d3-a456-426614174001",
    "sendTransaction": "AQAAAA...encoded_tx",
    "sendTransactionHash": "4Lz9W3yZn0...def456",
    "receiveTransactionHash": "5Mz0X4zAo1...ghi789",
    "status": "completed",
    "createdAt": "2025-01-15T10:00:00Z",
    "updatedAt": "2025-01-15T10:02:00Z"
  }
}
KYC Approved:
{
  "kyc_updated": {
    "customerId": "123e4567-e89b-12d3-a456-426614174000",
    "walletPublicKey": "9Qx7r...",
    "approved": true,
    "updateReason": "KYC approved by admin"
  }
}
KYC Rejected:
{
  "kyc_updated": {
    "customerId": "123e4567-e89b-12d3-a456-426614174000",
    "walletPublicKey": "9Qx7r...",
    "approved": false,
    "updateReason": "ID document is expired. Please submit a valid government-issued ID."
  }
}

Resources

The API manages these resources, all scoped to your organization:
  • Customers (customerId) — Your end users who complete KYC. You generate this UUID and provide it during onboarding.
  • Bank Accounts (bankAccountId) — Mexican bank accounts linked to a specific customer. You generate this UUID during onboarding. Must be used with the same customer it was onboarded with. Compliance is derived — accounts are compliant if explicitly marked or if the owning organization is approved.
  • Wallets (publicKey) — Crypto wallet addresses associated with customers during onboarding. Can be registered programmatically via POST /ramp/wallet with optional claimed ownership. When an approved organization claims ownership of a wallet, it is treated as compliant without individual KYC.
  • Orders (orderId) — Onramp and offramp transactions. You generate this UUID. Each order references a customer’s bankAccountId and publicKey.
  • Webhooks — Event notification subscriptions.
A customer, their bank account, and their wallet are all linked together during onboarding. When creating quotes and orders, you must use the same customerId, bankAccountId, and publicKey that were provided during that customer’s onboarding.

Troubleshooting

Common Errors

Error MessageCauseFix
"Proxy account not found"The customerId or publicKey in your quote/order doesn’t match what was used during onboardingVerify you’re using the exact same customerId and publicKey from the onboarding call
"Bank account not found"The bankAccountId in your order doesn’t match what was used during onboarding, or it belongs to a different customerVerify you’re using the same bankAccountId that was linked to this customerId during onboarding
401 UnauthorizedInvalid API key or incorrect auth header formatEnsure the header is Authorization: your-api-key with no Bearer prefix
Quote expiredOrder was created more than 2 minutes after the quoteCreate a new quote and submit the order promptly

Common Pitfalls

  • Onboarding must be completed before transacting. The customer’s wallet is registered during onboarding. Orders will fail if the customer hasn’t completed the full onboarding flow (including KYC verification).
  • IDs are permanently bound after onboarding. Generate and store your customerId and bankAccountId UUIDs before calling the onboarding endpoint. Changing them afterward will break the link.
  • Offramp: use the provided burnTransaction. Do not build your own transaction. The burnTransaction in the webhook is pre-built and partially signed by Etherfuse.
  • Stellar: add trust lines before ramping. On Stellar, the customer’s wallet must have trust lines established for the assets they are ramping into (e.g., CETES, USDC) before tokens can be received. Use the /ramp/assets endpoint to discover the correct asset identifiers (in CODE:ISSUER format) for setting up trust lines.