# Concepts

The objects an affiliate program is made of, and the lifecycle a referral moves through.

The dashboard, the API and the MCP server all use the same small set of objects. This page names
each one and follows a referral from first click to payout.

Three conventions hold everywhere:

- **Ids carry a prefix**, so you can tell what you're holding: `prg_` is a program, `part_` a partner, `com_` a commission.
- **Money is a whole number of the smallest unit**, like cents or pence, beside its currency. So 2000 in USD is $20.00.
- **Rates are basis points**, hundredths of a percent. So 2000 means 20%.

## The cast

**Program** (`prg_`). Your affiliate program, with its currency, cookie window, commission defaults,
portal branding and terms. One organization can run several.

**Partner** (`part_`). A person or company promoting you. A partner is `pending` while waiting for
review, then `active`, `declined` or `suspended`, and belongs to at most one **group** with any
number of **tags**. A partner who has been paid, or has a payout on its way, can't be deleted, only
suspended, so their payout history stays.

**Group.** A tier of partners with its own terms. For example: agencies at 30%, everyone else at 20%.

- A group decides what its partners earn and whether you review them first.
- Each group has its own signup link, so people land in the right tier on their own.

**Tag.** A label for finding partners again. Use tags to filter your list, and to point campaigns,
notifications and resources at the right partners. A tag never changes what a partner earns. Groups do that.

**Link and coupon.** A partner's ways in.

- A link is `yoursite.com/?ref=handle`. Add a short-link domain and `refer.yoursite.com/handle` works too.
- A coupon is a Stripe promotion code tied to a partner. A sale that uses it is credited to that partner, even with no click.

**Click** (`clk_`). One visit through a partner link. It records the landing page and where the
visitor came from. It also stores how long it keeps the credit for the partner (the attribution
window), which is fixed the moment the click happens and never recalculated. The default is 60
days. Inside it, the first partner to send the visitor gets the credit.

**Referral.** The thread from visit to money. It starts as a visit, may become a lead, and turns
converted when the customer first pays. Partners see the same steps in their portal, including how
each referral was credited, so they never have to take tracking on trust.

**Customer** (`cus_`). A referred customer, tied to the partner who referred them. A customer has
one of six statuses: lead, trial, active, cancelled, refunded, suspended.

**Sale** (`sale_`). One payment, with amount, tax and currency. By default we work out
commission on revenue after tax, so you never pay a percentage of the VAT you collected for the tax
office.

**Commission** (`com_`). What a sale earned a partner. Its status is `pending` (waiting for
approval), `approved`, `due` (matured and payable), `paid`, `rejected` or `voided`. It also
records the commission rule and branch that set its amount.

What a refund does depends on where the money is:

- **Not paid yet:** the commission is voided.
- **In a payout that hasn't gone out:** the payout shrinks to what's left, or is removed if nothing is.
- **Already sent, or on its way:** the commission stays, as a record of money that moved. We add a clawback instead. A **clawback** is a negative line against the partner's next balance.

A partial refund is your call. Let's say a $500 sale earned a $100 commission and you refund $50 of it: turn on **Partial refunds take back the same share** in **Settings**, under **Commissions**, and the commission drops by the same 10% to become $90. If it's already been paid, the partner gets a $10 clawback instead. Leave it off, which is the default, and any refund removes the whole $100.

**Commission rule** (`flw_`). What decides how much a sale earns. It has a trigger, an ordered list
of branches (each a condition and a rate), and a fallback rate. Rules sort by priority, and when
more than one could price a sale, the first rule that applies wins it. The id keeps its old `flw_` prefix, because changing it would rewrite
every commission's history. [Commission rules](/guides/rules) covers them in full.

**Payout** (`pyt_`) **and payout batch.** When a period closes, commissions that have matured add
up into one payout per partner per currency.

- It's sent on your NET term: 15, 30 or 60 days after the period ends.
- A partner who can't be paid is never dropped quietly. Their payout row exists as `not_eligible`, with the reason: no payout method, a missing tax form, or a balance under the minimum.
- You and the partner both see that reason.

## The lifecycle, end to end

1. A visitor lands through `?ref=alice`. The script records a **click** and sets the referral cookie.
2. They sign up. The **referral** becomes a lead. If you add them as a **customer** now, they're already tied to Alice.
3. They pay. Stripe tells us, and we record the **sale**.
4. Your commission rules price the sale into a **commission** for Alice.
5. The commission waits out your holding period, 14 days by default. That's your buffer for refunds.
6. You approve it, or your commission rule approves it for you. Once it matures, it's **due**.
7. The period closes, the NET term runs, and the commission goes into a **payout**. Your own PayPal or Wise account pays it.

Each step shows up in three places:

- It can send a message to your own server the moment it happens. That message is a [webhook event](/api/webhooks).
- You can read it over the [API](/api).
- The partner sees it in their portal.

## Live and test

Connect a test-mode Stripe account and the whole lifecycle runs on test data.

API keys come in two kinds, `rail_live_` and `rail_test_`. Every API response says which kind made the call. Both read and write the same data. The prefix labels the key. It doesn't separate the rows.

Attribution works the same in test mode. One thing changes: a sale Stripe reports as test mode is
marked as a test, and a marked sale never pays anybody. It shows up. It never becomes money.
