Webhooks
Receive real-time notifications for marketplace events via HTTP callbacks.
Overview
Webhooks allow your application to receive automatic notifications when events occur in Automatum. Instead of polling the API, webhooks push data to your endpoint as events happen.
How delivery is handled
You create and configure webhook endpoints through Automatum, but the actual delivery of events — signing requests, retrying failures, and applying backoff — is performed by Automatum’s webhook delivery service, a separate downstream component. The behavior described below (the signature scheme, retry policy, and auto-disable thresholds) reflects that delivery service.
How Webhooks Work
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Event │────▶│ Automatum │────▶│ Your │
│ Occurs │ │ Webhook │ │ Endpoint │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ Retry if │
│ Failed │
└─────────────┘- Event occurs in Automatum (e.g., offer accepted)
- The webhook delivery service sends an HTTP POST to your endpoint
- Your endpoint processes the event
- Returns 2xx status to acknowledge receipt
- If failed, the delivery service retries with exponential backoff
Setting Up Webhooks
Create Webhook Endpoint
- Navigate to Settings > Webhooks
- Click Add Webhook
- Configure:
- Endpoint URL: Your HTTPS endpoint
- Description: Human-readable name
- Events: Select events to subscribe
- Secret: Auto-generated signing secret
- Click Create Webhook
Endpoint Requirements
Your webhook endpoint must:
- Accept HTTP POST requests
- Use HTTPS (SSL/TLS required)
- Respond promptly (the delivery service enforces a request timeout)
- Return 2xx status code on success
- Be publicly accessible
Example Endpoint (Node.js)
javascript
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.AUTOMATUM_WEBHOOK_SECRET;
app.post('/webhooks/automatum', (req, res) => {
// Verify signature
const signature = req.headers['x-automatum-signature'];
const payload = JSON.stringify(req.body);
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
if (signature !== `sha256=${expectedSignature}`) {
return res.status(401).send('Invalid signature');
}
// Process event
const event = req.body;
console.log('Received event:', event.type);
switch (event.type) {
case 'entitlement.created':
handleEntitlementCreated(event.data);
break;
case 'entitlement.updated':
handleEntitlementUpdated(event.data);
break;
case 'private_offer.accepted':
handleOfferAccepted(event.data);
break;
case 'metering.failed':
handleMeteringFailed(event.data);
break;
// Handle other events...
}
// Acknowledge receipt
res.status(200).json({ received: true });
});
app.listen(3000);Example Endpoint (Python)
python
from flask import Flask, request, jsonify
import hmac
import hashlib
import os
app = Flask(__name__)
WEBHOOK_SECRET = os.environ['AUTOMATUM_WEBHOOK_SECRET']
def verify_signature(payload, signature):
expected = hmac.new(
WEBHOOK_SECRET.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f'sha256={expected}', signature)
@app.route('/webhooks/automatum', methods=['POST'])
def webhook():
signature = request.headers.get('X-Automatum-Signature')
if not verify_signature(request.data, signature):
return jsonify({'error': 'Invalid signature'}), 401
event = request.json
print(f"Received event: {event['type']}")
# Process event based on type
if event['type'] == 'entitlement.created':
handle_entitlement_created(event['data'])
elif event['type'] == 'private_offer.accepted':
handle_offer_accepted(event['data'])
elif event['type'] == 'metering.failed':
handle_metering_failed(event['data'])
return jsonify({'received': True}), 200
if __name__ == '__main__':
app.run(port=3000)Webhook Events
The type field is a free-form string; the API does not constrain it to a fixed enum. The only event type demonstrably emitted from within this API is webhook.test (sent by the Send Test Event action). The business-event catalog below (entitlement.*, private_offer.*, customer.*, metering.*) is defined and emitted by Automatum’s webhook delivery service, so treat these names as the delivery service’s contract rather than a guarantee from the API itself.
Test Events
| Event | Description |
|---|---|
webhook.test | Sent when you use Send Test Event to verify your endpoint |
Entitlement Events
| Event | Description |
|---|---|
entitlement.created | New entitlement/contract created |
entitlement.updated | Entitlement details updated |
entitlement.renewed | Entitlement was renewed |
entitlement.cancelled | Entitlement was cancelled |
Private Offer Events
| Event | Description |
|---|---|
private_offer.created | New private offer created |
private_offer.accepted | Customer accepted offer |
Customer Events
| Event | Description |
|---|---|
customer.created | New customer registered |
customer.updated | Customer info updated |
Metering Events
| Event | Description |
|---|---|
metering.submitted | Usage report submitted |
metering.confirmed | Marketplace confirmed receipt |
metering.failed | Usage report failed |
Webhook Payload
Payload Structure
json
{
"id": "evt_1234567890",
"type": "private_offer.accepted",
"created": "2026-01-16T10:30:00Z",
"data": {
"id": "offer_abc123",
"customerId": "cust_xyz789",
"listingId": "listing_456",
"vendor": "aws",
"value": 50000,
"duration": 12,
"acceptedAt": "2026-01-16T10:30:00Z"
},
"organizationId": "org_123"
}Common Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique event identifier |
type | string | Event type |
created | string | ISO 8601 timestamp |
data | object | Event-specific data |
organizationId | string | Your organization ID |
Event-Specific Data
entitlement.created:
json
{
"id": "ent_abc123",
"customerId": "cust_xyz789",
"listingId": "listing_456",
"details": {
"subscriptionStatus": "subscribed",
"entries": [
{
"name": "enterprise",
"units": 1,
"price": ""
}
],
"expiration": "2027-01-31T00:00:00Z",
"startDate": "2026-01-16T10:30:00Z"
}
}private_offer.accepted:
json
{
"id": "offer_abc123",
"listingId": "listing_456",
"vendorOfferId": "offer-123456",
"status": "accepted",
"details": {
"summary": {
"offerName": "Enterprise Deal",
"customerName": "Acme Corporation"
}
}
}metering.failed:
json
{
"id": "meter_abc123",
"listingId": "listing_456",
"customerId": "cust_xyz789",
"status": "failed",
"message": "Error message from marketplace",
"details": {
"reportingDate": "2026-01-16",
"usages": []
}
}Security
Signature Verification
The webhook delivery service signs every request with an HMAC-SHA256 signature over the payload, using your webhook secret, and sends it in a header:
X-Automatum-Signature: sha256=abc123...Always verify signatures to ensure requests are from Automatum. Because signing is performed by the delivery service, verify against the secret shown for your webhook in the dashboard.
Verification Code
javascript
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expectedSignature}`)
);
}Security Best Practices
- Always verify signatures - Never trust unverified requests
- Use HTTPS - Encrypt data in transit
- Rotate secrets - Periodically regenerate webhook secrets
- Validate data - Check payload structure and types
- Idempotency - Handle duplicate deliveries gracefully
Retry Policy
Retries and backoff are handled by Automatum’s webhook delivery service, not by this API. The delivery service is designed for reliable delivery with the following behavior:
- Automatic retries: Failed deliveries are retried with exponential backoff
- Request timeout: Each delivery attempt is subject to a request timeout
- Failure tracking: Consecutive failures are counted per webhook
- Auto-disable: A webhook is disabled after a number of consecutive failures
- Manual retry: Disabled webhooks can be re-enabled and retried from the dashboard
Exact timeout, backoff intervals, and failure thresholds are governed by the delivery service and may change; do not rely on specific values.
Managing Webhooks
View Webhook Logs
- Go to Settings > Webhooks
- Click on webhook endpoint
- View Delivery Logs
Log details include:
- Timestamp
- Event type
- Request payload
- Response status
- Response body
- Duration
Test Webhooks
Send test events to verify setup:
- Go to Settings > Webhooks
- Click on webhook endpoint
- Click Send Test Event
- Select event type
- Review delivery result
Disable/Enable Webhooks
Temporarily disable without deleting:
- Go to webhook settings
- Toggle Enabled switch
- Webhook paused (events not sent)
Delete Webhooks
Remove webhook permanently:
- Go to webhook settings
- Click Delete Webhook
- Confirm deletion
WARNING
Deleting a webhook stops all event delivery immediately. Events during downtime are not recoverable.
Webhook IP Addresses
If you need to whitelist IPs, Automatum webhooks originate from:
52.XX.XX.XX
52.XX.XX.XX
54.XX.XX.XXTIP
Contact support@automatum.io for current IP ranges.
Best Practices
1. Respond Quickly
Return 200 immediately, process async (must respond within 10 seconds):
javascript
app.post('/webhook', async (req, res) => {
// Acknowledge immediately
res.status(200).send('OK');
// Process asynchronously
processEventAsync(req.body);
});2. Handle Duplicates
Events may be delivered more than once:
javascript
const processedEvents = new Set();
function handleEvent(event) {
if (processedEvents.has(event.id)) {
return; // Already processed
}
processedEvents.add(event.id);
// Process event...
}3. Use Queues
For reliability, queue events for processing:
javascript
const Queue = require('bull');
const webhookQueue = new Queue('webhooks');
app.post('/webhook', (req, res) => {
webhookQueue.add(req.body);
res.status(200).send('OK');
});
webhookQueue.process(async (job) => {
await processEvent(job.data);
});4. Log Everything
Maintain detailed logs for debugging:
javascript
function handleWebhook(event) {
console.log({
eventId: event.id,
type: event.type,
receivedAt: new Date().toISOString(),
data: event.data
});
}5. Monitor Health
Track webhook delivery metrics:
- Success rate
- Average response time
- Error patterns
- Retry frequency
Troubleshooting
Not Receiving Webhooks
- Verify endpoint URL is correct
- Check endpoint is publicly accessible
- Confirm HTTPS certificate is valid
- Review firewall/security rules
- Check webhook is enabled
Signature Verification Failing
- Verify using correct secret
- Check payload encoding (UTF-8)
- Ensure no middleware modifies body
- Verify signature header name
Timeouts
- Respond promptly (the delivery service enforces a request timeout)
- Process async after acknowledging
- Check endpoint performance
- Review server resources
Missing Events
- Check event types are subscribed
- Review webhook logs
- Verify endpoint returned 2xx
- Check for filtered events
API Reference
::: note Webhook Management Webhook management endpoints are available through the Automatum dashboard. The webhook API routes are internal and not part of the public OAuth API (/api/v1/*). To manage webhooks, use the dashboard at Settings > Webhooks. :::
Webhook Management via Dashboard
- Create Webhook: Navigate to Settings > Webhooks > Add Webhook
- List Webhooks: View all webhooks in Settings > Webhooks
- Update Webhook: Click on a webhook to edit its configuration
- Delete Webhook: Click Delete on the webhook details page
- Test Webhook: Click Send Test Event to verify your endpoint
Webhook Configuration
When creating or updating a webhook, you can configure:
- Name: Human-readable identifier
- Description: Optional description
- URL: HTTPS endpoint URL (required)
- Events: Array of event types to subscribe to (at least one required)
- Secret: Optional signing secret for signature verification
- Active Status: Enable/disable webhook delivery
Next Steps
Need Help?
Contact support@automatum.io for webhook assistance.