← Referral Loop Audit / API
Tokens

Drive Referral Loop Audit from your own code

The page does its free work in the browser: it reads a pasted referral or affiliate program and its context, names the program type, finds the four stages of the referral loop (trigger moment, share action, converting the referred friend, the reward) with the line that shows each, prices the reward per referred customer against the maximum reward (LTV x gross margin - CAC), computes the referral rate, referrals per referrer and the K-factor, and raises flags RF-01..RF-20. Its two paid lanes are available over HTTP. You send one JSON object with task set to "audit" or "design", and the model replies with one JSON object. The easiest way to build the facts string is the page itself: Refkit.buildInput(lane, Refkit.analyze(program, {context, type, question}), {auditHandoff}) in refkit.js, which also runs under Node.

Base URL: https://api.skillsafe.ai/v1/app-api. Every call sends Content-Type: application/json and, once you have a token, Authorization: Bearer <token>. Both lanes run on gpt-terra with a 10% publisher markup. A run needs a signed-in (user) token and is metered: the platform holds the estimate's hold_credits while the run is in flight and then charges only what it used (charged_credits). /estimate is free. A plain-text summary is at /llms.txt.

The response envelope

Every response is {"data": ..., "error": null} on success or {"data": null, "error": {"code", "message"}} on failure.

Error codes

HTTPcodemeaning
400VALIDATION_ERRORThe body is not a JSON object, or a field is the wrong type. Every field of the run input is a string.
401UNAUTHORIZEDNo token, or an expired one: get a new one (step 2).
402INSUFFICIENT_CREDITSThe balance is below the run's minimum. Top up at skillsafe.ai/account/billing/.
403FORBIDDENA guest token tried a metered run: sign in for a personal token.
404NOT_FOUNDUnknown job id.
429RATE_LIMITEDBack off and retry with the same Idempotency-Key.

The task field: two lanes

