Run Platform Hire from your own code
Both metered lanes are available over HTTP and each returns one JSON object. The division of labour: the page scans the posting for who the role serves and for build work stacked with outreach work, ranks the hire, weights the competencies for the track, plans the loop against the interviewer-hour budget, and checks outcomes, the loop, sourcing and compensation, then hands it all to the run as facts. The run writes the scorecard or the loop; the page then holds it to its own facts (phreply.js).
Base URL and the response shape
Every endpoint lives under https://api.skillsafe.ai/v1/app-api, and every response has one shape:
{ "ok": true, "data": { ... } }
{ "ok": false, "error": { "code": "...", "message": "..." } }
The token is minted for this app (the guest call takes {"slug":"platform-hire"}), so no slug header is needed afterwards. Send it as Authorization: Bearer YOUR_TOKEN. The run body is the input object, sent bare.
| Status | Code | Meaning |
|---|---|---|
| 400 | validation_error | The body is not a JSON object, or a required key (task, role, posting, facts) is missing. The page always sends all five of task, role, posting, carry, facts; carry is an empty string for scorecard. |
| 401 | unauthorized | No token, or a stale one. Mint a guest token or sign in again. |
| 402 | insufficient_credits | The balance is under min_credits. Price with /estimate first. |
| 403 | forbidden | A guest token tried to run: both lanes are metered and need a personal sign-in. |
| 404 | not_found | Unknown job id. |
| 429 | rate_limited | Back off and retry. |
| 5xx | server_error | Transient. Retry with the same Idempotency-Key so a retry never double-bills. |
The task field comes first
Two lanes, chosen by task, in the order the work runs - before the posting goes out, then before the first candidate:
scorecard- the role scorecard: the calibration, a mission with its metric, three to eight quantified outcomes, the weighted competencies, the shape of the hire and the posting fixes.loop- the interview loop stage by stage, the sourcing plan and what to avoid, and the compensation anchor.
A missing or unknown task is answered as scorecard; an internal-platform hire is refused before it runs. Both lanes send the same five fields. The facts are the page's checks, one row per line, and a line starting "must:" is a rule the reply has to hold. The page's handoff carries the scorecard into carry for the loop lane.
The input
| Field | Required | What |
|---|---|---|
task | yes | scorecard or loop. If it is missing or neither, do scorecard and set "task": "scorecard". |
role | yes | the company and the role, who consumes what it builds, the archetype and track, first hire or addition, what it is measured on, resourcing, the compensation stance, deadline, reuse, the interviewer-hour budget and the recruiter; "not given" means not given. |
posting | yes | the draft posting, the outcomes drafted, the loop drafted and the sourcing channels drafted. |
carry | send it (empty for scorecard) | loop task only: the scorecard decisions, when the scorecard task ran first; may be empty. |
facts | yes | the page's checks, one line each as area | id | status | evidence, the verdict and the rankings. A line starting "must:" applies to your reply. |
retry_note | no | optional; if present, your previous reply was unusable - follow it. |
The rules the model applies
From the source skill, @samber/developer-platform-hiring - the only standard the run applies:
- "Platform engineer" mostly means internal developer platforms - self-service infrastructure for a company's own engineers. This hire is the other meaning: the role builds for developers outside the company - customers, partners, third-party app builders - and the posting says so plainly.
- Calibrate to the archetype: an API-first company, where the API is the product, needs the deepest technical bar; a company bolting a public API onto its product usually folds the hire into general backend hiring; an enterprise platform with a partner ecosystem needs the relationship-plus-technical hybrid. Most API teams run at one to nine people, so a first dedicated hire is a resourcing shift, not a backfill.
- The scorecard: a one-sentence mission naming the archetype and the metric the role is measured on, three to eight measurable outcomes - never "own the platform" - and competencies weighted per track.
- Scope collapse: a posting that stacks build work (API design, partner integration architecture) with outreach work (developer marketing, content, talks) in one seat with no headcount plan is three full-time jobs in one. Each skill can be held by one strong person; the failure is execution volume. Split the scope across hires, or state the resourcing, before the posting goes out. No named, sourced red-flag taxonomy exists for these roles - this is a structural inference.
- The loop: engineering tracks get an API-design interview judged on developer-facing usability and misuse-resistance rather than raw scale; the API Product Manager track weights a scoping and design-thinking round over coding; Partner and Integration Engineers follow a structured sequence - recruiter call, hiring-manager interview, two to five team interviews, an executive round for senior hires. This is an assembled design, not an industry standard. A tight interviewer-hour budget deletes stages rather than reordering them.
- Sourcing: apidays for API platform engineers and API product managers, never PlatformCon, which serves the internal-platform population; general senior backend channels - referrals, senior-IC pipelines, open-source contribution history - for engineering tracks; general technical product-management sourcing filtered for developer-facing products for the PM track.
- Compensation: anchor to the company's general engineering or product-management bands at the equivalent level, with a named source and date - never a bespoke platform-title salary search. GitLab's or Stripe's leveling is one sourced example, never a universal standard.
House rules
- Use only the input. Never invent a company, a person, a figure, a salary or a date - except a value a field below asks you to propose (a target, a deadline, an interviewer role, a range), always labelled as proposed.
- The page's rankings, weights, loop and checks are settled: never move a stage, change a weight, rank differently or call a failed gate fine. Write the target state: where the input shows a gap, give what replaces it; the gap itself belongs in a caveat.
- No web links (http or https).
- Write in the language of the input; keep the JSON keys and the shape and stage ids as given.
- Never use backticks and never write the input's field names as labels in your text. Words and terms of art from the rules above are free to use; what you never do is paste a whole sentence or quoted saying from this prompt, or state a rule with no fact of this hire in it.
- Never write a gendered pronoun for a candidate or interviewer; write they or the role.
- Reply with ONLY one JSON object - no prose before or after, no code fences.
The replies
scorecard
Write the role scorecard and the posting fixes the hiring manager will use.
summary- one sentence, at most 40 words: the shape of the hire, and the first thing that must change.calibration- one sentence: that the role serves developers outside the company, the archetype and the track - the veto-able calibration.mission- one sentence naming the archetype and the metric the role is measured on.outcomes- three to eight objects:outcome(what changes, in this company's terms),measure(the number and by when - labelled proposed when the input gives none).competencies- one object per competency the facts weight, in the same order:competency(as the facts name it),weight(the number the facts give).shape-shape(dedicated,splitorfold, exactly as the facts rank first),fix(one sentence: what that means for this hire - for a split, which work this hire keeps and which the next hire takes).posting_fixes- short strings: the edits the posting needs before it goes out (who the role serves, outcomes with numbers, the scope split or the headcount plan);[]when none.caveats- at most 4 short strings;[]when there is nothing to say.
{
"task": "scorecard",
"summary": "one sentence",
"calibration": "one sentence",
"mission": "one sentence",
"outcomes": [ { "outcome": "what changes", "measure": "a number and a date" } ],
"competencies": [ { "competency": "as the facts name it", "weight": 35 } ],
"shape": { "shape": "dedicated", "fix": "one sentence" },
"posting_fixes": [ "an edit" ],
"caveats": [ ]
}
The page holds it to its own facts (check() in phreply.js; any warning makes the reply flagged): the reply answers the task it was sent; no web link; no backticks; a summary of at most 40 words; a calibration naming developers outside the company; a mission; three to eight outcomes, each with a number; the page's competencies with exactly its weights, in order; the ranked hire shape; for a collapsed posting, a split or a headcount plan; posting fixes when a posting was pasted.
loop
Write the interview loop, the sourcing plan and the compensation stance.
summary- one sentence, at most 40 words.stages- one object per stage of the page's loop, in its order, no others:stage(the page's stage id),name(its name for this company),interviewer(the role who runs it - as the input names one, or proposed),minutes(a number - the page's),judges(one sentence: what this stage decides for this hire).sourcing- at least two objects:channel,why(one sentence tied to this track).avoid- short strings: the channels to avoid and why, PlatformCon among them.comp-anchor(one sentence: the general engineering or product-management ladder and the equivalent level),source(the named source with its date, as the input gives it, or proposed and said so).caveats- at most 4 short strings;[]when there is nothing to say.
{
"task": "loop",
"summary": "one sentence",
"stages": [ { "stage": "recruiter", "name": "Recruiter screen", "interviewer": "a role", "minutes": 30, "judges": "one sentence" } ],
"sourcing": [ { "channel": "a channel", "why": "one sentence" } ],
"avoid": [ "a channel and why" ],
"comp": { "anchor": "one sentence", "source": "a named, dated source" },
"caveats": [ ]
}
The page requires: the reply answers the task it was sent; the same text rules; the page's loop stages in order, each with an interviewer, minutes and what it judges, inside the interviewer-hour budget; no coding round for the PM track; apidays for the platform and PM tracks; at least two channels and never PlatformCon among them; PlatformCon named among the channels to avoid; compensation anchored to the general engineering or PM ladder, not a bespoke-title search, with a dated source or one proposed.
Worked examples
Three runs from the page's free samples (invented companies): the scorecard for a first public API with three jobs in one seat, the loop for the same hire carrying that scorecard, and the scorecard for an API-first company hiring a senior engineer. Each input is exactly what the page sends; each reply is the saved reply the sample replays, shipped unedited - but the facts and long strings are shortened in this display only, and every cut is listed under the example. The last line is the page's own check of the full reply.
scorecard - A first public API with three jobs in one seat
The page read it as: three jobs in one seat - split the scope first; track platform; hire split, fold, dedicated; 1 of 6 gates; failing checks: scope, outcomes, loop, sourcing, comp.
Input (facts is 2859 characters; the first 1395 are shown):
{
"task": "scorecard",
"role": "Company: Relaywise\nThe company and the role: A scheduling app for clinics that is adding its first public API so practice-management vendors can book appointments into it.\nWho consumes what the role builds: developers outside the company; archetype: A company bolting a public API onto its product; track: Platform Engineer / Architect\nFirst dedicated hire: yes; measured on: API design quality and contract stability; resourcing: solo ownership\nCompensation: from a bespoke platform-title search; range: $185k-$210k; source: salary-site search for platform engineer\nDeadline: this quarter; a one-off hire; interviewer-hours per candidate: 6; recruiter: no; effort ceiling: medium; as-of: 2026-11-01",
"posting": "Draft posting:\nPlatform Engineer - Relaywise\nYou will design our first public API and own the endpoints, versioning and SDKs that third-party developers use.\nYou will onboard our first ten partners and keep every integration healthy.\nYou will write tutorials and blog posts, speak at conferences and grow our developer community.\nYou report to the CTO and own the platform end to end.\n\nOutcomes drafted (outcome | has a number):\n- Own the public API | no\n- Ship the first 10 partner integrations | yes\n- Grow the developer community | no\n\nLoop drafted (stage | interviewer | minutes | format):\n- Recruiter screen | recruiter | 30 | call\n- System design | staff engineer | 60 | whiteboard\n- Coding | senior engineer | 60 | live coding\n\nSourcing channels drafted:\n- PlatformCon job board\n- Backstage community Slack\n- LinkedIn",
"carry": "",
"facts": "The page's checks (5 fail, 2 warn, 1 pass, 4 n/a); verdict: three jobs in one seat - split the scope first:\n- The posting | calibration | na | A company bolting a public API onto its product; Platform Engineer / Architect; measured on api design quality and contract stability\n- The posting | consumer | pass | names public api, sdks, third-party\n- The posting | scope | fail | build work (design our first public api, endpoints, versioning, sdks), partner work (partners) and outreach work (tutorials, blog, conferences, community) in one seat, owned solo, with no headcount plan\n- The posting | first | warn | a real resourcing shift, not a backfill - most API teams run at 1-9 people; size the hire to the actual team\n- The scorecard | outcomes | fail | 3 outcomes; no number in \"Own the public API\", \"Grow the developer community\"\n- The scorecard | weights | na | API and system design 35%, Infrastructure delivery 25%, Developer-facing usability judgment 20%, Collaboration 10%, Written communication 10%\n- The scorecard | shape | na | Split the scope across hires > Fold into general backend or PM hiring > One dedicated specialist hire - a bolt-on public API usually folds this hire into general backend hiring; the posting stacks build work and outreach work with no headcount plan - split the scope\n- The loop and sourcing | loop | fail | a general system-design round stands in for the\n\n[... 1464 more characters cut from this display ...]"
}
Reply:
{
"task": "scorecard",
"summary": "Relaywise's draft stacks API build, partner onboarding and developer outreach into one solo seat; split it so this first hire owns the public booking API and its partner integrations, and outreach goes to a later hire.",
"calibration": "This hire builds for developers outside Relaywise, the practice-management vendors booking appointments through the new public API, at a company bolting a public API onto its product, on the Platform Engineer / Architect track.",
"mission": "Design and run Relaywise's first public booking API, a public API bolted onto a clinic scheduling product, measured on API design quality and contract stability for the vendors integrating with it.",
"outcomes": [
{
"outcome": "The first public booking API ships with a published, versioned contract that practice-management vendors can build against",
"measure": "v1 contract published by 2027-03-31 (proposed)"
},
{
"outcome": "Vendors integrating with the API see no unannounced breaking changes",
"measure": "0 breaking changes per quarter after v1 ships (proposed)"
},
{
"outcome": "The first ten partner integrations go live on the API",
"measure": "10 live partner integrations by 2027-06-30 (proposed date)"
},
{
"outcome": "Vendors get a working booking call quickly from the docs and SDK",
"measure": "median time to first successful booking call under 1 day for the first 10 partners (proposed)"
},
{
"outcome": "Partner integrations stay healthy once live",
"measure": "under 2 partner-reported integration incidents per month by 2027-06-30 (proposed)"
}
],
"competencies": [
{
"competency": "API and system design",
"weight": 35
},
{
"competency": "Infrastructure delivery",
"weight": 25
},
{
"competency": "Developer-facing usability judgment",
"weight": 20
},
{
"competency": "Collaboration",
"weight": 10
},
{
"competency": "Written communication",
"weight": 10
}
],
"shape": {
"shape": "split",
"fix": "This Relaywise hire keeps the build work - endpoints, versioning, SDKs and the integration architecture for the first ten partners - while tutorials, blog posts, conference talks and community growth move to a separate later hire."
},
"posting_fixes": [
"Cut the tutorials, blog posts, conference talks and developer-community lines, or name the separate hire who will own them.",
"Replace own the platform end to end with ownership of the public booking API contract, versioning and SDKs.",
"Name practice-management vendors as the developers the API serves.",
"Swap Own the public API and Grow the developer community for outcomes with numbers and dates, such as 0 breaking changes per quarter (proposed).",
"State the resourcing: solo ownership reporting to the CTO for now, with the outreach hire planned."
],
"caveats": [
"A bolt-on public API often folds into general backend hiring; a dedicated seat here is a resourcing shift for Relaywise, not a backfill.",
"The $185k-$210k range comes from a salary-site platform-engineer search; re-anchor it to Relaywise's general engineering bands before posting.",
"The drafted loop uses a general system-design round where an API-design interview belongs.",
"PlatformCon and the Backstage community Slack reach internal-platform engineers, not this hire."
]
}
What step 5 prints for it: The first public booking API ships with a published, versioned contract that practice-management vendors can build against: v1 contract published by 2027-03-31 (proposed) | Vendors integrating with the API see no unannounced breaking changes: 0 breaking changes per quarter after v1 ships (proposed) | The first ten partner integrations go live on the API: 10 live partner integrations by 2027-06-30 (proposed date) | Vendors get a working booking call quickly from the docs and SDK: median time to first successful booking call under 1 day for the first 10 partners (proposed) | Partner integrations stay healthy once live: under 2 partner-reported integration incidents per month by 2027-06-30 (proposed)
The page's check: kept - nothing to flag
loop - A first public API with three jobs in one seat
The input carries the saved scorecard (R.laneForm fills carry from the scorecard reply), as the page's handoff does. The page's loop: wire, wireShown, wireNote, reply, shown, cuts, status, notes, carried, gist.
Input (facts is 2770 characters; the first 1395 are shown):
{
"task": "loop",
"role": "Company: Relaywise\nThe company and the role: A scheduling app for clinics that is adding its first public API so practice-management vendors can book appointments into it.\nWho consumes what the role builds: developers outside the company; archetype: A company bolting a public API onto its product; track: Platform Engineer / Architect\nFirst dedicated hire: yes; measured on: API design quality and contract stability; resourcing: solo ownership\nCompensation: from a bespoke platform-title search; range: $185k-$210k; source: salary-site search for platform engineer\nDeadline: this quarter; a one-off hire; interviewer-hours per candidate: 6; recruiter: no; effort ceiling: medium; as-of: 2026-11-01",
"posting": "Draft posting:\nPlatform Engineer - Relaywise\nYou will design our first public API and own the endpoints, versioning and SDKs that third-party developers use.\nYou will onboard our first ten partners and keep every integration healthy.\nYou will write tutorials and blog posts, speak at conferences and grow our developer community.\nYou report to the CTO and own the platform end to end.\n\nOutcomes drafted (outcome | has a number):\n- Own the public API | no\n- Ship the first 10 partner integrations | yes\n- Grow the developer community | no\n\nLoop drafted (stage | interviewer | minutes | format):\n- Recruiter screen | recruiter | 30 | call\n- System design | staff engineer | 60 | whiteboard\n- Coding | senior engineer | 60 | live coding\n\nSourcing channels drafted:\n- PlatformCon job board\n- Backstage community Slack\n- LinkedIn",
"carry": "Calibration: This hire builds for developers outside Relaywise, the practice-management vendors booking appointments through the new public API, at a company bolting a public API onto its product, on the Platform Engineer / Architect track.\nMission: Design and run Relaywise's first public booking API, a public API bolted onto a clinic scheduling product, measured on API design quality and contract stability for the vendors integrating with it.\nOutcomes: The first public booking API ships with a published, versioned contract that practice-management vendors can build against (v1 contract published by 2027-03-31 (proposed)); Vendors integrating with the API see no unannounced breaking changes (0 breaking changes per quarter after v1 ships (proposed)); The first ten partner integrations go live on the API (10 live partner integrations by 2027-06-30 (proposed date)); Vendors get a working booking call quickly from the docs and SDK (median time to first successful booking call under 1 day for the first 10 partners (proposed)); Partner integrations stay healthy once live (under 2 partner-reported integration incidents per month by 2027-06-30 (proposed))\nCompetencies: API and system design 35, Infrastructure delivery 25, Developer-facing usability judgment 20, Collaboration 10, Written communication 10\nHire: Split the scope across hires",
"facts": "The page's checks (5 fail, 2 warn, 1 pass, 4 n/a); verdict: three jobs in one seat - split the scope first:\n- The posting | calibration | na | A company bolting a public API onto its product; Platform Engineer / Architect; measured on api design quality and contract stability\n- The posting | consumer | pass | names public api, sdks, third-party\n- The posting | scope | fail | build work (design our first public api, endpoints, versioning, sdks), partner work (partners) and outreach work (tutorials, blog, conferences, community) in one seat, owned solo, with no headcount plan\n- The posting | first | warn | a real resourcing shift, not a backfill - most API teams run at 1-9 people; size the hire to the actual team\n- The scorecard | outcomes | fail | 3 outcomes; no number in \"Own the public API\", \"Grow the developer community\"\n- The scorecard | weights | na | API and system design 35%, Infrastructure delivery 25%, Developer-facing usability judgment 20%, Collaboration 10%, Written communication 10%\n- The scorecard | shape | na | Split the scope across hires > Fold into general backend or PM hiring > One dedicated specialist hire - a bolt-on public API usually folds this hire into general backend hiring; the posting stacks build work and outreach work with no headcount plan - split the scope\n- The loop and sourcing | loop | fail | a general system-design round stands in for the\n\n[... 1375 more characters cut from this display ...]"
}
Reply:
{
"task": "loop",
"summary": "Relaywise runs a thin five-stage loop with the CTO screening, an API-design interview replacing the general system-design round, apidays plus senior backend sourcing, and pay re-anchored to the general engineering ladder.",
"stages": [
{
"stage": "recruiter",
"name": "Screen call with the CTO",
"interviewer": "CTO, as hiring manager, since Relaywise has no recruiter",
"minutes": 30,
"judges": "Whether the candidate wants to build a first public booking API for practice-management vendors, solo, with outreach handed to a later hire."
},
{
"stage": "manager",
"name": "Hiring-manager interview",
"interviewer": "CTO",
"minutes": 45,
"judges": "Whether the candidate can own contract stability and versioning for Relaywise's first public API without a platform team around them."
},
{
"stage": "apidesign",
"name": "API-design interview: appointment booking for vendors",
"interviewer": "staff engineer (proposed)",
"minutes": 60,
"judges": "Whether the booking API the candidate designs is easy for practice-management vendors to use correctly and hard to misuse, with double bookings and versioning handled in the contract."
},
{
"stage": "system",
"name": "System and infrastructure delivery",
"interviewer": "staff engineer",
"minutes": 60,
"judges": "Whether the candidate can ship and run the API alongside the clinic scheduling product reliably enough to keep ten partner integrations healthy."
},
{
"stage": "practical",
"name": "Practical coding exercise",
"interviewer": "senior engineer",
"minutes": 60,
"judges": "Whether the candidate writes clear, tested endpoint and SDK code at the pace a solo owner needs."
}
],
"sourcing": [
{
"channel": "apidays speakers and attendees",
"why": "It gathers the API platform engineers who have designed public contracts, which is the core of this Relaywise seat."
},
{
"channel": "Referrals for senior backend engineers",
"why": "A bolt-on API sits close to general backend work, so referrals of senior backend engineers reach people who can also run the scheduling product's services."
},
{
"channel": "Open-source contributors to API tooling and SDKs",
"why": "Public contribution history shows versioning and SDK judgment before the API-design interview."
},
{
"channel": "LinkedIn senior-IC searches filtered for public API work",
"why": "Kept from the draft but narrowed to engineers who have shipped APIs for outside developers."
}
],
"avoid": [
"PlatformCon job board - it reaches internal developer platform engineers, not builders of an API for outside vendors.",
"Backstage community Slack - same internal-platform population, building portals for their own company's engineers."
],
"comp": {
"anchor": "Anchor the offer to Relaywise's general engineering ladder at the senior backend engineer level (proposed), and replace the $185k-$210k range drawn from a platform-title search.",
"source": "Relaywise general engineering ladder, senior band, reviewed 2026-11 (proposed source and date; the draft's salary-site platform-engineer search is not a valid anchor)"
},
"caveats": [
"With no recruiter, the CTO carries the screen and the manager interview, 75 minutes of the 4.3 interviewer-hours.",
"The team interview is dropped because this is a one-off hire.",
"Re-anchoring may move the range off $185k-$210k; post no range until the ladder band is confirmed."
]
}
What step 5 prints for it: recruiter: 30 | manager: 45 | apidesign: 60 | system: 60 | practical: 60
The page's check: kept - nothing to flag
scorecard - An API-first company hiring a senior engineer
The page read it as: a platform hire ready to post; track platform; hire dedicated, split, fold; 6 of 6 gates; failing checks: none.
Input (facts is 2075 characters; the first 1391 are shown):
{
"task": "scorecard",
"role": "Company: Tollvane\nThe company and the role: An API-first payments company whose product is its API; the platform team of six is adding a senior engineer.\nWho consumes what the role builds: developers outside the company; archetype: An infrastructure or API-first company; track: Platform Engineer / Architect, senior\nFirst dedicated hire: no, an addition to a platform team; measured on: API design quality and contract stability; resourcing: a small team\nCompensation: anchored to the general ladder; range: $210k-$240k base, L5; source: Tollvane engineering ladder, L5 band, reviewed 2026-09\nDeadline: this quarter; the first of several hires; interviewer-hours per candidate: 6; recruiter: yes; effort ceiling: high; as-of: 2026-11-01",
"posting": "Draft posting:\nSenior Platform Engineer - Tollvane\nDesign and evolve the public payments API that external developers and integrators build on.\nOwn versioning and the API contract for the payouts endpoints.\nJoin a platform team of six; we plan to hire a second engineer next year.\n\nOutcomes drafted (outcome | has a number):\n- Cut breaking changes on the payouts API to 0 per quarter | yes\n- Bring p95 latency on the payouts endpoints under 250 ms by Q3 | yes\n- Ship the v2 payouts contract to 3 pilot integrators by June | yes\n- Raise the SDK quickstart completion rate from 40% to 70% | yes\n\nLoop drafted (stage | interviewer | minutes | format):\n- Recruiter screen | recruiter | 30 | call\n- Hiring-manager interview | platform lead | 45 | conversation\n- API-design interview | staff engineer | 60 | design a webhooks API\n- System and infrastructure delivery | principal engineer | 60 | architecture\n- Practical coding exercise | senior engineer | 60 | pairing\n- Team interview | two engineers | 45 | panel\n- Executive round | CTO | 30 | conversation\n\nSourcing channels drafted:\n- apidays speaker and attendee lists\n- Referrals from the platform team\n- Open-source maintainers of API tooling\n- Senior backend engineering pipelines",
"carry": "",
"facts": "The page's checks (0 fail, 0 warn, 6 pass, 4 n/a); verdict: a platform hire ready to post:\n- The posting | calibration | na | An infrastructure or API-first company; Platform Engineer / Architect; measured on api design quality and contract stability\n- The posting | consumer | pass | names external developers, integrators\n- The posting | scope | pass | 1 function named\n- The scorecard | outcomes | pass | 4 outcomes; all quantified\n- The scorecard | weights | na | API and system design 35%, Infrastructure delivery 25%, Developer-facing usability judgment 20%, Collaboration 10%, Written communication 10%\n- The scorecard | shape | na | One dedicated specialist hire > Split the scope across hires > Fold into general backend or PM hiring\n- The loop and sourcing | loop | pass | 7 stages that fit the Platform Engineer / Architect track\n- The loop and sourcing | plan | na | Recruiter screen 30 min, Hiring-manager interview 45 min, API-design interview 60 min, System and infrastructure delivery 60 min, Practical coding exercise 60 min, Team interview 45 min, Executive round 30 min - 5.5 interviewer-hours\n- The loop and sourcing | sourcing | pass | apidays speaker and attendee lists, Referrals from the platform team, Open-source maintainers of API tooling, Senior backend engineering pipelines\n- Compensation | comp | pass | anchored to the general ladder at $210k-$240k base, L5 -\n\n[... 684 more characters cut from this display ...]"
}
Reply:
{
"task": "scorecard",
"summary": "Tollvane's senior platform engineer is a dedicated addition to a six-person API team and the posting is ready; first, give the June and Q3 targets a year before it goes out.",
"calibration": "This hire builds the public payments API for developers and integrators outside Tollvane, an infrastructure or API-first company, on the Platform Engineer / Architect track at senior level.",
"mission": "Evolve the payouts endpoints of Tollvane's public payments API, the product of an API-first company, measured on API design quality and contract stability for the external developers who build on it.",
"outcomes": [
{
"outcome": "External developers on the payouts API stop absorbing breaking changes",
"measure": "0 breaking changes per quarter on the payouts API"
},
{
"outcome": "The payouts endpoints answer fast enough for integrators' checkout and payout flows",
"measure": "p95 latency under 250 ms by Q3 2027 (proposed year)"
},
{
"outcome": "The v2 payouts contract is proven with real integrators before general release",
"measure": "v2 contract live with 3 pilot integrators by June 2027 (proposed year)"
},
{
"outcome": "New developers get from the SDK quickstart to a working call",
"measure": "quickstart completion rate from 40% to 70% by Q3 2027 (proposed date)"
}
],
"competencies": [
{
"competency": "API and system design",
"weight": 35
},
{
"competency": "Infrastructure delivery",
"weight": 25
},
{
"competency": "Developer-facing usability judgment",
"weight": 20
},
{
"competency": "Collaboration",
"weight": 10
},
{
"competency": "Written communication",
"weight": 10
}
],
"shape": {
"shape": "dedicated",
"fix": "Tollvane hires one senior specialist into the existing six-person platform team to own versioning and the payouts contract, with the second engineer planned for next year kept as a separate seat."
},
"posting_fixes": [
"Add the year to the June and Q3 targets, for example June 2027 and Q3 2027 (proposed).",
"Give the quickstart completion target a date, such as Q3 2027 (proposed)."
],
"caveats": [
"The 2027 years on the June and Q3 targets are proposed; the draft gives no year."
]
}
What step 5 prints for it: External developers on the payouts API stop absorbing breaking changes: 0 breaking changes per quarter on the payouts API | The payouts endpoints answer fast enough for integrators' checkout and payout flows: p95 latency under 250 ms by Q3 2027 (proposed year) | The v2 payouts contract is proven with real integrators before general release: v2 contract live with 3 pilot integrators by June 2027 (proposed year) | New developers get from the SDK quickstart to a working call: quickstart completion rate from 40% to 70% by Q3 2027 (proposed date)
The page's check: kept - nothing to flag
Build the input yourself
Load the engine in node (global.window = global; require("./phkit.js"); require("./phreply.js")), then:
const K = HireKit, R = HireReply;
const f = K.form(Object.assign(K.blank(), { name: "Acme", track: "platform", archetype: "bolton", comp: "bespoke",
posting: "Design our public API and SDKs for third-party developers. Write blog posts and speak at conferences.",
outcomes: "Own the public API" }));
// f.scanned (the posting scan), f.shapeRank (the ranked hire), f.plan (the page's loop), f.gates
// K.auditMd(f), K.loopCsv(f) - the posting self-audit and the loop schedule
const b = K.buildInput(f, "scorecard"); // or "loop" (R.laneForm(form, "loop", scorecard) fills carry)
const wire = K.toWire(b.input); // POST this to /estimate and /run
// then: const reply = R.normalize(R.parseReply(job.output.output), "scorecard");
// R.check(reply, b) // {status: kept or flagged, notes}
Get a token for the steps below from /tokens.html.
Step 1 — a tiny client helper
One function that sends JSON and unwraps the response. 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="YOUR_TOKEN" # from https://platform-hire.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"}
}
import json, urllib.request
BASE = "https://api.skillsafe.ai/v1/app-api"
TOKEN = "YOUR_TOKEN" # from https://platform-hire.skillsafe.ai/tokens.html
def api(method, path, body=None, headers=None):
req = urllib.request.Request(BASE + path, method=method,
data=None if body is None else json.dumps(body).encode(),
headers={"Content-Type": "application/json", **({"Authorization": "Bearer " + TOKEN} if TOKEN else {}), **(headers or {})})
with urllib.request.urlopen(req) as r:
env = json.load(r)
if env.get("error"):
raise RuntimeError(env["error"])
return env["data"]
// platform-hire.mjs -- Node 18+ (global fetch)
const BASE = "https://api.skillsafe.ai/v1/app-api";
let TOKEN = "YOUR_TOKEN"; // from https://platform-hire.skillsafe.ai/tokens.html
async function api(method, path, body, headers = {}) {
const r = await fetch(BASE + path, { method, headers: { "Content-Type": "application/json",
...(TOKEN ? { Authorization: "Bearer " + TOKEN } : {}), ...headers },
body: body === undefined ? undefined : JSON.stringify(body) });
const env = await r.json();
if (env.error) throw new Error(env.error.code + ": " + env.error.message);
return env.data;
}
package main
import ("bytes"; "encoding/json"; "fmt"; "net/http")
const base = "https://api.skillsafe.ai/v1/app-api"
var token = "YOUR_TOKEN" // from https://platform-hire.skillsafe.ai/tokens.html
func api(method, path string, body any, headers map[string]string) (map[string]any, error) {
var buf bytes.Buffer
if body != nil { json.NewEncoder(&buf).Encode(body) }
req, _ := http.NewRequest(method, base+path, &buf)
req.Header.Set("Content-Type", "application/json")
if token != "" { req.Header.Set("Authorization", "Bearer "+token) }
for k, v := range headers { req.Header.Set(k, v) }
res, err := http.DefaultClient.Do(req)
if err != nil { return nil, err }
defer res.Body.Close()
var env struct { Data map[string]any; Error map[string]any }
json.NewDecoder(res.Body).Decode(&env)
if env.Error != nil { return nil, fmt.Errorf("%v", env.Error) }
return env.Data, nil
}
// Platform Hire.java -- Java 17+, with com.fasterxml.jackson.core:jackson-databind
import com.fasterxml.jackson.databind.*;
import java.net.URI; import java.net.http.*; import java.util.*;
public class Platform Hire {
static final String BASE = "https://api.skillsafe.ai/v1/app-api";
static String token = "YOUR_TOKEN"; // from https://platform-hire.skillsafe.ai/tokens.html
static final ObjectMapper M = new ObjectMapper();
static final HttpClient C = HttpClient.newHttpClient();
static JsonNode api(String method, String path, Object body, Map<String, String> headers) throws Exception {
var b = HttpRequest.newBuilder(URI.create(BASE + path)).header("Content-Type", "application/json");
if (!token.isEmpty()) b.header("Authorization", "Bearer " + token);
if (headers != null) headers.forEach(b::header);
b.method(method, body == null ? HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofString(M.writeValueAsString(body)));
JsonNode env = M.readTree(C.send(b.build(), HttpResponse.BodyHandlers.ofString()).body());
if (env.hasNonNull("error")) throw new RuntimeException(env.get("error").toString());
return env.get("data");
}
}
require "json"
require "net/http"
BASE = "https://api.skillsafe.ai/v1/app-api"
TOKEN = "YOUR_TOKEN" # from https://platform-hire.skillsafe.ai/tokens.html
def api(method, path, body = nil, headers = {})
uri = URI(BASE + path)
req = Net::HTTPGenericRequest.new(method, !body.nil?, true, uri.request_uri,
{ "Content-Type" => "application/json" }.merge(TOKEN.empty? ? {} : { "Authorization" => "Bearer #{TOKEN}" }).merge(headers))
req.body = JSON.generate(body) unless body.nil?
env = JSON.parse(Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }.body)
raise env["error"].to_s if env["error"]
env["data"]
end
<?php
const BASE = "https://api.skillsafe.ai/v1/app-api";
$TOKEN = "YOUR_TOKEN"; // from https://platform-hire.skillsafe.ai/tokens.html
function api(string $method, string $path, $body = null, array $headers = []) {
global $TOKEN;
$h = ["Content-Type: application/json"];
if ($TOKEN) $h[] = "Authorization: Bearer $TOKEN";
foreach ($headers as $k => $v) $h[] = "$k: $v";
$ch = curl_init(BASE . $path);
curl_setopt_array($ch, [CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $h, CURLOPT_RETURNTRANSFER => true]);
if ($body !== null) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
$env = json_decode(curl_exec($ch), true);
if (!empty($env["error"])) throw new Exception(json_encode($env["error"]));
return $env["data"];
}
// Program.cs -- .NET 6+ console app
using System.Net.Http.Json; using System.Text.Json; using System.Text.Json.Nodes;
static class Api {
public const string Base = "https://api.skillsafe.ai/v1/app-api";
public static string Token = "YOUR_TOKEN"; // from https://platform-hire.skillsafe.ai/tokens.html
static readonly HttpClient C = new();
public static async Task<JsonNode?> Call(string method, string path, object? body = null, Dictionary<string, string>? headers = null) {
var req = new HttpRequestMessage(new HttpMethod(method), Base + path);
if (Token != "") req.Headers.Add("Authorization", "Bearer " + Token);
if (headers != null) foreach (var h in headers) req.Headers.Add(h.Key, h.Value);
if (body != null) req.Content = JsonContent.Create(body);
var env = JsonNode.Parse(await (await C.SendAsync(req)).Content.ReadAsStringAsync())!;
if (env["error"] is JsonNode e && e.GetValueKind() != JsonValueKind.Null) throw new Exception(e.ToJsonString());
return env["data"];
}
}
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":"platform-hire"}' | jq -r '.data.token')
# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN = ""
TOKEN = api("POST", "/guest", {"slug": "platform-hire"})["token"]
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN = "";
TOKEN = (await api("POST", "/guest", { slug: "platform-hire" })).token;
// inside main: a guest token (enough for /me and /estimate); a run needs your personal token
token = ""
g, err := api("POST", "/guest", map[string]string{"slug": "platform-hire"}, nil)
if err != nil { panic(err) }
token = g["token"].(string)
// inside main: a guest token (enough for /me and /estimate); a run needs your personal token
token = "";
token = api("POST", "/guest", Map.of("slug", "platform-hire"), null).get("token").asText();
# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN.replace("")
TOKEN.replace(api("POST", "/guest", { slug: "platform-hire" })["token"])
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
$TOKEN = "";
$TOKEN = api("POST", "/guest", ["slug" => "platform-hire"])["token"];
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
Api.Token = "";
Api.Token = (await Api.Call("POST", "/guest", new { slug = "platform-hire" }))!["token"]!.GetValue<string>();
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}'
me = api("GET", "/me")
print(me["subject_type"], me.get("credits"))
const me = await api("GET", "/me");
console.log(me.subject_type, me.credits);
me, _ := api("GET", "/me", nil, nil)
fmt.Println(me["subject_type"], me["credits"])
JsonNode me = api("GET", "/me", null, null);
System.out.println(me.get("subject_type") + " " + me.get("credits"));
me = api("GET", "/me")
puts [me["subject_type"], me["credits"]].inspect
$me = api("GET", "/me");
echo $me["subject_type"], " ", $me["credits"] ?? "", "\n";
var me = await Api.Call("GET", "/me");
Console.WriteLine($"{me!["subject_type"]} {me["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": "scorecard", "role": "Company: Relaywise
The company and the role: ...", "posting": "Draft posting:
Platform Engineer - Relaywise ...", "carry": "", "facts": "The page's checks (...); verdict: three jobs in one seat - split the scope first:
- The posting | scope | fail | ..."}
# - see the input table
api POST /estimate "$(cat input.json)" | jq '.data | {hold_credits, min_credits, model, model_alias, markup_bps, warnings}'
inp = json.load(open("input.json")) # {"task": "scorecard", "role": "Company: Relaywise
The company and the role: ...", "posting": "Draft posting:
Platform Engineer - Relaywise ...", "carry": "", "facts": "The page's checks (...); verdict: three jobs in one seat - split the scope first:
- The posting | scope | fail | ..."}
# - see the input table
est = api("POST", "/estimate", inp)
print(est["hold_credits"], est["min_credits"], est["model"], est.get("warnings"))
import { readFileSync } from "node:fs";
const input = JSON.parse(readFileSync("input.json", "utf8")); // {task: "scorecard" or "loop", role, posting, carry, facts} (see the input table)
const est = await api("POST", "/estimate", input);
console.log(est.hold_credits, est.min_credits, est.model, est.warnings);
raw, _ := os.ReadFile("input.json") // add "os" to the imports
var input map[string]any
json.Unmarshal(raw, &input)
est, _ := api("POST", "/estimate", input, nil)
fmt.Println(est["hold_credits"], est["min_credits"], est["model"])
Map<String, Object> input = M.readValue(new java.io.File("input.json"), Map.class);
JsonNode est = api("POST", "/estimate", input, null);
System.out.println(est.get("hold_credits") + " " + est.get("min_credits") + " " + est.get("model"));
input = JSON.parse(File.read("input.json"))
est = api("POST", "/estimate", input)
puts [est["hold_credits"], est["min_credits"], est["model"]].inspect
$input = json_decode(file_get_contents("input.json"), true);
$est = api("POST", "/estimate", $input);
echo $est["hold_credits"], " ", $est["min_credits"], " ", $est["model"], "\n";
var input = JsonNode.Parse(File.ReadAllText("input.json"))!;
var est = await Api.Call("POST", "/estimate", input);
Console.WriteLine($"{est!["hold_credits"]} {est["min_credits"]} {est["model"]}");
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 platform-hire:<task>:<inputHash>:a<attempt> - the lane is part of the key, retry_note is left out of the hash - and its one automatic reformat retry is a new attempt number, named in the page as one extra run. A scorecard reply carries summary, calibration, mission, outcomes, competencies, shape, posting_fixes and caveats; a loop reply carries summary, stages, sourcing, avoid, comp and caveats. The code below prints the gist of either: each outcome and its measure, or each loop stage and its minutes.
KEY="platform-hire:$(jq -r .task input.json):$(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}'
jq -r 'if .task == "loop" then (.stages[] | "\(.stage): \(.minutes)")
else (.outcomes[] | "\(.outcome): \(.measure)") end' reply.json
import hashlib, time
key = "platform-hire:" + inp["task"] + ":" + hashlib.sha256(json.dumps(inp).encode()).hexdigest()[:16] + ":a1"
job = api("POST", "/run", inp, {"Idempotency-Key": key})
while True:
j = api("GET", "/jobs/" + job["job_id"])
if j["status"] in ("succeeded", "failed", "cancelled"):
break
time.sleep(2)
reply = json.loads(j["output"]["output"]) # the reply as one JSON object
print(j["charged_credits"], j.get("truncated"), reply["task"])
if reply["task"] == "loop":
for x in reply["stages"]:
print(x["stage"], x["minutes"])
else:
for x in reply["outcomes"]:
print(x["outcome"], x["measure"])
import { createHash } from "node:crypto";
const key = `platform-hire:${input.task}:${createHash("sha256").update(JSON.stringify(input)).digest("hex").slice(0, 16)}:a1`;
const job = await api("POST", "/run", input, { "Idempotency-Key": key });
let j;
do { await new Promise((r) => setTimeout(r, 2000)); j = await api("GET", "/jobs/" + job.job_id); }
while (!["succeeded", "failed", "cancelled"].includes(j.status));
const reply = JSON.parse(j.output.output);
console.log(j.charged_credits, j.truncated, reply.task);
if (reply.task === "loop") { for (const x of reply.stages) console.log(x.stage, x.minutes); }
else { for (const x of reply.outcomes) console.log(x.outcome, x.measure); }
sum := sha256.Sum256(raw) // add "crypto/sha256", "encoding/hex", "time" to the imports
key := "platform-hire:" + input["task"].(string) + ":" + hex.EncodeToString(sum[:8]) + ":a1"
job, _ := api("POST", "/run", input, map[string]string{"Idempotency-Key": key})
var j map[string]any
for {
time.Sleep(2 * time.Second)
j, _ = api("GET", "/jobs/"+job["job_id"].(string), nil, nil)
if s := j["status"]; s == "succeeded" || s == "failed" || s == "cancelled" { break }
}
var reply map[string]any
json.Unmarshal([]byte(j["output"].(map[string]any)["output"].(string)), &reply)
fmt.Println(j["charged_credits"], j["truncated"], reply["task"])
key, a, b := "outcomes", "outcome", "measure"
if reply["task"] == "loop" {
key, a, b = "stages", "stage", "minutes"
}
xs, _ := reply[key].([]any)
for _, x := range xs {
xx := x.(map[string]any)
fmt.Println(xx[a], xx[b])
}
var digest = java.security.MessageDigest.getInstance("SHA-256").digest(M.writeValueAsBytes(input));
String key = "platform-hire:" + input.get("task") + ":" + HexFormat.of().formatHex(digest, 0, 8) + ":a1";
JsonNode job = api("POST", "/run", input, Map.of("Idempotency-Key", key)), j;
do { Thread.sleep(2000); j = api("GET", "/jobs/" + job.get("job_id").asText(), null, null); }
while (!Set.of("succeeded", "failed", "cancelled").contains(j.get("status").asText()));
JsonNode reply = M.readTree(j.get("output").get("output").asText());
System.out.println(j.get("charged_credits") + " " + reply.path("task").asText());
if (reply.path("task").asText().equals("loop")) {
for (JsonNode x : reply.path("stages")) System.out.println(x.path("stage").asText() + " " + x.path("minutes").asText());
} else {
for (JsonNode x : reply.path("outcomes")) System.out.println(x.path("outcome").asText() + " " + x.path("measure").asText());
}
require "digest"
key = "platform-hire:#{input["task"]}:#{Digest::SHA256.hexdigest(JSON.generate(input))[0, 16]}:a1"
job = api("POST", "/run", input, { "Idempotency-Key" => key })
j = nil
loop do
sleep 2
j = api("GET", "/jobs/#{job["job_id"]}")
break if %w[succeeded failed cancelled].include?(j["status"])
end
reply = JSON.parse(j["output"]["output"])
puts [j["charged_credits"], j["truncated"], reply["task"]].inspect
if reply["task"] == "loop"
reply["stages"].each { |x| puts "#{x["stage"]} #{x["minutes"]}" }
else
reply["outcomes"].each { |x| puts "#{x["outcome"]} #{x["measure"]}" }
end
$key = "platform-hire:" . $input["task"] . ":" . substr(hash("sha256", json_encode($input)), 0, 16) . ":a1";
$job = api("POST", "/run", $input, ["Idempotency-Key" => $key]);
do { sleep(2); $j = api("GET", "/jobs/" . $job["job_id"]); }
while (!in_array($j["status"], ["succeeded", "failed", "cancelled"]));
$reply = json_decode($j["output"]["output"], true);
echo $j["charged_credits"], " ", $reply["task"], "\n";
if ($reply["task"] === "loop") { foreach ($reply["stages"] as $x) echo $x["stage"], " ", $x["minutes"], "\n"; }
else { foreach ($reply["outcomes"] as $x) echo $x["outcome"], " ", $x["measure"], "\n"; }
var digest = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(input.ToJsonString()));
var key = $"platform-hire:{input["task"]}:{Convert.ToHexString(digest, 0, 8).ToLowerInvariant()}:a1";
var job = await Api.Call("POST", "/run", input, new() { ["Idempotency-Key"] = key });
JsonNode j;
do { await Task.Delay(2000); j = (await Api.Call("GET", "/jobs/" + job!["job_id"]))!; }
while (!new[] { "succeeded", "failed", "cancelled" }.Contains(j["status"]!.GetValue<string>()));
var reply = JsonNode.Parse(j["output"]!["output"]!.GetValue<string>())!;
var task = (string?)reply["task"];
Console.WriteLine($"{j["charged_credits"]} {task}");
if (task == "loop") { foreach (var x in reply["stages"]!.AsArray()) Console.WriteLine($"{x!["stage"]} {x["minutes"]}"); }
else { foreach (var x in reply["outcomes"]!.AsArray()) Console.WriteLine($"{x!["outcome"]} {x["measure"]}"); }
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: platform-hire:$(jq -r .task input.json):$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json
rev = json.load(open("input.json")) # the same run input as input.json: {"task": "scorecard", "role": "Company: Relaywise
The company and the role: ...", "posting": "Draft posting:
Platform Engineer - Relaywise ...", "carry": "", "facts": "The page's checks (...); verdict: three jobs in one seat - split the scope first:
- The posting | scope | fail | ..."}
# - see the input table
req = urllib.request.Request(BASE + "/run-stream", method="POST", data=json.dumps(rev).encode(),
headers={"Content-Type": "application/json", "Authorization": "Bearer " + TOKEN,
"Idempotency-Key": "platform-hire:" + rev["task"] + ":" + hashlib.sha256(json.dumps(rev).encode()).hexdigest()[:16] + ":a1"})
with urllib.request.urlopen(req) as r:
for line in r:
line = line.decode().strip()
if line.startswith("data:"):
print(line[5:].strip()[:200])
const rev = JSON.parse(readFileSync("input.json", "utf8"));
const r = await fetch(BASE + "/run-stream", { method: "POST", body: JSON.stringify(rev), headers: {
"Content-Type": "application/json", Authorization: "Bearer " + TOKEN,
"Idempotency-Key": `platform-hire:${rev.task}:${createHash("sha256").update(JSON.stringify(rev)).digest("hex").slice(0, 16)}:a1` } });
const dec = new TextDecoder();
for await (const chunk of r.body) for (const line of dec.decode(chunk).split("\n"))
if (line.startsWith("data:")) console.log(line.slice(5).trim().slice(0, 200));
rraw, _ := os.ReadFile("input.json") // add "bufio", "strings" to the imports
rs := sha256.Sum256(rraw)
req, _ := http.NewRequest("POST", base+"/run-stream", bytes.NewReader(rraw))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Idempotency-Key", "platform-hire:"+input["task"].(string)+":"+hex.EncodeToString(rs[:8])+":a1")
res, _ := http.DefaultClient.Do(req)
sc := bufio.NewScanner(res.Body)
for sc.Scan() { if l := sc.Text(); strings.HasPrefix(l, "data:") { fmt.Println(l[5:]) } }
String rev = java.nio.file.Files.readString(java.nio.file.Path.of("input.json"));
var rd = java.security.MessageDigest.getInstance("SHA-256").digest(rev.getBytes());
var sreq = HttpRequest.newBuilder(URI.create(BASE + "/run-stream")).header("Content-Type", "application/json")
.header("Authorization", "Bearer " + token).header("Idempotency-Key", "platform-hire:" + input.get("task") + ":" + HexFormat.of().formatHex(rd, 0, 8) + ":a1")
.POST(HttpRequest.BodyPublishers.ofString(rev)).build();
C.send(sreq, HttpResponse.BodyHandlers.ofLines()).body().filter(l -> l.startsWith("data:")).forEach(System.out::println);
rev = File.read("input.json")
uri = URI(BASE + "/run-stream")
req = Net::HTTP::Post.new(uri, "Content-Type" => "application/json", "Authorization" => "Bearer #{TOKEN}",
"Idempotency-Key" => "platform-hire:#{JSON.parse(rev)["task"]}:#{Digest::SHA256.hexdigest(rev)[0, 16]}:a1")
req.body = rev
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |h|
h.request(req) { |res| res.read_body { |chunk| chunk.each_line { |l| puts l if l.start_with?("data:") } } }
end
$rev = file_get_contents("input.json");
$ch = curl_init(BASE . "/run-stream");
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $rev, CURLOPT_HTTPHEADER => [
"Content-Type: application/json", "Authorization: Bearer $TOKEN",
"Idempotency-Key: platform-hire:" . json_decode($rev, true)["task"] . ":" . substr(hash("sha256", $rev), 0, 16) . ":a1"],
CURLOPT_WRITEFUNCTION => function ($ch, $chunk) { foreach (explode("\n", $chunk) as $l) if (str_starts_with($l, "data:")) echo $l, "\n"; return strlen($chunk); }]);
curl_exec($ch);
var rev = File.ReadAllText("input.json");
var rd = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(rev));
var sreq = new HttpRequestMessage(HttpMethod.Post, Api.Base + "/run-stream") { Content = new StringContent(rev, System.Text.Encoding.UTF8, "application/json") };
sreq.Headers.Add("Authorization", "Bearer " + Api.Token);
sreq.Headers.Add("Idempotency-Key", $"platform-hire:{input["task"]}:{Convert.ToHexString(rd, 0, 8).ToLowerInvariant()}:a1");
using var http = new HttpClient();
using var res = await http.SendAsync(sreq, HttpCompletionOption.ResponseHeadersRead);
using var rdr = new StreamReader(await res.Content.ReadAsStreamAsync());
for (string? l; (l = await rdr.ReadLineAsync()) != null;) if (l.StartsWith("data:")) Console.WriteLine(l);