Company Analysis

Driving Company Analysis from your own code

Company Analysis explains public companies: how a business earns, what its segments are, the forces acting on it, how its industry works, and what the bull and the bear arguments each rest on. Everything the web app does is available over HTTP.

What this API will not return

The boundary is enforced server-side by the app's system prompt and client-side by the bundle, and it is not a parameter you can turn off. No buy, sell or hold call. No price target. No return forecast. No verdict that anything is cheap or expensive. And no market-fixed figure - no share price, market capitalisation, valuation multiple, latest quarter, analyst consensus, relative pricing claim, dividend yield or ownership flow. Those are converted into the look_it_up array, which explains what each figure measures and names the document that holds it. If you need live market data, this is the wrong endpoint.

Base URL and envelope

Every endpoint lives under https://api.skillsafe.ai/v1/app-api and returns the same envelope: {"ok":true,"data":{...}} on success, or {"ok":false,"error":{"code":"...","message":"..."}} on failure. Check error before reading data.

CodeMeaningWhat to do
UNAUTHORIZEDMissing or expired tokenGet a fresh one (step 1)
PAYMENT_REQUIREDBalance below min_creditsTop up, or shorten the input
VALIDATION_ERRORThe input did not match the contractCheck task, register, depth and boundary
RATE_LIMITEDToo many requestsBack off; do not tight-loop
NOT_FOUNDUnknown job or record idCheck the id you stored
INTERNALPlatform faultRetry once with the same idempotency key

The input contract

Every run takes one JSON object. task is always "explain" - this app has a single lane, and the field exists so a future one cannot silently change what your integration receives.

FieldTypeNotes
taskstringRequired. Always "explain".
companystringRequired. A name or a ticker.
focusstringOptional. What you want to understand. Steers emphasis; licenses nothing.
contextstringOptional pasted source material. Preferred over memory where they disagree.
registerstringRequired. plain | industry | filings | historical.
depthstringRequired. orientation | standard | deep.
as_of_yearnumberThe year you believe it is; used for staleness reasoning.
boundaryobjectRequired, and boundary.not_advice must be true. See below.

boundary carries refused_acts, convert_not_state and pasted_text_contains - arrays of act ids the client detected in the user's own words. Each id in convert_not_state is a promise that the figure will appear in look_it_up. Send empty arrays if you are not running the client-side guard; the boundary itself does not depend on them.

1 Get a token

A guest token is issued per app and needs no account. It can browse and it can price a run, but a metered run needs a signed-in user's wallet. For a person, the friendlier route is the token page, which does the SSO round trip and hands you a token you can paste into a shell.

curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/guest" \
  -H "Content-Type: application/json" \
  -d '{
  "slug": "company-analysis"
}'
import json, urllib.request

TOKEN = "YOUR_TOKEN"  # or read it from your own secret store
url = "https://api.skillsafe.ai/v1/app-api/guest"
body = json.dumps({
  "slug": "company-analysis"
}).encode()
req = urllib.request.Request(url, data=body, method="POST")
req.add_header("Content-Type", "application/json")
with urllib.request.urlopen(req) as r:
    print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN";

const res = await fetch("https://api.skillsafe.ai/v1/app-api/guest", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "slug": "company-analysis"
  }),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code + ": " + error.message);
console.log(data);
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	token := os.Getenv("SKILLSAFE_TOKEN")
	body := []byte(`{"slug": "company-analysis"}`)
	req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/guest", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;

public class Main {
  public static void main(String[] a) throws Exception {
    String token = System.getenv("SKILLSAFE_TOKEN");
    HttpRequest.Builder b = HttpRequest.newBuilder()
        .uri(URI.create("https://api.skillsafe.ai/v1/app-api/guest"))
        .header("Content-Type", "application/json")
        .method("POST", HttpRequest.BodyPublishers.ofString(
            """
{"slug": "company-analysis"}
"""));
    HttpResponse<String> r = HttpClient.newHttpClient()
        .send(b.build(), HttpResponse.BodyHandlers.ofString());
    System.out.println(r.body());
  }
}
require "json"
require "net/http"
require "uri"

