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:

HTTP
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_TOKEN or ~/.skillplug/sync-token (mode 600), never in skillplug-state/.

Endpoints

MethodPathPurpose
GET/api/syncCheck a key. Returns ok, schema, paused, and packs with each pack's updated_at and bytes.
POST/api/sync/:packReplace that pack's snapshot (a full snapshot, not a delta).
GET/api/sync/:packMetadata for the stored snapshot: synced, updated_at, bytes, counts. The data itself is not echoed.
DELETE/api/sync/:packDelete that pack's synced data. Returns deleted.

Check a key

Terminal
curl -sS https://skillplug.io/api/sync \  -H "Authorization: Bearer $SKILLPLUG_SYNC_TOKEN"

Send a snapshot

Terminal
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.json

A successful POST returns:

JSON
{  "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

skillplug.sync.v1
{  "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.

PackExtra blocks
step1, step2daily_log, miss_log, today (columns as in the pack's CSV headers; see State files)
awaysaway_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, and takeaway). Dates must be YYYY-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": ... }.

StatusMeaningWhat the agent does
400Invalid JSON or schemaFix the payload once; don't loop
401Missing, invalid, or revoked keySet account_sync: paused and ask for a new key
404Unknown packCheck the pack id
405Wrong method (for example POST /api/sync)Use the right method
413Body over 256 KBSend fewer, more recent rows
415Not application/jsonSet the Content-Type header
423Dashboard sync is paused on the account pageSkip; tell the student they can turn it back on at /account/agent
429Rate limited, with Retry-After in secondsSkip and try next session
503Storage unavailableSkip and try next session; never retry in a loop
Previous
State files