← In Perpetuity
In Perpetuity API
Tokens

Drive In Perpetuity from your own code

Both metered lanes are available over HTTP: the term review (a brand's offer read clause by clause, with a sign / counter / walk-away verdict and what to ask for) and the counter email (the reply a creator sends back: accept, counter or decline, with line items and a total ask). A natural use is a creator's inbox helper or a talent-manager tool: your code sends the offer, the term sheet and the page's quote, and gets back a structured review or a ready-to-paste email.

The division of labour first: the page reads and prices; the model judges and writes; the page re-checks every quote and figure the model gives. Reading the offer into terms, the rule-of-thumb add-ons on the creator's base rate (all estimates, not market data), the flags and the page's verdict come from dealkit.js, which runs in node as well as in the browser. Its check function holds each reply to the offer: a clause quote must be the offer's own words, a deal-breaker the page flagged must be answered, line items must add up to the total, and the total must be at or above the brand's offer and the creator's minimum. Not legal advice.

Get a token on the token page (step 2 below also shows how to mint a guest token in code).

Base URL and the envelope

Every endpoint lives under https://api.skillsafe.ai/v1/app-api, and every response uses one envelope:

{ "ok": true,  "data":  { ... } }
{ "ok": false, "error": { "code": "...", "message": "...", "status": 402, "details": { ... } } }

The token is minted for this app (the guest call takes {"slug":"in-perpetuity"}), so no slug header is needed afterwards. Send it as Authorization: Bearer …. The run body is the input object, sent bare: never wrap it as {"input": {…}}.

StatusCodeMeaning
400validation_errorThe body is not a JSON object, or task / offer is missing.
401unauthorizedNo token, or a stale one. Mint a guest token or sign in again.
402insufficient_creditsThe balance is under min_credits. Price with /estimate first.
403forbiddenA guest token tried to run: both lanes are metered and need a personal token.
404not_foundUnknown job id.
429rate_limitedBack off and retry.
5xxserver_errorTransient. Retry with the same Idempotency-Key so a retry never double-bills.

The task field comes first

Every run sends task: review or counter. Both share the offer fields; the counter lane adds its own. The model follows only the named task's contract.

TaskVerdictsReply fields
reviewsign (fair as written), counter (workable once the asks are met), walk (a deal-breaker, or pay so far under the estimate that a counter would have to more than double it)title, verdict, summary, clauses [{quote, topic, level: ok|negotiate|walk, note, ask}], missing [{term, why}], asks [{ask, priority: must|nice}], numbers (strings)
counteraccept (yes, with the terms restated in writing), counter (changed terms and a price), decline (a polite no naming what would change it)title, verdict, summary, subject, email (plain text), line_items [{item, offered, asking, why}], total_ask (number or null), walk_away, trades (strings), followup

Clause topics: deliverables, fee, usage, paid_ads, whitelisting, exclusivity, revisions, payment, raw_footage, hooks, timeline, rights, ai_likeness, disclosure, kill_fee, other. The declared input schema carries scalars only, so object-valued fields travel JSON-encoded as strings (DealKit.toWire does this). The schema requires task and offer.

Input fields

FieldLaneTypeNotes
taskbothstringreview or counter.
today, creator, brandbothstringYYYY-MM-DD; names as typed (may be empty).
currency, base_ratebothstringUSD, EUR, GBP, CAD or AUD; the creator's rate for one video with 30 days of organic use (may be empty).
offerbothstringThe brand's message verbatim; past 6,000 characters the middle is cut with a marker.
termsbothstring (JSON){videos, fee, usage, usage_months, whitelisting, exclusivity_months, revision_rounds, payment_days, raw_footage, extra_hooks, rush}; unknowns are "not stated", endless ones "perpetual" / "unlimited".
quotebothstring (JSON){currency, base_rate, videos, base_total, add_ons: [{item, pct, amount}], estimate, floor, stretch, walk_line, offered, offered_share, figures_are_estimates}; money fields null without a base rate.
page_flags, page_verdictbothstring (JSON), string[{level, topic, text}] with level fix / warn / info; sign, counter or walk.
tonecounterstringwarm, direct or brief.
floorcounterstringThe creator's own minimum (may be empty) - not the quote's floor.
mustscounterstringTerms the creator will not move on (may be empty).
askscounterstringOne a line, each starting MUST: or NICE: - the review's asks (DealKit.asksToText), or empty.
retry_notebothstringOnly on a reformat retry.

The reply

The job's output.output is a string holding one JSON object. Parse it with DealKit.parseReply, then normalize(reply, task), then check(reply, state, task), which returns {notes, marks}: the page's notes (info, warn) shown under "Checked by the page", and for a review, each clause's span in the offer (null when its quote is not the offer's own words).