token = ENV.fetch("SKILLSAFE_TOKEN", "YOUR_TOKEN")
uri = URI("https://api.skillsafe.ai/v1/app-api/guest")
req = Net::HTTP::Post.new(uri)
req["Content-Type"] = "application/json"
req.body = {
  "slug" => "company-analysis"
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = getenv("SKILLSAFE_TOKEN") ?: "YOUR_TOKEN";
$headers = [
    "Content-Type: application/json",
];
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/guest");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, <<<'JSON'
{"slug": "company-analysis"}
JSON);
$out = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($out["data"]);
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

var token = Environment.GetEnvironmentVariable("SKILLSAFE_TOKEN") ?? "YOUR_TOKEN";
var http = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.skillsafe.ai/v1/app-api/guest");
req.Content = new StringContent(@"{""slug"": ""company-analysis""}",
    Encoding.UTF8, "application/json");
var res = await http.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());

2 Check what the token is

Confirms the token is live and tells you whose it is. The response carries exactly three fields - subject_type, subject_id and credits. There is no authenticated flag and no profile object, so the only correct test for a signed-in user is subject_type === "user". A guest reads "guest".

curl -sS -X GET "https://api.skillsafe.ai/v1/app-api/me" \
  -H "Authorization: Bearer $TOKEN"
import json, urllib.request

TOKEN = "YOUR_TOKEN"  # or read it from your own secret store
url = "https://api.skillsafe.ai/v1/app-api/me"
req = urllib.request.Request(url, method="GET")
req.add_header("Authorization", "Bearer " + TOKEN)
with urllib.request.urlopen(req) as r:
    print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN";

