> ## Documentation Index
> Fetch the complete documentation index at: https://docs.etherfuse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# V1 → V2

> Why to switch to v2, and how to migrate from v1: endpoint replacements, request fields, order statuses and webhooks.

v2 combines bank accounts and wallets into payment accounts, and uses the same quote and order endpoints for onramps, offramps and swaps. It also has its own versions of the organization, member, KYC, KYB, asset and statement endpoints, so a v2 integration uses one set of conventions throughout. Every v2 endpoint sits at the root of the API host, with no `/ramp` prefix.

v1 remains available during migration. Your API key works with both versions, so you can migrate one flow at a time.

## Why switch to v2

### Available now

* **Lower fees.** v1 charges 20 bps on a same-currency onramp or offramp, such as MXN to CETES. In v2 the platform fee on a same-currency transfer is 0 bps. Moving out of a stablebond into its own currency pays only that bond's exit fee (5 bps for CETES), and the volume-based FX fee applies only when you convert between currencies. Every quote and order itemizes its fees, partner fee included. See [Fees](/v2/fees).
* **One way to move money.** Quote any asset to any other asset between two payment accounts. Onramps, offramps, swaps and cross-chain transfers all use the same quote and order endpoints, and if we support the route, the quote works. There is no separate swap API.
* **Cross-chain transfers.** Send a token from a wallet on one supported chain to a wallet on another.
* **Payment accounts.** Register a bank account or wallet once and use it for any transfer. Each account lists the rails it can use (SPEI, PIX, Stellar, Solana, Base, Polygon, Monad and Avalanche), whether each rail can send or receive, and the amount limits we know of. One EVM address covers every EVM chain we support. You pick the rail per quote, or use the account's default.
* **Faster delivery.** v2 orders run on our new execution engine, which starts each step as soon as the previous one confirms.
* **Clear funding.** Each order carries its own funding instructions: where to pay, our reference for the payment, and a funding deadline. Ask for fresh instructions when a prepared transaction goes stale.
* **Safe retries.** Creating an order with a `quoteId` you already used returns the existing order instead of making a second one.
* **Complete webhooks.** Each event carries the full order, payment account, or KYC or KYB status, and one subscription covers your organization and every customer organization.
* **Structured errors.** Every error uses RFC 9457 problem details with a stable `type` to handle in code.
* **One set of conventions.** Organizations, members, KYC, KYB, assets and statements all use camelCase, `organizationId` in the path and the same paging, so one client handles every endpoint.
* **Sandbox deposits.** Simulate the fiat deposit to test an onramp without sending money.

### Coming to v2

These ship in v2 only:

* **More countries.** New fiat rails beyond Mexico, starting with Brazil (BRL) over PIX.
* **Third-party payments.** Pay out to, or receive from, an account that belongs to someone other than your customer.
* **Private accounts.** On some fiat providers, a customer can request a bank account in a country where they do not have one, after extra KYC or KYB steps.

We announce each one in the [changelog](/changelog) when it is available.

## What stays the same

Keep using your existing API key, organizations, customers and KYC approvals. Your organization ids carry over: a v1 `customerId` is the v2 `organizationId`. Your customers do not need to verify again.

These endpoints keep their paths and behavior:

* Authentication: [`POST /auth/token`](/v2/api-reference/authentication/exchange-a-partner-jwt) and `/auth/launch`
* The public `/lookup` endpoints

## 1. Read the v2 conventions

