Drive Math Solver from your own code
Everything the web app does goes through one public surface. Base URL:
https://api.skillsafe.ai/v1/app-api
Every request carries Authorization: Bearer <token> and Content-Type: application/json.
Every response is a JSON envelope: {"ok":true,"data":{…}} on success and
{"ok":false,"error":{"code":"…","message":"…"}} on failure. Read error.code, not only the HTTP status.
Errors
| Code | Meaning | What to do |
|---|---|---|
UNAUTHORIZED | Missing, expired or wrong-app token. | Mint a guest token or sign in again. |
INSUFFICIENT_CREDITS | Balance below min_credits. | Top up. /estimate is free and tells you the hold. |
VALIDATION_ERROR | The input object failed validation. | Check error.details. The body is the input object itself — never wrap it in {"input": …}. |
RATE_LIMITED | Too many requests. | Back off and retry. |
JOB_FAILED | The run started and did not complete. | Retry with the same Idempotency-Key. |
The task field: two lanes
Every input carries task. "solve" solves a problem; "explain" explains one step of an earlier solution. Fields are scalars; the two object-valued ones (facts, steps) travel as JSON strings.
| Field | Type | Lane | Meaning |
|---|---|---|---|
task | string | both, required | "solve" or "explain". |
problem | string | both, required | The problem text. The web app sends at most 4,000 characters, cut on line boundaries with a marker. |
level | string | both | "auto", "school" or "university". |
facts | string (JSON) | solve | The free in-browser prescan: kind_guess, word_problem, variables, and numeric (real roots, a value, a definite integral or a limit estimate). The answer is held to agree with it. |
steps | string (JSON) | explain | The earlier solution's steps, [{n, title, explanation, math}]. |
step | number | explain | 1-based number of the step to explain. |
question | string | explain | What is unclear, or the person's own working to find the slip in. |
retry_note | string | both | Sent only on the one automatic reformat retry. |
The output contract
The output (output.output) is one JSON object. For solve: task, status (ok · not_math · ambiguous · unsolvable), message, title, topic, restated, given[], approach,
steps[] (title, explanation with inline math in \( \), math as display LaTeX), final_answer (latex, text), check, common_mistakes[], notes.
check restates the final answer in plain calculator syntax so it can be verified by substituting numbers. Its type is one of solve · evaluate · derivative · antiderivative · definite_integral · limit · equivalent · inequality · none. Example: {"type":"solve","equations":["x^2-5*x+6=0"],"variables":["x"],"solutions":[{"x":"2"},{"x":"3"}]}. The web app runs this check in the browser; if you call the API directly, run your own.
For explain: task, step, headline, explanation, sub_steps[] (explanation, math), key_idea, watch_out, answer_to_question, correction.
1. Get a token
A guest token is enough for /me and /estimate. Running is metered and needs a personal token from signing in. The tokens page shows yours and copies it. Replace YOUR_TOKEN below with it.
2. Check the session and the balance
/me returns subject_type, subject_id and credits. Signed in means subject_type === "user".
curl -s "https://api.skillsafe.ai/v1/app-api/me" \ -H "Authorization: Bearer YOUR_TOKEN"
import requests
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
r = requests.get(f"{BASE}/me", headers=H, timeout=30).json()
print(r["data"]["subject_type"], r["data"]["credits"])
const TOKEN = "YOUR_TOKEN";
const BASE = "https://api.skillsafe.ai/v1/app-api";
const H = { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" };
const r = await (await fetch(`${BASE}/me`, { headers: H })).json();
console.log(r.data.subject_type, r.data.credits);
package main
import ("bytes"; "encoding/json"; "fmt"; "net/http")
const base = "https://api.skillsafe.ai/v1/app-api"
const token = "YOUR_TOKEN"
func main() {
req, _ := http.NewRequest("GET", base+"/me", nil)
req.Header.Set("Authorization", "Bearer "+token)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
var out map[string]any
json.NewDecoder(res.Body).Decode(&out)
fmt.Println(out["data"])
_ = bytes.NewReader
}
var token = "YOUR_TOKEN";
var base = "https://api.skillsafe.ai/v1/app-api";
var http = java.net.http.HttpClient.newHttpClient();
var req = java.net.http.HttpRequest.newBuilder(java.net.URI.create(base + "/me"))
.header("Authorization", "Bearer " + token).GET().build();
System.out.println(http.send(req, java.net.http.HttpResponse.BodyHandlers.ofString()).body());
require "net/http"
require "json"
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
uri = URI("#{BASE}/me")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{TOKEN}"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN";
$base = "https://api.skillsafe.ai/v1/app-api";
$ch = curl_init("$base/me");
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"]]);
print_r(json_decode(curl_exec($ch), true)["data"]);
using System.Net.Http.Headers;
using System.Text;
var token = "YOUR_TOKEN";
var baseUrl = "https://api.skillsafe.ai/v1/app-api";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
Console.WriteLine(await http.GetStringAsync($"{baseUrl}/me"));
3. Price it before you run it
/estimate is free and starts no job. hold_credits is a reservation priced against the longest possible answer, not the price. Estimate each lane you use. Solve:
curl -s -X POST "https://api.skillsafe.ai/v1/app-api/estimate" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"task": "solve", "problem": "x^2 - 5x + 6 = 0", "level": "auto", "facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"}'
import requests
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
body = {
"task": "solve",
"problem": "x^2 - 5x + 6 = 0",
"level": "auto",
"facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"
}
r = requests.post(f"{BASE}/estimate", headers={**H}, json=body, timeout=120).json()
print(r["data"]["hold_credits"], r["data"]["model_alias"])
const TOKEN = "YOUR_TOKEN";
const BASE = "https://api.skillsafe.ai/v1/app-api";
const H = { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" };
const body = {
"task": "solve",
"problem": "x^2 - 5x + 6 = 0",
"level": "auto",
"facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"
};
const r = await (await fetch(`${BASE}/estimate`, { method: "POST", headers: { ...H }, body: JSON.stringify(body) })).json();
console.log(r.data.hold_credits, r.data.model_alias);
package main
import ("bytes"; "encoding/json"; "fmt"; "net/http")
const base = "https://api.skillsafe.ai/v1/app-api"
const token = "YOUR_TOKEN"
func main() {
payload := []byte(`{"task": "solve", "problem": "x^2 - 5x + 6 = 0", "level": "auto", "facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"}`)
req, _ := http.NewRequest("POST", base+"/estimate", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
var out map[string]any
json.NewDecoder(res.Body).Decode(&out)
fmt.Println(out["data"])
}
var token = "YOUR_TOKEN";
var base = "https://api.skillsafe.ai/v1/app-api";
var http = java.net.http.HttpClient.newHttpClient();
var body = "{\"task\": \"solve\", \"problem\": \"x^2 - 5x + 6 = 0\", \"level\": \"auto\", \"facts\": \"{\\\"kind_guess\\\": \\\"solve\\\", \\\"word_problem\\\": false, \\\"variables\\\": [\\\"x\\\"], \\\"numeric\\\": {\\\"what\\\": \\\"real_roots\\\", \\\"variable\\\": \\\"x\\\", \\\"values\\\": [2, 3], \\\"range\\\": [-100, 100]}}\"}";
var req = java.net.http.HttpRequest.newBuilder(java.net.URI.create(base + "/estimate"))
.header("Authorization", "Bearer " + token).header("Content-Type", "application/json")
.POST(java.net.http.HttpRequest.BodyPublishers.ofString(body)).build();
System.out.println(http.send(req, java.net.http.HttpResponse.BodyHandlers.ofString()).body());
require "net/http"
require "json"
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
uri = URI("#{BASE}/estimate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{TOKEN}"
req["Content-Type"] = "application/json"
req.body = "{\"task\": \"solve\", \"problem\": \"x^2 - 5x + 6 = 0\", \"level\": \"auto\", \"facts\": \"{\\\"kind_guess\\\": \\\"solve\\\", \\\"word_problem\\\": false, \\\"variables\\\": [\\\"x\\\"], \\\"numeric\\\": {\\\"what\\\": \\\"real_roots\\\", \\\"variable\\\": \\\"x\\\", \\\"values\\\": [2, 3], \\\"range\\\": [-100, 100]}}\"}"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN";
$base = "https://api.skillsafe.ai/v1/app-api";
$body = "{\"task\": \"solve\", \"problem\": \"x^2 - 5x + 6 = 0\", \"level\": \"auto\", \"facts\": \"{\\\"kind_guess\\\": \\\"solve\\\", \\\"word_problem\\\": false, \\\"variables\\\": [\\\"x\\\"], \\\"numeric\\\": {\\\"what\\\": \\\"real_roots\\\", \\\"variable\\\": \\\"x\\\", \\\"values\\\": [2, 3], \\\"range\\\": [-100, 100]}}\"}";
$ch = curl_init("$base/estimate");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", "Content-Type: application/json"],
]);
print_r(json_decode(curl_exec($ch), true)["data"]);
using System.Net.Http.Headers;
using System.Text;
var token = "YOUR_TOKEN";
var baseUrl = "https://api.skillsafe.ai/v1/app-api";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var body = new StringContent("{\"task\": \"solve\", \"problem\": \"x^2 - 5x + 6 = 0\", \"level\": \"auto\", \"facts\": \"{\\\"kind_guess\\\": \\\"solve\\\", \\\"word_problem\\\": false, \\\"variables\\\": [\\\"x\\\"], \\\"numeric\\\": {\\\"what\\\": \\\"real_roots\\\", \\\"variable\\\": \\\"x\\\", \\\"values\\\": [2, 3], \\\"range\\\": [-100, 100]}}\"}", Encoding.UTF8, "application/json");
var res = await http.PostAsync($"{baseUrl}/estimate", body);
Console.WriteLine(await res.Content.ReadAsStringAsync());
Explain (worked example for the second lane):
curl -s -X POST "https://api.skillsafe.ai/v1/app-api/estimate" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"task": "explain", "problem": "x^2 - 5x + 6 = 0", "steps": "[{\"n\": 1, \"title\": \"Factor the left side\", \"explanation\": \"Find two numbers that multiply to 6 and add to -5.\", \"math\": \"(x-2)(x-3)=0\"}, {\"n\": 2, \"title\": \"Apply the zero-product property\", \"explanation\": \"A product is zero only if a factor is zero.\", \"math\": \"x-2=0 \\\\text{ or } x-3=0\"}]", "step": 2, "question": "Why does one factor have to be zero?", "level": "auto"}'
import requests
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
body = {
"task": "explain",
"problem": "x^2 - 5x + 6 = 0",
"steps": "[{\"n\": 1, \"title\": \"Factor the left side\", \"explanation\": \"Find two numbers that multiply to 6 and add to -5.\", \"math\": \"(x-2)(x-3)=0\"}, {\"n\": 2, \"title\": \"Apply the zero-product property\", \"explanation\": \"A product is zero only if a factor is zero.\", \"math\": \"x-2=0 \\\\text{ or } x-3=0\"}]",
"step": 2,
"question": "Why does one factor have to be zero?",
"level": "auto"
}
r = requests.post(f"{BASE}/estimate", headers={**H}, json=body, timeout=120).json()
print(r["data"]["hold_credits"])
const TOKEN = "YOUR_TOKEN";
const BASE = "https://api.skillsafe.ai/v1/app-api";
const H = { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" };
const body = {
"task": "explain",
"problem": "x^2 - 5x + 6 = 0",
"steps": "[{\"n\": 1, \"title\": \"Factor the left side\", \"explanation\": \"Find two numbers that multiply to 6 and add to -5.\", \"math\": \"(x-2)(x-3)=0\"}, {\"n\": 2, \"title\": \"Apply the zero-product property\", \"explanation\": \"A product is zero only if a factor is zero.\", \"math\": \"x-2=0 \\\\text{ or } x-3=0\"}]",
"step": 2,
"question": "Why does one factor have to be zero?",
"level": "auto"
};
const r = await (await fetch(`${BASE}/estimate`, { method: "POST", headers: { ...H }, body: JSON.stringify(body) })).json();
console.log(r.data.hold_credits);
package main
import ("bytes"; "encoding/json"; "fmt"; "net/http")
const base = "https://api.skillsafe.ai/v1/app-api"
const token = "YOUR_TOKEN"
func main() {
payload := []byte(`{"task": "explain", "problem": "x^2 - 5x + 6 = 0", "steps": "[{\"n\": 1, \"title\": \"Factor the left side\", \"explanation\": \"Find two numbers that multiply to 6 and add to -5.\", \"math\": \"(x-2)(x-3)=0\"}, {\"n\": 2, \"title\": \"Apply the zero-product property\", \"explanation\": \"A product is zero only if a factor is zero.\", \"math\": \"x-2=0 \\\\text{ or } x-3=0\"}]", "step": 2, "question": "Why does one factor have to be zero?", "level": "auto"}`)
req, _ := http.NewRequest("POST", base+"/estimate", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
var out map[string]any
json.NewDecoder(res.Body).Decode(&out)
fmt.Println(out["data"])
}
var token = "YOUR_TOKEN";
var base = "https://api.skillsafe.ai/v1/app-api";
var http = java.net.http.HttpClient.newHttpClient();
var body = "{\"task\": \"explain\", \"problem\": \"x^2 - 5x + 6 = 0\", \"steps\": \"[{\\\"n\\\": 1, \\\"title\\\": \\\"Factor the left side\\\", \\\"explanation\\\": \\\"Find two numbers that multiply to 6 and add to -5.\\\", \\\"math\\\": \\\"(x-2)(x-3)=0\\\"}, {\\\"n\\\": 2, \\\"title\\\": \\\"Apply the zero-product property\\\", \\\"explanation\\\": \\\"A product is zero only if a factor is zero.\\\", \\\"math\\\": \\\"x-2=0 \\\\\\\\text{ or } x-3=0\\\"}]\", \"step\": 2, \"question\": \"Why does one factor have to be zero?\", \"level\": \"auto\"}";
var req = java.net.http.HttpRequest.newBuilder(java.net.URI.create(base + "/estimate"))
.header("Authorization", "Bearer " + token).header("Content-Type", "application/json")
.POST(java.net.http.HttpRequest.BodyPublishers.ofString(body)).build();
System.out.println(http.send(req, java.net.http.HttpResponse.BodyHandlers.ofString()).body());
require "net/http"
require "json"
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
uri = URI("#{BASE}/estimate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{TOKEN}"
req["Content-Type"] = "application/json"
req.body = "{\"task\": \"explain\", \"problem\": \"x^2 - 5x + 6 = 0\", \"steps\": \"[{\\\"n\\\": 1, \\\"title\\\": \\\"Factor the left side\\\", \\\"explanation\\\": \\\"Find two numbers that multiply to 6 and add to -5.\\\", \\\"math\\\": \\\"(x-2)(x-3)=0\\\"}, {\\\"n\\\": 2, \\\"title\\\": \\\"Apply the zero-product property\\\", \\\"explanation\\\": \\\"A product is zero only if a factor is zero.\\\", \\\"math\\\": \\\"x-2=0 \\\\\\\\text{ or } x-3=0\\\"}]\", \"step\": 2, \"question\": \"Why does one factor have to be zero?\", \"level\": \"auto\"}"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN";
$base = "https://api.skillsafe.ai/v1/app-api";
$body = "{\"task\": \"explain\", \"problem\": \"x^2 - 5x + 6 = 0\", \"steps\": \"[{\\\"n\\\": 1, \\\"title\\\": \\\"Factor the left side\\\", \\\"explanation\\\": \\\"Find two numbers that multiply to 6 and add to -5.\\\", \\\"math\\\": \\\"(x-2)(x-3)=0\\\"}, {\\\"n\\\": 2, \\\"title\\\": \\\"Apply the zero-product property\\\", \\\"explanation\\\": \\\"A product is zero only if a factor is zero.\\\", \\\"math\\\": \\\"x-2=0 \\\\\\\\text{ or } x-3=0\\\"}]\", \"step\": 2, \"question\": \"Why does one factor have to be zero?\", \"level\": \"auto\"}";
$ch = curl_init("$base/estimate");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", "Content-Type: application/json"],
]);
print_r(json_decode(curl_exec($ch), true)["data"]);
using System.Net.Http.Headers;
using System.Text;
var token = "YOUR_TOKEN";
var baseUrl = "https://api.skillsafe.ai/v1/app-api";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var body = new StringContent("{\"task\": \"explain\", \"problem\": \"x^2 - 5x + 6 = 0\", \"steps\": \"[{\\\"n\\\": 1, \\\"title\\\": \\\"Factor the left side\\\", \\\"explanation\\\": \\\"Find two numbers that multiply to 6 and add to -5.\\\", \\\"math\\\": \\\"(x-2)(x-3)=0\\\"}, {\\\"n\\\": 2, \\\"title\\\": \\\"Apply the zero-product property\\\", \\\"explanation\\\": \\\"A product is zero only if a factor is zero.\\\", \\\"math\\\": \\\"x-2=0 \\\\\\\\text{ or } x-3=0\\\"}]\", \"step\": 2, \"question\": \"Why does one factor have to be zero?\", \"level\": \"auto\"}", Encoding.UTF8, "application/json");
var res = await http.PostAsync($"{baseUrl}/estimate", body);
Console.WriteLine(await res.Content.ReadAsStringAsync());
4. Run and poll
/run returns a job. Always send an Idempotency-Key — the same key is the same run, so a retry cannot bill twice. The web app derives it from the lane and a hash of the input.
curl -s -X POST "https://api.skillsafe.ai/v1/app-api/run" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: math-solver:solve:8f3ka2-1x:a1" \
-d '{"task": "solve", "problem": "x^2 - 5x + 6 = 0", "level": "auto", "facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"}'
import requests
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
body = {
"task": "solve",
"problem": "x^2 - 5x + 6 = 0",
"level": "auto",
"facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"
}
r = requests.post(f"{BASE}/run", headers={**H, "Idempotency-Key": "math-solver:solve:8f3ka2-1x:a1"}, json=body, timeout=120).json()
job_id = r["data"]["job_id"]
const TOKEN = "YOUR_TOKEN";
const BASE = "https://api.skillsafe.ai/v1/app-api";
const H = { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" };
const body = {
"task": "solve",
"problem": "x^2 - 5x + 6 = 0",
"level": "auto",
"facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"
};
const r = await (await fetch(`${BASE}/run`, { method: "POST", headers: { ...H, "Idempotency-Key": "math-solver:solve:8f3ka2-1x:a1" }, body: JSON.stringify(body) })).json();
const jobId = r.data.job_id;
package main
import ("bytes"; "encoding/json"; "fmt"; "net/http")
const base = "https://api.skillsafe.ai/v1/app-api"
const token = "YOUR_TOKEN"
func main() {
payload := []byte(`{"task": "solve", "problem": "x^2 - 5x + 6 = 0", "level": "auto", "facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"}`)
req, _ := http.NewRequest("POST", base+"/run", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "math-solver:solve:8f3ka2-1x:a1")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
var out map[string]any
json.NewDecoder(res.Body).Decode(&out)
fmt.Println(out["data"])
}
var token = "YOUR_TOKEN";
var base = "https://api.skillsafe.ai/v1/app-api";
var http = java.net.http.HttpClient.newHttpClient();
var body = "{\"task\": \"solve\", \"problem\": \"x^2 - 5x + 6 = 0\", \"level\": \"auto\", \"facts\": \"{\\\"kind_guess\\\": \\\"solve\\\", \\\"word_problem\\\": false, \\\"variables\\\": [\\\"x\\\"], \\\"numeric\\\": {\\\"what\\\": \\\"real_roots\\\", \\\"variable\\\": \\\"x\\\", \\\"values\\\": [2, 3], \\\"range\\\": [-100, 100]}}\"}";
var req = java.net.http.HttpRequest.newBuilder(java.net.URI.create(base + "/run"))
.header("Authorization", "Bearer " + token).header("Content-Type", "application/json")
.header("Idempotency-Key", "math-solver:solve:8f3ka2-1x:a1")
.POST(java.net.http.HttpRequest.BodyPublishers.ofString(body)).build();
System.out.println(http.send(req, java.net.http.HttpResponse.BodyHandlers.ofString()).body());
require "net/http"
require "json"
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
uri = URI("#{BASE}/run")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{TOKEN}"
req["Content-Type"] = "application/json"
req["Idempotency-Key"] = "math-solver:solve:8f3ka2-1x:a1"
req.body = "{\"task\": \"solve\", \"problem\": \"x^2 - 5x + 6 = 0\", \"level\": \"auto\", \"facts\": \"{\\\"kind_guess\\\": \\\"solve\\\", \\\"word_problem\\\": false, \\\"variables\\\": [\\\"x\\\"], \\\"numeric\\\": {\\\"what\\\": \\\"real_roots\\\", \\\"variable\\\": \\\"x\\\", \\\"values\\\": [2, 3], \\\"range\\\": [-100, 100]}}\"}"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
puts JSON.parse(res.body)["data"]
<?php
$token = "YOUR_TOKEN";
$base = "https://api.skillsafe.ai/v1/app-api";
$body = "{\"task\": \"solve\", \"problem\": \"x^2 - 5x + 6 = 0\", \"level\": \"auto\", \"facts\": \"{\\\"kind_guess\\\": \\\"solve\\\", \\\"word_problem\\\": false, \\\"variables\\\": [\\\"x\\\"], \\\"numeric\\\": {\\\"what\\\": \\\"real_roots\\\", \\\"variable\\\": \\\"x\\\", \\\"values\\\": [2, 3], \\\"range\\\": [-100, 100]}}\"}";
$ch = curl_init("$base/run");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", "Content-Type: application/json", "Idempotency-Key: math-solver:solve:8f3ka2-1x:a1"],
]);
print_r(json_decode(curl_exec($ch), true)["data"]);
using System.Net.Http.Headers;
using System.Text;
var token = "YOUR_TOKEN";
var baseUrl = "https://api.skillsafe.ai/v1/app-api";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var body = new StringContent("{\"task\": \"solve\", \"problem\": \"x^2 - 5x + 6 = 0\", \"level\": \"auto\", \"facts\": \"{\\\"kind_guess\\\": \\\"solve\\\", \\\"word_problem\\\": false, \\\"variables\\\": [\\\"x\\\"], \\\"numeric\\\": {\\\"what\\\": \\\"real_roots\\\", \\\"variable\\\": \\\"x\\\", \\\"values\\\": [2, 3], \\\"range\\\": [-100, 100]}}\"}", Encoding.UTF8, "application/json");
http.DefaultRequestHeaders.Add("Idempotency-Key", "math-solver:solve:8f3ka2-1x:a1");
var res = await http.PostAsync($"{baseUrl}/run", body);
Console.WriteLine(await res.Content.ReadAsStringAsync());
curl -s "https://api.skillsafe.ai/v1/app-api/jobs/JOB_ID" \ -H "Authorization: Bearer YOUR_TOKEN" # repeat until data.status is "succeeded" or "failed"; # the solution is the JSON string at data.output.output
import requests
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
import json, time
job_id = "JOB_ID"
while True:
job = requests.get(f"{BASE}/jobs/{job_id}", headers=H, timeout=30).json()["data"]
if job["status"] in ("succeeded", "failed"):
break
time.sleep(1)
solution = json.loads(job["output"]["output"])
print(solution["final_answer"]["text"], solution["check"])
const TOKEN = "YOUR_TOKEN";
const BASE = "https://api.skillsafe.ai/v1/app-api";
const H = { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" };
let job;
for (;;) {
job = (await (await fetch(`${BASE}/jobs/JOB_ID`, { headers: H })).json()).data;
if (job.status === "succeeded" || job.status === "failed") break;
await new Promise((r) => setTimeout(r, 1000));
}
const solution = JSON.parse(job.output.output);
console.log(solution.final_answer.text, solution.check);
package main
import ("bytes"; "encoding/json"; "fmt"; "net/http")
const base = "https://api.skillsafe.ai/v1/app-api"
const token = "YOUR_TOKEN"
// GET base+"/jobs/JOB_ID" every second until data.status is
// "succeeded" or "failed", then json.Unmarshal data.output.output.
func main() { fmt.Println("poll", base+"/jobs/JOB_ID"); _ = bytes.NewReader; _ = json.Marshal; _ = http.Get }
var token = "YOUR_TOKEN"; var base = "https://api.skillsafe.ai/v1/app-api"; var http = java.net.http.HttpClient.newHttpClient(); // GET base + "/jobs/JOB_ID" every second until data.status is // "succeeded" or "failed"; the solution is the JSON string at data.output.output.
require "net/http"
require "json"
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
loop do
uri = URI("#{BASE}/jobs/JOB_ID")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{TOKEN}"
job = JSON.parse(Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }.body)["data"]
if %w[succeeded failed].include?(job["status"])
puts JSON.parse(job["output"]["output"])["final_answer"]
break
end
sleep 1
end
<?php
$token = "YOUR_TOKEN";
$base = "https://api.skillsafe.ai/v1/app-api";
do {
$ch = curl_init("$base/jobs/JOB_ID");
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"]]);
$job = json_decode(curl_exec($ch), true)["data"];
if (!in_array($job["status"], ["succeeded", "failed"])) sleep(1);
} while (!in_array($job["status"], ["succeeded", "failed"]));
print_r(json_decode($job["output"]["output"], true)["final_answer"]);
using System.Net.Http.Headers;
using System.Text;
var token = "YOUR_TOKEN";
var baseUrl = "https://api.skillsafe.ai/v1/app-api";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
// GET {baseUrl}/jobs/JOB_ID every second until data.status is
// "succeeded" or "failed"; the solution is the JSON string at data.output.output.
5. Stream it
/run-stream answers with server-sent events and ends with a done frame carrying the whole output, charged_credits and truncated. If truncated is true the balance ran low mid-answer: parse what arrived and top up for the rest.
curl -sN -X POST "https://api.skillsafe.ai/v1/app-api/run-stream" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-H "Idempotency-Key: math-solver:solve:8f3ka2-1x:a1" \
-d '{"task": "solve", "problem": "x^2 - 5x + 6 = 0", "level": "auto", "facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"}'
# event: job data: {"job_id": ...}
# event: delta data: {"text": "..."} (may be absent: a browser often gets only
# event: tick heartbeats and the whole answer in the final frame)
# event: done data: {"output": {"output": "<the JSON solution>"}, "charged_credits": ..., "truncated": false}
import requests
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
import json
body = {"task": "solve", "problem": "x^2 - 5x + 6 = 0", "level": "auto", "facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"}
with requests.post(f"{BASE}/run-stream", json=body, stream=True, timeout=300,
headers={**H, "Accept": "text/event-stream", "Idempotency-Key": "math-solver:solve:8f3ka2-1x:a1"}) as r:
event, done = None, None
for line in r.iter_lines(decode_unicode=True):
if line.startswith("event:"): event = line[6:].strip()
elif line.startswith("data:") and event == "done": done = json.loads(line[5:])
solution = json.loads(done["output"]["output"])
print(solution["final_answer"]["text"], done.get("charged_credits"), done.get("truncated"))
const TOKEN = "YOUR_TOKEN";
const BASE = "https://api.skillsafe.ai/v1/app-api";
const H = { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" };
const res = await fetch(`${BASE}/run-stream`, { method: "POST",
headers: { ...H, Accept: "text/event-stream", "Idempotency-Key": "math-solver:solve:8f3ka2-1x:a1" },
body: JSON.stringify({"task": "solve", "problem": "x^2 - 5x + 6 = 0", "level": "auto", "facts": "{\"kind_guess\": \"solve\", \"word_problem\": false, \"variables\": [\"x\"], \"numeric\": {\"what\": \"real_roots\", \"variable\": \"x\", \"values\": [2, 3], \"range\": [-100, 100]}}"}) });
const text = await res.text(); // or read res.body incrementally
let done = null;
for (const frame of text.split("\n\n")) {
const ev = /^event: *(.*)$/m.exec(frame), data = /^data: *(.*)$/m.exec(frame);
if (ev && ev[1] === "done" && data) done = JSON.parse(data[1]);
}
const solution = JSON.parse(done.output.output);
console.log(solution.final_answer.text, done.truncated);
package main
import ("bytes"; "encoding/json"; "fmt"; "net/http")
const base = "https://api.skillsafe.ai/v1/app-api"
const token = "YOUR_TOKEN"
// POST base+"/run-stream" with Accept: text/event-stream, read lines with
// bufio.Scanner, and json.Unmarshal the data line of the "done" event.
func main() { fmt.Println("see the cURL tab for the frame format"); _ = bytes.NewReader; _ = json.Marshal; _ = http.Get }
var token = "YOUR_TOKEN"; var base = "https://api.skillsafe.ai/v1/app-api"; var http = java.net.http.HttpClient.newHttpClient(); // POST base + "/run-stream" with Accept: text/event-stream, read the body // line by line (BodyHandlers.ofLines()), and parse the data line of the "done" event.
require "net/http"
require "json"
TOKEN = "YOUR_TOKEN"
BASE = "https://api.skillsafe.ai/v1/app-api"
# POST to "#{BASE}/run-stream" with Accept: text/event-stream; read the body,
# split frames on blank lines, and JSON.parse the data line of the "done" event.
<?php $token = "YOUR_TOKEN"; $base = "https://api.skillsafe.ai/v1/app-api"; // POST to "$base/run-stream" with Accept: text/event-stream; split the body on // blank lines and json_decode the data line of the "done" event.
using System.Net.Http.Headers;
using System.Text;
var token = "YOUR_TOKEN";
var baseUrl = "https://api.skillsafe.ai/v1/app-api";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
// POST {baseUrl}/run-stream with Accept: text/event-stream; read the response
// stream line by line and parse the data line of the "done" event.