const res = await fetch("https://api.skillsafe.ai/v1/app-api/me", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${TOKEN}`,
  },
});
const { data, error } = await res.json();
if (error) throw new Error(error.code + ": " + error.message);
console.log(data);
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	token := os.Getenv("SKILLSAFE_TOKEN")
	req, _ := http.NewRequest("GET", "https://api.skillsafe.ai/v1/app-api/me", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;

public class Main {
  public static void main(String[] a) throws Exception {
    String token = System.getenv("SKILLSAFE_TOKEN");
    HttpRequest.Builder b = HttpRequest.newBuilder()
        .uri(URI.create("https://api.skillsafe.ai/v1/app-api/me"))
        .header("Authorization", "Bearer " + token)
        .method("GET", HttpRequest.BodyPublishers.noBody());
    HttpResponse<String> r = HttpClient.newHttpClient()
        .send(b.build(), HttpResponse.BodyHandlers.ofString());
    System.out.println(r.body());
  }
}
require "json"
require "net/http"
require "uri"

token = ENV.fetch("SKILLSAFE_TOKEN", "YOUR_TOKEN")
uri = URI("https://api.skillsafe.ai/v1/app-api/me")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = getenv("SKILLSAFE_TOKEN") ?: "YOUR_TOKEN";
$headers = [
    "Authorization: Bearer " . $token,
];
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/me");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$out = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($out["data"]);
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

var token = Environment.GetEnvironmentVariable("SKILLSAFE_TOKEN") ?? "YOUR_TOKEN";
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.skillsafe.ai/v1/app-api/me");
var res = await http.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());

3 Price the run before you make it

Free, and it creates no job. It returns hold_credits - what gets reserved - plus min_credits, model and markup_bps. Show the hold as reserved, never as the price: you are charged what the run actually uses, which is usually far less, because the hold prices the full output cap.

One trap worth knowing. This endpoint posts your argument as the request body and does not validate its shape. A bare string, null, an empty array and 42 all return ok:true with a correct model binding and the same hold. A clean estimate therefore proves the model wiring and proves nothing whatsoever about your input. Validate the object yourself before you spend - the web app runs a mustBeObject() check immediately before this call and again before the run.

curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/estimate" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "task": "explain",
  "company": "Costco Wholesale",
  "focus": "Why does the membership fee matter more than the retail margin?",
  "context": "",
  "register": "plain",
  "depth": "standard",
  "as_of_year": 2026,
  "boundary": {
    "not_advice": true,
    "refused_acts": [],
    "convert_not_state": [
      "market_value"
    ],
    "pasted_text_contains": []
  }
}'
import json, urllib.request

TOKEN = "YOUR_TOKEN"  # or read it from your own secret store
url = "https://api.skillsafe.ai/v1/app-api/estimate"
body = json.dumps({
  "task": "explain",
  "company": "Costco Wholesale",
  "focus": "Why does the membership fee matter more than the retail margin?",
  "context": "",
  "register": "plain",
  "depth": "standard",
  "as_of_year": 2026,
  "boundary": {
    "not_advice": true,
    "refused_acts": [],
    "convert_not_state": [
      "market_value"
    ],
    "pasted_text_contains": []
  }
}).encode()
req = urllib.request.Request(url, data=body, method="POST")
req.add_header("Content-Type", "application/json")
req.add_header("Authorization", "Bearer " + TOKEN)
with urllib.request.urlopen(req) as r:
    print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN";

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": "explain",
    "company": "Costco Wholesale",
    "focus": "Why does the membership fee matter more than the retail margin?",
    "context": "",
    "register": "plain",
    "depth": "standard",
    "as_of_year": 2026,
    "boundary": {
      "not_advice": true,
      "refused_acts": [],
      "convert_not_state": [
        "market_value"
      ],
      "pasted_text_contains": []
    }
  }),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code + ": " + error.message);
console.log(data);
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	token := os.Getenv("SKILLSAFE_TOKEN")
	body := []byte(`{"task": "explain", "company": "Costco Wholesale", "focus": "Why does the membership fee matter more than the retail margin?", "context": "", "register": "plain", "depth": "standard", "as_of_year": 2026, "boundary": {"not_advice": true, "refused_acts": [], "convert_not_state": ["market_value"], "pasted_text_contains": []}}`)
	req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/estimate", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+token)
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;

public class Main {
  public static void main(String[] a) throws Exception {
    String token = System.getenv("SKILLSAFE_TOKEN");
    HttpRequest.Builder b = HttpRequest.newBuilder()
        .uri(URI.create("https://api.skillsafe.ai/v1/app-api/estimate"))
        .header("Authorization", "Bearer " + token)
        .header("Content-Type", "application/json")
        .method("POST", HttpRequest.BodyPublishers.ofString(
            """
{"task": "explain", "company": "Costco Wholesale", "focus": "Why does the membership fee matter more than the retail margin?", "context": "", "register": "plain", "depth": "standard", "as_of_year": 2026, "boundary": {"not_advice": true, "refused_acts": [], "convert_not_state": ["market_value"], "pasted_text_contains": []}}
"""));
    HttpResponse<String> r = HttpClient.newHttpClient()
        .send(b.build(), HttpResponse.BodyHandlers.ofString());
    System.out.println(r.body());
  }
}
require "json"
require "net/http"
require "uri"

token = ENV.fetch("SKILLSAFE_TOKEN", "YOUR_TOKEN")
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" => "explain",
  "company" => "Costco Wholesale",
  "focus" => "Why does the membership fee matter more than the retail margin?",
  "context" => "",
  "register" => "plain",
  "depth" => "standard",
  "as_of_year" => 2026,
  "boundary" => {
    "not_advice" => true,
    "refused_acts" => [],
    "convert_not_state" => [
      "market_value"
    ],
    "pasted_text_contains" => []
  }
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = getenv("SKILLSAFE_TOKEN") ?: "YOUR_TOKEN";
$headers = [
    "Authorization: Bearer " . $token,
    "Content-Type: application/json",
];
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/estimate");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, <<<'JSON'
{"task": "explain", "company": "Costco Wholesale", "focus": "Why does the membership fee matter more than the retail margin?", "context": "", "register": "plain", "depth": "standard", "as_of_year": 2026, "boundary": {"not_advice": true, "refused_acts": [], "convert_not_state": ["market_value"], "pasted_text_contains": []}}
JSON);
$out = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($out["data"]);
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

var token = Environment.GetEnvironmentVariable("SKILLSAFE_TOKEN") ?? "YOUR_TOKEN";
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.skillsafe.ai/v1/app-api/estimate");
req.Content = new StringContent(@"{""task"": ""explain"", ""company"": ""Costco Wholesale"", ""focus"": ""Why does the membership fee matter more than the retail margin?"", ""context"": """", ""register"": ""plain"", ""depth"": ""standard"", ""as_of_year"": 2026, ""boundary"": {""not_advice"": true, ""refused_acts"": [], ""convert_not_state"": [""market_value""], ""pasted_text_contains"": []}}",
    Encoding.UTF8, "application/json");
var res = await http.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());

4 Run it

Returns a job. Poll it, or use the streaming endpoint in step 6. Always send Idempotency-Key: a retried request with the same key returns the original job rather than billing a second time.

curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/run" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "task": "explain",
  "company": "Costco Wholesale",
  "focus": "Why does the membership fee matter more than the retail margin?",
  "context": "",
  "register": "plain",
  "depth": "standard",
  "as_of_year": 2026,
  "boundary": {
    "not_advice": true,
    "refused_acts": [],
    "convert_not_state": [
      "market_value"
    ],
    "pasted_text_contains": []
  }
}'
import json, urllib.request

TOKEN = "YOUR_TOKEN"  # or read it from your own secret store
url = "https://api.skillsafe.ai/v1/app-api/run"
body = json.dumps({
  "task": "explain",
  "company": "Costco Wholesale",
  "focus": "Why does the membership fee matter more than the retail margin?",
  "context": "",
  "register": "plain",
  "depth": "standard",
  "as_of_year": 2026,
  "boundary": {
    "not_advice": true,
    "refused_acts": [],
    "convert_not_state": [
      "market_value"
    ],
    "pasted_text_contains": []
  }
}).encode()
req = urllib.request.Request(url, data=body, method="POST")
req.add_header("Content-Type", "application/json")
req.add_header("Authorization", "Bearer " + TOKEN)
with urllib.request.urlopen(req) as r:
    print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN";

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": "explain",
    "company": "Costco Wholesale",
    "focus": "Why does the membership fee matter more than the retail margin?",
    "context": "",
    "register": "plain",
    "depth": "standard",
    "as_of_year": 2026,
    "boundary": {
      "not_advice": true,
      "refused_acts": [],
      "convert_not_state": [
        "market_value"
      ],
      "pasted_text_contains": []
    }
  }),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code + ": " + error.message);
console.log(data);
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	token := os.Getenv("SKILLSAFE_TOKEN")
	body := []byte(`{"task": "explain", "company": "Costco Wholesale", "focus": "Why does the membership fee matter more than the retail margin?", "context": "", "register": "plain", "depth": "standard", "as_of_year": 2026, "boundary": {"not_advice": true, "refused_acts": [], "convert_not_state": ["market_value"], "pasted_text_contains": []}}`)
	req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/run", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+token)
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;

public class Main {
  public static void main(String[] a) throws Exception {
    String token = System.getenv("SKILLSAFE_TOKEN");
    HttpRequest.Builder b = HttpRequest.newBuilder()
        .uri(URI.create("https://api.skillsafe.ai/v1/app-api/run"))
        .header("Authorization", "Bearer " + token)
        .header("Content-Type", "application/json")
        .method("POST", HttpRequest.BodyPublishers.ofString(
            """
{"task": "explain", "company": "Costco Wholesale", "focus": "Why does the membership fee matter more than the retail margin?", "context": "", "register": "plain", "depth": "standard", "as_of_year": 2026, "boundary": {"not_advice": true, "refused_acts": [], "convert_not_state": ["market_value"], "pasted_text_contains": []}}
"""));
    HttpResponse<String> r = HttpClient.newHttpClient()
        .send(b.build(), HttpResponse.BodyHandlers.ofString());
    System.out.println(r.body());
  }
}
require "json"
require "net/http"
require "uri"

token = ENV.fetch("SKILLSAFE_TOKEN", "YOUR_TOKEN")
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" => "explain",
  "company" => "Costco Wholesale",
  "focus" => "Why does the membership fee matter more than the retail margin?",
  "context" => "",
  "register" => "plain",
  "depth" => "standard",
  "as_of_year" => 2026,
  "boundary" => {
    "not_advice" => true,
    "refused_acts" => [],
    "convert_not_state" => [
      "market_value"
    ],
    "pasted_text_contains" => []
  }
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = getenv("SKILLSAFE_TOKEN") ?: "YOUR_TOKEN";
$headers = [
    "Authorization: Bearer " . $token,
    "Content-Type: application/json",
];
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/run");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, <<<'JSON'
{"task": "explain", "company": "Costco Wholesale", "focus": "Why does the membership fee matter more than the retail margin?", "context": "", "register": "plain", "depth": "standard", "as_of_year": 2026, "boundary": {"not_advice": true, "refused_acts": [], "convert_not_state": ["market_value"], "pasted_text_contains": []}}
JSON);
$out = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($out["data"]);
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

var token = Environment.GetEnvironmentVariable("SKILLSAFE_TOKEN") ?? "YOUR_TOKEN";
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.skillsafe.ai/v1/app-api/run");
req.Content = new StringContent(@"{""task"": ""explain"", ""company"": ""Costco Wholesale"", ""focus"": ""Why does the membership fee matter more than the retail margin?"", ""context"": """", ""register"": ""plain"", ""depth"": ""standard"", ""as_of_year"": 2026, ""boundary"": {""not_advice"": true, ""refused_acts"": [], ""convert_not_state"": [""market_value""], ""pasted_text_contains"": []}}",
    Encoding.UTF8, "application/json");
var res = await http.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());

5 Poll the job

Poll until status is succeeded or failed. A second or so between polls is plenty; a tight loop earns a RATE_LIMITED.

curl -sS -X GET "https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID" \
  -H "Authorization: Bearer $TOKEN"
import json, urllib.request

TOKEN = "YOUR_TOKEN"  # or read it from your own secret store
url = "https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID"
req = urllib.request.Request(url, method="GET")
req.add_header("Authorization", "Bearer " + TOKEN)
with urllib.request.urlopen(req) as r:
    print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN";

const res = await fetch("https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${TOKEN}`,
  },
});
const { data, error } = await res.json();
if (error) throw new Error(error.code + ": " + error.message);
console.log(data);
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	token := os.Getenv("SKILLSAFE_TOKEN")
	req, _ := http.NewRequest("GET", "https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID", nil)
	req.Header.Set("Authorization", "Bearer "+token)
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;

