Skip to content
Gave

Spend events

POST /v1/spend-events

A spend event is one card transaction, as your processor reports it. Send each one as it happens. Gave stores it before answering, then applies your programs.

Kinds

kindWhenExtra field
authorizationThe card was authorized. Gives an estimate, never a reward
incremental_authorizationMore was authorized on an open authorization, such as a hotel extending its hold. amount is the increase, not the new totalauthorizationId
clearingThe transaction settled with its final amount. This is what earns a rewardauthorizationId, optional
reversalAn authorization was voided or expired before clearingauthorizationId
refundMoney went back to the cardholder after clearing, in full or in part. amount is this refund'soriginalTransactionId

authorizationId and originalTransactionId are the externalTransactionId of the event they refer to. If an event arrives before the one it refers to, such as a refund before its clearing, Gave sets it aside and applies it once the original arrives.

A refund before your user claims the reward reduces it, in proportion. A refund after they claimed it is owed back, and recovered from their next claimable rewards (owed in the balance).

Fields

FieldTypeWhat it is
kindstringOne of the kinds above
integratorIdstringYour integrator ID. It must be the key's
userIdstringYour ID for the user
externalTransactionIdstringYour processor's ID for the transaction
amount.currencystringISO 4217 code, such as USD
amount.amountstringIn the currency's minor unit (cents): up to 18 digits
merchant.descriptorstringAs on the card transaction, 1 to 200 characters
merchant.mccstringThe 4-digit merchant category code
merchant.midstring, optionalThe merchant ID, 1 to 64 characters
merchant.countrystring, optionalISO 3166 alpha-2 code, such as US
occurredAtstringWhen it happened, in UTC. At most a minute ahead of Gave's clock

USD spend earns rewards in USDC and EUR spend in EURe, one to one. Spend in other currencies is stored, and earns nothing for now.

{
  "kind": "clearing",
  "integratorId": "acme",
  "userId": "alice",
  "externalTransactionId": "txn_0001",
  "amount": { "currency": "USD", "amount": "5000" },
  "merchant": { "descriptor": "BLUE BOTTLE COFFEE", "mcc": "5814", "country": "US" },
  "occurredAt": "2026-10-11T09:30:00.000Z"
}

Response

202 Accepted, once the event is stored:

SpendEventAccepted
{ "id": "se:acme:alice:clearing:txn_0001", "duplicate": false }

Retries and duplicates

An event is identified by your integrator, the user, its kind and its externalTransactionId.

  • The same event again is a duplicate: 202 with "duplicate": true, and nothing changes. So after a timeout or a 503, retry with the same body.
  • Different content under the same identity, such as another amount, is refused with 409 SpendEventConflict. It's never treated as a duplicate: fix the event, or its ID.

Errors

StatusErrorMeaning
400InvalidRequestThe body doesn't match the fields above
403IntegratorMismatchintegratorId isn't your key's
409SpendEventConflictThis event's ID was used with different content
422EventInFutureoccurredAt is more than a minute ahead: check the sender's clock and time zone
503UnavailableRetry the same request