Sections
Theme

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

GET/v1/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

NameInRequiredSchemaDescription
limitqueryNo{"type":"integer","minimum":1,"maximum":100,"default":25}
starting_afterqueryNo{"type":"string"}A cursor (object id) for pagination; returns the page after this object.
decisionqueryNo{"$ref":"#/components/schemas/FraudDecision"}
statusqueryNo{"$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

POST/v1/fraud/decisions/{decisionId}/override

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

NameInRequiredSchemaDescription
decisionIdpathYes{"type":"string"}
Idempotency-KeyheaderNo{"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

POST/v1/referrers/{referrerId}/fraud/override

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

NameInRequiredSchemaDescription
referrerIdpathYes{"type":"string"}
Idempotency-KeyheaderNo{"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

GET/v1/fraud/payout-destination-control

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

POST/v1/fraud/payout-destination-control

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

NameInRequiredSchemaDescription
Idempotency-KeyheaderNo{"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

GET/v1/referrals/{referralId}/fraud

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

NameInRequiredSchemaDescription
referralIdpathYes{"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

FieldTypeRequiredDescription
objectstringYes
has_morebooleanYes
dataarrayYes

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

FieldTypeRequiredDescription
idstringYes
objectstringYes
referral_idstringYes
decisionFraudDecisionYesThe 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).
statusFraudStatusYesWhere 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.
overrideobject or nullYesSet once you override a flagged decision. decision, reason_code, signals and decided_at still describe the original AI decision.
reason_codeFraudReasonCodeNoWhy the engine decided as it did. Machine-readable because these are also the labels the AI fraud model trains on.
signalsarrayNoThe signals the engine weighed, as they stood when it decided.
decided_atstringYes
livemodebooleanYes
created_atstringYes

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

FieldTypeRequiredDescription
errorobjectYes

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

FieldTypeRequiredDescription
notestringNoOptional 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.

FieldTypeRequiredDescription
statusstringYes
queued_reward_idsarrayYes
failed_reward_idsarrayYes

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

FieldTypeRequiredDescription
objectstringYes
referrer_thresholdintegerYes
livemodebooleanYes

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

FieldTypeRequiredDescription
referrer_thresholdintegerYes

Full schema:

{
  "type": "object",
  "required": [
    "referrer_threshold"
  ],
  "properties": {
    "referrer_threshold": {
      "type": "integer",
      "minimum": 2,
      "maximum": 1000
    }
  }
}

The ReferralFraudDecision object

FieldTypeRequiredDescription
objectstringYes
referralReferralYes
decisioncomposedNoNull until the referral validates and is first decided.
referrerobject or nullNo
velocityobjectNoActivity around the referral at the time of reading.
rewardsarrayNo
validationobject or nullNoThe immutable gate evaluation that validated the referral — the spec exactly as evaluated, not as the campaign reads today. Null until the referral validates.
billingobjectNo

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

FieldTypeRequiredDescription
idstringYes
objectstringYes
statusReferralStatusYesThe referral lifecycle state machine.
fraud_statuscomposedNoThe 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_idstringYes
referrer_idstringYes
referral_link_idstring or nullNoThe referral link the referred user came in through, if attributed via one.
referred_user_idstring or nullNoThe customer's id for the referred end-user, once known (attribution).
modeModeNoWhether the object exists in test or live mode (determined by the API key).
livemodebooleanYes
gate_progressarrayNoPer-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_progresscomposedNoPresent for score or combined qualification modes; null for boolean-only campaigns.
is_billablebooleanNoWhether this referral counts toward billing (true once validated).
signup_atstring or nullNoWhen the referred user signed up — anchors the campaign's qualification window.
validated_atstring or nullNo
created_atstringYes
updated_atstringNoWhen 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.

FieldTypeRequiredDescription
eventstringYesThe event name that must occur.
whereobjectNoProperty filters the event must match exactly (e.g. plan = paid). Values are scalars — matching is exact equality.
gtenumberNoIf 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.

FieldTypeRequiredDescription
thresholdnumberYes
totalnumberYes
satisfiedbooleanYes
actionsarrayYes
mandatoryarrayYesBoolean 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

FieldTypeRequiredDescription
eventstringYes
pointsnumberYesPoints one counted occurrence contributes.
matched_eventsintegerYesAll in-window occurrences of this event.
contributed_eventsintegerYesOccurrences counted after applying the optional contribution cap.
max_contributionsinteger or nullNoMaximum counted occurrences for this event, or null when unlimited.
totalnumberYesTotal 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

FieldTypeRequiredDescription
idstringYes
objectstringYes
statusRewardStatusYes
referral_idstringYes
campaign_idstringNo
recipientstringNo
configRewardConfigNoHow 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.
payoutPayoutNoThe actual disbursement or app grant.
modeModeNoWhether the object exists in test or live mode (determined by the API key).
livemodebooleanYes
created_atstringYes

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.

FieldTypeRequiredDescription
methodstringYesWhat 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.
categoriesarrayNomonetary 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_methodsarrayNoFor 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.
recipientstringYesWho this entry rewards. Add one configuration per side to make a campaign double-sided.
amountintegerNoValue in smallest currency unit (for money methods) or app-defined units.
currencyCurrencyNoISO 4217 currency code (lowercase), e.g. "usd".
free_access_durationobjectNoRequired for method = free_access. The term your referral pages advertise — e.g. &#123; "count": 3, "unit": "month" &#125;. For code deliveries this is the advertised term only: the enforced one is baked into the code you supply, so generate codes that match.
deliverystringNoFor 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_payloadobjectNoFor method = in_app — what to grant (e.g. grant the gold skin).
milestone_thresholdintegerNoReward only after the referrer reaches N validated referrals (e.g. 5).
cap_per_referrerintegerNoMax rewards per referrer (fraud control).
cap_per_monthintegerNoMax rewards per campaign per month (fraud control).
expires_in_daysintegerNo

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.

FieldTypeRequiredDescription
methodstringNoThe reward's method. Campaigns stored before cash became a category may still report the retired paypal, venmo or ach.
providerstringNoIdentifies the app grant or money payout provider.
provider_referencestringNoExternal id (payout partner order id or webhook delivery id).
statusstringNo
amountintegerNo
currencyCurrencyNoISO 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"
    }
  }
}

On this page