public class Main {
  public static void main(String[] a) throws Exception {
    String token = System.getenv("SKILLSAFE_TOKEN");
    HttpRequest.Builder b = HttpRequest.newBuilder()
        .uri(URI.create("https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID"))
        .header("Authorization", "Bearer " + token)
        .method("GET", HttpRequest.BodyPublishers.noBody());
    HttpResponse<String> r = HttpClient.newHttpClient()
        .send(b.build(), HttpResponse.BodyHandlers.ofString());
    System.out.println(r.body());
  }
}
require "json"
require "net/http"
require "uri"

token = ENV.fetch("SKILLSAFE_TOKEN", "YOUR_TOKEN")
uri = URI("https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = getenv("SKILLSAFE_TOKEN") ?: "YOUR_TOKEN";
$headers = [
    "Authorization: Bearer " . $token,
];
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$out = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($out["data"]);
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

var token = Environment.GetEnvironmentVariable("SKILLSAFE_TOKEN") ?? "YOUR_TOKEN";
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var req = new HttpRequestMessage(new HttpMethod("GET"), "https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID");
var res = await http.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());

6 Or stream it

Server-sent events. Deltas arrive as they are generated, which is what lets the web app show real progress rather than a spinner. The final done event carries the same payload as a completed job, including charged_credits and truncated.

curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/run-stream" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "task": "explain",
  "company": "Costco Wholesale",
  "focus": "Why does the membership fee matter more than the retail margin?",
  "context": "",
  "register": "plain",
  "depth": "standard",
  "as_of_year": 2026,
  "boundary": {
    "not_advice": true,
    "refused_acts": [],
    "convert_not_state": [
      "market_value"
    ],
    "pasted_text_contains": []
  }
}'
import json, urllib.request

TOKEN = "YOUR_TOKEN"  # or read it from your own secret store
url = "https://api.skillsafe.ai/v1/app-api/run-stream"
body = json.dumps({
  "task": "explain",
  "company": "Costco Wholesale",
  "focus": "Why does the membership fee matter more than the retail margin?",
  "context": "",
  "register": "plain",
  "depth": "standard",
  "as_of_year": 2026,
  "boundary": {
    "not_advice": true,
    "refused_acts": [],
    "convert_not_state": [
      "market_value"
    ],
    "pasted_text_contains": []
  }
}).encode()
req = urllib.request.Request(url, data=body, method="POST")
req.add_header("Content-Type", "application/json")
req.add_header("Authorization", "Bearer " + TOKEN)
with urllib.request.urlopen(req) as r:
    print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN";

const res = await fetch("https://api.skillsafe.ai/v1/app-api/run-stream", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "task": "explain",
    "company": "Costco Wholesale",
    "focus": "Why does the membership fee matter more than the retail margin?",
    "context": "",
    "register": "plain",
    "depth": "standard",
    "as_of_year": 2026,
    "boundary": {
      "not_advice": true,
      "refused_acts": [],
      "convert_not_state": [
        "market_value"
      ],
      "pasted_text_contains": []
    }
  }),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code + ": " + error.message);
