Documentation Index
Fetch the complete documentation index at: https://orbit-docs.devotel.io/llms.txt
Use this file to discover all available pages before exploring further.
Webhooks API
Register HTTP endpoints to receive real-time event notifications from Orbit. Webhooks are signed with HMAC-SHA256 and delivered with automatic retries.
Base path: /v1/webhooks
Create Webhook Endpoint
POST /v1/webhooks
Register a new webhook endpoint to receive events.
The HTTPS URL where events will be delivered
Array of event types to subscribe to (e.g., message.delivered, message.failed, call.completed)
Human-readable description for this endpoint
curl -X POST "https://orbit-api.devotel.io/api/v1/webhooks" \
-H "X-API-Key: dv_live_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/orbit",
"events": [
"message.delivered",
"message.failed",
"call.completed"
],
"description": "Production webhook receiver"
}'
import { Orbit } from '@devotel/orbit-sdk'
const orbit = new Orbit({
apiKey: process.env.ORBIT_API_KEY!,
})
const res = await fetch('https://orbit-api.devotel.io/api/v1/webhooks', {
method: 'POST',
headers: {
'X-API-Key': process.env.ORBIT_API_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"url": "https://example.com/webhooks/orbit",
"events": [
"message.delivered",
"message.failed",
"call.completed"
],
"description": "Production webhook receiver"
}),
})
console.log(await res.json())
import os, requests
headers = {"X-API-Key": os.environ["ORBIT_API_KEY"]}
headers["Content-Type"] = "application/json"
r = requests.post("https://orbit-api.devotel.io/api/v1/webhooks", headers=headers, json={
"url": "https://example.com/webhooks/orbit",
"events": [
"message.delivered",
"message.failed",
"call.completed"
],
"description": "Production webhook receiver"
})
print(r.json())
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("POST", "https://orbit-api.devotel.io/api/v1/webhooks", bytes.NewBuffer([]byte(`{
"url": "https://example.com/webhooks/orbit",
"events": [
"message.delivered",
"message.failed",
"call.completed"
],
"description": "Production webhook receiver"
}`)))
req.Header.Set("X-API-Key", os.Getenv("ORBIT_API_KEY"))
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
require 'net/http'
require 'json'
uri = URI('https://orbit-api.devotel.io/api/v1/webhooks')
req = Net::HTTP::Post.new(uri)
req['X-API-Key'] = ENV['ORBIT_API_KEY']
req['Content-Type'] = 'application/json'
req.body = {
"url": "https://example.com/webhooks/orbit",
"events": [
"message.delivered",
"message.failed",
"call.completed"
],
"description": "Production webhook receiver"
}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.body
<?php
$ch = curl_init('https://orbit-api.devotel.io/api/v1/webhooks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . getenv('ORBIT_API_KEY'),
'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, <<<JSON
{
"url": "https://example.com/webhooks/orbit",
"events": [
"message.delivered",
"message.failed",
"call.completed"
],
"description": "Production webhook receiver"
}
JSON);
echo curl_exec($ch);
{
"data": {
"id": "wh_abc123",
"url": "https://example.com/webhooks/orbit",
"events": ["message.delivered", "message.failed", "call.completed"],
"description": "Production webhook receiver",
"active": true,
"signing_secret": "whsec_abc123...",
"created_at": "2026-03-08T12:00:00Z"
},
"meta": {
"request_id": "req_wh_001",
"timestamp": "2026-03-08T12:00:00Z"
}
}
The signing_secret is only returned once — when the endpoint is created. Store it securely. You’ll need it to verify the X-Devotel-Signature header on incoming webhook deliveries.
List Webhook Endpoints
GET /v1/webhooks
Retrieve all registered webhook endpoints with cursor-based pagination.
Number of results per page (max 100)
Get Webhook Endpoint
GET /v1/webhooks/{id}
Retrieve a single webhook endpoint by ID.
Webhook endpoint ID (e.g., wh_abc123)
Update Webhook Endpoint
PUT /v1/webhooks/{id}
Update an endpoint’s URL, subscribed events, active status, or description.
Updated event subscriptions (replaces existing list)
Set to false to temporarily disable delivery without deleting the endpoint
Delete Webhook Endpoint
DELETE /v1/webhooks/{id}
Permanently remove a webhook endpoint. Pending deliveries are cancelled.
Response: 204 No Content
Test Webhook Endpoint
POST /v1/webhooks/{id}/test
Send a test event to a webhook endpoint. The test payload is a webhook.test event with sample data. Use this to verify your endpoint is reachable and processing events correctly.
curl -X POST "https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/test" \
-H "X-API-Key: dv_live_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{}'
import { Orbit } from '@devotel/orbit-sdk'
const orbit = new Orbit({
apiKey: process.env.ORBIT_API_KEY!,
})
const res = await fetch('https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/test', {
method: 'POST',
headers: {
'X-API-Key': process.env.ORBIT_API_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
})
console.log(await res.json())
import os, requests
headers = {"X-API-Key": os.environ["ORBIT_API_KEY"]}
headers["Content-Type"] = "application/json"
r = requests.post("https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/test", headers=headers, json={})
print(r.json())
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("POST", "https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/test", bytes.NewBuffer([]byte(`{}`)))
req.Header.Set("X-API-Key", os.Getenv("ORBIT_API_KEY"))
req.Header.Set("Content-Type", "application/json")
http.DefaultClient.Do(req)
}
require 'net/http'
require 'json'
uri = URI('https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/test')
req = Net::HTTP::Post.new(uri)
req['X-API-Key'] = ENV['ORBIT_API_KEY']
req['Content-Type'] = 'application/json'
req.body = {}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.body
<?php
$ch = curl_init('https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/test');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . getenv('ORBIT_API_KEY'),
'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, <<<JSON
{}
JSON);
echo curl_exec($ch);
{
"data": {
"success": true,
"response_status": 200,
"response_time_ms": 145,
"delivered_at": "2026-03-08T12:00:00Z"
},
"meta": {
"request_id": "req_test_001",
"timestamp": "2026-03-08T12:00:00Z"
}
}
List Deliveries
GET /v1/webhooks/{id}/deliveries
Retrieve the delivery log for a specific webhook endpoint. Each entry shows the HTTP status, response time, retry count, and whether delivery succeeded.
Number of results per page (max 100)
curl -X GET "https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/deliveries?limit=5" \
-H "X-API-Key: dv_live_sk_your_key_here"
import { Orbit } from '@devotel/orbit-sdk'
const orbit = new Orbit({
apiKey: process.env.ORBIT_API_KEY!,
})
const res = await fetch('https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/deliveries?limit=5', {
method: 'GET',
headers: {
'X-API-Key': process.env.ORBIT_API_KEY!,
},
})
console.log(await res.json())
import os, requests
headers = {"X-API-Key": os.environ["ORBIT_API_KEY"]}
r = requests.get("https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/deliveries?limit=5", headers=headers)
print(r.json())
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/deliveries?limit=5", nil)
req.Header.Set("X-API-Key", os.Getenv("ORBIT_API_KEY"))
http.DefaultClient.Do(req)
}
require 'net/http'
require 'json'
uri = URI('https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/deliveries?limit=5')
req = Net::HTTP::Get.new(uri)
req['X-API-Key'] = ENV['ORBIT_API_KEY']
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.body
<?php
$ch = curl_init('https://orbit-api.devotel.io/api/v1/webhooks/wh_abc123/deliveries?limit=5');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-API-Key: ' . getenv('ORBIT_API_KEY'),
]);
echo curl_exec($ch);
{
"data": [
{
"id": "dlv_001",
"event_type": "message.delivered",
"event_id": "evt_abc123",
"status": "success",
"http_status": 200,
"response_time_ms": 92,
"attempt": 1,
"delivered_at": "2026-03-08T11:30:00Z"
},
{
"id": "dlv_002",
"event_type": "message.failed",
"event_id": "evt_def456",
"status": "failed",
"http_status": 500,
"response_time_ms": 30012,
"attempt": 6,
"next_retry_at": null,
"delivered_at": "2026-03-08T10:00:00Z"
}
],
"meta": {
"request_id": "req_dlv_001",
"timestamp": "2026-03-08T12:00:00Z",
"pagination": {
"cursor": "cur_dlv_abc",
"has_more": true
}
}
}
Delivery Retry Schedule
Orbit retries failed webhook deliveries on this schedule:
| Attempt | Delay after previous |
|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 8 hours |
| 7 | 24 hours |
After all retries are exhausted, the event is moved to a dead letter queue. Events in the DLQ can be viewed in the dashboard.
Signature Verification
Every webhook delivery includes an X-Devotel-Signature header containing an HMAC-SHA256 signature. Verify it using your endpoint’s signing_secret:
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
See Webhook Security for full implementation details.