Webhooks
Deliver Atlas filing and fund events to your own systems with signed webhook requests.
Webhooks deliver matching Atlas events to your systems.
Use webhooks as the default path for product event delivery. Use event feeds for backfill and reconciliation.
Delivery model
Atlas sends HTTPS POST requests to every active webhook endpoint in your organization that matches at least one active event subscription rule.
The portal supports multiple active endpoints per organization. Atlas evaluates subscriptions at the organization level, then fans matching events out to each active endpoint for that organization.
Supported event types include filing.new, filing.signal.created, board_change.detected, dividend.declared, fund.snapshot.updated, and fund.disclosure.updated.
The payload follows the webhook event envelope documented in Events.
Manual ping
Use the webhook ping route before you enable production workflows:
POST /v1/organizations/{org_id}/webhooks/{webhook_id}/pingThe ping sends a signed HTTPS POST to one active endpoint immediately and returns the delivery outcome synchronously.
Ping deliveries use type = "webhook.test" and the same event envelope as normal webhook deliveries. They are validation-only and do not appear in /v1/events or delivery-attempt history. Use sandbox synthetic events for auditable end-to-end tests.
Example webhook.test payload:
{
"id": "2b2dc6f4-48aa-4fd7-9d0a-6c96b9f1e4ea",
"type": "webhook.test",
"occurred_at": "2026-04-11T11:05:12.193927Z",
"created_at": "2026-04-11T11:05:12.193927Z",
"entity_kind": "webhook",
"entity_id": "6a4ce6d5-1a8f-4cb3-b5cc-070d46fe6f94",
"company_id": null,
"fund_id": null,
"source_kind": "webhook",
"source_id": "6a4ce6d5-1a8f-4cb3-b5cc-070d46fe6f94",
"title": "Atlas webhook test delivery",
"summary": "Validation-only test delivery for your Atlas webhook endpoint.",
"severity": "info",
"source_url": null,
"source_published_at": null,
"data": {
"message": "This is a validation-only Atlas webhook test delivery."
}
}Headers
Every webhook delivery includes Webhook-Id, Webhook-Timestamp, and Webhook-Signature.
Atlas signs the raw request body using:
<webhook_id>.<webhook_timestamp>.<raw_body>The signature header format is:
v1,<base64_hmac_sha256_digest>Signature verification examples
Use the raw request body exactly as received.
import crypto from 'node:crypto';
export function verifyAtlasWebhook({
rawBody,
secret,
webhookId,
webhookTimestamp,
signature,
}: {
rawBody: Buffer;
secret: string;
webhookId: string;
webhookTimestamp: string;
signature: string;
}) {
const signedPayload = Buffer.concat([
Buffer.from(webhookId, 'utf8'),
Buffer.from('.', 'utf8'),
Buffer.from(webhookTimestamp, 'utf8'),
Buffer.from('.', 'utf8'),
rawBody,
]);
const digest = crypto.createHmac('sha256', decodeSecret(secret)).update(signedPayload).digest('base64');
const expected = `v1,${digest}`;
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
function decodeSecret(secret: string) {
if (!secret.startsWith('whsec_')) {
return Buffer.from(secret, 'utf8');
}
const encoded = secret.slice('whsec_'.length);
const padded = encoded + '='.repeat((4 - (encoded.length % 4)) % 4);
return Buffer.from(padded, 'base64url');
}import base64
import hmac
from hashlib import sha256
def verify_atlas_webhook(*, raw_body: bytes, secret: str, webhook_id: str, webhook_timestamp: str, signature: str) -> bool:
signed_payload = b".".join(
[
webhook_id.encode("utf-8"),
webhook_timestamp.encode("utf-8"),
raw_body,
]
)
digest = hmac.new(_decode_secret(secret), signed_payload, sha256).digest()
expected = f"v1,{base64.b64encode(digest).decode('utf-8')}"
return hmac.compare_digest(expected, signature)
def _decode_secret(secret: str) -> bytes:
if not secret.startswith("whsec_"):
return secret.encode("utf-8")
encoded = secret[len("whsec_") :]
padded = encoded + ("=" * ((4 - len(encoded) % 4) % 4))
return base64.urlsafe_b64decode(padded.encode("utf-8"))Receiver requirements
Your receiver should accept JSON payloads over HTTPS, return a 2xx response quickly, verify Atlas signatures before processing, store event IDs to prevent duplicate processing, and hand off long-running work to an asynchronous job queue.
Retries
Atlas treats any non-2xx response, timeout, or connection failure as a failed attempt.
Atlas currently uses a 10s request timeout, retries after 5s, 2m, 15m, and 1h, and does not guarantee delivery ordering.
Your receiver should be idempotent and able to safely process the same event more than once.
Treat the webhook request as a notification, not as proof that work has completed in your system.
Recent delivery attempts are visible per endpoint in the Atlas Portal.
Ping results are returned inline by the ping endpoint instead of being added to this delivery history.
Sandbox testing
Atlas sandbox supports manual ping, subscription-scoped synthetic test events, and delivery-attempt inspection.
See Sandbox Testing for the recommended flow.
Recommended architecture
Atlas sends a webhook event
The delivery arrives as a signed HTTPS POST request with the documented webhook envelope.
Your edge receiver verifies the signature
Validate the signature against the raw request body before doing any downstream work.
Persist the event ID and enqueue work
Acknowledge the request quickly and move long-running work into an async queue.
Fetch any supporting API data
Pull filing, fund, or entity detail if your workflow needs richer context than the webhook payload carries.
Fan out to your application
Send alerts, update workflow state, or trigger internal automations after the event is accepted.
Security expectations
Terminate TLS correctly, verify the Atlas signature on every request, reject requests with invalid signatures, use distinct receiver URLs or endpoint configs for test validation and live traffic, and rotate webhook credentials and API keys through normal operational processes.