Referrals
Share your code, earn credit when friends sign up and pay.
https://getsnap.dev/?ref=YOURCODE and anyone who signs up through that link
gets a discount on their first paid month. When they actually pay, we credit your Stripe
balance so your next invoice is smaller.
Overview
Every getSnap.dev account has a unique 8-character referral code. When
someone signs up through https://getsnap.dev/?ref=YOURCODE and later pays for a
subscription, two things happen:
- They get a discount on their first paid month via a Stripe coupon
(currently
REFERRED20, 20% off, applied automatically at checkout). - You earn credit on your Stripe balance (currently $5.00 per paid conversion), applied to your next invoice.
There's no cap on how many referrals you can send. There's no cap on how much credit you can accumulate. Credit rolls over from month to month until you use it.
How it works, step by step
-
You share your link. Grab your code from the dashboard above and share
https://getsnap.dev/?ref=YOURCODEanywhere — tweets, blog posts, Discord, email signatures, sticker on your laptop. -
They click. Landing on
getsnap.devwith?ref=CODEin the URL sets a first-party cookiegetsnap_refvalid for 30 days. The cookie sticks even if they close the tab and come back later. -
They sign up. When they create an account, we associate their new
api_keywith your referral code via thereferralstable withstatus = 'pending'. They can start on the free plan without triggering anything for you yet. -
They upgrade to a paid plan. At Stripe Checkout, the
REFERRED20coupon is applied automatically. They see the discounted price on the first invoice. -
Their first invoice succeeds. Stripe fires
invoice.paidto our webhook. We look up the pending referral, mark itpaid, and credit your Stripe customer balance by $5.00 viastripe.customers.createBalanceTransaction. This is atomic — either both state changes commit or neither does. - Your next invoice is smaller. Stripe automatically deducts your balance on the next billing cycle. No action needed on your end.
Reward mechanics
| Detail | Value |
|---|---|
| Reward amount | $5.00 USD per paid conversion (500 cents). Configurable
per-deployment via REFERRAL_REWARD_CENTS. |
| Referee discount | 20% off first month via Stripe coupon REFERRED20.
Applied automatically at checkout. |
| When it fires | On the first successful invoice.paid Stripe webhook event for the
referee's subscription. Typically arrives within seconds of payment success. |
| How it's paid | Stripe customer balance credit (negative balance transaction). Automatically deducted from your next invoice. Rolls over indefinitely. |
| Trials | A referral stays pending during the trial. It only becomes
paid when Stripe actually collects money. |
| Renewals | Only the first paid invoice per referred customer counts. Subsequent renewals do not create additional credits. |
| Refunds & chargebacks | Reward is not clawed back. If a referee gets a refund after paying, you keep the credit. |
| Downgrades | If a referee moves from paid back to free, existing credit stays in your balance. A future re-upgrade does not fire again. |
Attribution & cookies
Attribution is based on a first-party cookie set on the
getsnap.dev landing when someone lands with ?ref=CODE in the URL.
| Cookie | Value |
|---|---|
| Name | getsnap_ref |
| Value | The 8-character referral code (uppercase, alphanumeric). |
| TTL | 30 days from last click on a referral link. |
| SameSite | Lax |
| Secure | true (HTTPS only). |
| HttpOnly | false — readable from JS so we can attach it to the signup form. |
| Overwrite | Yes. Latest click wins. If someone clicks Alice's link, then Bob's link, Bob gets the credit if they sign up within 30 days. |
If a user has cookies disabled or arrives via a shared browser cache, we fall back to no-attribution — nobody gets credit. We deliberately avoid IP or fingerprint-based attribution because those are unreliable and privacy-hostile.
API reference
GET /v1/referrals
Returns your referral code, share URL, reward config, aggregate stats, and the individual referrals you've sent. Everything the dashboard above renders comes from this single call.
Headers
| Name | Required | Description |
|---|---|---|
X-API-Key | Yes | Your active, verified API key (any plan). |
Response fields
| Field | Type | Description |
|---|---|---|
referral_code | string | Your 8-character code. Assigned on first call if not set. |
referral_url | string | The ready-to-share URL: https://getsnap.dev/?ref=CODE. |
reward | object | Reward config for this deployment. |
reward.per_conversion_cents | integer | How many cents you earn per paid referral. Currently 500. |
reward.referee_discount | string | Human-readable discount phrase, e.g. "20% off first month". |
stats | object | Aggregate counts. |
stats.total | integer | Total referrals attributed to you (any status). |
stats.pending | integer | Signed up but haven't paid yet. |
stats.paid | integer | Paid and credited — money in your balance. |
stats.reverted | integer | Rare. Stripe credit call failed at webhook time (e.g. deleted customer). |
stats.total_earned_cents | integer | Sum of credits actually issued. stats.paid × reward.per_conversion_cents. |
referrals | array | Individual entries with status, created_at, credited_at. Sorted newest first, capped at 100. |
Example: cURL
curl https://api.getsnap.dev/v1/referrals \
-H "X-API-Key: sk_live_YOUR_KEY"
Example: Node.js SDK
import { getSnap } from "getsnap";
const snap = getSnap({ apiKey: process.env.GETSNAP_API_KEY });
const data = await snap.referrals();
console.log(`Code: ${data.referral_code}`);
console.log(`Earned: $${(data.stats.total_earned_cents / 100).toFixed(2)}`);
console.log(`Paid: ${data.stats.paid} / Pending: ${data.stats.pending}`);
Example: Python SDK
from getsnap import GetSnap
snap = GetSnap(api_key=os.environ["GETSNAP_API_KEY"])
data = snap.referrals()
print(f"Code: {data['referral_code']}")
print(f"Earned: ${data['stats']['total_earned_cents'] / 100:.2f}")
print(f"Paid: {data['stats']['paid']} / Pending: {data['stats']['pending']}")
Example: CLI
export GETSNAP_API_KEY=sk_live_YOUR_KEY
getsnap referrals
Sample response
{
"referral_code": "XHXWV5Z9",
"referral_url": "https://getsnap.dev/?ref=XHXWV5Z9",
"reward": {
"per_conversion_cents": 500,
"referee_discount": "20% off first month"
},
"stats": {
"total": 12,
"pending": 5,
"paid": 6,
"reverted": 1,
"total_earned_cents": 3000
},
"referrals": [
{ "status": "paid", "created_at": "2026-09-14T10:22:00Z", "credited_at": "2026-09-18T08:12:00Z" },
{ "status": "pending", "created_at": "2026-09-20T11:03:00Z", "credited_at": null }
]
}
Anti-abuse rules
The following restrictions apply to keep the program fair:
-
No self-referral. Signing up with your own referral code just drops the
cookie silently — no referral row is created. If it were, we'd catch it at
invoice.paidtime (sameuser_id) and skip the credit. -
One referral per referee. Enforced by a
UNIQUEconstraint onreferrals.referee_api_key_id. If someone deletes their account and re-signs up under the same email, a second referral cannot be attributed. -
Credit only on real money. We hook
invoice.paid, notcustomer.subscription.created. A trial that never converts never credits you. -
Coupon is server-set. Users cannot enter
REFERRED20manually at checkout — we attach it programmatically only when a referral is on file. - Suspicious patterns get reviewed. We manually investigate anomalies (e.g. one IP creating dozens of pending referrals). We reserve the right to void credit for obvious fraud, but this is rare enough that we've never had to do it.
Data model
For the curious: how this looks in the database.
-- api_keys stores the referrer's code
api_keys.referral_code -- 8 char, UNIQUE partial index, assigned lazily
-- referrals stores each attribution
referrals(
id INTEGER PRIMARY KEY,
referrer_api_key_id TEXT, -- who gets credited
referee_api_key_id TEXT UNIQUE, -- who gets discounted (only once)
referrer_code TEXT, -- denormalized for audit
status TEXT, -- 'pending' | 'paid' | 'reverted'
created_at TEXT, -- when the referee signed up
credited_at TEXT -- when webhook fired (nullable)
)
Stripe idempotency for the crediting flow lives in a separate
stripe_events(event_id UNIQUE) table so a retried
invoice.paid webhook cannot credit you twice.
FAQ
What counts as "paid"?
A referral becomes paid the first time your referee successfully pays an
invoice on a Stripe subscription. Trial signups that never convert to a real payment don't
count — this prevents credit-farming.
When do I get credited?
Within seconds of Stripe firing the invoice.paid webhook. Your Stripe
customer balance drops by the reward amount, and Stripe automatically deducts it from your
next invoice. There's nothing to click.
Can I withdraw the credit?
No. Referral credit is account credit, not cash. It sits on your Stripe customer balance and is applied automatically against future invoices, reducing what you are charged. It cannot be withdrawn, transferred or paid out, and it has no cash value.
The practical consequence: if you refer people but never subscribe to a paid plan, the credit accumulates and is never spent. It becomes worth something the moment you have an invoice for it to reduce.
Does it work if my referee subscribes through a Team?
Not today. A team subscription bills the team's own Stripe customer, which is not attached to any individual account, so the referral lookup finds nothing and no credit is issued.
If you are referring someone who intends to use Teams, have them start on a personal Starter or Pro subscription first — that payment earns the credit — and create the team afterwards. We would rather tell you this than let you wonder why a conversion never paid out.
What if they get refunded?
If a paid referral is refunded later, the referral stays as paid in your
stats and no credit is reversed. In practice this is rare enough that we don't try to claw
back credit — you keep what was earned.
Can I see who signed up under my code?
No — for privacy reasons. You see aggregate counts and per-referral status/timestamps,
but never the referee's email or API key. If you want richer attribution (e.g. UTM tags,
landing page tracking), do that on your own domain before you send traffic to
getsnap.dev.
Does referral credit stack with other discounts?
The REFERRED20 coupon replaces any other checkout-time discount for the first
month. Your Stripe balance credit is applied on top of whatever coupon is active on the
invoice, so effectively yes — but not for the same invoice.
How long does attribution last?
30 days from the last click on your link. If someone clicks today and pays 45 days later, no credit. If they click again on day 29 (or any day after), the cookie's TTL rolls forward.
Can I change my referral code?
Not currently self-service. If your code was auto-generated to something awkward, email
support@getsnap.dev and we'll rotate it. Existing
pending referrals stay attached to your account regardless.
What if credit fails to apply?
Marked as reverted in your stats. The most common cause is a deleted Stripe
customer (rare). You can reach out to support and we'll manually reissue the credit.
Programmatic access
The dashboard is a thin wrapper over
GET /v1/referrals.
All SDKs (Node, Python, CLI) expose it as a top-level referrals() call.
There are no separate endpoints for "referrer stats" and "individual referrals" — one
call gets everything.