← Party Sized
API

Drive Party Sized from your own code

The one metered task, fold-it-down, is available over HTTP. It takes a job title and how the person describes the job at work (jargon welcome), plus an optional line on the part they most want people to get. It returns a plain swap for every flagged word, a plain rewrite of the knottiest sentence, a version for a curious stranger, a one-sentence party answer, a lift-sized line, and one everyday picture of the job with where that picture breaks.

The division of labour first: the page reads; the model folds. The page flags abbreviations, jargon and long words, picks the knottiest sentence and sets the word caps, and sends those as facts. After the reply it counts every fold itself and checks that no flagged word survived. The paper colour is the page's own and never sent.

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": "..." } }

The token is minted for this app (the guest call takes {"slug":"party-sized"}), 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 (task, job, blurb, proud, facts) 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 reasons are metered and need a personal sign-in.
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 and the input

Every run sends task: fold-it-down (the one task is fold-it-down); a missing or different one is still answered as fold-it-down. All fields are strings.

FieldRequiredWhat it holds
taskyesAlways fold-it-down.
jobyesThe job title, up to 60 characters.
blurbyesHow the person describes the job at work, cut on sentence boundaries to at most 900 characters.
proudyesThe part they most want people to get, or not given.
factsyesThe page's lines: the flagged words in order (at most ten), each with its kind (jargon, abbreviation or long word), or "none"; the knottiest sentence; the word caps.
retry_notenoOnly on a reformat retry: why the previous reply was unusable.

Flagged words: abbreviations of two or more capitals (everyday ones such as TV, UK or CEO are skipped), words from a fixed jargon list, and words of fourteen letters or more. None or one is a flat sheet, two to five a few creases, six or more tightly creased. The knottiest sentence is the one with the most words; ties go to the earlier one.

The reply

One JSON object, no prose around it:

{"task": "fold-it-down", "swaps": [{"term": "...", "plain": "..."}], "after": "...", "stranger": "...", "party": "...", "lift": "...", "picture": "...", "breaks": "..."}
FieldWhat it holds
swaps[]One per flagged word, same order, term copied exactly; plain is 2 to 8 everyday words. Empty when nothing was flagged.
afterThe knottiest sentence rewritten plainly, first person, at most 35 words.
strangerTwo or three sentences, 25 to 60 words, for a curious stranger.
partyOne sentence, at most 20 words, starting with "I".
liftAt most 8 words, starting with "I".
pictureOne sentence, at most 25 words, comparing the job to one familiar everyday thing.
breaksOne sentence, at most 25 words: one honest way the job is not like the picture.

The page then checks the reply (FoldKit.check) - a swap for every flagged word, no flagged word left in any fold, every fold within its cap, the party answer one sentence, and no time, number, pronoun or contact detail you did not give - and lists anything it finds under "The page's check".

Worked examples - all three sheets

These are the 3 free samples on the page: the exact input the page sends and the reply that replays for free. Together they cover a flat sheet, a few creases and a tightly creased sheet.

Bike mechanic - flat sheet (0 flagged)

Input:

{
 "task": "fold-it-down",
 "job": "Bicycle mechanic",
 "blurb": "I fix bikes in a small shop. Mostly brakes, gears and punctures, and now and then I build a wheel from scratch for someone who wants it just so.",
 "proud": "Building a wheel by hand",
 "facts": "flagged words: none (return an empty swaps list)\nknottiest sentence (rewrite it plainly as the after line): Mostly brakes, gears and punctures, and now and then I build a wheel from scratch for someone who wants it just so.\nword caps: stranger 60, party 20, lift 8, picture 25, breaks 25, after 35, each swap 8"
}

Reply:

{
 "task": "fold-it-down",
 "swaps": [],
 "after": "Mostly I fix brakes, gears and punctures, and now and then I build a wheel from scratch for someone who wants it just so.",
 "stranger": "I work on bikes in a small shop. Mostly that means brakes, gears and punctures, but now and then I build a wheel from scratch by hand for someone who wants it just so.",
 "party": "I fix bikes in a small shop, mostly brakes, gears and punctures, and now and then a wheel from scratch.",
 "lift": "I fix bikes in a small shop.",
 "picture": "Like keeping a home running, mostly small fixes, but now and then building a piece from scratch for someone who wants it just so.",
 "breaks": "Unlike a home, what gets fixed here is bikes, not the home itself."
}

Payroll - a few creases (3 flagged)

Input:

{
 "task": "fold-it-down",
 "job": "Payroll coordinator",
 "blurb": "I run the monthly payroll cycle for about 400 staff. I reconcile timesheets against the HRIS, chase managers for late approvals, and handle the year-end P60 queries from people who think they were taxed twice.",
 "proud": "not given",
 "facts": "flagged words (one plain swap each, in this order):\n1. reconcile (jargon)\n2. HRIS (abbreviation)\n3. P60 (abbreviation)\nknottiest sentence (rewrite it plainly as the after line): I reconcile timesheets against the HRIS, chase managers for late approvals, and handle the year-end P60 queries from people who think they were taxed twice.\nword caps: stranger 60, party 20, lift 8, picture 25, breaks 25, after 35, each swap 8"
}

