{
  "openapi": "3.1.0",
  "info": {
    "title": "Dawilo Partner API",
    "version": "1.1.0",
    "description": "Additive server-to-server API. Existing read scopes are unchanged. Write scopes default off and require explicit per-key establishment connections for live data. 120 requests/minute per key, 5000/minute globally. Sandbox/live credentials and mutation state are isolated. Clinical writes use Idempotency-Key and current revisions. Signed webhooks use an encrypted per-key secret. See docs/PARTNER-API.md."
  },
  "servers": [
    {
      "url": "https://dawilo.com",
      "description": "Use the configured Dawilo origin for self-hosted staging."
    }
  ],
  "security": [
    {
      "BearerKey": []
    }
  ],
  "paths": {
    "/api/partner/v1/practices": {
      "get": {
        "operationId": "listPractices",
        "summary": "List public practices and active practitioners",
        "description": "Requires directory:read. Ordered by stable practice ID; offset results may shift if public listings change.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            },
            "description": ""
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100000,
              "default": 0
            },
            "description": ""
          },
          {
            "name": "wilaya",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{2,3}$"
            },
            "description": ""
          },
          {
            "name": "specialty",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{1,60}$"
            },
            "description": ""
          }
        ],
        "responses": {
          "200": {
            "description": "Success; no patient records or prescription data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PracticesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid, duplicate or unknown parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Key inactive or required scope absent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Public practice or practitioner unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "API disabled by Dawilo, or temporary service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/partner/v1/availability": {
      "get": {
        "operationId": "getAvailability",
        "summary": "Read available times and booking links",
        "description": "Requires availability:read. Dates from today through today + 90 days in Africa/Algiers. Availability is indicative; booking conflicts are checked in the Dawilo request flow.",
        "parameters": [
          {
            "name": "practice_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": ""
          },
          {
            "name": "practitioner_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[-a-z0-9]{3,60}$"
            },
            "description": ""
          },
          {
            "name": "date",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": ""
          }
        ],
        "responses": {
          "200": {
            "description": "Success; no patient records or prescription data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AvailabilityResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid, duplicate or unknown parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Key inactive or required scope absent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Public practice or practitioner unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "API disabled by Dawilo, or temporary service failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/partner/v1/appointments": {
      "post": {
        "summary": "Create a connected practice booking",
        "description": "",
        "x-required-scopes": [
          "appointments:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppointmentWriteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppointmentCreate"
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_.:-]{8,100}$"
            },
            "description": "Reuse the exact payload/key after a lost response. A new logical operation uses a new key."
          }
        ]
      },
      "patch": {
        "summary": "Update a connected practice booking",
        "description": "",
        "x-required-scopes": [
          "appointments:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppointmentWriteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppointmentUpdate"
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_.:-]{8,100}$"
            },
            "description": "Reuse the exact payload/key after a lost response. A new logical operation uses a new key."
          }
        ]
      },
      "get": {
        "summary": "Get minimal booking metadata and current revision",
        "description": "",
        "x-required-scopes": [
          "appointments:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppointmentWriteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "query",
            "name": "practice_id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "in": "query",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/api/partner/v1/prescriptions": {
      "patch": {
        "summary": "Record one-time dispensing",
        "description": "",
        "x-required-scopes": [
          "prescriptions:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClinicalWriteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrescriptionDispense"
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_.:-]{8,100}$"
            },
            "description": "Reuse the exact payload/key after a lost response. A new logical operation uses a new key."
          }
        ]
      }
    },
    "/api/partner/v1/prescriptions/lookup": {
      "post": {
        "summary": "Read the QR-authorized structured prescription",
        "description": "",
        "x-required-scopes": [
          "prescriptions:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClinicalLookupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PrescriptionLookup"
              }
            }
          }
        }
      }
    },
    "/api/partner/v1/lab-results": {
      "post": {
        "summary": "Push a result against an existing accepted referral",
        "description": "",
        "x-required-scopes": [
          "lab-results:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClinicalWriteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LabResultUpload"
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_.:-]{8,100}$"
            },
            "description": "Reuse the exact payload/key after a lost response. A new logical operation uses a new key."
          }
        ]
      },
      "patch": {
        "summary": "Accept or QR-claim an existing referral",
        "description": "",
        "x-required-scopes": [
          "lab-results:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClinicalWriteResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReferralAccept"
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_.:-]{8,100}$"
            },
            "description": "Reuse the exact payload/key after a lost response. A new logical operation uses a new key."
          }
        ]
      }
    },
    "/api/partner/v1/lab-results/lookup": {
      "post": {
        "summary": "Read an authorized referral and current revision",
        "description": "",
        "x-required-scopes": [
          "lab-results:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClinicalLookupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReferralLookup"
              }
            }
          }
        }
      }
    },
    "/api/partner/v1/webhooks": {
      "get": {
        "summary": "Read this key’s webhook and latest delivery status",
        "description": "Any one write scope. Signing secret and payloads are never returned.",
        "x-required-scopes": [
          "appointments:write",
          "prescriptions:write",
          "lab-results:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookGetResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "Register/replace webhook and rotate per-key signing secret",
        "description": "Each subscribed event requires its corresponding write scope. One endpoint per key. Rotation cancels queued old-registration deliveries. Store secret returned once.",
        "x-required-scopes": [
          "appointments:write",
          "prescriptions:write",
          "lab-results:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookPutResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPut"
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Disable webhook by current revision",
        "description": "",
        "x-required-scopes": [
          "appointments:write",
          "prescriptions:write",
          "lab-results:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Success"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDelete"
              }
            }
          }
        }
      }
    },
    "/api/partner/v1/practice-configuration": {
      "get": {
        "summary": "Get connected practice configuration and practitioner mappings",
        "description": "Requires appointments:write and an explicit connection to this active practice. Returns no patient data, staff accounts, phone numbers or secrets. Sandbox returns only the fictional practice. Existing read scopes unchanged.",
        "x-required-scopes": [
          "appointments:write"
        ],
        "security": [
          {
            "BearerKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PracticeConfigurationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input or result bytes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Missing scope, resource connection, active account or patient sharing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Scoped record not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision, QR, slot, transition or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited; Retry-After: 60",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable or disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "query",
            "name": "practice_id",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "dwi_sandbox_<64 hex> or dwi_live_<64 hex>"
      }
    },
    "schemas": {
      "Meta": {
        "type": "object",
        "properties": {
          "environment": {
            "type": "string",
            "enum": [
              "sandbox",
              "live"
            ]
          },
          "api_version": {
            "type": "string",
            "const": "1"
          }
        },
        "required": [
          "environment",
          "api_version"
        ]
      },
      "Practitioner": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "name_ar": {
            "type": "string"
          },
          "specialty": {
            "type": "string"
          },
          "specialty_ar": {
            "type": "string"
          },
          "specialty_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "photo_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "required": [
          "id",
          "name",
          "name_ar",
          "specialty",
          "specialty_ar",
          "specialty_ids",
          "photo_url"
        ]
      },
      "Practice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "name_ar": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "medical",
              "veterinary"
            ]
          },
          "facility_type": {
            "type": "string",
            "enum": [
              "clinic",
              "hospital"
            ]
          },
          "verified": {
            "type": "boolean"
          },
          "location": {
            "type": "object",
            "properties": {
              "wilaya_code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "commune_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "city": {
                "type": "string"
              },
              "address": {
                "type": "string"
              },
              "address_ar": {
                "type": "string"
              },
              "latitude": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "longitude": {
                "type": [
                  "number",
                  "null"
                ]
              }
            },
            "required": [
              "wilaya_code",
              "commune_id",
              "city",
              "address",
              "address_ar",
              "latitude",
              "longitude"
            ]
          },
          "specialty_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "photo_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "booking_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "practitioners": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Practitioner"
            }
          }
        },
        "required": [
          "id",
          "name",
          "name_ar",
          "kind",
          "facility_type",
          "verified",
          "location",
          "specialty_ids",
          "photo_url",
          "booking_url",
          "practitioners"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          },
          "request_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "error",
          "request_id"
        ]
      },
      "PracticesResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Practice"
            }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "limit": {
                "type": "integer"
              },
              "offset": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              },
              "next_offset": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "limit",
              "offset",
              "total",
              "next_offset"
            ]
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "pagination",
          "meta"
        ]
      },
      "AvailabilityResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "practice_id": {
                "type": "string",
                "format": "uuid"
              },
              "practitioner_id": {
                "type": "string"
              },
              "date": {
                "type": "string",
                "format": "date"
              },
              "timezone": {
                "type": "string",
                "const": "Africa/Algiers"
              },
              "slots": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "time": {
                      "type": "string",
                      "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$"
                    },
                    "booking_url": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "uri"
                    }
                  },
                  "required": [
                    "time",
                    "booking_url"
                  ]
                }
              }
            },
            "required": [
              "practice_id",
              "practitioner_id",
              "date",
              "timezone",
              "slots"
            ]
          },
          "meta": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Meta"
              },
              {
                "type": "object",
                "properties": {
                  "booking_mode": {
                    "type": "string",
                    "const": "request"
                  },
                  "availability_guaranteed": {
                    "type": "boolean",
                    "const": false
                  }
                },
                "required": [
                  "booking_mode",
                  "availability_guaranteed"
                ]
              }
            ]
          }
        },
        "required": [
          "data",
          "meta"
        ]
      },
      "PartnerScope": {
        "type": "string",
        "enum": [
          "directory:read",
          "availability:read",
          "appointments:write",
          "prescriptions:write",
          "lab-results:write"
        ],
        "description": "Scopes are opt-in per key. Existing read-only keys gain no write permissions."
      },
      "AppointmentCreate": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "practice_id",
          "practitioner_id",
          "name",
          "phone",
          "service",
          "date",
          "time"
        ],
        "properties": {
          "practice_id": {
            "type": "string",
            "format": "uuid"
          },
          "practitioner_id": {
            "type": "string",
            "pattern": "^[-a-z0-9]{3,60}$"
          },
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 80
          },
          "phone": {
            "type": "string",
            "description": "Algerian mobile, 05/06/07 or +213 format; spaces/hyphens/parentheses normalized."
          },
          "service": {
            "enum": [
              "consultation",
              "controle",
              "vaccination"
            ]
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "time": {
            "type": "string",
            "pattern": "^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$"
          },
          "animalName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "animalSpecies": {
            "type": "string",
            "minLength": 1,
            "maxLength": 30
          },
          "petId": {
            "type": "string",
            "format": "uuid"
          },
          "birthDate": {
            "type": "string",
            "format": "date",
            "description": "Patient date of birth (YYYY-MM-DD), required for human-health bookings, including sandbox. Must be a real date from 1900-01-01 through today. Veterinary bookings omit it. Stored privately; never returned by read-only directory/availability scopes."
          }
        },
        "description": "Patient birthDate is required for human-health bookings, including sandbox; optional for veterinary bookings."
      },
      "AppointmentUpdate": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "practice_id",
          "id",
          "revision"
        ],
        "properties": {
          "practice_id": {
            "type": "string",
            "format": "uuid"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "revision": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "status": {
            "enum": [
              "confirmed",
              "cancelled"
            ]
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "time": {
            "type": "string",
            "pattern": "^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$"
          }
        },
        "description": "Provide status or date+time. Rescheduling and status changes are separate operations. Only pending/confirmed bookings are mutable."
      },
      "AppointmentWriteData": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "practice_id",
          "practitioner_id",
          "date",
          "time",
          "status",
          "revision"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "practice_id": {
            "type": "string",
            "format": "uuid"
          },
          "practitioner_id": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "time": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "revision": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          }
        }
      },
      "PrescriptionLookup": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "pharmacy_id",
          "id",
          "code"
        ],
        "properties": {
          "pharmacy_id": {
            "type": "string",
            "format": "uuid"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          }
        }
      },
      "PrescriptionDispense": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "pharmacy_id",
          "id",
          "code",
          "revision",
          "status"
        ],
        "properties": {
          "pharmacy_id": {
            "type": "string",
            "format": "uuid"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "revision": {
            "type": "integer",
            "minimum": 1
          },
          "status": {
            "const": "dispensed"
          }
        }
      },
      "ReferralLookup": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "lab_id",
          "id"
        ],
        "properties": {
          "lab_id": {
            "type": "string",
            "format": "uuid"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          }
        },
        "description": "A code is required to read an unlinked paper referral. Linked referrals require current patient sharing."
      },
      "ReferralAccept": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "lab_id",
          "id",
          "revision"
        ],
        "properties": {
          "lab_id": {
            "type": "string",
            "format": "uuid"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "revision": {
            "type": "integer",
            "minimum": 1
          }
        },
        "description": "Accept issued/requested referral. QR code required for an unlinked record. Sandbox fixture already accepted at revision 1."
      },
      "LabResultUpload": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "lab_id",
          "id",
          "revision",
          "name",
          "content_base64"
        ],
        "properties": {
          "lab_id": {
            "type": "string",
            "format": "uuid"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "revision": {
            "type": "integer",
            "minimum": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160
          },
          "content_base64": {
            "type": "string",
            "minLength": 4,
            "maxLength": 2796204,
            "contentEncoding": "base64",
            "description": "Canonical base64. PDF/JPEG/PNG magic bytes, decoded file <=2 MiB. Existing accepted referral required."
          }
        }
      },
      "ClinicalWriteData": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "status",
          "revision"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "enum": [
              "accepted",
              "dispensed",
              "ready"
            ]
          },
          "revision": {
            "type": "integer",
            "minimum": 1
          }
        }
      },
      "ClinicalDocument": {
        "type": "object",
        "properties": {
          "patientName": {
            "type": "string"
          },
          "doctorName": {
            "type": "string"
          },
          "clinicName": {
            "type": "string"
          },
          "clinicAddress": {
            "type": "string"
          },
          "clinicPhone": {
            "type": "string"
          },
          "doctorSpecialty": {
            "type": "string"
          },
          "medicines": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "name",
                "directions",
                "quantity"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 160
                },
                "directions": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 500
                },
                "quantity": {
                  "type": "string",
                  "maxLength": 80
                }
              }
            }
          },
          "tests": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            }
          },
          "notes": {
            "type": "string",
            "maxLength": 1500
          }
        }
      },
      "ClinicalLookupData": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "status",
          "revision",
          "document"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string"
          },
          "revision": {
            "type": "integer",
            "minimum": 1
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "document": {
            "$ref": "#/components/schemas/ClinicalDocument"
          }
        }
      },
      "AppointmentWriteResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "meta"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/AppointmentWriteData"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          },
          "replayed": {
            "type": "boolean"
          }
        }
      },
      "ClinicalWriteResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "meta"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/ClinicalWriteData"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          },
          "replayed": {
            "type": "boolean"
          }
        }
      },
      "ClinicalLookupResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "meta"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/ClinicalLookupData"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          },
          "replayed": {
            "type": "boolean"
          }
        }
      },
      "PartnerEventType": {
        "type": "string",
        "enum": [
          "appointment.created",
          "prescription.dispensed",
          "referral.completed"
        ]
      },
      "WebhookPut": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "url",
          "events",
          "revision"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "maxLength": 1000,
            "description": "Public HTTPS port 443; no credentials, fragments, internal/reserved addresses or redirects."
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "maxItems": 3,
            "items": {
              "$ref": "#/components/schemas/PartnerEventType"
            }
          },
          "revision": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "null for first registration; current UUID from GET for replacement."
          }
        }
      },
      "WebhookDelete": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "revision"
        ],
        "properties": {
          "revision": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "WebhookRegistration": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "url",
          "events",
          "revision",
          "signing_secret"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartnerEventType"
            }
          },
          "revision": {
            "type": "string",
            "format": "uuid"
          },
          "signing_secret": {
            "type": "string",
            "pattern": "^dwhsec_[a-f0-9]{64}$",
            "description": "Returned ONCE by PUT; encrypted at rest; full UTF-8 string is HMAC key."
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "event_id": {
            "type": "string",
            "format": "uuid"
          },
          "event_type": {
            "$ref": "#/components/schemas/PartnerEventType"
          },
          "state": {
            "enum": [
              "queued",
              "sending",
              "delivered",
              "failed",
              "cancelled"
            ]
          },
          "attempts": {
            "type": "integer"
          },
          "status_code": {
            "type": [
              "integer",
              "null"
            ]
          },
          "error_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "available_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        }
      },
      "WebhookGetResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "deliveries"
        ],
        "properties": {
          "data": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "url": {
                "type": "string",
                "format": "uri"
              },
              "events": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PartnerEventType"
                }
              },
              "revision": {
                "type": "string",
                "format": "uuid"
              }
            }
          },
          "deliveries": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          }
        }
      },
      "AppointmentCreated": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "type",
          "created_at",
          "api_version",
          "environment",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "const": "appointment.created"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "api_version": {
            "const": "1"
          },
          "environment": {
            "enum": [
              "sandbox",
              "live"
            ]
          },
          "data": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "practice_id",
              "status",
              "revision"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "practice_id": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "enum": [
                  "pending",
                  "confirmed"
                ]
              },
              "revision": {
                "type": "string",
                "pattern": "^[a-f0-9]{64}$"
              }
            }
          }
        }
      },
      "PrescriptionDispensed": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "type",
          "created_at",
          "api_version",
          "environment",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "const": "prescription.dispensed"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "api_version": {
            "const": "1"
          },
          "environment": {
            "enum": [
              "sandbox",
              "live"
            ]
          },
          "data": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "pharmacy_id",
              "status",
              "revision"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "pharmacy_id": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "const": "dispensed"
              },
              "revision": {
                "type": "integer",
                "minimum": 1
              }
            }
          }
        }
      },
      "ReferralCompleted": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "type",
          "created_at",
          "api_version",
          "environment",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "const": "referral.completed"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "api_version": {
            "const": "1"
          },
          "environment": {
            "enum": [
              "sandbox",
              "live"
            ]
          },
          "data": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "lab_id",
              "status",
              "revision"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "lab_id": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "const": "ready"
              },
              "revision": {
                "type": "integer",
                "minimum": 1
              }
            }
          }
        }
      },
      "PartnerWebhookEvent": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/AppointmentCreated"
          },
          {
            "$ref": "#/components/schemas/PrescriptionDispensed"
          },
          {
            "$ref": "#/components/schemas/ReferralCompleted"
          }
        ],
        "description": "Stable event id for deduplication. No patient identities or clinical content. At-least-once delivery; timestamps/signatures refresh on retry."
      },
      "WebhookPutResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/WebhookRegistration"
          }
        }
      },
      "Success": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "const": true
          }
        }
      },
      "PracticeConfigurationResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "meta"
        ],
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/Meta"
          },
          "data": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "practice_id",
              "name",
              "time_zone",
              "currency",
              "billing_period",
              "scopes",
              "services",
              "practitioners",
              "capabilities"
            ],
            "properties": {
              "practice_id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              },
              "time_zone": {
                "const": "Africa/Algiers"
              },
              "currency": {
                "const": "DZD"
              },
              "billing_period": {
                "const": "year"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PartnerScope"
                }
              },
              "services": {
                "type": "array",
                "items": {
                  "enum": [
                    "consultation",
                    "controle",
                    "vaccination"
                  ]
                }
              },
              "practitioners": {
                "type": "array",
                "maxItems": 100,
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "name",
                    "active",
                    "slot_minutes"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "active": {
                      "type": "boolean"
                    },
                    "slot_minutes": {
                      "type": "integer",
                      "minimum": 5,
                      "maximum": 120
                    }
                  }
                }
              },
              "capabilities": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "create_appointment",
                  "update_appointment",
                  "patient_directory",
                  "clinical_history_import",
                  "webhook_events"
                ],
                "properties": {
                  "create_appointment": {
                    "const": true
                  },
                  "update_appointment": {
                    "type": "array",
                    "items": {
                      "enum": [
                        "date",
                        "time",
                        "status"
                      ]
                    }
                  },
                  "patient_directory": {
                    "const": false
                  },
                  "clinical_history_import": {
                    "const": false
                  },
                  "webhook_events": {
                    "type": "array",
                    "items": {
                      "const": "appointment.created"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Dawilo developer hub",
    "url": "https://dawilo.com/help/developers"
  },
  "webhooks": {
    "partnerEvent": {
      "post": {
        "summary": "Signed event from Dawilo",
        "description": "Public HTTPS POST. Verify HMAC-SHA256 over timestamp + dot + exact raw body with full UTF-8 signing_secret; accept timestamps within 300 seconds. Deduplicate event.id, check environment, persist receipt before 2xx. Retries retain event id and payload, refresh timestamp/signature. No redirects. Retry transport errors, 408, 429 and 5xx up to 8 attempts/24h. Other errors are terminal. See docs/PARTNER-API.md.",
        "parameters": [
          {
            "name": "X-Dawilo-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-Dawilo-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^t=[0-9]+,v1=[a-f0-9]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartnerWebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Receipt durably persisted, including an already-received event ID."
          }
        }
      }
    }
  }
}
