Fiatside

Developers

Quoting an operation

Quoting is the only endpoint open today, and the most important one: it returns the line-by-line breakdown the site displays. It needs no key.

POST/api/quoteLive

Quote an operation

Returns the complete breakdown of a sale: the mid-market rate used, every charge on its own line, the net amount and the effective rate actually obtained. The lines sum to exactly the gap between gross and net — the invariant is checked before the response leaves, and an unbalanced response is never returned.

Authentication: none today. The quote endpoint is open: a quote reveals no personal data.

Parameters

Parameters
FieldTypeDescription
assetIdrequiredstringIdentifier of the deposited asset, for example “btc”, “usdt”, “sol”.
railIdrequiredstringIdentifier of the payout method, for example “sepa_instant”, “br_pix”, “ke_mpesa”.
networkIdstringDeposit network. Optional: the asset’s first network is used by default. Network cost varies a lot between networks, so this field changes the net amount.
directionrequired"sell" | "receive"Input direction. “sell”: the amount is what you deposit. “receive”: the amount is what you want to receive, and the required deposit is resolved by binary search.
amountrequiredstringAmount in major units, sent as a STRING. A JSON float would lose minor units on large amounts: a string is the only format on which client and server agree to the cent.
Requestbash
curl -sS -X POST https://fiatside.com/api/quote \
  -H 'Content-Type: application/json' \
  -d '{
    "assetId": "usdt",
    "railId": "sepa_instant",
    "networkId": "tron",
    "direction": "sell",
    "amount": "1000"
  }'
Response — real examplejson
{
  "deposit": { "amount": "1000.000000", "ticker": "USDT", "decimals": 6 },
  "gross": "921.68",
  "net": "912.28",
  "currency": "EUR",
  "currencyDecimals": 2,
  "midRate": "0.92168430",
  "effectiveRate": "0.91228000",
  "totalCostBps": 102,
  "lines": [
    { "code": "network", "amount": "1.11", "basis": "Cout reseau tron, preleve en USDT" },
    { "code": "spread",  "amount": "8.29", "basis": "0.90 % du montant converti" }
  ],
  "settlement": { "p50Minutes": 1, "p95Minutes": 12 },
  "lockSeconds": 1800,
  "rateAsOf": 1788356981608,
  "rateSource": "mock",
  "limitError": null
}
  • The response carries Cache-Control: no-store. A cached quote is a stale price served as a firm one.
  • A rail limit breach is not an HTTP error: the quote is returned with a limitError object carrying the below_min or above_max code and the exact limit, so your interface can show the right message without a second call.
  • rateSource states where the price came from. The value “mock” is the deterministic development source: it cannot boot in production, where the process refuses to start rather than quote frozen prices.

Possible errors: invalid_request, unknown_asset_or_rail, rail_not_open, asset_not_offered, invalid_amount, rate_stale, rate_unavailable, quote_failed. Full catalogue

01

Reading the breakdown

The lines array holds one entry per real charge. A zero line is not returned: showing “rail fee: 0.00” adds nothing and clutters the interface.

Reading the breakdown
codeWho receives itWhat it is
networkThe blockchain networkCost of moving the asset, taken in kind from the deposit before conversion. It varies with the network chosen, sometimes by a wide factor: that is why networkId changes the net amount.
spreadUsOur margin, expressed as a percentage of the converted amount. It is the only line that is our revenue.
railThe payment institutionPayout method fee, fixed, proportional or both. Absent when the rail charges nothing, which is the case for most open rails.
fxForeign exchangeLine reserved for an explicit exchange spread when an extra conversion happens. It does not appear on corridors where the rail currency is the quote currency.

The invariant that makes the table checkable

gross minus the sum of the lines equals net exactly, to the minor unit. That equality is checked on every quote before the response leaves; if it does not balance, an undeclared margin exists somewhere, and the engine raises rather than return it. You can redo the arithmetic: that is the point.

02

An example with a rail fee

The same amount towards a rail that charges for sending brings out the third line. Real response, obtained on the deterministic development source.

Requestbash
curl -sS -X POST https://fiatside.com/api/quote \
  -H 'Content-Type: application/json' \
  -d '{
    "assetId": "usdt",
    "railId": "ke_mpesa",
    "networkId": "tron",
    "direction": "sell",
    "amount": "1000"
  }'
Response — real examplejson
{
  "gross": "129525.90",
  "net": "128141.44",
  "currency": "KES",
  "totalCostBps": 107,
  "lines": [
    { "code": "network", "amount": "155.44", "basis": "Cout reseau tron, preleve en USDT" },
    { "code": "spread",  "amount": "582.17", "basis": "0.45 % du montant converti" },
    { "code": "rail",    "amount": "646.85", "basis": "0.50 % du montant converti" }
  ],
  "settlement": { "p50Minutes": 2, "p95Minutes": 45 },
  "limitError": null
}

Three lines, three different recipients: the network, us, the payment institution. The totalCostBps field gives the total gap from the mid-market rate in basis points — the only number worth comparing between services, because it covers everything, including what would otherwise hide inside a rate.

03

Rail limits

An amount outside the rail bounds does not produce an HTTP error: the quote is returned, with a limitError object. Your interface can therefore show the amount AND the exact reason, with no second call.

Response excerpt — real examplejson
{
  "net": "3.47",
  "currency": "EUR",
  "limitError": { "code": "below_min", "limit": "20.00" }
}

Possible values are below_min and above_max, and limit holds the bound in major units of the rail currency. Note: the bound applies to the NET amount, not the deposit — what the beneficiary receives is what has to fit within the rail limits.

04

Validity window

The lockSeconds field states how long the rate will be frozen once the order is created. It depends on the asset: longer on a stablecoin, shorter on a volatile one.

  • The quote itself is not firm: it is indicative until an order is created. The rate locks at order creation, not at the quote call.
  • The window covers your decision, not the network confirmation time. A bitcoin deposit can need an hour of confirmations: the lock protects against market movement while you decide and deposit.
  • If the deposit lands after expiry, the order is re-quoted and the new amount must be accepted. A silent re-price against the customer is impossible by construction.
  • Do not cache a quote to paper over a stale-rate error. A cached quote is a stale price presented as firm, which is exactly the problem the refusal code prevents.