API Referencev1

Webhooks

Webhooks let you receive real-time notifications when events happen in your Odento account. Register a URL, subscribe to events, and we'll send a POST request with the event payload every time something happens.

How Webhooks Work

  1. You create a webhook endpoint with a URL and a list of events to subscribe to
  2. When an event occurs (e.g., appointment.created), Odento sends an HTTP POST to your URL
  3. The request body contains the event payload, signed with your webhook secret
  4. You verify the signature, process the event, and respond with a 200 status
  5. If we don't receive a 200 within 10 seconds, we retry with exponential backoff

Retry Policy

We retry failed deliveries up to 5 times with exponential backoff: 1m, 5m, 30m, 2h, and 12h. After 5 failures, the webhook is automatically disabled.

Available Events

EventDescription
patient.createdA new patient record was created
patient.updatedA patient record was updated
appointment.createdA new appointment was scheduled
appointment.updatedAn appointment was modified
appointment.cancelledAn appointment was cancelled
appointment.completedAn appointment was marked completed
invoice.createdA new invoice was created
invoice.paidAn invoice was fully paid
payment.receivedA payment was recorded
lab_order.createdA lab order was created
lab_order.status_changedA lab order status changed
lab_order.shippedA lab order was shipped

Payload Format

Every webhook delivery sends a JSON body with the following structure:

Responsejson
{
  "event_id": "evt_abc123def456ghi789",
  "event_type": "appointment.created",
  "created_at": "2025-01-22T10:05:00Z",
  "data": {
    "object": {
      "id": "apt_7a3b9c1d2e5f8a4b",
      "patient_id": "pat_5f8d3a2b1c9e4a7b",
      "dentist_id": "usr_abc123",
      "start_time": "2025-01-22T10:00:00Z",
      "end_time": "2025-01-22T11:00:00Z",
      "type": "consultation",
      "status": "scheduled",
      "location_id": "loc_xyz789"
    }
  }
}

Signature Verification

Every webhook request includes an X-Odento-Signature header containing a HMAC-SHA256 signature of the request body, computed using your webhook signing secret. Always verify this signature before processing the payload.

The signature is computed as:

HMAC-SHA256(webhook_secret, raw_request_body)

Here's how to verify the signature in Node.js:

Requestjavascript
import crypto from 'crypto'

function verifyWebhookSignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(signature, 'hex')
  )
}

// Express example
app.post('/webhooks/odento', (req, res) => {
  const signature = req.headers['x-odento-signature']
  const secret = process.env.ODENTO_WEBHOOK_SECRET

  if (!verifyWebhookSignature(req.rawBody, signature, secret)) {
    return res.status(401).send('Invalid signature')
  }

  const event = JSON.parse(req.rawBody)
  console.log('Received event:', event.event_type)

  // Process the event...
  res.status(200).send('OK')
})
POST/webhooks

Create a webhook

Creates a new webhook endpoint. You'll receive a signing secret in the response — use it to verify webhook signatures. The secret is shown only once at creation time.

Parameters

ParameterTypeRequiredDescription
urlstringRequiredHTTPS URL to receive webhook deliveries
eventsarrayRequiredArray of event types to subscribe to (e.g., ["appointment.created", "invoice.paid"])
descriptionstringOptionalHuman-readable description
activebooleanOptionalWhether the webhook is active. Default: true

Example Request

Requestbash
curl -X POST https://api.odento.app/api/v1/webhooks \
  -H "X-API-Key-ID: ok_live_abc123def456ghi789jkl012" \
  -H "X-API-Key-Secret: os_abc123def456ghi789jkl012mno345pqr678stu901vwx234yzab567" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://myapp.com/webhooks/odento",
    "events": ["appointment.created", "appointment.cancelled", "invoice.paid"],
    "description": "Production webhook for appointment and billing events"
  }'

Example Response

Response201json
{
  "success": true,
  "data": {
    "id": "wh_abc123def456ghi789",
    "url": "https://myapp.com/webhooks/odento",
    "events": ["appointment.created", "appointment.cancelled", "invoice.paid"],
    "description": "Production webhook for appointment and billing events",
    "signing_secret": "whsec_abc123def456ghi789jkl012mno345pqr678",
    "active": true,
    "created_at": "2025-01-15T10:30:00Z"
  }
}
GET/webhooks

List webhooks

Returns all webhook endpoints for your organization.

Parameters

ParameterTypeRequiredDescription
activebooleanOptionalFilter by active status
limitintegerOptionalResults per page (1-100). Default: 20

Example Request

Requestbash
curl -X GET https://api.odento.app/api/v1/webhooks \
  -H "X-API-Key-ID: ok_live_abc123def456ghi789jkl012" \
  -H "X-API-Key-Secret: os_abc123def456ghi789jkl012mno345pqr678stu901vwx234yzab567"

