API overview

Authenticate with a Workspace API key, choose the Sandbox or Live environment, read the error envelope, and find every API route.

The RefRef API serves your trusted backend: it accepts Events and identifications, enrolls participants, creates referral codes, and reads Rewards and webhook events. The base URL is https://api.refref.ai.

The running API publishes its OpenAPI document at GET https://api.refref.ai/openapi. It is the reference for every request and response schema, and its webhooks section has a schema and a sample for each webhook event.

Authentication

Send a Workspace API key in the X-Api-Key header:

curl https://api.refref.ai/v1/rewards?projectId=prj_… \
  -H "X-Api-Key: $REFREF_API_KEY"

Owners and admins create API keys in the Console. A key belongs to the Workspace, not to the person who created it, so it keeps working after that person leaves.

Keep the key on your server. Never put it in browser code, mobile apps, prompts, or logs.

Two routes do not take an API key, because the browser calls them:

RouteCredential
POST /v1/captureThe handoff of a referral click. The landing script calls it.
POST /v1/widget/initA short-lived Widget token that your backend signs. See Widget.

Environments

Each key belongs to one environment: Sandbox or Live. Each Project is a pair of a Live Project and its Sandbox Project, and a key reaches only the Projects of its own environment.

The key callsAnswer
A Project of its Workspace and environmentThe operation runs
The other environment's Project403 ENVIRONMENT_MISMATCH
A Project of another Workspace404 NOT_FOUND

Use a Sandbox key and the Sandbox Project ID while you build. Change both when you go live.

API key scopes

Each API key has a reach and a set of permissions.

Reach. A key is owned by its Workspace and bound to Sandbox or Live. It reaches either all Projects of its environment, also Projects that you add later, or a list of Projects that you select. A Project outside the key answers 404 NOT_FOUND. A key never reaches another Workspace. If you run Projects in two Workspaces, create one key in each.

Permissions. Choose a preset when you create the key, or set custom permissions:

PresetUse it for
IntegrationYour application backend: send Events and identifications, manage participants, enrollments, and codes, fulfill Rewards, and manage webhook endpoints
Read-onlyReports and dashboards: every read, no writes
Full accessEvery API operation

Custom permissions combine these resources and actions:

ResourceActionsCovers
intakewriteEvents, subscription facts, purchase adjustments, paid history, identifications
participantsread, writeParticipants, enrollments, referral codes and links
programsread, writePrograms, benefit rules, reward terms, referee offers, delivery settings, join pages, custom units, qualifying event types
referralsread, writeReferrals, Events, purchases, evaluations, adjustments; write records a referral that you know
rewardsread, fulfill, voidRewards; fulfill records a fulfillment or a revocation; void voids a Reward with a reason
partnersread, writePartners, their payout history, invitations, applications, bans
integrationsreadConnections, diagnostics, webhook deliveries
webhooksread, writeWebhook endpoints and the event feed

An operation outside the key's permissions is refused. A key without permissions is refused.

These are never available through an API key: payout runs and payout settings (a partner's payout history is a partners read), RefRef billing, Project secrets, Workspace members and invitations, API key management, and provider credentials. Use the Console for them.

Routes

AreaRoutes
FactsPOST /v1/track/events, POST /v1/subscriptions/facts, POST /v1/purchase-adjustments, POST /v1/evidence/paid-history
IdentificationPOST /v1/identify, POST /v1/capture (browser)
ParticipantsPUT /v1/participants, POST /v1/participants/rekey
Enrollment and codesPOST /v1/enrollments, POST /v1/enrollments/{enrollmentId}/end, POST /v1/referral-codes, POST /v1/referral-links
ProgramsGET /v1/programs, POST /v1/programs, GET /v1/programs/{programId}, PATCH /v1/programs/{programId}, GET /v1/reward-rules, POST /v1/benefit-rules, POST /v1/benefit-rules/{ruleId}/terms, referee offer and delivery settings, POST /v1/attribution/policies
ReferralsPOST /v1/referrals: record a referral that you know, for example from a sales call
DataGET /v1/projects, GET /v1/participants, GET /v1/referrers, GET /v1/referrals, GET /v1/events, GET /v1/events/{eventId}/diagnosis, GET /v1/purchases, GET /v1/connections, GET /v1/webhook-deliveries
PartnersGET /v1/partners, GET /v1/partners/{participantId}, GET /v1/partners/{participantId}/payouts, GET /v1/partner-applications, POST /v1/partner-invitations, POST /v1/partner-invitations/{partnerRequestId}/revoke, POST /v1/partner-applications/{partnerRequestId}/approve and /decline, POST /v1/partners/{partnerId}/ban and /unban
OperationsPOST /v1/rewards/{rewardId}/void, POST /v1/rewards/{rewardId}/delivery/retry
Custom unitsGET /v1/custom-units, POST /v1/custom-units, PATCH /v1/custom-units/{key}
RewardsGET /v1/rewards, GET /v1/rewards/{rewardId}, POST /v1/rewards/{rewardId}/fulfillment, POST /v1/rewards/{rewardId}/revocation
WebhooksGET /v1/webhook-events, POST /v1/webhook-endpoints, GET /v1/webhook-endpoints, DELETE /v1/webhook-endpoints/{endpointId}
Widget (browser)POST /v1/widget/init, GET /v1/widget/payout-details, PUT /v1/widget/payout-details

The API reference lists every route with its permission. Each body or query names its Project with projectId. A body names a participant with your own ID: { "kind": "individual" | "group", "externalId": "…" }. A call that names an unknown participant creates it.

Successful answers

A successful answer has success: true and the result of the operation.

Retries

Retry a request with the same body. RefRef derives a key from each fact, so a retry of an accepted fact returns the first result and records nothing twice. A request that reuses a fact's key with different business facts answers 409 FACTS_CONFLICT. Do not change the facts to make a retry pass.

Errors

Every error has the same body:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "…",
    "details": [{ "path": "participant.externalId", "message": "…" }],
    "requestId": "req_…"
  }
}
CodeStatusMeaning
VALIDATION_ERROR400The request does not match its schema. details lists each field.
INVALID_REQUEST400RefRef refuses the request for another reason, for example an expired handoff
AUTH_REQUIRED401No valid API key or Widget token
FORBIDDEN403The Widget token lacks the scope of the route
ENVIRONMENT_MISMATCH403The key's environment differs from the Project's environment
NOT_FOUND404The resource does not exist or belongs to another owner
CONFLICT409The request conflicts with accepted state, for example a second signup with another key
FACTS_CONFLICT409The fact's key already names different business facts
UNKNOWN_EVENT_TYPE422The Event type is not built in, not a qualifying type of the Project, and no benefit rule names it
RATE_LIMIT_EXCEEDED429Too many requests. Wait the seconds of the Retry-After header, then retry
INTERNAL_SERVER_ERROR500An unexpected error. Retry with the same body.

message is for people; do not parse it. Handle an unknown code by its HTTP status. Give the requestId when you contact us about a request.

The API accepts a fact before RefRef decides it. An accepted Event can still be pending: its answer has a processingReason. Read the result later from webhooks or the Console.

On this page