Webhooks
Receive real-time notifications when data changes in Untether.
Webhooks allow you to build or configure integrations which subscribe to certain events in the Untether app. When one of those events is triggered, we'll send a HTTP POST payload to the webhook's configured URL.
Getting Started We haven't launched the self-service Webhook UI yet. To set up your first endpoint or update your destination URL, please reach out to our team.
Delivery Guarantees#
Untether uses a robust queuing system to ensure your events are delivered reliably.
- At-least-once delivery: We guarantee that every event will be delivered to your endpoint at least once.
- Retries: If your server returns a non-2xx status code, we will retry delivery with exponential backoff.
- Idempotency: The
idfield in the payload is consistent across re-deliveries. You should use this ID to prevent processing the same event twice. - Ordering: Message ordering is NOT guaranteed. Because of the distributed nature of our system, a later event might arrive before an earlier one. Always use the
timestampfield to determine the correct sequence of events.
Event Payload#
All webhook events follow a standardized JSON structure.
idstringUnique identifier for the event. Consistent across re-deliveries.
typestringThe type of event triggered (e.g., v1.user.created).
timestampstringThe ISO-8601 timestamp of when the event occurred.
actorobjectproperties
idstringThe ID of the user who triggered the event. Will be system for automated actions.
type'user' | 'bot'namestringThe display name of the actor.
dataobjectThe actual event data. The schema depends on the type.
Verifying Webhook Authenticity#
To ensure that webhooks are genuinely coming from Untether, you must verify the signature included in the request headers.
Every request sent to your server will include the following headers:
| Header | Description |
|---|---|
user-agent | Untether-Webhook-Agent/1.0 |
x-unt-webhook-id | Unique ID for the delivery attempt. |
x-unt-webhook-signature | The HMAC SHA-256 signature used for verification. |
The x-unt-webhook-signature header contains a timestamp and one or more signatures. The timestamp is prefixed by t=, and each signature is prefixed by a scheme (e.g., v1=).
You can verify the signature by comparing it against the expected signature computed using your signing secret. If any of the signatures match, the request is authentic.
Format:
t=1709575424,v1=6a29...v1=7b30...
Language Examples#
const crypto = require('crypto');
function verifyWebhook(header, body, secret) {
const parts = header.split(',');
const timestamp = parts.find(p => p.startsWith('t=')).slice(2);
const signatures = parts.filter(p => p.startsWith('v1=')).map(p => p.slice(3));
const message = `${timestamp}.${body}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
return signatures.includes(expectedSignature);
}Secret Rotation#
We support zero-downtime secret rotation using a dual-key (Alpha/Beta) system.
- Preparation: We generate a Beta secret and begin signing webhooks with both the Alpha and Beta secrets. The header will contain two
v1signatures. - Update: You update your application to recognize the new secret.
- Completion: We promote the Beta secret to Alpha and remove the old secret. We return to signing with only one key.