Webhooks
Webhooks enable real-time notifications to external systems when events occur in your ERP, supporting integrations and automated workflows.
Overview
Webhooks enable you to:
- Send real-time notifications
- Integrate with external systems
- Trigger automated workflows
- Sync data with other platforms
- Monitor webhook delivery
- Handle retry logic
Accessing Webhooks
Navigate to Settings → Integrations → Webhooks from the main menu.
Webhook Overview
Active Webhooks
Webhooks
Active Webhooks:
┌────────────────────────────────────────────────────────────────┐
│ Name │ URL │ Events │ Deliveries │
├────────────────────────────────────────────────────────────────┤
│ Order Sync │ api.partner.com │ 3 │ 5,678 (99%) │
│ Inventory Update │ warehouse.sys.com │ 2 │ 12,345 (98%)│
│ Customer CRM │ crm.company.com │ 4 │ 2,345 (100%)│
│ Accounting Sync │ quickbooks.api │ 5 │ 8,901 (99%) │
│ Slack Notifications│hooks.slack.com │ 6 │ 3,456 (100%)│
└────────────────────────────────────────────────────────────────┘
Delivery Statistics (Last 30 Days):
├─ Total Deliveries: 32,725
├─ Successful: 32,456 (99.2%)
├─ Failed: 269 (0.8%)
└─ Average Latency: 234ms
[+ Create Webhook]Creating Webhooks
Webhook Configuration
Create Webhook
Basic Information:
├─ Name: [Order Sync to Partner]
├─ Description: [Sends order data to partner fulfillment system]
├─ Status: [Active ▼]
└─ Version: [v1 ▼]
Endpoint Configuration:
├─ URL: [https://api.partner.com/webhooks/orders]
├─ Method: [POST ▼]
└─ Content Type: [application/json ▼]
Authentication:
├─ Type: [Bearer Token ▼]
│ ├─ None
│ ├─ Bearer Token
│ ├─ Basic Auth
│ ├─ API Key Header
│ └─ HMAC Signature
└─ Token/Credentials: [••••••••••••••••]
Headers (Optional):
├─ X-Source: angage-erp
├─ X-Environment: production
└─ [+ Add Header]
Events to Send:
├─ [x] order.created
├─ [x] order.updated
├─ [x] order.shipped
├─ [ ] order.cancelled
├─ [ ] order.completed
└─ [Show All Events]
[Test Webhook] [Save Webhook]Available Events
Event Categories
Webhook Events
Sales Events:
├─ order.created - New order placed
├─ order.updated - Order modified
├─ order.confirmed - Order confirmed
├─ order.shipped - Order shipped
├─ order.delivered - Order delivered
├─ order.cancelled - Order cancelled
├─ invoice.created - Invoice generated
├─ invoice.sent - Invoice emailed
├─ payment.received - Payment recorded
└─ payment.refunded - Refund processed
Customer Events:
├─ customer.created - New customer
├─ customer.updated - Customer modified
├─ customer.deleted - Customer removed
└─ contact.created - New contact added
Product Events:
├─ product.created - New product
├─ product.updated - Product modified
├─ product.deleted - Product removed
└─ inventory.updated - Stock changed
Purchase Events:
├─ purchase_order.created - New PO
├─ purchase_order.approved - PO approved
├─ purchase_order.received - Goods received
└─ bill.created - Vendor bill enteredEvent Filters
Event Filtering
Webhook: Order Sync to Partner
Event: order.created
Filters (only trigger when):
├─ Order Total > $[100]
├─ AND Order Source = [Online ▼]
├─ AND Ship Method = [Standard, Express ▼]
└─ [+ Add Filter]
Sample Matching:
├─ Order $150, Online, Express → ✓ Triggers
├─ Order $50, Online, Express → ✗ Below minimum
├─ Order $200, Phone, Standard → ✗ Wrong source
└─ Order $500, Online, Ground → ✗ Wrong ship method
[Save Filters]Payload Configuration
Payload Template
Webhook Payload
Event: order.created
Payload Format: [JSON ▼]
Payload Template:
┌────────────────────────────────────────────────────────────────┐
│ { │
│ "event": "order.created", │
│ "timestamp": "{webhook.timestamp}", │
│ "data": { │
│ "order_id": "{order.id}", │
│ "order_number": "{order.number}", │
│ "customer": { │
│ "id": "{customer.id}", │
│ "name": "{customer.name}", │
│ "email": "{customer.email}" │
│ }, │
│ "items": [ │
│ { │
│ "sku": "{item.sku}", │
│ "name": "{item.name}", │
│ "quantity": "{item.quantity}", │
│ "price": "{item.price}" │
│ } │
│ ], │
│ "totals": { │
│ "subtotal": "{order.subtotal}", │
│ "tax": "{order.tax}", │
│ "shipping": "{order.shipping}", │
│ "total": "{order.total}" │
│ } │
│ } │
│ } │
└────────────────────────────────────────────────────────────────┘
[Use Default Template] [Preview with Sample Data]Available Variables
Webhook Variables
System Variables:
├─ {webhook.id} - Webhook delivery ID
├─ {webhook.timestamp} - ISO 8601 timestamp
├─ {webhook.event} - Event name
└─ {webhook.attempt} - Retry attempt number
Order Variables:
├─ {order.id} - Internal order ID
├─ {order.number} - Order number
├─ {order.date} - Order date
├─ {order.status} - Order status
├─ {order.subtotal} - Subtotal amount
├─ {order.tax} - Tax amount
├─ {order.shipping} - Shipping amount
├─ {order.total} - Total amount
└─ {order.notes} - Order notes
Customer Variables:
├─ {customer.id} - Customer ID
├─ {customer.code} - Customer code
├─ {customer.name} - Company name
├─ {customer.email} - Email address
└─ {customer.phone} - Phone number
Line Item Variables (array):
├─ {item.sku} - Product SKU
├─ {item.name} - Product name
├─ {item.quantity} - Quantity ordered
├─ {item.price} - Unit price
└─ {item.total} - Line totalDelivery & Retry
Delivery Settings
Delivery Configuration
Webhook: Order Sync to Partner
Timeout Settings:
├─ Connection Timeout: [10] seconds
├─ Response Timeout: [30] seconds
└─ Consider success if HTTP: [200-299 ▼]
Retry Policy:
├─ [x] Enable automatic retries
├─ Max Retries: [5]
├─ Retry Intervals:
│ ├─ 1st retry: 1 minute
│ ├─ 2nd retry: 5 minutes
│ ├─ 3rd retry: 30 minutes
│ ├─ 4th retry: 2 hours
│ └─ 5th retry: 12 hours
└─ Backoff: [Exponential ▼]
Failure Handling:
├─ After all retries fail: [Notify admin ▼]
├─ Notification email: [[email protected]]
├─ [x] Log failed payloads
└─ [ ] Pause webhook after 10 consecutive failures
[Save Delivery Settings]Delivery Log
Webhook Delivery Log
Webhook: Order Sync to Partner
Time Period: [Last 7 Days ▼]
Summary:
├─ Total Deliveries: 567
├─ Successful: 561 (98.9%)
├─ Failed: 6 (1.1%)
└─ Avg Response Time: 234ms
Recent Deliveries:
┌────────────────────────────────────────────────────────────────┐
│ Time │ Event │ Status │ Response│ Duration │
├────────────────────────────────────────────────────────────────┤
│ 10:45:32 AM │ order.created │ ✓ 200 │ OK │ 189ms │
│ 10:43:15 AM │ order.shipped │ ✓ 200 │ OK │ 234ms │
│ 10:40:01 AM │ order.created │ ✓ 200 │ OK │ 201ms │
│ 10:35:22 AM │ order.updated │ ⚠️ 500 │ Retry 1 │ 5,023ms │
│ 10:30:45 AM │ order.created │ ✓ 200 │ OK │ 178ms │
└────────────────────────────────────────────────────────────────┘
[View Details] [Retry Failed] [Export Log]Delivery Detail
Delivery Detail
Delivery ID: whd_abc123def456
Webhook: Order Sync to Partner
Event: order.created
Record: SO-2026-0892
Timeline:
├─ Jan 22, 10:35:22 AM - Triggered
├─ Jan 22, 10:35:22 AM - Attempt 1: Failed (500)
├─ Jan 22, 10:36:22 AM - Attempt 2: Failed (500)
├─ Jan 22, 10:41:22 AM - Attempt 3: Success (200)
└─ Total Duration: 6 minutes
Request:
├─ URL: https://api.partner.com/webhooks/orders
├─ Method: POST
├─ Headers: [View]
└─ Payload: [View]
Response (Attempt 3):
├─ Status: 200 OK
├─ Duration: 234ms
├─ Headers: [View]
└─ Body: {"status": "received", "id": "12345"}
[Resend] [View Full Payload]Testing
Test Webhook
Test Webhook
Webhook: Order Sync to Partner
Endpoint: https://api.partner.com/webhooks/orders
Test Options:
├─ Event: [order.created ▼]
├─ Sample Data: [Recent Order ▼]
│ ├─ Recent Order (SO-2026-0892)
│ ├─ Sample Data (generated)
│ └─ Custom (enter JSON)
└─ Include signature: [x]
Payload Preview:
┌────────────────────────────────────────────────────────────────┐
│ { │
│ "event": "order.created", │
│ "timestamp": "2026-01-22T15:30:00Z", │
│ "data": { │
│ "order_id": "ord_abc123", │
│ "order_number": "SO-2026-0892", │
│ ... │
│ } │
│ } │
└────────────────────────────────────────────────────────────────┘
[Send Test]
Test Result:
├─ Status: ✓ 200 OK
├─ Duration: 234ms
├─ Response: {"status": "received"}
└─ Webhook is working correctly!Security
Webhook Signatures
Webhook Security
Signature Verification:
Each webhook includes a signature header for verification:
X-Angage-Signature: sha256=abc123...
Signing Secret: whsec_••••••••••••••••
Verification Code (Python):
┌────────────────────────────────────────────────────────────────┐
│ import hmac │
│ import hashlib │
│ │
│ def verify_signature(payload, signature, secret): │
│ expected = hmac.new( │
│ secret.encode(), │
│ payload.encode(), │
│ hashlib.sha256 │
│ ).hexdigest() │
│ return hmac.compare_digest(f"sha256={expected}", signature)│
└────────────────────────────────────────────────────────────────┘
Additional Security:
├─ [x] Include timestamp in signature
├─ [x] Reject requests older than 5 minutes
├─ [x] Require HTTPS endpoints
└─ [ ] IP allowlist for receiving servers
[Regenerate Secret]Best Practices
Configuration
- Use HTTPS endpoints
- Implement signature verification
- Set appropriate timeouts
- Configure retry policies
Handling
- Respond quickly (< 30s)
- Return 2xx for success
- Process asynchronously
- Implement idempotency
Monitoring
- Monitor delivery rates
- Set up failure alerts
- Review logs regularly
- Test after changes
Troubleshooting
Common Issues
Webhook not triggering
- Verify webhook is active
- Check event subscriptions
- Review filter conditions
- Test with sample data
Delivery failures
- Check endpoint URL
- Verify authentication
- Review error responses
- Check firewall rules
Duplicate deliveries
- Implement idempotency
- Check retry settings
- Use delivery IDs
- Verify success responses
Related Documentation
Learn about API Settings for bi-directional integration.
