Skip to main content

Migrating from v1 to v2

Bank-transfer on-ramp and off-ramp orders are moving from API v1 to API v2 (RAMP), and API v1 will be shut down soon. If your integration calls the v1 /v1/otc/deposit/, /v1/otc/withdraw/ or /v1/order/info/… endpoints, this guide lists everything you need to change.

API v2 is not a drop-in replacement: paths, field names, tickers and some flows are different, and there is no compatibility layer for the old request shapes. API v1 and API v2 run side by side on different hosts until v1 is shut down, so you can migrate and test at your own pace.

1. What changes at a glance​

  • New base URL with no /v1 prefix and no trailing slashes. A path ending in / returns 404.
  • One endpoint per direction: POST /onramp (fiat → crypto) and POST /offramp (crypto → fiat).
  • No from_asset/to_asset. Every order has one crypto asset and one fiat_currency. The direction is decided by the endpoint you call.
  • New tickers. The -ARK suffix is gone. Arkade assets have their own tickers (ARK-BTC, USDT-CX). Plain BTC and USDT now mean on-chain Bitcoin and Tron.
  • Amounts are decimal strings ("100.00", "0.00250000"), not JSON numbers.
  • KYC goes through ID-Flow. Orders at or above the KYC threshold need a customer verified with ID-Flow under the order's email address.
  • Off-ramp needs a new call. After sending the crypto, report the transaction id with POST /order/{token}/deposit. Until you do, the order is not credited automatically.
  • Off-ramp: pay exactly the returned amount. API v2 may lower the requested crypto_amount slightly (by up to 1000 base units), and the deposit must match the returned value exactly.
  • SWIFT payouts now take the IBAN, BIC and a structured beneficiary address as separate fields.
  • Errors are {"error": …} with a proper HTTP status (400/403/404/409/422/502). KYC and minimum-order refusals are 403.
  • Not in API v2: crypto↔crypto swaps and trades, order cancellation, vouchers, and the ref/sub_id partner fields.

2. Environments and base URLs​

EnvironmentAPI v1 (old)API v2 (new)
Productionhttps://api.outlogic.net/v1https://api.ramp.outlogic.net
Staginghttps://api.staging.outlogic.net/v1https://api-staging.ramp.outlogic.net
Other URLsProductionStaging
API v2 referenceThese docsThese docs
ID-Flow identity verification (KYC) for customersYour own ID-Flow instance (agreed with us during onboarding)https://demo-staging.idflow.ch/

Staging is a sandbox: bank payments and crypto transfers there use test networks and never move real money. Use it for all integration testing.

3. Endpoint map​

API v1 (old)API v2 (new)Notes
GET /v1/assets/GET /assetsSame top-level keys. Each asset now has a network label.
(none)GET /limitsMinimum order and KYC threshold, per currency.
POST /v1/otc/deposit/POST /onrampFiat → crypto. See section 7.
POST /v1/otc/withdraw/POST /offrampCrypto → bank (sepa/swift/us). See section 8.
(none)POST /order/{token}/depositNew and required for off-ramp. See section 9.
GET /v1/order/info/{id}/GET /order/{token}Uses the id returned at creation. See section 10.
GET /v1/otc/markets/, POST /v1/otc/trade/, POST /v1/order/, /v1/order/cancel/…Not availableCrypto↔crypto trading and cancellation are not part of API v2. Contact us if you depend on them.
sub_id, ref, expo_token_strNot acceptedNo partner sub-accounts, referral codes or push tokens.

