API contract draft
Draft v0.1 · REST contract for the demonstrator. Machine-readable draft: OpenAPI JSON.
Conventions
Prefix /api/v1. JSON requests and responses; ISO date strings for weeks and activities; UTC timestamps for audit events. A seeded demo session determines the actor server-side. The interface cannot gain access by choosing an arbitrary role header. Production authentication is undecided.
List responses return {items: [...]}. Error responses contain code, message and optional fieldErrors. The demo has a small bounded fixture set; production paging is deferred. Mutating operations use an Idempotency-Key; plan-state and plan-change acceptance also require If-Match against the latest plan ETag.
Operations
| Operation | Role | Behavior |
|---|---|---|
| GET /members/me | Member | Own preferences, permissions and plan summary |
| PATCH /members/me | Member | Update goal and preferences |
| PUT /members/me/consents/{purpose} | Member | Record optional choice, including revocation |
| POST /plans | Member | Produce a plan proposal from a demo template |
| GET /plans/{planId} | Owner or assigned authorized coach | Current plan, versions and ETag |
| PATCH /plans/{planId} | Owner | Accept, decline, pause, resume, complete or withdraw with valid transition |
| POST /activities | Member | Create a manual activity |
| PATCH /activities/{activityId} | Owner | Correct a manual record |
| DELETE /activities/{activityId} | Owner | Remove a manual record and preserve audit metadata |
| POST /imports/activity-batches | Adapter scoped to member | Validate, deduplicate and record a batch after permission checks |
| PUT /plans/{planId}/check-ins/{weekStart} | Owner | Create or replace current check-in revision |
| POST /plans/{planId}/reviews | Owner or assigned authorized coach | Calculate and persist a review revision |
| POST /support-requests | Member | Explicitly request help |
| GET /coach/support-requests | Coach | Assigned requests and assignable demo queue entries |
| PATCH /support-requests/{requestId} | Assigned coach or member as allowed | Assign/respond/close or member cancel |
| POST /plans/{planId}/changes | Assigned authorized coach | Propose adjustment without changing active version |
| POST /plans/{planId}/changes/{changeId}/decision | Owner | Accept or decline, with current plan ETag |
| GET /analyst/decisions | Analyst | Pseudonymous traces without free text |
| GET /analyst/metrics | Analyst | Aggregate measures with definitions |
Example review response
{
"id": "review-camille-1",
"planId": "plan-camille",
"planVersion": 1,
"weekStart": "2026-10-05",
"revision": 1,
"sessionCount": 1,
"target": 3,
"completeness": "complete",
"outcome": "support_offered",
"ruleId": "BR06",
"ruleVersion": "review-v1",
"nextActions": ["request_support", "continue"]
}
Error and access rules
| HTTP status | Code examples | Expected behavior |
|---|---|---|
| 400 | invalid_json, missing_idempotency_key | No mutation |
| 401 | unauthenticated | Request a valid demo session |
| 403 | permission_revoked, role_forbidden | No protected result or write |
| 404 | resource_not_found | Also used for another member's inaccessible resource |
| 409 | duplicate_request, event_conflict, stale_version, invalid_transition | Preserve current state and return safe conflict details |
| 412 | etag_mismatch | Reload plan before retrying a change |
| 422 | invalid_date, invalid_duration, no_suitable_template | Return field errors or matching limit |
| 428 | precondition_required | Require current plan ETag |
| 503 | service_unavailable | Do not confirm a save |
Identical retries reuse the original response when the idempotency key and payload match. Reusing a key with a different payload returns 409. Import batches return accepted, duplicate and rejected counts plus item errors; valid items may commit even when others fail. Batch-level revoked permission rejects the whole batch.
The OpenAPI schemas define main request shapes and reusable errors. Authorization, transition rules, normalization and transaction semantics also require these documents; a schema alone cannot enforce them.
R1 demo controls and implemented subset, 14 October 2026
Correct contract link: OpenAPI. Operations carry x-r1-status so planned POC extensions are not represented as working APIs. R1 implements preferences, consents, proposal and accept/decline, manual create/list, check-ins, reviews, support creation/coach queue, changes and decisions, and analyst decisions. Lifecycle PATCH actions other than accept/decline, support administration, imports, manual correction/deletion and analyst metrics are deferred.
| Route | Contract |
|---|---|
| POST /api/v1/demo/start | JSON {}, no account registration; reuse a valid visitor or create a guided dataset and opaque cookie |
| GET /api/v1/demo/session | Envelope: generation, revision, role, scenario and expiresAt; 401 if missing/expired |
| GET /api/v1/demo/state | Envelope plus role-scoped screen state; coach sharing is rechecked; analyst gets decisions only |
| POST /api/v1/demo/role | JSON role: member/coach/analyst; increment actor revision |
| POST /api/v1/demo/scenario | JSON scenario: guided/camille/jules/noor; restore explicit seed, increment generation/revision and select its member |
| POST /api/v1/demo/reset | JSON {}; restore only this visitor to guided/Member, increment generation/revision |
All mutations require same-origin JSON. APP_ORIGIN may specify the deployed origin. Requests are limited to 8 KiB. Except start, mutations require Idempotency-Key, X-Demo-Generation and X-Demo-Revision; activation/decline and adjustment decisions also require If-Match. Cookie prevention_demo is HttpOnly, SameSite=Lax and Secure on HTTPS. Responses are no-store. Tokens are not exposed in JSON or logs.
Errors add origin_forbidden (403), payload_too_large (413), stale_generation/stale_actor/idempotency_conflict (409), and named field-validation codes. Failed requests roll back and never confirm a save. Current generation and actor revision must match before a domain mutation or replay. A visitor can reload after a reset/role conflict. Locale-prefixed pages do not change API paths. No real messages are sent and no outbox implementation is claimed for R1.
Control retry qualification: reset/scenario/role responses can be replayed with their original envelope headers only while the stored resulting generation and actor revision are still current. A later control change invalidates that exception. Domain requests always require the current envelope before replay. New R1 schemas preserve full-POC schemas separately and describe the actual currentVersion=0 proposal, requested/proposed support states, 500-character notes/rationale and categorical analyst projection. Complete manual reporting can be saved through PATCH /members/me with reportingComplete without submitting a check-in.