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.io/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 via POST /entities.
{
"id": "evt_abc123",
"type": "entity.created",
"created_at": "2024-01-20T14:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"name": "My Company LLC",
"status": "draft",
"jurisdiction_product_id": "jp_abc123"
}
}entity.updatedEntity details have been updated.
{
"id": "evt_def456",
"type": "entity.updated",
"created_at": "2024-01-21T10:30:00Z",
"data": {
"entity_id": "ent_xyz789",
"changes": {
"name": {
"from": "My Company LLC",
"to": "My Company Ltd"
}
}
}
}entity.status_changedEntity status has changed — fired on every status transition (submitted, in_review, returned_for_changes, submitted_to_csp, incorporated, etc.).
{
"id": "evt_ghi789",
"type": "entity.status_changed",
"created_at": "2024-01-22T09:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"name": "My Company Ltd",
"old_status": "submitted_to_csp",
"new_status": "incorporated",
"company_number": "12345678",
"incorp_date": "2024-01-22"
}
}entity.invoicedAn invoice has been issued for an entity via POST /entities/{id}/invoice.
{
"id": "evt_inv001",
"type": "entity.invoiced",
"created_at": "2024-01-20T15:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"invoice_id": "inv_abc123",
"invoice_number": "INV-001",
"total_minor": 150000,
"currency": "USD"
}
}entity.feedback_createdAdmin has raised a review issue requiring your response.
{
"id": "evt_fb001",
"type": "entity.feedback_created",
"created_at": "2024-01-21T11:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"feedback_id": "fb_abc123",
"feedback_type": "document_issue",
"message": "The passport scan is unclear. Please upload a higher quality image."
}
}entity.feedback_resolvedA feedback issue has been resolved by admin.
{
"id": "evt_fb002",
"type": "entity.feedback_resolved",
"created_at": "2024-01-22T14:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"feedback_id": "fb_abc123",
"resolution_note": "Document accepted."
}
}document.uploadedA document has been uploaded for an entity.
{
"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 by admin.
{
"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"
}
}document.rejectedA document has been rejected by admin.
{
"id": "evt_doc003",
"type": "document.rejected",
"created_at": "2024-01-21T09:30:00Z",
"data": {
"entity_id": "ent_xyz789",
"document_id": "doc_abc123",
"document_type": "passport",
"rejected_reason": "Image quality too low."
}
}party.addedA party (person, company, or foundation) has been added to an entity.
{
"id": "evt_jkl012",
"type": "party.added",
"created_at": "2024-01-20T15:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"party_id": "pty_abc123",
"party_type": "person",
"first_name": "John",
"last_name": "Smith",
"roles": ["director", "shareholder"]
}
}party.updatedA party's details have been updated.
{
"id": "evt_per002",
"type": "party.updated",
"created_at": "2024-01-21T10:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"party_id": "pty_abc123",
"party_type": "person",
"first_name": "John",
"last_name": "Smith"
}
}party.removedA party has been removed from an entity.
{
"id": "evt_per003",
"type": "party.removed",
"created_at": "2024-01-21T11:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"party_id": "pty_abc123",
"party_type": "person"
}
}payment.session_createdA hosted Stripe or Radom checkout session has been created for an invoice.
{
"id": "evt_pay001",
"type": "payment.session_created",
"created_at": "2024-01-20T15:30:00Z",
"data": {
"invoice_id": "inv_abc123",
"entity_id": "ent_xyz789",
"provider": "stripe",
"checkout_url": "https://checkout.stripe.com/..."
}
}payment.session_expiredA hosted checkout session expired before payment was completed. Regenerate via POST /invoices/{id}/checkout-session.
{
"id": "evt_pay002",
"type": "payment.session_expired",
"created_at": "2024-01-21T15:30:00Z",
"data": {
"invoice_id": "inv_abc123",
"entity_id": "ent_xyz789",
"provider": "stripe"
}
}payment.receivedPayment has been received and the invoice is marked paid.
{
"id": "evt_pay003",
"type": "payment.received",
"created_at": "2024-01-21T16:00:00Z",
"data": {
"invoice_id": "inv_abc123",
"entity_id": "ent_xyz789",
"amount_minor": 150000,
"currency": "USD",
"provider": "stripe"
}
}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
}
}shareholding.updatedThe number of shares held in an existing shareholding has been updated.
{
"id": "evt_def013",
"type": "shareholding.updated",
"created_at": "2024-01-21T10:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"shareholding_id": "sh_abc123",
"party_id": "pty_def456",
"share_class_id": "sc_abc123",
"shares_held": 750
}
}addon.purchasedAn addon has been purchased for an entity.
{
"id": "evt_adn001",
"type": "addon.purchased",
"created_at": "2024-01-20T15:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"addon_id": "addon_ein_123",
"addon_slug": "ein-registration"
}
}addon.status_changedAn addon status has changed (e.g., submitted for review, approved, completed).
{
"id": "evt_adn002",
"type": "addon.status_changed",
"created_at": "2024-01-22T10:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"addon_id": "addon_ein_123",
"old_status": "submitted_for_review",
"new_status": "approved"
}
}addon.invoicedA separate invoice has been raised for an addon purchase (post-submission addons that require additional payment).
{
"id": "evt_adn003",
"type": "addon.invoiced",
"created_at": "2024-01-22T11:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"addon_slug": "ein-registration",
"entity_addon_id": "ea_abc123",
"invoice_id": "inv_xyz789",
"total_minor": 25000,
"currency": "USD",
"checkout_url": "https://checkout.stripe.com/..."
}
}invitation.sentA collaborator invitation has been sent for an entity.
{
"id": "evt_inv001",
"type": "invitation.sent",
"created_at": "2024-01-20T12:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"invitation_id": "ivt_abc123",
"email": "colleague@example.com",
"expires_at": "2024-01-27T12:00:00Z"
}
}invitation.acceptedA collaborator invitation has been accepted.
{
"id": "evt_inv002",
"type": "invitation.accepted",
"created_at": "2024-01-21T09:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"invitation_id": "ivt_abc123",
"email": "colleague@example.com"
}
}invitation.expiredA collaborator invitation expired before being accepted.
{
"id": "evt_inv003",
"type": "invitation.expired",
"created_at": "2024-01-27T12:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"invitation_id": "ivt_abc123",
"email": "colleague@example.com"
}
}invitation.revokedA pending collaborator invitation has been revoked via DELETE /invitations/{id}.
{
"id": "evt_inv004",
"type": "invitation.revoked",
"created_at": "2024-01-22T10:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"invitation_id": "ivt_abc123",
"email": "colleague@example.com"
}
}collaborator.addedA collaborator has gained access to an entity after accepting an invitation.
{
"id": "evt_col001",
"type": "collaborator.added",
"created_at": "2024-01-20T13:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"user_id": "usr_abc123",
"email": "colleague@example.com"
}
}collaborator.removedA collaborator has been removed from an entity.
{
"id": "evt_col002",
"type": "collaborator.removed",
"created_at": "2024-01-23T14:00:00Z",
"data": {
"entity_id": "ent_xyz789",
"user_id": "usr_abc123"
}
}