Webhooks
Receiving webhook events from Angage
Overview
Extensions receive webhook events from Angage to react to marketplace and ERP state changes.
Webhooks are declared in the manifest under the webhooks array.
Declaring Webhooks
In your manifest.json:
{
"webhooks": [
"app.installed",
"app.uninstalled",
"invoice.paid",
"customer.created"
]
}
The extension's webhook_url in the developer portal
is the endpoint that receives these events.
Lifecycle Events
app.installed— Tenant installed your extensionapp.uninstalled— Tenant removed your extensionapp.activated— Tenant activated the extensionapp.deactivated— Tenant deactivated the extensionapp.scopes_updated— Tenant's granted scopes changed
Business Events
Events driven by ERP activity:
invoice.created,invoice.updated,invoice.paidpayment.receivedcustomer.created,customer.updatedorder.created,order.updatedproduct.created,product.updatedinventory.adjusted
Compliance Webhooks (Required)
To pass pre-review checks, your extension MUST declare:
tenant.data_request— Respond with exported tenant datatenant.data_redact— Delete tenant data on request
These are enforced by the automated pre-review check and are required for all submissions.
Webhook Payload
Requests are POSTed to your webhook_url with this structure:
{
"event": "app.installed",
"tenant_id": "tenant-abc-123",
"extension_slug": "your-extension",
"timestamp": "2026-04-07T10:00:00Z",
"data": {
"...": "event-specific fields"
}
}
Signature Verification
Every webhook includes an X-Webhook-Signature header
containing an HMAC-SHA256 digest of the raw request body:
X-Webhook-Signature: sha256=<hex_digest>
PHP verification example:
$signature = $request->header('X-Webhook-Signature');
$payload = $request->getContent(); // raw body — do not re-encode
$expected = 'sha256=' . hash_hmac('sha256', $payload, $webhookSecret);
if (!hash_equals($expected, $signature)) {
abort(401, 'Invalid signature');
}
Response Expectations
- Return 2xx within 10 seconds
- Be idempotent — the same event may be delivered more than once
- Do not block on downstream work — queue it