Driving Deal Launch from your own code
Deal Launch is a SkillSafe app. Everything the page does — estimating a lane, running it, streaming
the reply — is an HTTP call you can make yourself. The base URL is
https://api.skillsafe.ai/v1/app-api and the app slug is deal-launch.
The fact-set reader — the financial table parser, the growth and margin arithmetic, the identifier
index and the flags — runs entirely client-side in dealscan.js and has no endpoint.
If you are driving the API you compute or supply prescan_facts yourself; the model is
instructed not to contradict it.
The envelope
Every response is {"data": ...} on success or {"error": {"code", "message",
"details"}} on failure, with the HTTP status matching the code.
Error codes
| code | status | what it means |
|---|---|---|
UNAUTHORIZED | 401 | No token, or a token that has expired. Mint a guest token or sign in again. |
FORBIDDEN | 403 | The token belongs to another app. Tokens are scoped per app slug. |
NOT_FOUND | 404 | Wrong path. Every path on this page begins /v1/app-api. |
VALIDATION_ERROR | 400 | The input failed validation — usually a missing task or a non-object body. |
INSUFFICIENT_CREDITS | 402 | The balance is below min_credits. Call /estimate first. |
RATE_LIMITED | 429 | Too many requests. Back off; do not retry in a tight loop. |
JOB_FAILED | 500 | The model run failed after it started. The error SSE event carries the job id. |
The task field comes first
Deal Launch is one app with one system prompt and five lanes. Every run input must carry a
task field naming the lane; the prompt routes on it. Send an unknown value and
the model picks the closest lane and says which one it chose, which is almost never what you wanted.
| task | lane | source skill | what the reply carries |
|---|---|---|---|
teaser | Anonymous teaser | @anthropics/teaser | Five named sections and an empty rows array. The reply is re-checked in the browser against the identifier index; a teaser that names the company is flagged to the user. |
buyers | Buyer universe | @anthropics/buyer-list | Rows carry buyer, type, tier, rationale, fit, concerns, priority. |
process | Process letter | @anthropics/process-letter | Both a letter body and a timetable. Every date is parsed and turned into an iCalendar file, so only real calendar dates are accepted. |
cim | CIM outline | @anthropics/cim-builder | Rows carry section, subsection, evidence, owner (company/adviser/both) and status (have/partial/missing). |
diligence | Diligence request list | @anthropics/dd-checklist | Rows carry ref, workstream, request, priority, format and why. |
Input fields
| field | type | notes |
|---|---|---|
task | string | Required. One of the five lane ids above. |
facts | string | Required. The company fact set. The app clips at 24,000 characters by removing the middle on line boundaries and marking the cut in-band. |
deal_type | string | majority-sale, minority-growth, carve-out or full-exit. |
audience | string | both, strategic, sponsor or management. |
stage | string | pre-launch, phase-one or phase-two. |
identifiers_masked | boolean | Whether facts has already had its identifying details replaced. |
context | string | Optional constraints. Treated as binding by the prompt. |
prescan_facts | object | The client-side read: parsed figures, computed growth and margins, the identifier list and the flags. The prompt requires one coverage_check entry per applicable flag id. Each entry of prescan_facts.identifiers carries id, kind and replacement; when identifiers_masked is false it also carries literal, the exact string in facts that the replacement stands for — without it the model cannot tell which words to replace. When masking is on, literal is deliberately withheld so the prescan block does not undo the masking. |
upstream | object | Optional. A digest of an earlier lane's output when you are chaining lanes. |
The output envelope — identical for every lane
The model returns one JSON object. The app takes the text from the first { to the last
} and parses it; only the inner body differs per lane.
{
"lane": "teaser",
"title": "…",
"headline": "…",
"verdict": "ready-to-send | needs-work | blocked",
"readiness": 0,
"summary": "…",
"sections": [
{
"id": "overview",
"heading": "…",
"body": "…",
"bullets": [
"…"
]
}
],
"rows": [],
"gaps": [
{
"id": "G1",
"need": "…",
"why": "…",
"severity": "high"
}
],
"coverage_check": [
{
"flag_id": "DL-040",
"status": "addressed",
"note": "…"
}
],
"anonymity": {
"claimed_anonymous": true,
"notes": "…"
},
"artifact": {
"kind": "markdown",
"filename": "teaser.md",
"content": "# …"
}
}
One worked example per lane
Each block is the exact body to POST to /estimate, /run or
/run-stream for that lane, trimmed for length.
Anonymous teaser — task: "teaser"
- sections[] — overview, highlights, financials, rationale, process
- rows[] — always empty for this lane
- artifact.kind — markdown
{
"task": "teaser",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}
Buyer universe — task: "buyers"
- rows[] — 12 to 20 acquirers, tiered
- sections[] — at most two framing sections
- artifact.kind — csv, header buyer,type,tier,rationale,fit,concerns,priority
{
"task": "buyers",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}
Process letter — task: "process"
- sections[] — opening, instructions, conditions, next
- rows[] — date, milestone, owner, detail
- artifact.kind — markdown
{
"task": "process",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}
CIM outline — task: "cim"
- rows[] — 12 to 25 outline rows
- gaps[] — the sections the fact set cannot fill
- artifact.kind — markdown
{
"task": "cim",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}
Diligence request list — task: "diligence"
- rows[] — 18 to 30 requests by workstream
- priority — 1 decides signing, 2 important, 3 confirmatory
- artifact.kind — csv, header ref,workstream,request,priority,format,why
{
"task": "diligence",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}
Step 1 — a token
Every call needs Authorization: Bearer <token>. A guest token is
minted in one call and is enough for /me and /estimate; running a lane is
metered and needs a personal token from signing in. The easiest way to get a
personal token is the token page, which reads the one this browser
already holds. Put it in an environment variable your shell already has — never paste it into a
file you commit.
curl -s -X POST "https://api.skillsafe.ai/v1/app-api/guest" \
-H "Authorization: Bearer $DEAL_LAUNCH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"slug": "deal-launch"
}'import json, urllib.request
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/guest",
data=json.dumps({
"slug": "deal-launch"
}).encode(),
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json"},
method="POST")
body = json.load(urllib.request.urlopen(req))
print(body["data"])const res = await fetch("https://api.skillsafe.ai/v1/app-api/guest", {
method: "POST",
headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" },
body: JSON.stringify({
"slug": "deal-launch"
}),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);body := strings.NewReader(`{
"slug": "deal-launch"
}`)
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/guest", body)
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil { log.Fatal(err) }
defer res.Body.Close()
var envelope struct{ Data json.RawMessage `json:"data"` }
json.NewDecoder(res.Body).Decode(&envelope)
fmt.Println(string(envelope.Data))HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/guest"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.post(HttpRequest.BodyPublishers.ofString("""
{
"slug": "deal-launch"
}
"""))
.build();
HttpResponse<String> res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());require "net/http"
require "json"
uri = URI("https://api.skillsafe.ai/v1/app-api/guest")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req.body = {
"slug": "deal-launch"
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]<?php
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/guest");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $token,
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode({
"slug": "deal-launch"
}));
$out = json_decode(curl_exec($ch), true);
print_r($out["data"]);using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
var payload = new StringContent(@"{
""slug"": ""deal-launch""
}",
Encoding.UTF8, "application/json");
var res = await http.PostAsync("https://api.skillsafe.ai/v1/app-api/guest", payload);
Console.WriteLine(await res.Content.ReadAsStringAsync());Step 2 — who am I, and what is the balance
GET /me returns subject_type (user or guest),
subject_id and credits. Compare the balance against the estimate below
before running; a 402 after submit is avoidable.
curl -s "https://api.skillsafe.ai/v1/app-api/me" \
-H "Authorization: Bearer $DEAL_LAUNCH_TOKEN"import json, urllib.request
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/me",
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json"},
method="GET")
body = json.load(urllib.request.urlopen(req))
print(body["data"])const res = await fetch("https://api.skillsafe.ai/v1/app-api/me", {
method: "GET",
headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" },
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);req, _ := http.NewRequest("GET", "https://api.skillsafe.ai/v1/app-api/me", nil)
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil { log.Fatal(err) }
defer res.Body.Close()
var envelope struct{ Data json.RawMessage `json:"data"` }
json.NewDecoder(res.Body).Decode(&envelope)
fmt.Println(string(envelope.Data))HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/me"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());require "net/http"
require "json"
uri = URI("https://api.skillsafe.ai/v1/app-api/me")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]<?php
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/me");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $token,
"Content-Type: application/json",
]);
$out = json_decode(curl_exec($ch), true);
print_r($out["data"]);using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
var res = await http.GetAsync("https://api.skillsafe.ai/v1/app-api/me");
Console.WriteLine(await res.Content.ReadAsStringAsync());Step 3 — estimate the lane (free, no job)
POST /estimate returns model, model_alias,
markup_bps, hold_credits, min_credits and
sponsor_enabled. It costs nothing and creates no job. Estimate the lane you are
about to run — the hold differs per lane because the prompts and output caps differ.
hold_credits is what is reserved, not what you pay; settlement is usually far lower.
curl -s -X POST "https://api.skillsafe.ai/v1/app-api/estimate" \
-H "Authorization: Bearer $DEAL_LAUNCH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"task": "teaser",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}'import json, urllib.request
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/estimate",
data=json.dumps({
"task": "teaser",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}).encode(),
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json"},
method="POST")
body = json.load(urllib.request.urlopen(req))
print(body["data"])const res = await fetch("https://api.skillsafe.ai/v1/app-api/estimate", {
method: "POST",
headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" },
body: JSON.stringify({
"task": "teaser",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);body := strings.NewReader(`{
"task": "teaser",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}`)
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/estimate", body)
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil { log.Fatal(err) }
defer res.Body.Close()
var envelope struct{ Data json.RawMessage `json:"data"` }
json.NewDecoder(res.Body).Decode(&envelope)
fmt.Println(string(envelope.Data))HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/estimate"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.post(HttpRequest.BodyPublishers.ofString("""
{
"task": "teaser",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}
"""))
.build();
HttpResponse<String> res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());require "net/http"
require "json"
uri = URI("https://api.skillsafe.ai/v1/app-api/estimate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req.body = {
"task": "teaser",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]<?php
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/estimate");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $token,
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode({
"task": "teaser",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}));
$out = json_decode(curl_exec($ch), true);
print_r($out["data"]);using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
var payload = new StringContent(@"{
""task"": ""teaser"",
""facts"": ""Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |"",
""deal_type"": ""majority-sale"",
""audience"": ""both"",
""stage"": ""pre-launch"",
""identifiers_masked"": true,
""context"": ""Bids wanted before the end of the financial year."",
""prescan_facts"": {
""readiness"": 88,
""readiness_tier"": ""launch-ready"",
""currency"": ""GBP"",
""years"": [
2024,
2025
],
""revenue_cagr_pct"": 25.3,
""latest_growth_pct"": 25.3,
""ebitda_margins_pct"": [
{
""year"": 2024,
""pct"": 21.7
},
{
""year"": 2025,
""pct"": 25.0
}
],
""largest_customer_pct"": 14,
""size_band"": ""10m to 50m"",
""identifiers"": [
{
""id"": ""ID-1"",
""kind"": ""company"",
""replacement"": ""[the Company]""
}
],
""flags"": [
{
""id"": ""DL-040"",
""severity"": ""high"",
""title"": ""13 identifying details are in this paste"",
""lanes"": [
""teaser""
]
}
]
}
}",
Encoding.UTF8, "application/json");
var res = await http.PostAsync("https://api.skillsafe.ai/v1/app-api/estimate", payload);
Console.WriteLine(await res.Content.ReadAsStringAsync());Step 4 — run it, and poll
POST /run returns {"job_id": "…"}. Always send an
Idempotency-Key header. The app uses
deal-launch:<lane>:<hash of the input>:a<attempt>, so a network blip
cannot bill twice and two lanes over the same fact set never collide on one key.
curl -s -X POST "https://api.skillsafe.ai/v1/app-api/run" \
-H "Authorization: Bearer $DEAL_LAUNCH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"task": "buyers",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}'import json, urllib.request
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/run",
data=json.dumps({
"task": "buyers",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}).encode(),
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json"},
method="POST")
body = json.load(urllib.request.urlopen(req))
print(body["data"])const res = await fetch("https://api.skillsafe.ai/v1/app-api/run", {
method: "POST",
headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" },
body: JSON.stringify({
"task": "buyers",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);body := strings.NewReader(`{
"task": "buyers",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}`)
req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/run", body)
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil { log.Fatal(err) }
defer res.Body.Close()
var envelope struct{ Data json.RawMessage `json:"data"` }
json.NewDecoder(res.Body).Decode(&envelope)
fmt.Println(string(envelope.Data))HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/run"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.post(HttpRequest.BodyPublishers.ofString("""
{
"task": "buyers",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}
"""))
.build();
HttpResponse<String> res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());require "net/http"
require "json"
uri = URI("https://api.skillsafe.ai/v1/app-api/run")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req.body = {
"task": "buyers",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]<?php
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/run");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $token,
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode({
"task": "buyers",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}));
$out = json_decode(curl_exec($ch), true);
print_r($out["data"]);using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
var payload = new StringContent(@"{
""task"": ""buyers"",
""facts"": ""Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |"",
""deal_type"": ""majority-sale"",
""audience"": ""both"",
""stage"": ""pre-launch"",
""identifiers_masked"": true,
""context"": ""Bids wanted before the end of the financial year."",
""prescan_facts"": {
""readiness"": 88,
""readiness_tier"": ""launch-ready"",
""currency"": ""GBP"",
""years"": [
2024,
2025
],
""revenue_cagr_pct"": 25.3,
""latest_growth_pct"": 25.3,
""ebitda_margins_pct"": [
{
""year"": 2024,
""pct"": 21.7
},
{
""year"": 2025,
""pct"": 25.0
}
],
""largest_customer_pct"": 14,
""size_band"": ""10m to 50m"",
""identifiers"": [
{
""id"": ""ID-1"",
""kind"": ""company"",
""replacement"": ""[the Company]""
}
],
""flags"": [
{
""id"": ""DL-040"",
""severity"": ""high"",
""title"": ""13 identifying details are in this paste"",
""lanes"": [
""teaser""
]
}
]
}
}",
Encoding.UTF8, "application/json");
var res = await http.PostAsync("https://api.skillsafe.ai/v1/app-api/run", payload);
Console.WriteLine(await res.Content.ReadAsStringAsync());Then poll GET /jobs/{job_id} until status is terminal. The reply text is
in output.output.
curl -s "https://api.skillsafe.ai/v1/app-api/jobs/job_123" \
-H "Authorization: Bearer $DEAL_LAUNCH_TOKEN"import json, urllib.request
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/jobs/job_123",
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json"},
method="GET")
body = json.load(urllib.request.urlopen(req))
print(body["data"])const res = await fetch("https://api.skillsafe.ai/v1/app-api/jobs/job_123", {
method: "GET",
headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" },
});
const { data, error } = await res.json();
if (error) throw new Error(error.code);
console.log(data);req, _ := http.NewRequest("GET", "https://api.skillsafe.ai/v1/app-api/jobs/job_123", nil)
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil { log.Fatal(err) }
defer res.Body.Close()
var envelope struct{ Data json.RawMessage `json:"data"` }
json.NewDecoder(res.Body).Decode(&envelope)
fmt.Println(string(envelope.Data))HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/jobs/job_123"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());require "net/http"
require "json"
uri = URI("https://api.skillsafe.ai/v1/app-api/jobs/job_123")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]<?php
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/jobs/job_123");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $token,
"Content-Type: application/json",
]);
$out = json_decode(curl_exec($ch), true);
print_r($out["data"]);using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
var res = await http.GetAsync("https://api.skillsafe.ai/v1/app-api/jobs/job_123");
Console.WriteLine(await res.Content.ReadAsStringAsync());Step 5 — stream it instead
POST /run-stream returns text/event-stream with four event names:
job (the job id, as soon as it exists), delta ({"text": "…"}
chunks), done ({job_id, status, charged_credits, output, truncated}) and
error. The app uses this lane and advances its progress card on the envelope keys as
they arrive.
curl -N -X POST "https://api.skillsafe.ai/v1/app-api/run-stream" \
-H "Authorization: Bearer $DEAL_LAUNCH_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: deal-launch:cim:9f2a1c04:a1" \
-d '{
"task": "cim",
"facts": "Company: Northwind Compliance Systems Ltd\\nSector: regulatory compliance software\\n| Year | Revenue | EBITDA |\\n| 2024 | 24.9 | 5.4 |\\n| 2025 | 31.2 | 7.8 |",
"deal_type": "majority-sale",
"audience": "both",
"stage": "pre-launch",
"identifiers_masked": true,
"context": "Bids wanted before the end of the financial year.",
"prescan_facts": {
"readiness": 88,
"readiness_tier": "launch-ready",
"currency": "GBP",
"years": [
2024,
2025
],
"revenue_cagr_pct": 25.3,
"latest_growth_pct": 25.3,
"ebitda_margins_pct": [
{
"year": 2024,
"pct": 21.7
},
{
"year": 2025,
"pct": 25.0
}
],
"largest_customer_pct": 14,
"size_band": "10m to 50m",
"identifiers": [
{
"id": "ID-1",
"kind": "company",
"replacement": "[the Company]"
}
],
"flags": [
{
"id": "DL-040",
"severity": "high",
"title": "13 identifying details are in this paste",
"lanes": [
"teaser"
]
}
]
}
}'import json, urllib.request
req = urllib.request.Request(
"https://api.skillsafe.ai/v1/app-api/run-stream",
data=json.dumps(payload).encode(),
headers={"Authorization": "Bearer " + TOKEN,
"Content-Type": "application/json",
"Idempotency-Key": key},
method="POST")
event, out = "message", ""
for raw in urllib.request.urlopen(req):
line = raw.decode().rstrip("\n")
if line.startswith("event:"):
event = line[6:].strip()
elif line.startswith("data:"):
payload_line = json.loads(line[5:].strip())
if event == "delta":
out += payload_line.get("text", "")
elif event == "done":
out = payload_line["output"]["output"]
print(json.loads(out[out.index("{"):out.rindex("}") + 1])["lane"])const res = await fetch("https://api.skillsafe.ai/v1/app-api/run-stream", {
method: "POST",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
"Idempotency-Key": key,
},
body: JSON.stringify(payload),
});
const reader = res.body.getReader();
const dec = new TextDecoder();
let buf = "", out = "";
for (;;) {
const { done, value } = await reader.read();
if (done) break;
buf += dec.decode(value, { stream: true });
let i;
while ((i = buf.indexOf("\n\n")) >= 0) {
const frame = buf.slice(0, i); buf = buf.slice(i + 2);
const ev = /event:\s*(\w+)/.exec(frame);
const dt = /data:\s*(.+)/.exec(frame);
if (!dt) continue;
const data = JSON.parse(dt[1]);
if (ev && ev[1] === "delta") out += data.text || "";
if (ev && ev[1] === "done") out = data.output.output;
}
}
console.log(JSON.parse(out.slice(out.indexOf("{"), out.lastIndexOf("}") + 1)));req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/run-stream", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", key)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
sc := bufio.NewScanner(res.Body)
event := "message"
var out strings.Builder
for sc.Scan() {
line := sc.Text()
switch {
case strings.HasPrefix(line, "event:"):
event = strings.TrimSpace(line[6:])
case strings.HasPrefix(line, "data:") && event == "delta":
var d struct{ Text string `json:"text"` }
json.Unmarshal([]byte(line[5:]), &d)
out.WriteString(d.Text)
}
}
fmt.Println(out.String())HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.skillsafe.ai/v1/app-api/run-stream"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.header("Idempotency-Key", key)
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
StringBuilder out = new StringBuilder();
HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofLines())
.body()
.filter(l -> l.startsWith("data:"))
.forEach(l -> out.append(l.substring(5).trim()));
System.out.println(out);uri = URI("https://api.skillsafe.ai/v1/app-api/run-stream")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req["Idempotency-Key"] = key
req.body = payload.to_json
out = +""
event = "message"
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(req) do |res|
res.read_body do |chunk|
chunk.each_line do |line|
event = line[6..].strip if line.start_with?("event:")
out << JSON.parse(line[5..])["text"].to_s if line.start_with?("data:") && event == "delta"
end
end
end
end
puts out<?php
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/run-stream");
$out = "";
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $token,
"Content-Type: application/json",
"Idempotency-Key: " . $key,
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$out) {
foreach (explode("\n", $chunk) as $line) {
if (str_starts_with($line, "data:")) {
$d = json_decode(substr($line, 5), true);
$out .= $d["text"] ?? "";
}
}
return strlen($chunk);
});
curl_exec($ch);
echo $out;using var http = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post, "https://api.skillsafe.ai/v1/app-api/run-stream");
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
req.Headers.Add("Idempotency-Key", key);
req.Content = new StringContent(payload, Encoding.UTF8, "application/json");
var res = await http.SendAsync(req, HttpCompletionOption.ResponseHeadersRead);
using var reader = new StreamReader(await res.Content.ReadAsStreamAsync());
var sb = new StringBuilder();
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
if (!line.StartsWith("data:")) continue;
using var doc = JsonDocument.Parse(line[5..]);
if (doc.RootElement.TryGetProperty("text", out var t)) sb.Append(t.GetString());
}
Console.WriteLine(sb);Step 6 — what to do with the reply
- Parse from the first
{to the last}. A model that adds a sentence before the object is still recoverable this way. - Check
laneagainst thetaskyou sent. A mismatch means the router section of the prompt was weak for your input, not that the reply is useless. - Parse
artifact.contentbefore you hand it to anything. A CSV whose row width does not match its header, or a markdown file with an unclosed code fence, is worse than no file. The app shows the parse error instead of offering the download. - Check every applicable flag id appears exactly once in
coverage_check. - For the
teaserlane, re-check the reply against your identifier list. The app does this in the browser and shows any leak in context.
Rate limits and cost
/estimate,/meand/guestare free.- A run is metered: you are charged
charged_creditsfrom thedonepayload, nothold_credits. - Owner markup is
markup_bps: 1000— ten per cent. - If the balance sits between
min_creditsandhold_creditsthe run still executes with a reduced output cap and returnstruncated: true. Treat that as a partial reply, not a complete one.