An FX quote was issued for a crypto send.
Triggered when the recipient has picked a currency and network and a quote has been issued. This is the earliest event you receive for a given crypto send.
payout_type is always crypto.
Body
The crypto body, meaning event, payout_type, and data. data is the provider's send request.
One event per send, not per requestIdempotent retries of the same quote call do not re-emit. You get one
payout.quote_createdper send.If the quote expires or gets cancelled and the recipient quotes again, that is a new send with its own
payout.quote_createdand its owndata.id. Treat each as a separate lifecycle.
The data object
data objectThis is our crypto provider's send request, passed through as we received it. The shape is the same on every crypto event, so it is documented once here.
| Field | Type | Notes |
|---|---|---|
id | Integer | The send identifier. Key your records on this. |
status | String | The provider's raw status, not GIFQ's mapped status. See the mapping callout. |
purpose | String | Readable description. |
created_at | String | ISO-8601, when the send request was created. |
input_amount | String | Amount being sent, in input_currency. |
input_currency | Hash | Currency object. |
sending_amount | String | Amount the recipient receives, in sending_currency. Absent on a cross-currency send until the exchange is confirmed. |
sending_currency | Hash | Currency object. |
input_to_sending_rate | String | FX rate applied. "1.0" for same-currency. May be absent before confirmation on cross-currency. |
balance_debit_amount | String | Amount debited from the funding ledger, in balance_debit_currency. |
balance_debit_currency | Hash | Currency object. |
sending_to_balance_debit_rate | String | Rate from sending_currency to balance_debit_currency. |
fees.service_fee | Hash | { amount, currency }. Always present. |
fees.conversion_fee | Hash | { amount, currency }. Only on cross-currency sends. The key is omitted entirely otherwise. |
exchange | Hash | { rate, expires_at }. Cross-currency only. expires_at is when the quote lapses. |
ledger_account | Hash | { id, title, status, balance, account_type, currency }. The account funds are debited from. id is a string. |
beneficiary_payout_setting | Hash | { id, beneficiary_id, created_at, currency, platform, crypto_address, crypto_address_metadata }. Destination wallet. |
blockchain_transactions | Array | Empty [] until the chain broadcast lands. See BlockchainTransaction. |
requires_2fa_confirmation | Boolean | Whether the recipient must complete 2FA before the send proceeds. |
actions_required | null | Hash | Provider-side approval flag. null in normal operation. |
Absent is not the same as failedA
nullor missingsending_amount,input_to_sending_rate, orfees.conversion_feeon a cross-currency send usually means the exchange was never confirmed, because the recipient cancelled or the quote lapsed. Checkstatusbefore treating it as a data problem.
Amounts insidedataare decimal stringsParse them with an arbitrary-precision decimal type, never a float. Gift-card bodies differ, since their amounts are JSON numbers.
Currency object
input_currency, sending_currency, balance_debit_currency, and the nested currency under fees.*, ledger_account, and beneficiary_payout_setting all share one shape.
| Field | Type | Notes |
|---|---|---|
id | Integer | Internal currency ID. |
kind | String | "fiat" or "crypto". |
title | String | Full name, such as "Ethereum". |
symbol | String | Ticker, such as "ETH". |
BlockchainTransaction object
These are the entries in data.blockchain_transactions[]. The array is empty until the broadcast lands.
| Field | Type | Notes |
|---|---|---|
id | Integer | Internal transaction ID. |
txid | String | On-chain transaction hash. |
amount | String | Decimal amount transferred. |
status | String | For example "confirmed". |
network_confirmations | Integer | Confirmations received. |
currency | Hash | A thinner variant: { id, title, symbol, platform: { id, title } }. platform names the chain, such as "Base" or "Solana". |
The blockchain gas fee is not in this payload
feescovers the service fee and, on cross-currency sends, the FX conversion fee. Neither is blockchain gas. Gas is not exposed at quote time and only becomes visible throughblockchain_transactions[]after the broadcast.
Example
{
"event": "payout.quote_created",
"payout_type": "crypto",
"data": {
"id": 354,
"status": "draft",
"purpose": "Gifq payout to [email protected]",
"created_at": "2026-05-25T10:00:00.000Z",
"input_amount": "100.0",
"input_currency": {
"id": 2, "kind": "fiat", "title": "Euro", "symbol": "EUR"
},
"sending_amount": "0.049422",
"sending_currency": {
"id": 5, "kind": "crypto", "title": "Ethereum", "symbol": "ETH"
},
"input_to_sending_rate": "0.00049422",
"sending_to_balance_debit_rate": "40.3258",
"balance_debit_amount": "0.00122557",
"balance_debit_currency": {
"id": 1, "kind": "crypto", "title": "Bitcoin", "symbol": "BTC"
},
"fees": {
"service_fee": {
"amount": "1.016086",
"currency": { "id": 2, "kind": "fiat", "title": "Euro", "symbol": "EUR" }
},
"conversion_fee": {
"amount": "0.5",
"currency": { "id": 2, "kind": "fiat", "title": "Euro", "symbol": "EUR" }
}
},
"exchange": {
"rate": "0.00049422",
"expires_at": "2026-05-25T10:01:00Z"
},
"ledger_account": {
"id": "01JNQWKKJ6WXN8BZT1Y66B6G9H",
"status": "active",
"balance": "1.0",
"currency": { "id": 1, "kind": "crypto", "title": "Bitcoin", "symbol": "BTC" }
},
"beneficiary_payout_setting": {
"id": 2,
"beneficiary_id": 1,
"created_at": "2026-05-25T09:59:59.000Z",
"crypto_address": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B",
"crypto_address_metadata": null,
"platform": { "id": 21, "title": "Solana", "id_name": "solana" },
"currency": { "id": 5, "kind": "crypto", "title": "Ethereum", "symbol": "ETH" }
},
"blockchain_transactions": [],
"requires_2fa_confirmation": false,
"actions_required": null
}
}What to do on receipt
- Start a payout lifecycle keyed on
data.id, and store the snapshot if you show quote details to your users. - No funds have moved. Do not credit anything yet.
- If
exchange.expires_atis present, the recipient is on a cross-currency quote with a deadline. Expect eitherpayout.quote_confirmedorpayout.quote_cancellednext. - Same-currency sends skip confirmation and go straight to
payout.in_progress.