Worked examples

Replies produced against the app's prompt for the sample offers (made up; lists shortened, emails folded; the full replies ship in example-result.js). Together they cover every verdict. The page replays each of them free from its sample buttons.

task: review - skincare serum - sign

Input:

{
 "task": "review",
 "today": "2026-10-20",
 "creator": "Maya R.",
 "brand": "Glowbird Skin",
 "currency": "USD",
 "base_rate": "300",
 "offer": "Hi Maya!\n\nWe love your skincare content and would like to work with you on the launch of our new Dew Drop seru ... (706 characters)",
 "terms": "{\"videos\":2,\"fee\":1050,\"usage\":\"paid\",\"usage_months\":3,\"whitelisting\":false,\"exclusivity_months\":0,\"revision_rounds\":1,\"payment_days\":30,\"raw_footage\":false,\"extra_hooks\":2,\"rush\":false}",
 "quote": "{\"currency\":\"USD\",\"base_rate\":300,\"videos\":2,\"base_total\":600,\"add_ons\":[{\"item\":\"Paid-ad usage, 3 months\",\"pct\":0.5,\"amount\":300},{\"item\":\"2 extra hooks\",\"pct\":0.3,\"amount\":180}],\"estimate\":1080,\"floor\":918,\"stretch\":1296,\"walk_line\":540,\"offered\":1050,\"offered_share\":0.97,\"figures_are_estimates\":true}",
 "page_flags": "[]",
 "page_verdict": "sign"
}

Reply:

{
 "task": "review",
 "title": "Glowbird Dew Drop Serum Launch Deal",
 "verdict": "sign",
 "summary": "This is a solid offer: the $1,050 fee lands close to the page's $1,080 estimate for two videos with three months of paid-ad usage and two extra hooks, well above the page's floor. There's no exclusivity, payment is net 30, and a 50% kill fee covers the creator if Glowbird cancels after filming. The one open point is what happens if Glowbird wants to keep the ads running past the three-month window, and the offer never says who handles the paid-partnership disclosure label. Sign as written, but get the renewal fee and the disclosure responsibility confirmed in writing first.",
 "clauses": [
  {
   "quote": "2 UGC videos (30-45 seconds, vertical), plus 1 extra hook per video.",
   "topic": "deliverables",
   "level": "ok",
   "note": "Two 30-45 second vertical videos plus an extra hook each is a clearly scoped deliverable.",
   "ask": ""
  },
  {
   "quote": "$1,050 total for the package.",
   "topic": "fee",
   "level": "ok",
   "note": "At $1,050 this sits close to the page's estimate for this package and comfortably above its floor.",
   "ask": ""
  },
  {
   "quote": "we would run the videos as paid ads on Meta and TikTok for 3 months from first spend, and post them on our own channels.",
   "topic": "usage",
   "level": "negotiate",
   "note": "Three months of paid-ad usage plus posting on Glowbird's own channels is priced into the offer, but nothing says what happens if they want to keep running the ads longer.",
   "ask": "Get it in writing that any paid-ad usage past the 3 months comes with a renewal fee."
  },
  "..."
 ],
 "missing": [
  {
   "term": "Paid-partnership disclosure",
   "why": "The videos will run as paid ads, but the offer never says who adds the paid-partnership label or confirms the disclosure requirement."
  }
 ],
 "asks": [
  {
   "ask": "Get it in writing that any paid-ad usage beyond the 3 months triggers a renewal fee.",
   "priority": "nice"
  },
  {
   "ask": "Confirm in writing who is responsible for the paid-partnership disclosure label on these ads.",
   "priority": "nice"
  }
 ],
 "numbers": [
  "The $1,050 fee offered is about 97% of the page's $1,080 estimate for two videos with 3 months of paid-ad usage and two extra hooks, and well above the page's floor of $918.",
  "That estimate breaks down as roughly $600 for the two videos, about $300 for the paid-ad usage, and about $180 for the two extra hooks."
 ]
}

