Receive webhooks
Return to the full receiver flow and follow-up pattern.
Guide
Validate ChartHero webhook headers, timestamps, and HMAC signatures.
Planned / not generally availableVerify webhook signatures before parsing trusted business fields or fetching clinical follow-up resources. The check proves the delivery was signed with the endpoint signing secret and that the timestamp is within the documented tolerance.
Planned / not generally available: Runtime delivery for
recording.transcript_readyis not generally available. Implement this verification pattern before a receiver is activated.
This page covers verification only. For the full receiver workflow, see Receive webhooks.
Signature verification does not use ChartHero API-key scopes. It requires the endpoint signing secret and these webhook headers:
| Header | Purpose |
|---|---|
ChartHero-Event-Id |
Business idempotency key that must match body id. |
ChartHero-Delivery-Id |
Stable delivery identifier for support/debug metadata and retry correlation. |
ChartHero-Timestamp |
Decimal Unix epoch seconds used in the signature input. |
ChartHero-Signature |
v1= HMAC-SHA256 digest for the delivery. |
ChartHero-Webhook-Version |
Webhook version that must match body api_version. |
Reject requests with missing headers, malformed timestamps, unsupported signature versions, or timestamps outside the allowed tolerance.
Example signed delivery inputs:
curl -X POST "https://partner.example.test/chart-hero/webhooks" \
-H "Content-Type: application/json" \
-H "ChartHero-Event-Id: evt_recording_transcript_ready_01" \
-H "ChartHero-Delivery-Id: whd_recording_transcript_ready_01" \
-H "ChartHero-Timestamp: 1777649400" \
-H "ChartHero-Signature: v1=a3bb0750eef64758be4a034aaff5dd5774c21bf7fe25083b51d61ba0214c0419" \
-H "ChartHero-Webhook-Version: 2026-05-01" \
--data-raw '{"id":"evt_recording_transcript_ready_01","type":"recording.transcript_ready","api_version":"2026-05-01","occurred_at":"2026-05-01T15:29:55Z","organization_id":"org_synthetic_webhook_001","resources":{"encounter_id":"enc_synthetic_webhook_001","document_id":"doc_synthetic_transcript_001"}}'
Build the signed payload as {timestamp}.{raw_request_body}. Use the exact body bytes received by the HTTP server, before JSON reserialization or whitespace normalization.
1777649400.{"id":"evt_recording_transcript_ready_01","type":"recording.transcript_ready","api_version":"2026-05-01","occurred_at":"2026-05-01T15:29:55Z","organization_id":"org_synthetic_webhook_001","resources":{"encounter_id":"enc_synthetic_webhook_001","document_id":"doc_synthetic_transcript_001"}}
Compute the HMAC-SHA256 digest with the endpoint signing secret and compare it to the v1 value in ChartHero-Signature using a constant-time comparison.
Language-neutral verification steps:
ChartHero-Timestamp and reject it if it is not decimal Unix epoch seconds.300 seconds from your server clock.{timestamp}.{raw_request_body}.ChartHero-Signature and require the supported v1= value.ChartHero-Event-Id equals body id.ChartHero-Webhook-Version equals body api_version.If verification and lightweight validation succeed, return any HTTP 2xx response. No JSON acknowledgement body is required.
HTTP/1.1 204 No Content
If verification fails, do not process clinical follow-up work. Return a non-2xx response according to your receiver policy.
After the signature is valid, parse the JSON body and verify these consistency checks:
| Header | Body field |
|---|---|
ChartHero-Event-Id |
id |
ChartHero-Webhook-Version |
api_version |
Do not process clinical follow-up work when either check fails.
Other common verification failures include missing headers, unsupported signature versions, non-decimal timestamps, stale timestamps outside the 300 second tolerance, and comparing against a JSON-reserialized body instead of the raw request body.
Return to the full receiver flow and follow-up pattern.
Confirm the webhook headers and retry contract.
Inspect the generated webhook operation.