console.log(data);
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	token := os.Getenv("SKILLSAFE_TOKEN")
	body := []byte(`{"task": "explain", "company": "Costco Wholesale", "focus": "Why does the membership fee matter more than the retail margin?", "context": "", "register": "plain", "depth": "standard", "as_of_year": 2026, "boundary": {"not_advice": true, "refused_acts": [], "convert_not_state": ["market_value"], "pasted_text_contains": []}}`)
	req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/run-stream", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+token)
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;

public class Main {
  public static void main(String[] a) throws Exception {
    String token = System.getenv("SKILLSAFE_TOKEN");
    HttpRequest.Builder b = HttpRequest.newBuilder()
        .uri(URI.create("https://api.skillsafe.ai/v1/app-api/run-stream"))
        .header("Authorization", "Bearer " + token)
        .header("Content-Type", "application/json")
        .method("POST", HttpRequest.BodyPublishers.ofString(
            """
{"task": "explain", "company": "Costco Wholesale", "focus": "Why does the membership fee matter more than the retail margin?", "context": "", "register": "plain", "depth": "standard", "as_of_year": 2026, "boundary": {"not_advice": true, "refused_acts": [], "convert_not_state": ["market_value"], "pasted_text_contains": []}}
"""));
    HttpResponse<String> r = HttpClient.newHttpClient()
        .send(b.build(), HttpResponse.BodyHandlers.ofString());
    System.out.println(r.body());
  }
}
require "json"
require "net/http"
require "uri"

token = ENV.fetch("SKILLSAFE_TOKEN", "YOUR_TOKEN")
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.body = {
  "task" => "explain",
  "company" => "Costco Wholesale",
  "focus" => "Why does the membership fee matter more than the retail margin?",
  "context" => "",
  "register" => "plain",
  "depth" => "standard",
  "as_of_year" => 2026,
  "boundary" => {
    "not_advice" => true,
    "refused_acts" => [],
    "convert_not_state" => [
      "market_value"
    ],
    "pasted_text_contains" => []
  }
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = getenv("SKILLSAFE_TOKEN") ?: "YOUR_TOKEN";
$headers = [
    "Authorization: Bearer " . $token,
    "Content-Type: application/json",
];
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/run-stream");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, <<<'JSON'
{"task": "explain", "company": "Costco Wholesale", "focus": "Why does the membership fee matter more than the retail margin?", "context": "", "register": "plain", "depth": "standard", "as_of_year": 2026, "boundary": {"not_advice": true, "refused_acts": [], "convert_not_state": ["market_value"], "pasted_text_contains": []}}
JSON);
$out = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($out["data"]);
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

