← Cut the Line
API
Tokens

Drive Cut the Line from your own code

The metered reply is available over HTTP. It takes one offer a writer received - the message, the sender's address, what it claims to be, who wrote first, whether anything was paid, and the page's bait scan - and returns a verdict of cut (cut the line), check (check the hook first) or clear (no hook in sight), each bait explained with a word-for-word quote, which way the money flows, how a genuine offer of that kind usually works, three checks to do on your own, a reply you could send and, when something was already paid, what to do now.

The division of labour first: the page owns the bait scan and the rule; the model owns the judgement and the words; the page re-checks the reply. The word lists, the money current and the verdict rule come from linekit.js, which runs in node as well as in the browser. The model never scans anything itself: LineKit.buildInput(form) builds the exact input the page sends, and LineKit.check(reply, built) is the page's re-check.

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":"cut-the-line"}), so no slug header is needed afterwards. Send it as Authorization: Bearer …. The run body is the input object, sent bare.

StatusCodeMeaning
400validation_errorThe body is not a JSON object, or a required field (message, lures, figures) 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: the reply is metered and needs 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 verdict rule

There is one task, so no task field is sent. The verdict is decided by a fixed rule on the page's figures, checked in this order - the first that applies wins:

  1. cut - money is asked of you (fee_found is yes) and they wrote first (contact is them).
  2. check - money is asked of you, or 2 or more other kinds of bait were found (other_lure_types).
  3. clear - everything else.

The word lists are a rough rule of thumb: a hit is a reason to look closer, not proof of a scam, and a clean scan is not proof an offer is real. The declared input schema carries scalars only, so the array- and object-valued fields (lures, figures) travel as JSON-encoded strings - LineKit.toWire() does this for you.

Input fields

FieldTypeNotes
messagestringThe offer as received; past 3,000 characters the opening and closing are kept with the middle marked [...]. Required.
senderstringThe sender's address or name, or empty.
kind, kind_labelstringbookclub, review, agent, publisher, film, marketing, award or other, and its plain label.
contact, contact_labelstringthem (they wrote first) or me (you contacted them first), and its plain label.
paidstringyes or no: have you already paid them anything?
luresstring (JSON)The bait the page found, in tray order: [{id, label, found}], id one of fee, flattery, urgency, prestige, secrecy, greeting, sender; found lists up to 4 matched phrases. May be []. Required.
figuresstring (JSON){fee_found, other_lure_types, lure_types, money_flow, amounts}, every value a string; money_flow is away, toward, both or unclear. Required.
clip_note, retry_notestringWhat the page cut, when it cut something; and only on a reformat retry, what was wrong.

The reply

The job's output.output is a string holding one JSON object: verdict, title, summary, lures (one {lure, quote, why} per bait in the input, in order, each quote copied from the message - the sender quote from the sender - then at most 2 with lure other), money_flow, real_ones (how a genuine offer of this kind usually works - a rule of thumb), verify (exactly 3 checks), reply ({subject, body}, signed [Your name]) and if_paid (steps when paid is yes, else empty). It never names a person or organisation in its own words and never passes on a link, address or phone number from the message.

Worked examples

Replies produced against the app's prompt for the five sample offers (made up; the full replies ship in example-result.js). Together they cover every verdict and the already-paid steps.

Book club fee - cut

Input:

