Webhooks
Receive real-time notifications when events happen
Webhooks allow you to receive real-time HTTP notifications when events happen in your EntityEngine account. Instead of polling the API, you can subscribe to events and receive instant updates.
Real-time
Get notified instantly when events occur
Secure
HMAC-SHA256 signatures verify authenticity
Reliable
Automatic retries with exponential backoff
Setting Up Webhooks
Via Dashboard
- Log in to your EntityEngine account
- Navigate to Profile → Webhooks
- Click Create Webhook
- Enter your endpoint URL (must be HTTPS)
- Select the events you want to receive
- Save and copy your webhook secret
Via API
curl -X POST "https://app.entityengine.com/api/v1/webhooks" \
-H "Authorization: Bearer sk_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/entityengine",
"events": ["entity.created", "entity.updated", "document.uploaded"],
"description": "Production webhook"
}'Webhook Payload
All webhook payloads follow a consistent structure:
{
"id": "evt_abc123",
"type": "entity.created",
"created_at": "2024-01-20T14:00:00Z",
"data": {
// Event-specific data
}
}HTTP Headers
| Header | Description |
|---|---|
X-Webhook-ID | Unique identifier for this webhook delivery |
X-Webhook-Timestamp | Unix timestamp when the webhook was sent |
X-Webhook-Signature | HMAC-SHA256 signature for verification |
Verifying Signatures
Always verify webhook signatures
Verifying signatures ensures the webhook was sent by EntityEngine and hasn't been tampered with.
The signature is computed using HMAC-SHA256 with your webhook secret:
signature = HMAC-SHA256(webhook_secret, timestamp + "." + payload)Node.js Example
import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
timestamp: string,
secret: string
): boolean {
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your webhook handler
app.post('/webhooks/entityengine', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const timestamp = req.headers['x-webhook-timestamp'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, timestamp, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the webhook
const event = req.body;
console.log('Received event:', event.type);
res.status(200).json({ received: true });
});Retry Policy
If your endpoint returns a non-2xx status code or times out, we'll retry the delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry (final) | 24 hours |
Best Practice
Return a 200 status code as quickly as possible. Process the webhook asynchronously to avoid timeouts.
Event Types
entity.createdA new entity has been created
{
"id": "evt_abc123",
"type": "entity.created",
"created_at": "2024-01-20T14:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"name": "My Company LLC",
"status": "pre_incorporation",
"jurisdiction_product_id": "jp_abc123"
}
}entity.updatedAn entity has been updated
{
"id": "evt_def456",
"type": "entity.updated",
"created_at": "2024-01-21T10:30:00Z",
"data": {
"entity_id": "ent_xyz789",
"changes": {
"status": {
"from": "pre_incorporation",
"to": "in_progress"
}
}
}
}entity.status_changedAn entity status has changed
{
"id": "evt_ghi789",
"type": "entity.status_changed",
"created_at": "2024-01-22T09:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"previous_status": "in_progress",
"new_status": "active"
}
}person.addedA person has been added to an entity
{
"id": "evt_jkl012",
"type": "person.added",
"created_at": "2024-01-20T15:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"person_id": "per_abc123",
"first_name": "John",
"last_name": "Smith",
"roles": ["director", "shareholder"]
}
}document.uploadedA document has been uploaded
{
"id": "evt_stu901",
"type": "document.uploaded",
"created_at": "2024-01-20T16:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"document_id": "doc_abc123",
"document_type": "passport",
"name": "passport_john_smith.pdf"
}
}document.approvedA document has been approved
{
"id": "evt_vwx234",
"type": "document.approved",
"created_at": "2024-01-21T09:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"document_id": "doc_abc123",
"document_type": "passport"
}
}kyc.completedKYC verification has been completed for an entity
{
"id": "evt_bcd890",
"type": "kyc.completed",
"created_at": "2024-01-23T10:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"status": "verified",
"verified_persons": ["per_abc123", "per_def456"]
}
}share_class.createdA new share class has been created for an entity
{
"id": "evt_cde901",
"type": "share_class.created",
"created_at": "2024-01-20T14:30:00Z",
"data": {
"entity_id": "ent_xyz789",
"share_class_id": "sc_abc123",
"name": "Ordinary Shares",
"currency": "USD",
"par_value": 1.00
}
}shareholding.createdA new shareholding has been allocated to a shareholder
{
"id": "evt_def012",
"type": "shareholding.created",
"created_at": "2024-01-20T15:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"shareholding_id": "sh_abc123",
"party_id": "pty_def456",
"party_name": "John Smith",
"share_class_id": "sc_abc123",
"shares_held": 1000
}
}