task: review - meal kit - counter

Input:

{
 "task": "review",
 "today": "2026-10-20",
 "creator": "Dev P.",
 "brand": "Panwhistle",
 "currency": "USD",
 "base_rate": "250",
 "offer": "Hey Dev, Panwhistle here!\n\nWe'd love 3 short-form videos of you cooking one of our weeknight kits.\nBudget is $1 ... (565 characters)",
 "terms": "{\"videos\":3,\"fee\":1100,\"usage\":\"paid\",\"usage_months\":3,\"whitelisting\":true,\"exclusivity_months\":2,\"revision_rounds\":2,\"payment_days\":45,\"raw_footage\":true,\"extra_hooks\":0,\"rush\":false}",
 "quote": "{\"currency\":\"USD\",\"base_rate\":250,\"videos\":3,\"base_total\":750,\"add_ons\":[{\"item\":\"Paid-ad usage, 3 months\",\"pct\":0.5,\"amount\":375},{\"item\":\"Whitelisting (ads from your handle)\",\"pct\":0.5,\"amount\":375},\"... 3 more\"],\"estimate\":2100,\"floor\":1785,\"stretch\":2520,\"walk_line\":1050,\"offered\":1100,\"offered_share\":0.52,\"figures_are_estimates\":true}",
 "page_flags": "[{\"level\":\"warn\",\"topic\":\"fee\",\"text\":\"The offer of $1,100 is 52% of the page's estimate for these terms ($2,100) - room to counter.\"},{\"level\":\"info\",\"topic\":\"whitelisting\",\"text\":\"Ads run from your own handle - ask to approve each ad and for the access to end with the usage window.\"},\"... 4 more\"]",
 "page_verdict": "counter"
}

Reply:

{
 "task": "review",
 "title": "Panwhistle 3-Video Meal Kit Offer",
 "verdict": "counter",
 "summary": "This offer is workable once a couple of terms are fixed, not one to sign as-is. The $1,100 budget covers only about half of what the page estimates these terms are worth once paid usage, whitelisting, exclusivity, raw footage and an extra revision round are counted, and the 45-day payment wait runs longer than standard. Start by asking Panwhistle to raise the fee toward the page's estimate and shorten the payment window; the kill fee, ad approval and exclusivity definition are good secondary asks. Nothing in the offer is a deal-breaker as written, so this is worth countering rather than walking. If the final written agreement gets more complex than this email, have a lawyer look it over before signing.",
 "clauses": [
  {
   "quote": "We'd love 3 short-form videos of you cooking one of our weeknight kits.",
   "topic": "deliverables",
   "level": "ok",
   "note": "The scope is specific: three short-form cooking videos of one product line.",
   "ask": ""
  },
  {
   "quote": "Budget is $1,100 for all three videos.",
   "topic": "fee",
   "level": "negotiate",
   "note": "The page estimates these terms (paid usage, whitelisting, exclusivity, raw footage and an extra revision round) are worth about $2,100, with a floor around $1,785; $1,100 is only about half that.",
   "ask": "Raise the fee toward the page's estimate, around $1,785-$2,100."
  },
  {
   "quote": "We'd like usage rights for paid social for 3 months",
   "topic": "usage",
   "level": "negotiate",
   "note": "The window has a clear end date, which is fair, but there's nothing about what happens if Panwhistle keeps running the ads past 3 months.",
   "ask": "Add that any use beyond the 3-month window requires a renewal fee."
  },
  "..."
 ],
 "missing": [
  {
   "term": "Kill fee",
   "why": "If Panwhistle cancels after you've filmed, nothing in the offer compensates you for the completed work."
  }
 ],
 "asks": [
  {
   "ask": "Raise the fee toward the page's estimate, around $1,785-$2,100, given the paid usage, whitelisting, exclusivity, raw footage and extra revision round.",
   "priority": "must"
  },
  {
   "ask": "Move payment to net 30, or get 50% upfront with the balance due on delivery.",
   "priority": "must"
  },
  {
   "ask": "Add a 50% kill fee if the brand cancels after you've filmed.",
   "priority": "nice"
  },
  "..."
 ],
 "numbers": [
  "Panwhistle's $1,100 offer is about 52% of the page's $2,100 estimate for these terms.",
  "The page's floor estimate is $1,785 - nearly $700 more than what's on the table, so there's real room to counter up.",
  "..."
 ]
}

