Webhooks
Webhooks
Webhook subscription management and event fan-out. Register HTTPS endpoints to receive real-time notifications when events happen in your project — KV changes, channel messages, job completions, and more.
How it works: Create a webhook with one or more
topics. When a matching event fires, SaaSignal POSTs a signed JSON payload to your url. Failed deliveries are retried with exponential backoff. You can inspect delivery history and manually retry failures.Available Topics
Topics support exact match, * wildcard (all events), and prefix wildcards (e.g. jobs.* matches jobs.completed, jobs.failed, jobs.dead).
Topic
Fired when
Payload fields
kv.setA key-value pair is created or updated
key, value, ttl, expires_atkv.deleteA key is deleted
keychannels.publishedA message is published to a channel
channel, event, event_id, deliveredjobs.completedA job finishes successfully
job_id, name, run_id, attempt, resultjobs.failedA job fails but has retries remaining
job_id, name, run_id, attempt, error, retry_atjobs.deadA job exhausts all retry attempts
job_id, name, run_id, attempt, error, max_attemptsai.operation.completedAn async AI operation finishes successfully
operation_id, model, kindai.operation.failedAn async AI operation fails
operation_id, model, reasonai.index.createdA managed retrieval index is created
index_id, name, dimensionsai.index.deletedA managed retrieval index is deleted
index_idlogistics.geo.createdA geo entity is created
entity_id, type, namelogistics.geo.updatedA geo entity is updated
entity_idlogistics.geo.deactivatedA geo entity is deactivated
entity_idlogistics.geofence.createdA geofence is created
fence_id, name, typelogistics.geofence.deletedA geofence is deleted
fence_idlogistics.geofence.enteredA tracked entity enters a geofence
entity_id, fence_id, fence_name, lat, lnglogistics.geofence.exitedA tracked entity exits a geofence
entity_id, fence_id, fence_name, lat, lnglogistics.eta_fence.createdAn ETA fence is created
fence_id, name, dest_lat, dest_lng, threshold_minlogistics.eta_fence.deletedAn ETA fence is deleted
fence_idlogistics.eta_fence.breachEntity's driving ETA drops below threshold
entity_id, fence_id, fence_name, eta_min, threshold_min, lat, lng, dest_lat, dest_lnglogistics.eta_fence.clearedEntity's driving ETA rises above threshold
entity_id, fence_id, fence_name, eta_min, threshold_min, lat, lnglogistics.pingA tracking ping is received
entity_id, lat, lng, speed, headingdelivery.driver.onlineDriver goes online
driver_id, namedelivery.driver.offlineDriver goes offline
driver_id, namedelivery.order.assignedOrder assigned to driver
order_id, driver_iddelivery.order.acceptedDriver accepted order
order_id, driver_iddelivery.order.in_transitDriver in transit to pickup
order_id, driver_iddelivery.order.picked_upOrder picked up
order_id, driver_iddelivery.order.deliveredOrder delivered
order_id, driver_iddelivery.order.failedDelivery failed
order_id, driver_id, reasondelivery.order.cancelledOrder cancelled
order_iddelivery.zone.createdDelivery zone created
zone_id, namedelivery.zone.updatedDelivery zone updated
zone_iddelivery.zone.deletedDelivery zone deleted
zone_iddelivery.hub.updatedHub updated
hub_id, namedelivery.hub.deletedHub deleted
hub_idcustom.*User-published custom events via
POST /infra/webhooks/publishAny JSON payload
test.pingSent when testing a webhook
messagePayload envelope
All payloads are wrapped: { event_id, topic, timestamp, data: { ...fields } }. Deliveries include an HMAC-SHA256 signature in the X-Saasignal-Signature: sha256={hex} header.
Publish Event
GET
typescript
await ss.infra.webhooks.publish('custom.order.created', {
order_id: 'ord_123',
customer: 'cust_456',
})
- Use the SDK or API to publish custom events
- Topics must start with
custom.(e.g.custom.order.created) - All webhooks subscribed to a matching topic pattern will receive the event
Body field
Type
Description
topic requiredstring
Event topic. Must start with
custom. (e.g. custom.order.created). Max 256 chars.data requiredany
Arbitrary JSON payload to include in the webhook delivery. Max 64 KB.
Error responses
400 Topic does not start with <code>custom.</code>, invalid format, or payload exceeds 64 KB
401 Unauthorized
402 Insufficient Tokens
429 Rate Limited
Create Webhook
GET
typescript
await ss.infra.webhooks.create({
name: 'order-events',
url: 'https://app.acme.com/webhooks/saasignal',
topics: ['kv.set', 'jobs.*'],
secret: 'whsec_...',
})
- Open Dashboard and select your project
- Go to Webhooks in the sidebar
- Click Add Webhook
- Enter a name, endpoint URL, and select the topics to subscribe to
- Click Create
Body field
Type
Description
name requiredstring
Display name for this webhook (1–128 chars)
url requiredstring
HTTPS endpoint URL that receives webhook POST requests
secretstring
Signing secret for HMAC-SHA256 verification (16–256 chars). Auto-generated if omitted.
enabledboolean
Whether the webhook is active. Default
true.Error responses
400 Invalid body (validation error)
401 Unauthorized
402 Insufficient Tokens
429 Rate Limited
List Webhooks
GET
typescript
await ss.infra.webhooks.list()
- Open Dashboard and select your project
- Go to Webhooks to see all registered webhooks with their status and topics
Query param
Type
Description
limitinteger
Max results per page. Range 1–100, default
25.cursorstring
Pagination cursor from a previous response.
enabledboolean
Filter by enabled status.
Error responses
401 Unauthorized
402 Insufficient Tokens
429 Rate Limited
Get Webhook
GET
typescript
await ss.infra.webhooks.get('wh_01JNXS...')
- Open Dashboard and select your project
- Go to Webhooks and click on any webhook to view its details, secret, and delivery history
Path param
Type
Description
webhook_id requiredstring
Webhook ID
Error responses
401 Unauthorized
402 Insufficient Tokens
404 Not Found
429 Rate Limited
Update Webhook
GET
typescript
await ss.infra.webhooks.update('wh_01JNXS...', { enabled: false })
- Open Dashboard and select your project
- Go to Webhooks and click on the webhook
- Edit the URL, topics, or toggle enabled/disabled
- Click Save
Path param
Type
Description
webhook_id requiredstring
Webhook ID
Body field
Type
Description
namestring
Updated display name
urlstring
Updated HTTPS endpoint URL
topicsarray
Updated list of event topics
secretstring
Updated signing secret
enabledboolean
Enable or disable the webhook
Error responses
400 Invalid body (validation error)
401 Unauthorized
402 Insufficient Tokens
404 Not Found
429 Rate Limited
Delete Webhook
GET
typescript
await ss.infra.webhooks.delete('wh_01JNXS...')
- Open Dashboard and select your project
- Go to Webhooks and click on the webhook
- Click Delete to remove it
Path param
Type
Description
webhook_id requiredstring
Webhook ID
Error responses
401 Unauthorized
402 Insufficient Tokens
404 Not Found
429 Rate Limited
Test Webhook
GET
typescript
await ss.infra.webhooks.test('wh_01JNXS...')
- Open Dashboard and select your project
- Go to Webhooks and click on the webhook
- Click Test to send a
test.pingevent
Path param
Type
Description
webhook_id requiredstring
Webhook ID to send a
test.ping event toError responses
401 Unauthorized
402 Insufficient Tokens
404 Not Found
429 Rate Limited
List Deliveries
GET
typescript
await ss.infra.webhooks.listDeliveries('wh_01JNXS...')
- Open Dashboard and select your project
- Go to Webhooks and click on a webhook
- The Deliveries tab shows all delivery attempts with status, timing, and response codes
Path param
Type
Description
webhook_id requiredstring
Webhook ID
Query param
Type
Description
limitinteger
Max results per page. Default
25.cursorstring
Pagination cursor
statusstring
Filter by delivery status:
success or failedError responses
401 Unauthorized
402 Insufficient Tokens
404 Not Found
429 Rate Limited
Retry Delivery
GET
typescript
await ss.infra.webhooks.retryDelivery('wh_01JNXS...', 'dlv_01JNXS...')
- Open Dashboard and select your project
- Go to Webhooks → click on a webhook → Deliveries
- Click Retry next to a failed delivery
Path param
Type
Description
webhook_id requiredstring
Webhook ID
delivery_id requiredstring
Delivery ID to retry
Error responses
401 Unauthorized
402 Insufficient Tokens
404 Not Found
429 Rate Limited