Skip to content
Coritan Docs

Run a referral program

Let customers share a link and earn wallet credit, make partner codes that pay a commission, void a referral, and read what the program has paid.

View as Markdown

A referral starts when a customer of your storefront shares a link with their code and the person who follows it pays a first invoice. The customer who shared the code earns wallet credit. You can also pay the new customer a welcome credit.

The program is off until you turn it on. Your team runs it in the staff console, under Marketing, as Run campaign links and referrals in the staff console describes. The owner and scripts use the API, which this page describes.

  • You need the Admin or Owner role in the organization. Members with any other role cannot read or change the program.
  • Your storefront must be one that Coritan serves, so the order records the code the visitor arrived with. How customers and orders are attributed explains what an order records.
  • The reward is wallet credit that you give. A customer spends it on an invoice like any other credit, and an invoice paid from credit is not part of a payout.

Owners and admins run the program in the dashboard. Your team can do the same in the staff console, as Marketing campaigns and referrals in the staff console describes. A member with another role does not see the page, and its address opens Overview.

  1. In the dashboard, open the organization, then Settings, then Referrals.
  2. Under Program, turn on Run the referral program. While it is off the page says so, and nothing is made or paid.
  3. Set "Reward for the referrer", "Welcome credit for the new customer", "First invoice must reach", "Days before a reward is paid" and "Most rewards for one customer in 30 days". Each hint shows the range the API allows. Amounts are in US dollars, the unit of a customer's wallet, and the first invoice is counted without tax. Turn Refuse orders that came from a paid ad on or off.
  4. Select Save changes. The page says "Referrals turned on." when the switch was the only change, and "Referral settings saved." otherwise. A value the API refuses shows its sentence under the input. A new amount applies to referrals that start after you save it, and a referral already waiting keeps the amounts it started with.
  5. Read the tiles under the card: Qualified, Credited and Void, and Pending when a referral is in that state. Each shows how many referrals are in it, with what is owed or paid out. Select a tile to filter the list below it, and select it again to clear the filter.

Referrals lists each referred customer, newest first, with who referred them, the code that was used, their first invoice, the reward and the welcome credit, and the status. A qualified referral says when it pays, such as "Pays in 2 days". A void one says why: "The same customer", "Both addresses reach one mailbox", "Signed up from the same network", "Signed up on the same device", "The order came from a paid ad", "An account is closed, suspended or banned", "The referrer reached the monthly cap", "The first invoice was refunded", "The first invoice was charged back", or the reason a person gave. Search by either customer's email, or choose a status. The search, the status and the page stay in the address.

To void a referral that has not been paid, open its actions menu and select Void referral…. Type the reason, 1 to 120 characters, and select Void referral. The reason is kept with the referral. A referral that is paid or void cannot be voided, and money already paid is not taken back. You can void 60 an hour.

Codes lists every code with its owner, whether it is a customer's own or a partner's, what it pays, how many referrals it started and whether it is Active or Stopped. Select New partner code…, type the customer's "Customer email", an optional "Code" and "Label", and the "Share of the first invoice" as a percent from 0.01 to 50, then select Create code. The page turns the share into basis points for the API. You can make 30 codes an hour. In a partner code's actions menu, Edit… changes its share and label, Stop code… stops it from starting new referrals and Restart code starts it again. Referrals a stopped code already started still pay.

Every amount on this page is in wallet dollars, the unit a customer's wallet is kept in (US dollars), whatever currency the customer is billed in.

  • A customer's own code is made the first time they open their referral page, and only while the program is on. It is 8 characters, capital letters and digits without the look-alikes I, O, 0 and 1. It never changes.
  • The link is your storefront's address followed by /?ref= and the code, such as https://shop.example.com/?ref=K7M2Q9XA.
  • The storefront keeps the code for 30 days in the visitor's browser, in a cookie named _ct_ref, and every order placed from that browser records it. A storefront you build yourself sets that cookie. A code is at most 40 letters, digits, hyphens and underscores.
  • A code is found without regard to capitals, and it belongs to one organization. A code of another organization never starts a referral on yours.
  • A partner code is a code that you make for a customer, as Partner codes describes. It pays a share of the first invoice instead of a fixed reward.

A referral starts when an invoice is paid and every one of these is true:

  • The program is on.
  • The order recorded a code of your organization, and the code is not stopped.
  • It is the paying customer's first paid invoice with a total above 0. A free invoice, an unpaid one or a later one does not count as an earlier paid invoice, but a refunded one does.
  • Money passed through a payment gateway. An invoice that a wallet paid in full, or that your team marked as paid, never starts a referral.
  • The invoice total without tax, converted to wallet dollars, is at least threshold_amount.
  • None of the rules in What stops a referral applies.