{
 "message": "Dear Author,\nOur reading circle has just finished your novel and our members were deeply moved. It is a captivating, profound story, and we would love to feature it as our Book of the Month for our 12,000 members.\nTo cover member copies and the live discussion evening there is a one-time contribution fee of $199. Only 3 spots remain for November, so please confirm within 48 hours and we will send the payment details.\nWarm regards,\nThe Quillmere Readers Circle",
 "sender": "quillmere.readers.team@gmail.com",
 "kind": "bookclub",
 "kind_label": "a book club feature",
 "contact": "them",
 "contact_label": "they wrote to you first",
 "paid": "no",
 "lures": "[{\"id\":\"fee\",\"label\":\"money asked of you\",\"found\":[\"contribution fee\",\"send the payment\"]},{\"id\":\"flattery\",\"label\":\"flattery\",\"found\":[\"deeply moved\",\"captivating\",\"profound\"]},{\"id\":\"urgency\",\"label\":\"a rush\",\"found\":[\"Only 3 spots remain\",\"within 48 hours\"]},{\"id\":\"greeting\",\"label\":\"generic greeting\",\"found\":[\"Dear Author\"]},{\"id\":\"sender\",\"label\":\"free-mail sender\",\"found\":[\"quillmere.readers.team@gmail.com\"]}]",
 "figures": "{\"fee_found\":\"yes\",\"other_lure_types\":\"4\",\"lure_types\":\"5\",\"money_flow\":\"away\",\"amounts\":\"$199\"}"
}

Reply:

{
 "verdict": "cut",
 "title": "A fee dressed up as a book feature",
 "summary": "The message offers a book club feature and asks you to pay a fee before a deadline. Because the fee comes from someone who approached you first, don't pay or engage further; not replying is also fine.",
 "lures": [
  {
   "lure": "fee",
   "quote": "one-time contribution fee of $199",
   "why": "It presents a fee as part of being featured, pushing you to pay before you can check who is asking."
  },
  {
   "lure": "flattery",
   "quote": "deeply moved",
   "why": "The praise is meant to make you feel special and want to keep the good feeling instead of checking the offer."
  },
  {
   "lure": "urgency",
   "quote": "Only 3 spots remain for November, so please confirm within 48 hours",
   "why": "The deadline and limited spots push you to decide fast, before you have time to check who is really asking."
  },
  {
   "lure": "greeting",
   "quote": "Dear Author",
   "why": "A greeting with no name suggests the message went to many writers at once, not only to you."
  },
  {
   "lure": "sender",
   "quote": "quillmere.readers.team@gmail.com",
   "why": "A free email address is easy for anyone to set up and does not confirm who is contacting you."
  }
 ],
 "money_flow": "The message asks you to pay the sender, not the other way round, naming a fee of $199.",
 "real_ones": "A genuine book club or reviewer usually does not charge the author anything to be featured, and any costs are usually explained openly rather than rushed.",
 "verify": [
  "Search for the organisation's own website yourself, rather than clicking any link in the message.",
  "Search the organisation's name together with the word scam to see what others have found.",
  "Ask a writers' organisation or someone you trust whether this kind of request is normal."
 ],
 "reply": {
  "subject": "Thank you, but I must decline",
  "body": "Thank you for the kind words about my novel. After thinking it over, I've decided not to go ahead with this offer, and I won't be sending any payment. I'd rather not continue this conversation. I wish you well. [Your name]"
 },
 "if_paid": ""
}

Film rights, already paid - cut, with the already-paid steps

Input:

{
 "message": "Hello,\nI scout books for a group of Hollywood producers, and your thriller is exactly the kind of compelling story they are looking for. They want to discuss the film rights.\nBefore I can present it, the book needs professional script coverage. Our coverage package is $350 and it is the only step between you and the meeting. Please keep this offer confidential until contracts are signed, and text me on my private number if you have questions.\nBest,\nRay at Vellowmark Pictures",
 "sender": "ray.scout@vellowmark-pictures.example.com",
 "kind": "film",
 "kind_label": "a film or TV adaptation",
 "contact": "them",
 "contact_label": "they wrote to you first",
 "paid": "yes",
 "lures": "[{\"id\":\"fee\",\"label\":\"money asked of you\",\"found\":[\"package is $350\"]},{\"id\":\"flattery\",\"label\":\"flattery\",\"found\":[\"compelling\"]},{\"id\":\"prestige\",\"label\":\"big-stage promises\",\"found\":[\"Hollywood\",\"producers\",\"film rights\"]},{\"id\":\"secrecy\",\"label\":\"off-channel or hush\",\"found\":[\"confidential\",\"text me\",\"private number\"]}]",
 "figures": "{\"fee_found\":\"yes\",\"other_lure_types\":\"3\",\"lure_types\":\"4\",\"money_flow\":\"away\",\"amounts\":\"$350\"}"
}