taskwhat the model does
"audit"The program audit: the type and stage; the viral fit (natural, limited or unclear, with product-embedded mechanisms that fit); the four loop stages (trigger, share, convert, reward) each strong, weak or missing with a finding and a fix; the reward against the economics (the page's maximum reward and reward cost, within, over or unknown); the numbers; fraud protection and the gaps left open; the issues as finding, impact and fix with the page's flag ids; 3 to 6 fixes; a verdict ship, fix_first or redesign.
"design"The program: the type; product-embedded mechanisms when the product spreads by use; 1 to 3 trigger moments; the share mechanism and a pre-written message; the reward (structure, referrer, friend, framing, when it is paid, cap, within the maximum); the landing for the referred friend; 3 to 5 program emails; 3 to 6 fraud rules; affiliate terms; 3 to 6 metrics; 2 to 4 experiments; a launch checklist.

Input fields (all strings)

fieldwhencontent
taskrequiredaudit or design
programrequiredThe program, verbatim. Past 6,000 characters the page cuts the middle on line boundaries and leaves a [referral-loop-audit: ...] marker.
factsrequiredA JSON string: program (type, basis, stage, audience), economics (price, price_period, ltv, margin_pct, cac, cac_kind, max_reward, reward_value, reward_vs_max_pct), reward (found, sided, timing, types, referrer, friend, commission), viral, loop (trigger, share, convert, reward: found, evidence, note), found, protection, nurture, terms, counts, metrics, flags, notes. It is Refkit.factsOf(A).
contextoptionalThe product, the price, LTV, gross margin, CAC and the program's numbers. Cut past 4,000 characters.
program_typeoptionalreferral, affiliate or both, when the user chose it.
questionoptionalWhat the user wants to know.
audit_handoffdesign onlyA JSON string of an audit's type, verdict, max_reward, missing[] (loop stages), issues[{flag, finding, fix}] and fixes[], for the same input.
retry_noteoptionalOnly on a reformat retry: what was wrong with the previous reply.

The reply contracts

Both lanes share an envelope: task, headline, questions[], summary.

task: "audit"

program{type: referral|affiliate|both, stage: running|planned, why}, viral_fit{potential: natural|limited|unclear, mechanisms[], why}, loop[{stage: trigger|share|convert|reward, status: strong|weak|missing, finding, evidence[], fix}] (exactly four, in order), economics{max_reward, reward_cost, verdict: within|over|unknown, read}, numbers{read}, protection{status: strong|weak|missing, gaps[], fix}, issues[{flag, kind: incentive|economics|loop|fraud|performance|measurement|affiliate, severity: high|medium|low, finding, impact, evidence[], fix}], fixes[] (3 to 6), verdict (ship|fix_first|redesign).

task: "design"

source (audit handoff|from the input), program{type, why}, viral{potential, mechanisms[{mechanism: powered_by|exposure_loop|social_sharing|embed|watermark, how}]}, trigger_moments[{moment, where, why}] (1 to 3), share{mechanism: in_product|personal_link|email_invite|social|code, message, steps}, reward{structure: double_sided|single_sided|tiered, referrer, friend, framing, paid_when, cap, within_max: yes|no|unknown}, landing{headline, body, cta}, emails[{when, subject, body, cta}] (3 to 5), fraud_rules[] (3 to 6), affiliate{commission, cookie, buyout, recruit[], enablement[]}, metrics[{metric, definition}], experiments[{test, hypothesis, metric}] (2 to 4), launch_checklist[].

Worked examples

These are the page's own bundled examples (invented products and numbers), with the input as app.js builds it and the saved model reply the page replays for free.

Audit: a coffee subscription that pays $15 a side at signup, with the ask under Billing

Input (program and facts shortened here):

{
 "task": "audit",
 "program": "Tamperlee refer-a-friend program (running since March):\n\nWhere it lives: a \"Refer a friend\" link on the Account page, under Billing. It is not shown anywhere else in the app or in our emails.\nHow people share: copy your referral code (TL-XXXX) and send it however you like. There is no share link and no message to send.\nWhat your friend sees: the code works at checkout on the regular homepage; the page does not say wh... (568 characters in all)",
 "facts": "(a JSON string; decoded: referral program, 4 of 4 loop stages found (trigger, share, convert, reward), maximum reward $17, reward cost $30, metrics referral_rate 6.49, per_referrer 0.67, signup_conversion 22.4, k_factor 0.04, flags RF-03, RF-08, RF-01, RF-05, RF-07, RF-11, RF-12, RF-14, RF-18)",
 "context": "Tamperlee - a specialty coffee subscription for home brewers (B2C). A bag is $24 and ships every month.\nAverage customer LTV is $180, gross margin is 40%, and our blended CAC from paid social is $55.\nLast 90 days: 9,400 active subscribers; 610 subscribers shared their code; 1,830 friends signed up with a code; 410 became paying subscribers.\nAbout 30% of code signups cancel before their first bag ships.\n",
 "question": "Why do so few subscribers refer anyone?"
}

Reply:

{
 "task": "audit",
 "program": {
  "type": "referral",
  "stage": "running",
  "why": "A refer-a-friend program for subscribers, running since March, with a code and a reward on both sides and no affiliates."
 },
 "viral_fit": {
  "potential": "unclear",
  "mechanisms": [],
  "why": "A home coffee subscription is not used in front of non-users the way a collaboration or communication tool is, so the program has to carry the referrals."
 },
 "loop": [
  {
   "stage": "trigger",
   "status": "weak",
   "finding": "The only ask is a link on the Account page under Billing, never shown at a moment of value.",
   "evidence": [
    "Where it lives: a \"Refer a friend\" link on the Account page, under Billing.",
    "It is not shown anywhere else in the app or in our emails."
   ],
   "fix": "Ask right after a high-intent moment, such as a delivered bag or a renewal, in the app and in email."
  },
  {
   "stage": "share",
   "status": "weak",
   "finding": "Sharing means copying a code and writing your own message, with no link and nothing pre-written.",
   "evidence": [
    "How people share: copy your referral code (TL-XXXX) and send it however you like.",
    "There is no share link and no message to send."
   ],
   "fix": "Give each subscriber a personal link with a one-click, pre-written message, and keep the code for offline use."
  },
  {
   "stage": "convert",
   "status": "weak",
   "finding": "The friend lands on the regular homepage and only sees the offer at checkout, with no sign of who invited them.",
   "evidence": [
    "What your friend sees: the code works at checkout on the regular homepage; the page does not say who sent them."
   ],
   "fix": "Send the friend to a referral landing page that names the referrer and shows the $15 off their first bag up front.
... (shortened here; the page shows it whole)

Design: the same program, carrying the audit

Input (with the audit handed over):

{
 "task": "design",
 "program": "Tamperlee refer-a-friend program (running since March):\n\nWhere it lives: a \"Refer a friend\" link on the Account page, under Billing. It is not shown anywhere else in the app or in our emails.\nHow people share: copy your referral code (TL-XXXX) and send it however you like. There is no share link and no message to send.\nWhat your friend sees: the code works at checkout on the regular homepage; the page does not say wh... (568 characters in all)",
 "facts": "(a JSON string; decoded: referral program, 4 of 4 loop stages found (trigger, share, convert, reward), maximum reward $17, reward cost $30, metrics referral_rate 6.49, per_referrer 0.67, signup_conversion 22.4, k_factor 0.04, flags RF-03, RF-08, RF-01, RF-05, RF-07, RF-11, RF-12, RF-14, RF-18)",
 "context": "Tamperlee - a specialty coffee subscription for home brewers (B2C). A bag is $24 and ships every month.\nAverage customer LTV is $180, gross margin is 40%, and our blended CAC from paid social is $55.\nLast 90 days: 9,400 active subscribers; 610 subscribers shared their code; 1,830 friends signed up with a code; 410 became paying subscribers.\nAbout 30% of code signups cancel before their first bag ships.\n",
 "question": "Why do so few subscribers refer anyone?",
 "audit_handoff": "{\"type\":\"referral\",\"verdict\":\"redesign\",\"max_reward\":\"$17\",\"missing\":[],\"issues\":[{\"flag\":\"RF-03\",\"finding\":\"The reward costs $30 per referred customer, above the $17 maximum (LTV x gross margin - CAC).\",\"fix\":\"Cut the combined referrer and friend reward below $17, or tie part of it to product value such as a free bag ..."
}

Reply:

{
 "task": "design",
 "source": "audit handoff",
 "program": {
  "type": "referral",
  "why": "Tamperlee is a B2C coffee subscription with no partners or affiliates named, so a refer-a-friend program between subscribers fits."
 },
 "viral": {
  "potential": "unclear",
  "mechanisms": []
 },
 "trigger_moments": [
  {
   "moment": "Right after a bag is delivered",
   "where": "The delivery confirmation screen in the app and the delivery email",
   "why": "A fresh bag is the moment a home brewer feels the value and wants to tell a friend."
  },
  {
   "moment": "Right after a renewal",
   "where": "The renewal confirmation page and its receipt email",
   "why": "A subscriber who just chose to stay is at high intent to recommend Tamperlee."
  },
  {
   "moment": "After a support conversation rated as great",
   "where": "The support follow-up email",
   "why": "Great support leaves the customer happy and open to sharing."
  }
 ],
 "share": {
  "mechanism": "personal_link",
  "message": "I get my coffee from Tamperlee and it is the best I have brewed at home. Here is $8 off your first bag: [referral link]",
  "steps": "The subscriber clicks Share, picks email, text or social, and sends the pre-written message with their personal link already in it."
 },
 "reward": {
  "structure": "double_sided",
  "referrer": "$8 in Tamperlee credit toward their next bag",
  "friend": "$8 off their first bag",
  "framing": "Give $8, get $8: your friend gets $8 off their first bag and you get $8 credit when it ships.",
  "paid_when": "After the friend's first paid bag ships, never at signup.",
  "cap": "[monthly referral cap] rewarded referrals per referrer per month and [lifetime referral cap] per lifetime",
  "within_max": "yes"
 },
 "landing": {
  "headline": "[referrer name] sent you $8 
... (shortened here; the page shows it whole)

Audit: a B2B form builder's affiliate program, 40% for life and a 7-day cookie

Input:

{
 "task": "audit",
 "program": "Fillowby affiliate program\n\nWho: bloggers, YouTubers and agencies who write about no-code tools. Anyone can join from the \"Affiliates\" link in our site footer.\nCommission: 40% recurring commission for the lifetime of every customer you refer.\nCookie: 7-day cookie.\nTracking and payouts: through Rewardful, paid monthly by PayPal 30 days after the customer's payment; refunded payments are clawed back.\nAssets: a logo pac... (515 characters in all)",
 "facts": "(a JSON string; decoded: affiliate program, 4 of 4 loop stages found (trigger, share, convert, reward), maximum reward $306, reward cost $248, metrics active_affiliates_pct 14.62, per_referrer 4.77, referred_share 11.75, flags RF-05, RF-11, RF-15, RF-16, RF-14, RF-17, RF-18, RF-19)",
 "context": "Fillowby - a form and survey builder for small businesses and agencies (B2B SaaS). Pro is $29/month.\nLTV is about $620, gross margin 80%, target CAC $190.\nEvery published form is seen by the people who fill it in.\nLast quarter: 212 affiliates signed up; 31 referred at least one customer; affiliates brought 148 new paying customers out of 1,260 new customers in total.\n"
}

Reply:

{
 "task": "audit",
 "program": {
  "type": "affiliate",
  "stage": "running",
  "why": "Fillowby pays bloggers, YouTubers and agencies a recurring commission tracked through Rewardful, with no reward for customers who refer."
 },
 "viral_fit": {
  "potential": "natural",
  "mechanisms": [
   "powered_by",
   "embed"
  ],
  "why": "Every published form is seen by the people who fill it in, yet no badge or embed turns those viewers into visitors."
 },
 "loop": [
  {
   "stage": "trigger",
   "status": "weak",
   "finding": "The only way in is a footer link, so the ask never appears at a moment of value.",
   "evidence": [
    "Anyone can join from the \"Affiliates\" link in our site footer."
   ],
   "fix": "Invite agencies and power users to the program inside the app after a milestone, such as their first published form, and keep the footer link as an extra place."
  },
  {
   "stage": "share",
   "status": "weak",
   "finding": "Affiliates get a tracked link but only a logo pack and one paragraph, with no pre-written message or content to share.",
   "evidence": [
    "Assets: a logo pack and a one-paragraph product description."
   ],
   "fix": "Add pre-written posts, an email template, screenshots and a demo video to the affiliate kit."
  },
  {
   "stage": "convert",
   "status": "weak",
   "finding": "Referred visitors see the regular pricing page, so the affiliate's endorsement is lost.",
   "evidence": [
    "Referred visitors land on the regular pricing page."
   ],
   "fix": "Send affiliate traffic to a landing page that names the affiliate and what the visitor gets."
  },
  {
   "stage": "reward",
   "status": "weak",
   "finding": "A 40% commission for the customer's lifetime has no end and no buyout, and sits above the skill's typical 10-25% recurring range
... (shortened here; the page shows it whole)

Design: a newsletter platform, from a rough idea

Input:

{
 "task": "design",
 "program": "We want to start a referral program for Letterwick and have nothing yet. Rough idea:\n\n- Give writers 1 month free for every friend who signs up\n- Put a \"Refer a friend\" page in Settings\n- Friends would sign up on the normal signup page\n",
 "facts": "(a JSON string; decoded: referral program, 3 of 4 loop stages found (trigger, convert, reward), maximum reward $105, reward cost $12, metrics none, flags RF-01, RF-02, RF-05, RF-08, RF-11, RF-13, RF-14, RF-18, RF-19)",
 "context": "Letterwick - a newsletter platform for independent writers. The Creator plan is $12/month, billed monthly; writers pay for themselves.\nLTV $260, gross margin 75%, CAC $90 from search ads.\nEvery newsletter issue a writer sends goes out to their readers.\n4,800 paying writers today.\nWriters who stay usually publish their 3rd issue in the first month.\n",
 "program_type": "referral"
}

Reply:

{
 "task": "design",
 "source": "from the input",
 "program": {
  "type": "referral",
  "why": "You chose a referral program, and the context names writers referring writers, not partners or affiliates."
 },
 "viral": {
  "potential": "natural",
  "mechanisms": [
   {
    "mechanism": "powered_by",
    "how": "Add a small \"Powered by Letterwick\" line to the footer of every newsletter issue, linking to the writer's personal referral link."
   },
   {
    "mechanism": "exposure_loop",
    "how": "Readers who want their own newsletter land on a page that says which writer they came from and offers them the same free month."
   }
  ]
 },
 "trigger_moments": [
  {
   "moment": "Right after a writer publishes their 3rd issue",
   "where": "The post-publish confirmation screen",
   "why": "Writers who stay usually publish their 3rd issue in the first month, so this is the milestone where they have seen the value."
  },
  {
   "moment": "Right after a writer's monthly renewal goes through",
   "where": "The renewal receipt email",
   "why": "A renewal is a fresh signal the writer chose to keep paying for Letterwick."
  },
  {
   "moment": "After a support ticket is closed with a good rating",
   "where": "The support follow-up email",
   "why": "A writer who just got great support is most willing to recommend the product."
  }
 ],
 "share": {
  "mechanism": "personal_link",
  "message": "I write my newsletter on Letterwick and like it. Use my link to get your first month of the Creator plan free: [referral link]",
  "steps": "The writer clicks Copy link or Send by email on the share card, with the message already filled in."
 },
 "reward": {
  "structure": "double_sided",
  "referrer": "1 month free ($12 credit) for each friend who pays for their first month",
  "friend": "Fi
... (shortened here; the page shows it whole)

The page re-checks the reply; the API does not

The page holds every reply to account (recon.js): for an audit, the program type you chose; four loop stages in order, none called present that the page found absent without a quote, none called strong that a flag faults; the maximum reward and the reward cost equal to the page's arithmetic and "over" exactly when the reward is above the maximum; fraud protection never present when the page found none; every high and medium flag carried and a high one never downgraded; redesign when the reward is over the maximum or two stages are missing, and no "ship" while a high flag or three medium flags stand. For a design, no trigger moment at signup and not only in settings; a pre-written share message; a reward paid after the friend buys, inside the maximum, framed in dollars on a low price; a landing with a call to action; 3 to 5 emails with the launch first; 3 to 6 fraud rules with a delayed payout or verification; affiliate terms with an end or a buyout; referral rate among the metrics; experiments with metrics; the handed-off audit's missing stages designed. In both, quotes are checked word for word and no count, rate, price or window may be invented beyond the skill's constants. Over the API you get the model's reply as it is; run the same checks yourself with Recon.reconcile in recon.js, or paste the same input into the page.

Step 1 — a tiny client helper

One function that sends JSON and unwraps the envelope.

BASE="https://api.skillsafe.ai/v1/app-api"
TOKEN="paste-your-token-here"   # from https://referral-loop-audit.skillsafe.ai/tokens.html
api() { # api METHOD PATH [JSON-BODY]
  curl -s -X "$1" "$BASE$2" -H "Content-Type: application/json" \
    ${TOKEN:+-H "Authorization: Bearer $TOKEN"} ${3:+--data "$3"}
}

Step 2 — a token

A guest token is enough for /me and /estimate. A run is metered, so it needs a personal token: sign in on /tokens.html and copy it from there.

# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN=$(curl -s -X POST "$BASE/guest" -H "Content-Type: application/json" -d '{"slug":"referral-loop-audit"}' | jq -r '.data.token')

Step 3 — GET /me

Who the token is (subject_type: user or guest) and the credit balance.

api GET /me | jq '.data | {subject_type, credits}' 

Step 4 — POST /estimate

Free. The body is the run input itself (not wrapped in {"input": ...}). hold_credits is a reservation, not the price; min_credits is what the balance must cover; model reads gpt-5.6-terra and model_alias gpt-terra.

# input.json: the run input object - {"task": "audit", "program": "...", "context": "...", "facts": "..."}
api POST /estimate "$(cat input.json)" | jq '.data | {hold_credits, min_credits, model, model_alias, markup_bps, warnings}' 

Step 5 — POST /run, then poll the job

Send an Idempotency-Key built from the lane and the input: a retry with the same key never bills twice. The page uses referral-loop-audit:<lane>:<inputHash>:a<attempt>. The job's output.output is the reply text; truncated: true means the balance cut it short.

KEY="referral-loop-audit:audit:$(shasum -a 256 input.json | cut -c1-16):a1"
JOB=$(curl -s -X POST "$BASE/run" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $KEY" --data @input.json | jq -r '.data.job_id')
while :; do
  J=$(api GET "/jobs/$JOB"); S=$(echo "$J" | jq -r '.data.status')
  case "$S" in succeeded|failed|cancelled) break;; esac; sleep 2
done
echo "$J" | jq -r '.data.output.output' > reply.json   # one JSON object, the lane's contract
echo "$J" | jq '.data | {charged_credits, truncated}' 

Step 6 — POST /run-stream (design)

The same run as Server-Sent Events. design.json is a design input, with audit_handoff when it follows an audit.

# Server-Sent Events: tick/delta events while the job runs, then a final event with the job
curl -N -s -X POST "$BASE/run-stream" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: referral-loop-audit:design:$(shasum -a 256 design.json | cut -c1-16):a1" --data @design.json