The customer is referred once. A second code, or a second invoice, starts nothing, and a referral that was voided is not started again. A paid ad order is refused only while block_paid_ads is on.

A referral that is refused before it starts leaves no row, so it does not appear in the list. We write the reason to our logs. Troubleshooting lists the reasons.

A new referral is qualified and waits hold_days days before it is paid. A refund or a lost chargeback on the invoice during the hold voids it. You can void it by hand as well.

Once an hour we pay every qualified referral whose hold has passed, at most 200 each time, oldest first. We check every rule again first, so a referral that no longer passes is voided instead of paid. One organization's referrals are paid by one worker at a time.

For each referral we pay the customer who shared the code reward_amount, or for a partner code its commission, and the referred customer referee_reward_amount when it is above 0. Both credits are written together or not at all. Each is a credit_add entry in the customer's wallet history with no gateway and the reference referral:<referral id>:<customer id>, so a second run pays nothing. The referral becomes credited.

After the credit is saved, we email each customer who was paid. These are service emails, so they go to a customer who has not agreed to marketing, and they skip an address on your suppression list. If an email fails, the credit stays.

These rules are checked when the referral starts and again when it is due. A referral that fails one when it is due is void, and void_reason holds the word.

void_reason The rule
self The customer who shared the code is the customer who paid.
same_mailbox The two email addresses reach one mailbox. We ignore capitals, cut +tag off the part before the @, and for gmail.com and googlemail.com also ignore dots and treat the two domains as one.
same_network Both accounts were made from the same network address, within 30 days of each other.
same_device Both accounts were made from the same browser fingerprint.
paid_ad The order's last channel is paid_search, paid_social or display, and block_paid_ads is on.
closed Either account is closed, banned or suspended.
cap The customer who shared the code already has monthly_cap referrals paid in the last 30 days.
refunded The invoice is no longer paid in full: it was refunded, or part of it was.
chargeback A chargeback on the invoice was lost.

A referral that staff void by hand keeps the words they gave as void_reason.

In the staff console, under Marketing, turn the program on and set its amounts. With the API, send only the settings you want to change:

Turn the program on with a 5.00 reward and a 7 day hold
curl -X PUT "https://api.coritan.com/api/v1/orgs/acme/referrals/settings" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true, "reward_amount": "5.00", "hold_days": 7}'

The answer holds every setting, the wallet currency, the range of each number and changed, the keys that differ from before:

JSON
{
  "enabled": true,
  "reward_amount": "5.00",
  "referee_reward_amount": "0.00",
  "threshold_amount": "5.00",
  "hold_days": 7,
  "monthly_cap": 20,
  "block_paid_ads": true,
  "currency": "USD",
  "limits": {"hold_days": {"min": 1, "max": 90}},
  "changed": ["enabled", "hold_days"]
}

limits lists every number's range. This example shows one.

Setting Default What it does
enabled false Turns the program on. While it is off nothing starts and no code is made.
reward_amount "5.00" What a customer's own code pays the customer who shared it. An amount from 0 to 1000 with at most 2 decimals.
referee_reward_amount "0.00" A welcome credit for the referred customer. An amount from 0 to 1000. 0 pays none.
threshold_amount "5.00" What the referred customer's first paid invoice must reach, without tax. An amount from 0 to 10000.
hold_days 14 Days a referral waits before it is paid, from 1 to 90.
monthly_cap 20 The most referrals one customer is paid for in 30 days, from 1 to 500.
block_paid_ads true Refuses a referral whose order came from a paid ad.

Amounts are decimal strings. A value that does not fit, or a name that is not a setting, answers 422 with detail, the sentence to show, and field, the setting it belongs to, and nothing changes. A change is recorded in the audit log as referrals.settings_updated, with the settings before and after. A save that changes nothing is not recorded.

A new amount applies to referrals that start after the change. A referral that is already waiting keeps the amounts it started with. The new hold_days also applies only to referrals that start after the change.

A partner code pays a customer a share of every first invoice it brings, instead of the fixed reward. Use it for a streamer, a newsletter author or a community owner who already holds an account on your storefront. Your team makes the code in the staff console, under Marketing.

With the API, name the owner by customer_id or email, and give commission_bp, the share in basis points. 100 is 1 percent, and the range is 1 to 5000. The share is taken from the invoice total without tax, in wallet dollars, and kept to four decimal places. The owner must be an active customer of this organization.

