All docs pages

Reference

REST API

Every v1 endpoint, its parameters and its scope.

Base URL https://referralmeter.com. Authenticate with a secret key: Authorization: Bearer sk_…. Create keys on Install & verify or in Settings; a key is read-only unless it has the write scope. The machine-readable description is openapi.json.

  • Amounts are integer cents with an ISO currency.
  • Lists are newest first with cursor pagination: limit (1–100, default 50) and cursor (the previous page's next_cursor).
  • Errors look like {"error":{"code":"…","message":"…"}}: 400 invalid input, 401 bad key, 403 read-only key, 404 not in your program, 429 over 600 requests a minute.
  • Every write is recorded in your program's audit log with the key that made it.
  • No endpoint moves money or marks a payout as paid.

Get the program

GET /api/v1/program · read scope

Name, public key, portal URL and the commission rules in force.

curl https://referralmeter.com/api/v1/program \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"

Response:

{
  "id": "…",
  "name": "Acme AI",
  "slug": "acme",
  "public_key": "pk_…",
  "currency": "usd",
  "commission": {
    "type": "percent",
    "value": 30,
    "duration": "months",
    "months": 12,
    "hold_days": 30
  }
}

Update commission rules and portal text

PATCH /api/v1/program · write scope

Send only the fields you change. Changes apply to commissions earned from now on; existing commissions keep their amount.

FieldInType
commission_typebodypercent, flat
commission_valuebodynumber, 0–100000
commission_durationbodyonce, months, lifetime
commission_monthsbodyinteger, 1–120
pay_on_one_timebodyboolean
pay_on_usagebodyboolean
attribution_daysbodyinteger, 1–365
attribution_modelbodyfirst, last
hold_daysbodyinteger, 0–120
min_payout_centsbodyinteger, 0–100000000
approval_threshold_centsbodyinteger, 0–100000000 or null
auto_approve_affiliatesbodyboolean
portal_headlinebodystring or null
portal_bodybodystring or null
terms_urlbodystring (uri) or null
curl -X PATCH https://referralmeter.com/api/v1/program \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"commission_value":25,"commission_duration":"months","commission_months":12,"portal_headline":"Earn 25% for a year"}'

List affiliates

GET /api/v1/affiliates · read scope

Newest first. Verification test affiliates are hidden unless include_test=true.

FieldInType
limitqueryinteger, 1–100, default 50
cursorquerystring
statusquerypending, approved, rejected, banned
qquerystring
include_testqueryboolean or 0, 1, true, false
curl https://referralmeter.com/api/v1/affiliates \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"

Response:

{
  "data": [
    {
      "id": "8d0f7c1e-2a7b-4c55-9d1e-3b4a5c6d7e8f",
      "email": "maya@example.com",
      "name": "Maya Chen",
      "code": "maya",
      "status": "approved",
      "referral_link": "https://referralmeter.com/go/acme/maya",
      "commission_override": null,
      "clicks": 412,
      "customers": 9,
      "earned_cents": 13230,
      "currency": "usd"
    }
  ],
  "next_cursor": null
}

Add an affiliate

POST /api/v1/affiliates · write scope

Creates an affiliate directly (no application). Omit code and one is derived from the name.

FieldInType
email *bodystring (email)
namebodystring, default ``
codebodystring
statusbodyapproved, pending, default approved
notesbodystring
commission_typebodypercent, flat or null
commission_valuebodynumber, 0–100000 or null
curl -X POST https://referralmeter.com/api/v1/affiliates \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"email":"maya@example.com","name":"Maya Chen","code":"maya"}'

Response:

{
  "id": "8d0f7c1e-2a7b-4c55-9d1e-3b4a5c6d7e8f",
  "email": "maya@example.com",
  "name": "Maya Chen",
  "code": "maya",
  "status": "approved",
  "referral_link": "https://referralmeter.com/go/acme/maya",
  "commission_override": null,
  "clicks": 412,
  "customers": 9,
  "earned_cents": 13230,
  "currency": "usd"
}

Get an affiliate

GET /api/v1/affiliates/{id} · read scope

One affiliate with clicks, paying customers and commission earned.

FieldInType
idpathAffiliate id
curl https://referralmeter.com/api/v1/affiliates/<id> \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"

Response:

{
  "id": "8d0f7c1e-2a7b-4c55-9d1e-3b4a5c6d7e8f",
  "email": "maya@example.com",
  "name": "Maya Chen",
  "code": "maya",
  "status": "approved",
  "referral_link": "https://referralmeter.com/go/acme/maya",
  "commission_override": null,
  "clicks": 412,
  "customers": 9,
  "earned_cents": 13230,
  "currency": "usd"
}

Approve, reject or ban; set a commission override; edit notes

PATCH /api/v1/affiliates/{id} · write scope

status: approved | pending | rejected | banned. Set commission_type and commission_value together, or both to null to fall back to the program rule.

FieldInType
idpathAffiliate id
statusbodyapproved, pending, rejected, banned
notesbodystring or null
commission_typebodypercent, flat or null
commission_valuebodynumber, 0–100000 or null
curl -X PATCH https://referralmeter.com/api/v1/affiliates/<id> \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"status":"approved","commission_type":"percent","commission_value":40}'

List commissions

GET /api/v1/commissions · read scope

Newest first. Reversals (refunds, disputes) are rows with a negative amount and reversal_of set. Test commissions are hidden unless include_test=true.

FieldInType
limitqueryinteger, 1–100, default 50
cursorquerystring
statusquerypending, needs_approval, approved, paid, reversed, rejected
affiliate_idquerystring (uuid)
sincequerystring (date-time) or string (date)
include_testqueryboolean or 0, 1, true, false
curl https://referralmeter.com/api/v1/commissions \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"

Response:

{
  "data": [
    {
      "id": "…",
      "affiliate_code": "maya",
      "amount_cents": 1470,
      "base_amount_cents": 4900,
      "currency": "usd",
      "rate_label": "30% · month 1 of 12",
      "status": "pending",
      "hold_until": "2026-12-03T14:01:31Z"
    }
  ],
  "next_cursor": null
}

List referred customers

GET /api/v1/customers · read scope

Every referral: leads (signed up) and customers (paid), with the affiliate who brought them and revenue so far.

FieldInType
limitqueryinteger, 1–100, default 50
cursorquerystring
statusquerylead, customer, refunded, canceled
affiliate_idquerystring (uuid)
include_testqueryboolean or 0, 1, true, false
curl https://referralmeter.com/api/v1/customers \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"

Program stats

GET /api/v1/stats · read scope

Live traffic only (test payments and verification runs are excluded). Revenue and commissions are in the program currency.

FieldInType
daysqueryinteger, 1–365, default 30
curl https://referralmeter.com/api/v1/stats \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"

Response:

{
  "days": 30,
  "currency": "usd",
  "revenue_cents": 418000,
  "commissions_owed_cents": 125400,
  "clicks": 3120,
  "leads": 211,
  "customers": 38,
  "active_affiliates": 7,
  "ai_customers": 5
}

Start an install verification

POST /api/v1/verifications · write scope

Creates a test affiliate and returns a test link. Open it, sign up, pay in test mode; poll GET /api/v1/verifications/{id} until status is passed. A running run is reused; runs expire after 24 hours.

curl -X POST https://referralmeter.com/api/v1/verifications \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"

Response:

{
  "id": "…",
  "publicId": "Qm3x…",
  "status": "running",
  "testLink": "https://acme.ai/?via=verify-k3m9tq",
  "next": "Waiting for: affiliate click recorded. …",
  "certificate_url": "https://referralmeter.com/verify/Qm3x…"
}

Get a verification run

GET /api/v1/verifications/{id} · read scope

Each step with its timestamp, a plain-English hint for the step it is waiting on, and diagnostics from your data (e.g. a payment that arrived without a referral). Use latest as the id for the newest run.

FieldInType
idpathRun id, or latest
curl https://referralmeter.com/api/v1/verifications/<id> \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"

What you owe, per affiliate

GET /api/v1/payouts/due · read scope

Approved, unpaid live commissions grouped by affiliate and currency. Read-only: no API creates a payout batch or marks money as sent.

curl https://referralmeter.com/api/v1/payouts/due \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY"

Response:

{
  "data": [
    {
      "affiliate_id": "…",
      "email": "maya@example.com",
      "currency": "usd",
      "amount_cents": 13230,
      "commissions": 9,
      "meets_minimum": true
    }
  ],
  "min_payout_cents": 5000
}

Record a sale (server-side)

POST /api/v1/track/sale · write scope

For billing we don't connect to natively. Idempotent on event_id. Returns 201 with the outcome and commission_cents, or 200 for a duplicate.

FieldInType
event_id *bodystring — Your unique id for this payment. Re-sending the same id is a no-op.
payment_idbodystring — The id a later refund will name. Defaults to event_id.
amount *bodyinteger — Amount in minor units (cents).
currency *bodystring — ISO 4217 code, e.g. usd.
customer_idbodystring — Your billing customer id. Later sales for the same customer attribute to the same affiliate.
customer_emailbodystring (email)
customer_external_idbodystring — Your own user id (the uid you passed to referralmeter.signup).
referralbodystring — The value of referralmeter.ref() (click id) or an affiliate code.
couponbodystring — Coupon code used, if it belongs to an affiliate.
kindbodysubscription, one_time, credits, usage, default subscription
livemodebodyboolean, default true — false for test payments: recorded, never paid out.
occurred_atbodystring (date-time)
curl -X POST https://referralmeter.com/api/v1/track/sale \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"event_id":"pay_123","amount":4900,"currency":"usd","customer_external_id":"user_42","referral":"<referralmeter.ref()>","kind":"subscription"}'

Record a refund

POST /api/v1/track/refund · write scope

Claws the commission back in proportion to the refunded amount.

FieldInType
event_id *bodystring — Your unique id for this refund.
payment_id *bodystring — The payment_id (or event_id) of the sale being refunded.
amount *bodyinteger — Refunded amount in cents. Partial refunds claw back proportionally.
currencybodystring — Defaults to the program currency.
livemodebodyboolean, default true
curl -X POST https://referralmeter.com/api/v1/track/refund \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"event_id":"ref_9","payment_id":"pay_123","amount":4900}'

Record a signup (server-side)

POST /api/v1/referrals · write scope

The server-side twin of referralmeter.signup(): attributes a new user to the click or affiliate code in referral.

FieldInType
email *bodystring (email) — The new user's email.
external_idbodystring — Your own user id.
referral *bodystring — referralmeter.ref() from the browser (click id) or an affiliate code.
ipbodystring — The visitor's IP, so self-referral checks still work server-side.
curl -X POST https://referralmeter.com/api/v1/referrals \
  -H "Authorization: Bearer $REFERRALMETER_SECRET_KEY" \
  -H "Content-Type: application/json" -d '{"email":"new.user@example.com","external_id":"user_42","referral":"<referralmeter.ref()>"}'