Reply:

{
 "verdict": "cut",
 "title": "A fee hidden inside a film offer",
 "summary": "The message offers to bring your book to a group of producers, but first asks you to pay for a coverage package before any meeting happens. Since a fee was asked of you by a sender who wrote to you first, cut it off: don't pay, and don't reply further.",
 "lures": [
  {
   "lure": "fee",
   "quote": "package is $350",
   "why": "Paying this fee is presented as the only thing standing between you and the meeting the message describes."
  },
  {
   "lure": "flattery",
   "quote": "compelling",
   "why": "Calling your story compelling is meant to make you feel singled out, so you're less likely to question the fee."
  },
  {
   "lure": "prestige",
   "quote": "a group of Hollywood producers",
   "why": "Mentioning well-known producers and film rights is meant to excite you into moving quickly without checking the offer first."
  },
  {
   "lure": "secrecy",
   "quote": "keep this offer confidential until contracts are signed",
   "why": "Asking you to keep this quiet and to contact a private number outside email tries to stop you from checking it with anyone else."
  },
  {
   "lure": "other",
   "quote": "it is the only step between you and the meeting",
   "why": "Presenting payment as the single remaining step is a promise that paying guarantees the result, with nothing else needed."
  }
 ],
 "money_flow": "The money here flows away from you: the message asks you to pay $350 for the coverage package before anything moves forward.",
 "real_ones": "A film company that wants to option your book usually pays you for that option rather than asking you to pay first; coverage, if needed, is usually arranged and paid for on the company's side.",
 "verify": [
  "Search for the production company's name independently, not through any link or contact in the message.",
  "Search the sender's name together with the word scam to see what others have reported.",
  "Ask a writers' organisation or someone you trust whether this kind of request is normal."
 ],
 "reply": {
  "subject": "Not moving forward",
  "body": "Thank you for reaching out about my book. I won't be paying a fee in order to move forward, and I'd rather not continue this conversation. Please don't contact me again about this.\n\n[Your name]"
 },
 "if_paid": "Stop any further payments right away and contact your bank or card provider about the payment you already made. Keep every message, email, and receipt related to this. Consider reporting it to your local fraud or consumer protection service."
}

Award shortlist - check (bait, no fee yet)

Input:

{
 "message": "Hello Writer,\nWe are pleased to tell you that your book has been shortlisted for the Brassfern International Readers Award. The judges called it a remarkable debut.\nFinalists must confirm their place by Friday. Winners are announced at a gala and featured on a billboard in Times Square.\nReply to accept your nomination and we will send the next steps.\nThe Awards Committee",
 "sender": "brassfern.awards.committee@outlook.com",
 "kind": "award",
 "kind_label": "an award, prize or contest",
 "contact": "them",
 "contact_label": "they wrote to you first",
 "paid": "no",
 "lures": "[{\"id\":\"flattery\",\"label\":\"flattery\",\"found\":[\"remarkable\"]},{\"id\":\"urgency\",\"label\":\"a rush\",\"found\":[\"confirm their place by Friday\"]},{\"id\":\"prestige\",\"label\":\"big-stage promises\",\"found\":[\"billboard\",\"Times Square\"]},{\"id\":\"greeting\",\"label\":\"generic greeting\",\"found\":[\"Hello Writer\"]},{\"id\":\"sender\",\"label\":\"free-mail sender\",\"found\":[\"brassfern.awards.committee@outlook.com\"]}]",
 "figures": "{\"fee_found\":\"no\",\"other_lure_types\":\"5\",\"lure_types\":\"5\",\"money_flow\":\"unclear\",\"amounts\":\"\"}"
}

Reply:

{
 "verdict": "check",
 "title": "Flattery, a deadline, and a big stage",
 "summary": "The message offers you a finalist spot in the award it names and asks you to reply to accept the nomination by a set day. Since other bait is present, verify on your own before you send money or anything else.",
 "lures": [
  {
   "lure": "flattery",
   "quote": "The judges called it a remarkable debut.",
   "why": "This praise seeks to make you feel special so you skip questions about who is asking and why."
  },
  {
   "lure": "urgency",
   "quote": "confirm their place by Friday",
   "why": "This deadline pushes you to decide fast before you've had time to check who is contacting you."
  },
  {
   "lure": "prestige",
   "quote": "featured on a billboard in Times Square",
   "why": "This big stage promise distracts you with imagined fame instead of what you are being asked to do."
  },
  {
   "lure": "greeting",
   "quote": "Hello Writer",
   "why": "A greeting with no name suggests this was sent to many people rather than written for you alone."
  },
  {
   "lure": "sender",
   "quote": "brassfern.awards.committee@outlook.com",
   "why": "A free email address is easy for anyone to set up and does not confirm a real organisation."
  }
 ],
 "money_flow": "The message does not mention money in either direction yet - it does not ask you to pay and does not say it will pay you anything.",
 "real_ones": "A genuine award or contest usually does not charge the writer to be nominated, shortlisted or to accept a place; genuine recognition itself is free, with any optional extras spelled out plainly.",
 "verify": [
  "Look up the organisation yourself by searching for its name, not through any link or address in the message.",
  "Search the organisation's name together with the word scam to see what others have reported.",
  "Ask a writers' organisation or someone you trust whether this kind of nomination is normal."
 ],
 "reply": {
  "subject": "A few questions before I confirm",
  "body": "Thank you for the news about the nomination. Before I confirm, I'd like a few things in writing: who pays whom and when, a written contract covering any fees, and where I can independently confirm the organisation and the award. I won't send any payment or personal details until I have those answers.\n\nLooking forward to hearing from you.\n\n[Your name]"
 },
 "if_paid": ""
}

Promotion quote you asked for - check (a fee after you wrote first)

Input:

{
 "message": "Hi,\nThanks for your enquiry about promoting your mystery novel. Our standard newsletter feature is $55 per placement, payable by invoice after we agree the date. The newsletter goes to readers who signed up for mystery picks, and last month's open and click figures are in the sheet I attached.\nLet me know which month suits and I will hold a place.\nPriya\nTallowmere Reader Newsletter",
 "sender": "priya@tallowmere-news.example.com",
 "kind": "marketing",
 "kind_label": "marketing or advertising for the book",
 "contact": "me",
 "contact_label": "you contacted them first",
 "paid": "no",
 "lures": "[{\"id\":\"fee\",\"label\":\"money asked of you\",\"found\":[\"$55 per placement\",\"payable\",\"invoice\"]}]",
 "figures": "{\"fee_found\":\"yes\",\"other_lure_types\":\"0\",\"lure_types\":\"1\",\"money_flow\":\"away\",\"amounts\":\"$55\"}"
}

Reply:

{
 "verdict": "check",
 "title": "An invoice to check before you pay",
 "summary": "The message offers a newsletter placement for your book and asks you to pay $55 by invoice. Since a fee is involved, verify the service independently before you send any money.",
 "lures": [
  {
   "lure": "fee",
   "quote": "$55 per placement, payable by invoice after we agree the date",
   "why": "It asks you to pay a fee by invoice once a date is agreed, dressed as a routine business cost."
  }
 ],
 "money_flow": "The message asks you to pay $55 for the placement; no money is offered to you.",
 "real_ones": "For marketing like this, a fee is usually normal, but a fair offer usually sets out clearly what you get, when payment is due, and lets you check the audience figures independently before you pay.",
 "verify": [
  "Look up the newsletter directly through its own website rather than any link in the message.",
  "Search the sender's business name with the word \"scam\" to check for warnings.",
  "Ask for the rates, audience numbers, and payment terms in writing before you agree to pay."
 ],
 "reply": {
  "subject": "Questions before confirming the newsletter placement",
  "body": "Hello,\n\nThank you for the details about the placement. Before I confirm a date, could you send a written contract or terms covering what the fee covers and when payment is due? I would also like to confirm your newsletter's details independently through your own website. I won't send any payment until I have everything in writing.\n\nThanks,\n[Your name]"
 },
 "if_paid": ""
}