Make a partner code that pays 12.5 percent
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/referrals/codes" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email": "pat@example.com", "code": "PAT-LAUNCH", "commission_bp": 1250, "label": "Pat, launch week"}'
JSON
{
  "id": 41,
  "code": "PAT-LAUNCH",
  "kind": "partner",
  "customer": {"id": 12, "email": "pat@example.com", "name": "Pat Tester"},
  "commission_bp": 1250,
  "label": "Pat, launch week",
  "active": true,
  "referrals": {"total": 0, "credited": 0, "earned": "0.00"},
  "created_at": "2026-10-11T12:00:00"
}
  • code is optional: 3 to 40 letters, digits, hyphens or underscores. Left out, we make an 8 character one. A code that is in use answers 409, and two codes that differ only in capitals are one code.
  • label is a note for your team, at most 120 characters.
  • You can make 30 codes an hour for each member.
  • PATCH /referrals/codes/{code_id} changes active, commission_bp (a partner code only) and label. The code never changes. active: false stops the code from starting new referrals, and referrals it already started still pay.
  • GET /referrals/codes lists customer codes and partner codes, newest first, with kind, active, q (part of the code, its label or the owner's email) and limit (at most 200). Each code shows referrals: how many it started, how many were paid and what they paid the owner.

The code is recorded as referral_code.created, and a change as referral_code.updated, with the values before and after.

GET /referrals lists the referrals of your organization, newest first. Each row names the referrer and the referred customer, the code, the invoice that started it, the rewards, the status and the dates. Filter by status (pending, qualified, credited or void), and by q, which matches either customer's email address without regard to capitals. limit is at most 200.

Referrals waiting for their hold
curl "https://api.coritan.com/api/v1/orgs/acme/referrals?status=qualified&limit=20" \
  -H "Authorization: Bearer $CORITAN_TOKEN"
JSON
{
  "referrals": [
    {
      "id": 118,
      "status": "qualified",
      "referrer": {"id": 7, "email": "ada@example.com", "name": "Ada Tester"},
      "referee": {"id": 9, "email": "sam@example.com", "name": "Sam Tester"},
      "code": {"id": 4, "code": "K7M2Q9XA", "kind": "customer"},
      "invoice": {"id": 310, "number": "INV-000310"},
      "reward_amount": "5.00",
      "referee_reward_amount": "0.00",
      "currency": "USD",
      "void_reason": null,
      "qualified_at": "2026-10-11T12:00:00",
      "hold_until": "2026-10-25T12:00:00",
      "credited_at": null,
      "created_at": "2026-10-11T12:00:00"
    }
  ],
  "count": 1,
  "limit": 20,
  "offset": 0,
  "totals": {"currency": "USD", "pending": 0, "qualified": 1, "credited": 0, "void": 0, "credited_amount": "0.00", "owed_amount": "5.00"}
}

count is how many referrals match the filters. totals covers the whole program and ignores them: the number of referrals in each status, credited_amount paid out so far and owed_amount for the open ones.

A referral that you do not want to pay can be voided while it is pending or qualified. A referral that is already credited or void answers 409, and money already paid is not taken back.

Void a referral
curl -X POST "https://api.coritan.com/api/v1/orgs/acme/referrals/118/void" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Same household"}'

reason is required, 1 to 120 characters. The answer is {"id": 118, "status": "void", "void_reason": "Same household"}. You can void 60 referrals an hour for each member. The void is recorded in the audit log as referral.voided, with the reason.

A signed-in customer reads their own page with GET /api/v1/orgs/{org_slug}/portal/referrals. It answers:

JSON
{
  "enabled": true,
  "code": "K7M2Q9XA",
  "link": "https://shop.example.com/?ref=K7M2Q9XA",
  "reward_amount": "5.00",
  "referee_reward_amount": "0.00",
  "threshold_amount": "5.00",
  "currency": "USD",
  "hold_days": 14,
  "stats": {"pending": 0, "qualified": 1, "credited": 2, "earned": "10.00"},
  "referrals": [
    {"id": 118, "status": "qualified", "referee": "Sam", "reward_amount": "5.00", "currency": "USD",
     "qualified_at": "2026-10-11T12:00:00", "hold_until": "2026-10-25T12:00:00", "credited_at": null,
     "created_at": "2026-10-11T12:00:00"}
  ]
}
  • While the program is off, enabled is false and there is no code or link. No code is made.
  • The customer sees the last 50 of their referrals. A referred customer shows as their first name, or Someone when there is none. The customer never sees an email address.
  • A code that you stopped is not shown.
  • A support session that signed in as the customer reads the page but does not make a code.

What your customers see on the storefront

Section titled What your customers see on the storefront

A storefront that Coritan serves draws the panel and keeps the link's code for you. This section says what a visitor reads. A storefront you build yourself calls GET /portal/referrals and writes its own words.

The panel sits in the customer's account, near their wallet or billing settings. It draws nothing while the program is off, and nothing while the customer has no link, so a storefront with the program off shows no gap. When the program is on it shows:

  • The words "Share your link. When a friend pays a first invoice of $10.00 or more, you get $5.00 in wallet credit. We add it after a 14 day hold." The amounts and the days come from your settings, in wallet dollars. When referee_reward_amount is above 0 it adds "Your friend gets $2.00 in wallet credit too." The panel never mentions reviews.
  • The customer's link and a "Copy link" button. The page says "Link copied." and, when the browser refuses, "Could not copy. Select the link and copy it."
  • Three counts: "Waiting" (referrals that are pending or qualified), "Credited" and "Earned".
  • "Your referrals": the first five, then "Show all" for up to 50 and "Show fewer". Each row has a first name or "Someone", a status and an amount. The status reads "Waiting for the hold to end" with "Credit on" and the date, "Credited" with the date, or "Not credited" with a dash for the amount. The panel never says why a referral is void.
  • Before any referral exists, "No referrals yet. Share your link to get started."

A link that ends in ?ref=<code>, on any page of the storefront, keeps the code for 30 days when the program is on:

  • The cookie is _ct_ref, with the path /, a maximum age of 2,592,000 seconds, SameSite=Lax and Secure on https.
  • A code is 1 to 40 letters, digits, _ and -, and its case is kept. A value that does not fit sets nothing. A long value is dropped whole, never cut.
  • A newer valid code replaces the older one.
  • While the program is off the storefront sets nothing, and the page does not load the code that would.
  • The order records the cookie when the customer pays, and that is how a referral finds its code. See How customers and orders are attributed.

The cookie is the only thing the storefront keeps for the program. It is set when a visitor opens a referral link, whatever they chose in the cookie banner, so name _ct_ref in the cookie list of your privacy policy.

  • A referred customer has one referral, whoever referred them.
  • A pass pays at most 200 referrals. The rest wait for the next hour.
  • A list returns at most 200 rows. offset pages through the rest.
  • A member can make 30 partner codes and void 60 referrals an hour. Past that, the API answers 429.
A referral did not start
Check the program is on, the order carried the code (the _ct_ref cookie was set when the customer paid), it was the customer's first paid invoice, a gateway took the money, and the total without tax reached threshold_amount. A referral that is refused before it starts leaves no row. The reason is in our logs as one of disabled, unknown_code, inactive_code, not_first_invoice, not_paid_by_gateway, below_threshold, no_exchange_rate, no_reward, or a word from What stops a referral.
A referral is void and nobody voided it
Read void_reason. It is one of the words in What stops a referral. Money is never paid for a voided referral.
A referral is still qualified after its hold
We pay once an hour, at most 200 at a time, and an organization that is not active waits. Check again in an hour.
409 when voiding
The referral is already credited or void. Read the list for its status.
422 on a save
The answer's field names the setting or input, and detail says what fits.

API operations on this page

MethodPathWhat it does
GET/api/v1/orgs/{org_slug}/referralsList the organization's referrals and what the program has paid
GET/api/v1/orgs/{org_slug}/referrals/settingsRead the referral program's settings
PUT/api/v1/orgs/{org_slug}/referrals/settingsChange the referral program's settings
GET/api/v1/orgs/{org_slug}/referrals/codesList referral codes, customers' and partners'
POST/api/v1/orgs/{org_slug}/referrals/codesMake a partner code for a customer
PATCH/api/v1/orgs/{org_slug}/referrals/codes/{code_id}Stop or restart a code, or change a partner's commission or label
POST/api/v1/orgs/{org_slug}/referrals/{referral_id}/voidVoid a referral that has not been paid
GET/api/v1/orgs/{org_slug}/staff/marketing/referralsList the organization's referrals and what the program has paid
GET/api/v1/orgs/{org_slug}/staff/marketing/referrals/settingsRead the referral program's settings
PUT/api/v1/orgs/{org_slug}/staff/marketing/referrals/settingsChange the referral program's settings
GET/api/v1/orgs/{org_slug}/staff/marketing/referrals/codesList referral codes, customers' and partners'
POST/api/v1/orgs/{org_slug}/staff/marketing/referrals/codesMake a partner code for a customer
PATCH/api/v1/orgs/{org_slug}/staff/marketing/referrals/codes/{code_id}Stop or restart a code, or change a partner's commission or label
POST/api/v1/orgs/{org_slug}/staff/marketing/referrals/{referral_id}/voidVoid a referral that has not been paid
GET/api/v1/orgs/{org_slug}/portal/referralsMy referrals