Skip to content

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 Webhooks Work

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Event      │────▶│  Automatum  │────▶│  Your       │
│  Occurs     │     │  Webhook    │     │  Endpoint   │
└─────────────┘     └─────────────┘     └─────────────┘


                    ┌─────────────┐
                    │  Retry if   │
                    │  Failed     │
                    └─────────────┘
  1. Event occurs in Automatum (e.g., offer accepted)
  2. Automatum sends HTTP POST to your endpoint
  3. Your endpoint processes the event
  4. Returns 2xx status to acknowledge receipt
  5. If failed, Automatum retries with exponential backoff

Setting Up Webhooks

Create Webhook Endpoint

  1. Navigate to Settings > Webhooks
  2. Click Add Webhook
  3. Configure:
    • Endpoint URL: Your HTTPS endpoint
    • Description: Human-readable name
    • Events: Select events to subscribe
    • Secret: Auto-generated signing secret
  4. Click Create Webhook

Endpoint Requirements

Your webhook endpoint must:

  • Accept HTTP POST requests
  • Use HTTPS (SSL/TLS required)
  • Respond within 10 seconds (timeout enforced)
  • 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

Entitlement Events

EventDescription
entitlement.createdNew entitlement/contract created
entitlement.updatedEntitlement details updated
entitlement.renewedEntitlement was renewed
entitlement.cancelledEntitlement was cancelled

Private Offer Events

EventDescription
private_offer.createdNew private offer created
private_offer.acceptedCustomer accepted offer

Customer Events

EventDescription
customer.createdNew customer registered
customer.updatedCustomer info updated

Metering Events

EventDescription
metering.submittedUsage report submitted
metering.confirmedMarketplace confirmed receipt
metering.failedUsage 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

FieldTypeDescription
idstringUnique event identifier
typestringEvent type
createdstringISO 8601 timestamp
dataobjectEvent-specific data
organizationIdstringYour 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

Every webhook request includes a signature header:

X-Automatum-Signature: sha256=abc123...

Always verify signatures to ensure requests are from Automatum.

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

  1. Always verify signatures - Never trust unverified requests
  2. Use HTTPS - Encrypt data in transit
  3. Rotate secrets - Periodically regenerate webhook secrets
  4. Validate data - Check payload structure and types
  5. Idempotency - Handle duplicate deliveries gracefully

Retry Policy

Webhook delivery uses AWS SQS for reliable message delivery with automatic retries:

  • SQS Retry Mechanism: Failed deliveries are automatically retried by SQS with exponential backoff
  • Failure Tracking: Each webhook tracks failure count
  • Auto-Disable: Webhooks are automatically disabled after 10 consecutive failures
  • Manual Retry: Disabled webhooks can be re-enabled and retried from the dashboard

Managing Webhooks

View Webhook Logs

  1. Go to Settings > Webhooks
  2. Click on webhook endpoint
  3. View Delivery Logs

Log details include:

  • Timestamp
  • Event type
  • Request payload
  • Response status
  • Response body
  • Duration

Test Webhooks

Send test events to verify setup:

  1. Go to Settings > Webhooks
  2. Click on webhook endpoint
  3. Click Send Test Event
  4. Select event type
  5. Review delivery result

Disable/Enable Webhooks

Temporarily disable without deleting:

  1. Go to webhook settings
  2. Toggle Enabled switch
  3. Webhook paused (events not sent)

Delete Webhooks

Remove webhook permanently:

  1. Go to webhook settings
  2. Click Delete Webhook
  3. 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.XX

TIP

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

  1. Verify endpoint URL is correct
  2. Check endpoint is publicly accessible
  3. Confirm HTTPS certificate is valid
  4. Review firewall/security rules
  5. Check webhook is enabled

Signature Verification Failing

  1. Verify using correct secret
  2. Check payload encoding (UTF-8)
  3. Ensure no middleware modifies body
  4. Verify signature header name

Timeouts

  1. Respond within 10 seconds (timeout enforced)
  2. Process async after acknowledging
  3. Check endpoint performance
  4. Review server resources

Missing Events

  1. Check event types are subscribed
  2. Review webhook logs
  3. Verify endpoint returned 2xx
  4. 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

  1. Create Webhook: Navigate to Settings > Webhooks > Add Webhook
  2. List Webhooks: View all webhooks in Settings > Webhooks
  3. Update Webhook: Click on a webhook to edit its configuration
  4. Delete Webhook: Click Delete on the webhook details page
  5. 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.

Automatum GTM Platform