4. General conventions​

  • JSON request and response bodies (Content-Type: application/json), with snake_case field names.
  • No authentication on the endpoints in this guide. CORS is open (Access-Control-Allow-Origin: *, no credentials), so you can call them from a browser or a server. Order creation is rate limited per client IP (section 11).
  • Amounts are strings in plain decimal notation, with at most 8 decimals and never more than the asset has (USDT/USDT-CX have 6). Don't send scientific notation such as 1e-7.
  • Optional origin on create calls. Leave it unset (it defaults to api). The old mobile value is not accepted.
  • Order identifiers: id is the short public token (use it for status and deposit reporting), code is a human-readable reference such as ORD-XXXX-XXXX (quote it to support), and transfer_code is the bank payment reference.
  • Timestamps are ISO 8601 (2026-10-23T09:15:00.000Z). API v1 used 2026-10-23 09:15:00.
  • No quote step and no locked rate. The rate is set when the payment arrives, so the other leg of the trade is null until settlement (sections 7 and 8).

5. Assets, tickers and currencies​

Read the live list from GET /assets rather than hardcoding it. Each entry in from_assets has symbol, name, precision (decimals) and network, which names the address format destination_crypto_address must use. to_assets lists the fiat currencies.

TickerNetworkPayout address formatDecimalsAPI v1 equivalentNotes
ARK-BTCArkadeark1… / tark1…8BTC-ARKNear-instant payout.
USDT-CXArkadeark1… / tark1…6USDT-ARKNear-instant payout.
CEXTArkadeark1… / tark1…8—
BTCBitcoin1… / 3… / bc1… (tb1… on staging)8on-chain BTCOn-ramp payout on-chain, usually within a few minutes.
USDTTronT…6USDT (Tron)On-ramp payouts take longer: they are not automated yet.

Fiat currencies: EUR, CHF, USD.

The ticker sets the payout network. An Arkade address with BTC is refused (destination_crypto_address is not a valid Bitcoin address). If you used BTC-ARK on API v1, send ARK-BTC on API v2. Responses echo the ticker you sent.

Off-ramp deposits must be Arkade transfers. The off-ramp deposit address is always an Arkade address, and only an Arkade transfer to it is credited. Use ARK-BTC or USDT-CX for off-ramp. On-chain Bitcoin or Tron deposits are not credited automatically.

6. Limits and KYC (ID-Flow)​

GET /limits returns the minimum order and the KYC threshold. Both are set in CHF and also converted into each fiat currency at the rates the server uses for its own check. The values can change without notice, so read them at runtime instead of hardcoding them.

{
"min_order_chf": "20.00",
"kyc_threshold_chf": "1000.00",
"by_currency": {
"EUR": { "min_order": "...", "kyc_threshold": "..." },
"CHF": { "min_order": "20.00", "kyc_threshold": "1000.00" },
"USD": { "min_order": "...", "kyc_threshold": "..." }
}
}
  • Below the minimum: refused with 403, {"error": "Minimum order amount is CHF 20"}.
  • Below the KYC threshold: no identity verification is needed.
  • At or above the KYC threshold: the customer must have completed identity verification with ID-Flow, using the same email address you send as email on the order. The check happens when the order is created. A customer who isn't verified is refused with 403, {"error": "KYC verification required for orders over CHF 1000"}. Send them to your ID-Flow instance to verify (on staging, the shared one in section 2), then create the order again.
  • The order's kyc_verified field is true when its ID-Flow verification was confirmed.
  • SEPA payouts for verified customers go to the IBAN registered in the customer's ID-Flow profile, which takes precedence over the IBAN in the request (section 8).
  • API v1 reported KYC failures as a message or kycError field. On API v2, check for HTTP 403 instead.

The values above are illustrative. Use what the endpoint returns.

7. On-ramp: fiat → crypto​

POST /onramp replaces POST /v1/otc/deposit/. The customer pays fiat by bank transfer and receives crypto at destination_crypto_address.

Request field mapping​

API v1 /v1/otc/deposit/API v2 /onrampNotes
from_asset ("EUR")fiat_currencyRequired. EUR, CHF or USD.
to_asset ("BTC-ARK")assetRequired. An API v2 ticker such as ARK-BTC (section 5).
from_amount (number)fiat_amount (string)Required. The amount the customer will pay.
emailemailRequired. Also used for the KYC check (section 6).
destination_addressdestination_crypto_addressRequired. Validated against the ticker's network.
refund_addressrefund_addressOptional.
ref, sub_id, expo_token_str—Not accepted.

