openapi: 3.0.3 info: title: 'ZoetiCoach Partner API Documentation' description: 'Read/write client identity records and pull real, AI-verified WhatsApp check-in adherence data into your own EHR, CRM, or backend system. Enterprise plan required.' version: 1.0.0 servers: - url: 'https://zoeticoach.com' tags: - name: Adherence description: "\nReal, AI-verified check-in adherence data — the core value of this API.\nDerived entirely from actual WhatsApp check-in behavior run through\nZoetiCoach's own verification pipeline. This is deliberately read-only:\nthere is no way to write a check-in through this API." - name: Authentication description: "\nIntrospect the current API token — its abilities and when it was created.\nUseful for a partner's SDK to confirm which endpoints a given token can\ncall without having to trigger a 403 first." - name: Clients description: "\nMinimal client-identity endpoints — establishing the external_id mapping a\npartner needs to later pull adherence data via the Adherence group below.\nThere is no list/enumerate endpoint anywhere in this API by design — every\nlookup requires you to already know the specific external_id you're\nasking about." components: securitySchemes: default: type: http scheme: bearer description: 'Generate a token from Settings → Partner API Tokens (Enterprise plan required). Grant it the abilities it needs: `clients:write` to create/update client identity records, `checkins:read` to pull adherence data. The plaintext token is shown once at creation — store it securely.' security: - default: [] paths: '/api/partner/v1/clients/{externalId}/checkins': get: summary: "Get a client's adherence history" operationId: getAClientsAdherenceHistory description: "Per-day done/partial/missed/frozen/replied/none status for the\nrequested window, plus the client's current streak and total points." parameters: - in: query name: days description: 'How many trailing days of history to return (1-90). Defaults to 30.' example: 30 required: false schema: type: integer description: 'How many trailing days of history to return (1-90). Defaults to 30.' example: 30 responses: 200: description: '' content: application/json: schema: type: object example: external_id: patient-8821 days: - date: '2026-09-28' status: done - date: '2026-09-29' status: partial current_streak_days: 4 total_points: 55 week_energy_score: 7 properties: external_id: type: string example: patient-8821 days: type: array example: - date: '2026-09-28' status: done - date: '2026-09-29' status: partial items: type: object properties: date: type: string example: '2026-09-28' status: type: string example: done current_streak_days: type: integer example: 4 total_points: type: integer example: 55 week_energy_score: type: integer example: 7 404: description: '' content: application/json: schema: type: object example: message: 'Client not found.' properties: message: type: string example: 'Client not found.' tags: - Adherence parameters: - in: path name: externalId description: 'Your own record id for this client.' example: patient-8821 required: true schema: type: string /api/partner/v1/me: get: summary: "Get the current token's abilities" operationId: getTheCurrentTokensAbilities description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: token_name: 'Zapier integration' abilities: - 'clients:write' - 'checkins:read' created_at: '2026-09-29T10:00:00.000000Z' properties: token_name: type: string example: 'Zapier integration' abilities: type: array example: - 'clients:write' - 'checkins:read' items: type: string created_at: type: string example: '2026-09-29T10:00:00.000000Z' tags: - Authentication /api/partner/v1/clients: post: summary: 'Create a client' operationId: createAClient description: "Creates a minimal client-identity record and returns ZoetiCoach's own id\nalongside your external_id, so you can map the two going forward.\nConsent is never set via this API — the client starts inert (no\nWhatsApp check-ins) until they complete ZoetiCoach's own opt-in flow,\nwhich this call triggers automatically.\n\nSend an `Idempotency-Key` header to make a retry of this exact request\nsafe — a repeat with the same key returns the original response\ninstead of creating a duplicate client." parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: id: 42 external_id: patient-8821 name: 'Priya Nair' status: active language: en properties: id: type: integer example: 42 external_id: type: string example: patient-8821 name: type: string example: 'Priya Nair' status: type: string example: active language: type: string example: en 422: description: '' content: application/json: schema: type: object example: message: 'The external id has already been taken.' errors: external_id: - 'The external id has already been taken.' properties: message: type: string example: 'The external id has already been taken.' errors: type: object properties: external_id: type: array example: - 'The external id has already been taken.' items: type: string tags: - Clients requestBody: required: true content: application/json: schema: type: object properties: external_id: type: string description: 'Must not be greater than 255 characters.' example: b name: type: string description: 'Must not be greater than 255 characters.' example: 'n' phone: type: string description: 'Must not be greater than 20 characters.' example: gzmiyvdljnikhway language: type: string description: 'Must not be greater than 10 characters.' example: kcmyuw nullable: true required: - external_id - name - phone '/api/partner/v1/clients/{externalId}': get: summary: 'Get a client' operationId: getAClient description: 'Look up a client by the external_id you gave it at creation.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 42 external_id: patient-8821 name: 'Priya Nair' status: active language: en properties: id: type: integer example: 42 external_id: type: string example: patient-8821 name: type: string example: 'Priya Nair' status: type: string example: active language: type: string example: en 404: description: '' content: application/json: schema: type: object example: message: 'Client not found.' properties: message: type: string example: 'Client not found.' tags: - Clients patch: summary: 'Update a client' operationId: updateAClient description: "Updates name and/or status only — nothing else about a client is\nwritable through this API." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: id: 42 external_id: patient-8821 name: 'Priya Nair' status: paused language: en properties: id: type: integer example: 42 external_id: type: string example: patient-8821 name: type: string example: 'Priya Nair' status: type: string example: paused language: type: string example: en 404: description: '' content: application/json: schema: type: object example: message: 'Client not found.' properties: message: type: string example: 'Client not found.' tags: - Clients requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Must not be greater than 255 characters.' example: b status: type: string description: '' example: paused enum: - active - paused - archived parameters: - in: path name: externalId description: 'Your own record id for this client.' example: patient-8821 required: true schema: type: string