Rewards
REST API reference for rewards
This reference is generated from the Invitebase OpenAPI contract.
What is owed once a referral is validated, and its fulfillment.
List rewards
Authentication
Authorization: Bearer <secret key>.
Parameters
| Name | In | Required | Schema | Description |
|---|---|---|---|---|
limit | query | No | {"type":"integer","minimum":1,"maximum":100,"default":25} | |
starting_after | query | No | {"type":"string"} | A cursor (object id) for pagination; returns the page after this object. |
status | query | No | {"$ref":"#/components/schemas/RewardStatus"} | |
referral_id | query | No | {"type":"string"} | Only rewards issued for this referral. |
campaign_id | query | No | {"type":"string"} | Only rewards issued under this campaign. |
referrer_id | query | No | {"type":"string"} | Only rewards whose referral belongs to this referrer. |
Responses
200
A paginated list of rewards.
application/json schema:
{
"allOf": [
{
"$ref": "#/components/schemas/ListResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Reward"
}
}
}
}
]
}400
The request was malformed or invalid.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}401
Missing or invalid API key.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}403
The API key is valid but is not permitted to call this endpoint.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}429
Too many requests.
Response headers:
{
"Retry-After": {
"description": "Seconds until the caller may retry.",
"schema": {
"type": "integer",
"minimum": 1
}
}
}application/json schema:
{
"$ref": "#/components/schemas/Error"
}Retrieve a reward
Authentication
Authorization: Bearer <secret key>.
Parameters
| Name | In | Required | Schema | Description |
|---|---|---|---|---|
rewardId | path | Yes | {"type":"string"} |
Responses
200
The reward and its payout details.
application/json schema:
{
"$ref": "#/components/schemas/Reward"
}401
Missing or invalid API key.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}403
The API key is valid but is not permitted to call this endpoint.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}404
The requested resource does not exist.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}429
Too many requests.
Response headers:
{
"Retry-After": {
"description": "Seconds until the caller may retry.",
"schema": {
"type": "integer",
"minimum": 1
}
}
}application/json schema:
{
"$ref": "#/components/schemas/Error"
}Mark a reward fulfilled
Acknowledge fulfillment of an app-grant reward. When the customer's backend receives a reward.pending webhook and grants the entitlement in its own system, it acks with this endpoint: the reward moves to fulfilled, delivery retries stop, and a reward.fulfilled event fires. Idempotent — repeating the call returns the same result. Money-rail rewards are fulfilled by the payout provider and do not use this endpoint.
Authentication
Authorization: Bearer <secret key>.
Parameters
| Name | In | Required | Schema | Description |
|---|---|---|---|---|
rewardId | path | Yes | {"type":"string"} | |
Idempotency-Key | header | No | {"type":"string"} | A unique key for one logical mutation. The same key and request replay the original result for 24 hours; using the key with a different request returns 409. |
Responses
200
Reward marked fulfilled.
application/json schema:
{
"$ref": "#/components/schemas/Reward"
}401
Missing or invalid API key.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}403
The API key is valid but is not permitted to call this endpoint.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}404
The requested resource does not exist.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}409
The request conflicts with the resource's current state.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}429
Too many requests.
Response headers:
{
"Retry-After": {
"description": "Seconds until the caller may retry.",
"schema": {
"type": "integer",
"minimum": 1
}
}
}application/json schema:
{
"$ref": "#/components/schemas/Error"
}Claim a platform-compatible offer code
Server-side delivery for a validated offer-code reward. Your backend verifies the recipient, supplies their external id and platform, then receives the one code reserved for this reward. Referral-link visits alone never reveal a code, and codes never fall back across platforms.
Authentication
Authorization: Bearer <secret key>.
Parameters
| Name | In | Required | Schema | Description |
|---|---|---|---|---|
rewardId | path | Yes | {"type":"string"} | |
Idempotency-Key | header | No | {"type":"string"} | A unique key for one logical mutation. The same key and request replay the original result for 24 hours; using the key with a different request returns 409. |
Request body
Required.
application/json schema:
{
"$ref": "#/components/schemas/OfferCodeClaimRequest"
}Responses
200
The code reserved for this reward. Treat this response as sensitive.
application/json schema:
{
"$ref": "#/components/schemas/OfferCodeDelivery"
}400
The request was malformed or invalid.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}401
Missing or invalid API key.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}403
The API key is valid but is not permitted to call this endpoint.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}404
The requested resource does not exist.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}409
The request conflicts with the resource's current state.
application/json schema:
{
"$ref": "#/components/schemas/Error"
}429
Too many requests.
Response headers:
{
"Retry-After": {
"description": "Seconds until the caller may retry.",
"schema": {
"type": "integer",
"minimum": 1
}
}
}application/json schema:
{
"$ref": "#/components/schemas/Error"
}Schemas
Schema references below resolve against these definitions. Required fields, enums, bounds, and composed types are preserved from the contract.
The RewardStatus object
Full schema:
{
"type": "string",
"enum": [
"pending",
"held_for_review",
"approved",
"fulfilled",
"failed",
"rejected"
]
}The ListResponse object
| Field | Type | Required | Description |
|---|---|---|---|
object | string | Yes | |
has_more | boolean | Yes | |
data | array | Yes |
Full schema:
{
"type": "object",
"required": [
"object",
"data",
"has_more"
],
"properties": {
"object": {
"type": "string",
"const": "list"
},
"has_more": {
"type": "boolean"
},
"data": {
"type": "array",
"items": {}
}
}
}The Reward object
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | |
object | string | Yes | |
status | RewardStatus | Yes | |
referral_id | string | Yes | |
campaign_id | string | No | |
recipient | string | No | |
config | RewardConfig | No | How one recipient of a validated referral is rewarded. A campaign's reward is an array of these, one per recipient. Validated at write time: unknown fields are rejected, money methods require amount + currency, free_access requires free_access_duration, and money rewards must be included in the account's plan (otherwise 400 reward_not_in_plan). Delivery is separate from method: the same free_access reward can arrive over your webhook or as a code, without changing what the recipient is promised. |
payout | Payout | No | The actual disbursement or app grant. |
mode | Mode | No | Whether the object exists in test or live mode (determined by the API key). |
livemode | boolean | Yes | |
created_at | string | Yes |
Full schema:
{
"type": "object",
"required": [
"id",
"object",
"status",
"referral_id",
"livemode",
"created_at"
],
"properties": {
"id": {
"type": "string",
"example": "rwd_123"
},
"object": {
"type": "string",
"const": "reward"
},
"status": {
"$ref": "#/components/schemas/RewardStatus"
},
"referral_id": {
"type": "string"
},
"campaign_id": {
"type": "string"
},
"recipient": {
"type": "string",
"enum": [
"referrer",
"referred_user"
]
},
"config": {
"$ref": "#/components/schemas/RewardConfig"
},
"payout": {
"$ref": "#/components/schemas/Payout"
},
"mode": {
"$ref": "#/components/schemas/Mode"
},
"livemode": {
"type": "boolean"
},
"created_at": {
"type": "string",
"format": "date-time"
}
}
}Reward statuses
| Status | Meaning |
|---|---|
pending | Created on validation, awaiting fulfillment. For app grants this is the acting state: reward.pending fires and your backend confirms the grant. |
held_for_review | Held back from fulfillment, and blocked from being fulfilled until it is approved. Fires reward.held_for_review. |
approved | Queued for fulfillment once any hold window elapses. |
fulfilled | Delivered — app grants when your backend confirms the grant; payouts when the provider completes. |
failed | Payout fulfillment failed (money rewards only, e.g. payout error). App grants cannot fail. |
rejected | Flagged with its referral by the AI fraud check, or clawed back inside the hold window. Not paid or billed unless the referral is unblocked. |
The RewardConfig object
How one recipient of a validated referral is rewarded. A campaign's reward is an array of these, one per recipient. Validated at write time: unknown fields are rejected, money methods require amount + currency, free_access requires free_access_duration, and money rewards must be included in the account's plan (otherwise 400 reward_not_in_plan). Delivery is separate from method: the same free_access reward can arrive over your webhook or as a code, without changing what the recipient is promised.
| Field | Type | Required | Description |
|---|---|---|---|
method | string | Yes | What the recipient gets — never how it reaches them, which is delivery. in_app and free_access are app grants with no money movement. The rest are money rewards paid through our payout partner, drawn from the prefunded balance: a store gift_card, a prepaid_visa card, a charity donation, or cash (see cash_methods). monetary lets the recipient choose among categories at claim time. Plans gate categories: Indie offers gift_card and charity; prepaid_visa and cash need Growth or Enterprise, which offer all four. The former single-rail methods paypal, venmo and ach are rejected — use cash with cash_methods. |
categories | array | No | monetary only. The categories the recipient may choose from. Omit it to offer every category your plan includes; the stored campaign shows the resolved list. |
cash_methods | array | No | For cash, or monetary offering cash. The cash options the recipient may pick: PayPal, Venmo, Cash App, bank transfer, or debit card. Omit it to offer every cash option your plan includes. |
recipient | string | Yes | Who this entry rewards. Add one configuration per side to make a campaign double-sided. |
amount | integer | No | Value in smallest currency unit (for money methods) or app-defined units. |
currency | Currency | No | ISO 4217 currency code (lowercase), e.g. "usd". |
free_access_duration | object | No | Required for method = free_access. The term your referral pages advertise — e.g. { "count": 3, "unit": "month" }. For code deliveries this is the advertised term only: the enforced one is baked into the code you supply, so generate codes that match. |
delivery | string | No | For method = free_access — how the grant reaches the recipient. webhook (the default) calls your backend over the signed reward webhook. manual, api, and app_store_connect hand over a code from campaign inventory, and an active campaign using one of them requires stocked inventory. revenuecat grants the entitlement through your RevenueCat project. |
in_app_payload | object | No | For method = in_app — what to grant (e.g. grant the gold skin). |
milestone_threshold | integer | No | Reward only after the referrer reaches N validated referrals (e.g. 5). |
cap_per_referrer | integer | No | Max rewards per referrer (fraud control). |
cap_per_month | integer | No | Max rewards per campaign per month (fraud control). |
expires_in_days | integer | No |
Full schema:
{
"type": "object",
"required": [
"method",
"recipient"
],
"additionalProperties": false,
"description": "How one recipient of a validated referral is rewarded. A campaign's `reward` is an array of these, one per recipient. Validated at write time: unknown fields are rejected, money methods require `amount` + `currency`, `free_access` requires `free_access_duration`, and money rewards must be included in the account's plan (otherwise 400 `reward_not_in_plan`). Delivery is separate from method: the same `free_access` reward can arrive over your webhook or as a code, without changing what the recipient is promised.\n",
"properties": {
"method": {
"type": "string",
"enum": [
"in_app",
"free_access",
"monetary",
"gift_card",
"prepaid_visa",
"charity",
"cash"
],
"description": "What the recipient gets — never how it reaches them, which is `delivery`. `in_app` and `free_access` are app grants with no money movement. The rest are money rewards paid through our payout partner, drawn from the prefunded balance: a store `gift_card`, a `prepaid_visa` card, a `charity` donation, or `cash` (see `cash_methods`). `monetary` lets the recipient choose among `categories` at claim time. Plans gate categories: Indie offers `gift_card` and `charity`; `prepaid_visa` and `cash` need Growth or Enterprise, which offer all four. The former single-rail methods `paypal`, `venmo` and `ach` are rejected — use `cash` with `cash_methods`.\n"
},
"categories": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"$ref": "#/components/schemas/RewardCategory"
},
"description": "`monetary` only. The categories the recipient may choose from. Omit it to offer every category your plan includes; the stored campaign shows the resolved list.\n"
},
"cash_methods": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"$ref": "#/components/schemas/CashMethod"
},
"description": "For `cash`, or `monetary` offering `cash`. The cash options the recipient may pick: PayPal, Venmo, Cash App, bank transfer, or debit card. Omit it to offer every cash option your plan includes.\n"
},
"recipient": {
"type": "string",
"enum": [
"referrer",
"referred_user"
],
"description": "Who this entry rewards. Add one configuration per side to make a campaign double-sided.\n"
},
"amount": {
"type": "integer",
"description": "Value in smallest currency unit (for money methods) or app-defined units."
},
"currency": {
"$ref": "#/components/schemas/Currency"
},
"free_access_duration": {
"type": "object",
"required": [
"count",
"unit"
],
"additionalProperties": false,
"description": "Required for method = free_access. The term your referral pages advertise — e.g. `{ \"count\": 3, \"unit\": \"month\" }`. For code deliveries this is the advertised term only: the enforced one is baked into the code you supply, so generate codes that match.\n",
"properties": {
"count": {
"type": "integer",
"minimum": 1,
"maximum": 120
},
"unit": {
"type": "string",
"enum": [
"day",
"week",
"month"
]
}
}
},
"delivery": {
"type": "string",
"enum": [
"webhook",
"manual",
"api",
"app_store_connect",
"revenuecat"
],
"default": "webhook",
"description": "For method = free_access — how the grant reaches the recipient. `webhook` (the default) calls your backend over the signed reward webhook. `manual`, `api`, and `app_store_connect` hand over a code from campaign inventory, and an active campaign using one of them requires stocked inventory. `revenuecat` grants the entitlement through your RevenueCat project.\n"
},
"in_app_payload": {
"type": "object",
"additionalProperties": true,
"description": "For method = in_app — what to grant (e.g. grant the gold skin)."
},
"milestone_threshold": {
"type": "integer",
"description": "Reward only after the referrer reaches N validated referrals (e.g. 5)."
},
"cap_per_referrer": {
"type": "integer",
"description": "Max rewards per referrer (fraud control)."
},
"cap_per_month": {
"type": "integer",
"description": "Max rewards per campaign per month (fraud control)."
},
"expires_in_days": {
"type": "integer"
}
}
}The RewardCategory object
A kind of money reward. Each is a product offered by our payout partner.
Full schema:
{
"type": "string",
"description": "A kind of money reward. Each is a product offered by our payout partner.",
"enum": [
"gift_card",
"prepaid_visa",
"charity",
"cash"
]
}The CashMethod object
How a cash reward reaches the recipient, through our payout partner: paypal, venmo, cash_app, bank (bank transfer), or debit (debit card).
Full schema:
{
"type": "string",
"description": "How a cash reward reaches the recipient, through our payout partner: `paypal`, `venmo`, `cash_app`, `bank` (bank transfer), or `debit` (debit card).\n",
"enum": [
"paypal",
"venmo",
"cash_app",
"bank",
"debit"
]
}The Currency object
ISO 4217 currency code (lowercase), e.g. "usd".
Full schema:
{
"type": "string",
"description": "ISO 4217 currency code (lowercase), e.g. \"usd\".",
"example": "usd"
}The Payout object
The actual disbursement or app grant.
| Field | Type | Required | Description |
|---|---|---|---|
method | string | No | The reward's method. Campaigns stored before cash became a category may still report the retired paypal, venmo or ach. |
provider | string | No | Identifies the app grant or money payout provider. |
provider_reference | string | No | External id (payout partner order id or webhook delivery id). |
status | string | No | |
amount | integer | No | |
currency | Currency | No | ISO 4217 currency code (lowercase), e.g. "usd". |
Full schema:
{
"type": "object",
"description": "The actual disbursement or app grant.",
"properties": {
"method": {
"type": "string",
"description": "The reward's method. Campaigns stored before cash became a category may still report the retired `paypal`, `venmo` or `ach`.\n",
"enum": [
"in_app",
"free_access",
"monetary",
"gift_card",
"prepaid_visa",
"charity",
"cash",
"paypal",
"venmo",
"ach"
]
},
"provider": {
"type": "string",
"enum": [
"webhook",
"tremendous"
],
"description": "Identifies the app grant or money payout provider."
},
"provider_reference": {
"type": "string",
"description": "External id (payout partner order id or webhook delivery id)."
},
"status": {
"type": "string",
"enum": [
"pending",
"sent",
"delivered",
"failed"
]
},
"amount": {
"type": "integer"
},
"currency": {
"$ref": "#/components/schemas/Currency"
}
}
}The Mode object
Whether the object exists in test or live mode (determined by the API key).
Full schema:
{
"type": "string",
"enum": [
"test",
"live"
],
"description": "Whether the object exists in test or live mode (determined by the API key)."
}The Error object
| Field | Type | Required | Description |
|---|---|---|---|
error | object | Yes |
Full schema:
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"type",
"code",
"message",
"doc_url"
],
"properties": {
"type": {
"type": "string",
"enum": [
"invalid_request_error",
"authentication_error",
"rate_limit_error",
"api_error"
]
},
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"param": {
"type": "string"
},
"doc_url": {
"type": "string",
"format": "uri"
}
}
}
}
}The OfferCodeClaimRequest object
| Field | Type | Required | Description |
|---|---|---|---|
platform | string | Yes | The recipient's actual redemption platform. No fallback occurs. |
recipient_external_id | string | Yes | The recipient identity your authenticated backend has verified. |
Full schema:
{
"type": "object",
"required": [
"platform",
"recipient_external_id"
],
"additionalProperties": false,
"properties": {
"platform": {
"type": "string",
"enum": [
"ios",
"android",
"web",
"custom"
],
"description": "The recipient's actual redemption platform. No fallback occurs."
},
"recipient_external_id": {
"type": "string",
"maxLength": 512,
"description": "The recipient identity your authenticated backend has verified."
}
}
}The OfferCodeDelivery object
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The associated reward id. |
object | string | Yes | |
reward_id | string | Yes | |
recipient | string | Yes | |
platform | string | Yes | |
code | string | Yes | Sensitive one-time assigned offer code. Do not log it. |
redemption_url | string or null | No | |
expires_at | string or null | No | |
livemode | boolean | Yes |
Full schema:
{
"type": "object",
"required": [
"id",
"object",
"reward_id",
"recipient",
"platform",
"code",
"livemode"
],
"properties": {
"id": {
"type": "string",
"description": "The associated reward id."
},
"object": {
"type": "string",
"const": "offer_code_delivery"
},
"reward_id": {
"type": "string"
},
"recipient": {
"type": "string",
"enum": [
"referrer",
"referred_user"
]
},
"platform": {
"type": "string",
"enum": [
"ios",
"android",
"web",
"custom"
]
},
"code": {
"type": "string",
"description": "Sensitive one-time assigned offer code. Do not log it."
},
"redemption_url": {
"type": [
"string",
"null"
],
"format": "uri"
},
"expires_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"livemode": {
"type": "boolean"
}
}
}