ConnectAI
Developers/Webhooks

Webhooks

We POST appointment events to a URL you host. This is how your system learns about bookings ConnectAI made.

Events

Event typeFires when
appointment.createdAny new appointment, from any ConnectAI channel
appointment.rescheduledTime, mode or location changes
appointment.cancelledThe appointment is cancelled
appointment.completedThe appointment is marked completed
appointment.no_showThe patient did not attend
appointment.payment_updatedPayment captured, or the balance due changes
patient.createdA new patient record originates in ConnectAI
document.deliveredA report or prescription reached the patient
document.failedWe could not deliver one. statusReason says why

You subscribe to a subset when your key is issued. Unsubscribed types are never sent.

Request we send

POST https://your-system.example.com/connectai/webhook
Content-Type: application/json
X-ConnectAI-Key: cai_live_9f2c4a1b8e7d3c06
X-ConnectAI-Timestamp: 1758614400
X-ConnectAI-Signature: v1=6b8d…c31f
X-ConnectAI-Event-Id: 9a7f1c20-5db4-4f31-8e02-2b6c9d77a145
X-ConnectAI-Event-Type: appointment.created
X-ConnectAI-Delivery-Attempt: 1
Body
{
  "eventId": "9a7f1c20-5db4-4f31-8e02-2b6c9d77a145",
  "eventType": "appointment.created",
  "occurredAt": "2026-09-24T14:32:07.412Z",
  "clinicId": "68d63629fdec0a56e25e0a6d",
  "appointment": {
    "connectaiId": "68f04b1177ce0a1d2e9b4410",
    "externalId": null,
    "startsAt": "2026-09-25T04:45:00.000Z",
    "startsAtLocal": "2026-09-25T10:15:00+05:30",
    "mode": "Offline",
    "status": "Approved",
    "token": "A-14",
    "notes": "Follow-up",
    "payment": {
      "type": "Partial",
      "amountPaid": 200,
      "balanceDue": 600,
      "currency": "INR",
      "payAtClinic": true
    }
  },
  "doctor":  { "connectaiId": "66a1…", "externalId": "HMS-DR-114", "name": "Dr Anita Rao" },
  "patient": { "connectaiId": "68a9…", "externalId": "HMS-PT-88213", "name": "Rohan Mehta", "phone": "+919811223344" },
  "location": { "connectaiId": "67b2…", "externalId": "HMS-LOC-2", "name": "Gomti Nagar" }
}

Every entity carries both identifiers. externalId is null when the record originated in ConnectAI and you have not claimed it yet — create your own record, then send us the mapping.

Times appear twice deliberately: startsAt in UTC is authoritative, startsAtLocal is for display. Integrate against startsAt.

Verifying us

Node.js / Express
// Express — capture the raw body so the signature can be checked.
app.use("/connectai/webhook", express.json({
  verify: (req, _res, buf) => { req.rawBody = buf; },
}));

app.post("/connectai/webhook", (req, res) => {
  const timestamp = req.headers["x-connectai-timestamp"];
  const provided  = req.headers["x-connectai-signature"];

  const expected =
    "v1=" +
    crypto.createHmac("sha256", OUTBOUND_SECRET)
          .update(`${timestamp}.${req.rawBody.toString("utf8")}`, "utf8")
          .digest("hex");

  const a = Buffer.from(expected), b = Buffer.from(String(provided));
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.sendStatus(401);
  }

  // Persist first, then return 200. Do the work afterwards.
  enqueue(req.body);
  res.sendStatus(200);
});

What you must return

Any 2xx, with any body, within 10 seconds.

Return 200 the moment you have persisted the event, BEFORE you process it. If you do your business logic inside the webhook handler and time out, we will treat it as a failure and redeliver — and you will process it twice.

Retries and ordering

  • Delivery is at-least-once. Deduplicate on eventId.
  • Retry ladder: 30s, 2m, 10m, 1h, 6h, 12h, 24h. Seven attempts over roughly 44 hours, then we stop and alert our team.
  • Deliveries for one appointment are ordered. Different appointments may arrive out of order.
  • Every payload is a complete current-state snapshot, not a diff, so a late-arriving older event is safe to discard by comparing occurredAt.
  • After 50 consecutive failures we pause your queue rather than keep hammering a dead endpoint. Queued events are kept and drain in order once it is resumed.