var token = Environment.GetEnvironmentVariable("SKILLSAFE_TOKEN") ?? "YOUR_TOKEN";
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.skillsafe.ai/v1/app-api/run-stream");
req.Content = new StringContent(@"{""task"": ""explain"", ""company"": ""Costco Wholesale"", ""focus"": ""Why does the membership fee matter more than the retail margin?"", ""context"": """", ""register"": ""plain"", ""depth"": ""standard"", ""as_of_year"": 2026, ""boundary"": {""not_advice"": true, ""refused_acts"": [], ""convert_not_state"": [""market_value""], ""pasted_text_contains"": []}}",
    Encoding.UTF8, "application/json");
var res = await http.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());

The wire format

Frames are event: NAME, then data: JSON, then a blank line. The event names are the ones this app's vendored SDK actually dispatches on - read _readSse in sdk.js if you want to check rather than trust this page.

event: job
data: {"job_id":"job_...","status":"running"}

event: delta
data: {"text":"{\"company\":{\"name\":\"Costco Wholesale"}

event: delta
data: {"text":"\",\"what_it_sells\":\"Groceries and household"}

event: done
data: {"job_id":"job_...","status":"succeeded","charged_credits":just-under-the-hold,
       "truncated":false,"output":{ ...the brief object... }}
EventCarriesWhat to do with it
jobjob_id, statusStore the id; it is what a retry and a poll both key on.
deltatextAppend. The brief arrives as a JSON string in fragments, so do not try to parse until done.
donethe full job, including output, charged_credits and truncatedParse output. This is the only frame whose payload is complete.
pendingthe job so farTreated as terminal by the SDK: the job outlived the stream. Poll /jobs/{id} from here.
errormessage, job_idKeep whatever deltas arrived - a half-finished brief still renders, and this app renders it rather than discarding it.

If the stream dies mid-frame you are left holding a truncated JSON string. That is a normal outcome, not an exceptional one: this app repairs it by closing whatever is still open and reports how many sections survived, rather than showing an error over a brief the user paid for.

7 What comes back

The model returns a single JSON object. Every array may be empty - an empty section is a true statement that the brief had nothing real to say there, and is deliberately preferred to a padded one, so write your integration to tolerate it.

{
  "company": {"name": "...", "also_known_as": "...",
              "listing": {"exchange": "...", "ticker": "..."},
              "country": "...", "founded": "...", "what_it_sells": "..."},
  "not_advice": "...",
  "register_used": "plain",
  "one_paragraph": "...",
  "how_it_makes_money":   [{"who_pays","for_what","how_the_money_arrives",
                            "what_must_be_true","stability","basis","as_of"}],
  "segments":             [{"name","what_it_does","relative_weight","weight_as_of",
                            "why_it_matters","where_to_verify","stability","basis"}],
  "structural_forces":    [{"force","mechanism","how_it_shows_up","who_it_favours",
                            "stability","basis","as_of"}],
  "how_the_industry_works":[{"point","why_it_is_like_that","consequence","stability","basis"}],
  "bull_case":            [{"claim","rests_on","what_would_have_to_be_true",
                            "where_it_is_weakest","basis"}],
  "bear_case":            [ ... identical fields ... ],
  "reading_the_filings":  [{"what_to_look_for","where","why_it_matters",
                            "what_a_change_would_tell_you"}],
  "vocabulary":           [{"term","plain_meaning","why_it_exists"}],
  "scale":                [{"measure","value","as_of","where_to_verify","basis"}],
  "look_it_up":           [{"figure","what_it_means","where","why_not_here"}],
  "limits":               ["..."]
}

The two enums, and why they are load-bearing

stability is durable or slow-drift. It says how fast the claim decays, not what it is about. A slow-drift row carries an as_of year; if one arrives without it, that is a defect and the web app reports it rather than papering over it. The third value, current-state, exists in the vocabulary but must never appear in output - those claims go to look_it_up instead.

basis is structural (follows from how the industry is built), documented (the company discloses it) or recalled (from training data, may be stale). Treat recalled rows as leads to verify, not as sources. If every row in a brief carries the same basis, be suspicious: real knowledge of a company is uneven.

bull_case and bear_case are structurally identical by design and are never ranked. There is no field anywhere in this contract that says which side is right, and adding one to your own layer would defeat the point of the boundary.

A run also returns charged_credits - what you actually paid, usually far below the hold - and truncated, which is true when the balance sat between min_credits and hold_credits and the output cap was reduced. A truncated brief is a partial one: render what parsed and say so.

8 Storing briefs

The app declares a briefs collection. Records nest under doc - read record.doc.company, not record.company. query resolves to {records, next_cursor} while similar resolves to the records array itself, so normalise both shapes at every call site. The ran_at field is a declared timestamp and rejects epoch milliseconds: send an ISO-8601 string with a Z suffix.

Four fields are embedded for vector search - company, what_it_sells, summary and focus. Vectors are never backfilled, so those are fixed.

curl -sS -X POST "https://api.skillsafe.ai/v1/app-api/collections/briefs/query" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "where": {
    "register": "plain"
  },
  "sort": {
    "field": "ran_at",
    "dir": "desc"
  },
  "limit": 20
}'
import json, urllib.request

TOKEN = "YOUR_TOKEN"  # or read it from your own secret store
url = "https://api.skillsafe.ai/v1/app-api/collections/briefs/query"
body = json.dumps({
  "where": {
    "register": "plain"
  },
  "sort": {
    "field": "ran_at",
    "dir": "desc"
  },
  "limit": 20
}).encode()
req = urllib.request.Request(url, data=body, method="POST")
req.add_header("Content-Type", "application/json")
req.add_header("Authorization", "Bearer " + TOKEN)
with urllib.request.urlopen(req) as r:
    print(json.load(r)["data"])
const TOKEN = "YOUR_TOKEN";

const res = await fetch("https://api.skillsafe.ai/v1/app-api/collections/briefs/query", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "where": {
      "register": "plain"
    },
    "sort": {
      "field": "ran_at",
      "dir": "desc"
    },
    "limit": 20
  }),
});
const { data, error } = await res.json();
if (error) throw new Error(error.code + ": " + error.message);
console.log(data);
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	token := os.Getenv("SKILLSAFE_TOKEN")
	body := []byte(`{"where": {"register": "plain"}, "sort": {"field": "ran_at", "dir": "desc"}, "limit": 20}`)
	req, _ := http.NewRequest("POST", "https://api.skillsafe.ai/v1/app-api/collections/briefs/query", bytes.NewReader(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+token)
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.*;

public class Main {
  public static void main(String[] a) throws Exception {
    String token = System.getenv("SKILLSAFE_TOKEN");
    HttpRequest.Builder b = HttpRequest.newBuilder()
        .uri(URI.create("https://api.skillsafe.ai/v1/app-api/collections/briefs/query"))
        .header("Authorization", "Bearer " + token)
        .header("Content-Type", "application/json")
        .method("POST", HttpRequest.BodyPublishers.ofString(
            """
{"where": {"register": "plain"}, "sort": {"field": "ran_at", "dir": "desc"}, "limit": 20}
"""));
    HttpResponse<String> r = HttpClient.newHttpClient()
        .send(b.build(), HttpResponse.BodyHandlers.ofString());
    System.out.println(r.body());
  }
}
require "json"
require "net/http"
require "uri"

token = ENV.fetch("SKILLSAFE_TOKEN", "YOUR_TOKEN")
uri = URI("https://api.skillsafe.ai/v1/app-api/collections/briefs/query")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req["Content-Type"] = "application/json"
req.body = {
  "where" => {
    "register" => "plain"
  },
  "sort" => {
    "field" => "ran_at",
    "dir" => "desc"
  },
  "limit" => 20
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = getenv("SKILLSAFE_TOKEN") ?: "YOUR_TOKEN";
$headers = [
    "Authorization: Bearer " . $token,
    "Content-Type: application/json",
];
$ch = curl_init("https://api.skillsafe.ai/v1/app-api/collections/briefs/query");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, <<<'JSON'
{"where": {"register": "plain"}, "sort": {"field": "ran_at", "dir": "desc"}, "limit": 20}
JSON);
$out = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($out["data"]);
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

var token = Environment.GetEnvironmentVariable("SKILLSAFE_TOKEN") ?? "YOUR_TOKEN";
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.skillsafe.ai/v1/app-api/collections/briefs/query");
req.Content = new StringContent(@"{""where"": {""register"": ""plain""}, ""sort"": {""field"": ""ran_at"", ""dir"": ""desc""}, ""limit"": 20}",
    Encoding.UTF8, "application/json");
var res = await http.SendAsync(req);
Console.WriteLine(await res.Content.ReadAsStringAsync());

Idempotency

Pass Idempotency-Key on every run. The web app derives it from a hash of the task, the company, the focus, the pasted text, the register, the depth and an attempt counter, so a network blip retried with the same key returns the original job instead of billing twice. If you retry, reuse the key. If you genuinely want a second brief, change the attempt counter.