Skip to main content

Two classes, never one bucket

A Feddi wallet holds value in two distinct classes. Conflating them is the most common modeling mistake an integrator makes: it overstates the merchant’s real liability. Keep them separate in your own ledger and in anything you render to a cashier.

Actual balance (real money)

Funded by customer top-ups. A real deferred-revenue liability the merchant tracks. Spent on purchases after promotional credit is exhausted.

Promotional credit

Cashback, reload bonus, signup bonus. A contingent class: locked until earned, expirable, clawback-able, merchant-funded, never cashable. Not a real-money liability.

The Balance object

Every balance Feddi returns exposes both classes distinctly, never a single summed number. Money is always integer minor units paired with an explicit ISO-4217 currency.
required
Real money funded by top-ups, in minor units. A real deferred-revenue liability. Spent on purchases after promotional credit is exhausted.
required
Sum of remaining_minor across all released, non-expired promotional grants. Spendable now (promo-first). Not real money.
required
Sum of remaining_minor across all locked promotional grants. Gated on an activation condition (for example wallet signup or first top-up). Not yet spendable.
required
Top-ups in flight, not yet confirmed. Informational only, not spendable.
required
ISO-4217 currency code for all minor-unit fields in this balance, for example QAR.
Wallet identity state. One of verified or pending_proof. A pending_proof wallet may hold an actual balance but cannot pay; its cashback-class promo stays LOCKED.
Itemized promotional grant breakdown. Each entry carries source, state, remaining_minor, and expires_at. May be an empty array on a tight payment result object.
Grant state is uppercase everywhere grants appear (LOCKED, RELEASED, CLAWED_BACK, EXPIRED), both inside the promo_grants array and in the grant ledger read at GET /customers/{customerId}/grants. Claim states are a separate machine and stay lowercase.

Promo-first debit

When Feddi debits a wallet, it spends promotional credit first (FIFO by expiry across all released grants), then actual balance. The payment result splits the debit explicitly, and the two parts always sum to the amount.
required
Total amount debited, in minor units. Equal to debited_promo_minor + debited_actual_minor.
required
Portion drawn from released promo grants (FIFO by expiry). Zero if no promo was available.
required
Portion drawn from the actual (real-money) balance.
The invariant debited_promo_minor + debited_actual_minor == amount_minor always holds. If actual plus released promo cannot cover the amount, the call returns INSUFFICIENT_FUNDS (402) and the credential is not consumed, so you can route to top-up recovery and retry. See Idempotency and errors.

The promo-grant lifecycle

A promotional grant moves through a small state machine. In the grant ledger, the four states are uppercase.
required
One of LOCKED, RELEASED, CLAWED_BACK, EXPIRED.
  • LOCKED: accrued but gated. Cashback accrues on every transaction, including cash and card purchases, as locked promo. The customer signs up or tops up to unlock it.
  • RELEASED: spendable. Released only when the customer is verified and the merchant’s claim-gate condition is met. See PENDING_PROOF and promo release.
  • CLAWED_BACK: reversed. For example, reversing a top-up that earned a bonus claws the bonus back. A clawback that hits already-spent promo books the spent portion as a merchant marketing loss; it is never pulled from the customer’s actual cash. This is a terminal state.
  • EXPIRED: past its own clock. Promo expires on a merchant-configured schedule (for example, three months), independent of actual balance. This is a terminal state.
The grant source is one of CASHBACK, RELOAD_BONUS, SKU_TOPUP_BONUS, GATEWAY_BONUS, or SIGNUP_BONUS. Treat the set as open: read GET /capabilities and validate against the served OpenAPI spec rather than hard-coding it.

Accounting for the two classes

Promotional credit is accounted separately from the real-money float. Actual balance is a real liability (deferred revenue the merchant owes as goods or services). Promotional credit is a contingent promotional cost, not a settled obligation, because until it is released the customer cannot spend it. Treating the two as one bucket would overstate what the merchant owes.

Where to go next

PENDING_PROOF and promo release

How locked promo gets released safely, only on verified phone proof.

Top-up and reload bonus

Crediting actual balance and accruing reload-bonus promo.

Payments and redemption

The promo-first debit endpoint in detail.

Incentives

Read the promo-grant ledger and claw back a grant.