Agent asks for the manuscript - clear

Input:

{
 "message": "Dear Sam,\nThank you for sending the first three chapters of The Salt Orchard. I enjoyed the voice and the opening, and I would like to read the full manuscript. Could you send it as a document or PDF to this address?\nThere is no fee for this. If we decide to work together, our agency earns 15% commission on sales of your book, as set out in our standard agreement, which I would share before anything is signed. I aim to reply within six weeks.\nBest wishes,\nMaya Brindlecombe\nWrenhollow Literary",
 "sender": "maya@wrenhollow-literary.example.com",
 "kind": "agent",
 "kind_label": "a literary agent",
 "contact": "me",
 "contact_label": "you contacted them first",
 "paid": "no",
 "lures": "[]",
 "figures": "{\"fee_found\":\"no\",\"other_lure_types\":\"0\",\"lure_types\":\"0\",\"money_flow\":\"toward\",\"amounts\":\"\"}"
}

Reply:

{
 "verdict": "clear",
 "title": "An ordinary request for the full manuscript",
 "summary": "The message asks for your full manuscript and says there is no fee, with a commission taken only if they sign you. This page saw no bait, so reply as you normally would and still confirm who the sender is on your own.",
 "lures": [],
 "money_flow": "The message asks for no payment from you; it describes a commission the agency would keep from sales if you sign, not money paid upfront by you.",
 "real_ones": "A literary agent usually earns a commission from sales of your book rather than charging you a fee up front, and usually sets out the terms in a written agreement before anything is signed.",
 "verify": [
  "Look up the agency's details yourself through its own website found by searching, not a link in this message.",
  "Search the agency's name together with the word scam or check writers' watchdog sites for warnings.",
  "Ask for the standard agreement in writing before you send the full manuscript or sign anything."
 ],
 "reply": {
  "subject": "Full manuscript on its way",
  "body": "Hello, Thank you for your note and for your interest in reading further. I'm pleased you enjoyed the opening, and I'll send the full manuscript as a document shortly. Before I do, could you send the standard agreement in writing so I can see how the commission would work and when it would apply? I appreciate you taking the time, and I look forward to hearing more. [Your name]"
 },
 "if_paid": ""
}

Build the input yourself

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

const K = LineKit;
const form = K.form({ message: "Dear Author, your novel is a masterpiece. A listing fee of $95 secures your place this week.",
  sender: "editor.desk@example.com", kind: "review", contact: "them", paid: "no" });
const r = K.read(form);                            // r.lures: each kind of bait and its hits; r.fig: money_flow, amounts, verdict
const built = K.buildInput(form);
const wire = K.toWire(built.input);               // POST this to /estimate and /run
// then: const reply = K.normalize(K.parseReply(job.output.output));
// K.check(reply, built).notes                    // the page's re-check of the reply
// K.csv(built, reply)                            // the bait sheet, one row per kind of bait

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://cut-the-line.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":"cut-the-line"}' | 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 - {"message": "Dear Author,\nOur reading circle has just finished your novel and our members were deeply m...", "sender": "quillmere.readers.team@gmail.com", "kind": "bookclub", "kind_label": "a book club feature", "contact": "them", "contact_label": "they wrote to you first", "paid": "no", "lures": "[...]", "figures": "{...}"}
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 input: a retry with the same key never bills twice. The page uses cut-the-line:read:<inputHash>:a<attempt> (the one task is read), 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="cut-the-line:read:$(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: cut-the-line:read:$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json