Example Response

Response200json
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "wh_abc123def456ghi789",
        "url": "https://myapp.com/webhooks/odento",
        "events": ["appointment.created", "appointment.cancelled", "invoice.paid"],
        "description": "Production webhook for appointment and billing events",
        "active": true,
        "last_delivered_at": "2025-01-22T10:05:00Z",
        "last_response_status": 200,
        "created_at": "2025-01-15T10:30:00Z"
      }
    ],
    "pagination": {
      "has_more": false,
      "next_cursor": null,
      "per_page": 20
    }
  }
}

Try It Out

API Playground
Headers
This is a simulated response — no real API calls are made from the browser.
GET/webhooks/{id}

Retrieve a webhook

Retrieves a single webhook endpoint by ID, including delivery statistics.

Parameters

ParameterTypeRequiredDescription
idstringRequiredThe webhook ID (wh_*)

Example Request

Requestbash
curl -X GET https://api.odento.app/api/v1/webhooks/wh_abc123def456ghi789 \
  -H "X-API-Key-ID: ok_live_abc123def456ghi789jkl012" \
  -H "X-API-Key-Secret: os_abc123def456ghi789jkl012mno345pqr678stu901vwx234yzab567"

Example Response

Response200json
{
  "success": true,
  "data": {
    "id": "wh_abc123def456ghi789",
    "url": "https://myapp.com/webhooks/odento",
    "events": ["appointment.created", "appointment.cancelled", "invoice.paid"],
    "description": "Production webhook for appointment and billing events",
    "active": true,
    "statistics": {
      "total_deliveries": 342,
      "successful": 338,
      "failed": 4,
      "last_24h": 18
    },
    "last_delivered_at": "2025-01-22T10:05:00Z",
    "last_response_status": 200,
    "created_at": "2025-01-15T10:30:00Z"
  }
}
PATCH/webhooks/{id}

Update a webhook

Updates a webhook endpoint's URL, events, or active status. To rotate the signing secret, use the rotate-secret endpoint.

Parameters

ParameterTypeRequiredDescription
idstringRequiredThe webhook ID (wh_*)
urlstringOptionalUpdated URL
eventsarrayOptionalUpdated event subscriptions
activebooleanOptionalUpdated active status
descriptionstringOptionalUpdated description

Example Request

Requestbash
curl -X PATCH https://api.odento.app/api/v1/webhooks/wh_abc123def456ghi789 \
  -H "X-API-Key-ID: ok_live_abc123def456ghi789jkl012" \
  -H "X-API-Key-Secret: os_abc123def456ghi789jkl012mno345pqr678stu901vwx234yzab567" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["appointment.created", "appointment.cancelled", "invoice.paid", "payment.received"],
    "active": true
  }'

Example Response

Response200json
{
  "success": true,
  "data": {
    "id": "wh_abc123def456ghi789",
    "url": "https://myapp.com/webhooks/odento",
    "events": ["appointment.created", "appointment.cancelled", "invoice.paid", "payment.received"],
    "active": true,
    "updated_at": "2025-01-22T12:00:00Z"
  }
}
DELETE/webhooks/{id}

Delete a webhook

Permanently deletes a webhook endpoint. Pending deliveries are cancelled. This action cannot be undone.

Parameters

ParameterTypeRequiredDescription
idstringRequiredThe webhook ID (wh_*)

Example Request

Requestbash
curl -X DELETE https://api.odento.app/api/v1/webhooks/wh_abc123def456ghi789 \
  -H "X-API-Key-ID: ok_live_abc123def456ghi789jkl012" \
  -H "X-API-Key-Secret: os_abc123def456ghi789jkl012mno345pqr678stu901vwx234yzab567"

Example Response

Response200json
{
  "success": true,
  "data": {
    "id": "wh_abc123def456ghi789",
    "deleted": true
  }
}
POST/webhooks/{id}/rotate-secret

Rotate signing secret

Generates a new signing secret for the webhook. The old secret immediately stops working. Update your verification logic before rotating.

Parameters

ParameterTypeRequiredDescription
idstringRequiredThe webhook ID (wh_*)

Example Request

Requestbash
curl -X POST https://api.odento.app/api/v1/webhooks/wh_abc123def456ghi789/rotate-secret \
  -H "X-API-Key-ID: ok_live_abc123def456ghi789jkl012" \
  -H "X-API-Key-Secret: os_abc123def456ghi789jkl012mno345pqr678stu901vwx234yzab567"

Example Response

Response200json
{
  "success": true,
  "data": {
    "id": "wh_abc123def456ghi789",
    "signing_secret": "whsec_new987xyz654abc321def098mno765pqr432",
    "rotated_at": "2025-01-22T12:30:00Z"
  }
}

Was this page helpful?

Help us improve our documentation