← Free Tool Desk / API
Tokens

Drive Free Tool Desk from your own code

The page does its free work in the browser: it reads what your company does and your notes on one free-tool idea (labelled lines or prose), works out what a lead is worth (stated, or your deal size times the share of leads that become customers), the leads a month (stated, or visitors times the visitor-to-lead rate), the build in money and engineer-weeks, the monthly upkeep, and over 12 months the first year's lead value against the first year's cost, the payback and the leads a month the first year needs, with flags FT-01..FT-12 (a first year that costs more than its leads are worth, scraping or third-party APIs, features to skip at first, a build past 4 engineer-weeks, vanity metrics, no gate). Its two paid lanes are available over HTTP. You send one JSON object with task set to "score" or "plan", and the model replies with one JSON object. The easiest way to build the facts string is the page itself: ToolKit.buildInput(lane, ToolKit.analyze(you, tool, {company, goal, question, scores}), {scoreHandoff}) in toolkit.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
"score"The skill's evaluation: a verdict of build, build smaller or don't build (don't build under 15; build only at 25 or more with no FT-01 or FT-08), the tool_type, the goal, the eight-factor scorecard with quotes, the total and band, a reading of the page's math, the closest_case, the pitfalls quoted, the gating, the build_route, conditions and what to find_out.
"plan"The minimum viable tool: one_job, inputs, output, what to skip, lead_capture, the path_to_product, seo, distribution, the build route, 4-8 milestones ordered scope, build, launch, measure, three metrics and maintenance.

Input fields (all strings)

fieldwhencontent
taskrequiredscore or plan
companyrequiredYour company's name (may be empty; the page then reads it from the first line of you).
goaloptionalWhat the tool is for: leads, seo, brand or education.
yourequiredWhat your company does: what you sell and who buys, the deal size, the share of leads that become customers or what a lead is worth, who could build. Past 5,000 characters the page cuts the middle on line boundaries and leaves a [free-tool-desk: ...] marker.
toolrequiredYour notes on the tool idea: what it does, the type, the keyword and its searches, the existing tools, the build cost and effort, the upkeep, the traffic and visitor-to-lead rate, the gate. Cut the same way past 6,000 characters.
factsrequiredA JSON string: company, goal, today, currency, tool{name, type, keyword, searches, visitors, conversion, leads_stated, competitors[], gating, build_cost, build_weeks, maintenance_month, launch_date, external, skip_features[], vanity}, you{product, acv, lead_to_customer, lead_value_stated}, lead_value, self_scores{}, self_total, math{leads_month, leads_basis, value_year, cost_year, ratio, payback_months, breakeven_leads_month}, flags[{id, severity, text}], notes[].
questionoptionalWhat you want to know.
score_handoffplan onlyA JSON string of the score the plan follows: verdict, tool_type, goal, total, gating, route, conditions[].
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: "score"

verdict: build|build smaller|don't build, reason, tool_type: calculator|generator|analyzer|tester|library|interactive, goal: leads|seo|brand|education, scorecard[{factor, score, why, evidence[]}] (exactly eight, in order: search demand exists, audience match to buyers, uniqueness vs existing, natural path to product, build feasibility, maintenance burden (inverse), link-building potential, share-worthiness; each score a whole number 1-5), total (the sum), band: strong candidate|promising|reconsider, math_reading, closest_case{case, why} (Unsplash, HubSpot Website Grader, Baremetrics Forecasting, CoSchedule Headline Analyzer, Moz Keyword Explorer, Buffer Salary Calculator, Shopify Hatchful or none), pitfalls[{pitfall, evidence[]}] (over-engineering, poor product integration, maintenance and security debt, vanity metrics), gating{approach: fully gated|partially gated|ungated + optional|ungated entirely, why}, build_route{route: build custom|no-code|embed existing, why}, conditions[], find_out[].

task: "plan"

source (score handoff|from the input), tool_type, goal, one_job, inputs[] (2 to 6), output, skip[] (1 to 5), lead_capture{approach, value_exchange, fields[], qualifying_question} (email first), path_to_product, seo{landing_keyword, supporting[]}, distribution[], build{route, why}, milestones[{step: scope|build|launch|measure, when, owner, what}] (4 to 8, in step order), metrics[{metric, target}] (exactly three, in order: leads, qualification rate, trial or signup conversion), maintenance{owner, cadence, watch}.

Worked examples

These are the page's own bundled examples (invented companies, people and numbers), with the input as app.js builds it and the saved model reply the page replays for free. One worked example per verdict and per lane, and the score-to-plan handoff.

Score: a contractor vs employee cost calculator with 9,500 searches a month (build)

Input (description, notes and facts shortened here):

{
 "task": "score",
 "company": "Wagequill",
 "you": "Wagequill - payroll and contractor payments for agencies and studios with 10-80 people.\nOur buyer is the founder or the operations lead. ACV is about $4,800.\nAbout 3% of our inbound leads become customers.\nLeads today come from paid search at roughly $95 each and from partner referrals.\nWe have one full-stack engineer and a designer who can spare time this quarter.\n",
 "tool": "Contractor vs employee cost calculator\nType: calculator\nWhat it does: enter a salary or a day rate, the country and the hours, and see the full cost of a contractor against an employee, side by side.\nKeyword: \"contractor vs employee cost calculator\" - about 9,500 searches a month (Ahrefs, US + UK)\nExisting tools: two state-government pages, one accounting firm's spreadsheet\nNone of them compares day rates with salari... (789 characters in all)",
 "facts": "(a JSON string; decoded: company Wagequill, goal leads, tool Contractor vs employee cost calculator (calculator), keyword contractor vs employee cost calculator at 9500 searches a month, build 8000 over 2 engineer-weeks, maintenance 150 a month, a lead worth 144, leads a month 150, first-year value 259200 against cost 9800, ratio 26.4, payback 0.4 months, break-even 6 leads a month; flags none)",
 "goal": "leads",
 "question": "Is this worth a two-week sprint?"
}

Reply:

{
 "task": "score",
 "verdict": "build",
 "reason": "It scores 32 of 40 with no flags, the build is small, and the page's math shows the first year paying for itself many times over.",
 "tool_type": "calculator",
 "goal": "leads",
 "scorecard": [
  {
   "factor": "search demand exists",
   "score": 5,
   "why": "The notes give a measured search volume for the exact keyword.",
   "evidence": [
    "about 9,500 searches a month (Ahrefs, US + UK)"
   ]
  },
  {
   "factor": "audience match to buyers",
   "score": 4,
   "why": "Agencies weighing contractors against employees are the people who pay contractors and run payroll.",
   "evidence": [
    "payroll and contractor payments for agencies and studios with 10-80 people",
    "Our buyer is the founder or the operations lead"
   ]
  },
  {
   "factor": "uniqueness vs existing",
   "score": 4,
   "why": "Existing tools are government pages and a spreadsheet, and none compares day rates with salaries.",
   "evidence": [
    "None of them compares day rates with salaries"
   ]
  },
  {
   "factor": "natural path to product",
   "score": 4,
   "why": "Someone costing a contractor against an employee is close to needing a way to pay them, and success is counted in trials.",
   "evidence": [
    "Success: leads and trials that started on the calculator"
   ]
  },
  {
   "factor": "build feasibility",
   "score": 5,
   "why": "One engineer for two weeks is the size of the skill's winning cases.",
   "evidence": [
    "Build: one engineer, 2 weeks, about $8,000"
   ]
  },
  {
   "factor": "maintenance burden (inverse)",
   "score": 4,
   "why": "Upkeep is small and known, though tax tables need updating twice a year.",
   "evidence": [
    "Maintenance: $150 a month (tax tables updated twice a year)"
   ]
  },
  {
   "factor": "l
... (shortened here; the page shows it whole)

Plan: the same calculator, carrying the score

Input (with the score handed over):

{
 "task": "plan",
 "company": "Wagequill",
 "you": "Wagequill - payroll and contractor payments for agencies and studios with 10-80 people.\nOur buyer is the founder or the operations lead. ACV is about $4,800.\nAbout 3% of our inbound leads become customers.\nLeads today come from paid search at roughly $95 each and from partner referrals.\nWe have one full-stack engineer and a designer who can spare time this quarter.\n",
 "tool": "Contractor vs employee cost calculator\nType: calculator\nWhat it does: enter a salary or a day rate, the country and the hours, and see the full cost of a contractor against an employee, side by side.\nKeyword: \"contractor vs employee cost calculator\" - about 9,500 searches a month (Ahrefs, US + UK)\nExisting tools: two state-government pages, one accounting firm's spreadsheet\nNone of them compares day rates with salari... (789 characters in all)",
 "facts": "(a JSON string; decoded: company Wagequill, goal leads, tool Contractor vs employee cost calculator (calculator), keyword contractor vs employee cost calculator at 9500 searches a month, build 8000 over 2 engineer-weeks, maintenance 150 a month, a lead worth 144, leads a month 150, first-year value 259200 against cost 9800, ratio 26.4, payback 0.4 months, break-even 6 leads a month; flags none)",
 "goal": "leads",
 "question": "Is this worth a two-week sprint?",
 "score_handoff": "{\"verdict\":\"build\",\"tool_type\":\"calculator\",\"goal\":\"leads\",\"total\":32,\"gating\":\"partially gated\",\"route\":\"build custom\",\"conditions\":[]}"
}

Reply:

{
 "task": "plan",
 "source": "score handoff",
 "tool_type": "calculator",
 "goal": "leads",
 "one_job": "Show the full cost of a contractor against an employee, side by side.",
 "inputs": [
  "salary or day rate",
  "country",
  "hours"
 ],
 "output": "The full cost of a contractor and of an employee side by side, with a full PDF breakdown for an email.",
 "skip": [
  "account creation",
  "saving results",
  "advanced features",
  "perfect design",
  "every edge case"
 ],
 "lead_capture": {
  "approach": "partially gated",
  "value_exchange": "Get the full PDF breakdown",
  "fields": [
   "email"
  ],
  "qualifying_question": "How many people work at your agency or studio?"
 },
 "path_to_product": "The PDF breakdown shows how Wagequill runs payroll and contractor payments for agencies and studios and invites the reader to start a trial.",
 "seo": {
  "landing_keyword": "contractor vs employee cost calculator",
  "supporting": [
   "How to compare a day rate with a salary",
   "What does an employee really cost compared with a contractor?"
  ]
 },
 "distribution": [
  "Share it with partner referrals to pass on to their agency and studio clients",
  "Launch it in communities where agency and studio founders and operations leads gather",
  "Offer it as a linkable resource to accounting and payroll blogs, since none of the existing tools compares day rates with salaries"
 ],
 "build": {
  "route": "build custom",
  "why": "One full-stack engineer can build it in 2 weeks for about $8,000, and the cost logic needs its own tax tables."
 },
 "milestones": [
  {
   "step": "scope",
   "when": "this quarter",
   "owner": "full-stack engineer",
   "what": "Fix the inputs, the countries covered and the side-by-side result, leaving out accounts and saved results."
  },
  {
   "st
... (shortened here; the page shows it whole)

Score: a $72,000 website grader with accounts and two paid APIs (build smaller)

Input:

{
 "task": "score",
 "company": "Crawlwren",
 "you": "Crawlwren - a technical SEO agency for B2B software companies.\nWe sell a monthly retainer; the average client pays about $4,000 a month.\nA lead is worth about $120 to us (from last year's closed deals over all inbound leads).\nTwo developers and one designer could be moved onto an internal project.\n",
 "tool": "Crawlwren Site Grader - a website grader for B2B SaaS marketing sites\nIt crawls up to 500 pages of any site, calls the PageSpeed Insights API and the Ahrefs API, and scores technical SEO, speed and content.\nUsers create an account to save their reports, see a dashboard of past scores and invite their team.\nExisting tools: HubSpot Website Grader, Seoptimer, Ubersuggest\nBuild: 3 developers for 8 weeks, about $72,000\nMa... (610 characters in all)",
 "facts": "(a JSON string; decoded: company Crawlwren, goal leads, tool Crawlwren Site Grader (analyzer), keyword - at None searches a month, build 72000 over 24 engineer-weeks, maintenance 1800 a month, a lead worth 120, leads a month 40, first-year value 57600 against cost 93600, ratio 0.6, payback 24 months, break-even 65 leads a month; flags FT-01, FT-06, FT-07, FT-08, FT-09)",
 "goal": "leads"
}

Reply:

{
 "task": "score",
 "verdict": "build smaller",
 "reason": "The idea fits Crawlwren's buyers, but as scoped the first year's leads do not cover the build and running cost and the build is far past the skill's tiny-tool size.",
 "tool_type": "analyzer",
 "goal": "leads",
 "scorecard": [
  {
   "factor": "search demand exists",
   "score": 2,
   "why": "The notes name no keyword and no search volume, only a visitor goal.",
   "evidence": []
  },
  {
   "factor": "audience match to buyers",
   "score": 5,
   "why": "The grader targets the same B2B software companies the agency sells to.",
   "evidence": [
    "a website grader for B2B SaaS marketing sites",
    "a technical SEO agency for B2B software companies"
   ]
  },
  {
   "factor": "uniqueness vs existing",
   "score": 2,
   "why": "Three well-known graders already do this and the notes do not say what this one does better.",
   "evidence": [
    "Existing tools: HubSpot Website Grader, Seoptimer, Ubersuggest"
   ]
  },
  {
   "factor": "natural path to product",
   "score": 4,
   "why": "A technical SEO score leads straight to the agency's technical SEO retainer.",
   "evidence": [
    "scores technical SEO, speed and content"
   ]
  },
  {
   "factor": "build feasibility",
   "score": 2,
   "why": "The build is 24 engineer-weeks, well past a tiny first version.",
   "evidence": [
    "Build: 3 developers for 8 weeks, about $72,000"
   ]
  },
  {
   "factor": "maintenance burden (inverse)",
   "score": 2,
   "why": "A crawler and two third-party APIs carry ongoing fees, hosting and fixes.",
   "evidence": [
    "Maintenance: $1,800 a month (API fees, crawler hosting, fixes)"
   ]
  },
  {
   "factor": "link-building potential",
   "score": 3,
   "why": "The notes say nothing about links, and the grader space is al
... (shortened here; the page shows it whole)

Score: dental software and a crypto tax estimator (don't build)

Input:

{
 "task": "score",
 "company": "Molarly",
 "you": "Molarly - scheduling and billing software for independent dental practices.\nOur buyer is the practice owner or the office manager.\nOur marketing site gets most of its leads from dental conferences and referrals.\n",
 "tool": "Crypto tax estimator\nCrypto is trending and a calculator like this could go viral on social media.\nVisitors connect a wallet and the tool pulls live data from exchange APIs to estimate capital gains tax for the year.\nExisting tools: Koinly, CoinTracker and TurboTax all have free crypto tax calculators\nBuild: one contractor, 6 weeks, about $18,000\nWe would put our logo on it and a link to Molarly at the bottom.\n",
 "facts": "(a JSON string; decoded: company Molarly, goal brand, tool Crypto tax estimator (calculator), keyword - at None searches a month, build 18000 over 6 engineer-weeks, maintenance None a month, a lead worth None, leads a month None, first-year value None against cost 18000, ratio None, payback None months, break-even None leads a month; flags FT-02, FT-04, FT-05, FT-06, FT-08, FT-10)",
 "goal": "brand",
 "question": "Could this go viral and bring us dentists?"
}

Reply:

{
 "task": "score",
 "verdict": "don't build",
 "reason": "It scores 12 of 40: a crypto tax tool is not adjacent to dental practice software, three free versions already exist, and it depends on live exchange APIs.",
 "tool_type": "calculator",
 "goal": "brand",
 "scorecard": [
  {
   "factor": "search demand exists",
   "score": 2,
   "why": "The notes give no keyword and no search volume, only that crypto is trending.",
   "evidence": [
    "Crypto is trending"
   ]
  },
  {
   "factor": "audience match to buyers",
   "score": 1,
   "why": "Crypto tax users are not the dental practice owners and office managers who buy Molarly.",
   "evidence": [
    "Our buyer is the practice owner or the office manager"
   ]
  },
  {
   "factor": "uniqueness vs existing",
   "score": 1,
   "why": "Three well-known products already give this away free.",
   "evidence": [
    "Koinly, CoinTracker and TurboTax all have free crypto tax calculators"
   ]
  },
  {
   "factor": "natural path to product",
   "score": 1,
   "why": "A logo and a footer link are the only connection to scheduling and billing for dental practices.",
   "evidence": [
    "We would put our logo on it and a link to Molarly at the bottom"
   ]
  },
  {
   "factor": "build feasibility",
   "score": 2,
   "why": "Six weeks of a contractor plus wallet connections is past the skill's small builds, and the page flags it.",
   "evidence": [
    "Build: one contractor, 6 weeks, about $18,000"
   ]
  },
  {
   "factor": "maintenance burden (inverse)",
   "score": 1,
   "why": "Live exchange data and tax rules need constant upkeep, and no maintenance is stated.",
   "evidence": [
    "pulls live data from exchange APIs"
   ]
  },
  {
   "factor": "link-building potential",
   "score": 2,
   "why": "The notes say nothing abou
... (shortened here; the page shows it whole)

Plan: a free SSL certificate checker, from the input

Input:

{
 "task": "plan",
 "company": "Stackcrate",
 "you": "Stackcrate - uptime and certificate monitoring for small engineering teams.\nOur buyer is the engineering lead or the solo founder who gets paged.\nACV: $1,200. Lead-to-customer: 5%.\nMost signups come from a free plan; developers find us through our blog.\n",
 "tool": "SSL certificate checker\nType: tester\nWhat it does: enter a domain and see the certificate's issuer, expiry date, chain and common misconfigurations, in under two seconds.\nKeyword: \"ssl checker\" - 40,000 searches a month\nExisting tools: SSL Labs, DigiCert's checker\nBuild: one engineer, 1 week, $3,500\nMaintenance: $80 a month\nGating: ungated + optional - email to get an alert 14 days before the certificate expires\nLaun... (506 characters in all)",
 "facts": "(a JSON string; decoded: company Stackcrate, goal leads, tool SSL certificate checker (tester), keyword ssl checker at 40000 searches a month, build 3500 over 1 engineer-weeks, maintenance 80 a month, a lead worth 60, leads a month 200, first-year value 144000 against cost 4460, ratio 32.3, payback 0.3 months, break-even 7 leads a month; flags none)",
 "goal": "leads"
}

Reply:

{
 "task": "plan",
 "source": "from the input",
 "tool_type": "tester",
 "goal": "leads",
 "one_job": "Check a domain's SSL certificate and show its issuer, expiry date, chain and common misconfigurations.",
 "inputs": [
  "domain",
  "email for the expiry alert (optional)"
 ],
 "output": "The certificate's issuer, expiry date, chain and common misconfigurations, in under two seconds.",
 "skip": [
  "account creation",
  "saving results or check history",
  "advanced features beyond the one check",
  "perfect design",
  "every edge case"
 ],
 "lead_capture": {
  "approach": "ungated + optional",
  "value_exchange": "Get an alert 14 days before this certificate expires",
  "fields": [
   "email"
  ],
  "qualifying_question": "How many domains does your team look after?"
 },
 "path_to_product": "The expiry alert is a free taste of Stackcrate's certificate monitoring, so each alert email invites the user onto the free plan to monitor uptime and certificates.",
 "seo": {
  "landing_keyword": "ssl checker",
  "supporting": [
   "How to check when an SSL certificate expires",
   "What is an SSL certificate chain?",
   "How to fix common SSL misconfigurations"
  ]
 },
 "distribution": [
  "Launch it on the Stackcrate blog, where developers already find you",
  "Link it from blog posts on certificates and uptime",
  "Share it in developer communities with an example check",
  "Pitch it to [resource pages] that list SSL tools"
 ],
 "build": {
  "route": "build custom",
  "why": "The notes scope it to one engineer and one week, and certificate checks are close to what Stackcrate already does."
 },
 "milestones": [
  {
   "step": "scope",
   "when": "[date]",
   "owner": "Ines Varrowby (growth engineer)",
   "what": "Fix the one check, the result screen and the optional alert, and
... (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 a score, the eight factors in the skill's order, each a whole number from 1 to 5, a 4 or 5 only with a quote, the caps for an oversized build (FT-08) and for scraping or third-party APIs (FT-06), the total as the sum and the band that follows it, don't build under 15, build only at 25 or more with neither FT-01 nor FT-08, conditions for build smaller, the goal you chose, and only the skill's cases, pitfalls (quoted), gates and routes. For a plan, the goal you chose, one job, 2 to 6 inputs, 1 to 5 things to skip, a gate with email first, a path to the product, your keyword, 4 to 8 milestones ordered scope, build, launch, measure, and exactly leads, qualification rate and trial or signup conversion. In both, quotes are checked word for word and no cost, count, rate, date or duration may be invented. 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://free-tool-desk.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":"free-tool-desk"}' | 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": "score", "company": "...", "goal": "leads", "you": "...", "tool": "...", "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 free-tool-desk:<lane>:<inputHash>:a<attempt>. The job's output.output is the reply text; truncated: true means the balance cut it short.

KEY="free-tool-desk:score:$(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 (plan)

The same run as Server-Sent Events. plan.json is a plan-lane input, with score_handoff when it follows a score.

# 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: free-tool-desk:plan:$(shasum -a 256 plan.json | cut -c1-16):a1" --data @plan.json