Documentation

Webhooks

Receive real-time notifications when events occur in the Cari platform.

Overview

Redis-backed event bus with publish/subscribe pattern.

Cari uses an internal event bus (Redis-backed) to propagate events between microservices. Key domain events are published as event envelopes that services consume asynchronously. The platform also supports inbound webhooks from external services like Stripe, LiveKit, and mobile money providers.

Event Architecture

Internally, Cari uses a publish/subscribe pattern where events flow through a Redis queue. Each event is wrapped in an EventEnvelope containing metadata about the event and a typed payload:

{
  "id": "event-uuid",
  "topic": "cari.auth.user_created",
  "timestamp": "2026-04-18T10:30:00Z",
  "payload": {
    "user_id": "user-uuid",
    "email": "newuser@example.com",
    "registration_role": "DOCTOR"
  }
}

Internal Event Topics

Events published by Cari services for data synchronization and workflow automation.

Auth Events

cari.auth.user_created

Fired when a new user registers. Consumed by the Doctors service to auto-create a doctor profile when the registration role is DOCTOR.

Organization Events

cari.organization.member_added

Fired when a member is added to an organization. Consumed by the Doctors service to link doctor profiles to organizations.

Scheduling Events

Appointment booked

An appointment has been confirmed

Appointment cancelled

An appointment was cancelled

Appointment rescheduled

An appointment time was changed

Clinical Events

Lab result received

A new lab result was ingested via HL7v2

Prescription created

A new prescription was written

Clinical record updated

A patient record was modified

Workforce Events

Leave approved

A leave request was approved (consumed via /api/workforce/webhooks/leave-approved for roster updates).

Inbound Webhooks

Signature-verified webhook endpoints for external services.

Cari receives webhooks from external services. These endpoints verify signatures and process incoming events from third-party platforms.

Stripe Webhooks

POST /api/webhooks/stripe

// Stripe sends events for:
// - checkout.session.completed
// - invoice.payment_succeeded
// - invoice.payment_failed
// - customer.subscription.updated
// - customer.subscription.deleted

// The webhook handler verifies the Stripe signature header
// and processes subscription/payment state changes.

LiveKit Webhooks

POST /api/webhooks/livekit

// LiveKit sends events for telemedicine sessions:
// - room_started — A video room was created
// - room_finished — A video room ended
// - participant_joined — A participant entered the room
// - participant_left — A participant left the room
// - track_published — A media track was published

// Signature verification is performed inside the handler.

Mobile Money Webhooks

// Orange Money payment callbacks
POST /api/payments/webhooks/orange-money

// MTN MoMo payment callbacks
POST /api/payments/webhooks/mtn-momo

// These endpoints receive payment status updates:
// - Payment successful
// - Payment failed
// - Payment pending/timeout

WhatsApp Webhooks

// WhatsApp Business API webhook verification
GET /webhook

// WhatsApp incoming message handler
POST /webhook

// Handles:
// - Incoming patient messages
// - Delivery receipts
// - Read receipts

GTM Webhooks

// Resend email delivery events
POST /api/gtm/webhooks/resend

// Inbound lead capture from external forms
POST /api/gtm/webhooks/inbound

Event Envelope Format

Consistent metadata wrapper for all internal events.

All internal events follow a consistent envelope format. The envelope contains metadata about the event and a typed payload:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "topic": "cari.auth.user_created",
  "timestamp": "2026-04-18T10:30:00Z",
  "source_service": "cari-auth",
  "payload": {
    // Topic-specific payload
  }
}

// Example: User Created Event
{
  "id": "event-uuid",
  "topic": "cari.auth.user_created",
  "timestamp": "2026-04-18T10:30:00Z",
  "payload": {
    "user_id": "user-uuid",
    "email": "doctor@hospital.org",
    "first_name": "Sarah",
    "last_name": "Chen",
    "registration_role": "DOCTOR"
  }
}

// Example: Organization Member Added
{
  "id": "event-uuid",
  "topic": "cari.organization.member_added",
  "timestamp": "2026-04-18T11:00:00Z",
  "payload": {
    "organization_id": "org-uuid",
    "user_id": "user-uuid",
    "role": "ORG:DOCTOR"
  }
}

Dead Letter Queue

Capture failed events for inspection, retry, or discard.

When an event fails to process (deserialization errors, handler failures), it is automatically sent to the Dead Letter Queue (DLQ) instead of being lost. Administrators can inspect, retry, or discard failed events.

// List all failed events
GET /admin/dlq

// Check DLQ depth and alert status
GET /admin/dlq/depth

// Response:
{
  "depth": 3,
  "alert": true,
  "oldest_event": "2026-04-17T08:15:00Z"
}

// Retry a failed event (re-queues for processing)
POST /admin/dlq/:id/retry

// Discard a failed event permanently
DELETE /admin/dlq/:id

DLQ Entry Format

{
  "id": "dlq-entry-uuid",
  "event_id": "original-event-uuid",
  "topic": "cari.auth.user_created",
  "original_payload": "{ ... raw JSON ... }",
  "error": "Failed to parse envelope: missing field 'email'",
  "created_at": "2026-04-17T08:15:00Z"
}

Setting Up Webhook Endpoints

Configure webhook URLs in each external service dashboard.

To receive webhook notifications from external services integrated with Cari, you need to configure the webhook URL in each service's dashboard:

Stripe

1

Add endpoint

Go to your Stripe Dashboard > Developers > Webhooks. Add endpoint: https://api.cari.care/api/webhooks/stripe

2

Select events

Choose: checkout.session.completed, invoice.payment_succeeded, customer.subscription.*

3

Configure secret

Copy the webhook signing secret and set it as the STRIPE_WEBHOOK_SECRET environment variable.

LiveKit

1

Set webhook URL

In your LiveKit server configuration, set the webhook URL to https://api.cari.care/api/webhooks/livekit

2

Match credentials

Ensure the API key and secret match your LiveKit configuration. The handler verifies webhook signatures using the LiveKit SDK.

WhatsApp Business

1

Configure callback URL

In Meta Business Manager, configure the webhook callback URL.

2

Verify endpoint

The verify endpoint (GET /webhook) handles the Meta verification challenge.

3

Handle messages

The handler endpoint (POST /webhook) processes incoming messages.

Best Practices

Guidelines for reliable webhook handling.

Respond quickly

Return a 200 status within 5 seconds. Process heavy logic asynchronously.

Handle duplicates

Use the event id field for idempotency. The same event may be delivered more than once.

Verify signatures

Always verify webhook signatures before processing. Never trust unsigned payloads.

Monitor the DLQ

Regularly check /admin/dlq/depth for failed events that need attention.

Use HTTPS

All webhook endpoints must use HTTPS. HTTP endpoints will be rejected.

Always verify webhook signatures before processing any event payload. Unsigned payloads may have been tampered with or sent by unauthorized sources.