> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Incentives: catalog, ledger, and fulfillment

> Issue one-off rewards and support credits through the promotions API: the reward-type catalog and provider picker, the event-sourced incentive ledger, the fulfillment engine behind referrals, surveys, and loyalty redemption, and how issuance connects to Wallet Passes.

# Incentives

Incentives is the rewards primitive behind every "we owe this person something" moment in Orbit: a referral hits its reward step, a survey respondent earns a thank-you, a loyalty redemption pays out, or your support team grants a one-off credit. Direct API access (`POST /incentives/issue`, plus list, redeem, and void) works like a standalone promotions API you can drive for any trigger: win-back promos, goodwill credits, campaign prizes.

The same engine powers the Incentives screen in the dashboard's Outbound hub, where operators inspect the issued-incentive ledger, redeem a reward, or void one.

## Incentive types

Every issuance names a **reward type** (`reward_type`). Four types exist:

| Reward type     | What the recipient gets                                    | Who fulfills it                                                                                             |
| --------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `credit`        | Orbit balance credit applied to the tenant billing account | The billing ledger owns this; the incentive engine refuses to double-pay it                                 |
| `discount_code` | A unique, 12-character redeemable code minted by Orbit     | Orbit, instantly. No third-party account needed                                                             |
| `gift_card`     | A gift card in a fixed amount (USD, EUR, GBP, CAD, AUD)    | An external gift-card network, after you connect its API credentials                                        |
| `custom`        | Anything else: a perk, a physical item, a service credit   | You. Orbit records a structured payout with status `manual` and your webhook or operations team fulfills it |

**Providers** are the fulfillment targets a reward can route to. `GET /incentives/providers` returns the catalog, and the dashboard reward-source picker renders it. Providers fall into two kinds:

* **Internal** (always available): `orbit_code` mints discount codes; `orbit_manual` records a custom payout for you to fulfill.
* **External** (gift-card networks such as Tremendous or Tango Card): these appear in the catalog as descriptors with `configured: false` until you connect the provider's API credentials in the dashboard. Before that, an issuance targeting one is recorded with status `manual` and reason `provider_not_configured` rather than calling the external API.

Pin a provider explicitly with `provider_id`, or omit it and Orbit picks the default for the reward type, preferring a configured provider. A provider can only fulfil the reward types it lists: you cannot mint a discount code through a gift-card network.

## Ledger accounting

Issuance, redemption, and voiding are events on an append-only ledger, not rows you mutate. Each incentive issues exactly one record; the events that follow (`incentive.issued`, then optionally `incentive.redeemed` or `incentive.voided`) fold into the incentive's current state. The lifecycle is short: **issued** is the only open state; **redeemed** and **voided** are terminal. Nothing can move out of a terminal state.

This ledger lives inside your tenant and answers the question "what did we hand out, to whom, and where did it end up" for audits and support reviews. `GET /incentives/issued` reads it, with filters for `status`, `source`, `reward_type`, and `contact_id`.

The ledger tracks what you issued; it is separate from your wallet budget. An incentive is a record of a promised reward, not a pre-funded pool. Balance credits flow through the tenant billing ledger on their own rails, so an incentive cannot silently charge your account twice: `credit` rewards are refused by the incentive engine and handled by billing instead.

## Fulfillment flow and redemption semantics

Issuing an incentive runs the shared fulfillment engine:

1. **Route.** Resolve the provider (your pin, or the reward type's default) and check it supports the reward type.
2. **Fulfil.** A `discount_code` resolves immediately to status `issued` with the minted code in the response. A `custom` reward, or any gift card on an unconnected provider, resolves to status `manual` with a machine-readable `reason` (`awaiting_tenant_fulfillment` or `provider_not_configured`), so a downstream webhook or operations queue picks it up. Statuses `pending`, `delivered`, and `failed` model the asynchronous lifecycle a connected gift-card network drives through provider callbacks.

**Retry and idempotency.** Send an `Idempotency-Key` header (or an `idempotency_key` body field) on `POST /incentives/issue`. A retry carrying the same key replays the original incentive with its current lifecycle state instead of minting a second reward, and the response marks `replayed: true`. Concurrent submissions of the same key serialise, so one incentive issues even under a bursty retry storm. Only issue accepts an idempotency key: redeem and void are naturally idempotent because a terminal-state incentive returns a conflict.

**Redemption.** `POST /incentives/:id/redeem` consumes an issued incentive (with an optional external `reference`, such as the order the code was applied to) and `POST /incentives/:id/void` cancels it with a reason. Both transitions are guarded by the state machine: redeeming an already-redeemed incentive, or voiding a redeemed one, returns `409` with the current lifecycle status. Concurrent redeem and void calls on the same incentive serialise; exactly one of them wins.

## Where incentives enter the flow

Three product surfaces call the same fulfillment engine server-side, so a reward earned anywhere resolves through one tracked path:

* **Referrals** — when a referral rewards a discount code, gift card, or custom perk instead of balance credit, the referral flow issues it through the engine.
* **Surveys** — respondent thank-you rewards fulfil through the engine when the survey completes.
* **Loyalty redemption** — spending loyalty points on a reward routes through the engine.

Direct API issuance (`POST /incentives/issue`) is the fourth source, tagged `api`. Every incentive records which source created it, and you can filter the ledger by `source` to audit one surface at a time.

## Issue an incentive

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/incentives/issue \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Idempotency-Key: support-credit-ticket-4812" \
  -H "Content-Type: application/json" \
  -d '{
    "reward_type": "discount_code",
    "source_ref": "ticket-4812",
    "recipient": { "contact_id": "cnt_9f8a7b6c5d4e3f2a1b0c" },
    "amount": 15,
    "metadata": { "campaign": "winback-q3" }
  }'
```

Issue a gift card through a connected provider by pinning `provider_id` (for example `"tremendous"`) and sending `amount` in minor units (cents) with an ISO-4217 `currency`. The minted code appears on the response as `data.code`; redeem it later with `POST /incentives/{incentive_id}/redeem`.

Wallet balance credits are a separate primitive: issue them through the wallet API, not `POST /incentives/issue`. See [Billing overview](/billing/overview).

## Relationship to Wallet Passes

[Wallet Passes](/channels/wallet-passes) are the carrier for loyalty cards: the pass in Apple Wallet or Google Wallet holds the customer's points balance and tier. When a customer redeems points against a loyalty card, that redemption triggers incentive issuance through the same engine described here, and the resulting reward (a code, a gift card, a custom perk) is what the customer actually receives. Wallet Passes carry the program; incentives pay out what the program owes.

## Related reading

* [Wallet Passes](/channels/wallet-passes) — loyalty cards and pass distribution.
* [Billing overview](/billing/overview) — wallet balances and balance credits.
* [Campaigns end to end](/guides/campaign-end-to-end) — outbound campaign setup that can trigger referral and survey rewards.
