Events you’ll receive:
appointment.confirmed— patient’s appointment is confirmed and assigned to your clinicappointment.reassigned— an existing appointment has been moved to your clinic (from another partner)
Future event types (appointment.cancelled, appointment.updated) are reserved and will follow the same payload shape.
Headers we send on every request:
Content-Type: application/json
X-MedWorks-Event: appointment.confirmed
X-MedWorks-Signature: sha256=<hex hmac of raw body>
User-Agent: MedWorks-ClinicConnect/1.0Sample appointment.confirmed payload:
{
"event": "appointment.confirmed",
"appointment_id": "a9d6f16c-1234-4f87-8b6e-aa11bb22cc33",
"booking_number": "A9D6F16C",
"service_type": "telemedicine",
"country": "mexico",
"appointment_date": "2026-06-26",
"appointment_time": "14:00",
"walk_in": false,
"patient": {
"first_name": "Jane",
"last_name": "Lopez",
"email": "jane.lopez@example.com",
"phone": "+1 555 123 4567"
},
"reason_for_visit": "Sore throat, mild fever 38C",
"clinic_notes_required": true,
"language": "en",
"timezone": "America/Mexico_City",
"status": "confirmed",
"timestamp": "2026-06-26T13:30:00Z"
}Event names you will see:
• appointment.confirmed — initial confirmation
• appointment.reassigned — admin moved this appointment to your clinic from another
Field reference:
• appointment_id — stable UUID for the booking (also used in the Admin retry tool)
• booking_number — short 8-char code shown to patients (e.g. "A9D6F16C")
• service_type — telemedicine | in_clinic | dental | mental_health
• country — mexico | canada
• walk_in — true for Mexico walk-in / waiting-room bookings (appointment_time = "ASAP")
• status — confirmed (always confirmed when we POST appointment.* events)
• reason_for_visit — patient-supplied free-text complaint, may be empty
• clinic_notes_required — true when the patient asked for written clinic notes after the consult (to submit to their insurance). Deliver the notes to the patient via your usual channel; MedWorks records this on the appointment.
• timestamp — when MedWorks fired the webhook (ISO-8601 UTC)X-MedWorks-Signature: sha256=<hex>. Verify against the raw request bytes using the secret we issued you in your integration pack.import hmac, hashlib
from fastapi import Request, HTTPException
CLINIC_WEBHOOK_SECRET = "<provided in your integration pack>"
async def verify_medworks(request: Request):
sent = request.headers.get("X-MedWorks-Signature", "")
body = await request.body()
expected = "sha256=" + hmac.new(
CLINIC_WEBHOOK_SECRET.encode(), body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(sent, expected):
raise HTTPException(401, "bad signature")import crypto from "node:crypto";
const CLINIC_WEBHOOK_SECRET = process.env.MW_WEBHOOK_SECRET;
export function verifyMedWorks(req) {
const sent = req.header("X-MedWorks-Signature") || "";
const expected =
"sha256=" +
crypto.createHmac("sha256", CLINIC_WEBHOOK_SECRET)
.update(req.rawBody) // unparsed bytes
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(sent), Buffer.from(expected))) {
throw new Error("bad signature");
}
}The appointment is already confirmed when it reaches your endpoint — there is no accept/decline step. Persist the booking in your system and return200 OK. Anything outside the 2xx range is logged as a failed delivery on the MedWorks admin side.
# MedWorks treats any 2xx as a successful delivery — your endpoint should
# acknowledge as soon as you have persisted the booking. There is no
# separate accept/decline call for appointment.* events; the appointment
# is already confirmed when it reaches you.
HTTP/1.1 200 OK
Content-Type: application/json
{ "ack": true }Every fire attempt is recorded in the admin Webhook Deliveries log against theappointment_id. If your endpoint returns a non-2xx (or times out after 10 seconds), MedWorks support can re-fire the same event manually from the admin console — your handler will see the same appointment_idagain, so treat it as idempotent and de-duplicate on that field.
Automatic retry / dead-letter fallback to email is on the roadmap — for now, the “Retry” button in the admin Webhook Deliveries card is the source of truth.
Each webhook is a single POST attempt with a 10-second timeout. On failure, MedWorks staff can re-fire the same event from the admin Webhook Deliveries card — your handler should be idempotent onappointment_id.
2xx— delivery considered successful3xx— not followed; treated as failure4xx/5xx— logged with the response body in the admin console; retry on demandtimeout— 10 second hard limit per attempt
