Webhooks are essential for building reliable integrations that respond to
asynchronous events. Rather than continuously polling for updates, webhooks
push data to your application in real-time.
Overview
Webhooks enable you to:- React to events instantly: Get notified the moment something happens in your Nomos account
- Reduce polling: No need to continuously check for updates via API calls
- Build asynchronous workflows: Handle long-running processes without blocking user interactions
Getting started
- Set up an endpoint: Create an HTTPS endpoint in your application to receive webhook
POSTrequests - Register your endpoint: Access your dashboard to register your webhook URL and receive a webhook secret
- Verify signatures: Always validate incoming requests using the provided signature verification
- Process events: Handle the event data based on the
topicfield - Respond quickly: Return a
2xxstatus code within 30 seconds
Security
Signature verification
Every webhook request includes anX-Nomos-Signature header containing an HMAC-SHA256 signature. Always verify this signature to ensure the request is authentic and from Nomos.
Never process webhook events without verifying the signature first. This
protects against unauthorized requests and tampering.
Signature format
The signature header follows this format:t= Unix timestamp (seconds) when the webhook was sentv1= HMAC-SHA256 signature (hex-encoded)
How signatures are computed
Nomos generates signatures using HMAC-SHA256:- The timestamp (in seconds)
- A period (
.) separator - The JSON-stringified request body
Preventing replay attacks
Nomos includes a timestamp in each webhook signature to prevent replay attacks. The timestamp is part of the signed payload, so attackers cannot modify it without invalidating the signature. Recommended tolerance: We recommend rejecting webhook signatures older than 5 minutes (based on thet value)
When verifying signatures, you should set a tolerance window that protects against:
- Old webhook events being replayed by attackers
- Clock skew between servers
- Network delays
You can adjust the tolerance window based on your security requirements, but
never disable it entirely (setting it to 0) as this removes replay attack
protection.
Event structure
All webhook events follow a consistent structure:| Field | Type | Description |
|---|---|---|
id | string | Unique event identifier (starts with evt_) |
timestamp | string | ISO 8601 timestamp when the event was created |
topic | string | Event type identifier (e.g., subscription.created) |
context | object | Event-specific data containing relevant resource IDs |
context values returned, refer to the events endpoint.
Event topics
Nomos currently supports the following webhook events:| Event Topic | Context Fields | Description |
|---|---|---|
subscription.created | subscription, lead (optional) | A new subscription has been created |
subscription.confirmed | subscription | A subscription has been confirmed - can happen multiple times when the start date changes |
All event topics follow the format
resource.action (e.g.,
subscription.created, invoice.finalized). The context object contains IDs
of relevant resources that you can use to fetch additional details via the
API.Response requirements
Timeout and expected response
Your webhook endpoint must:- Respond within 30 seconds or the request will timeout
- Return a
2xxstatus code (e.g.,200,201,204) to acknowledge successful receipt - Not perform long-running operations before responding
If your endpoint doesn’t respond with a
2xx status within 30 seconds, Nomos
considers the delivery failed and will retry according to the exponential
backoff schedule.Best practice: Respond immediately
The recommended pattern is to:- Verify the signature
- Store the event or queue it for processing
- Return a
2xxresponse immediately - Process the event asynchronously
Delivery and retries
Automatic retry strategy
If your endpoint returns a non-2xx status code or times out, Nomos automatically retries delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | 1 minute |
| 2 | 2 minutes |
| 3 | 4 minutes |
| 4 | 8 minutes |
| 5 | 16 minutes |
| 6 | 32 minutes |
| 7 | 1 hour |
| 8 | 2 hours |
| 9 | 4 hours |
| 10 | 8 hours |
| 11 | 16 hours |
| 12 | 32 hours |
2xx response or after all retry attempts are exhausted.
Handling duplicate events
Due to retries and network conditions, your endpoint may occasionally receive the same event multiple times. Your implementation should be idempotent. Recommended approaches:- Store processed event IDs in a database and skip duplicates
- Use the event ID as an idempotency key in your system
- Design handlers that can safely process the same event multiple times
Event ordering
Nomos does not guarantee that events will be delivered in the order they
were generated.
subscription.confirmedbeforesubscription.createdinvoice.finalizedbeforesubscription.confirmed
- Design webhook handlers to process events independently
- Use the
timestampfield to determine event order if needed - Query the API for the current state of resources
- Use event IDs to track which events you’ve processed