# Referrals

Each person who joins gets a link to share. You decide what they and their friends get.

## Referrals

Each person who joins gets a link to share (`?ref=<code>`). The project decides what both sides get when a friend joins through it. The line, Analytics' `referrals`, and People's `place` and `friends` follow from that.

Hunchwire records codes even while referrals are off, so links already shared work the day you turn them on.

A friend counts for the person who shared only once both have confirmed. An email confirms by the link Hunchwire sends. A number confirms when your product sends `confirmed` (see API).

People can share before they confirm. Until they do, their confirmed friends are pending, and nothing they'd earn applies: no places, milestones or access. It all applies the moment they confirm.

Referrals need confirmation emails. A project that can't send them (the free month, or no verified mail domain) earns no referral credit by email until it can (see Set up email). Sign-ups by number are unaffected. The friend's own side never waits: they start higher or get straight in when they join. Friends who counted before confirmation was required stay counted.

### Set up referrals

- `GET /projects/:id/referrals`: get the referral settings. *analytics*
  - Returns `enabled`, `hold`, `sharer`, `friend`, `milestones`, `deal`, `link` and `link_example`.
  - `deal`: what both sides get, in plain words, as the founder's screen says it.
  - `link`: the referral link on the founder's own site, with `{code}` where a person's code goes, or `null`.
  - `link_example`: a person's link as it reads now. Without `link`, it's the project's site with `?ref=<code>`.
  - `hold`: whether friends who look gamed wait for review before they count (see Review flagged friends). On for new projects.
  - `sharer`: what the person who shares gets.
    - `gets`: `nothing`, `move_up` (up the line by `places_per_friend` for each friend), `access` (once `friends_for_access` friends join) or `reward` (something the founder gives).
    - `places_per_friend`: at least 1. The default is 1.
    - `friends_for_access`: 1 to 100. The default is 3.
  - `friend`: what the friend who joins gets.
    - `gets`: `nothing`, `start_higher` (join `places` above the end of the line), `access` (straight in, see Let friends straight in) or `reward` (the founder gives them `reward`).
    - `places`: 1 to 1000. The default is 10.
    - `reward`: up to 140 characters, or `null`. Friends see nothing until it's written.
    - `access_limit`: how many friends of one person get straight in. 1 to 1000. The default is 10.
    - `access_from`: whose links let friends straight in. `anyone` on the list (the default) or only people `let_in`.
  - `milestones`: extra rewards for the sharer, fewest friends first. Each has `friends` (1 to 1000) and `reward` (up to 140 characters). Up to 10, each for a different number of friends. After joining, a person sees how many more friends they need for the next one.
- `PATCH /projects/:id/referrals`: change the referral settings. *manage*
  ```
  {"referrals": {"enabled": true, "sharer": {"gets": "move_up", "places_per_friend": 1}, "friend": {"gets": "reward", "reward": "20% off the first year"}, "milestones": [{"friends": 3, "reward": "Early access"}, {"friends": 10, "reward": "A free year"}]}}
  ```
  - Send any part. What you leave out stays.
  - `milestones` replaces the whole list. Send `[]` for none.
  - Before turning referrals on, ask the founder what each side gets. People see it the moment they join.
  - Turning referrals off hides places, links and lines from visitors. It doesn't change the line, so turning them on again shows the same places.
  - When people share a page on the founder's own site, send `"link": "https://yourapp.com/r/{code}"`. It must be a full address containing `{code}`. Send `""` to clear it.
  - The founder's own product reads each person's place, friends and link from the API (see API).

### Edit the share kit

The share kit is what people get to share after joining.

- `GET /projects/:id/setup/referrals/share-kit`: get the share kit. *analytics*
  - `headline`: shown on each person's share image. The default is the project's name.
  - `posts`: one per channel (`x`, `linkedin`, `reddit`, `email`). A post is the founder's words, or a default until they write one. An empty post means no button for that channel.
- `PATCH /projects/:id/setup/referrals/share-kit` with `{"share_kit": {"headline": "Habits that stick, together.", "posts": {"x": "I'm #{place} in line for Loop. Skip the line with my link: {link}", "reddit": ""}}}`: change the share kit. *manage*
  - Send any part. What you leave out stays.
  - `{link}` is the person's link. `{place}` is their place in line. It's empty when the line doesn't move, so don't use it then.
  - A post without `{link}` gets it at the end.
  - Up to 500 characters a post, and 80 for the headline.
  - Write posts the way someone would say it to a friend. The defaults are plain on purpose.

### Give rewards

