payout.quote_created

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 request

Idempotent retries of the same quote call do not re-emit. You get one payout.quote_created per send.

If the quote expires or gets cancelled and the recipient quotes again, that is a new send with its own payout.quote_created and its own data.id. Treat each as a separate lifecycle.

The data object

This 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.

FieldTypeNotes
idIntegerThe send identifier. Key your records on this.
statusStringThe provider's raw status, not GIFQ's mapped status. See the mapping callout.
purposeStringReadable description.
created_atStringISO-8601, when the send request was created.
input_amountStringAmount being sent, in input_currency.
input_currencyHashCurrency object.
sending_amountStringAmount the recipient receives, in sending_currency. Absent on a cross-currency send until the exchange is confirmed.
sending_currencyHashCurrency object.
input_to_sending_rateStringFX rate applied. "1.0" for same-currency. May be absent before confirmation on cross-currency.
balance_debit_amountStringAmount debited from the funding ledger, in balance_debit_currency.
balance_debit_currencyHashCurrency object.
sending_to_balance_debit_rateStringRate from sending_currency to balance_debit_currency.
fees.service_feeHash{ amount, currency }. Always present.
fees.conversion_feeHash{ amount, currency }. Only on cross-currency sends. The key is omitted entirely otherwise.
exchangeHash{ rate, expires_at }. Cross-currency only. expires_at is when the quote lapses.
ledger_accountHash{ id, title, status, balance, account_type, currency }. The account funds are debited from. id is a string.
beneficiary_payout_settingHash{ id, beneficiary_id, created_at, currency, platform, crypto_address, crypto_address_metadata }. Destination wallet.
blockchain_transactionsArrayEmpty [] until the chain broadcast lands. See BlockchainTransaction.
requires_2fa_confirmationBooleanWhether the recipient must complete 2FA before the send proceeds.
actions_requirednull | HashProvider-side approval flag. null in normal operation.
🚧

Absent is not the same as failed

A null or missing sending_amount, input_to_sending_rate, or fees.conversion_fee on a cross-currency send usually means the exchange was never confirmed, because the recipient cancelled or the quote lapsed. Check status before treating it as a data problem.

📘

Amounts inside data are decimal strings

Parse 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.

FieldTypeNotes
idIntegerInternal currency ID.
kindString"fiat" or "crypto".
titleStringFull name, such as "Ethereum".
symbolStringTicker, such as "ETH".

BlockchainTransaction object

These are the entries in data.blockchain_transactions[]. The array is empty until the broadcast lands.

FieldTypeNotes
idIntegerInternal transaction ID.
txidStringOn-chain transaction hash.
amountStringDecimal amount transferred.
statusStringFor example "confirmed".
network_confirmationsIntegerConfirmations received.
currencyHashA 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

fees covers 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 through blockchain_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_at is present, the recipient is on a cross-currency quote with a deadline. Expect either payout.quote_confirmed or payout.quote_cancelled next.
  • Same-currency sends skip confirmation and go straight to payout.in_progress.