Quickstart
This walks the full loop a typical integration follows: authenticate → store a resume → stream an AI edit. Replace localhost ports with your production base URL as needed.
1. Mint a Personal Access Token
export CLERK_JWT="<clerk-session-jwt>"
curl -s -X POST http://localhost:3111/api/users/me/personal-access-tokens \
-H "Authorization: Bearer $CLERK_JWT" \
-H "Content-Type: application/json" \
-d '{ "name": "quickstart" }' | jq -r '.data.token'Save the mr_pat_… value:
export PAT="mr_pat_xxxxxxxxxxxxxxxxxxxxxxxx"2. Create a resume
content is a serialized JSON string of your resume document — the backend stores it opaquely.
curl -s -X POST http://localhost:3111/api/resumes \
-H "Authorization: Bearer $PAT" \
-H "Content-Type: application/json" \
-d '{
"title": "Frontend Resume",
"content": "{\"basics\":{\"name\":\"Ada Lovelace\"},\"work\":[]}"
}' | jq '.data.id'3. List your resumes
curl -s http://localhost:3111/api/resumes/mine \
-H "Authorization: Bearer $PAT" | jq '.data'4. Stream an AI chat
The chat endpoint streams Server-Sent Events. Each data: line is a JSON object with a type. Watch for message_chunk (incremental text) and resume_update (a full revised resume).
curl -N -X POST http://localhost:3112/api/chat \
-H "Content-Type: application/json" \
-d '{
"mode": "optimize",
"messages": [
{ "role": "user", "content": "Make my summary punchier and quantify impact." }
],
"currentResume": { "basics": { "name": "Ada Lovelace" } }
}'You’ll see a stream like:
data: {"type":"run_started","runId":"clx..."}
data: {"type":"message_chunk","content":"Here","runId":"clx..."}
data: {"type":"message_chunk","content":"'s a tighter","runId":"clx..."}
data: {"type":"resume_update","data":{...revised resume...},"runId":"clx..."}
data: {"type":"run_completed","runId":"clx..."}
data: {"type":"done","runId":"clx..."}In TypeScript
A minimal client that wraps the envelope and consumes the SSE stream:
REST helper
const PLATFORM = 'http://localhost:3111'
const PAT = process.env.PAT!
async function api<T>(path: string, init: RequestInit = {}): Promise<T> {
const res = await fetch(`${PLATFORM}/api${path}`, {
...init,
headers: {
Authorization: `Bearer ${PAT}`,
'Content-Type': 'application/json',
...init.headers,
},
})
const body = await res.json()
if (!res.ok || body.code >= 400) {
throw new Error(body.message ?? `HTTP ${res.status}`)
}
return body.data as T // unwrap the envelope
}
const resumes = await api<Array<{ id: string; title: string }>>('/resumes/mine')SSE frames are separated by a blank line (\n\n). Buffer across reads and only parse complete frames — a single network chunk may split a frame in half. See SSE events for the full event catalog.
Next steps
- Browse the full Platform API for resumes, versions, sharing, and collaboration.
- See Agent Service for workflows, interview, PDF, and translation.
- Keep the Response envelope and Errors pages handy.