Before: API v1

POST https://api.outlogic.net/v1/otc/deposit/
Content-Type: application/json

{
"email": "jane@example.com",
"from_asset": "EUR",
"from_amount": 250,
"to_asset": "BTC-ARK",
"destination_address": "ark1qq…"
}

After: API v2

POST https://api.ramp.outlogic.net/onramp
Content-Type: application/json

{
"email": "jane@example.com",
"fiat_currency": "EUR",
"fiat_amount": "250.00",
"asset": "ARK-BTC",
"destination_crypto_address": "ark1qq…"
}

Response (201 Created)​

{
"order": {
"id": "k8d2m4x9qa", // public token: use it for GET /order/{token}
"code": "ORD-7KQ2-M9XD",
"email": "jane@example.com",
"direction": "onramp",
"asset": "ARK-BTC",
"fiat_currency": "EUR",
"fiat_amount": "250.00",
"crypto_amount": null, // set when the payment arrives
"status": "WAITING_FOR_DEPOSIT",
"transfer_code": "k3x9q2m7ab",
"destination_type": "crypto",
"destination_crypto_address": "ark1qq…",
"deposit_txid": null,
"deposit_iban": "LT00 0000 0000 0000 0000", "deposit_bic": "XXXXLT21XXX",
"deposit_beneficiary": "…", "deposit_bank_name": "…", "deposit_payment_type": "sepa",
"kyc_verified": false,
"created_at": "2026-10-23T09:15:00.000Z",
"expires_at": "2026-10-25T09:15:00.000Z",
"completed_at": null
},
"bank_details": {
"iban": "LT00 0000 0000 0000 0000", "bic": "XXXXLT21XXX",
"beneficiary": "…", "bank_name": "…",
"payment_type": "sepa", "transfer_code": "k3x9q2m7ab"
},
"fee": { "feePct": "0.01", "feeFlat": "0", "feeAmount": "2.50", "netAmount": "247.50" }
}
  • Show the customer bank_details. These replace API v1's deposit_sepa_* / deposit_swift_* fields. The bank details above are placeholders: always use what the API returns, as the receiving account can differ by currency.
  • The customer must put transfer_code in the payment reference. It is 10 lowercase letters and digits, with no prefix or separators. Without it the payment can't be matched to the order automatically.
  • crypto_amount stays null until the payment is confirmed. The trade is priced then, fees are deducted, and the crypto is sent. Show it as "to be determined at the market rate when your payment arrives", not as a quote.
  • The customer must pay by expires_at. Later payments are not credited automatically.

8. Off-ramp: crypto → fiat​

POST /offramp replaces POST /v1/otc/withdraw/. The customer sends crypto and receives a bank payout. destination_type must be sepa, swift or us. Crypto payouts (destination_type: "crypto") are not part of the off-ramp.

Common fields​

API v1 /v1/otc/withdraw/API v2 /offrampNotes
from_asset ("BTC-ARK")assetRequired. Use ARK-BTC or USDT-CX (section 5).
to_asset ("EUR")fiat_currencyRequired.
from_amount (number, in BTC)crypto_amount (string)Required, in whole units: "0.00250000" = 250,000 sats.
emailemailRequired. Also used for the KYC check (section 6).
destination_typedestination_typeRequired: sepa | swift | us.
refund_address, expo_token_str—Not accepted.

Destination fields by type​

