> For the complete documentation index, see [llms.txt](https://docs.wynta.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.wynta.com/bonus/flows/promo-sync-and-grant.md).

# Promo Code Sync, Validation & Bonus Grant

{% hint style="info" %}
**There is no code-application endpoint, and validation never grants.** `POST /validate-code` is a read-only eligibility check. **The bonus grant is created internally by Wynta when the configured release trigger event fires** (`deposit`, `registration`, `bet_placed`, …) — see [Bonus Events](/bonus/api-reference/bonus-events.md). The PAM learns of the grant via the `BONUS_GRANTED` webhook and updates its client wallet from it.
{% endhint %}

## Flow 1 — Promo code sync (PAM → Wynta, pull)

**Trigger:** the PAM (external client) needs to display available offers — deposit screen, registration, lobby promotions page.

**Endpoint:** `GET /api/v1/user-bonuses/applicable-codes?user_id=&chip_type=&display_on=` (no auth header)

Returns active codes ordered by `display_order`, filtered to the requested display flow (`display_on`, default `DEPOSIT`, matched against each code's comma-separated `display_on` list), with presentation fields (`display_title`, `banner_image_url`, `badge_text`, `cta_text`, `terms_url`, …) plus mechanics the PAM can surface (`wager_multiplier`, `no_of_chunks`, `applicability_frequency`, `max_amount`, validity window). See the [full endpoint reference](/bonus/api-reference/player-and-s2s.md#1-list-applicable-bonus-codes).

**Rules:**

* Synchronous request/response. Do **not** cache beyond the current session — budgets, validity windows, and eligibility change server-side.
* Codes are filtered by validity window, `active` flag, `min_display_amount`, and the configure's eligibility criteria.
* Codes flagged `system_auto_apply` are never returned — the backend applies them automatically when a `BONUS_RELEASE` event fires; they are not for manual selection.

## Flow 2 — Validate bonus code (PAM → Wynta)

**Trigger:** the player enters a bonus code in the PAM UI.

**Endpoint:** `POST /api/v1/user-bonuses/validate-code` with `{ "user_id", "chip_type", "code" }` (no auth header)

1. The PAM validates before accepting the code.
2. Wynta returns `valid` with either the bonus preview (`promo_id`, `display_title`, `wager_multiplier`, `no_of_chunks`) or a human-readable `reason` when `valid` is `false`.
3. On success the PAM attaches the code to the player's flow (e.g., the deposit in progress) and can show the wagering terms up front; on failure it surfaces `reason` directly.

Validation is **read-only** — no grant, no wallet change, no webhook. A code that validates now can still fail at grant time (budget exhausted in the interim, frequency consumed on another device) — the grant-time evaluation is authoritative.

## Flow 3 — Release trigger event → bonus grant (events → Wynta → PAM)

**The grant is created by the event trigger, not by any API call from the code flow.** When a qualifying [PAM event](/bonus/api-reference/bonus-events.md) arrives — `deposit` (with `is_ftd` for first-deposit rules), `registration`, `tournament_won`, `friend_signup`, … — Wynta evaluates it against the configured release triggers, resolved via the promo code:

1. **Trigger match** — event type, `occurrence` (e.g., `1` = first deposit only), `min/max_trigger_amount`, `payment_method`, `product`, `trigger_config_json` conditions
2. **Eligibility criteria** — all AND-ed rows must pass
3. **Applicability frequency** — `EVERYTIME` / `ONCE` / `WEEKLY` / `MONTHLY` per player
4. **Budget caps** — atomically checked at Configure → Subhead → Head levels

On approval, Wynta computes the grant amount (`bonus_amount_fixed`, or `bonus_amount_percent` of the event amount capped by `bonus_amount_max`), splits it into `no_of_chunks` chunks — all **`PENDING`** — writes the `grant` ledger entry, and emits the **`BONUS_GRANTED`** webhook. **The PAM updates its client wallet from the webhook**, incrementing **Pending**.

`system_auto_apply` codes are granted the same way without any player code entry.

**Failure handling:** if the trigger conditions, eligibility, frequency, or budget checks fail, no grant is created — no ledger entry, no webhook, no wallet change.

## Flow 4 — Release delivers the spendable bonus

Chunks then move `PENDING → RELEASE` through further trigger events and wagering progress, each emitting `BONUS_RELEASED` and moving value **Pending → Available** in the client wallet — see [Wager-Based Chunk Release](/bonus/flows/wager-release.md).

{% hint style="warning" %}
Budget checks and the grant ledger write are atomic in Wynta — a cap breach can never leak a grant. The PAM's wallet is updated **only** by webhooks: `BONUS_GRANTED` for pending value, `BONUS_RELEASED` for spendable value.
{% endhint %}
