> ## Documentation Index
> Fetch the complete documentation index at: https://docs.healos.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a webhook

> Registers a webhook for one event type. Deliveries start with the next matching event for the key owner's notes and documents. `url` must be HTTPS on a public host. Requires the webhooks:write scope.

| Requirement | Detail |
| - | - |
| **Scope** | `webhooks:write` |
| **Rate limit** | About 60 requests per minute per API key (shared by all endpoints; approximate) |
| **Cost** | Free |

> [!NOTE]
>
> **Safety**
>
> * **Writes data:** Yes. Registers a webhook. HealOS starts sending events to `url` with the next matching note or document event.
> * **Safe to retry:** Only with an `Idempotency-Key` header: a repeat with the same key returns the first webhook instead of a second one.
> * **Contacts an outside system:** Not at creation. Later deliveries POST to your `url`.
> * **Dry run:** Not available.

> [!NOTE]
>
> Rolling out: this endpoint is on staging first and not yet on `api.healos.ai`.

One webhook receives one `event_type`; create one per event you need. `url` must be HTTPS on a public host (loopback, private, link-local and cloud-metadata addresses are rejected, at creation and again before every delivery).

Use `headers` to send a shared secret your endpoint checks, for example `{"Authorization": "Bearer <secret>"}`. `Host`, `Content-Type`, `Content-Length`, `User-Agent` and other framing headers are set by HealOS and cannot be configured. Header values cannot be read back, so keep your copy.

Webhooks belong to the user who created the API key and receive that user's note and document events, the same as on the dashboard's Webhooks page. A webhook of another user, in your organization or any other, is a `404`.

Guide: [Webhooks](https://docs.healos.ai/webhooks.md). Errors: [Error catalog](https://docs.healos.ai/errors.md).


## OpenAPI

````yaml openapi/ext-api-v1.json POST /webhooks
openapi: 3.0.0
info:
  title: Healos External API
  version: 1.0.0
  description: >-
    External API for managing patients, documents, and appointments, listing
    providers and note templates, pulling clinical notes (with transcript and
    patient context), running insurance eligibility checks, browsing the EHR
    action catalog, reading AI Receptionist calls (summary, transcript,
    extracted details and recording), managing the AI Receptionist inbox tasks,
    and registering webhooks for note and document events.
servers:
  - url: https://api.healos.ai/ext-api/v1
    description: Production
  - url: http://localhost:8787/ext-api/v1
    description: Local development
security:
  - ApiKeyAuth: []
paths:
  /webhooks:
    post:
      tags:
        - Webhooks
      summary: Create a webhook
      description: >-
        Registers a webhook for one event type. Deliveries start with the next
        matching event for the key owner's notes and documents. `url` must be
        HTTPS on a public host. Requires the webhooks:write scope.
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 255
            description: >-
              Up to 255 printable ASCII characters. Use a new random value (a
              UUID) for each new request and resend the same value when you
              retry it.
            example: 5f0c3a8e-2b7d-4c1e-9a64-0d3f2e1b7c90
          required: false
          name: Idempotency-Key
          in: header
          description: >-
            Makes a retry of this request safe. A repeat with the same key and
            the same request within 24 hours does not run again: it returns the
            original status with the resource as it is now, and an
            `Idempotent-Replayed: true` header. Keys are scoped to your
            organization and API key. See https://docs.healos.ai/idempotency.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookCreate'
      responses:
        '201':
          description: Webhook created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookResponse'
          headers:
            Idempotent-Replayed:
              description: >-
                `true` when this response is a replay of an earlier request with
                the same `Idempotency-Key`.
              schema:
                type: string
                enum:
                  - 'true'
        '400':
          description: >-
            Validation error: an unknown event type or format, a URL that is not
            HTTPS on a public host, a reserved or malformed header, or an
            unknown field; or `Idempotency-Key` is empty, longer than 255
            characters or not printable ASCII
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/IdempotencyError'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Insufficient scope (needs webhooks:write)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            You already have 25 webhooks; delete one first; or a request with
            this `Idempotency-Key` is still being processed
            (`idempotency_in_progress`; retry after `Retry-After`)
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/IdempotencyError'
        '422':
          description: >-
            This `Idempotency-Key` was already used for a different request
            (`idempotency_key_reused`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IdempotencyError'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
components:
  schemas:
    WebhookCreate:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 200
          example: EHR sync
        url:
          type: string
          maxLength: 2048
          format: uri
          description: >-
            Your HTTPS endpoint. It must resolve to a public host: loopback,
            private, link-local and cloud-metadata addresses are rejected.
          example: https://hooks.example.com/healos
        event_type:
          type: string
          enum:
            - NOTE_CREATED
            - NOTE_REGENERATED
            - NOTE_UPDATED
            - DOCUMENT_STATUS_CHANGED
          description: The event this webhook receives. One event per webhook.
          example: NOTE_CREATED
        format:
          type: string
          enum:
            - JSON
            - XML
            - Form Data
          description: How the payload is encoded. Default `JSON`.
          example: JSON
        description:
          type: string
          nullable: true
          maxLength: 1000
          example: Pushes new notes to our EHR bridge
        headers:
          type: object
          additionalProperties:
            type: string
          description: >-
            Up to 10 static headers sent with every delivery, for example a
            shared secret your endpoint checks. Values are write-only: responses
            list the header names, never the values.
          example:
            Authorization: Bearer your-shared-secret
      required:
        - name
        - url
        - event_type
      additionalProperties: false
    WebhookResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/Webhook'
      required:
        - data
    ValidationError:
      type: object
      properties:
        error:
          type: string
        details:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
      required:
        - error
    IdempotencyError:
      type: object
      properties:
        error:
          type: string
        code:
          type: string
          enum:
            - idempotency_key_invalid
            - idempotency_in_progress
            - idempotency_key_reused
            - idempotency_resource_gone
      required:
        - error
        - code
    Error:
      type: object
      properties:
        error:
          type: string
      required:
        - error
    RateLimitError:
      type: object
      properties:
        error:
          type: string
          example: Rate limit exceeded. Please retry after the window resets.
        code:
          type: string
          enum:
            - daily_cap_reached
          description: >-
            Set when the organization reached its daily cap for this paid
            operation (not on a per-minute limit).
        reset_at:
          type: string
          format: date-time
          description: 'With `code`: when the daily cap resets (next 00:00 UTC).'
          example: '2026-10-28T00:00:00.000Z'
      required:
        - error
    Webhook:
      type: object
      properties:
        id:
          type: string
          example: 3f2b8c1e-0000-4000-8000-000000000001
        name:
          type: string
        url:
          type: string
        event_type:
          type: string
          example: NOTE_CREATED
        format:
          type: string
          example: JSON
        description:
          type: string
          nullable: true
        header_names:
          type: array
          items:
            type: string
          description: >-
            The names of the configured headers. Their values are never
            returned.
          example:
            - Authorization
        active:
          type: boolean
        created_at:
          type: string
          example: '2026-11-03T14:00:00.000Z'
      required:
        - id
        - name
        - url
        - event_type
        - format
        - description
        - header_names
        - active
        - created_at
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key obtained from /api/v1/ext-api-keys

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.