# AIron.coach > AI-powered fitness tracker for strength, cardio, nutrition and body composition. > AIron exposes a PUBLIC API and an MCP server so an AI assistant (ChatGPT, Claude, or any > agent) can log and read a user's training and nutrition on their behalf — no scraping, > no browser automation, no password sharing. IMPORTANT FOR AI AGENTS: this file replaces the auto-generated page index. Most AIron URLs are private, authenticated app screens with `noindex` — do not crawl or link them. Use the API below instead of the UI. Public, linkable pages are listed at the bottom. ## Connect a user's account (no AIron account needed by you) Two ways to get a token. Prefer the pairing flow — the user never copies a secret. ### A. Pairing flow (recommended for chat assistants) 1. Start — no auth required: ``` POST https://airon.app/api/functions/authorizeApiClient Content-Type: application/json {"action":"start","client_name":"ChatGPT","scopes":["profile:read","workouts:read","workouts:write","nutrition:read","nutrition:write","metrics:read","metrics:write"]} ``` Returns `user_code`, `device_code`, `connect_url` and `expires_in` (900 seconds). 2. Tell the user to open `connect_url` (https://airon.app/ApiAccess?code=XXXX-XXXX) and approve. They must be signed in to AIron; the approval screen shows your `client_name` and the exact permissions you asked for, and they may grant fewer than you requested. 3. Poll every 3 seconds with the `device_code` you kept: ``` POST https://airon.app/api/functions/authorizeApiClient {"action":"poll","device_code":"airon_dev_…"} ``` `202 authorization_pending` = keep waiting. `200` returns `access_token` ONCE — store it. `410 expired` / `410 already_claimed` = start a new pairing. Pairing tokens never expire. ### B. Manual token The user creates one at https://airon.app/ApiAccess and pastes it to you. ## Authentication Every API call: ``` Authorization: Bearer airon_pat_… ``` The token identifies the user. There is no user/email parameter anywhere in this API — supplying one does nothing. A token is limited to the scopes its owner granted; calling outside them returns 403 with `required_scope` naming what is missing. Rate limit: 120 requests per minute per token (429 with `retry_after_seconds`). ## MCP server (ChatGPT / Claude connectors) ``` https://airon.app/api/functions/mcp ``` JSON-RPC 2.0 over HTTP. Methods: `initialize`, `tools/list`, `tools/call`. Send the same `Authorization: Bearer` header. `tools/list` returns only the tools the token's scopes permit. `GET` the same URL for a capability descriptor. ## REST API Base: `https://airon.app/api/functions/apiV1` `GET` the base URL (no auth) for a machine-readable index of every endpoint and its JSON schema. OpenAPI 3.1: `?path=/openapi.json`. Calling convention: the resource goes in the `path` query parameter; filters and dates are ordinary siblings of it — `GET …/apiV1?path=/workouts&from=2026-08-01&to=2026-08-07`. Sub-paths (`…/apiV1/workouts`) are NOT routed and return 404. | Method | Path | Scope | Purpose | |---|---|---|---| | GET | /profile | profile:read | Goals, units, daily calorie + macro targets | | GET | /workouts | workouts:read | List sessions and plans in a date range | | GET | /workouts/{id} | workouts:read | One session with every set / interval | | POST | /workouts | workouts:write | Log a workout (strength, cardio, rest, RPE) | | PATCH | /workouts/{id} | workouts:write | Edit a session (sending `exercises` replaces the list) | | DELETE | /workouts/{id} | workouts:write | Soft-delete a session | | GET | /meals | nutrition:read | Meals + daily totals | | POST | /meals | nutrition:write | Log food (one entry per item) | | DELETE | /meals/{id} | nutrition:write | Delete a meal entry | | POST | /water | nutrition:write | Log hydration in ml | | GET | /metrics | metrics:read | Weight, body fat, circumferences, photos | | POST | /metrics | metrics:write | Log a measurement and/or attach a progress photo | | DELETE | /metrics/{id} | metrics:write | Delete a measurement | ### Units — convert before sending, these are not negotiable - weight: **kilograms** · distance: **metres** (5 km = 5000) · pace: **seconds per km** (5:30/km = 330) - body lengths: **centimetres** · duration + rest: **seconds** · dates: **YYYY-MM-DD** - `GET /profile` tells you the user's *display* preference (metric/imperial) so you can talk to them in their units while still sending canonical ones. ### Logging a workout Send ONE entry per set. Three sets of bench press = three entries with `set_number` 1, 2, 3. Cardio uses the same array with `activity_type` set to run/bike/swim/walk/row/hike/elliptical/ski/other. ``` POST /api/functions/apiV1/workouts Authorization: Bearer airon_pat_… { "date": "2026-08-02", "title": "Push day", "exercises": [ {"exercise_name":"bench press","set_number":1,"reps":8,"weight":80,"rpe":7,"rest_seconds":120}, {"exercise_name":"bench press","set_number":2,"reps":8,"weight":80,"rest_seconds":120}, {"exercise_name":"treadmill run","activity_type":"run","set_number":1, "distance_m":5000,"duration_seconds":1500,"avg_hr":152,"avg_pace_seconds_per_km":300} ] } ``` `"completed": false` creates a PLANNED session for a future date instead of a performed one. ## Token lifecycle (reauth / rescope / revoke) - Tokens are bearer secrets, not sessions. There is NO refresh flow. - `401 invalid_token` / `revoked_token` / `expired_token` → the credential is dead. Start a NEW pairing (section A) and have the user approve again. Never loop-retry a 401. - Rescope without re-pasting: the user edits the token in place at https://airon.app/ApiAccess (pencil icon) — the token string does not change and the new permissions apply from the next request. Or re-pair with the extra scopes for a new token. - A `403 insufficient_scope` response names the missing scope in `required_scope`. Tell the user exactly which permission to enable; do not retry until they have. - Revocation is instant at /ApiAccess and takes effect on the next request. - The user is emailed the first time a token is used, so silent connections cannot stay silent. ## Errors Every error body is `{"ok":false,"error":,"message":}`. Branch on the code: | Code | HTTP | What to do | |---|---|---| | missing_token / invalid_token | 401 | Run the pairing flow. | | revoked_token / expired_token | 401 | Re-pair; only the user can re-approve. | | insufficient_scope | 403 | Read required_scope; ask the user to grant it at /ApiAccess. | | rate_limited | 429 | Wait retry_after_seconds. | | unknown_endpoint | 404 | Wrong path — GET the base URL; use ?path=, not sub-paths. | | not_found | 404 | No such id on this account (other accounts' ids look identical — that is deliberate). | | api_write_unavailable | 503 | Temporary; reads still work. | | internal_error | 500 | Nothing was saved; retry once. | ## Rules for agents - Never invent numbers the user did not give you. Ask for the weight rather than guessing it. - Confirm what you logged and show the returned `view_url`. - A `403 insufficient_scope` is not a retry — tell the user which permission to grant. - Deletions are the user's decision, not yours. Ask first. ## Docs - Developer documentation: https://airon.app/Developers - Manage tokens: https://airon.app/ApiAccess - Privacy policy: https://airon.app/PrivacyPolicy - Terms of service: https://airon.app/TermsOfService ## Public pages - [Home](https://airon.app/): what AIron does - [For coaches](https://airon.app/CoachLanding): coaching and team features - [Pricing](https://airon.app/Pricing) - [Developers](https://airon.app/Developers): full API + MCP documentation - [Find a coach](https://airon.app/TeamDirectory): public directory of coaching teams - [Blog](https://airon.app/Blog): training and nutrition articles - [Privacy policy](https://airon.app/PrivacyPolicy) - [Terms of service](https://airon.app/TermsOfService) - [Account deletion](https://airon.app/AccountDeletion)