Events and qualifying event types

The Event types that RefRef accepts, which types can create a referral, how to send signups, purchases, custom Events, subscriptions, and refunds, and how RefRef decides each Event.

An Event is one fact about one participant: a signup, a purchase, or a milestone that you define. Your backend sends Events with POST /v1/track/events, or a connected integration sends them for you. Every Event gets an attribution decision, and benefit rules turn Events into Rewards.

Event types

TypeMeaningKey and time
signupThe participant signed up. A participant has one signup.Optional. Without them, RefRef uses one key per participant and the receipt time.
purchaseA paid invoice or order, with its amountsDerived from the invoice or order ID; the time is paidAt
custom_…A milestone that you define, such as custom_demo_bookedRequired: sourceEventId and occurredAt

A type that you define must start with custom_. Other names are reserved. RefRef refuses a type with 422 UNKNOWN_EVENT_TYPE when it is not built in, not a qualifying type of the Project, and not named by a benefit rule of the Project. Create the rule or add the qualifying type first.

Qualifying event types

The qualifying event types of a Project are the types that can create a new referral. The default is signup and purchase. A Workspace owner or admin changes the list in the Console.

The Event's typeThe participant has a referralThe participant has no referral
A qualifying typeThe Event uses the referralThe Event can create a referral from an eligible click or code
Another typeThe Event uses the referralUnattributed, reason not_qualifying_type

So an Event of any type can earn referrer and referee Rewards once a referral exists. A loyalty Program's subject rules evaluate every Event of their type, with or without a referral.

A change of the list applies to Events that arrive after the change. The start of a Subscription qualifies when purchase qualifies.

Use a custom qualifying type when the moment that matters is not a signup or a purchase, for example a booked demo for a sales-led product.

Send Events

Every Event names its Project, its source, and its participant:

{
  "projectId": "prj_…",
  "sourceNamespaceId": "…",
  "type": "custom_demo_booked",
  "sourceEventId": "demo_8812",
  "occurredAt": "2026-10-08T10:00:00.000Z",
  "participant": { "kind": "group", "externalId": "acct_7" },
  "actor": { "kind": "individual", "externalId": "user_42" },
  "refCode": "AB12CD3"
}
  • actor is optional: the person who acted for a group participant.
  • refCode is optional: a referral code that the person typed. One code per Event. A code that counts wins over every click.
  • A signup can also carry identify: { handle }. See signup tracking.

Purchases

A purchase sends its facts in purchase:

{
  "projectId": "prj_…",
  "sourceNamespaceId": "…",
  "type": "purchase",
  "participant": { "kind": "individual", "externalId": "user_42" },
  "purchase": {
    "resourceType": "invoice",
    "externalResourceId": "in_123",
    "paidAt": "2026-10-08T10:00:00.000Z",
    "currency": "USD",
    "currencyExponent": 2,
    "paidAmountMinor": "4900",
    "taxMinor": "0",
    "commissionableAmountMinor": "4900"
  }
}
  • Amounts are integers in minor units, as strings: "4900" is 49.00 USD.
  • commissionableAmountMinor is the part that percentage Rewards use. It must fit in the paid amount without tax.
  • Send only fully paid invoices or orders. A partial payment is not a purchase.
  • For a subscription invoice, add externalSubscriptionId, so the purchase belongs to its Subscription.
  • sourceOrderIndex is optional: the customer's order number from your store, where 1 is the first order. A Project that accepts only new customers needs it.

A purchase carries no browser data. It uses the participant's referral.

Subscriptions

POST /v1/subscriptions/facts records the life of a Subscription: subscription.started (with commencementPhase trial or active), and later status changes such as a pause, a resume, or a cancellation. The start fixes the Subscription's origin. Its renewals use that origin without a new click, also after 90 days. A pause, a resume, or a cancellation does not reset it.

Refunds and disputes

POST /v1/purchase-adjustments records a refund, a lost dispute, or a restoration of a purchase. Rewards that were calculated from the purchase get a proportional adjustment. RefRef does not take back a Reward that was already delivered; void it in the Console if needed.

A purchase rule counts a participant's purchases from a fixed start, so that a "first purchase" Reward pays only once and a period limit is correct. To do this, RefRef needs proof of the participant's paid purchases. A billing integration supplies it. Otherwise your backend sends it with POST /v1/evidence/paid-history: a list of every purchase of the participant from its binding time, or earlier, through the evaluated purchase. Until the proof arrives, the Reward evaluation waits. One proof serves every purchase rule.

How RefRef decides an Event

RefRef accepts the Event first, then decides it. An accepted Event can be pending. Its answer has a processingReason, for example awaiting_attribution. A fact dated in the future waits until its time.

OutcomeCommon reasons
Attributedlatest_eligible_touch (a click), referral_code_on_fact (a typed code), recorded_lead_preserved (an existing referral)
Unattributedno_eligible_touch, not_qualifying_type, self_touch_excluded, existing_customer_excluded, predates_source_namespace, predates_recorded_lead, participant_limit_paused

RefRef decides each fact once, with the identifications that it had received when the fact arrived. A fact never waits for an identification, and a later click never replaces a referral. event.recorded webhooks carry each decision.

Retries

Retry with the same body. A retry of an accepted fact returns the first result. A request that reuses a key with different facts answers 409 FACTS_CONFLICT. A participant has one signup: a second signup with another key answers 409 CONFLICT.

On this page