Fiatside

Developers

Orders and idempotency

Creating an order locks the rate and assigns a deposit address. It is the one place where an integration mistake moves money: idempotency is not a convenience there.

Published contract, not open yet

These endpoints are not exposed today. They are documented so you can build your integration ahead of time; their shape is settled, and any breaking change will go through a new version and a changelog entry.

POST/api/v1/ordersPublished contract, not open

Create an order

Locks the rate and returns a dedicated deposit address. The order carries the breakdown as locked: it is replayable, which lets you reconstruct the exact price applied even months later. The Idempotency-Key header is required.

Authentication: Authorization: Bearer … See authentication

Parameters

Parameters
FieldTypeDescription
quoteIdrequiredstringIdentifier of the accepted quote.
beneficiaryrequiredobjectFields imposed by the rail schema. The name must match the verified identity: no third-party payouts.
networkIdrequiredstringNetwork the deposit will be sent on. It determines the address returned and, on some networks, the mandatory memo.
Requestbash
curl -sS -X POST https://fiatside.com/api/v1/orders \
  -H 'Authorization: Bearer sk_live_...' \
  -H 'Idempotency-Key: 7f3a1c92-5d0e-4a1b-9c2f-6b8e0d4a1f33' \
  -H 'Content-Type: application/json' \
  -d '{
    "quoteId": "qt_01J9Z...",
    "networkId": "tron",
    "beneficiary": {
      "railId": "sepa_instant",
      "beneficiaryName": "Camille Dupont",
      "iban": "FR7630001007941234567890185"
    }
  }'
Response — published contractjson
{
  "reference": "K7Q4-M2XB",
  "state": "AWAITING_DEPOSIT",
  "deposit": {
    "asset": "USDT",
    "network": "tron",
    "address": "T...",
    "memo": null,
    "amountBase": "1000000000",
    "expiresAt": "2026-09-02T12:41:00Z"
  },
  "payout": { "railId": "sepa_instant", "netMinor": 91228, "currency": "EUR" },
  "rateLock": { "midRate": "0.92168430", "lockedUntil": "2026-09-02T12:41:00Z" }
}
  • The memo is null on most networks and mandatory on XRP, Stellar and TON. Omitting it there loses the funds: treat the field as required as soon as it is non-null.

Possible errors: unauthorized, invalid_request, quote_expired, idempotency_conflict, beneficiary_rejected, country_not_served. Full catalogue

GET/api/v1/orders/{reference}Published contract, not open

Read an order

Current state and timestamped transition history. The history is the source of truth: it is append-only, never rewritten, and it is what answers “why did my order move to that state at that time”.

Authentication: Authorization: Bearer … See authentication

Requestbash
curl -sS https://fiatside.com/api/v1/orders/K7Q4-M2XB \
  -H 'Authorization: Bearer sk_live_...'
Response — published contractjson
{
  "reference": "K7Q4-M2XB",
  "state": "COMPLETED",
  "transitions": [
    { "at": "2026-09-02T12:11:04Z", "from": "QUOTE_LOCKED",     "to": "AWAITING_DEPOSIT" },
    { "at": "2026-09-02T12:19:52Z", "from": "AWAITING_DEPOSIT", "to": "DEPOSIT_DETECTED" },
    { "at": "2026-09-02T12:21:10Z", "from": "CONFIRMING",       "to": "DEPOSIT_CONFIRMED" },
    { "at": "2026-09-02T12:21:44Z", "from": "PAYOUT_QUEUED",    "to": "PAYOUT_SENT" },
    { "at": "2026-09-02T12:22:03Z", "from": "PAYOUT_SENT",      "to": "COMPLETED" }
  ]
}

Possible errors: unauthorized, not_found. Full catalogue

01

Idempotency

A creation request that times out on the network does not tell you whether the order was created. Without an idempotency key you only have two bad options: retry and risk two orders, or do not retry and risk none.

Headerhttp
Idempotency-Key: 7f3a1c92-5d0e-4a1b-9c2f-6b8e0d4a1f33

One key per intent

The key identifies the intent “create that order”, not the HTTP request. A unique id on your side: a cart id, a UUID generated before the call, never a counter.

A replay returns the original response

Replaying the same key with the same body returns the first request’s response, with the same HTTP status. That is what makes a retry safe, including after a timeout.

Same key, different body: conflict

The response is an explicit conflict. If the content changes, the key must change: otherwise nobody can tell which of the two orders to replay.

24-hour retention

After that the key is forgotten and a replay would create a new order. Retry inside the window, or check the state with the read endpoint.

02

The memo, on networks that require one

On XRP, Stellar and TON the deposit address is not enough: an extra identifier designates the final recipient. It is the costliest incident cause in an off-ramp integration.

A deposit without its memo is a lost deposit

The memo field is null on most networks and non-null on those that require one. Treat it as mandatory as soon as it is non-null, and display it with the same weight as the address. A deposit arriving without its memo on a shared address needs manual recovery, which does not always succeed.

03

Order states

The states below are the ones your integration can observe. Transitions are timestamped and appended, never rewritten: the history answers “why did my order move to that state at that time”.

Order states
StateWhat it means
QUOTE_LOCKEDThe rate is frozen. The order awaits beneficiary details or identity verification.
AWAITING_DEPOSITThe deposit address is assigned and the deposit window is running. That is the only moment to send funds.
DEPOSIT_DETECTEDAn incoming transaction is seen on the network, not yet confirmed. Reassure the user, deliver nothing.
CONFIRMINGConfirmations are accumulating. The number required depends on the network, not the amount.
DEPOSIT_CONFIRMEDThe deposit is secured. Compliance and re-pricing rules are evaluated from here.
UNDERPAIDThe amount received is below expected beyond tolerance. Three outcomes: top up, continue at the received amount, or be refunded.
OVERPAIDThe amount received exceeds expected. The initial amount stays at the locked rate, the excess is handled separately.
PAYOUT_QUEUEDThe transfer is queued. The queue guarantees a payout is sent once, even if several workers fire in parallel.
PAYOUT_SENTThe transfer has left on the rail. Sent is not received: the final delay depends on the beneficiary’s bank.
COMPLETEDSettlement is confirmed by the rail. Terminal state.
PAYOUT_FAILEDThe rail rejected or returned the transfer. No automatic retry: the cause is nearly always in the details.
REFUNDEDFunds returned to the originating address, net of network fees. Terminal state.