Reply:

{
 "task": "fold-it-down",
 "swaps": [
  {
   "term": "reconcile",
   "plain": "compare records to find mismatches"
  },
  {
   "term": "HRIS",
   "plain": "the system holding staff records"
  },
  {
   "term": "P60",
   "plain": "a document showing tax paid"
  }
 ],
 "after": "I check that timesheets match the system that holds staff records, chase managers for late approvals, and handle year-end queries about the tax document from people who think they were taxed twice.",
 "stranger": "I run the monthly payroll cycle for about 400 staff, making sure timesheets match the system that holds their records. I also follow up with managers who are late with approvals, and I answer year-end questions about the tax document from people who think they were taxed twice.",
 "party": "I run payroll for about 400 staff and sort out pay and tax queries.",
 "lift": "I run payroll and answer tax queries.",
 "picture": "It is like balancing a shop's till, chasing missing slips from staff, and answering people's questions about their charges.",
 "breaks": "Unlike a shop's till, this payroll work covers about 400 staff, not just a handful of people."
}

Data engineer - tightly creased (10 flagged)

Input:

{
 "task": "fold-it-down",
 "job": "Senior data platform engineer",
 "blurb": "I own the ingestion pipelines and orchestration layer for our analytics stack, partnering with cross-functional stakeholders to deliver ELT workflows with SLAs on data freshness. Most days that means fixing whatever broke overnight before anyone opens a dashboard.",
 "proud": "Nobody notices when the numbers are right, and that is the point",
 "facts": "flagged words (one plain swap each, in this order):\n1. ingestion (jargon)\n2. pipelines (jargon)\n3. orchestration (jargon)\n4. analytics (jargon)\n5. stack (jargon)\n6. cross-functional (jargon)\n7. stakeholders (jargon)\n8. ELT (abbreviation)\n9. workflows (jargon)\n10. SLAs (abbreviation)\nknottiest sentence (rewrite it plainly as the after line): I own the ingestion pipelines and orchestration layer for our analytics stack, partnering with cross-functional stakeholders to deliver ELT workflows with SLAs on data freshness.\nword caps: stranger 60, party 20, lift 8, picture 25, breaks 25, after 35, each swap 8"
}

Reply:

{
 "task": "fold-it-down",
 "swaps": [
  {
   "term": "ingestion",
   "plain": "bringing the data in"
  },
  {
   "term": "pipelines",
   "plain": "the paths that carry data"
  },
  {
   "term": "orchestration",
   "plain": "making sure every step runs in order"
  },
  {
   "term": "analytics",
   "plain": "making sense of the numbers"
  },
  {
   "term": "stack",
   "plain": "the set of tools used together"
  },
  {
   "term": "cross-functional",
   "plain": "people from different teams"
  },
  {
   "term": "stakeholders",
   "plain": "people who have an interest in it"
  },
  {
   "term": "ELT",
   "plain": "pulling in and reshaping the data"
  },
  {
   "term": "workflows",
   "plain": "the steps someone follows to get it done"
  },
  {
   "term": "SLAs",
   "plain": "agreed targets it has to meet"
  }
 ],
 "after": "I own bringing data in and keeping it running in order to make sense of numbers, and work with people from different teams to pull in and reshape data, meeting agreed targets for data freshness.",
 "stranger": "I bring data into our systems and keep it running in order, working with people from different teams to pull it in, reshape it, and meet agreed targets for how fresh it stays. Most days that means fixing whatever broke overnight before anyone opens a dashboard, and when the numbers are right, nobody notices, which is the point.",
 "party": "I bring data in, keep it running, and most days fix what breaks overnight before anyone opens a dashboard.",
 "lift": "I keep the numbers right without anyone noticing.",
 "picture": "The job is like keeping a home's electricity and water running, where nothing is noticed unless something breaks overnight.",
 "breaks": "Unlike a home's electricity and water, this job also means working with people from different teams to pull in and reshape data."
}

Build the input yourself

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

const K = FoldKit;
const form = K.form({ job: "Payroll coordinator", blurb: "I reconcile timesheets against the HRIS.", proud: "", paper: "sage" });
const built = K.buildInput(form);       // built.facts holds the flagged words, the knottiest sentence and the sheet
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.md(built, reply, K.title(form))    // the folds as Markdown

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://party-sized.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":"party-sized"}' | 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": "fold-it-down", "job": "Payroll coordinator", "blurb": "I run the monthly payroll cycle...", "proud": "not given", "facts": "...", ...}
# - see the field table
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 party-sized:<task>:<inputHash>:a<attempt> (the one task is fold-it-down), 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="party-sized:fold-it-down:$(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: party-sized:fold-it-down:$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json