Webhooks
Solum sends webhook events to URLs you register when patients and tasks in your workspace change — created, updated, stage changed, verification completed, comment added. Each delivery is signed with HMAC-SHA256 so you can confirm it came from Solum and that the body has not been modified in transit.Webhook payloads are intentionally ID-only and do not contain PHI, following the same convention as Epic and athenahealth. The event tells you what changed and which record changed; fetch the current state from the corresponding
GET /v1/... endpoint with your API key.How webhooks work
- Create a subscription with the URL of your endpoint and the event types you want to receive. Solum returns a signing secret once.
- When a matching event occurs, Solum signs the JSON payload with your secret and sends it to your URL with
X-Solum-*headers. - Your endpoint verifies the signature, processes the event, and responds
2xxwithin 30 seconds. - Any non-2xx response or timeout is retried up to two times: first after 60 seconds, then after 5 minutes.
Create a subscription
Create webhook subscriptions through the API or the dashboard at Settings → Webhooks. The example below uses the API.POST https://api.getsolum.com/v1/webhooks
Authentication: X-API-Key: <your_api_key>.
Subscription and delivery endpoints
The webhook routes are not included in the generated API Reference, so the complete management surface is listed here:Delivery format
Every delivery is an HTTPPOST to your endpoint URL with the following headers:
The body is compact JSON with no whitespace. Sign the raw bytes you received, not a re-serialized form (see Verifying signatures).
Your endpoint must return a
2xx status within 30 seconds. Any other response, or a timeout, is treated as a failure and retried.
Event types
Example payloads
All payloads share three top-level fields:event_type, event_id, timestamp. The rest depends on the event.
GET /v1/patients/{id} or GET /v1/tasks/{id} using the ID in the payload.
Verifying signatures
Solum signs every delivery with HMAC-SHA256 using your subscription’s signing secret. Verify the signature on every incoming request to confirm it came from Solum and that the body has not been modified in transit. TheX-Solum-Signature header contains a single scheme — sha256 — followed by the hex-encoded digest:
Verify signatures manually
Step 1: Read the raw request body
The HMAC input is the raw bytes of the HTTP request body, byte-for-byte. If your framework parses the body into a dict or object and you re-serialize it, key order, whitespace, and unicode escaping can differ from the original — and the signature will not match. Read the body before any parsing. In FastAPI:await request.body(). In Flask: request.get_data(). In Django: request.body. In Express: mount express.raw({ type: "application/json" }) on the webhook route, ahead of any express.json() middleware.
Step 2: Prepare the signing key
Your subscription secret has the formwhsec_<hex>. The whsec_ prefix is a label identifying the secret’s purpose — it is not part of the cryptographic key. Strip it before computing the HMAC.
The remaining characters are used directly as UTF-8 bytes. There is no hex-decoding or base64-decoding step.
Step 3: Compute the expected signature
Compute an HMAC using SHA-256 with the cleaned secret as the key and the raw body as the message. Hex-encode the digest.Step 4: Compare against the header
Take everything aftersha256= in X-Solum-Signature and compare it to your computed hex using a constant-time comparison (hmac.compare_digest in Python, crypto.timingSafeEqual in Node).
Code example
Reference test vector
Use this fixed vector to confirm your implementation produces the expected hex before connecting to live deliveries.
Reproduce the expected hex in any of the following environments — each snippet is fully self-contained and prints
d6973f7d4441d3e3af74c4839f744987c2684a1b097ddca0cb4f936a64d66fad.
Verify a specific delivery
When verification fails on a live request, save the exact bytes Solum POSTed to a file — for example by capturing them in your access log — and re-run the HMAC outside your application:sha256= in the X-Solum-Signature header. If it doesn’t, the cause is almost always one of:
- The
whsec_prefix was kept as part of the HMAC key. - The body was modified after receipt — a logger appended a newline, a reverse proxy re-encoded the JSON, or your handler parsed and re-serialized it before signing.
- The secret was rotated and the request was signed with the previous value.
Test events
Each subscription exposes a test endpoint that delivers a synthetic event to your URL using the subscription’s real signing secret. Use it to validate end-to-end signature verification before enabling production traffic.test-patient-id, test-task-id, test-comment-id, and test-user-id, with an event_id prefixed with test_. The requested event type always matches both X-Solum-Event-Type and event_type in the body. The same action is available in the dashboard under Settings → Webhooks → Test.
Retries
Every patient and task event uses the same retry behavior and reuses the same
event_id. After three failed attempts the delivery is marked failed. To redeliver any delivery — including successful ones — call:
GET /v1/webhooks/{subscription_id}/deliveries.
Idempotency
Webhook delivery is at-least-once. A network delay can cause Solum to retry a request your handler already processed, because the original2xx response did not arrive within the timeout.
Persist the X-Solum-Event-ID of every event you process and short-circuit duplicates on subsequent attempts. The header and the event_id field in the body always hold the same value.
Troubleshooting
For unresolved issues, contact support@getsolum.com with the delivery ID from
GET /v1/webhooks/{subscription_id}/deliveries and the hex your implementation computes.
