Sync API
The packs' account-sync skills use a small JSON API. You don't need it to use SkillPlug, but here it is in full.
Base URL: https://skillplug.io. Pack ids: step1, step2, aways, residency (residency is reserved; no pack sends it yet).
Authentication
Send your SkillPlug key as a bearer token:
Authorization: Bearer sp_live_...- Keys are
sp_live_plus 43 base64url characters, created on the AI connections page, shown once, and stored only as a SHA-256 hash. The same key works for the agent API and MCP server. - Older sync keys (
sps_plus 43 characters) are still accepted on these endpoints until revoked. New ones are no longer issued. - Keys in query strings or bodies are rejected.
- A key covers one account. It can't read orders, change billing, or sign in.
- Agents keep the key in
SKILLPLUG_SYNC_TOKENor~/.skillplug/sync-token(mode 600), never inskillplug-state/.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET | /api/sync | Check a key. Returns ok, schema, paused, and packs with each pack's updated_at and bytes. |
POST | /api/sync/:pack | Replace that pack's snapshot (a full snapshot, not a delta). |
GET | /api/sync/:pack | Metadata for the stored snapshot: synced, updated_at, bytes, counts. The data itself is not echoed. |
DELETE | /api/sync/:pack | Delete that pack's synced data. Returns deleted. |
Check a key
curl -sS https://skillplug.io/api/sync \ -H "Authorization: Bearer $SKILLPLUG_SYNC_TOKEN"Send a snapshot
curl -sS -X POST https://skillplug.io/api/sync/step1 \ -H "Authorization: Bearer $SKILLPLUG_SYNC_TOKEN" \ -H "Content-Type: application/json" \ --data @/tmp/skillplug-step1-snapshot.jsonA successful POST returns:
{ "ok": true, "pack": "step1", "received_at": "2026-10-17T19:05:00Z", "bytes": 18234, "counts": { "scores": 14, "daily_log": 42 }, "dropped": [], "dashboard_url": "https://skillplug.io/account/dashboards/step1"}dropped lists anything the server ignored (unknown keys, rows over a cap, bad dates) so the agent can fix its mapping.
Snapshot format
{ "schema": "skillplug.sync.v1", "pack": "step1", "pack_version": "2.1", "generated_at": "2026-10-17T14:05:00Z", "client": { "agent": "claude-code", "skill": "s1-account-sync" }, "profile": { "preferred_name": "Riley", "degree": "MD", "class_year": "2028" }, "state": { "status": "active", "current_phase": "04-dedicated-execution", "current_subskill": "s1-daily-checkin", "last_session": "2026-10-17", "next_weekly_review": "2026-10-18", "weekly_review_day": "Sunday", "streak_days": 12, "next_actions": [{ "due": "2026-10-18", "text": "CBSSA 27 timed, full review" }], "notes": "one line" }, "countdowns": [{ "label": "Step 1 exam", "date": "2026-11-09", "source_url": "https://www.usmle.org/" }], "today": { "date": "2026-10-17", "checklist": [{ "text": "3 timed blocks + review", "minutes": 300, "done": false }] }, "tasks": [{ "text": "Book CBSSA 30", "due": "2026-10-20", "phase": "04", "done": false, "done_on": null }], "deadlines": [{ "date": "2026-10-24", "item": "Last day to reschedule without fee", "source_url": "https://...", "status": "todo", "notes": "" }], "scores": [], "weak_areas": [{ "rank": 1, "area": "Renal acid-base", "evidence": "CBSSA 29: 52%", "action": "...", "retest_date": "2026-10-25", "status": "open" }], "daily_log": [], "miss_log": []}Only schema and pack are required, and pack must match the URL. Every other block is optional, and a dashboard panel renders only when its block is present and non-empty. Missing values are null or omitted, never invented.
| Pack | Extra blocks |
|---|---|
step1, step2 | daily_log, miss_log, today (columns as in the pack's CSV headers; see State files) |
aways | away_tracker, letters, budget ({ total, currency }); no today |
Enums: state.status is active, paused, or complete. deadlines[].status is todo, done, missed, or moved. weak_areas[].status is open, improving, resolved, or parked. Away and letter statuses are listed in What syncs.
Limits
- Body: 256 KB per POST, UTF-8 JSON.
- Rate: 30 accepted syncs per rolling hour per account, all packs combined.
- Strings: trimmed and capped at 300 characters (600 for
notes,evidence, andtakeaway). Dates must beYYYY-MM-DD. - Rows: scores 500, daily_log 120, miss_log 500, tasks 200, deadlines 200, weak_areas 50, next_actions 3, today.checklist 12, countdowns 8, away_tracker 150, letters 40.
Errors
Errors return { "ok": false, "error": "...", "details": ... }.
| Status | Meaning | What the agent does |
|---|---|---|
400 | Invalid JSON or schema | Fix the payload once; don't loop |
401 | Missing, invalid, or revoked key | Set account_sync: paused and ask for a new key |
404 | Unknown pack | Check the pack id |
405 | Wrong method (for example POST /api/sync) | Use the right method |
413 | Body over 256 KB | Send fewer, more recent rows |
415 | Not application/json | Set the Content-Type header |
423 | Dashboard sync is paused on the account page | Skip; tell the student they can turn it back on at /account/agent |
429 | Rate limited, with Retry-After in seconds | Skip and try next session |
503 | Storage unavailable | Skip and try next session; never retry in a loop |