- `GET /projects/:id/people/rewards?page=1`: list rewards earned, newest first, 50 a page. *emails*
  - Shows who is owed what, and whether the founder gave it.
  - Returns `total` (all of them), `page`, `per_page` and `rewards`. Ask for the next `page` while `page × per_page < total`.
  - `.csv` returns a file of every reward, unpaged.
  - The list is empty while referrals are off.
  - Each item in `rewards` has `email`, `reward` (`milestone:3`, `access` or `friend`), `label` (as the screen says it, like "3 friends · Early access"), `reached_at`, `given`, `given_at` and `given_by` (who marked it, `automatic` when a friend's link let them in, or `null`).
  - A milestone is reached when the person's Nth friend joins. `access` is reached when a sharer who gets access unlocks it. `friend` is reached when someone joins through a link and friends get access or a reward.
  - Give access with an invite (`POST /projects/:id/invites`, see Let people in). Once the person has one, the reward reads as given. A friend let in through a link has one already.
- `POST /projects/:id/people/rewards` with `email`, `reward` and `given` (`true`, the default, or `false`): mark a reward given, or undo that. *manage* and *emails*
  - Mark it once the founder has sent it. Only do this when the founder says they gave it.
  - Returns the reward. `404` for a reward that isn't earned.

### Let friends straight in

When friends get access, joining through a friend's link is the invite.

- The friend gets an invite the moment they sign up, with `via` `referral`. Hunchwire sends no confirmation email: the founder's own sign-up checks the address.
- From the form, they go straight to the Let people in address with a token. From the API, the sign-up's answer carries the invite, so your product can welcome them in its first reply.
- A friend who signs up by number gets access at sign-up, with no hand-off: there's no web sign-up by number. Check `access` when they first text you (`POST /v1/people` or `GET /v1/people?phone=`). That first text proves the number.
- On a first sign-up, it applies when the friend counts: not held for review and not rejected. A removed person's link lets no one in.
- Someone already on the list who signs up again through someone else's link is let in the same way, once they confirm. Their place and referrer don't change.
  - The link's owner gets credit for them, as for a friend who joined through it. They move up, and it counts toward milestones and access. It counts from the moment the sign-up is confirmed. Their referrer keeps their own credit.
  - A link that changes nothing earns no one anything. That's someone already in, or a link at its `access_limit`.
  - By email, Hunchwire sends a confirmation whose link carries the friend's code. Clicking it lets them in if the link still has room. From the form, it then sends them to the Let people in address. The project must be able to email its people (see Confirm sign-ups).
  - By number, send the sign-up again with `confirmed` and the `ref`. The answer carries the invite.
  - With `hold` on, a sign-up again from a browser the link's owner signed up from isn't let in.
  - A removed person who signs up again through a link comes back when they click, then is let in if the link allows.
- With `access_from` `let_in`, only the links of people the founder let in let friends in. Let in means the person has an invite, of any kind and in any state. A friend let in through a link counts too. Other people's friends still count for them but wait on the list, and the form promises nothing.
- Each person's link lets in up to `access_limit` people. It counts everyone let in through it, at sign-up or at confirmation. After that, friends still count for them but wait on the list, and the form stops promising to skip the wait.
- The form needs a Let people in address to send an email friend somewhere. Without one, they wait on the list and the founder invites them. The API needs no address.
- A friend approved later in Review flagged friends isn't let in by that. Invite them from **People › Rewards earned**.

### Review flagged friends

While `hold` is on, some friends wait for review. A friend waits when they signed up from a browser their referrer signed up from. Friends also wait when two or more of one referrer's friends signed up from one browser.

Until approved, they don't count for their referrer, or for their own reward.

- `GET /projects/:id/people/referrals/flagged?page=1`: list friends held for review, newest first, 50 groups a page. *emails*
  - Returns `total`, `page`, `per_page` and `flagged`.
  - Each item in `flagged` has `referrer`, `friends` (their emails; several from one browser are decided together), `reason` (`same_browser` or `one_browser`), `why` (as the screen says it) and `joined_at`.
- `POST /projects/:id/people/referrals/flagged` with `emails` (a list) and `decision` (`approved` or `rejected`): approve or reject held friends. *manage* and *emails*
  - Approved friends count at once. Rejected ones never count.
  - Only do this when the founder decided. Never approve or reject on your own judgement.
  - Returns `decision` and `friends`. `404` when none of the emails are waiting.

### How the line works

A person's place is their join position, minus:
- `places_per_friend` × friends, when sharers move up.
- The friend's `places`, when friends start higher.
- Places the founder or an agent moved them by hand (`moved`, in People).

The lowest number comes first. Removed people have no place. Ties go to whoever has more friends, then to a friend who started higher, then to whoever joined first.

When neither side moves anyone, the line is join order and visitors see no place.

A friend is someone whose first sign-up came through the link. A sharer's own sign-ups, and other spellings of their email, never count.
