API Reference
CoachLayer API v1.0.0 · OpenAPI 3.1 · Base URL https://coachlayer.justzon.com. Sandbox keys (cl_test_) run in test mode; live keys open with the paid tiers.
Quickstart
Three calls from zero to coaching. Create an account to mint a sandbox key from the dashboard (300 free credits/month, hard stop, no card), or do it straight from the terminal:
# 1. mint a sandbox key (shown once, stored hashed)
curl https://coachlayer.justzon.com/v1/signup \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Fitness",
"email": "dev@acme.fit"
}'
# 2. your first coaching call
curl https://coachlayer.justzon.com/v1/brief \
-H "Authorization: Bearer $COACHLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"biometrics": {
"sleep_score": 82,
"hrv_value": 68,
"resting_heart_rate": 52,
"subjective_readiness": 4
},
"schedule": {
"has_workout": true,
"workout_name": "Push Day A",
"is_heavy": true
},
"user_profile": {
"age": 31,
"weight_kg": 78,
"height_cm": 181,
"gender": "male"
},
"lang": "en"
}'
# 3. see what it cost
curl https://coachlayer.justzon.com/v1/usage -H "Authorization: Bearer $COACHLAYER_API_KEY"
Authentication
Every call (except /health) is authenticated with a Bearer API key: Authorization: Bearer cl_test_…. Test keys (cl_test_) are the only kind that exist in the prototype; live keys (cl_live_) are structurally blocked until launch. Keys are stored hashed and shown once at mint time; revoke and re-mint at will.
Credits & tiers
Every endpoint costs a fixed number of credits per call; heavier reasoning costs more. Two endpoints carry a length surcharge. Credits reset monthly with your tier; overage is billed per credit on production tiers.
| Endpoint | Route | Credits | Surcharge |
| Coach Chat | /v1/chat | 2 / message | none |
| Readiness Brief (SITREP) | /v1/brief | 3 / brief | none |
| Coach Insight | /v1/coach-insight | 3 / insight | none |
| Analyze Workout | /v1/workout-analysis | 6 / analysis | none |
| Adaptive Program | /v1/adaptive-session | 8 / day rewrite | none |
| Weekly Report | /v1/weekly-report | 12 / report | none |
| Form Check | /v1/form-check | 25 / clip | +25 per extra 30 seconds beyond 30 |
| Magic Import | /v1/import | 40 / import | +20 per extra 12 weeks beyond 12 |
| Tier | Price | Credits/mo | Overage | rpm | Notes |
| Sandbox | $0/mo | 300 | hard stop | 10 | No card required |
| Build | $39/mo | 2,500 | $0.025/cr | 30 | No form_check. Email support |
| Launch | $99/mo | 7,000 | $0.022/cr | 60 | Webhooks, usage dashboard |
| Growth recommended | $299/mo | 24,000 | $0.018/cr | 300 | Analytics, priority support |
| Scale | $999/mo | 95,000 | $0.014/cr | 1000 | White-label, SSO, DPA |
| Enterprise | Custom | 250,000 | Custom | 2000 | Annual, committed discounts, fine-tunes on your data, dedicated infra |
Estimate a real workload with the pricing calculator.
Errors
One envelope everywhere: {"error": {"type", "code", "message", "request_id"}}:
| Type | Status | Meaning |
authentication_error | 401 | Missing, malformed or revoked API key. |
invalid_request_error | 400 | Body fails validation; the message names the field. |
billing_error | 402 / 403 | credit_limit_exhausted (Sandbox hard stop) or endpoint_not_in_tier (e.g. Form Check on Build). |
rate_limit_error | 429 | Tier rpm exceeded; Retry-After header tells you when to retry. |
upstream_error | 502 | Model upstream failed. You were not charged. |
capacity_error | 503 | free_tier_paused (shared free-sandbox budget exhausted for the month, paid tiers unaffected) or gateway_unavailable (transient backend outage, retry shortly). |
Failed calls are never charged. A 502 from the model upstream logs telemetry for our reliability tracking but bills 0 credits.
Metering headers & rate limits
Every metered response tells you what it cost:
| Header | Meaning |
X-Credits-Charged | Credits charged for this call, length surcharges included. |
X-Credits-Overage | Portion of the charge billed as overage (0 while inside the allowance). |
X-Credits-Remaining | Included credits remaining in the current billing period. |
X-Request-Id | Correlation id, echoed in error envelopes and the usage ledger. |
Rate limits are per-tier requests-per-minute over a fixed 60-second window; a 429 carries Retry-After in seconds.
LLM-readable docs & MCP
Your coding agent can read this API natively:
llms.txt: the index, per the llms.txt standard.
llms-full.txt: the whole reference in one markdown file. Paste it into any LLM's context.
openapi.yaml: the machine-readable OpenAPI 3.1 contract.
- MCP server: the gateway ships a Model Context Protocol server exposing all 10 tools (stdio transport). Point Claude Code / Claude Desktop at it:
{
"mcpServers": {
"coachlayer": {
"command": "npm",
"args": ["run", "-s", "mcp", "--prefix", "/path/to/coachlayer"],
"env": {
"COACHLAYER_API_KEY": "cl_test_…",
"COACHLAYER_BASE_URL": "https://coachlayer.justzon.com"
}
}
}
}
Then ask your agent things like “run a form check on this clip” or “how many credits did we burn this week?”. The tools map 1:1 onto the endpoints below.
Guides & comparisons
Before you wire it in: what it costs, how it fits your stack, and how it compares with building it yourself.
Intelligence endpoints
POST /v1/chat
2 credits / message
Coach chat (2 credits/message)
Request fields
| Field | Type | Description |
messages required | array of object | Conversation so far; the last entry must be role "user". Trimmed to the last 12. |
workout_context | object | Live workout state that grounds the reply. |
lang | string | ISO 639-1 Default: "en". |
Example request
curl https://coachlayer.justzon.com/v1/chat \
-H "Authorization: Bearer $COACHLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "Bench felt heavy at 80kg for 3x8. Should I go up next session?"
}
],
"workout_context": {
"workout_name": "Push Day A",
"completed_sets_summary": "Bench 3x8 @ 80kg, OHP 3x10 @ 40kg",
"active_exercise_name": "Bench Press",
"primary_goal": "strength"
},
"lang": "en"
}'
Example response
{
"reply": "Nice work on the bench sets. Given 3x8 at 80kg felt solid, load 82.5kg for your next set and keep the same rep target. Stop one rep shy of failure."
}
POST /v1/brief
3 credits / brief
Daily readiness brief, aka SITREP (3 credits)
Request fields
| Field | Type | Description |
biometrics required | object | |
schedule required | object | |
completed_today | object | |
user_profile | object | |
lang | string | Default: "en". |
Example request
curl https://coachlayer.justzon.com/v1/brief \
-H "Authorization: Bearer $COACHLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"biometrics": {
"sleep_score": 82,
"hrv_value": 68,
"resting_heart_rate": 52,
"subjective_readiness": 4
},
"schedule": {
"has_workout": true,
"workout_name": "Push Day A",
"is_heavy": true
},
"user_profile": {
"age": 31,
"weight_kg": 78,
"height_cm": 181,
"gender": "male"
},
"lang": "en"
}'
Example response
{
"title": "Primed for Push Day",
"short_recommendation": "Green light: train as planned.",
"status": "normal",
"message": "Sleep score 82 and HRV trending up: recovery is on your side today. Your push session is a go at full intensity. Cap the last pressing movement two reps shy of failure to bank tomorrow."
}
POST /v1/coach-insight
3 credits / insight
Coach-facing athlete insight (3 credits)
Same input contract as /v1/brief, framed for the coach reviewing an athlete.
Request fields
| Field | Type | Description |
biometrics required | object | |
schedule required | object | |
lang | string | Default: "en". |
Example request
curl https://coachlayer.justzon.com/v1/coach-insight \
-H "Authorization: Bearer $COACHLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"biometrics": {
"sleep_score": 64,
"hrv_value": 51,
"resting_heart_rate": 58
},
"schedule": {
"has_workout": true,
"workout_name": "Pull Day B"
},
"lang": "en"
}'
Example response
{
"title": "Adherence is the story this week",
"short_recommendation": "Flag the missed pull sessions before they become a pattern.",
"status": "normal",
"message": "This athlete hit 3 of 5 planned sessions and skipped both pull days. Volume on push muscles is 40% above their 30-day average; worth rebalancing next week before elbow niggles show up."
}
POST /v1/workout-analysis
6 credits / analysis
Post-workout analysis (6 credits)
Request fields
| Field | Type | Description |
workout required | object | The completed session: name, exercises[] (name, muscle_group, tracking_type, sets[] with weight_kg/reps/rpe/distance_meters/duration_seconds), duration_seconds, notes, debrief_tags/debrief_note, average_bpm, total_distance_meters. Optional session_type override. |
history | array of object | Prior sessions (date, name, total_volume_kg, exercises[]); enables PR detection and e1RM deltas (needs >= 2 prior data points per lift). |
athlete | object | age, weight_kg, goal, experience (beginner|intermediate|advanced), sessions_completed, streak_days, days_since_last_session. |
coach_directives | string | Free-text instructions from the athlete's human coach, applied by the analysis. |
warning_counts | object | 7-day repeat-warning counts (low_sleep, low_readiness, pace_fade, sessions_in_window); dampens or escalates repeated warnings. |
options | object | progressive_overload: boolean (default false). True emits per-exercise load prescriptions. |
lang | string | Default: "en". |
Example request
curl https://coachlayer.justzon.com/v1/workout-analysis \
-H "Authorization: Bearer $COACHLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workout": {
"name": "Lower A",
"duration_seconds": 3600,
"exercises": [
{
"name": "Back Squat",
"muscle_group": "quads",
"tracking_type": "weight_reps",
"sets": [
{
"weight_kg": 100,
"reps": 5,
"rpe": 8
},
{
"weight_kg": 100,
"reps": 5,
"rpe": 8.5
}
]
}
]
},
"history": [
{
"date": "2026-08-28",
"name": "Lower A",
"total_volume_kg": 5200
}
],
"athlete": {
"age": 31,
"weight_kg": 78,
"goal": "strength",
"experience": "intermediate",
"sessions_completed": 142,
"streak_days": 12
},
"options": {
"progressive_overload": false
},
"lang": "en"
}'
Example response
{
"headline": "Strong session with a pacing caveat",
"rating": 8,
"key_insights": [
{
"type": "volume",
"label": "Total volume",
"metric": "+12% vs last legs day",
"tone": "positive"
},
{
"type": "pacing",
"label": "Rest drift",
"metric": "rests grew 45s by the final block",
"tone": "warning"
}
],
"next_step": "Keep the added back-squat set; tighten rests to 2:30 on accessories.",
"summary": "Volume progression is on track and bar speed held up across the top sets. The only leak is pacing: the back half of the session drifted long, which mutes the conditioning stimulus.",
"strengths": [
"Progressive overload on squat",
"Consistent depth across all sets"
],
"improvements": [
"Rest discipline on accessories"
],
"session_type": "strength",
"schema_version": 2
}
POST /v1/adaptive-session
8 credits / day rewrite
Adaptive session synthesis (8 credits)
Request fields
| Field | Type | Description |
duration_minutes required | 15 | 30 | 45 | 60 | 90 | |
equipment_preset required | "full_gym" | "home_gym" | "hotel" | "custom" | |
allowed_equipment | array of string | |
signals | object | Recovery + load signals (ACWR per muscle, 7/30-day volume, sleep, HRV, soreness…). |
personal_records | array of object | |
goal | string | null | |
notes | string | null | |
lang | string | Default: "en". |
Example request
curl https://coachlayer.justzon.com/v1/adaptive-session \
-H "Authorization: Bearer $COACHLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"duration_minutes": 45,
"equipment_preset": "full_gym",
"signals": {
"sleep_hours": 7.5,
"hrv_trend": "up",
"soreness": {
"hamstrings": 6
}
},
"personal_records": [
{
"exercise_name": "Back Squat",
"e1rm": 140
}
],
"goal": "strength",
"lang": "en"
}'
Example response
{
"session_name": "Adaptive Lower Body (45 min)",
"reasoning": "ACWR shows quads fresh but hamstrings near the top of their band; the session biases hinge volume down and keeps squat intensity, matching the 45-minute cap.",
"estimated_volume_kg": 6450,
"estimated_duration_minutes": 44,
"exercises": [
{
"library_exercise_name": "Back Squat",
"order_index": 1,
"block_label": "A",
"target_sets": 4,
"target_reps": 6,
"target_weight_kg": 100,
"rest_seconds": 180,
"notes": "Top set at RPE 8.",
"tracking_type": "weight_reps"
},
{
"library_exercise_name": "Romanian Deadlift",
"order_index": 2,
"block_label": "B",
"target_sets": 3,
"target_reps": 8,
"target_weight_kg": 80,
"rest_seconds": 150,
"notes": "Reduced a set vs plan: hamstring ACWR 1.28.",
"tracking_type": "weight_reps"
}
]
}
POST /v1/weekly-report
12 credits / report
Weekly training report (12 credits)
Request fields
| Field | Type | Description |
week required | object | Aggregates of the week under review (start_date, end_date, total_volume_kg, total_duration_seconds, session_count, avg_rpe, total_distance_meters). |
previous_week | object | Same aggregates for the prior week; enables trends (deltas are computed server-side and clamped). |
goal | object | category: endurance|strength|crossfit|hypertrophy|weight_loss|general; focus: free text. |
movements | array of object | Per-lift context (name, top_set, e1rm_kg, previous_e1rm_kg, sets_done, target_sets); this is what turns narration into coaching. |
sessions | array of object | Session summaries of the week (date, name, volume_kg, distance_meters, duration_seconds, avg_rpe). |
wellness | object | daily: array of {date, sleep_hours, sleep_quality, stress_level, soreness_level, energy_level}. |
nutrition | array of object | Daily macros ({date, kcal, protein_g, carb_g, fat_g}). |
check_in | object | Weekly check-in (date, weight_kg, notes, qa[]). |
previous_directives | array of object | Prior weeks' directives ({week_start_date, focus_area, directive}); prevents repetition. |
lang | string | Default: "en". |
Example request
curl https://coachlayer.justzon.com/v1/weekly-report \
-H "Authorization: Bearer $COACHLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"week": {
"start_date": "2026-08-31",
"end_date": "2026-09-06",
"total_volume_kg": 42300,
"total_duration_seconds": 14400,
"session_count": 4,
"avg_rpe": 7.6
},
"previous_week": {
"start_date": "2026-08-24",
"end_date": "2026-08-30",
"total_volume_kg": 38800,
"session_count": 4,
"avg_rpe": 7.3
},
"goal": {
"category": "strength",
"focus": "squat 1RM"
},
"movements": [
{
"name": "Back Squat",
"top_set": "120kg x 5",
"e1rm_kg": 140,
"previous_e1rm_kg": 136,
"sets_done": 12,
"target_sets": 12
}
],
"lang": "en"
}'
Example response
{
"rank": "A",
"headline": "Best training week in a month",
"summary": "4 of 4 planned sessions completed, volume up 9% on rising intensity, and sleep held above 7h every night. One watch-out: Friday soreness spiked after the deadlift PR.",
"metrics": {
"volume": {
"value": "42,300 kg",
"trend": "up",
"diff_percent": 9
},
"intensity": {
"value": "7.6",
"trend": "up",
"diff_percent": 4,
"unit": "RPE"
},
"consistency": {
"value": "100%",
"trend": "flat",
"diff_percent": 0
}
},
"focus_area": "Recovery",
"coach_directive": "Hold volume next week and bank the adaptation: no new PR attempts before Thursday.",
"next_week_plan": [
{
"title": "Deload hinge pattern",
"detail": "RDLs at 80% of this week’s load."
},
{
"title": "Keep squat intensity",
"detail": "Same top-set weight, one fewer back-off set."
}
],
"wins": [
"Deadlift PR 180kg",
"Perfect session adherence"
]
}
POST /v1/form-check
25 credits / clip · +25 per extra 30 seconds
Video form check (25 credits ≤30s, +25 per extra 30s)
Request fields
| Field | Type | Description |
video_url required | string | |
video_seconds | number | Clip length; drives the length surcharge. Clips are analyzed at pinned low media resolution. |
exercise_name | string | null | |
lang | string | Default: "en". |
Example request
curl https://coachlayer.justzon.com/v1/form-check \
-H "Authorization: Bearer $COACHLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_url": "https://cdn.example.com/clips/squat-topset.mp4",
"video_seconds": 24,
"exercise_name": "Back Squat",
"lang": "en"
}'
Example response
{
"score": 78,
"strengths": [
"Consistent bar path",
"Solid brace at setup"
],
"improvements": [
"Knees cave slightly on reps 4-5",
"Depth just above parallel under fatigue"
],
"recommendations": [
"Add a 2-second pause squat set at 60% to groove depth.",
"Cue \"knees out\" on the final reps or drop 5% load."
],
"detected_exercise": "Back Squat",
"low_confidence": false
}
POST /v1/import
40 credits / import · +20 per extra 12 weeks
Magic Import: parse a program from text/file (40 credits up to 12 weeks, +20 per extra 12)
Request fields
| Field | Type | Description |
text_content | string | Raw program text (one of text_content / file_url / file_base64 required). |
file_url | string | PDF/image/markdown source. |
file_base64 | string | Inline file content |
file_mime_type | string | MIME type of file_base64 (application/pdf |
program_weeks | number | Declared length; drives the length surcharge. |
import_type | "full_program" | "routine" | "nutrition_import" | Default: "full_program". |
lang | string | Default: "en". |
Example request
curl https://coachlayer.justzon.com/v1/import \
-H "Authorization: Bearer $COACHLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text_content": "Week 1\nDay 1: Squat 5x5 @ 75%, RDL 3x8, Plank 3x60s\nDay 2: Bench 5x5 @ 77.5%…",
"program_weeks": 8,
"import_type": "full_program",
"lang": "en"
}'
Example response
{
"message": "Program parsed and structured successfully.",
"import_type": "full_program",
"is_finished": true,
"imported_data": {
"type": "full_program",
"weeks_count": 8,
"workouts_count": 32,
"program_json": {
"name": "Intermediate Strength Block",
"weeks": 8,
"days_per_week": 4,
"sample_day": {
"name": "Day 1: Squat focus",
"exercises": [
{
"name": "Back Squat",
"sets": 5,
"reps": 5,
"intensity": "75-82% 1RM"
}
]
}
}
}
}
POST /v1/signup
free · public
Self-serve sandbox signup (no auth, no card)
Request fields
| Field | Type | Description |
name required | string | Account or project name (1-120 characters). |
email required | string | Contact address for the account. |
Example request
curl https://coachlayer.justzon.com/v1/signup \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Fitness",
"email": "dev@acme.fit"
}'
Example response
{
"tenant_id": "ten_9f2c",
"name": "Acme Fitness",
"tier": "sandbox",
"api_key": "cl_test_k3H…",
"note": "Store this key now: it is shown once and kept only as a hash. Sandbox is test-mode only."
}
GET /v1/me
free · authenticated
Current key's tenant, tier and limits
Example request
curl https://coachlayer.justzon.com/v1/me \
-H "Authorization: Bearer $COACHLAYER_API_KEY"
Example response
{
"tenant_id": "ten_9f2c",
"name": "Acme Fitness",
"tier": "growth",
"monthly_credits": 24000,
"rpm": 300,
"blocked_endpoints": []
}
GET /v1/usage
free · authenticated
Current billing period usage
Example request
curl https://coachlayer.justzon.com/v1/usage \
-H "Authorization: Bearer $COACHLAYER_API_KEY"
Example response
{
"period": "2026-09",
"tier": "growth",
"credits_included": 24000,
"credits_used": 1240,
"credits_remaining": 22760,
"by_endpoint": {
"chat": {
"calls": 310,
"credits": 620,
"tokens_in": 868000,
"tokens_out": 198400
},
"weekly_report": {
"calls": 40,
"credits": 480,
"tokens_in": 392000,
"tokens_out": 108000
}
}
}
GET /health
free · public
Liveness (public)