Fraud
REST API reference for fraud
This reference is generated from the Invitebase OpenAPI contract.
The automatic fraud outcome for each referral, the evidence behind it, and your override of it. Every referral gets an AI fraud decision when it validates. The decision is not final: you can review a flagged referral and override it to not-fraud, which pays it out through the normal path, or override every flagged referral of one end user at once.
List fraud decisions
Every referral's fraud outcome, newest decision first. Every referral gets an AI fraud decision, approved or rejected, on the pass that validates it. There's no queue and no waiting state. status adds your side: a rejected decision is flagged until you override it, then overridden.
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. |
decision | query | No | {"$ref":"#/components/schemas/FraudDecision"} | |
status | query | No | {"$ref":"#/components/schemas/FraudStatus"} |
Responses
200
A paginated list of fraud decisions.
application/json schema:
{
"allOf": [
{
"$ref": "#/components/schemas/ListResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/FraudDecisionRecord"
}
}
}
}
]
}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"
}Override a flagged fraud decision
Mark a flagged (rejected) referral as not fraud and pay it out. The referral returns to validated, the rewards the fraud flag rejected become approved and go to fulfillment like any other approved reward, and the referral is billed again. The original AI decision (decision, reason_code, signals, decided_at) is kept unchanged; override records who overrode it and when, and a fraud.decision.overridden audit event is written. Called with your secret key, the actor is that key (api_key). An unblock from the Invitebase dashboard is recorded as the signed-in team member who clicked it (user). Idempotent — overriding an already-overridden decision returns it unchanged and pays nothing twice. Only the account that owns the referral can override it; any other key gets a 404.
The override commits before its payouts are queued, so payout_queue says whether they were. If queueing fails, the override still stands, the reward stays approved with status_reason payout_enqueue_failed, its id is listed in payout_queue.failed_reward_ids, and calling the override again queues it again.
Only a referral rejected for fraud can be overridden: the decision names a fraud rule (blocklist_match, payout_destination_match or velocity_limit) and the referral is still rejected after it validated. A referral rejected for any other reason returns 409 referral_not_rejected_for_fraud and nothing changes. An approved decision returns 409 fraud_decision_not_flagged.
Authentication
Authorization: Bearer <secret key>.
Parameters
| Name | In | Required | Schema | Description |
|---|---|---|---|---|
decisionId | 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
Optional.
application/json schema:
{
"$ref": "#/components/schemas/FraudOverrideCreate"
}Responses
200
The overridden fraud decision, plus payout_queue: whether the payouts it released were queued.
application/json schema:
{
"allOf": [
{
"$ref": "#/components/schemas/FraudDecisionRecord"
},
{
"type": "object",
"required": [
"payout_queue"
],
"properties": {
"payout_queue": {
"$ref": "#/components/schemas/FraudOverridePayoutQueue"
}
}
}
]
}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"
}Override every flagged fraud decision for one end user
Override all of this referrer's still-flagged referrals at once, with the same effect as overriding each one. Returns the decisions this call overrode. A flagged referral that was not rejected for fraud is skipped, left unchanged and listed in skipped; the counts say how many were overridden and how many were skipped. Idempotent — a repeat overrides nothing new and returns an empty data list, but re-queues any payout an earlier call could not queue (see payout_queue).
Authentication
Authorization: Bearer <secret key>.
Parameters
| Name | In | Required | Schema | Description |
|---|---|---|---|---|
referrerId | 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
Optional.
application/json schema:
{
"$ref": "#/components/schemas/FraudOverrideCreate"
}Responses
200
The decisions this call overrode.
application/json schema:
{
"type": "object",
"required": [
"object",
"data",
"has_more",
"overridden_count",
"skipped_count",
"skipped",
"payout_queue"
],
"properties": {
"object": {
"type": "string",
"const": "list"
},
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/FraudDecisionRecord"
}
},
"has_more": {
"type": "boolean",
"const": false
},
"overridden_count": {
"type": "integer",
"description": "How many decisions this call overrode (the length of `data`)."
},
"skipped_count": {
"type": "integer",
"description": "How many flagged decisions were skipped because the referral was not rejected for fraud."
},
"skipped": {
"type": "array",
"description": "The flagged decisions this call skipped and why.",
"items": {
"type": "object",
"required": [
"decision_id",
"referral_id",
"code"
],
"properties": {
"decision_id": {
"type": "string"
},
"referral_id": {
"type": "string"
},
"code": {
"type": "string",
"const": "referral_not_rejected_for_fraud"
}
}
}
},
"payout_queue": {
"$ref": "#/components/schemas/FraudOverridePayoutQueue"
}
}
}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"
}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 the payout-destination dedup threshold
Authentication
Authorization: Bearer <secret key>.
Responses
200
The number of referrer accounts sharing a destination that rejects a referral.
application/json schema:
{
"$ref": "#/components/schemas/PayoutDestinationControl"
}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"
}Set the payout-destination dedup threshold
A referral is rejected when its referrer's matching destination is used by this many referrer accounts in the same app and mode. The default is 2.
Authentication
Authorization: Bearer <secret key>.
Parameters
| Name | In | Required | Schema | Description |
|---|---|---|---|---|
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/PayoutDestinationControlUpdate"
}Responses
200
The stored control.
application/json schema:
{
"$ref": "#/components/schemas/PayoutDestinationControl"
}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 referral's fraud decision and evidence
Everything the system knows about one referral, so an automatic rejection is never a black box and you can decide whether to override it: the decision and the signals it was made on, the campaign's criteria, the referrer's standing (tenure, referrals that stuck, prior rejections), the velocity around the referral, the rewards at stake, and the immutable gate evaluation that validated it.
Authentication
Authorization: Bearer <secret key>.
Parameters
| Name | In | Required | Schema | Description |
|---|---|---|---|---|
referralId | path | Yes | {"type":"string"} |
Responses
200
The referral's fraud decision and evidence.
application/json schema:
{
"$ref": "#/components/schemas/ReferralFraudDecision"
}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"
}Schemas
Schema references below resolve against these definitions. Required fields, enums, bounds, and composed types are preserved from the contract.
The FraudDecision object
The AI fraud check's decision, made when the referral validates. There's no waiting state. It is not final: you can override a rejected decision, and it is kept as-is when you do (see FraudStatus).
Full schema:
{
"type": "string",
"description": "The AI fraud check's decision, made when the referral validates. There's no waiting state. It is not final: you can override a `rejected` decision, and it is kept as-is when you do (see `FraudStatus`).\n",
"enum": [
"approved",
"rejected"
]
}The FraudStatus object
Where a referral stands with fraud. approved: the AI approved it. flagged: the AI rejected it and nobody has overridden that; it is not paid or billed. overridden: you overrode the flag, so it pays out.
Full schema:
{
"type": "string",
"description": "Where a referral stands with fraud. `approved`: the AI approved it. `flagged`: the AI rejected it and nobody has overridden that; it is not paid or billed. `overridden`: you overrode the flag, so it pays out.\n",
"enum": [
"approved",
"flagged",
"overridden"
]
}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 FraudDecisionRecord object
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | |
object | string | Yes | |
referral_id | string | Yes | |
decision | FraudDecision | Yes | The AI fraud check's decision, made when the referral validates. There's no waiting state. It is not final: you can override a rejected decision, and it is kept as-is when you do (see FraudStatus). |
status | FraudStatus | Yes | Where a referral stands with fraud. approved: the AI approved it. flagged: the AI rejected it and nobody has overridden that; it is not paid or billed. overridden: you overrode the flag, so it pays out. |
override | object or null | Yes | Set once you override a flagged decision. decision, reason_code, signals and decided_at still describe the original AI decision. |
reason_code | FraudReasonCode | No | Why the engine decided as it did. Machine-readable because these are also the labels the AI fraud model trains on. |
signals | array | No | The signals the engine weighed, as they stood when it decided. |
decided_at | string | Yes | |
livemode | boolean | Yes | |
created_at | string | Yes |
Full schema:
{
"type": "object",
"required": [
"id",
"object",
"referral_id",
"decision",
"status",
"decided_at",
"override",
"livemode",
"created_at"
],
"properties": {
"id": {
"type": "string",
"example": "fdc_123"
},
"object": {
"type": "string",
"const": "fraud_decision"
},
"referral_id": {
"type": "string"
},
"decision": {
"$ref": "#/components/schemas/FraudDecision"
},
"status": {
"$ref": "#/components/schemas/FraudStatus"
},
"override": {
"type": [
"object",
"null"
],
"description": "Set once you override a flagged decision. `decision`, `reason_code`, `signals` and `decided_at` still describe the original AI decision.\n",
"required": [
"overridden_at",
"actor",
"note"
],
"properties": {
"overridden_at": {
"type": "string",
"format": "date-time"
},
"actor": {
"type": "object",
"required": [
"type",
"id"
],
"description": "Who overrode it: `api_key` (with the key's id) when called through the API, or `user` (with the team member's id) when unblocked from the Invitebase dashboard.\n",
"properties": {
"type": {
"type": "string",
"enum": [
"user",
"api_key",
"system"
]
},
"id": {
"type": [
"string",
"null"
]
}
}
},
"note": {
"type": [
"string",
"null"
]
}
}
},
"reason_code": {
"$ref": "#/components/schemas/FraudReasonCode"
},
"signals": {
"type": "array",
"description": "The signals the engine weighed, as they stood when it decided.",
"items": {
"type": "object",
"additionalProperties": true
}
},
"decided_at": {
"type": "string",
"format": "date-time"
},
"livemode": {
"type": "boolean"
},
"created_at": {
"type": "string",
"format": "date-time"
}
}
}The FraudReasonCode object
Why the engine decided as it did. Machine-readable because these are also the labels the AI fraud model trains on.
Full schema:
{
"type": "string",
"description": "Why the engine decided as it did. Machine-readable because these are also the labels the AI fraud model trains on.\n",
"enum": [
"criteria_met",
"blocklist_match",
"payout_destination_match",
"velocity_limit"
]
}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 FraudOverrideCreate object
| Field | Type | Required | Description |
|---|---|---|---|
note | string | No | Optional reason for the override, kept with it and in the audit log. |
Full schema:
{
"type": "object",
"properties": {
"note": {
"type": "string",
"maxLength": 500,
"description": "Optional reason for the override, kept with it and in the audit log."
}
}
}The FraudOverridePayoutQueue object
Whether the payouts an override released were queued for fulfillment. queued: all of them. failed / partially_failed: some were not; each such reward stays approved with status_reason payout_enqueue_failed and is queued again when you repeat the override. nothing_to_queue: the call released no payouts.
| Field | Type | Required | Description |
|---|---|---|---|
status | string | Yes | |
queued_reward_ids | array | Yes | |
failed_reward_ids | array | Yes |
Full schema:
{
"type": "object",
"description": "Whether the payouts an override released were queued for fulfillment. `queued`: all of them. `failed` / `partially_failed`: some were not; each such reward stays `approved` with `status_reason` `payout_enqueue_failed` and is queued again when you repeat the override. `nothing_to_queue`: the call released no payouts.\n",
"required": [
"status",
"queued_reward_ids",
"failed_reward_ids"
],
"properties": {
"status": {
"type": "string",
"enum": [
"queued",
"partially_failed",
"failed",
"nothing_to_queue"
]
},
"queued_reward_ids": {
"type": "array",
"items": {
"type": "string"
}
},
"failed_reward_ids": {
"type": "array",
"items": {
"type": "string"
}
}
}
}The PayoutDestinationControl object
| Field | Type | Required | Description |
|---|---|---|---|
object | string | Yes | |
referrer_threshold | integer | Yes | |
livemode | boolean | Yes |
Full schema:
{
"type": "object",
"required": [
"object",
"referrer_threshold",
"livemode"
],
"properties": {
"object": {
"type": "string",
"const": "payout_destination_control"
},
"referrer_threshold": {
"type": "integer",
"minimum": 2,
"maximum": 1000
},
"livemode": {
"type": "boolean"
}
}
}The PayoutDestinationControlUpdate object
| Field | Type | Required | Description |
|---|---|---|---|
referrer_threshold | integer | Yes |
Full schema:
{
"type": "object",
"required": [
"referrer_threshold"
],
"properties": {
"referrer_threshold": {
"type": "integer",
"minimum": 2,
"maximum": 1000
}
}
}The ReferralFraudDecision object
| Field | Type | Required | Description |
|---|---|---|---|
object | string | Yes | |
referral | Referral | Yes | |
decision | composed | No | Null until the referral validates and is first decided. |
referrer | object or null | No | |
velocity | object | No | Activity around the referral at the time of reading. |
rewards | array | No | |
validation | object or null | No | The immutable gate evaluation that validated the referral — the spec exactly as evaluated, not as the campaign reads today. Null until the referral validates. |
billing | object | No |
Full schema:
{
"type": "object",
"required": [
"object",
"referral"
],
"properties": {
"object": {
"type": "string",
"const": "referral_fraud_decision"
},
"referral": {
"$ref": "#/components/schemas/Referral"
},
"decision": {
"oneOf": [
{
"$ref": "#/components/schemas/FraudDecisionRecord"
},
{
"type": "null"
}
],
"description": "Null until the referral validates and is first decided."
},
"referrer": {
"type": [
"object",
"null"
],
"properties": {
"id": {
"type": "string"
},
"external_id": {
"type": "string"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "Account tenure — how long this referrer existed before referring."
},
"validated_referrals": {
"type": "integer"
},
"rejected_referrals": {
"type": "integer"
}
}
},
"velocity": {
"type": "object",
"description": "Activity around the referral at the time of reading.",
"properties": {
"referrer_last_day": {
"type": "integer"
},
"referrer_last_week": {
"type": "integer"
},
"same_device": {
"type": "integer",
"description": "Referrals across the whole app sharing this referral's click identifier — app-wide, because a device farm spreads signups over many referrer accounts.\n"
}
}
},
"rewards": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Reward"
}
},
"validation": {
"type": [
"object",
"null"
],
"description": "The immutable gate evaluation that validated the referral — the spec exactly as evaluated, not as the campaign reads today. Null until the referral validates.\n",
"properties": {
"qualification": {
"type": "object",
"additionalProperties": true
},
"gate_evaluations": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
},
"suppressed_rewards": {
"type": "array",
"description": "Rewards a configured cap prevented at validation.",
"items": {
"type": "object",
"additionalProperties": true
}
},
"evaluated_at": {
"type": "string",
"format": "date-time"
}
}
},
"billing": {
"type": "object",
"properties": {
"is_billable": {
"type": "boolean",
"description": "What the meter counted at validation. Never cleared."
},
"billing_reversed_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "When a rejection credited this referral back off the meter."
}
}
}
}
}The Referral object
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | |
object | string | Yes | |
status | ReferralStatus | Yes | The referral lifecycle state machine. |
fraud_status | composed | No | The referral's fraud standing; null until it validates and is decided. A flagged referral stays in the end user's referral history with fraud_status: flagged (and status: rejected) until you override it. |
campaign_id | string | Yes | |
referrer_id | string | Yes | |
referral_link_id | string or null | No | The referral link the referred user came in through, if attributed via one. |
referred_user_id | string or null | No | The customer's id for the referred end-user, once known (attribution). |
mode | Mode | No | Whether the object exists in test or live mode (determined by the API key). |
livemode | boolean | Yes | |
gate_progress | array | No | Per-condition progress toward the campaign's qualification gate (read-only — the gate itself is built in the dashboard). A fresh snapshot is taken on every engine evaluation; updated_at records when. |
score_progress | composed | No | Present for score or combined qualification modes; null for boolean-only campaigns. |
is_billable | boolean | No | Whether this referral counts toward billing (true once validated). |
signup_at | string or null | No | When the referred user signed up — anchors the campaign's qualification window. |
validated_at | string or null | No | |
created_at | string | Yes | |
updated_at | string | No | When the referral last transitioned or its gate progress was re-evaluated. |
Full schema:
{
"type": "object",
"required": [
"id",
"object",
"status",
"campaign_id",
"referrer_id",
"livemode",
"created_at"
],
"properties": {
"id": {
"type": "string",
"example": "rfl_123"
},
"object": {
"type": "string",
"const": "referral"
},
"status": {
"$ref": "#/components/schemas/ReferralStatus"
},
"fraud_status": {
"oneOf": [
{
"$ref": "#/components/schemas/FraudStatus"
},
{
"type": "null"
}
],
"description": "The referral's fraud standing; null until it validates and is decided. A flagged referral stays in the end user's referral history with `fraud_status: flagged` (and `status: rejected`) until you override it.\n"
},
"campaign_id": {
"type": "string"
},
"referrer_id": {
"type": "string"
},
"referral_link_id": {
"type": [
"string",
"null"
],
"description": "The referral link the referred user came in through, if attributed via one."
},
"referred_user_id": {
"type": [
"string",
"null"
],
"description": "The customer's id for the referred end-user, once known (attribution)."
},
"mode": {
"$ref": "#/components/schemas/Mode"
},
"livemode": {
"type": "boolean"
},
"gate_progress": {
"type": "array",
"description": "Per-condition progress toward the campaign's qualification gate (read-only — the gate itself is built in the dashboard). A fresh snapshot is taken on every engine evaluation; `updated_at` records when.\n",
"items": {
"type": "object",
"properties": {
"condition": {
"$ref": "#/components/schemas/QualificationCondition"
},
"satisfied": {
"type": "boolean"
},
"matched_events": {
"type": "integer",
"description": "Events matching the condition (name + property filters) within the window."
},
"total": {
"type": "number",
"description": "Summed contributed value across matching events (compared to the condition's `gte`)."
}
}
}
},
"score_progress": {
"oneOf": [
{
"$ref": "#/components/schemas/ScoreProgress"
},
{
"type": "null"
}
],
"description": "Present for score or combined qualification modes; null for boolean-only campaigns."
},
"is_billable": {
"type": "boolean",
"description": "Whether this referral counts toward billing (true once validated)."
},
"signup_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "When the referred user signed up — anchors the campaign's qualification window."
},
"validated_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "When the referral last transitioned or its gate progress was re-evaluated."
}
}
}The ReferralStatus object
The referral lifecycle state machine.
Full schema:
{
"type": "string",
"description": "The referral lifecycle state machine.",
"enum": [
"clicked",
"signed_up",
"in_progress",
"validated",
"reward_pending",
"reward_fulfilled",
"reward_failed",
"expired",
"rejected"
]
}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 QualificationCondition object
A single condition of a campaign's qualification gate, evaluated against the referred user's events. Read-only in the API: gates are built in the dashboard's Campaign Builder and surface here only inside a referral's gate_progress.
| Field | Type | Required | Description |
|---|---|---|---|
event | string | Yes | The event name that must occur. |
where | object | No | Property filters the event must match exactly (e.g. plan = paid). Values are scalars — matching is exact equality. |
gte | number | No | If the event carries a numeric value/count, require it to be ≥ this. |
Full schema:
{
"type": "object",
"required": [
"event"
],
"description": "A single condition of a campaign's qualification gate, evaluated against the referred user's events. Read-only in the API: gates are built in the dashboard's Campaign Builder and surface here only inside a referral's `gate_progress`.\n",
"properties": {
"event": {
"type": "string",
"description": "The event name that must occur."
},
"where": {
"type": "object",
"additionalProperties": {
"type": [
"string",
"number",
"boolean",
"null"
]
},
"description": "Property filters the event must match exactly (e.g. plan = paid). Values are scalars — matching is exact equality.\n"
},
"gte": {
"type": "number",
"exclusiveMinimum": 0,
"description": "If the event carries a numeric value/count, require it to be ≥ this."
}
}
}The ScoreProgress object
Read-only progress for score-based qualification.
| Field | Type | Required | Description |
|---|---|---|---|
threshold | number | Yes | |
total | number | Yes | |
satisfied | boolean | Yes | |
actions | array | Yes | |
mandatory | array | Yes | Boolean steps that must also be satisfied for a score-based referral. |
Full schema:
{
"type": "object",
"required": [
"threshold",
"total",
"satisfied",
"actions",
"mandatory"
],
"description": "Read-only progress for score-based qualification.",
"properties": {
"threshold": {
"type": "number",
"exclusiveMinimum": 0
},
"total": {
"type": "number",
"minimum": 0
},
"satisfied": {
"type": "boolean"
},
"actions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ScoreActionProgress"
}
},
"mandatory": {
"type": "array",
"description": "Boolean steps that must also be satisfied for a score-based referral.",
"items": {
"type": "object",
"properties": {
"condition": {
"$ref": "#/components/schemas/QualificationCondition"
},
"satisfied": {
"type": "boolean"
},
"matched_events": {
"type": "integer",
"minimum": 0
},
"total": {
"type": "number",
"minimum": 0
}
}
}
}
}
}The ScoreActionProgress object
| Field | Type | Required | Description |
|---|---|---|---|
event | string | Yes | |
points | number | Yes | Points one counted occurrence contributes. |
matched_events | integer | Yes | All in-window occurrences of this event. |
contributed_events | integer | Yes | Occurrences counted after applying the optional contribution cap. |
max_contributions | integer or null | No | Maximum counted occurrences for this event, or null when unlimited. |
total | number | Yes | Total points contributed by this event type. |
Full schema:
{
"type": "object",
"required": [
"event",
"points",
"matched_events",
"contributed_events",
"total"
],
"properties": {
"event": {
"type": "string"
},
"points": {
"type": "number",
"description": "Points one counted occurrence contributes."
},
"matched_events": {
"type": "integer",
"minimum": 0,
"description": "All in-window occurrences of this event."
},
"contributed_events": {
"type": "integer",
"minimum": 0,
"description": "Occurrences counted after applying the optional contribution cap."
},
"max_contributions": {
"type": [
"integer",
"null"
],
"minimum": 1,
"description": "Maximum counted occurrences for this event, or null when unlimited."
},
"total": {
"type": "number",
"description": "Total points contributed by this event type."
}
}
}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"
}
}
}The RewardStatus object
Full schema:
{
"type": "string",
"enum": [
"pending",
"held_for_review",
"approved",
"fulfilled",
"failed",
"rejected"
]
}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"
}
}
}