Integration Guides

Integration Checklist

The path from the first request to go-live, in four phases. Each item is a question to answer before moving on, with a pointer to the page that has the details. Coverage says what the API supports; this page says in what order to use it.

What You Are Building

Your product lets your users exchange stablecoins for euros, or euros for stablecoins, without leaving your application. Stablegate provides the regulated entity, customer verification and screening, bank and blockchain settlement, and the order lifecycle. Your side owns the user: sign-up, the verification hand-off, the screen with deposit instructions, and the status the user sees afterwards.

From the user's point of view: sign up in your app, pass verification once, add the account the money should go to, see a quote, send the deposit, receive the payout.

Phase 1: Prepare

  • Which flows do you need?
    On-ramp, off-ramp or both. Confirm the pairs with GET /v1/exchange-routes/; the API exchanges only what that endpoint returns.
  • Who are your customers?
    Individuals can use Instant Verification and trade within minutes; corporate customers go through the hosted Standard flow and activation. Ask your account manager to enable Instant Verification if you plan to use it.
  • Where does the payout go?
    To a bank account or wallet registered for the customer. If your product needs anything else, agree it with Stablegate before you build.
  • Do you have access?
    Partner API access shows API keys, Webhooks and Your clients in the Developers section; without it every call answers 403. See Getting Started.
  • Does the smoke test pass?
    GET /v1/exchange-routes/ from your backend answers 200 with X-Api-Key and a trailing slash on the path. A missing slash answers 307 with a redirect to the slashed path instead of the data. See Authentication.
  • Is your client generated from the OpenAPI specification?
    Required fields are validated by the API; optional fields are not, so a typo in an optional field name silently falls back to the default.

Phase 2: Build

Customers and verification (Customers)

  • Do you store the customer uuid and your own external_reference?
    Create the customer when the user enters the exchange feature and keep the mapping; a customer cannot be edited later.
  • Do you start verification explicitly?
    It never starts on its own. Instant Verification needs first_name, last_name and date_of_birth; the Standard link is valid for 30 minutes.
  • Do you gate trading on state: active and permissions.can_trade: true?
    Poll GET /v1/customers/{customer_uuid}/ after submission. kyc_level alone is not enough for a Standard customer, who also needs activation.

Accounts (External Accounts)

  • Is the payout account registered before the first order?
    A bank account for off-ramp, a wallet for on-ramp. Keep the uuid to pass as destination.client_account_uuid.
  • Do you collect the wallet ownership proof at registration time?
    Ethereum wallets need the signed message, with a timestamp less than 24 hours old. A duplicate address answers 400 oa_client_external_account_address_exists; ask the user for another wallet.

Orders (Fees, Limits, Orders)

  • Do you run the three checks before each order?
    POST /v1/exchange-routes/check/ answers available: true; check-fees gives the quote you show as an estimate; check-limits answers an empty list. Any item in that list means refusal.
  • Do you send an Idempotency-Key?
    Generate it before the first attempt and reuse the same key only when retrying the same request. Retry network errors and 5xx; do not retry 4xx except 409. See Idempotency.
  • Is the deposit screen rendered from the order you just created?
    On-ramp: deposit_bank_info with holder_name as the payee and the reference the user must copy exactly. Off-ramp: deposit_address, the network and source.amount. Both show valid_until as the deadline and destination.amount as an estimate until the deposit lands.
  • Is there one open order per customer and destination?
    Crypto deposits are matched by address and attach to the newest open order. See How Deposits Are Matched.

Monitoring (Webhooks)

  • Does your webhook endpoint handle deliveries correctly?
    Verify X-Api-Sig over the raw body before parsing, answer 2xx within 60 seconds, and ignore event types you do not know.
  • Do you deduplicate and order events yourself?
    Deduplicate on order_uuid plus status and order by your receipt time; the payload timestamp is the order creation time.
  • Do you poll open orders as a fallback?
    A delivery that fails its retries is not replayed. While state is new, the same poll reads source.deposit_status.
  • Is failed non-terminal in your status model?
    Final states are done, rejected, cancelled, stopped and rollbacked.

Phase 3: Test

  • Has one on-ramp and one off-ramp order reached done?
    End to end, with a real deposit.
  • Have the negative paths run?
    A route that is unavailable, a limit that is exceeded, an order left to expire past valid_until, a cancelled order, a webhook endpoint that was down during a status change and caught up by polling.
  • Do your logs keep trace_id from every error response?
    Support asks for it first.

Phase 4: Go Live

  • Are support contacts exchanged in both directions?
    The cases that need them: a deposit without reference, a transfer on the wrong network, a rejected deposit, a customer that needs closing or unblocking.
  • Is key rotation rehearsed?
    Create a new key, switch, delete the old one; deletion takes effect immediately.
  • Do you follow changes?
    The Changelog lists every change, and Stablegate sends each partner a personal digest of what affects their integration.

Common Mistakes

MistakeWhat happensWhat to do instead
Path without the trailing slash307 and an extra round trip, or no data for a client that does not follow redirectsEnd every path with /
Treating check-fees as a locked quoteThe payout differs from what the user sawShow the quote as an estimate; read exchange_rate and rate_valid_until from the order
Reading excess_amount > 0 as "limit exceeded"A breached minimum-amount rule is missedAny item in the check-limits response means refusal
Waiting for a webhook for verification or depositNothing arrivesPoll the customer detail for can_trade, and the order detail for deposit_status
Creating a second order while one is open on the same addressThe deposit attaches to the newest orderOne open order per customer and destination
Re-serializing the webhook body before verifying the signatureEvery signature check failsVerify over the raw bytes
Ordering events by the webhook timestampTransitions appear out of orderUse your receipt time and the previous_status to status pair
Treating failed as finalThe order later moves to processing or done and your user sees a wrong statusKeep polling until a final state
Treating 404 on a customer UUID as an auth problemTime lost on key checks404 means not your customer; 403 means the key lacks access
Parsing amounts as floatsRounding errors and refused ordersUse a decimal type and fraction_digits

Ready to integrate?

Tell us about your use case and we will enable Partner API access for your account.
Copyright © 2026