Webhooks
Webhooks deliver real-time HTTP notifications when extractions or entity credentials change.
Delivery flow
sequenceDiagram
autonumber
participant API as Meefi API
participant App as Your webhook endpoint
participant Queue as Your job queue
Note over API: extraction.update or entity.update
API->>+App: POST /hooks/meefi
Authorization: Bearer {token}
App->>App: Verify bearer token
alt Token valid
App->>Queue: Enqueue side effects
App-->>-API: 2xx (quick ack)
Queue->>Queue: Sync invoices, alerts, etc.
else Token invalid
App-->>API: 401 Unauthorized
end
Note over API,App: Non-2xx may trigger retries
— handlers must be idempotentRegister a webhook
POST /v1/webhooks
{
"url": "https://your-app.example.com/hooks/meefi",
"events": []
}
| Field | Description |
|---|---|
url |
HTTPS endpoint that accepts POST requests |
events |
Optional filter (currently all organization events are sent) |
Response includes:
| Field | Description |
|---|---|
id |
Webhook UUID |
url |
Callback URL |
token |
Bearer token included in delivery requests |
events |
Subscribed events array |
Store the token securely. It is used to authenticate incoming webhook calls.
List and manage
GET /v1/webhooks— list all webhooksGET /v1/webhooks/{id}— get one webhookDELETE /v1/webhooks/{id}— remove subscription (204)
Delivery format
Each event is POSTed as JSON:
{
"event": "extraction.update",
"source": "extractions/a1ef89c2-9226-498d-8adf-38fc1e97cbcd",
"resource": {
"type": "Extraction",
"id": "a1ef89c2-9226-498d-8adf-38fc1e97cbcd",
"path": "extractions/a1ef89c2-9226-498d-8adf-38fc1e97cbcd"
},
"object": {
"status": "finished",
"started_at": "2026-06-03T15:50:05.000000Z",
"finished_at": "2026-06-03T15:52:18.000000Z",
"entity": {
"id": "9e08bb63-f6c1-44cf-a5b5-a92967cb172d",
"tax_id": "…",
"name": "…"
}
}
}
Authentication
Requests include:
Authorization: Bearer {webhook.token}
Verify this token on your endpoint before processing the payload.
Event types
| Event | When fired | object contents |
|---|---|---|
extraction.update |
Extraction starts, finishes, or fails | Status, timestamps, nested entity summary |
entity.update |
Credential validation completes or credential status changes | credential_status, entity identifiers |
flowchart LR
subgraph Events
E1[extraction.update]
E2[entity.update]
end
subgraph Triggers
T1[status pending → running → finished]
T2[credential pending → valid / invalid]
end
T1 --> E1
T2 --> E2Recommended handler pattern
flowchart TD
A[Receive POST] --> B{Bearer token valid?}
B -->|No| C[Return 401]
B -->|Yes| D[Parse JSON]
D --> E{event type}
E -->|extraction.update| F{object.status}
F -->|finished| G[Queue invoice sync]
F -->|failed| H[Alert operations]
E -->|entity.update| I[Update credential cache]
G --> J[Return 2xx immediately]
H --> J
I --> JRetry behavior
Failed deliveries may be retried. Implement idempotent handlers because the same event may be delivered more than once.
Local development
Use a tunneling tool (ngrok, Cloudflare Tunnel) to expose a local URL, then register it via POST /v1/webhooks.
Example handler (Node.js):
app.post('/hooks/meefi', (req, res) => {
const token = req.headers.authorization?.replace('Bearer ', '');
if (token !== process.env.MEEFI_WEBHOOK_TOKEN) {
return res.status(401).send('Unauthorized');
}
const { event, object } = req.body;
if (event === 'extraction.update' && object.status === 'finished') {
queueInvoiceSync(object.entity.id);
}
res.sendStatus(204);
});