TypeAPI v1API v2
sepadestination_bank_address = IBAN
destination_bank_name = account holder
destination_bank_address = IBAN
destination_bank_name = beneficiary name
Unchanged. For a customer verified with ID-Flow, the IBAN in their ID-Flow profile is used instead of the submitted one.
swiftdestination_bank_address = BIC
destination_bank_account_number = IBAN
destination_bank_name = account holder
destination_bank_address = IBAN (changed meaning)
destination_bic = BIC (new)
destination_bank_name = beneficiary name
destination_country (ISO 3166-1 alpha-2, e.g. CH)
destination_street_name, destination_building_number, destination_town_name, destination_post_code
All required. The beneficiary address is now structured, not free text.
usdestination_bank_account_number
destination_bank_routing_number
destination_bank_account_number
destination_bank_routing_number (ABA checksum validated)
destination_bank_name = beneficiary name (now required)
US payouts take longer: they are not automated yet.
caution

SWIFT is the easiest change to miss: destination_bank_address held the BIC on API v1 and holds the IBAN on API v2.

Example​

POST https://api.ramp.outlogic.net/offramp
Content-Type: application/json

{
"email": "jane@example.com",
"asset": "ARK-BTC",
"fiat_currency": "EUR",
"crypto_amount": "0.00250000",
"destination_type": "sepa",
"destination_bank_address": "DE89370400440532013000",
"destination_bank_name": "Jane Doe"
}

201 Created

{
"order": {
"id": "p4z7c1n8wd", "direction": "offramp", "asset": "ARK-BTC",
"crypto_amount": "0.00249873", // pay EXACTLY this amount (see below)
"fiat_amount": null, // set when the payout is priced
"status": "WAITING_FOR_DEPOSIT", "destination_type": "sepa",
"expires_at": "2026-10-25T09:15:00.000Z"
// …
},
"deposit_crypto_address": "ark1qq…", // send the crypto here
"fee": { "feePct": "0.01", "feeFlat": "0", "feeAmount": "…", "netAmount": "…" }
}
  • Send exactly order.crypto_amount, not the amount you requested. Each open order gets a unique amount, the request or up to 1000 base units (sats, or 0.001 USDT) below it, so a deposit can only match its own order. A deposit that doesn't match exactly is not credited.
  • The crypto must be an Arkade transfer to deposit_crypto_address, sent after the order was created. Then report it (section 9).
  • fiat_amount stays null until the deposit is credited. The payout is priced then and rounded down to whole cents.

9. Reporting an off-ramp deposit (new step)​

API v1 had no equivalent. Once the Arkade transfer has been sent, tell API v2 which transaction paid the order:

// POST /order/{token}/deposit
{ "txid": "3f1c…e9a0" } // 64 lowercase hex characters (the Arkade txid)

The transaction is verified before anything is credited. It must be an Arkade transfer that pays the deposit address exactly the order's crypto_amount of the order's asset, it must not be older than the order, and it must not have been credited to another order. On success the order moves to DEPOSIT_RECEIVED and the payout follows.

StatusMeaning and what to do
200Credited. Returns {"order": …}. Reporting the same txid again returns the same order unchanged, so retries are safe.
404No order with that token.
409The order isn't an off-ramp order waiting for a deposit, or the transaction was already credited to another order.
422The transaction doesn't pay this order: wrong amount, wrong asset, not to the deposit address, older than the order, or not an Arkade transfer.
502The transaction couldn't be verified right now. Retry later with the same txid.

If a deposit is never reported, the order stays in WAITING_FOR_DEPOSIT until our support team matches it by hand. Report the txid as soon as the transfer is sent, and keep retrying on 502.

10. Order status​

GET /order/{token} replaces GET /v1/order/info/{id}/. Both wrap the order in {"order": …}. The token is the id returned when the order was created. Orders created on API v1 are not visible on API v2 (section 12).

Response field mapping​

