Payout events

The recipient.* family, covering the entitlement as a whole, its running balance, and the four transitions we notify on.

payout.* events report one payout moving through its lifecycle, meaning a single crypto send or a single gift card. They fire for any payout order with a callback_url. See Subscribing.

For events about the recipient's entitlement as a whole, such as viewed, partially redeemed, and expired, see Recipient events.

Two payout types, two bodies

The payout.* family covers two payout types with two different body shapes. The event name on its own does not tell you which body you are holding.

CryptoGift cards
payout_typecryptogift_cards
Bodyevent, payout_type, dataFlat GIFQ envelope
IdentifiersInside dataTop level
AmountsDecimal strings in dataJSON numbers
Events6 status, 3 quote4 status

Route on event and payout_type together. payout.processing, payout.failed, and payout.cancelled exist on both sides.


Gift-card payout events

The subject is one gift card, and subject_type is "payout".

A recipient can hold several gift cards, one per brand and denomination they pick, so each body carries enough brand and amount detail to reconcile a specific card without another API call.

Events

EventStatusFires when
payout.processingprocessingThe card has been requested from the brand and is not yet issued.
payout.fulfilledfulfilledThe card was issued to the recipient. Terminal.
payout.failedfailedIssuance failed. Terminal. The recipient's balance goes back to them.
payout.cancelledcancelledThe card was cancelled. Terminal.

Each transition emits exactly one delivery.

Body

The GIFQ envelope, plus these keys.

FieldTypeNotes
payout_uuidStringThis gift card. Use it as your key for card-level reconciliation.
brand_uuidStringThe brand the card is drawn on.
brand_nameStringReadable brand name, such as "Amazon UK".
amountNumberCard denomination, in currency.
currencyStringThe currency amount is denominated in. This is not always the recipient's wallet currency.

Wallet balances, initial_amount and remaining_amount, are not on this body. They live on recipient events, because an FX redemption leaves those balances in the recipient's currency while the card is denominated in the brand's.

Example

{
  "event": "payout.fulfilled",
  "payout_order_uuid": "11111111-2222-3333-4444-555555555555",
  "recipient_email": "[email protected]",
  "recipient_uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "recipient_name": "Alice Doe",
  "subject_type": "payout",
  "status": "fulfilled",
  "updated_at": "2026-05-21T10:05:00Z",
  "payout_type": "gift_cards",
  "currency": "GBP",
  "sent_at": "2026-05-20T09:00:00Z",
  "viewed_at": "2026-05-21T10:00:00Z",
  "expires_at": "2026-08-20T09:00:00Z",
  "payout_uuid": "99999999-8888-7777-6666-555555555555",
  "brand_uuid": "77777777-6666-5555-4444-333333333333",
  "brand_name": "Amazon UK",
  "amount": 25.0
}

What to do on receipt

  • Key your ledger on payout_uuid. A recipient produces one of these per card, so recipient_uuid alone will collide.
  • On payout.fulfilled the card exists and the recipient has it. The code, PIN, and serial are never in this body.
  • On payout.failed the amount returns to the recipient's remaining balance. Expect them to redeem again, which produces a new payout_uuid.
  • Expect a recipient.partially_redeemed or recipient.redeemed alongside payout.fulfilled. We write them together, so a crash cannot leave you holding one without the other.

Crypto payout events

The subject is one crypto send.

Crypto bodies have three keys. No GIFQ envelope fields appear. Every detail lives inside data, which is our crypto provider's send request passed through.

Status events

These fire as the send progresses.

EventFires when
payout.in_progressThe send request was accepted. No funds have moved.
payout.processingAn FX exchange is in flight, or the chain broadcast is pending.
payout.completedThe send is finalized. Terminal.
payout.failedThe send did not go through. Terminal.
payout.expiredNobody actioned the send inside its window. Terminal.
payout.cancelledThe send was cancelled and no funds moved. Terminal.

A draft send emits nothing, since payout.quote_created already covers that moment.

Quote events

These fire from the recipient's redeem flow as they pick a currency and network.

EventFires when
payout.quote_createdA quote was issued. This is the earliest event for a given send.
payout.quote_confirmedThe recipient confirmed a cross-currency quote. Same-currency sends never emit this.
payout.quote_cancelledThe recipient cancelled an open quote. That send cannot be re-confirmed, and a new quote produces a new send.
📘

One quote event per send, not per request

Idempotent retries of the same quote call do not re-emit. If a quote expires and the recipient quotes again, that is a new send with its own payout.quote_created. Treat each as a separate lifecycle.

Crypto bodies

POST <your callback_url>
Content-Type: application/json
X-Gifq-Event: payout.completed
X-Gifq-Signature: sha256=<hex digest>
X-Gifq-Delivery: <uuid>
X-Gifq-Timestamp: 1774000000

{
  "event": "payout.completed",
  "payout_type": "crypto",
  "data": { "…": "provider send request" }
}
FieldTypeNotes
eventStringThe mapped GIFQ status. Mirrors X-Gifq-Event.
payout_typeStringAlways crypto on these bodies.
dataHash | nullThe provider's send request as we received it. null when the emitting path had no payload to attach.
🚧

data can be null

data carries a payload when the emitter had one, meaning an inbound provider callback, a pull-sync read, or a quote response. Otherwise it is null. Guard before reaching into it. Only event and payout_type are guaranteed non-null.

data.status holds the provider's raw string rather than GIFQ's. See the mapping callout.

What to do on receipt

  • Key on data.id, the send identifier. One recipient can produce several sends over time if quotes expire or get cancelled.
  • Treat payout.completed as the authoritative outcome, and cross-check through the GIFQ API rather than trusting the body alone.
  • If data is null on a terminal event, fetch the payout from the API to get the detail.
  • A crypto recipient reaching full redemption also produces recipient.redeemed.

Multiple recipients, multiple cards

One payout order fans out. For an order of N recipients where each redeems M gift cards, expect roughly N recipient event streams and N × M payout event streams.

Deliveries are capped at 5 per second per account and are delayed rather than dropped above that, so a large expiry sweep arrives spread over time and out of order. Sort on updated_at.