Webhooks
Receive signed HTTPS notifications for account grants, sync, account resources, orders, and reauth.
Finatic can POST JSON events to an HTTPS endpoint you control whenever subscribed account grants, sync state, account resources, orders, or reauth requirements change. Delivery is handled by FinaticBackground and is scoped to company account grants.
Configure subscriptions
Create and manage webhook endpoints in the Finatic dashboard (Settings → Webhooks) after you sign in.
For each subscription you provide:
- URL — Must be HTTPS.
- Environment —
liveorsandbox. - Event types — One or more event strings from the catalog below.
- Secret — Used to compute
X-Finatic-Signature.
The public event catalog is available at GET /api/v1/webhooks/catalog (no auth required). Subscription management is performed through the dashboard.
Event catalog
The canonical catalog is available at /api/v1/webhooks/catalog.
Account grants
account.grant.createdaccount.grant.updatedaccount.grant.revoked
Account sync
account.sync.startedaccount.sync.succeededaccount.sync.failed
Account resources
account.balance.updatedaccount.position.updatedaccount.transaction.created
Orders
order.createdorder.updatedorder.filledorder.cancelledorder.rejected
Connections
connection.reauth.required
Request shape
Each POST body is a JSON object with:
- schemaVersion — currently
v1. - eventId — unique event id.
- eventType — subscribed event string.
- createdAt — ISO timestamp.
- environment —
liveorsandbox. - companyAccountId — company workspace that owns the grant/subscription.
- accountId — financial account ID when the event is account-scoped.
- grantId — account grant ID when available.
- resource — resource pointer with
resourceType,resourceId,accountId, andgrantId. - data — event-specific payload.
Example:
1{
2"schemaVersion": "v1",
3"eventId": "evt_01HX...",
4"eventType": "order.filled",
5"createdAt": "2026-06-08T20:15:00Z",
6"environment": "live",
7"companyAccountId": "acct_company_123",
8"accountId": "acct_financial_456",
9"grantId": "grant_789",
10"resource": {
11"resourceType": "order",
12"resourceId": "order_abc",
13"accountId": "acct_financial_456",
14"grantId": "grant_789"
15},
16"data": {
17"status": "FILLED",
18"symbol": "AAPL"
19}
20}
21Headers
Finatic sends at least:
1Content-Type: application/json
2User-Agent: Finatic-Webhooks/3.0
3Finatic-Event-Id: <eventId>
4 Finatic-Timestamp: <createdAt>
5 X-Finatic-Event: <eventType>
6 X-Finatic-Event-Id: <eventId>
7 X-Finatic-Timestamp: <createdAt>
8 X-Finatic-Delivery: live|test
9 ```
10
11 `Finatic-Delivery-Id` / `X-Finatic-Delivery-Id` and `Finatic-Trace-Id` / `X-Finatic-Trace-Id` are included
12 when those
13 values are available. When a subscription secret is configured, Finatic also sends both signature headers with
14 the
15 same value:
16
17 ```http
18 Finatic-Signature: sha256=<hex>
19 X-Finatic-Signature: sha256=<hex>
20 ```
21
22 ## Verify signatures
23
24 The signature is HMAC-SHA256 over the exact UTF-8 JSON body Finatic posts. Read and verify the raw body
25 before parsing or
26 re-serializing it. Acknowledge quickly with any HTTP 2xx and process expensive work asynchronously.
27
28 ```typescript
29 import { createHmac, timingSafeEqual } from 'node:crypto';
30
31 export async function POST(request: Request) {
32 const rawBody = await request.text();
33 const signature = request.headers.get('x-finatic-signature') ?? '';
34 const expected = `sha256=${createHmac(
35 'sha256',
36 process.env.FINATIC_WEBHOOK_SECRET!,
37 )
38 .update(rawBody, 'utf8')
39 .digest('hex')}`;
40
41 const valid =
42 signature.length === expected.length &&
43 timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
44
45 if (!valid) {
46 return new Response('invalid signature', { status: 401 });
47 }
48
49 return new Response('ok', { status: 200 });
50 }
51 ```
52
53 ```python
54 import hashlib
55 import hmac
56 import os
57
58 def is_valid_finatic_signature(raw_body: bytes, signature_header: str) -> bool:
59 expected = "sha256=" + hmac.new(
60 os.environ["FINATIC_WEBHOOK_SECRET"].encode("utf-8"),
61 raw_body,
62 hashlib.sha256,
63 ).hexdigest()
64 return hmac.compare_digest(signature_header, expected)
65 ```
66
67 ## Retries and idempotency
68
69 The worker treats any HTTP 2xx response as success. On timeouts, transport errors, or non-2xx responses,
70 Finatic retries
71 with exponential backoff and jitter up to the configured attempt limit. Use `eventId` as your idempotency
72 key and store
73 the latest processed event per resource if your workflow is order-sensitive.
74
75 ## Testing
76
77 - Use sandbox subscriptions while you iterate.
78 - Use dashboard test sends to validate endpoint routing and signature handling.
79 - Confirm your handler routes by `companyAccountId`, `accountId`, and `grantId`.
80 - Do not use provider connection IDs in webhook routing logic.
81
82 ## Next steps
83
84 1. **[Account-First Model](/docs/quick-start/v1-account-first)** — Understand public identity fields.
85 2. **[Account Grants](/docs/quick-start/account-grants)** — Manage grant scopes and disconnect behavior.
86 3. **[API Reference](/docs/api-reference)** — Explore the webhook event catalog.