task: review - energy drink - walk

Input:

{
 "task": "review",
 "today": "2026-10-20",
 "creator": "Sam K.",
 "brand": "Fizzlorn",
 "currency": "USD",
 "base_rate": "200",
 "offer": "Hi Sam, congrats - you've been selected for the Fizzlorn creator family!\n\nWe'll send you our full product  ... (644 characters)",
 "terms": "{\"videos\":4,\"fee\":0,\"usage\":\"paid\",\"usage_months\":\"perpetual\",\"whitelisting\":false,\"exclusivity_months\":12,\"revision_rounds\":\"unlimited\",\"payment_days\":\"not stated\",\"raw_footage\":false,\"extra_hooks\":0,\"rush\":true}",
 "quote": "{\"currency\":\"USD\",\"base_rate\":200,\"videos\":4,\"base_total\":800,\"add_ons\":[{\"item\":\"Paid-ad usage, in perpetuity\",\"pct\":2,\"amount\":1600},{\"item\":\"Exclusivity, 12 months\",\"pct\":1.8,\"amount\":1440},\"... 2 more\"],\"estimate\":4280,\"floor\":3638,\"stretch\":5136,\"walk_line\":2140,\"offered\":0,\"offered_share\":0,\"figures_are_estimates\":true}",
 "page_flags": "[{\"level\":\"fix\",\"topic\":\"fee\",\"text\":\"Product only, no cash - while the brand also wants ad usage or exclusivity. Gifting can cover a post you would make anyway, not a licence.\"},{\"level\":\"fix\",\"topic\":\"usage\",\"text\":\"Paid-ad usage in perpetuity: the brand can run your face in ads forever for one fee. Ask for an end date (3-12 months) with a renewal fee.\"},\"... 6 more\"]",
 "page_verdict": "walk"
}

Reply:

{
 "task": "review",
 "title": "Product-Only Deal With Perpetual Rights Grab",
 "verdict": "walk",
 "summary": "This is a walk: Fizzlorn is offering $180 of product in exchange for an irrevocable, lifetime licence to run your face and voice in paid ads, make AI-generated versions of you, and lock you out of the whole beverage category for a year - with unlimited free revisions on top. Several of these are deal-breakers on their own, and together they read like a one-sided rights grab dressed up as a 'creator family' invite rather than a paid UGC deal. The page's estimate for this scope is about $4,280, and even its floor estimate is thousands above the $180 of product on the table, so a normal counter would not close that gap. If you want to try anyway, start by asking for a cash fee and a time limit on the ad usage; if the brand will not move on those, walk. Given the irrevocable, perpetual rights and AI-likeness language, a lawyer should read the actual contract before you sign anything.",
 "clauses": [
  {
   "quote": "4 TikTok-style videos",
   "topic": "deliverables",
   "level": "ok",
   "note": "This sets the scope of work: four short vertical videos for the brand.",
   "ask": ""
  },
  {
   "quote": "We'll send you our full product range (worth $180) in exchange for 4 TikTok-style videos.",
   "topic": "fee",
   "level": "walk",
   "note": "The only pay offered is product worth $180, while the brand is also asking for a paid-advertising licence and a full category exclusivity - product can cover a post you'd make anyway, not a licence like this.",
   "ask": "Ask for a cash fee alongside the product, priced to the usage and exclusivity being granted."
  },
  {
   "quote": "you grant Fizzlorn an irrevocable, worldwide licence",
   "topic": "rights",
   "level": "negotiate",
   "note": "The grant is irrevocable rather than a normal licence, which reads closer to handing over ownership outright than giving the brand permission to use the videos.",
   "ask": "Change this to a revocable licence rather than an irrevocable grant, so the rights can end with the usage window."
  },
  "..."
 ],
 "missing": [
  {
   "term": "Kill fee",
   "why": "nothing is promised if the brand cancels after you've started work."
  },
  {
   "term": "Paid-partnership disclosure",
   "why": "the offer doesn't say whether the videos need to be labeled as a paid partnership."
  },
  "..."
 ],
 "asks": [
  {
   "ask": "A cash fee instead of product-only pay, priced to cover the paid-advertising licence and exclusivity.",
   "priority": "must"
  },
  {
   "ask": "An end date on paid-ad usage (3-12 months) with a renewal fee, not in perpetuity.",
   "priority": "must"
  },
  {
   "ask": "Strike the AI-generated-likeness clause, or limit it to edits of the delivered videos.",
   "priority": "must"
  },
  "..."
 ],
 "numbers": [
  "The brand is offering $180 of product for work the page estimates at about $4,280 once paid-ad usage, exclusivity, unlimited revisions and the rush turnaround are priced in - far below the page's floor estimate of $3,638.",
  "Even the page's walk-line estimate of $2,140 is more than ten times what's being offered, so a normal counter would not close that gap."
 ]
}

task: counter - skincare serum - accept

Input:

{
 "task": "counter",
 "today": "2026-10-20",
 "creator": "Maya R.",
 "brand": "Glowbird Skin",
 "currency": "USD",
 "base_rate": "300",
 "offer": "Hi Maya!\n\nWe love your skincare content and would like to work with you on the launch of our new Dew Drop seru ... (706 characters)",
 "terms": "{\"videos\":2,\"fee\":1050,\"usage\":\"paid\",\"usage_months\":3,\"whitelisting\":false,\"exclusivity_months\":0,\"revision_rounds\":1,\"payment_days\":30,\"raw_footage\":false,\"extra_hooks\":2,\"rush\":false}",
 "quote": "{\"currency\":\"USD\",\"base_rate\":300,\"videos\":2,\"base_total\":600,\"add_ons\":[{\"item\":\"Paid-ad usage, 3 months\",\"pct\":0.5,\"amount\":300},{\"item\":\"2 extra hooks\",\"pct\":0.3,\"amount\":180}],\"estimate\":1080,\"floor\":918,\"stretch\":1296,\"walk_line\":540,\"offered\":1050,\"offered_share\":0.97,\"figures_are_estimates\":true}",
 "page_flags": "[]",
 "page_verdict": "sign",
 "tone": "warm",
 "floor": "",
 "musts": "",
 "asks": "NICE: Get it in writing that any paid-ad usage beyond the 3 months triggers a renewal fee.\nNICE: Confirm in wr ... (190 characters)"
}

Reply:

{
 "task": "counter",
 "title": "Accepting the Glowbird Dew Drop Deal",
 "verdict": "accept",
 "summary": "This offer pays $1,050 for two videos with paid-ad usage and extra hooks, which sits close to the page's estimate of $1,080 and comfortably above its floor, so it's fair to accept as written. Maya should confirm the terms in writing and get two small things nailed down: a renewal fee if the paid-ad usage runs past three months, and who is responsible for the paid-partnership disclosure label.",
 "subject": "Re: Dew Drop Serum Partnership - confirming details",
 "email": "Hi Priya,\n\nThanks so much for reaching out about the Dew Drop serum launch - I'd love to work with you on this!\n\nTo confirm the details: 2 UGC videos (30-45 seconds, vertical), with 1 extra hook per video, for $1,050 total. The videos will run as paid ads on Meta and TikTok for 3 months from first spend, plus on your own channels, with one round of revisions included. Payment is net 30 from invoice, with a 50% kill fee if you cancel after I've filmed. Drafts are due within 14 days of receiving the product, and since there's no exclusivity, I'm free to work with other skincare brands too.\n\nTwo small things I'd like confirmed in writing before we start: if the paid-ad usage runs past the 3 months, let's agree on a renewal fee at that point, and could you let me know who's handling the paid-partnership disclosure label on these ads?\n\n[... 4 more lines]",
 "line_items": [],
 "total_ask": 1050,
 "walk_away": "If Glowbird can't confirm the usage renewal and disclosure responsibility in writing, Maya will hold off signing until those points are settled.",
 "trades": [],
 "followup": "If there's no reply within a week, Maya will send one short follow-up email."
}

task: counter - meal kit - counter

Input:

{
 "task": "counter",
 "today": "2026-10-20",
 "creator": "Dev P.",
 "brand": "Panwhistle",
 "currency": "USD",
 "base_rate": "250",
 "offer": "Hey Dev, Panwhistle here!\n\nWe'd love 3 short-form videos of you cooking one of our weeknight kits.\nBudget is $1 ... (565 characters)",
 "terms": "{\"videos\":3,\"fee\":1100,\"usage\":\"paid\",\"usage_months\":3,\"whitelisting\":true,\"exclusivity_months\":2,\"revision_rounds\":2,\"payment_days\":45,\"raw_footage\":true,\"extra_hooks\":0,\"rush\":false}",
 "quote": "{\"currency\":\"USD\",\"base_rate\":250,\"videos\":3,\"base_total\":750,\"add_ons\":[{\"item\":\"Paid-ad usage, 3 months\",\"pct\":0.5,\"amount\":375},{\"item\":\"Whitelisting (ads from your handle)\",\"pct\":0.5,\"amount\":375},\"... 3 more\"],\"estimate\":2100,\"floor\":1785,\"stretch\":2520,\"walk_line\":1050,\"offered\":1100,\"offered_share\":0.52,\"figures_are_estimates\":true}",
 "page_flags": "[{\"level\":\"warn\",\"topic\":\"fee\",\"text\":\"The offer of $1,100 is 52% of the page's estimate for these terms ($2,100) - room to counter.\"},{\"level\":\"info\",\"topic\":\"whitelisting\",\"text\":\"Ads run from your own handle - ask to approve each ad and for the access to end with the usage window.\"},\"... 4 more\"]",
 "page_verdict": "counter",
 "tone": "direct",
 "floor": "1700",
 "musts": "Raw footage only if it is paid for separately. Payment within 30 days.",
 "asks": "MUST: Raise the fee toward the page's estimate, around $1,785-$2,100, given the paid usage, whitelisting, excl ... (610 characters)"
}

Reply:

{
 "task": "counter",
 "title": "Panwhistle Weeknight Kit Counter",
 "verdict": "counter",
 "summary": "Panwhistle's $1,100 covers roughly half of what these terms are worth once paid usage, whitelisting, exclusivity, raw footage and the extra revision round are priced in, so this calls for a counter rather than a sign-as-is. Dev is asking for $2,100 total, payment within 30 days instead of 45, and raw footage only if it's priced separately. A few more items - ad approval on whitelisting, a kill fee, and naming the exclusivity competitors - are worth raising but aren't deal-breakers on their own.",
 "subject": "Re: Panwhistle videos - a few changes before I confirm",
 "email": "Hi Jordan,\n\nThanks for thinking of me for the Panwhistle weeknight kit videos. I'd like to move forward, with a few changes to the terms.\n\nFor three videos with 3 months of paid usage, whitelisting from my handle, 2 months of exclusivity, an extra revision round, and raw footage priced separately since your team will cut extra versions, my rate comes to $2,100 total, up from the $1,100 offered.\n\nA few other items: payment within 30 days of invoice instead of 45, approval on each ad running under whitelisting with that access ending when the usage window closes, a 50% kill fee if the project is cancelled after filming, and the specific meal-kit competitors named for the exclusivity clause rather than the category.\n\n[... 4 more lines]",
 "line_items": [
  {
   "item": "3 videos (base rate)",
   "offered": 1100,
   "asking": 750,
   "why": "Your standard rate for three videos at $250 each."
  },
  {
   "item": "Paid-ad usage, 3 months",
   "offered": 0,
   "asking": 375,
   "why": "The offer doesn't pay separately for running the videos as paid ads."
  },
  {
   "item": "Whitelisting (ads from your handle)",
   "offered": 0,
   "asking": 375,
   "why": "Ads running from my own handle need their own price."
  },
  {
   "item": "Exclusivity, 2 months",
   "offered": 0,
   "asking": 225,
   "why": "Being locked out of other meal-kit brands for 2 months has a cost."
  },
  "..."
 ],
 "total_ask": 2100,
 "walk_away": "Dev won't go below $1,700 total, won't hand over raw footage without it being paid for separately, and needs payment within 30 days - without those, it's not worth taking on.",
 "trades": [
  "Could drop the kill-fee ask if the fee lands at the full $2,100.",
  "Willing to skip the named-competitor ask if the exclusivity window is shortened to match the campaign.",
  "..."
 ],
 "followup": "If Panwhistle doesn't reply, send one friendly follow-up note before moving on."
}

task: counter - energy drink - decline

Input:

{
 "task": "counter",
 "today": "2026-10-20",
 "creator": "Sam K.",
 "brand": "Fizzlorn",
 "currency": "USD",
 "base_rate": "200",
 "offer": "Hi Sam, congrats - you've been selected for the Fizzlorn creator family!\n\nWe'll send you our full product  ... (644 characters)",
 "terms": "{\"videos\":4,\"fee\":0,\"usage\":\"paid\",\"usage_months\":\"perpetual\",\"whitelisting\":false,\"exclusivity_months\":12,\"revision_rounds\":\"unlimited\",\"payment_days\":\"not stated\",\"raw_footage\":false,\"extra_hooks\":0,\"rush\":true}",
 "quote": "{\"currency\":\"USD\",\"base_rate\":200,\"videos\":4,\"base_total\":800,\"add_ons\":[{\"item\":\"Paid-ad usage, in perpetuity\",\"pct\":2,\"amount\":1600},{\"item\":\"Exclusivity, 12 months\",\"pct\":1.8,\"amount\":1440},\"... 2 more\"],\"estimate\":4280,\"floor\":3638,\"stretch\":5136,\"walk_line\":2140,\"offered\":0,\"offered_share\":0,\"figures_are_estimates\":true}",
 "page_flags": "[{\"level\":\"fix\",\"topic\":\"fee\",\"text\":\"Product only, no cash - while the brand also wants ad usage or exclusivity. Gifting can cover a post you would make anyway, not a licence.\"},{\"level\":\"fix\",\"topic\":\"usage\",\"text\":\"Paid-ad usage in perpetuity: the brand can run your face in ads forever for one fee. Ask for an end date (3-12 months) with a renewal fee.\"},\"... 6 more\"]",
 "page_verdict": "walk",
 "tone": "warm",
 "floor": "",
 "musts": "",
 "asks": "MUST: A cash fee instead of product-only pay, priced to cover the paid-advertising licence and exclusivity.\nMU ... (526 characters)"
}

Reply:

{
 "task": "counter",
 "title": "Decline the offer as written",
 "verdict": "decline",
 "summary": "This offer pays nothing in cash for four videos plus a never-ending paid-ad and AI-generated-likeness licence, twelve months of exclusivity, and unlimited revisions - the page's estimate puts the fair value of what's being asked at about $4,280 against $0 offered. That gap, combined with deal-breakers that need rewriting rather than just a bigger check, makes a straight counter unrealistic, so declining while naming exactly what would change the answer is the better move. If the brand comes back with a cash fee, a defined usage window, no AI use of likeness, capped revisions, and a short, paid, narrowly defined exclusivity, this could work.",
 "subject": "Re: Fizzlorn creator offer - a few changes needed",
 "email": "Hi Fizzlorn team,\n\nThank you for thinking of me for the creator family!\n\nHaving looked at the details, I don't think I can say yes to this version of the offer. As written, it's product only - no cash fee - in exchange for four videos plus the right to run my face and voice in paid ads with no end date, make AI-generated versions of me, twelve months of exclusivity in the beverage category, and unlimited revisions. By my own estimate, pricing out everything this offer is asking for comes to roughly $4,280, so a product package worth $180 doesn't come close.\n\nHere's what would change my answer: a cash fee in that range, a set usage window (3-12 months) with a renewal fee instead of forever, no AI-generated use of my likeness or voice, one or two revision rounds with a fee for extra ones, and a shorter, narrowly defined, paid exclusivity period.\n\n[... 4 more lines]",
 "line_items": [],
 "total_ask": 4280,
 "walk_away": "Without a cash fee near the page's estimate, a defined end date on the paid-ad and AI-likeness use, capped revisions, and a short, paid, narrowly defined exclusivity, I won't sign this.",
 "trades": [
  "A shorter usage window (around 3 months) instead of one price for a much longer one.",
  "Two revision rounds built into the base fee instead of unlimited, with extra rounds billed separately.",
  "..."
 ],
 "followup": "If I don't hear back within a week, I'll send one follow-up note before treating the offer as closed."
}

Build the input yourself

Load the script in node (global.window = {}; require("./dealkit.js")), then:

const K = DealKit;
const offer = "Hi! We'd love 2 UGC videos. $600 total, 3 months of paid usage on Meta, one round of revisions, net 30.";
const terms = K.readTerms(offer).terms;          // the term sheet as the page reads it - correct any field
const st = K.state(Object.assign({ offer, base: "300", currency: "USD", creator: "", brand: "" }, terms));
console.log(st.quote.fair, st.quote.ratio, st.flags, st.verdict);   // estimate, share of it offered, flags, sign|counter|walk
const wire = K.toWire(K.buildInput(st, "review", { today: "2026-10-20" }).input);  // POST this to /estimate and /run
// counter lane: set st.form.asks (or the "asks" form field) to K.asksToText(reviewReply), then buildInput(st, "counter")
// later: const reply = K.normalize(K.parseReply(job.output.output), "review");
// const { notes, marks } = K.check(reply, st, "review");

Step 1 — a tiny client helper

One function that sends JSON and unwraps the envelope. Paste a personal token from /tokens.html, or leave it empty and mint a guest token in step 2.

BASE="https://api.skillsafe.ai/v1/app-api"
TOKEN="paste-your-token-here"   # from https://in-perpetuity.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":"in-perpetuity"}' | 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, the bare object (never wrapped in {"input": ...}). hold_credits is a reservation, not the price; min_credits is what the balance must cover; model_alias reads gpt-terra.

# input.json: the run input object - {"task": "review", "today": "2026-10-20", "creator": "Dev P.", "brand": "Panwhistle", "currency": "USD", "base_rate": "250", "offer": "Hey Dev, Panwhistle here! ...", "terms": "{...}", "quote": "{...}", "page_flags": "[...]", "page_verdict": "counter"}
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 in-perpetuity:<task>:<inputHash>:a<attempt> (the examples below use the review lane), and its one reformat retry (with retry_note added) is attempt 2, a new key and a second run. The job's output.output is the reply text; truncated: true means the balance cut it short.

KEY="in-perpetuity:review:$(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 reply contract
echo "$J" | jq '.data | {charged_credits, truncated}' 

Step 6 — POST /run-stream

The same run as Server-Sent Events, with the same input.json. Browsers receive progress ticks rather than text deltas; the final done event carries the reply.

# 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: in-perpetuity:review:$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json