Overview
The incentives surface exposes a customer’s promotional-grant ledger: the bonus credit they hold, the state of each grant, and the operator action to reverse a grant. Two operations are callable.GET /customers/{customerId}/grantslists a customer’s promotional grants and the state of each.POST /grants/{id}/clawbackreverses a grant when the event that funded it is voided, refunded, or fraudulent.
Call
GET /capabilities and GET /openapi at runtime for the authoritative list of what is available. Where this page and the served spec disagree, the spec wins.List a customer’s grants
GET /customers/{customerId}/grants returns the customer’s promotional grants, each with its source, its state-machine state, its original and remaining amounts, and its expiry. The feed is read-only, tenant-scoped (it returns only grants belonging to the authenticated tenant), and cursor-paginated. Authenticate with the PosTerminalJWT scheme.
customerId is the customer’s wallet identity id, passed as a path parameter.
Query parameters
required
Filter by grant state. One of
LOCKED, RELEASED, CLAWED_BACK, EXPIRED.required
Opaque pagination cursor. Pass
next_cursor from the previous page.required
Max grants per page. Default
50, maximum 100.Response fields
required
The wallet identity id the grants belong to.
required
The customer’s promotional grants. Each entry is a grant object (fields below).
required
The cursor for the next page, or
null when there are no more pages.required
true when more pages follow.required
The grant’s stable id. Pass this as the path id when clawing back.
required
What funded the grant. One of
CASHBACK, RELOAD_BONUS, SKU_TOPUP_BONUS, GATEWAY_BONUS.required
The state-machine state. One of
LOCKED, RELEASED, CLAWED_BACK, EXPIRED. A LOCKED grant becomes RELEASED on claim; CLAWED_BACK and EXPIRED are terminal.required
The grant’s original value, as
amount_minor (integer, minor units) and currency (ISO-4217).required
The unspent value, in the same
amount_minor plus currency shape.required
RFC3339 timestamp of when the grant accrued, or
null.required
RFC3339 timestamp of when the grant expires unclaimed or unspent, or
null.required
Server-derived reference to the finalized source event (for example
pos:order:5512), or null.An empty
grants array is a success. It means the customer holds no grants matching the filter, not an error. A 404 (NOT_FOUND) means the customer was not found or belongs to another tenant.Errors
The JWT is missing or invalid. Re-exchange your terminal credential for a fresh JWT and retry.
The customer was not found, or resolves to another tenant. Cross-tenant lookups collapse to
NOT_FOUND so existence is not leaked.Clawback a grant
POST /grants/{id}/clawback reverses a promotional grant when the source event that funded it is voided or refunded, or for fraud. Authenticate with the ApiKeyAuth scheme: this is an operator action gated to operator or admin keys, not a terminal JWT.
id is the grant_id from the grants list, passed as a path parameter.
A LOCKED grant claws back its full amount. A RELEASED grant claws back only the remaining unspent amount. Any already-spent portion is booked as a merchant loss and is never pulled back from the customer’s cash balance, because promotional money never converts to cash. The grant transitions to CLAWED_BACK, which is terminal, in a single atomic operation.
Clawback moves promotional money and lands the grant in a terminal state. It cannot be undone. Confirm the source event is genuinely voided, refunded, or fraudulent before calling.
Request fields
required
A unique key for this clawback. Replaying the same key is a no-op that returns the original result.
required
Request metadata. Requires
partner_request_id (your correlation UUID) and api_version. occurred_at and sent_at are recommended RFC3339 timestamps. partner_request_id is a correlation id only, never the deduplication key; deduplication is keyed on the Idempotency-Key header.required
Why the grant is being clawed back. One of
SOURCE_ORDER_VOIDED, SOURCE_REFUNDED, FRAUD, DUPLICATE, OTHER.required
Free-text note for the audit trail, or
null.Response fields
required
The grant that was clawed back.
required
Always
CLAWED_BACK on success.required
The amount reversed, as
amount_minor and currency.required
The already-spent promotional portion booked as a merchant loss, as
amount_minor and currency. Not recovered from the customer.required
RFC3339 timestamp of the clawback.
Idempotency
The clawback is mutating and idempotent on theIdempotency-Key header. Send a unique key per clawback. A same-key, same-payload retry replays the original result with meta.idempotency_replayed: true. Clawing back an already CLAWED_BACK grant is a no-op replay. A same-key, different-payload request returns IDEMPOTENCY_KEY_REUSED (422). See Idempotency and errors.
Errors
The grant is not in a clawback-able state (already
EXPIRED or CLAWED_BACK), or the body failed validation. Re-read the grant with the list endpoint to confirm its current state.The API key is missing or invalid.
The key lacks clawback permission. Clawback requires an operator or admin key.
The grant was not found, or belongs to another tenant.
The same
Idempotency-Key was presented with a different payload. Use a new key.Response metadata
Both operations return the standardmeta envelope. Two fields are informational:
data_completeness_score: an opaque integer Feddi may use internally. No action required.decision_trace_id: an opaque correlation id. Persist it and echo it where a call accepts one.
Where to go next
Money: actual vs promotional
The two-class balance model and the grant state machine: LOCKED, RELEASED, CLAWED_BACK, EXPIRED.
Transactions
Read the transaction record where redeemed promotional credit and clawbacks land.
Idempotency and errors
The idempotency contract and the typed error codes both operations return.
API conventions
The response envelope, money-as-minor-units, pagination, and versioning.