Skip to content

Webhooks

Zocdoc sends two kinds of webhook notification:

Security

Webhooks support HTTPS only (except for testing within the sandbox environment). All webhook requests are signed with a shared key that is known only to Zocdoc and to the client. You should manually verify the signature of each request to ensure its origin from the Zocdoc API server and to confirm that it has not been tampered with during transit.

Setting up Webhooks

  1. Create an HTTPS endpoint on your server (HTTP can be used for testing purposes).
  2. You can also use tools like webhook.site to test webhook responses within the sandbox.
  3. In the sandbox environment, you may use any valid base64 string as a key to test.
    Example key:
    g9Y9hjTUk9KKH7ffBRbtRmJYo2OISsdMK4flbfDa3zR=
  4. Submit your URL to the Zocdoc API team. The URL you provide will be hit by Zocdoc to post updates.

Handling a Notification

  1. Verify the signature.
  2. Return a 2xx. Zocdoc times out after 5 seconds.
  3. Parse the JSON payload. Each webhook type documents its payload below.

A retry can deliver a notification you already processed, so make processing idempotent.

Verify the Signature of the Webhook

  1. Convert the shared key provided by the Zocdoc API team to bytes as a base64 encoded string.

  2. Extract the timestamp from the webhook-timestamp header. The timestamp is in Unix epoch time (seconds) (e.g. 1686772989 = June 14, 2023 20:03:09 UTC).

  3. Verify that the timestamp is within a few minutes (default: 5 minutes) of the current time.

  4. Convert the request body's JSON payload to a string. Note: Zocdoc may modify the schema at any time.

  5. Concatenate the signed payload: <webhook_timestamp>.<json payload>

  6. Encode this message as UTF-8 bytes.

  7. Calculate the HMAC SHA256 hash using:

    • The shared key as the key
    • The encoded message as the input
  8. Compare the calculated hash with the signature in the webhook-signature header.

Example webhook-signature format:

v1:8KsUa1qDHGmJhK25hReYCRhOKkqxTYx7UC78f0FBkdA=;v2:8KsUa1qDHGmJhK25hReYCRhOKkqxTYx7UC78f0FBkdA=

Each signature is prefixed by the version (e.g., v1:) and separated by semicolons.

Retries

Zocdoc makes up to 15 delivery attempts. Retries start after 5 minutes and double each time, capped at just under 12 hours between attempts, so the last attempt comes about 4 days after the first.

Zocdoc will retry if:

  • A connection cannot be established with the developer's server
  • No response is provided within 5 seconds
  • The connection is severed before a response

Zocdoc will not retry based on the status code returned by the webhook endpoint.

Webhook types

Appointment webhook

For the patient booking use case, webhook notifications will only be sent for provider-initiated appointment changes. For developer/patient-initiated actions: Update your internal systems based on the API response. Do not wait for a webhook.

{
  "data": {
    "appointment_data": {
      "appointment_id": "62g4ar44-1yv9-0931-dl3t-e9c2174kks09",
      "appointment_updated_timestamp": "2023-06-14T17:06:54.9430804Z",
      "appointment_update_type": "updated",
      "changed_attributes": [
        {
          "attribute_path": "appointment.start_time"
        },
        {
          "attribute_path": "patient.uploaded_attachments",
          "attachment_type": "id_card"
        }
      ]
    },
    "data_type": "appointment_data"
  },
  "event_type": "appointment_updated",
  "webhook_timestamp": "2023-06-14T17:08:54.9430839Z"
}

Note:

  • Currently the only supported value for data_type is appointment_data and for event_type is appointment_updated.
  • Supported values for appointment_update_type are: updated, cancelled, and created. (The created value is only supported within the provider scheduling use case.)
  • When the webhook is triggered due to attribute changes, the appointment_data payload MUST include a changed_attributes array. Each object MUST contain at least an attribute_path. For patient.uploaded_attachments, the object MUST also include the attachment_type.

Insurance reference-data webhook

Zocdoc posts an insurance_plans_updated or insurance_carriers_updated notification when a plan or carrier field exposed by the API changes. A change to a Zocdoc-internal field sends nothing.

{
  "event_id": "evt_4f2c8a91d0b34e6f8a1c7d5e9b0f2a63",
  "event_type": "insurance_plans_updated",
  "event_time_utc": "2026-01-15T14:30:00Z",
  "changed_entities": [
    {
      "insurance_plan_id": "ip_5432",
      "changed_attributes": [
        { "attribute_path": "insurance_plan.name" }
      ]
    },
    {
      "insurance_plan_id": "ip_2345",
      "changed_attributes": [
        { "attribute_path": "insurance_plan.carrier" },
        { "attribute_path": "insurance_plan.status" }
      ]
    }
  ]
}

Note:

  • Every entry in changed_entities matches the notification's event_type. Each entry has insurance_plan_id on insurance_plans_updated or insurance_carrier_id on insurance_carriers_updated. The other key is absent.
  • changed_entities holds 1 to 100 entries. A larger change arrives as several notifications.
  • attribute_path names the field that changed, such as insurance_plan.status or insurance_carrier.name. It can be any field on the plan or carrier returned by Get Insurance Plan.
  • event_id is for support requests. It is not a dedup key.

To process a notification:

  1. Skip each entry whose changed_attributes lists no field you use.
  2. Fetch each remaining plan from Get Insurance Plan.

An insurance_carriers_updated notification means a field on the carrier itself changed, such as its name. It does not mean the carrier's plans changed. The API returns a carrier only as carrier on a plan. To read the new value, fetch any plan you hold with that carrier.

A retry can re-send entities you already processed. Dedup on insurance_plan_id or insurance_carrier_id.

To send yourself a sample in Sandbox, see the insurance mock request.