← Profile README / API
Get a token

Drive Profile README 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.

The model writes prose only. Every badge, link and stats-card URL in the web app is built in the browser from the form, and the reply is checked against what was typed; code calling the API should treat the reply the same way and build its own links.

Errors

CodeMeaningWhat to do
UNAUTHORIZEDMissing, expired or wrong-app token.Mint a guest token or sign in again.
INSUFFICIENT_CREDITSBalance below min_credits.Top up. /estimate is free and tells you the hold.
VALIDATION_ERRORThe input object failed validation.Check error.details. The body is the input object itself — never wrap it in {"input": …}.
RATE_LIMITEDToo many requests.Back off and retry.
JOB_FAILEDThe run started and did not complete.Retry with the same Idempotency-Key.

The task field comes first

One prompt serves two turns, chosen by task:

Input

One flat object of strings. task is required; everything else may be empty. Objects travel as JSON text.

FieldTypeMeaning
taskstring, required"write" or "revise".
name, handle, tagline, locationstringName, GitHub username, headline in their words, where they are based.
aboutstringA few sentences in their words (1,500 characters).
now, learning, ask_me, fun_factstringOne line each (300).
stackstringTechnologies as typed, comma-separated.
projectsstringOne per line: name - what it does | link (3,000; long lists keep the first and last lines).
linksstringService names only, e.g. LinkedIn, Email (you@example.com), Website (yoursite.dev). Never URLs.
tonestringfriendly, professional, playful or minimal.
emojistringon or off.
notesstringAnything else, e.g. "open to work" (800).
prescanstring (JSON)The web app's free parse: {"stack":[],"stack_groups":[{"label","items"}],"projects":[{"name","has_link","desc"}],"link_services":[],"stats_cards":[],"warnings":[]}. stack and projects are the canonical names the reply must reuse.
previousstring (JSON)Revise only: the earlier reply object.
revise_notestringRevise only: what to change (400).
retry_notestringSent only on the one automatic reformat retry.

Output

The output (output.output) is one JSON object: task, status (ok · need_more · off_topic), message, tagline, intro, about[] (bullets), stack_groups[] of {label, items[]}, projects[] of {name, blurb}, extra[] of {heading, body}, fun_fact, closing and suggestions[].

The prose carries no links, images or badges — assemble those yourself. For need_more and off_topic only message is filled. The model may wrap the object in a code fence; strip it before parsing.

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".

3. Price it before you run it

/estimate is free and starts no job. hold_credits is a reservation priced against the longest possible reply, not the price. A first version (task: "write"):

A revise round (task: "revise") carries the earlier reply and the note:

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 task and a hash of the input, plus an attempt number for its one automatic reformat retry.

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: keep the fields that arrived whole and top up for the rest.