← Doctor Visit Prep / API
Get a token

Drive Doctor Visit Prep 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 app organizes a person's own notes for a clinician. It does not diagnose, triage or recommend treatment, and neither does its output when called from code.

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.

Input

One flat object of strings. task and concern are required; everything else may be empty. The web app sends at most these lengths, cutting long fields on line boundaries from the middle with a marker.

FieldTypeMeaning
taskstring, requiredAlways "prep".
concernstring, requiredThe main reason for the visit (600).
for_whomstring"self", "child" or "other". Sets the point of view of the questions.
age, sexstringAs the person gives them.
visit_typestringprimary, specialist, urgent, telehealth, follow_up or empty.
storystringWhat happened and when, ideally one line per event starting with the time (5,000).
medsstringMedicines and supplements, one per line (1,500).
allergies, conditions, tried, goalsstringFree text (400, 1,200, 1,200, 600).
prescanstring (JSON)The web app's free warning-sign check: {"flags":[{"id","sign","level"}],"meds_parsed":[…],"clipped":[…]}. Every flag is required to appear in the reply's red_flags. Send {"flags":[]} if you have no check of your own.
retry_notestringSent only on the one automatic reformat retry.

Output

The output (output.output) is one JSON object: task, status (ok · urgent · need_more · not_health), message, title, summary (chief_concern, onset, history, pertinent[], meds[] of {name, dose, how_often, reason, note}, allergies[], conditions[], tried[], goals), timeline[] of {when, event, kind} with kind in onset · change · treatment · test · visit · other, questions[] of {q, why, priority} with priority top or also, they_may_ask[] of {q, answer}, bring[], red_flags[] of {sign, action, why} with action emergency · urgent · call, and missing[].

status: "urgent" means the notes describe a warning sign happening now: show message first. The model may wrap the object in a code fence; strip it before parsing. The web app also reads the reply for diagnosis-like sentences and flags them; if you call the API directly, do the same.

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 sheet, not the price. There is one lane, prep:

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, 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: parse what arrived and top up for the rest.