For the complete documentation index, see llms.txt. This page is also available as Markdown.

Bonus Consumption & Reversal

Flow 4 — Consume bonus (client wallet first, then notify Wynta)

Trigger: the player places a wager funded (fully or partly) from bonus.

Order of operations — the PAM debits its client wallet first, then notifies Wynta:

  1. Client wallet debit (PAM): the PAM checks its local Bonus Wallet Available balance for the chip type, debits the bonus portion of the wager, and lets gameplay proceed. If Available is insufficient, the PAM rejects the bonus spend locally — no call to Wynta.

  2. Consume notification (PAM → Wynta): the PAM immediately notifies Wynta via bonus_consume_bonus (S2S) with a unique consume_txn_id.

  3. Ledger write (Wynta): Wynta validates and debits the amount across RELEASED chunks — earliest expires_at first, then earliest released_at — writing each chunk debit under consume_txn_id.

  4. Confirmation (Wynta → PAM): Wynta emits the BONUS_CONSUMED webhook. The PAM does not debit again — it matches the webhook to its step-1 debit by consume_txn_id and reconciles its balance against resulting_balance.

Player          PAM (Client) — external client         Wynta Bonus
  │  wager 50     │                                    │
  │──────────────▶│ 1. wallet: Available 40 → 20       │
  │               │    (consume 20 from client wallet) │
  │               │ 2. POST /consume             │
  │               │    {consume_txn_id, bonus: 20}     │
  │               │───────────────────────────────────▶│ 3. debit chunks,
  │               │                                    │    write ledger
  │               │◀──── 4. webhook BONUS_CONSUMED ────│
  │               │    match by consume_txn_id;        │
  │               │    verify resulting_balance        │

Endpoint: POST /api/v1/user-bonuses/consume (S2S, requires the X-Client-Id header):

Response 201 Created echoes consume_txn_id with the ledger txn_id and consumed_amount. The service auto-selects the user's next available released chunk — the PAM never picks chunks. Monetary values are decimal strings.

Rules:

  • Idempotency: consume_txn_id must be unique per consumption. Generate and store it before calling the API. A retry with the same ID returns 409 Conflict — treat a 409 for an ID you have recorded as "already consumed" (success), not an error. 409 is also returned when no released chunk is available, or when reverting an already-reverted consumption.

  • Wynta rejects the notification — 409 no released chunk available (a 409 for an unknown consume_txn_id state), 404 unknown record, or 400 validation error: the client wallet has drifted — the PAM must reverse its step-1 debit and flag the player for targeted reconciliation. Wynta's ledger is final authority.

  • Notification delayed/failed (Wynta unreachable): the PAM queues and retries the consume notification with the same consume_txn_id. The client debit stands in the meantime; reconciliation catches anything the retry queue loses.

  • Missing webhook: if BONUS_CONSUMED doesn't arrive within the delivery SLA but the API call succeeded, the ledger entry exists — the webhook will arrive via retry or the gap is closed at reconciliation. The PAM must not double-debit either way.

Reversal — voided rounds

Endpoint: POST /api/v1/user-bonuses/consume/{consume_txn_id}/revert

Mirroring the consume order, the PAM credits its client wallet back and notifies Wynta:

  1. PAM restores the amount to its wallet (Available += amount) when the round is voided.

  2. PAM calls the revert endpoint with the original consume_txn_id in the path (no auth header required); the 200 OK response returns the reversed amount and chip_type. Reverting twice returns 409 Conflict.

  3. Wynta reverses the consumption chunk by chunk — exact, because every consumption is recorded per chunk — and emits BONUS_CONSUMPTION_REVERTED.

  4. The PAM matches the webhook by consume_txn_id (no double credit) and verifies resulting_balance.

If a chunk expired between consume and revert, the reverted amount follows the expiry rules rather than silently returning to Available — the webhook deltas make the outcome explicit; the PAM adjusts to match.

Player-facing queries

API
Purpose

GET /{user_id}/summary

Authoritative bonus_balance / pending_bonus / wagering_required per chip type — drift checks, progress bars, support tooling

GET /{user_id}/transactions?chip_type=

Flat paginated ledger — every grant / released / consumed / expiry / forfeited event is its own entry (limit 1–200, default 50)

GET /{user_id}/transactions/{txn_id}

Full grant detail including chunks, forfeit record, and expiry events — ground truth for disputes and reconciliation

Last updated

Was this helpful?