Webhooks
Receive signed appointment and consultation-document updates at an HTTPS endpoint configured by Doctronic.
Doctronic can send signed HTTP POST requests when selected appointment or consultation-document
events occur. Webhooks are configured manually. Provide your HTTPS endpoint and event subscriptions
to your Doctronic implementation contact. Doctronic will provide the signing secret through the
agreed secure channel.
Webhook configuration is managed by Doctronic
There is no public endpoint or dashboard for registering a webhook, rotating its secret, viewing deliveries, or replaying an event. Coordinate those actions with your implementation contact.
Event envelope
Every request uses this camelCase envelope:
{
"eventId": "0f8fad5b-d9cb-469f-a165-70867728950e",
"event": "appointment.waiting_room_ready",
"occurredAt": "2026-08-25T18:30:00Z",
"data": {
"appointmentId": "appointment-id",
"userId": "doctronic-user-id",
"waitingRoomUrl": "https://dctd.co/r/example/"
}
}eventId remains the same across delivery attempts. Use it as the idempotency key for processing.
occurredAt records when the event occurred, not when a particular attempt reached your endpoint.
Available events
| Event | data fields | Meaning |
|---|---|---|
appointment.waiting_room_ready | appointmentId, userId, waitingRoomUrl | A join URL is ready. The URL currently expires one hour after issuance and can rotate when reissued. |
appointment.practitioner_joined | appointmentId, userId | A practitioner joined the appointment. |
appointment.call_ended | appointmentId, userId | The appointment call ended. |
artifact.ready | artifactId, artifactType, chatId, userId | A consultation document is ready for retrieval. userId can be null. |
Only events enabled for your integration are sent. Ignore unknown event names so additive changes do not break your receiver.
Verify the signature
The X-Doctronic-Signature header contains a lowercase hexadecimal HMAC-SHA256 digest of the exact
request body bytes, signed with your webhook secret.
Verify the signature before parsing or processing the JSON. Do not reserialize the body first.
import { createHmac, timingSafeEqual } from 'node:crypto';
export async function verifyDoctronicWebhook(
request: Request,
secret: string,
) {
const body = Buffer.from(await request.arrayBuffer());
const supplied = request.headers.get('x-doctronic-signature') ?? '';
const expected = createHmac('sha256', secret).update(body).digest('hex');
const suppliedBytes = Buffer.from(supplied, 'utf8');
const expectedBytes = Buffer.from(expected, 'utf8');
const valid =
suppliedBytes.length === expectedBytes.length &&
timingSafeEqual(suppliedBytes, expectedBytes);
if (!valid) throw new Error('Invalid Doctronic webhook signature');
return JSON.parse(body.toString('utf8'));
}import hashlib
import hmac
import json
def verify_doctronic_webhook(body: bytes, supplied: str, secret: str) -> dict:
expected = hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(supplied, expected):
raise ValueError("Invalid Doctronic webhook signature")
return json.loads(body)Process deliveries safely
- Read and preserve the raw request body.
- Verify
X-Doctronic-Signaturewith a constant-time comparison. - Validate the event envelope and expected
datafields. - Insert
eventIdinto a durable uniqueness store. - If it was already processed, return a success response without applying the change again.
- Queue the work and return any
2xxresponse promptly. - Apply the event only to the matching organization and user records in your system.
The current signature has no separate delivery timestamp header. The signed occurredAt value can
support a workflow-specific freshness check, but it may be several hours old during retries. Do
not use freshness alone as replay protection. Signature verification and durable eventId
deduplication are both required.
Delivery behavior
- Network failures,
429, and5xxresponses are retried with exponential backoff. - Other
4xxresponses are treated as permanent failures and are not retried. - The general retry window is up to six hours.
appointment.waiting_room_readyhas a shorter retry window of up to five minutes and stops when the event is no longer useful for the appointment.- Appointment lifecycle retries can stop when the appointment has ended.
Do not rely on a specific number of attempts. Keep the receiver available, idempotent, and fast.
Rotate a webhook secret
Secret rotation is coordinated with Doctronic. Plan a short maintenance procedure that can accept the agreed secret at the agreed cutover point, verify a signed test delivery, and remove the prior secret from your systems. Do not send the secret in email or an unapproved messaging channel.
Test before production
Ask your implementation contact to enable the required events in staging. Verify:
- Valid signatures succeed and changed bodies fail verification.
- Duplicate
eventIdvalues do not repeat side effects. - Unknown event names return success without blocking other events.
- Your endpoint responds correctly to retries and out-of-order events.
- A waiting-room URL replaces an older URL rather than becoming a permanent identifier.
- Processing failures are visible to your on-call team without logging secrets or unrestricted patient content.