Skip to Content
Getting StartedQuickstart

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:

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

Last updated on