Webhook endpoints
Tell WhatIsUp.dev where to deliver event notifications. One customer can have multiple endpoints (different URLs for different event subsets). One instance can be the source of events for multiple endpoints, and one endpoint can subscribe to multiple instances — they're a many-to-many.
Conceptual model
Endpoints describe a subscription: where to send, which events to send, and the signing secret used for the HMAC. The actual delivery records are in Webhook deliveries.
api_key → customer ──┬── instance ◄───┐
│ │
└── webhook_endpoint
│
└── webhook_delivery (per event)
List endpoints
Returns every endpoint owned by the authenticated customer.
Create an endpoint
| Field | Type | Required | Notes |
|---|---|---|---|
| url | string · URL | required | |
| events | array<`message.received` \| `message.sent` \| `instance.connected` \| `instance.disconnected` \| `qr.updated`> | required | |
| instance_id | string · uuid | optional | |
| signing_secret | string | optional | |
| enabled | boolean | optional |
curl -sX POST "$WHATISUP_API/v1/webhook-endpoints" \
-H "Authorization: Bearer $WHATISUP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://api.acme.dev/whatisup/webhook","events":["message.received","message.sent"],"instance_ids":["inst_01J..."]}'The response includes the signing secret in plaintext — only on this one call. Store it; we never show it again. (We can rotate it; we cannot recover it.)
| Field | Type | Required | Notes |
|---|---|---|---|
| id | string · uuid | required | |
| customer_id | string · uuid | required | |
| instance_id | string · uuid | required · nullable | |
| url | string · URL | required | |
| events | array<`message.received` \| `message.sent` \| `instance.connected` \| `instance.disconnected` \| `qr.updated`> | required | |
| enabled | boolean | required | |
| has_custom_signing_secret | boolean | required | |
| created_at | string · ISO 8601 | required | |
| updated_at | string · ISO 8601 | required |
The url is validated for SSRF at create time and at delivery time (DNS-rebind
defense). Loopback / link-local / RFC1918 / cloud-metadata IPs are rejected with
a 400. In production (NODE_ENV=production), only https:// is accepted.
Update an endpoint
| Field | Type | Required | Notes |
|---|---|---|---|
| url | string · URL | optional | |
| events | array<`message.received` \| `message.sent` \| `instance.connected` \| `instance.disconnected` \| `qr.updated`> | optional | |
| signing_secret | string \| unknown | optional | |
| enabled | boolean | optional |
You can rotate the signing secret by passing rotate_secret: true. The new secret is returned in the response body, exactly once. Old secret is invalidated immediately — verify the rollout before flipping it.
Delete an endpoint
Returns 204 No Content. In-flight deliveries (already in BullMQ) for this endpoint will fail to a non-existent target and exhaust their retry budget. If you need a hard stop, pause the queue first.