API documentation

Webhook endpoints, events and deliveries API

Manage webhook endpoints as code, re-read an event, list deliveries and replay one.

GET/v1/webhook-endpointswebhooks:manageThe API key needs the webhooks:manage permission. Without it the call is refused with 403 insufficient_scope.Sign in to try

Your webhook endpoints, and the IP addresses webhooks come from

Request
curl -X GET "https://api.iotabot.com/v1/webhook-endpoints" \
  -H "Authorization: Bearer $IOTABOT_API_KEY"
Response · 200
{
  "data": {
    "items": [
      {
        "id": "6a4bb0…",
        "object": "webhook_endpoint",
        "url": "https://crm.acme.com/iotabot",
        "description": "CRM",
        "channels": [
          "whatsapp"
        ],
        "events": [
          "message.received"
        ],
        "website_ids": [],
        "metadata_only": false,
        "test_events": false,
        "status": "active",
        "verified_at": "2026-10-01T09:00:00.000Z",
        "created_at": "2026-10-01T09:00:00.000Z"
      }
    ],
    "egress_ips": [
      "16.16.181.103"
    ]
  }
}
POST/v1/webhook-endpointswebhooks:manageThe API key needs the webhooks:manage permission. Without it the call is refused with 403 insufficient_scope.Sign in to try

Add an endpoint — verified straight away; the signing secret is returned once

The URL must answer the endpoint.verification event before it receives anything. metadataOnly: true sends ids and status without content or customer details; testEvents: true also sends sandbox events.

Request
curl -X POST "https://api.iotabot.com/v1/webhook-endpoints" \
  -H "Authorization: Bearer $IOTABOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://crm.acme.com/iotabot",
  "description": "CRM",
  "channels": [
    "whatsapp",
    "email"
  ],
  "events": [
    "message.received",
    "message.status"
  ],
  "metadataOnly": false,
  "testEvents": false
}'
Response · 201
{
  "data": {
    "id": "6a4bb0…",
    "object": "webhook_endpoint",
    "url": "https://crm.acme.com/iotabot",
    "status": "active",
    "secret": "whsec_…",
    "verification": {
      "verified": true,
      "reason": null
    }
  }
}
PATCH/v1/webhook-endpoints/{id}webhooks:manageThe API key needs the webhooks:manage permission. Without it the call is refused with 403 insufficient_scope.Sign in to try

Change URL (re-verifies), events, channels, websites or switch it on or off

Parameters
idrequiredIn the path
Request
curl -X PATCH "https://api.iotabot.com/v1/webhook-endpoints/ENDPOINT_ID" \
  -H "Authorization: Bearer $IOTABOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "events": [
    "message.received",
    "message.sent"
  ],
  "enabled": true
}'
Response · 200
{
  "data": {
    "id": "6a4b…",
    "events": [
      "message.received",
      "message.sent"
    ],
    "enabled": true
  }
}
DELETE/v1/webhook-endpoints/{id}webhooks:manageThe API key needs the webhooks:manage permission. Without it the call is refused with 403 insufficient_scope.Sign in to try

Delete an endpoint — deliveries still retrying are dropped

Parameters
idrequiredIn the path
Request
curl -X DELETE "https://api.iotabot.com/v1/webhook-endpoints/ENDPOINT_ID" \
  -H "Authorization: Bearer $IOTABOT_API_KEY"
Response · 200
{
  "data": {
    "id": "6a4bb0…",
    "deleted": true
  }
}
POST/v1/webhook-endpoints/{id}/roll-secretwebhooks:manageThe API key needs the webhooks:manage permission. Without it the call is refused with 403 insufficient_scope.Sign in to try

New signing secret; the old one keeps co-signing for grace_hours (0–168)

Parameters
idrequiredIn the path
Request
curl -X POST "https://api.iotabot.com/v1/webhook-endpoints/ENDPOINT_ID/roll-secret" \
  -H "Authorization: Bearer $IOTABOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "grace_hours": 24
}'
Response · 200
{
  "data": {
    "id": "6a4b…",
    "grace_hours": 24
  }
}
GET/v1/events/{id}Sign in to try

Re-read a webhook event — the same envelope your endpoint received

Parameters
idrequiredIn the path — evt_…
Request
curl -X GET "https://api.iotabot.com/v1/events/EVENT_ID" \
  -H "Authorization: Bearer $IOTABOT_API_KEY"
Response · 200
{
  "data": {
    "ok": true
  }
}
Errors
event_not_found
GET/v1/webhook-deliverieswebhooks:manageThe API key needs the webhooks:manage permission. Without it the call is refused with 403 insufficient_scope.Sign in to try

Webhook delivery log, newest first

Parameters
endpoint_idQuery
statusQuery — pending, retrying, succeeded, failed
limitQuery
starting_afterQuery
Request
curl -X GET "https://api.iotabot.com/v1/webhook-deliveries" \
  -H "Authorization: Bearer $IOTABOT_API_KEY"
Response · 200
{
  "data": {
    "items": [
      {
        "id": "whd_6a4ba2…",
        "object": "webhook_delivery",
        "endpoint_id": "6a4ba3…",
        "event_id": "evt_6a4ba4…",
        "event_type": "message.received",
        "status": "succeeded",
        "attempts": 1,
        "last_response_status": 200,
        "last_error": null,
        "next_attempt_at": null,
        "replay_of": null,
        "created_at": "2026-10-01T09:15:03.100Z"
      }
    ],
    "has_more": false,
    "next_cursor": null
  }
}
POST/v1/webhook-deliveries/{id}/replaywebhooks:manageThe API key needs the webhooks:manage permission. Without it the call is refused with 403 insufficient_scope.Sign in to try

Send a delivery's event to its endpoint again

Parameters
idrequiredIn the path — whd_…
Request
curl -X POST "https://api.iotabot.com/v1/webhook-deliveries/DELIVERY_ID/replay" \
  -H "Authorization: Bearer $IOTABOT_API_KEY"
Response · 202
{
  "data": {
    "ok": true
  }
}
Errors
endpoint_disabledevent_expired