API v1 order fieldAPI v2 order fieldNotes
ididShort public token on both.
—code, directiondirection is onramp or offramp.
from_asset / to_assetasset, fiat_currency
from_amount, deposit_amountfiat_amount, crypto_amountThe customer-declared leg is set at creation. The other is null until settlement.
deposit_sepa_address / deposit_swift_address / deposit_bank_addressdeposit_ibanOn-ramp receiving account.
deposit_sepa_bic / deposit_swift_bicdeposit_bic
deposit_*_beneficiary, deposit_*_bank_namedeposit_beneficiary, deposit_bank_name
(inferred from which fields were set)deposit_payment_typesepa or swift.
deposit_crypto_addresscreate response onlyOff-ramp: returned by POST /offramp as deposit_crypto_address.
funding.txsdeposit_txidOff-ramp: the credited Arkade transaction.
transfer_code, destination_type, destination_crypto_address, email, created_at, expires_at, completed_atsame namesTimestamps are now ISO 8601.
chf, referral, sub_id, refund, confirmed_at, approved_at, …—Not returned.
—kyc_verifiedWhether the customer's ID-Flow verification was confirmed for this order.

Status mapping​

API v1API v2Meaning on API v2
WAITING_FOR_DEPOSITWAITING_FOR_DEPOSITWaiting for the customer's payment.
DEPOSIT_RECEIVEDDEPOSIT_RECEIVEDPayment confirmed. Settlement is starting.
DEPOSIT_CONFIRMED, APPROVED, PROCESSINGPROCESSINGThe payout is being made.
COMPLETEDCOMPLETEDPaid out. Final.
—PENDING_MANUALNew. Our team is reviewing the order before paying out, for example for large amounts. Not a failure. Keep polling.
—FAILEDNew. Settlement failed. Contact support with the order code.
EXPIREDEXPIREDMay not be set automatically, so treat expires_at as the deadline.
REJECTED, CANCELLEDREJECTEDFinal. API v2 has no customer cancellation.
REFUNDEDREFUNDEDFinal.

There are no webhooks to partners. Poll GET /order/{token}, for example every 30–60 seconds while the customer is waiting and less often afterwards. Bank transfers can take several days.

11. Errors and rate limits​

Errors are always {"error": …}. For most errors it's a readable string naming the field the request carried, e.g. {"error": "destination_bic is required for swift payouts"}. When the request body doesn't match the schema of /onramp or /offramp, it's an object with the problems per field: {"error": {"formErrors": [], "fieldErrors": {"fiat_amount": ["Invalid"]}}}.

StatusWhen
400Invalid request: missing or malformed field, unknown ticker or currency, wrong address format for the ticker, invalid IBAN/BIC/ABA number, too many decimals.
403Below the minimum order, or KYC required (section 6).
404Unknown order token, or a wrong path (including a trailing /).
409 / 422 / 502Deposit reporting (section 9).
429Rate limit exceeded. Back off and retry.
EndpointRate limit per client IP
POST /onramp, POST /offramp, POST /order/{token}/deposit30 per minute

If you create orders from a server on behalf of many customers, all of them count against your server's IP. Contact us before launch if you expect to go above this limit.

12. Switching over​

API v1 will be shut down soon, so plan a one-way move to API v2.

Before switching​

  • Implement the API v2 calls: the new paths (no /v1, no trailing slashes), the ticker mapping (section 5), amounts as strings, the new SWIFT fields, error handling by HTTP status, and the off-ramp deposit report (section 9).
  • Read assets and limits from GET /assets and GET /limits instead of hardcoding them.
  • Make sure customers who will order at or above the KYC threshold verify with ID-Flow using the email address you send on the order.
  • Test end to end on staging (https://api-staging.ramp.outlogic.net): one on-ramp, and one off-ramp including the deposit report.

Switching​

  • Send all new orders to https://api.ramp.outlogic.net.
  • Orders are not migrated. Orders already created on API v1 finish there: customers who already have v1 payment instructions pay against those, and you look those orders up on API v1 until they are final or past their expires_at. Plan for this before API v1 shuts down.
  • Stop creating orders on API v1.