{
  "openapi": "3.1.0",
  "info": {
    "title": "Rehabify Partner API",
    "version": "1.0.0",
    "summary": "Refer patients to Rehabify Health, follow their care, and reconcile commissions.",
    "description": "The Rehabify Partner API lets HMOs, hospitals and clinics, employers, gyms and digital health products refer patients to MRTBN-licensed physiotherapists, follow each referral's status, sessions and progress reports, manage no-code referral links, and reconcile commissions.\n\n**Environments.** Sandbox and live share one base URL; the API key decides the environment (`sk_test_…` = sandbox, `sk_live_…` = live). The same API is also reachable at `https://physioaroundme.com/api/v1`.\n\n**Conventions.** JSON (UTF-8) bodies; ISO-8601 UTC timestamps; money as integer kobo in fields ending `_kobo` with `currency` `NGN`; cursor pagination (`limit` 1–100, default 25, and `cursor`); `Idempotency-Key` on authenticated POST requests (remembered for 24 hours per environment). Every response carries `X-Request-Id` and `X-Rehabify-Environment`. Unknown request fields are ignored.\n\n**Rate limits.** Sandbox 10 requests/second; live 20 requests/second (enterprise contracts: 100/s).\n\nDocumentation: https://docs.physioaroundme.com",
    "contact": {
      "name": "Rehabify Health partner integrations",
      "url": "https://docs.physioaroundme.com",
      "email": "partners@physioaroundme.com"
    }
  },
  "externalDocs": {
    "description": "Rehabify developer documentation",
    "url": "https://docs.physioaroundme.com"
  },
  "servers": [
    {
      "url": "https://api.physioaroundme.com/v1",
      "description": "Sandbox and live. The API key selects the environment."
    }
  ],
  "security": [
    { "bearerAuth": [] },
    { "apiKeyHeader": [] }
  ],
  "tags": [
    { "name": "Referrals", "description": "Create, list and retrieve patient referrals." },
    { "name": "Sessions", "description": "Appointments for your referrals." },
    { "name": "Reports", "description": "Non-clinical progress reports (JSON and PDF)." },
    { "name": "Providers", "description": "Directory of verified physiotherapists." },
    { "name": "Referral links", "description": "No-code referral links and their stats." },
    { "name": "Commercial", "description": "Commercial terms, earnings and the commission ledger." },
    { "name": "Eligibility", "description": "Coming soon. Live returns 501 feature_not_available; sandbox returns a simulated preview." },
    { "name": "Sandbox", "description": "Sandbox-only endpoints. Live keys receive 403 sandbox_only." },
    { "name": "Public", "description": "Unauthenticated, CORS-enabled endpoints used by referral-link landing pages." }
  ],
  "paths": {
    "/partners/referrals": {
      "post": {
        "tags": ["Referrals"],
        "operationId": "createReferral",
        "summary": "Create a referral",
        "description": "Creates a referral with status `received`. In live, Rehabify's care team and Joy (WhatsApp assistant) then contact the patient; give the patient `links.whatsapp_intake_url` so they can start immediately. Status changes are pushed by webhooks. In sandbox, magic phone numbers simulate journeys (`+2348000000004` returns 422 `patient_ineligible`).",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ReferralCreateRequest" },
              "examples": {
                "hmo": {
                  "summary": "HMO referral",
                  "value": {
                    "partner_reference": "HMO-REF-2026-0091",
                    "patient": {
                      "first_name": "Adeola",
                      "last_name": "Balogun",
                      "phone": "+2348012345678",
                      "email": "adeola@example.com",
                      "city": "Lagos",
                      "state": "Lagos",
                      "area": "Ikeja",
                      "preferred_language": "en"
                    },
                    "clinical": {
                      "condition": "Lower back pain",
                      "notes": "L4-L5 disc bulge on MRI. No red flags.",
                      "priority": "standard",
                      "recommended_sessions": 6,
                      "referring_clinician": "Dr. Okafor"
                    },
                    "care": { "preferred_mode": "patient_choice", "preferred_contact_channel": "whatsapp" },
                    "billing_mode": "hmo_direct_billing",
                    "consent": {
                      "granted": true,
                      "method": "electronic",
                      "captured_at": "2026-10-13T09:00:00.000Z",
                      "privacy_notice_version": "2026-09-01"
                    },
                    "metadata": { "member_plan": "gold" }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Referral created. A replayed request (same Idempotency-Key and body) returns the original response with `Idempotent-Replayed: true`.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" },
              "Idempotent-Replayed": { "$ref": "#/components/headers/Idempotent-Replayed" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Referral" },
                "examples": {
                  "created": { "$ref": "#/components/examples/ReferralReceived" }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "409": {
            "description": "`duplicate_partner_reference` (a referral with this partner_reference already exists in this environment; `error.existing` holds its `id` and `tracking_code`) or `idempotency_request_in_progress`.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "examples": {
                  "duplicate_partner_reference": {
                    "value": {
                      "error": {
                        "type": "conflict_error",
                        "code": "duplicate_partner_reference",
                        "message": "A referral with partner_reference HMO-REF-2026-0091 already exists.",
                        "request_id": "req_8a1d4c7e2b9f4a3c8d6e1f0a",
                        "doc_url": "https://docs.physioaroundme.com/getting-started/errors#duplicate_partner_reference",
                        "existing": { "id": "jd7f3k2m9x1q8w4e5r6t7y8u9i0o1p2a", "tracking_code": "RHB-4829173655" }
                      }
                    }
                  },
                  "idempotency_request_in_progress": { "$ref": "#/components/examples/ErrorIdempotencyInProgress" }
                }
              }
            }
          },
          "422": {
            "description": "`validation_error` (`param` set), `consent_required`, `patient_ineligible` (sandbox scenario +2348000000004; no referral created) or `idempotency_key_reused`.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "examples": {
                  "validation_error": { "$ref": "#/components/examples/ErrorValidation" },
                  "consent_required": {
                    "value": {
                      "error": {
                        "type": "invalid_request_error",
                        "code": "consent_required",
                        "message": "consent.granted must be true.",
                        "param": "consent.granted",
                        "request_id": "req_1b2c3d4e5f60718293a4b5c6",
                        "doc_url": "https://docs.physioaroundme.com/getting-started/errors#consent_required"
                      }
                    }
                  },
                  "patient_ineligible": {
                    "value": {
                      "error": {
                        "type": "invalid_request_error",
                        "code": "patient_ineligible",
                        "message": "The patient is not eligible for referral (sandbox scenario).",
                        "request_id": "req_6c5b4a3f2e1d0c9b8a7f6e5d",
                        "doc_url": "https://docs.physioaroundme.com/getting-started/errors#patient_ineligible"
                      }
                    }
                  },
                  "idempotency_key_reused": { "$ref": "#/components/examples/ErrorIdempotencyKeyReused" }
                }
              }
            }
          },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      },
      "get": {
        "tags": ["Referrals"],
        "operationId": "listReferrals",
        "summary": "List referrals",
        "description": "Returns referrals in the API key's environment, newest first.",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" },
          {
            "name": "status",
            "in": "query",
            "description": "Only referrals in this public status.",
            "schema": { "$ref": "#/components/schemas/ReferralStatus" }
          },
          {
            "name": "partner_reference",
            "in": "query",
            "description": "Only the referral with this partner_reference.",
            "schema": { "type": "string", "maxLength": 100 }
          },
          {
            "name": "created_after",
            "in": "query",
            "description": "ISO-8601 timestamp. Only referrals created after this time.",
            "schema": { "type": "string", "format": "date-time" }
          },
          {
            "name": "created_before",
            "in": "query",
            "description": "ISO-8601 timestamp. Only referrals created before this time.",
            "schema": { "type": "string", "format": "date-time" }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of referrals.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ReferralList" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/referrals/{id}": {
      "get": {
        "tags": ["Referrals"],
        "operationId": "getReferral",
        "summary": "Retrieve a referral",
        "description": "`{id}` is the referral `id`, its `tracking_code` (case-insensitive) or your `partner_reference` (URL-encoded). Returns 404 `referral_not_found` when nothing matches in this environment, including referrals that belong to another partner or the other environment.",
        "parameters": [
          { "$ref": "#/components/parameters/ReferralIdentifier" }
        ],
        "responses": {
          "200": {
            "description": "The referral.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Referral" },
                "examples": {
                  "received": { "$ref": "#/components/examples/ReferralReceived" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/ReferralNotFound" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/sessions": {
      "get": {
        "tags": ["Sessions"],
        "operationId": "listSessions",
        "summary": "List sessions",
        "description": "Appointments for your referrals, newest first. Session notes are never returned. This endpoint has no cursor: `next_cursor` is always null; narrow the filters when `has_more` is true. In sandbox, sessions are simulated from the referral's sandbox status (`simulated: true`).",
        "parameters": [
          {
            "name": "referral_id",
            "in": "query",
            "description": "Any referral identifier: `id`, `tracking_code` or `partner_reference`.",
            "schema": { "type": "string" }
          },
          {
            "name": "status",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/SessionStatus" }
          },
          {
            "name": "from",
            "in": "query",
            "description": "ISO-8601 timestamp. Start of the range, applied to `scheduled_start`.",
            "schema": { "type": "string", "format": "date-time" }
          },
          {
            "name": "to",
            "in": "query",
            "description": "ISO-8601 timestamp. End of the range, applied to `scheduled_start`.",
            "schema": { "type": "string", "format": "date-time" }
          },
          { "$ref": "#/components/parameters/Limit" }
        ],
        "responses": {
          "200": {
            "description": "Sessions.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SessionList" },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "session",
                      "id": "k97d4m2x8q1w5e3r7t9y6u0i2o4p6a8s",
                      "referral_id": "jd7f3k2m9x1q8w4e5r6t7y8u9i0o1p2a",
                      "tracking_code": "RHB-4829173655",
                      "partner_reference": "HMO-REF-2026-0091",
                      "sequence": 1,
                      "status": "completed",
                      "mode": "virtual",
                      "scheduled_start": "2026-10-15T10:00:00.000Z",
                      "scheduled_end": "2026-10-15T10:45:00.000Z",
                      "completed_at": "2026-10-15T10:45:00.000Z",
                      "provider": { "name": "Chiamaka Obi" },
                      "simulated": false
                    }
                  ],
                  "has_more": false,
                  "next_cursor": null
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/reports/{id}": {
      "get": {
        "tags": ["Reports"],
        "operationId": "getReport",
        "summary": "Retrieve a progress report",
        "description": "A non-clinical progress report for the referral: provider, session counts and milestones. Never contains clinical notes. `{id}` is any referral identifier.",
        "parameters": [
          { "$ref": "#/components/parameters/ReferralIdentifier" }
        ],
        "responses": {
          "200": {
            "description": "The progress report.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Report" },
                "example": {
                  "object": "report",
                  "referral": {
                    "id": "jd7f3k2m9x1q8w4e5r6t7y8u9i0o1p2a",
                    "tracking_code": "RHB-4829173655",
                    "partner_reference": "HMO-REF-2026-0091",
                    "status": "in_treatment",
                    "environment": "live"
                  },
                  "provider": { "name": "Chiamaka Obi", "license_number": "MRTBN/PT/12345" },
                  "summary": {
                    "prescribed_sessions": 6,
                    "completed_sessions": 2,
                    "upcoming_sessions": 1,
                    "cancelled_sessions": 0,
                    "first_session_at": "2026-10-15T10:00:00.000Z",
                    "last_session_at": "2026-10-18T10:00:00.000Z",
                    "next_session_at": "2026-10-22T10:00:00.000Z",
                    "discharged": false,
                    "discharged_at": null
                  },
                  "milestones": [
                    { "key": "referral_received", "label": "Referral received", "status": "completed", "completed_at": "2026-10-13T09:30:00.000Z" },
                    { "key": "patient_contacted", "label": "Patient contacted", "status": "completed", "completed_at": "2026-10-13T09:32:40.000Z" },
                    { "key": "provider_matched", "label": "Physiotherapist matched", "status": "completed", "completed_at": "2026-10-13T09:34:05.000Z" },
                    { "key": "first_session", "label": "First session attended", "status": "completed", "completed_at": "2026-10-15T10:45:00.000Z" },
                    { "key": "treatment_completed", "label": "Treatment completed", "status": "pending", "completed_at": null }
                  ],
                  "pdf_url": "https://api.physioaroundme.com/v1/partners/reports/RHB-4829173655/pdf",
                  "generated_at": "2026-10-19T08:00:00.000Z"
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/ReferralNotFound" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/reports/{id}/pdf": {
      "get": {
        "tags": ["Reports"],
        "operationId": "getReportPdf",
        "summary": "Download a progress report as PDF",
        "description": "The same report as a PDF document, sent as an attachment. Requires the same API key (server-to-server download).",
        "parameters": [
          { "$ref": "#/components/parameters/ReferralIdentifier" }
        ],
        "responses": {
          "200": {
            "description": "The PDF document.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" },
              "Content-Disposition": {
                "description": "`attachment`, optionally with a filename.",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/pdf": {
                "schema": { "type": "string", "contentMediaType": "application/pdf" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/ReferralNotFound" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/providers": {
      "get": {
        "tags": ["Providers"],
        "operationId": "listProviders",
        "summary": "List verified physiotherapists",
        "description": "Approved physiotherapists who are accepting patients. Unknown values are null (never invented). Single page: no cursor; `next_cursor` is null and `has_more` is true when more providers match than `limit`.",
        "parameters": [
          { "name": "city", "in": "query", "schema": { "type": "string" } },
          { "name": "state", "in": "query", "schema": { "type": "string" } },
          { "name": "specialty", "in": "query", "schema": { "type": "string" } },
          { "name": "mode", "in": "query", "schema": { "$ref": "#/components/schemas/ProviderMode" } },
          { "$ref": "#/components/parameters/Limit" }
        ],
        "responses": {
          "200": {
            "description": "Providers.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ProviderList" },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "provider",
                      "id": "jh6n3b8v1c5x7z9a2s4d6f8g0h1j3k5l",
                      "name": "Chiamaka Obi",
                      "title": "Physiotherapist",
                      "license_number": "MRTBN/PT/12345",
                      "city": "Lagos",
                      "years_of_experience": 7,
                      "rating": 4.8,
                      "review_count": 23,
                      "specializations": ["Sports injury", "Orthopaedics"],
                      "modes": ["virtual", "in_person"]
                    }
                  ],
                  "has_more": true,
                  "next_cursor": null
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/referral-links": {
      "post": {
        "tags": ["Referral links"],
        "operationId": "createReferralLink",
        "summary": "Create a referral link",
        "description": "Creates a no-code referral link (`https://physioaroundme.com/r/<public_code>`). All fields are optional. The link inherits the API key's environment.",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ReferralLinkCreateRequest" },
              "example": {
                "campaign_name": "Staff wellness Q4",
                "service_scope": "all_rehabilitation",
                "default_care_mode": "patient_choice",
                "expires_at": "2027-01-31T23:59:59.000Z"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new referral link.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" },
              "Idempotent-Replayed": { "$ref": "#/components/headers/Idempotent-Replayed" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ReferralLink" },
                "examples": {
                  "created": { "$ref": "#/components/examples/ReferralLinkActive" }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "409": { "$ref": "#/components/responses/IdempotencyInProgress" },
          "422": { "$ref": "#/components/responses/UnprocessableEntity" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      },
      "get": {
        "tags": ["Referral links"],
        "operationId": "listReferralLinks",
        "summary": "List referral links",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" }
        ],
        "responses": {
          "200": {
            "description": "A page of referral links.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ReferralLinkList" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/referral-links/{id}": {
      "patch": {
        "tags": ["Referral links"],
        "operationId": "updateReferralLink",
        "summary": "Activate or deactivate a referral link",
        "description": "An inactive (or expired) link shows an \"unavailable\" page, accepts no leads and does not attribute.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The referral link `id`.",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ReferralLinkUpdateRequest" },
              "example": { "status": "inactive" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated referral link.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ReferralLink" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/ReferralLinkNotFound" },
          "422": { "$ref": "#/components/responses/UnprocessableEntity" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/commercial": {
      "get": {
        "tags": ["Commercial"],
        "operationId": "getCommercialTerms",
        "summary": "Retrieve commercial terms and earnings",
        "description": "If no signed contract exists, `contract.is_default` is true and the platform default partner share applies (`revenue_share_percent` = platform partner percent, currently 10). In sandbox, `earnings` are always zero.",
        "responses": {
          "200": {
            "description": "Commercial terms.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CommercialTerms" },
                "example": {
                  "object": "commercial_terms",
                  "contract": {
                    "contract_number": "CTR-2026-001",
                    "model": "percentage_revenue_share",
                    "revenue_share_percent": 10,
                    "base_fee_per_booking_kobo": null,
                    "withholding_tax_percent": 5,
                    "payment_terms_days": 30,
                    "currency": "NGN",
                    "effective_from": "2026-10-01T00:00:00.000Z",
                    "is_default": false
                  },
                  "earnings": {
                    "earned_kobo": 0,
                    "pending_payout_kobo": 0,
                    "paid_out_kobo": 0,
                    "reversed_kobo": 0,
                    "currency": "NGN"
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/commissions": {
      "get": {
        "tags": ["Commercial"],
        "operationId": "listCommissions",
        "summary": "List commissions",
        "description": "Commission ledger. Live only; sandbox returns an empty list. Commissions are earned only on verified paid bookings by patients attributed to you (API referral, referral link or WhatsApp referral code). Refunds reverse the commission (status `reversed`, or a negative adjustment if already paid out). Paid out monthly to your verified bank account.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/CommissionStatus" }
          },
          {
            "name": "billing_period",
            "in": "query",
            "description": "Month in `YYYY-MM` format.",
            "schema": { "type": "string", "pattern": "^[0-9]{4}-(0[1-9]|1[0-2])$" }
          },
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" }
        ],
        "responses": {
          "200": {
            "description": "A page of commission entries.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CommissionList" },
                "example": {
                  "object": "list",
                  "data": [
                    {
                      "object": "commission",
                      "id": "kd2m4n6b8v0c1x3z5a7s9d2f4g6h8j0k",
                      "referral_id": "jd7f3k2m9x1q8w4e5r6t7y8u9i0o1p2a",
                      "tracking_code": "RHB-4829173655",
                      "event_type": "payment",
                      "gross_amount_kobo": 1500000,
                      "commission_amount_kobo": 150000,
                      "net_payable_kobo": 142500,
                      "currency": "NGN",
                      "status": "approved",
                      "billing_period": "2026-10",
                      "earned_at": "2026-10-15T10:05:00.000Z",
                      "paid_at": null
                    }
                  ],
                  "has_more": false,
                  "next_cursor": null
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/partners/eligibility": {
      "post": {
        "tags": ["Eligibility"],
        "operationId": "checkEligibility",
        "summary": "Check eligibility (coming soon)",
        "description": "COMING SOON. With a live key this returns 501 `feature_not_available`. With a sandbox key it returns a simulated preview: any `member_id` containing `EXPIRED` returns `eligible: false` with `reason: \"policy_inactive\"`.",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/EligibilityCheckRequest" },
              "example": { "member_id": "WH-123", "hmo_code": "wellahealth", "requested_sessions": 6 }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Simulated result (sandbox only).",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EligibilityCheck" },
                "example": {
                  "object": "eligibility_check",
                  "simulated": true,
                  "eligible": true,
                  "member_id": "WH-123",
                  "approved_sessions": 6,
                  "reason": null
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "422": { "$ref": "#/components/responses/UnprocessableEntity" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "501": {
            "description": "`feature_not_available`: eligibility checks are not yet available in live.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": {
                  "error": {
                    "type": "api_error",
                    "code": "feature_not_available",
                    "message": "Eligibility checks are not yet available in live.",
                    "request_id": "req_2c7e9b4a1d6f4e8a9b0c3d5e",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#feature_not_available"
                  }
                }
              }
            }
          },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/sandbox/referrals/{id}/advance": {
      "post": {
        "tags": ["Sandbox"],
        "operationId": "advanceSandboxReferral",
        "summary": "Advance a sandbox referral",
        "description": "Moves a sandbox referral to a new status and fires the same webhooks a real transition fires (`booked` also fires `referral.provider_matched` first if no provider is matched yet). Moving backwards or out of a terminal status returns 422 `invalid_status_transition`. Live keys receive 403 `sandbox_only`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The sandbox referral's `id` or `tracking_code`.",
            "schema": { "type": "string" }
          },
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SandboxAdvanceRequest" },
              "example": { "status": "booked" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated referral.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Referral" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/ReferralNotFound" },
          "422": {
            "description": "`invalid_status_transition` or `validation_error`.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": {
                  "error": {
                    "type": "invalid_request_error",
                    "code": "invalid_status_transition",
                    "message": "Cannot move a referral from completed to contacted.",
                    "param": "status",
                    "request_id": "req_9e8d7c6b5a4f3e2d1c0b9a8f",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#invalid_status_transition"
                  }
                }
              }
            }
          },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/sandbox/trigger-webhook": {
      "post": {
        "tags": ["Sandbox"],
        "operationId": "triggerSandboxWebhook",
        "summary": "Send a test webhook",
        "description": "Queues a test event to your configured SANDBOX webhook endpoint, signed with your SANDBOX secret, in the same format as real events. Allowed types: every event type plus `ping`. Without `referral_id`, a sample sandbox referral is used (`id` `ref_sample_000000000000000000000000`, `tracking_code` `RHB-1234567890`). Test events for referral types carry `data.previous_status: null`, `data.sequence: 0` and `data.test: true`. Returns 409 `webhook_endpoint_not_configured` if no sandbox endpoint is set. Live keys receive 403 `sandbox_only`.",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SandboxTriggerWebhookRequest" },
              "example": { "type": "referral.booked" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The test event was queued.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/WebhookTest" },
                "example": {
                  "object": "webhook_test",
                  "event_id": "evt_01JA4W6X8Y0Z2A4B6C8D0E2F4G",
                  "type": "referral.booked",
                  "status": "queued",
                  "endpoint": "https://example.com/webhooks/rehabify"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/ReferralNotFound" },
          "409": {
            "description": "`webhook_endpoint_not_configured`: no webhook endpoint is configured for this environment.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": {
                  "error": {
                    "type": "conflict_error",
                    "code": "webhook_endpoint_not_configured",
                    "message": "No webhook endpoint is configured for the sandbox environment.",
                    "request_id": "req_4d3c2b1a0f9e8d7c6b5a4f3e",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#webhook_endpoint_not_configured"
                  }
                }
              }
            }
          },
          "422": { "$ref": "#/components/responses/UnprocessableEntity" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/public/referral-links/{public_code}/leads": {
      "post": {
        "tags": ["Public"],
        "operationId": "createLead",
        "summary": "Submit a lead through a referral link",
        "description": "Public, unauthenticated and CORS-enabled. Rate limited per IP address (5 requests per 10 minutes). Creates a referral in the link's environment (fires `referral.created`). `patient.first_name` is required, `patient.phone` or `patient.email` is required, and `consent.granted` must be true. If the same phone was submitted for this partner in the last 24 hours, returns 200 with `duplicate: true` and `tracking_code: null`.",
        "security": [],
        "parameters": [
          {
            "name": "public_code",
            "in": "path",
            "required": true,
            "description": "The referral link's `public_code`.",
            "schema": { "type": "string" },
            "example": "wellah-7KQ2X9MD"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/LeadCreateRequest" },
              "example": {
                "patient": {
                  "first_name": "Ngozi",
                  "last_name": "Eze",
                  "phone": "+2348031234567",
                  "email": "ngozi@example.com",
                  "city": "Abuja",
                  "state": "FCT",
                  "preferred_language": "en"
                },
                "need": { "reason": "knee_injury", "preferred_care_mode": "patient_choice" },
                "contact": { "preferred_channel": "whatsapp" },
                "consent": { "granted": true, "privacy_notice_version": "2026-09-01" }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Lead accepted; a referral was created.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Lead" },
                "example": {
                  "object": "lead",
                  "tracking_code": "RHB-7302918465",
                  "status": "received",
                  "duplicate": false,
                  "tracking_url": "https://physioaroundme.com/track/RHB-7302918465",
                  "whatsapp_intake_url": "https://wa.me/2348061525811?text=START%20RHB-7302918465"
                }
              }
            }
          },
          "200": {
            "description": "Duplicate: the same phone was submitted for this partner in the last 24 hours. No new referral is created.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Lead" },
                "example": {
                  "object": "lead",
                  "tracking_code": null,
                  "status": null,
                  "duplicate": true,
                  "tracking_url": null,
                  "whatsapp_intake_url": null
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "404": { "$ref": "#/components/responses/ReferralLinkNotFound" },
          "410": {
            "description": "`link_inactive`: the link is inactive or expired.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": {
                  "error": {
                    "type": "invalid_request_error",
                    "code": "link_inactive",
                    "message": "This referral link is no longer active.",
                    "request_id": "req_0a1b2c3d4e5f60718293a4b5",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#link_inactive"
                  }
                }
              }
            }
          },
          "422": { "$ref": "#/components/responses/UnprocessableEntity" },
          "429": {
            "description": "`rate_limit_exceeded`: more than 5 requests in 10 minutes from this IP address.",
            "headers": {
              "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
              "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
              "Retry-After": { "$ref": "#/components/headers/Retry-After" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "examples": {
                  "rate_limit_exceeded": { "$ref": "#/components/examples/ErrorRateLimit" }
                }
              }
            }
          },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    }
  },
  "webhooks": {
    "referral.created": {
      "post": {
        "operationId": "webhookReferralCreated",
        "summary": "referral.created",
        "description": "A referral is created (API, referral-link lead, or portal). `data.previous_status` is null.",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "referral.created" }, "data": { "$ref": "#/components/schemas/ReferralEventData" } } }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds. Any other outcome (non-2xx, redirect, timeout, connection error) is retried." }
        }
      }
    },
    "referral.contacted": {
      "post": {
        "operationId": "webhookReferralContacted",
        "summary": "referral.contacted",
        "description": "Patient reached / intake started (incl. patient messaged Joy with the tracking code).",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "referral.contacted" }, "data": { "$ref": "#/components/schemas/ReferralEventData" } } }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds." }
        }
      }
    },
    "referral.provider_matched": {
      "post": {
        "operationId": "webhookReferralProviderMatched",
        "summary": "referral.provider_matched",
        "description": "A physiotherapist was assigned. Matching does not change the status, so `data.previous_status` equals the referral's current status.",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "referral.provider_matched" }, "data": { "$ref": "#/components/schemas/ReferralEventData" } } }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds." }
        }
      }
    },
    "referral.booked": {
      "post": {
        "operationId": "webhookReferralBooked",
        "summary": "referral.booked",
        "description": "First appointment confirmed (payment verified or care covered).",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "referral.booked" }, "data": { "$ref": "#/components/schemas/ReferralEventData" } } }
                ]
              },
              "examples": {
                "booked": { "$ref": "#/components/examples/WebhookReferralBooked" }
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds." }
        }
      }
    },
    "referral.in_treatment": {
      "post": {
        "operationId": "webhookReferralInTreatment",
        "summary": "referral.in_treatment",
        "description": "Treatment under way.",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "referral.in_treatment" }, "data": { "$ref": "#/components/schemas/ReferralEventData" } } }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds." }
        }
      }
    },
    "referral.completed": {
      "post": {
        "operationId": "webhookReferralCompleted",
        "summary": "referral.completed",
        "description": "Care episode completed.",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "referral.completed" }, "data": { "$ref": "#/components/schemas/ReferralEventData" } } }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds." }
        }
      }
    },
    "referral.not_suitable": {
      "post": {
        "operationId": "webhookReferralNotSuitable",
        "summary": "referral.not_suitable",
        "description": "Not appropriate for Rehabify services (patient redirected to appropriate care; no clinical detail disclosed).",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "referral.not_suitable" }, "data": { "$ref": "#/components/schemas/ReferralEventData" } } }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds." }
        }
      }
    },
    "referral.cancelled": {
      "post": {
        "operationId": "webhookReferralCancelled",
        "summary": "referral.cancelled",
        "description": "Cancelled / refunded.",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "referral.cancelled" }, "data": { "$ref": "#/components/schemas/ReferralEventData" } } }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds." }
        }
      }
    },
    "referral.closed": {
      "post": {
        "operationId": "webhookReferralClosed",
        "summary": "referral.closed",
        "description": "Closed (no further activity expected).",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "referral.closed" }, "data": { "$ref": "#/components/schemas/ReferralEventData" } } }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds." }
        }
      }
    },
    "ping": {
      "post": {
        "operationId": "webhookPing",
        "summary": "ping",
        "description": "Test event from the portal or POST /sandbox/trigger-webhook.",
        "security": [],
        "parameters": [
          { "$ref": "#/components/parameters/WebhookSignature" },
          { "$ref": "#/components/parameters/WebhookTimestamp" },
          { "$ref": "#/components/parameters/WebhookEventId" },
          { "$ref": "#/components/parameters/WebhookEventType" },
          { "$ref": "#/components/parameters/WebhookEnvironment" },
          { "$ref": "#/components/parameters/WebhookDeliveryAttempt" },
          { "$ref": "#/components/parameters/WebhookUserAgent" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  { "$ref": "#/components/schemas/WebhookEvent" },
                  { "type": "object", "properties": { "type": { "const": "ping" }, "data": { "$ref": "#/components/schemas/PingEventData" } } }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": { "description": "Acknowledge within 10 seconds." }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Secret API key: `Authorization: Bearer sk_test_…` (sandbox) or `Bearer sk_live_…` (live). Keys are server-side secrets; never use them in browsers or mobile apps."
      },
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Alternative to the Authorization header: `X-API-Key: sk_test_…` or `sk_live_…`."
      }
    },
    "parameters": {
      "Limit": {
        "name": "limit",
        "in": "query",
        "description": "Number of items to return (1–100).",
        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "description": "The `next_cursor` value from the previous page. Opaque.",
        "schema": { "type": "string" }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Unique string (≤255 characters) that makes the request safe to retry. Remembered for 24 hours per environment. Same key + same body replays the original response (`Idempotent-Replayed: true`); same key + different body returns 422 `idempotency_key_reused`; same key while the first request is still processing returns 409 `idempotency_request_in_progress`.",
        "schema": { "type": "string", "minLength": 1, "maxLength": 255 },
        "example": "9b2f6c1e-4d7a-4c3b-8e5f-2a1d0c9b8e7f"
      },
      "ReferralIdentifier": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The referral `id`, its `tracking_code` (case-insensitive), or your `partner_reference` (URL-encoded).",
        "schema": { "type": "string" },
        "example": "RHB-4829173655"
      },
      "WebhookSignature": {
        "name": "X-Rehabify-Signature",
        "in": "header",
        "required": true,
        "description": "`t=<unix seconds>,v1=<hex>` where v1 = hex(HMAC_SHA256(key = signing secret, message = \"<t>.<raw request body>\")). Verify with a constant-time compare and reject if |now − t| > 300 s.",
        "schema": { "type": "string" },
        "example": "t=1791884113,v1=94cb1b4033aa43ffa747a13629a033766fe033d8f82f8c17664ef1bf075dae4c"
      },
      "WebhookTimestamp": {
        "name": "X-Rehabify-Timestamp",
        "in": "header",
        "required": true,
        "description": "Unix seconds.",
        "schema": { "type": "string", "pattern": "^[0-9]+$" }
      },
      "WebhookEventId": {
        "name": "X-Rehabify-Event-Id",
        "in": "header",
        "required": true,
        "description": "The event `id` (`evt_…`), stable across retries. Deduplicate on it.",
        "schema": { "type": "string" }
      },
      "WebhookEventType": {
        "name": "X-Rehabify-Event-Type",
        "in": "header",
        "required": true,
        "schema": { "$ref": "#/components/schemas/WebhookEventType" }
      },
      "WebhookEnvironment": {
        "name": "X-Rehabify-Environment",
        "in": "header",
        "required": true,
        "schema": { "$ref": "#/components/schemas/Environment" }
      },
      "WebhookDeliveryAttempt": {
        "name": "X-Rehabify-Delivery-Attempt",
        "in": "header",
        "required": true,
        "description": "1 for the first attempt, up to 9 for the last retry.",
        "schema": { "type": "integer", "minimum": 1, "maximum": 9 }
      },
      "WebhookUserAgent": {
        "name": "User-Agent",
        "in": "header",
        "required": true,
        "schema": { "type": "string", "const": "Rehabify-Webhooks/1.0" }
      }
    },
    "headers": {
      "X-Request-Id": {
        "description": "Unique request ID. Quote it to support.",
        "schema": { "type": "string", "examples": ["req_5f2c9a1b7d3e4f60a1b2c3d4"] }
      },
      "X-Rehabify-Environment": {
        "description": "The environment that handled the request.",
        "schema": { "$ref": "#/components/schemas/Environment" }
      },
      "X-RateLimit-Limit": {
        "description": "Requests allowed in the current window.",
        "schema": { "type": "integer" }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests remaining in the current window.",
        "schema": { "type": "integer" }
      },
      "X-RateLimit-Reset": {
        "description": "When the window resets, in Unix seconds.",
        "schema": { "type": "integer" }
      },
      "Retry-After": {
        "description": "Seconds to wait before retrying.",
        "schema": { "type": "integer" }
      },
      "Idempotent-Replayed": {
        "description": "Present (`true`) when the response was replayed for a repeated Idempotency-Key.",
        "schema": { "type": "string", "enum": ["true"] }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "`invalid_json` (body is not valid JSON) or `invalid_parameter` (a query parameter is invalid; `param` set).",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "examples": {
              "invalid_json": {
                "value": {
                  "error": {
                    "type": "invalid_request_error",
                    "code": "invalid_json",
                    "message": "Request body is not valid JSON.",
                    "request_id": "req_7a6b5c4d3e2f1a0b9c8d7e6f",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#invalid_json"
                  }
                }
              },
              "invalid_parameter": {
                "value": {
                  "error": {
                    "type": "invalid_request_error",
                    "code": "invalid_parameter",
                    "message": "limit must be an integer between 1 and 100.",
                    "param": "limit",
                    "request_id": "req_3e4f5a6b7c8d9e0f1a2b3c4d",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#invalid_parameter"
                  }
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "`missing_api_key` or `invalid_api_key` (unknown or revoked).",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "examples": {
              "missing_api_key": {
                "value": {
                  "error": {
                    "type": "authentication_error",
                    "code": "missing_api_key",
                    "message": "No API key supplied. Send Authorization: Bearer <key>.",
                    "request_id": "req_5a4b3c2d1e0f9a8b7c6d5e4f",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#missing_api_key"
                  }
                }
              },
              "invalid_api_key": {
                "value": {
                  "error": {
                    "type": "authentication_error",
                    "code": "invalid_api_key",
                    "message": "The API key is unknown or has been revoked.",
                    "request_id": "req_6b5c4d3e2f1a0b9c8d7e6f5a",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#invalid_api_key"
                  }
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "`partner_inactive` (organisation not approved or suspended), `production_access_required` (live key used but production access is not approved) or, on /sandbox endpoints, `sandbox_only` (live key used).",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "examples": {
              "partner_inactive": {
                "value": {
                  "error": {
                    "type": "permission_error",
                    "code": "partner_inactive",
                    "message": "Your organisation is not active.",
                    "request_id": "req_8c7d6e5f4a3b2c1d0e9f8a7b",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#partner_inactive"
                  }
                }
              },
              "production_access_required": {
                "value": {
                  "error": {
                    "type": "permission_error",
                    "code": "production_access_required",
                    "message": "Production access has not been approved for your organisation.",
                    "request_id": "req_9d8e7f6a5b4c3d2e1f0a9b8c",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#production_access_required"
                  }
                }
              },
              "sandbox_only": {
                "value": {
                  "error": {
                    "type": "permission_error",
                    "code": "sandbox_only",
                    "message": "This endpoint is only available with a sandbox (sk_test_) key.",
                    "request_id": "req_0e9f8a7b6c5d4e3f2a1b0c9d",
                    "doc_url": "https://docs.physioaroundme.com/getting-started/errors#sandbox_only"
                  }
                }
              }
            }
          }
        }
      },
      "ReferralNotFound": {
        "description": "`referral_not_found`: no referral with that id / tracking code / partner_reference in this environment.",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": {
              "error": {
                "type": "not_found_error",
                "code": "referral_not_found",
                "message": "No referral found with identifier RHB-0000000000.",
                "request_id": "req_1f0a9b8c7d6e5f4a3b2c1d0e",
                "doc_url": "https://docs.physioaroundme.com/getting-started/errors#referral_not_found"
              }
            }
          }
        }
      },
      "ReferralLinkNotFound": {
        "description": "`referral_link_not_found`: referral link not found.",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": {
              "error": {
                "type": "not_found_error",
                "code": "referral_link_not_found",
                "message": "Referral link not found.",
                "request_id": "req_2a1b0c9d8e7f6a5b4c3d2e1f",
                "doc_url": "https://docs.physioaroundme.com/getting-started/errors#referral_link_not_found"
              }
            }
          }
        }
      },
      "IdempotencyInProgress": {
        "description": "`idempotency_request_in_progress`: a request with the same Idempotency-Key is still processing.",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "examples": {
              "idempotency_request_in_progress": { "$ref": "#/components/examples/ErrorIdempotencyInProgress" }
            }
          }
        }
      },
      "UnprocessableEntity": {
        "description": "`validation_error` (`param` set), `consent_required` or `idempotency_key_reused`.",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "examples": {
              "validation_error": { "$ref": "#/components/examples/ErrorValidation" },
              "idempotency_key_reused": { "$ref": "#/components/examples/ErrorIdempotencyKeyReused" }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "`rate_limit_exceeded`. Wait `Retry-After` seconds, then retry with backoff.",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" },
          "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
          "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
          "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" },
          "Retry-After": { "$ref": "#/components/headers/Retry-After" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "examples": {
              "rate_limit_exceeded": { "$ref": "#/components/examples/ErrorRateLimit" }
            }
          }
        }
      },
      "InternalError": {
        "description": "`internal_error`: unexpected error. Safe to retry with the same Idempotency-Key.",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": {
              "error": {
                "type": "api_error",
                "code": "internal_error",
                "message": "An unexpected error occurred. It is safe to retry with the same Idempotency-Key.",
                "request_id": "req_3b2c1d0e9f8a7b6c5d4e3f2a",
                "doc_url": "https://docs.physioaroundme.com/getting-started/errors#internal_error"
              }
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "`service_unavailable`: temporary outage. Retry with backoff.",
        "headers": {
          "X-Request-Id": { "$ref": "#/components/headers/X-Request-Id" },
          "X-Rehabify-Environment": { "$ref": "#/components/headers/X-Rehabify-Environment" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": {
              "error": {
                "type": "api_error",
                "code": "service_unavailable",
                "message": "The service is temporarily unavailable. Retry with backoff.",
                "request_id": "req_4c3d2e1f0a9b8c7d6e5f4a3b",
                "doc_url": "https://docs.physioaroundme.com/getting-started/errors#service_unavailable"
              }
            }
          }
        }
      }
    },
    "examples": {
      "ReferralReceived": {
        "summary": "A newly created live referral",
        "value": {
          "object": "referral",
          "id": "jd7f3k2m9x1q8w4e5r6t7y8u9i0o1p2a",
          "tracking_code": "RHB-4829173655",
          "partner_reference": "HMO-REF-2026-0091",
          "environment": "live",
          "status": "received",
          "patient": {
            "first_name": "Adeola",
            "last_name": "Balogun",
            "phone": "+2348012345678",
            "email": "adeola@example.com",
            "city": "Lagos",
            "state": "Lagos",
            "area": "Ikeja",
            "preferred_language": "en"
          },
          "clinical": {
            "condition": "Lower back pain",
            "priority": "standard",
            "recommended_sessions": 6,
            "referring_clinician": "Dr. Okafor"
          },
          "care": { "preferred_mode": "patient_choice", "preferred_contact_channel": "whatsapp" },
          "billing_mode": "hmo_direct_billing",
          "provider": null,
          "sessions": { "completed": 0, "total": 6, "last_session_at": null, "next_session_at": null },
          "links": {
            "tracking_url": "https://physioaroundme.com/track/RHB-4829173655",
            "whatsapp_intake_url": "https://wa.me/2348061525811?text=START%20RHB-4829173655"
          },
          "metadata": { "member_plan": "gold" },
          "created_at": "2026-10-13T09:30:00.000Z",
          "updated_at": "2026-10-13T09:30:00.000Z"
        }
      },
      "ReferralLinkActive": {
        "summary": "An active referral link",
        "value": {
          "object": "referral_link",
          "id": "kx1p9o8i7u6y5t4r3e2w1q0a9s8d7f6g",
          "public_code": "wellah-7KQ2X9MD",
          "url": "https://physioaroundme.com/r/wellah-7KQ2X9MD",
          "campaign_name": "Staff wellness Q4",
          "service_scope": "all_rehabilitation",
          "default_care_mode": "patient_choice",
          "status": "active",
          "environment": "live",
          "expires_at": "2027-01-31T23:59:59.000Z",
          "stats": { "clicks": 0, "leads": 0, "signups": 0, "bookings": 0, "payments": 0 },
          "created_at": "2026-10-13T09:30:00.000Z"
        }
      },
      "WebhookReferralBooked": {
        "summary": "referral.booked event",
        "value": {
          "id": "evt_01JA4T7Q9Y2V3W4X5Z6A7B8C9D",
          "object": "event",
          "type": "referral.booked",
          "api_version": "2026-10-01",
          "created_at": "2026-10-13T09:35:12.000Z",
          "environment": "live",
          "data": {
            "previous_status": "contacted",
            "sequence": 4,
            "referral": {
              "object": "referral",
              "id": "jd7f3k2m9x1q8w4e5r6t7y8u9i0o1p2a",
              "tracking_code": "RHB-4829173655",
              "partner_reference": "HMO-REF-2026-0091",
              "environment": "live",
              "status": "booked",
              "clinical": {
                "condition": "Lower back pain",
                "priority": "standard",
                "recommended_sessions": 6,
                "referring_clinician": "Dr. Okafor"
              },
              "care": { "preferred_mode": "patient_choice", "preferred_contact_channel": "whatsapp" },
              "billing_mode": "hmo_direct_billing",
              "provider": { "name": "Chiamaka Obi", "license_number": "MRTBN/PT/12345" },
              "sessions": { "completed": 0, "total": 6, "last_session_at": null, "next_session_at": "2026-10-15T10:00:00.000Z" },
              "links": {
                "tracking_url": "https://physioaroundme.com/track/RHB-4829173655",
                "whatsapp_intake_url": "https://wa.me/2348061525811?text=START%20RHB-4829173655"
              },
              "metadata": { "member_plan": "gold" },
              "created_at": "2026-10-13T09:30:00.000Z",
              "updated_at": "2026-10-13T09:35:12.000Z"
            }
          }
        }
      },
      "ErrorValidation": {
        "summary": "validation_error",
        "value": {
          "error": {
            "type": "invalid_request_error",
            "code": "validation_error",
            "message": "patient.phone must be a valid phone number (E.164, e.g. +2348012345678).",
            "param": "patient.phone",
            "request_id": "req_5f2c9a1b7d3e4f60a1b2c3d4",
            "doc_url": "https://docs.physioaroundme.com/getting-started/errors#validation_error"
          }
        }
      },
      "ErrorIdempotencyKeyReused": {
        "summary": "idempotency_key_reused",
        "value": {
          "error": {
            "type": "invalid_request_error",
            "code": "idempotency_key_reused",
            "message": "This Idempotency-Key was already used with a different request body.",
            "request_id": "req_6a5b4c3d2e1f0a9b8c7d6e5f",
            "doc_url": "https://docs.physioaroundme.com/getting-started/errors#idempotency_key_reused"
          }
        }
      },
      "ErrorIdempotencyInProgress": {
        "summary": "idempotency_request_in_progress",
        "value": {
          "error": {
            "type": "conflict_error",
            "code": "idempotency_request_in_progress",
            "message": "A request with this Idempotency-Key is still being processed.",
            "request_id": "req_7b6c5d4e3f2a1b0c9d8e7f6a",
            "doc_url": "https://docs.physioaroundme.com/getting-started/errors#idempotency_request_in_progress"
          }
        }
      },
      "ErrorRateLimit": {
        "summary": "rate_limit_exceeded",
        "value": {
          "error": {
            "type": "rate_limit_error",
            "code": "rate_limit_exceeded",
            "message": "Too many requests. Retry after the number of seconds in the Retry-After header.",
            "request_id": "req_8c7d6e5f4a3b2c1d0e9f8a7c",
            "doc_url": "https://docs.physioaroundme.com/getting-started/errors#rate_limit_exceeded"
          }
        }
      }
    },
    "schemas": {
      "Environment": {
        "type": "string",
        "enum": ["sandbox", "live"]
      },
      "ReferralStatus": {
        "type": "string",
        "description": "received: Rehabify accepted the referral. contacted: the care team / Joy reached the patient (intake started). booked: first appointment confirmed. in_treatment: rehabilitation sessions under way. completed: care episode completed / discharged. not_suitable: not appropriate for Rehabify services. cancelled: referral or booking cancelled / refunded. closed: no further activity expected.",
        "enum": ["received", "contacted", "booked", "in_treatment", "completed", "not_suitable", "cancelled", "closed"]
      },
      "PreferredLanguage": {
        "type": "string",
        "enum": ["en", "yo", "ig", "ha"]
      },
      "Priority": {
        "type": "string",
        "enum": ["standard", "urgent"]
      },
      "CareMode": {
        "type": "string",
        "enum": ["remote", "in_person", "patient_choice"]
      },
      "ContactChannel": {
        "type": "string",
        "enum": ["whatsapp", "phone", "email", "sms"]
      },
      "BillingMode": {
        "type": "string",
        "enum": ["patient_self_pay", "hmo_direct_billing", "corporate_sponsored"]
      },
      "SessionStatus": {
        "type": "string",
        "enum": ["scheduled", "completed", "cancelled", "no_show"]
      },
      "SessionMode": {
        "type": "string",
        "enum": ["virtual", "in_person"]
      },
      "ProviderMode": {
        "type": "string",
        "enum": ["virtual", "in_person"]
      },
      "MilestoneKey": {
        "type": "string",
        "enum": ["referral_received", "patient_contacted", "provider_matched", "first_session", "treatment_completed"]
      },
      "MilestoneStatus": {
        "type": "string",
        "enum": ["completed", "in_progress", "pending"]
      },
      "ReferralLinkStatus": {
        "type": "string",
        "enum": ["active", "inactive"]
      },
      "CommissionStatus": {
        "type": "string",
        "enum": ["pending", "approved", "paid", "reversed", "cancelled"]
      },
      "ContractModel": {
        "type": "string",
        "enum": ["fixed_per_patient", "percentage_revenue_share", "hybrid", "tiered_volume"]
      },
      "WebhookEventType": {
        "type": "string",
        "enum": [
          "referral.created",
          "referral.contacted",
          "referral.provider_matched",
          "referral.booked",
          "referral.in_treatment",
          "referral.completed",
          "referral.not_suitable",
          "referral.cancelled",
          "referral.closed",
          "ping"
        ]
      },
      "SandboxAdvanceStatus": {
        "type": "string",
        "enum": ["contacted", "booked", "in_treatment", "completed", "not_suitable", "cancelled", "closed"]
      },
      "ErrorType": {
        "type": "string",
        "enum": [
          "invalid_request_error",
          "authentication_error",
          "permission_error",
          "not_found_error",
          "conflict_error",
          "rate_limit_error",
          "api_error"
        ]
      },
      "ErrorCode": {
        "type": "string",
        "enum": [
          "invalid_json",
          "invalid_parameter",
          "missing_api_key",
          "invalid_api_key",
          "partner_inactive",
          "production_access_required",
          "sandbox_only",
          "referral_not_found",
          "referral_link_not_found",
          "resource_not_found",
          "duplicate_partner_reference",
          "idempotency_request_in_progress",
          "webhook_endpoint_not_configured",
          "link_inactive",
          "validation_error",
          "consent_required",
          "patient_ineligible",
          "idempotency_key_reused",
          "invalid_status_transition",
          "rate_limit_exceeded",
          "internal_error",
          "feature_not_available",
          "service_unavailable"
        ]
      },
      "Timestamp": {
        "type": "string",
        "format": "date-time",
        "description": "ISO-8601 UTC timestamp.",
        "examples": ["2026-10-13T09:30:00.000Z"]
      },
      "NullableTimestamp": {
        "type": ["string", "null"],
        "format": "date-time",
        "description": "ISO-8601 UTC timestamp, or null."
      },
      "TrackingCode": {
        "type": "string",
        "description": "`RHB-` followed by 10 digits (older referrals: `RHB-` followed by 5 digits). Case-insensitive.",
        "pattern": "^[Rr][Hh][Bb]-([0-9]{10}|[0-9]{5})$",
        "examples": ["RHB-4829173655"]
      },
      "Metadata": {
        "type": "object",
        "description": "Up to 20 keys (≤40 characters) with string values (≤500 characters). Echoed back on the referral and in webhooks. Do not put personal or clinical data here.",
        "maxProperties": 20,
        "propertyNames": { "type": "string", "maxLength": 40 },
        "additionalProperties": { "type": "string", "maxLength": 500 }
      },
      "ReferralPatient": {
        "type": "object",
        "description": "Patient contact details as stored. Never included in webhooks.",
        "required": ["first_name", "last_name", "phone", "email", "city", "state", "area", "preferred_language"],
        "properties": {
          "first_name": { "type": "string" },
          "last_name": { "type": ["string", "null"] },
          "phone": { "type": "string", "description": "E.164.", "examples": ["+2348012345678"] },
          "email": { "type": ["string", "null"], "format": "email" },
          "city": { "type": ["string", "null"] },
          "state": { "type": ["string", "null"] },
          "area": { "type": ["string", "null"] },
          "preferred_language": {
            "anyOf": [
              { "$ref": "#/components/schemas/PreferredLanguage" },
              { "type": "null" }
            ]
          }
        }
      },
      "ReferralClinical": {
        "type": "object",
        "description": "Clinical summary. `clinical.notes` is write-only and never returned.",
        "required": ["condition", "priority", "recommended_sessions", "referring_clinician"],
        "properties": {
          "condition": { "type": ["string", "null"] },
          "priority": { "$ref": "#/components/schemas/Priority" },
          "recommended_sessions": { "type": "integer", "minimum": 1, "maximum": 52 },
          "referring_clinician": { "type": ["string", "null"] }
        }
      },
      "ReferralCare": {
        "type": "object",
        "required": ["preferred_mode", "preferred_contact_channel"],
        "properties": {
          "preferred_mode": { "$ref": "#/components/schemas/CareMode" },
          "preferred_contact_channel": { "$ref": "#/components/schemas/ContactChannel" }
        }
      },
      "ReferralProvider": {
        "type": "object",
        "description": "The matched physiotherapist. In sandbox: `{ \"name\": \"Sandbox Physiotherapist\", \"license_number\": \"SANDBOX-0001\" }`.",
        "required": ["name", "license_number"],
        "properties": {
          "name": { "type": "string", "examples": ["Chiamaka Obi"] },
          "license_number": { "type": ["string", "null"], "examples": ["MRTBN/PT/12345"] }
        }
      },
      "ReferralSessionSummary": {
        "type": "object",
        "required": ["completed", "total", "last_session_at", "next_session_at"],
        "properties": {
          "completed": { "type": "integer", "minimum": 0, "description": "Sessions attended." },
          "total": { "type": "integer", "minimum": 0, "description": "Sessions prescribed." },
          "last_session_at": { "$ref": "#/components/schemas/NullableTimestamp" },
          "next_session_at": { "$ref": "#/components/schemas/NullableTimestamp" }
        }
      },
      "ReferralTrackingLinks": {
        "type": "object",
        "required": ["tracking_url", "whatsapp_intake_url"],
        "properties": {
          "tracking_url": {
            "type": "string",
            "format": "uri",
            "description": "Public status page (status timeline only; no personal or clinical data).",
            "examples": ["https://physioaroundme.com/track/RHB-4829173655"]
          },
          "whatsapp_intake_url": {
            "type": "string",
            "format": "uri",
            "description": "Opens WhatsApp with Joy, pre-filled with `START <tracking_code>`.",
            "examples": ["https://wa.me/2348061525811?text=START%20RHB-4829173655"]
          }
        }
      },
      "Referral": {
        "type": "object",
        "required": [
          "object", "id", "tracking_code", "partner_reference", "environment", "status", "patient", "clinical",
          "care", "billing_mode", "provider", "sessions", "links", "metadata", "created_at", "updated_at"
        ],
        "properties": {
          "object": { "type": "string", "const": "referral" },
          "id": { "type": "string", "examples": ["jd7f3k2m9x1q8w4e5r6t7y8u9i0o1p2a"] },
          "tracking_code": { "$ref": "#/components/schemas/TrackingCode" },
          "partner_reference": { "type": ["string", "null"], "maxLength": 100 },
          "environment": { "$ref": "#/components/schemas/Environment" },
          "status": { "$ref": "#/components/schemas/ReferralStatus" },
          "patient": { "$ref": "#/components/schemas/ReferralPatient" },
          "clinical": { "$ref": "#/components/schemas/ReferralClinical" },
          "care": { "$ref": "#/components/schemas/ReferralCare" },
          "billing_mode": { "$ref": "#/components/schemas/BillingMode" },
          "provider": {
            "anyOf": [
              { "$ref": "#/components/schemas/ReferralProvider" },
              { "type": "null" }
            ]
          },
          "sessions": { "$ref": "#/components/schemas/ReferralSessionSummary" },
          "links": { "$ref": "#/components/schemas/ReferralTrackingLinks" },
          "metadata": {
            "anyOf": [
              { "$ref": "#/components/schemas/Metadata" },
              { "type": "null" }
            ]
          },
          "created_at": { "$ref": "#/components/schemas/Timestamp" },
          "updated_at": { "$ref": "#/components/schemas/Timestamp" }
        }
      },
      "WebhookReferral": {
        "type": "object",
        "description": "The Referral object WITHOUT the `patient` block. Patient personal data is never sent in webhooks.",
        "required": [
          "object", "id", "tracking_code", "partner_reference", "environment", "status", "clinical",
          "care", "billing_mode", "provider", "sessions", "links", "metadata", "created_at", "updated_at"
        ],
        "properties": {
          "object": { "type": "string", "const": "referral" },
          "id": { "type": "string" },
          "tracking_code": { "$ref": "#/components/schemas/TrackingCode" },
          "partner_reference": { "type": ["string", "null"] },
          "environment": { "$ref": "#/components/schemas/Environment" },
          "status": { "$ref": "#/components/schemas/ReferralStatus" },
          "clinical": { "$ref": "#/components/schemas/ReferralClinical" },
          "care": { "$ref": "#/components/schemas/ReferralCare" },
          "billing_mode": { "$ref": "#/components/schemas/BillingMode" },
          "provider": {
            "anyOf": [
              { "$ref": "#/components/schemas/ReferralProvider" },
              { "type": "null" }
            ]
          },
          "sessions": { "$ref": "#/components/schemas/ReferralSessionSummary" },
          "links": { "$ref": "#/components/schemas/ReferralTrackingLinks" },
          "metadata": {
            "anyOf": [
              { "$ref": "#/components/schemas/Metadata" },
              { "type": "null" }
            ]
          },
          "created_at": { "$ref": "#/components/schemas/Timestamp" },
          "updated_at": { "$ref": "#/components/schemas/Timestamp" }
        }
      },
      "ReferralCreateRequest": {
        "type": "object",
        "description": "Unknown fields are ignored.",
        "required": ["patient", "consent"],
        "properties": {
          "partner_reference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Your own reference. Unique per partner per environment (409 duplicate_partner_reference)."
          },
          "patient": {
            "type": "object",
            "required": ["first_name", "phone"],
            "properties": {
              "first_name": { "type": "string", "minLength": 1, "maxLength": 100 },
              "last_name": { "type": "string", "maxLength": 100 },
              "phone": {
                "type": "string",
                "description": "E.164 (`+2348012345678`) or Nigerian local (`08012345678`, `2348012345678`). Stored and returned as E.164.",
                "examples": ["+2348012345678"]
              },
              "email": { "type": "string", "format": "email" },
              "city": { "type": "string", "maxLength": 100 },
              "state": { "type": "string", "maxLength": 100 },
              "area": { "type": "string", "maxLength": 100 },
              "preferred_language": { "$ref": "#/components/schemas/PreferredLanguage" }
            }
          },
          "clinical": {
            "type": "object",
            "properties": {
              "condition": { "type": "string", "maxLength": 200 },
              "notes": {
                "type": "string",
                "maxLength": 5000,
                "writeOnly": true,
                "description": "Write-only: stored for Rehabify clinicians, never returned by the API or webhooks."
              },
              "priority": { "$ref": "#/components/schemas/Priority", "default": "standard" },
              "recommended_sessions": { "type": "integer", "minimum": 1, "maximum": 52, "default": 4 },
              "referring_clinician": { "type": "string", "maxLength": 200 }
            }
          },
          "care": {
            "type": "object",
            "properties": {
              "preferred_mode": { "$ref": "#/components/schemas/CareMode", "default": "patient_choice" },
              "preferred_contact_channel": { "$ref": "#/components/schemas/ContactChannel", "default": "whatsapp" }
            }
          },
          "billing_mode": { "$ref": "#/components/schemas/BillingMode", "default": "patient_self_pay" },
          "consent": {
            "type": "object",
            "description": "Required. `granted` must be `true` (the partner attests the patient agreed to be contacted by Rehabify); otherwise 422 consent_required.",
            "required": ["granted"],
            "properties": {
              "granted": { "type": "boolean", "const": true },
              "method": { "type": "string", "maxLength": 50, "examples": ["electronic"] },
              "captured_at": { "type": "string", "format": "date-time" },
              "privacy_notice_version": { "type": "string", "maxLength": 50 }
            }
          },
          "metadata": { "$ref": "#/components/schemas/Metadata" }
        }
      },
      "ReferralList": {
        "type": "object",
        "required": ["object", "data", "has_more", "next_cursor"],
        "properties": {
          "object": { "type": "string", "const": "list" },
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Referral" } },
          "has_more": { "type": "boolean" },
          "next_cursor": { "type": ["string", "null"] }
        }
      },
      "Session": {
        "type": "object",
        "description": "One appointment. Session notes are never returned.",
        "required": [
          "object", "id", "referral_id", "tracking_code", "partner_reference", "sequence", "status", "mode",
          "scheduled_start", "scheduled_end", "completed_at", "provider", "simulated"
        ],
        "properties": {
          "object": { "type": "string", "const": "session" },
          "id": { "type": "string" },
          "referral_id": { "type": "string", "description": "The referral's `id`." },
          "tracking_code": { "$ref": "#/components/schemas/TrackingCode" },
          "partner_reference": { "type": ["string", "null"] },
          "sequence": { "type": "integer", "minimum": 1 },
          "status": { "$ref": "#/components/schemas/SessionStatus" },
          "mode": { "$ref": "#/components/schemas/SessionMode" },
          "scheduled_start": { "$ref": "#/components/schemas/Timestamp" },
          "scheduled_end": { "$ref": "#/components/schemas/Timestamp" },
          "completed_at": { "$ref": "#/components/schemas/NullableTimestamp" },
          "provider": {
            "anyOf": [
              {
                "type": "object",
                "required": ["name"],
                "properties": { "name": { "type": "string" } }
              },
              { "type": "null" }
            ]
          },
          "simulated": { "type": "boolean", "description": "true for sandbox sessions." }
        }
      },
      "SessionList": {
        "type": "object",
        "required": ["object", "data", "has_more", "next_cursor"],
        "properties": {
          "object": { "type": "string", "const": "list" },
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Session" } },
          "has_more": { "type": "boolean" },
          "next_cursor": { "type": "null", "description": "Always null: this endpoint has no cursor." }
        }
      },
      "ReportMilestone": {
        "type": "object",
        "required": ["key", "label", "status", "completed_at"],
        "properties": {
          "key": { "$ref": "#/components/schemas/MilestoneKey" },
          "label": { "type": "string" },
          "status": { "$ref": "#/components/schemas/MilestoneStatus" },
          "completed_at": { "$ref": "#/components/schemas/NullableTimestamp" }
        }
      },
      "Report": {
        "type": "object",
        "description": "Non-clinical progress report. Never contains clinical notes.",
        "required": ["object", "referral", "provider", "summary", "milestones", "pdf_url", "generated_at"],
        "properties": {
          "object": { "type": "string", "const": "report" },
          "referral": {
            "type": "object",
            "required": ["id", "tracking_code", "partner_reference", "status", "environment"],
            "properties": {
              "id": { "type": "string" },
              "tracking_code": { "$ref": "#/components/schemas/TrackingCode" },
              "partner_reference": { "type": ["string", "null"] },
              "status": { "$ref": "#/components/schemas/ReferralStatus" },
              "environment": { "$ref": "#/components/schemas/Environment" }
            }
          },
          "provider": {
            "anyOf": [
              { "$ref": "#/components/schemas/ReferralProvider" },
              { "type": "null" }
            ]
          },
          "summary": {
            "type": "object",
            "required": [
              "prescribed_sessions", "completed_sessions", "upcoming_sessions", "cancelled_sessions",
              "first_session_at", "last_session_at", "next_session_at", "discharged", "discharged_at"
            ],
            "properties": {
              "prescribed_sessions": { "type": "integer", "minimum": 0 },
              "completed_sessions": { "type": "integer", "minimum": 0 },
              "upcoming_sessions": { "type": "integer", "minimum": 0 },
              "cancelled_sessions": { "type": "integer", "minimum": 0 },
              "first_session_at": { "$ref": "#/components/schemas/NullableTimestamp" },
              "last_session_at": { "$ref": "#/components/schemas/NullableTimestamp" },
              "next_session_at": { "$ref": "#/components/schemas/NullableTimestamp" },
              "discharged": { "type": "boolean" },
              "discharged_at": { "$ref": "#/components/schemas/NullableTimestamp" }
            }
          },
          "milestones": { "type": "array", "items": { "$ref": "#/components/schemas/ReportMilestone" } },
          "pdf_url": {
            "type": "string",
            "format": "uri",
            "description": "PDF download; requires your API key.",
            "examples": ["https://api.physioaroundme.com/v1/partners/reports/RHB-4829173655/pdf"]
          },
          "generated_at": { "$ref": "#/components/schemas/Timestamp" }
        }
      },
      "Provider": {
        "type": "object",
        "description": "A verified physiotherapist. Unknown values are null (never invented).",
        "required": [
          "object", "id", "name", "title", "license_number", "city", "years_of_experience", "rating",
          "review_count", "specializations", "modes"
        ],
        "properties": {
          "object": { "type": "string", "const": "provider" },
          "id": { "type": "string" },
          "name": { "type": "string" },
          "title": { "type": ["string", "null"] },
          "license_number": { "type": ["string", "null"] },
          "city": { "type": ["string", "null"] },
          "years_of_experience": { "type": ["integer", "null"] },
          "rating": { "type": ["number", "null"] },
          "review_count": { "type": ["integer", "null"] },
          "specializations": { "type": "array", "items": { "type": "string" } },
          "modes": { "type": "array", "items": { "$ref": "#/components/schemas/ProviderMode" } }
        }
      },
      "ProviderList": {
        "type": "object",
        "required": ["object", "data", "has_more", "next_cursor"],
        "properties": {
          "object": { "type": "string", "const": "list" },
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Provider" } },
          "has_more": { "type": "boolean", "description": "true when more providers match than `limit`." },
          "next_cursor": { "type": "null", "description": "Always null: this endpoint has no cursor." }
        }
      },
      "ReferralLinkStats": {
        "type": "object",
        "required": ["clicks", "leads", "signups", "bookings", "payments"],
        "properties": {
          "clicks": { "type": "integer", "minimum": 0, "description": "Unique visitors, de-duplicated per visitor per 30 minutes, bots excluded." },
          "leads": { "type": "integer", "minimum": 0, "description": "Landing-page forms submitted." },
          "signups": { "type": "integer", "minimum": 0, "description": "Accounts attributed." },
          "bookings": { "type": "integer", "minimum": 0, "description": "Bookings created by attributed patients." },
          "payments": { "type": "integer", "minimum": 0, "description": "Paid bookings." }
        }
      },
      "ReferralLink": {
        "type": "object",
        "required": [
          "object", "id", "public_code", "url", "campaign_name", "service_scope", "default_care_mode",
          "status", "environment", "expires_at", "stats", "created_at"
        ],
        "properties": {
          "object": { "type": "string", "const": "referral_link" },
          "id": { "type": "string" },
          "public_code": { "type": "string", "examples": ["wellah-7KQ2X9MD"] },
          "url": { "type": "string", "format": "uri", "examples": ["https://physioaroundme.com/r/wellah-7KQ2X9MD"] },
          "campaign_name": { "type": ["string", "null"] },
          "service_scope": { "type": "string", "examples": ["all_rehabilitation"] },
          "default_care_mode": { "$ref": "#/components/schemas/CareMode" },
          "status": { "$ref": "#/components/schemas/ReferralLinkStatus" },
          "environment": { "$ref": "#/components/schemas/Environment" },
          "expires_at": { "$ref": "#/components/schemas/NullableTimestamp" },
          "stats": { "$ref": "#/components/schemas/ReferralLinkStats" },
          "created_at": { "$ref": "#/components/schemas/Timestamp" }
        }
      },
      "ReferralLinkCreateRequest": {
        "type": "object",
        "description": "All fields optional. The link inherits the API key's environment.",
        "properties": {
          "campaign_name": { "type": "string" },
          "service_scope": { "type": "string", "examples": ["all_rehabilitation"] },
          "default_care_mode": { "$ref": "#/components/schemas/CareMode" },
          "expires_at": { "type": "string", "format": "date-time" }
        }
      },
      "ReferralLinkUpdateRequest": {
        "type": "object",
        "required": ["status"],
        "properties": {
          "status": { "$ref": "#/components/schemas/ReferralLinkStatus" }
        }
      },
      "ReferralLinkList": {
        "type": "object",
        "required": ["object", "data", "has_more", "next_cursor"],
        "properties": {
          "object": { "type": "string", "const": "list" },
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/ReferralLink" } },
          "has_more": { "type": "boolean" },
          "next_cursor": { "type": ["string", "null"] }
        }
      },
      "CommercialTerms": {
        "type": "object",
        "required": ["object", "contract", "earnings"],
        "properties": {
          "object": { "type": "string", "const": "commercial_terms" },
          "contract": {
            "type": "object",
            "required": [
              "contract_number", "model", "revenue_share_percent", "base_fee_per_booking_kobo",
              "withholding_tax_percent", "payment_terms_days", "currency", "effective_from", "is_default"
            ],
            "properties": {
              "contract_number": { "type": ["string", "null"] },
              "model": { "$ref": "#/components/schemas/ContractModel" },
              "revenue_share_percent": { "type": ["number", "null"] },
              "base_fee_per_booking_kobo": { "type": ["integer", "null"] },
              "withholding_tax_percent": { "type": ["number", "null"] },
              "payment_terms_days": { "type": ["integer", "null"] },
              "currency": { "type": "string", "const": "NGN" },
              "effective_from": { "$ref": "#/components/schemas/NullableTimestamp" },
              "is_default": {
                "type": "boolean",
                "description": "true when no signed contract exists and the platform default partner share applies (currently 10%)."
              }
            }
          },
          "earnings": {
            "type": "object",
            "description": "Always zero in sandbox.",
            "required": ["earned_kobo", "pending_payout_kobo", "paid_out_kobo", "reversed_kobo", "currency"],
            "properties": {
              "earned_kobo": { "type": "integer" },
              "pending_payout_kobo": { "type": "integer" },
              "paid_out_kobo": { "type": "integer" },
              "reversed_kobo": { "type": "integer" },
              "currency": { "type": "string", "const": "NGN" }
            }
          }
        }
      },
      "Commission": {
        "type": "object",
        "required": [
          "object", "id", "referral_id", "tracking_code", "event_type", "gross_amount_kobo",
          "commission_amount_kobo", "net_payable_kobo", "currency", "status", "billing_period", "earned_at", "paid_at"
        ],
        "properties": {
          "object": { "type": "string", "const": "commission" },
          "id": { "type": "string" },
          "referral_id": { "type": "string" },
          "tracking_code": { "$ref": "#/components/schemas/TrackingCode" },
          "event_type": { "type": "string", "examples": ["payment"] },
          "gross_amount_kobo": { "type": "integer" },
          "commission_amount_kobo": { "type": "integer" },
          "net_payable_kobo": { "type": "integer", "description": "Commission after withholding tax." },
          "currency": { "type": "string", "const": "NGN" },
          "status": { "$ref": "#/components/schemas/CommissionStatus" },
          "billing_period": { "type": "string", "pattern": "^[0-9]{4}-(0[1-9]|1[0-2])$", "examples": ["2026-10"] },
          "earned_at": { "$ref": "#/components/schemas/Timestamp" },
          "paid_at": { "$ref": "#/components/schemas/NullableTimestamp" }
        }
      },
      "CommissionList": {
        "type": "object",
        "required": ["object", "data", "has_more", "next_cursor"],
        "properties": {
          "object": { "type": "string", "const": "list" },
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Commission" } },
          "has_more": { "type": "boolean" },
          "next_cursor": { "type": ["string", "null"] }
        }
      },
      "EligibilityCheckRequest": {
        "type": "object",
        "required": ["member_id"],
        "properties": {
          "member_id": { "type": "string", "examples": ["WH-123"] },
          "hmo_code": { "type": "string", "examples": ["wellahealth"] },
          "requested_sessions": { "type": "integer", "minimum": 1, "examples": [6] }
        }
      },
      "EligibilityCheck": {
        "type": "object",
        "description": "Simulated sandbox preview. Live returns 501 feature_not_available.",
        "required": ["object", "simulated", "eligible", "member_id", "approved_sessions", "reason"],
        "properties": {
          "object": { "type": "string", "const": "eligibility_check" },
          "simulated": { "type": "boolean", "const": true },
          "eligible": { "type": "boolean" },
          "member_id": { "type": "string" },
          "approved_sessions": { "type": "integer", "minimum": 0 },
          "reason": {
            "type": ["string", "null"],
            "description": "`policy_inactive` when not eligible; null otherwise.",
            "examples": ["policy_inactive"]
          }
        }
      },
      "SandboxAdvanceRequest": {
        "type": "object",
        "required": ["status"],
        "properties": {
          "status": { "$ref": "#/components/schemas/SandboxAdvanceStatus" }
        }
      },
      "SandboxTriggerWebhookRequest": {
        "type": "object",
        "required": ["type"],
        "properties": {
          "type": { "$ref": "#/components/schemas/WebhookEventType" },
          "referral_id": {
            "type": "string",
            "description": "Optional sandbox referral `id` or `tracking_code`. Without it, a sample sandbox referral is used."
          }
        }
      },
      "WebhookTest": {
        "type": "object",
        "required": ["object", "event_id", "type", "status", "endpoint"],
        "properties": {
          "object": { "type": "string", "const": "webhook_test" },
          "event_id": { "type": "string", "examples": ["evt_01JA4W6X8Y0Z2A4B6C8D0E2F4G"] },
          "type": { "$ref": "#/components/schemas/WebhookEventType" },
          "status": { "type": "string", "const": "queued" },
          "endpoint": { "type": "string", "format": "uri", "description": "Your configured sandbox endpoint." }
        }
      },
      "LeadCreateRequest": {
        "type": "object",
        "required": ["patient", "consent"],
        "properties": {
          "patient": {
            "type": "object",
            "description": "`first_name` is required, and at least one of `phone` or `email`.",
            "required": ["first_name"],
            "anyOf": [
              { "required": ["phone"] },
              { "required": ["email"] }
            ],
            "properties": {
              "first_name": { "type": "string", "minLength": 1 },
              "last_name": { "type": "string" },
              "phone": { "type": "string" },
              "email": { "type": "string", "format": "email" },
              "city": { "type": "string" },
              "state": { "type": "string" },
              "preferred_language": { "$ref": "#/components/schemas/PreferredLanguage" }
            }
          },
          "need": {
            "type": "object",
            "properties": {
              "reason": { "type": "string", "examples": ["knee_injury"] },
              "preferred_care_mode": { "$ref": "#/components/schemas/CareMode" }
            }
          },
          "contact": {
            "type": "object",
            "properties": {
              "preferred_channel": { "$ref": "#/components/schemas/ContactChannel" }
            }
          },
          "consent": {
            "type": "object",
            "required": ["granted"],
            "properties": {
              "granted": { "type": "boolean", "const": true },
              "privacy_notice_version": { "type": "string" }
            }
          }
        }
      },
      "Lead": {
        "type": "object",
        "required": ["object", "tracking_code", "status", "duplicate", "tracking_url", "whatsapp_intake_url"],
        "properties": {
          "object": { "type": "string", "const": "lead" },
          "tracking_code": {
            "anyOf": [
              { "$ref": "#/components/schemas/TrackingCode" },
              { "type": "null" }
            ],
            "description": "null when `duplicate` is true."
          },
          "status": {
            "anyOf": [
              { "type": "string", "const": "received" },
              { "type": "null" }
            ]
          },
          "duplicate": { "type": "boolean" },
          "tracking_url": { "type": ["string", "null"], "format": "uri" },
          "whatsapp_intake_url": { "type": ["string", "null"], "format": "uri" }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["type", "code", "message", "request_id", "doc_url"],
            "properties": {
              "type": { "$ref": "#/components/schemas/ErrorType" },
              "code": { "$ref": "#/components/schemas/ErrorCode" },
              "message": { "type": "string", "description": "Human-readable; may change. Branch on `code`." },
              "param": { "type": "string", "description": "Present only when a specific field is at fault." },
              "request_id": { "type": "string", "examples": ["req_5f2c9a1b7d3e4f60a1b2c3d4"] },
              "doc_url": {
                "type": "string",
                "format": "uri",
                "examples": ["https://docs.physioaroundme.com/getting-started/errors#validation_error"]
              },
              "existing": {
                "type": "object",
                "description": "Only on duplicate_partner_reference: the referral that already exists.",
                "required": ["id", "tracking_code"],
                "properties": {
                  "id": { "type": "string" },
                  "tracking_code": { "$ref": "#/components/schemas/TrackingCode" }
                }
              }
            }
          }
        }
      },
      "ReferralEventData": {
        "type": "object",
        "required": ["previous_status", "sequence", "referral"],
        "properties": {
          "previous_status": {
            "description": "Status before this event; null for referral.created and for test events. For referral.provider_matched it equals the current status.",
            "anyOf": [
              { "$ref": "#/components/schemas/ReferralStatus" },
              { "type": "null" }
            ]
          },
          "sequence": {
            "type": "integer",
            "minimum": 0,
            "description": "Increases by 1 for every event of the same referral. 0 for test events."
          },
          "test": {
            "type": "boolean",
            "const": true,
            "description": "Present (true) only on test events sent from the portal or POST /sandbox/trigger-webhook."
          },
          "referral": { "$ref": "#/components/schemas/WebhookReferral" }
        }
      },
      "PingEventData": {
        "type": "object",
        "required": ["message", "referral"],
        "properties": {
          "message": { "type": "string", "examples": ["Test event from Rehabify"] },
          "referral": { "$ref": "#/components/schemas/WebhookReferral" }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "description": "Event envelope. The request body is exactly what is signed (X-Rehabify-Signature).",
        "required": ["id", "object", "type", "api_version", "created_at", "environment", "data"],
        "properties": {
          "id": { "type": "string", "description": "Event id (`evt_…`), stable across retries.", "examples": ["evt_01JA4T7Q9Y2V3W4X5Z6A7B8C9D"] },
          "object": { "type": "string", "const": "event" },
          "type": { "$ref": "#/components/schemas/WebhookEventType" },
          "api_version": { "type": "string", "examples": ["2026-10-01"] },
          "created_at": { "$ref": "#/components/schemas/Timestamp" },
          "environment": { "$ref": "#/components/schemas/Environment" },
          "data": {
            "oneOf": [
              { "$ref": "#/components/schemas/ReferralEventData" },
              { "$ref": "#/components/schemas/PingEventData" }
            ]
          }
        }
      }
    }
  }
}