v2 uses camelCase keys and camelCase enum values (`debitCard`, `orderUpdated`), decimal strings for amounts, and `pageSize` and `pageNumber` query parameters for lists. See [Conventions](/v2/overview#conventions).

## 2. Put the organization in the path

Routes that act for one organization start with `/organization/{organizationId}`. Use the organization ID previously sent as `customerId` in v1. For your own organization, get the ID from [`GET /me`](/v2/api-reference/organizations/get-me); for a customer, use that customer's organization ID. See [Organizations in the route](/v2/overview#organizations-in-the-route).

In the tables below, `...` abbreviates `/organization/{organizationId}`.

## 3. Use payment accounts

Etherfuse will migrate your existing v1 bank accounts and wallets to v2 payment accounts. Do not re-register them.

Use the v2 registration endpoint for new bank accounts and wallets:

| v1 | v2 |
| - | - |
| `POST /ramp/bank-account`, `POST /ramp/customer/{customer_id}/bank-account` | [`POST /organization/{organizationId}/payment_account`](/v2/api-reference/payment-accounts/register-payment-account) with `kind: "bank"` |
| `POST /ramp/wallet`, `POST /ramp/customer/{customer_id}/wallet` | The same endpoint with `kind: "wallet"` |
| `GET /ramp/bank-account/{id}`, `GET /ramp/wallet/{id}` | [`GET .../payment_account/{id}`](/v2/api-reference/payment-accounts/get-payment-account) |
| `GET`/`POST /ramp/bank-accounts`, `GET`/`POST /ramp/wallets` and the customer variants | [`GET .../payment_accounts`](/v2/api-reference/payment-accounts/list-payment-accounts) |
| `DELETE /ramp/wallet/{wallet_id}` | No equivalent. v2 has no endpoint to delete a payment account. |
| `bank_account_updated` webhook | `paymentAccountUpdated` webhook |

A new account starts as `pending`. Before quoting, check that the required rail direction (`source` or `destination`) is `ready`. Subscribe to `paymentAccountUpdated` for status changes.

## 4. Move organizations, KYC, assets and statements

These endpoints work the same way in v2, with v2 conventions: camelCase enum values (`notStarted`, `personalData`), `organizationId` in place of `customerId`, problem details errors, and `{ items }` for lists.

| v1 | v2 |
| - | - |
| `GET /ramp`, `GET /ramp/me` | [`GET /me`](/v2/api-reference/organizations/get-me) |
| `PUT /ramp/partner-fee` | [`PATCH /me`](/v2/api-reference/organizations/update-me) with `partnerFeeDefaultBps` |
| `GET`/`POST /ramp/customers` | [`GET /organizations`](/v2/api-reference/organizations/list-organizations), with `pageSize` and `pageNumber` in the query. There is no date filter. |
| `GET /ramp/customer/{customer_id}` | [`GET /organization/{organizationId}`](/v2/api-reference/organizations/get-organization) |
| `POST /ramp/organization` | [`POST /organization`](/v2/api-reference/organizations/create-organization). The same fields, except `wallets`: register wallets as payment accounts. |
| `PUT /ramp/organization/{org_id}/name` | [`PATCH /organization/{organizationId}`](/v2/api-reference/organizations/update-organization) with `displayName` |
| `POST /ramp/organization/{id}/member` | [`POST .../member`](/v2/api-reference/members/add-organization-member), with `memberId` in place of `customerId` |
| `GET /ramp/organization/{id}/member` | [`GET .../members`](/v2/api-reference/members/list-organization-members) |
| `DELETE /ramp/organization/{id}/member/{customer_id}` | [`DELETE .../member/{memberId}`](/v2/api-reference/members/remove-organization-member) |
| `DELETE /ramp/organization/{id}/member/invite/{email}` | [`DELETE .../member_invite/{email}`](/v2/api-reference/members/revoke-organization-invite) |
| `GET /ramp/customer/{customer_id}/organization` | [`GET /member/{memberId}/organizations`](/v2/api-reference/members/list-member-organizations) |
| `GET /ramp/customer/{customer_id}/kyc` | [`GET .../kyc`](/v2/api-reference/kyc/get-kyc-status) |
| `POST /ramp/customer/{customer_id}/verification` and its `/documents`, `/questionnaire` and `/import` | [`POST .../verification`](/v2/api-reference/kyc/submit-verification-data) and the same sub-paths |
| `GET /ramp/verification/occupations` | [`GET /verification/occupations`](/v2/api-reference/kyc/list-occupation-categories) |
| `GET /ramp/organization/{id}/kyb/status` | [`GET .../kyb`](/v2/api-reference/kyb/get-kyb-status) |
| `GET /ramp/assets` | [`GET /supported_assets`](/v2/api-reference/assets/list-supported-assets). It lists markets as well as tokens, and filters by `chain`, `currency`, `paymentAccountId` or `organizationId`. It returns no balances. |
| `GET /ramp/balances` | [`GET .../payment_account/{id}/balances`](/v2/api-reference/assets/get-payment-account-balances) |
| `GET /ramp/partner-statements` and its `/{year}-{month}/csv` and `/pdf` | [`GET /partner_statements`](/v2/api-reference/statements/list-partner-statements), [`GET /partner_statement/{year}-{month}/csv`](/v2/api-reference/statements/download-statement-csv) and [`/pdf`](/v2/api-reference/statements/download-statement-pdf) |

What changes in the responses:

* **Organizations** come back as one shape: `id`, `displayName`, `accountType`, `approvedAt`, `createdAt` and `updatedAt`.
* **KYC and KYB** `status` uses the webhook values: `notStarted`, `inProgress`, `submitted`, `approved`, `denied`. Requirement `type` and `status` are camelCase too (`identityDocument`, `awaitingReview`). The KYC response drops `walletPublicKey` and `onChainMarked`.
* **Members** are named by `memberId`: the person's JWT `sub`, which v1 called `customerId` on members. Members of your own organization are managed in the Etherfuse portal; the v2 member endpoints return `403` for it. They work for your customer business organizations.

## 5. Quote with two payment accounts

[`POST /organization/{organizationId}/quote`](/v2/api-reference/quotes/create-quote) replaces `POST /ramp/quote`:

| v1 request field | v2 replacement |
| - | - |
| `quoteId` | Omit from the request. Use the API-generated `quoteId` from the response. |
| `customerId` | Pass as `organizationId` in the path. |
| `blockchain`, `walletAddress` | Set `source` and `destination` to payment account references: `{ "type": "stored", "id": "<payment_account_id>" }`. Both accounts must belong to the organization in the path. |
| `quoteAssets` | Move `quoteAssets.sourceAsset` to `sourceAsset` and `quoteAssets.targetAsset` to `destinationAsset`. Omit `quoteAssets.type`. Both take an `asset` from [`GET /supported_assets`](/v2/api-reference/assets/list-supported-assets). |
| `sourceAmount` | Unchanged: a positive decimal string. |
| `partnerFeeBps` | `partnerFeeBpsOverride`. Your default partner fee still applies when you leave it out. |

Set `sourceRail` and `destinationRail` to choose rails, or omit them to use the accounts' defaults. A bank-to-wallet transfer is an onramp, a wallet-to-bank transfer is an offramp, a transfer between wallets on the same chain is a swap, and a transfer of the same token between wallets on different chains is a cross-chain transfer.

The response itemizes fees in `fees`. Quotes expire after 2 minutes.

## 6. Create and follow orders

[`POST /organization/{organizationId}/order`](/v2/api-reference/orders/create-order) accepts `quoteId` and an optional `memo`. Remove the v1 fields `orderId`, `bankAccountId`, `cryptoWalletId`, `publicKey`, `direction`, `feePayer` and `useAnchor`. The order's `id` equals the `quoteId`. Reusing the same quote returns the existing order.

Use `fundingInstructions` in place of the v1 deposit fields and `burnTransaction`. Its `destination` contains a CLABE for SPEI, a BR Code for PIX, or a blockchain address and optional `preparedTransaction`. For embedded wallets, it references the order's `authorization` instead.

| v1 | v2 |
| - | - |
| `POST /ramp/swap` | A quote between two wallets on the same chain, then an order |
| `GET /ramp/order/{id}` | [`GET .../order/{id}`](/v2/api-reference/orders/get-order) |
| `GET`/`POST /ramp/orders`, `/ramp/customer/{customer_id}/orders` | [`GET /orders`](/v2/api-reference/orders/list-orders), covering your organization and every customer organization |
| `POST /ramp/order/{id}/cancel` | [`POST .../order/{id}/cancel`](/v2/api-reference/orders/cancel-order) |
| `POST /ramp/order/{id}/regenerate_tx`, `POST /ramp/swap/{id}/regenerate_tx` | [`POST .../order/{id}/funding_instructions/refresh`](/v2/api-reference/orders/refresh-funding-instructions) |
| `GET`/`POST /ramp/order/{id}/approvals` | The order's `authorization` and [`POST .../order/{id}/authorization`](/v2/api-reference/orders/submit-authorization) |
| `POST /ramp/evm/approve` | No equivalent. An EVM offramp needs no token approval: the customer sends the token to `fundingInstructions.destination.address`, or signs the `preparedTransaction`, and pays the gas. |

Order statuses:

| v1 | v2 |
| - | - |
| `created`, `funded`, `completed`, `failed`, `canceled`, `refunded` | Unchanged. |
| `finalized` | Use `completed`; v2 has no `finalized` status. |
| No equivalent | `claimable`: funds are waiting for the customer to claim. See `claimInstructions` and [`POST .../order/{id}/claim`](/v2/api-reference/orders/prepare-claim). |

## 7. Subscribe to v2 webhooks

Existing subscriptions continue sending v1 payloads. Create separate v2 subscriptions with [`POST /webhook_subscription`](/v2/api-reference/webhook-subscriptions/create-webhook-subscription), one per event type:

| v1 event | v2 event |
| - | - |
| `order_updated`, `swap_updated` | `orderUpdated` |
| `bank_account_updated` | `paymentAccountUpdated`, for bank accounts and wallets |
| `kyc_updated` | `kycUpdated` |
| `kyb_updated` | `kybUpdated` |
| `customer_updated` | No v2 event. Use `kycUpdated` and `kybUpdated`. |

Store the `secret` returned when you create the subscription. Decode v2 secrets with **URL-safe base64**, replacing the standard base64 decoding used for v1. See [Verifying webhooks](/v2/guides/verifying-webhooks).

Replace v1 WebSocket listeners with webhooks. Use `GET .../order/{id}` to check an order's current state.

## 8. Handle problem details

For v2 errors (`application/problem+json`), select your error handler using the `type` field. Use the HTTP status as a fallback for unknown types, and do not parse `detail`. See [Errors](/v2/errors). The `/auth` and `/lookup` endpoints keep their own error format.

## 9. Test in sandbox

Run each flow in sandbox before you switch production traffic. [`POST .../order/{id}/fiat_received`](/v2/api-reference/sandbox/simulate-fiat-received) simulates the SPEI or PIX deposit for an onramp. Follow the [Onramps](/v2/guides/testing-onramps), [Offramps](/v2/guides/testing-offramps) and [Swaps](/v2/guides/testing-swaps) guides.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.