API Reference
Webhooks
Subscribe to events. We POST a signed JSON payload to your URL within seconds. Retries are automatic with exponential backoff if your endpoint doesn't respond 2xx.
Create a webhook
/v1/webhooksRegister a URL to receive event deliveries.
{"url": "https://your-app.com/webhooks/bluereplies","events": ["message.inbound", "message.delivered", "message.read"]}
| Field | Type | Description |
|---|---|---|
urlrequired | string | HTTPS URL we will POST to. Must respond in < 30s. |
eventsrequired | string[] | Array of event types to subscribe to. See list below. |
isActive | booleandefault true | Disable temporarily without deleting. |
Response includes a signingSecret — store it. You'll use it to verify every delivery.
The delivery payload
Every delivery looks like this:
{"event": "message.delivered","timestamp": "2026-05-25T17:23:15.812Z","deliveryId": "wdl_…","data": {"messageId": "msg_pq3z9Vc7BmHkLxQ1aWoZP","from": "+12138765278","to": "+15551234567","lineId": "lin_a802426485c04055f82cafd3","deliveredAt": "2026-05-25T17:23:15.812Z"}}
Headers we send: x-bluereplies-signature (HMAC-SHA256 hex), x-bluereplies-event (event name), x-bluereplies-delivery-id (idempotency key for the delivery itself).
Verify the signature
Always verify x-bluereplies-signature against the raw request body using your signing secret. Reject anything that doesn't match — it's the only way to know the payload is really from us.
import crypto from 'node:crypto';export function verifyWebhook(req, signingSecret) {const sig = req.headers['x-bluereplies-signature'];if (!sig) return false;const expected = crypto.createHmac('sha256', signingSecret).update(req.rawBody) // raw bytes BEFORE JSON.parse!.digest('hex');return crypto.timingSafeEqual(Buffer.from(sig, 'hex'),Buffer.from(expected, 'hex'),);}
Use raw request body, not the parsed JSON
express.raw({ type: 'application/json' }) for the webhook route.Retries
If your endpoint returns anything but a 2xx status code (or times out after 30s), we retry with exponential backoff:
Attempt 1 — immediateAttempt 2 — 30 seconds laterAttempt 3 — 2 minutes laterAttempt 4 — 10 minutes laterAttempt 5 — 1 hour laterAttempt 6 — 6 hours laterAttempt 7 — 24 hours later (final)
We use the same deliveryId across retries. Make your handler idempotent by checking + storing the deliveryId.
POST /v1/webhooks/:id/deliveries/:did/replay.Event catalogue
Subscribe to any combination of these events:
Messages
message.inboundAn iMessage was received from a recipient.message.sentOutbound message left our line and is in flight.message.deliveredApple confirmed delivery to the recipient device.message.readRecipient read receipt fired (if they have read receipts on).message.failedSend failed. Payload includes the error reason.message.editedA previously-sent message was edited.message.unsentA previously-sent message was unsent.message.reactionA tapback/reaction was added or removed.message.typingRecipient is typing (or stopped typing).
Messages — fallback
message.fallbackFired when an iMessage send fell back to SMS (recipient not on iMessage).
Calls
call.initiatedFaceTime call placed.call.ringingRecipient device is ringing.call.connectedRecipient accepted the call.call.completedCall ended normally; includes durationSeconds.call.no_answerCall timed out without being answered.call.failedCall failed to connect.
Lines
line.status_changedLine transitioned between active / degraded / inactive / error.line.ban_detectedHeuristic flagged the line as likely banned (consecutive failures).line.ban_recoveredLine returned to healthy state from suspected ban.
Groups
group.createdNew group chat created.group.renamedGroup name was updated.group.member_addedA participant was added.group.member_removedA participant was removed (or left).
Contacts
contact.opted_outA recipient was added to your opt-out list (auto-detection or manual).
Workflows + campaigns
workflow.node_executedA workflow node executed for an enrollment.workflow.completedWorkflow run reached an end node.workflow.failedWorkflow run errored out.campaign.step_sentA step in a campaign sequence sent.campaign.completedCampaign sequence finished for one contact.
Manage webhooks
/v1/webhooksList your registered webhooks.
/v1/webhooks/:idUpdate URL, events, or active flag.
/v1/webhooks/:idRemove a webhook permanently.
/v1/webhooks/:id/deliveriesRecent delivery attempts with status, response code, latency.