Webhooks
Webhooks Guide
Webhooks let your application receive real-time notifications when events happen in EEv3. Instead of polling, you register a URL and receive HTTP POST requests whenever relevant events fire.
Supported Events
| Event | Description |
|---|---|
| entity.created | A new entity has been provisioned |
| entity.updated | Entity configuration was changed |
| entity.deleted | An entity was deprovisioned |
| capability.invoked | A capability was called via /do |
| billing.payment | A payment was processed successfully |
| billing.failed | A payment attempt failed |
| billing.subscription.created | A new subscription started |
| billing.subscription.cancelled | A subscription was cancelled |
| auth.login | A user logged in |
| auth.login.failed | A login attempt failed |
| auth.user.created | A new user account was created |
| storage.upload | A file was uploaded to storage |
| workflow.completed | A workflow run finished |
| workflow.failed | A workflow run failed |
Webhook Payload
Every webhook delivers a JSON payload with a consistent shape: event ID, type, timestamp, entity, and event-specific data.
{
"id": "evt_abc123",
"type": "entity.created",
"timestamp": "2024-10-15T09:30:00Z",
"entity": "my-company",
"data": {
"entityId": "ent_xyz789",
"name": "Acme Corp",
"stack": ["auth", "billing", "storage"]
}
}Signature Verification
Every webhook request includes an X-EE-Signature header containing an HMAC-SHA256 signature. Always verify this signature before processing the event to ensure the request came from EEv3 and wasn't tampered with.
Express Webhook Handler
import crypto from 'crypto'
import type { Request, Response } from 'express'
const WEBHOOK_SECRET = process.env.EE_WEBHOOK_SECRET!
function verifySignature(payload: string, signature: string): boolean {
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
)
}
export function webhookHandler(req: Request, res: Response) {
const signature = req.headers['x-ee-signature'] as string
const rawBody = JSON.stringify(req.body)
if (!verifySignature(rawBody, signature)) {
return res.status(401).json({ error: 'Invalid signature' })
}
const event = req.body
switch (event.type) {
case 'entity.created':
// Handle new entity
break
case 'billing.payment':
// Handle payment
break
default:
console.log('Unhandled event:', event.type)
}
res.status(200).json({ received: true })
}Retry Policy
If your endpoint returns a non-2xx status code or times out, EEv3 retries the webhook up to 3 times with exponential backoff:
- Attempt 1: immediate
- Attempt 2: after 30 seconds
- Attempt 3: after 5 minutes
- Attempt 4: after 30 minutes
After all retries are exhausted, the event is marked as failed in your dashboard. You can manually replay any failed event.
Related
- Authentication— JWT verification for webhook signatures
- Error Handling— error codes and debugging