Developer documentation · V1 preview
Official-source records.
One API key.
Read structured news, publisher release schedules, source health and immutable event revisions through the same canonical data API used by the Atlas terminal. No client ID, second REST secret or OAuth refresh flow.
Customer API access requires an active Pro plan. Paid subscriptions are not yet open. The customer base URL is https://www.olympusatlas.com/api/v1. A hosted staging preview is not a public paid offer. External alert dispatch is disabled; no latency or availability SLA is offered in this preview.
Make your first request
- Sign in and open Account → Integrations. Customer REST access requires an active Pro plan.
- Create a key with a meaningful label and expiry. Copy the single
oa_…string shown once; store it asOLYMPUS_ATLAS_API_KEYin your backend’s private environment. - Send it as
Authorization: Bearer <your-key>. The base URL is an address, not another credential.
# Set OLYMPUS_ATLAS_API_KEY in your private environment.
curl --fail-with-body --get \
"https://www.olympusatlas.com/api/v1/source-events" \
-H "Authorization: Bearer $OLYMPUS_ATLAS_API_KEY" \
-H "Accept: application/json" \
--data-urlencode "limit=25" \
--data-urlencode "order=desc" \
--data-urlencode "source_classification=live"Examples use curl, Python’s standard library and Node’s built-in fetch. They read live-classified sources, not necessarily events that are fresh or deliverable. An empty data array is a valid response. Never put the key in a website’s client bundle.
Historical quotes & orders
Historical purchasing is not open in this preview. When enabled, your API key can request an exact, no-charge quote with POST /historical-quotes, then obtain a Stripe-hosted payment link with POST /historical-orders. The key cannot charge a saved card. A person must complete Checkout; verified payment and private fulfillment are required before access starts. Reuse the same idempotency key if a Checkout request times out. Quotes expire after 30 minutes and changed catalogs require a new quote.
curl --fail-with-body -X POST "https://www.olympusatlas.com/api/v1/historical-quotes" -H "Authorization: Bearer $OLYMPUS_ATLAS_API_KEY" -H "Content-Type: application/json" -d '{"dataset_id":"official_macro_events","start_date":"2026-01-01","end_date":"2026-02-01"}'
# Review quote.amount_cents and billable_event_count before proceeding.
# Replace the placeholders below with the returned quote ID and your own
# stable 16–100 character retry key. Open checkout_url in a browser.
curl --fail-with-body -X POST "https://www.olympusatlas.com/api/v1/historical-orders" -H "Authorization: Bearer $OLYMPUS_ATLAS_API_KEY" -H "Content-Type: application/json" -d '{"quote_id":"<quote-id>","idempotency_key":"<stable-retry-key>"}'An API key can then list only its owner’s latest 100 orders at GET /historical-orders and repeat-download a ready order at /historical-orders/{orderId}/download. The immutable ZIP is available for 30 days from readiness, not purchase time. Expiry, refund, dispute or revocation ends access. A different account’s key cannot retrieve the order.
These routes are omitted from the downloadable OpenAPI document until customer historical access is enabled and the paid-order acceptance gate passes. The whole eligible event count sets the order price at the current plan’s quoted curve; API calls and repeat downloads are not pricing units. The first event is $1 on every eligible plan, and larger orders have lower average prices. Source/publisher weighting is not applied.
Authentication & key lifecycle
Authorization: Bearer oa_<your-key>
Accept: application/jsonThe prefix identifies an Atlas credential; everything after it is part of the same secret. Key IDs, labels and redacted prefixes are management metadata—you do not send those to authenticate. A Supabase publishable/secret key, Google login token or Stripe key will not work.
Atlas-Api-Key: <the-same-key> remains a backward-compatible alternative. Send exactly one supported header, not both; ambiguous or malformed credentials are refused.
Up to five active keys per customer. Choose expiry from 1–365 days (the account form defaults to 90). Pro access, scope, expiry and revocation are checked on each request. Rotation creates a replacement and revokes the old key atomically; update your integration immediately. Lost keys cannot be retrieved—revoke and replace. If an issuance response is lost, revoke the orphan key shown in your key list.
Keys authorize events:read only on the documented customer surface. They do not grant admin, execution, proprietary strategy, market-price or programmatic webhook-management access. Never send keys in query strings, tickets, screenshots or logs. Revoking a key does not cancel billing.
Endpoint reference
All paths below are relative to https://www.olympusatlas.com/api/v1. Read responses are JSON except historical ZIP downloads. Filter values are single, exact-match query values unless described otherwise. Discover identifiers through /sources and the event payload; do not guess provider names.
List sources
Discover physical source IDs, publisher policies, classifications and observed health.
Response shape: SourcePage in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
cursorquery · optional | string | Opaque next_cursor from the same endpoint and filter scope. Omit on the first request. |
limitquery · optional | integer Default: 50 | Page/observation size: 1–500, default 50. |
publisher_idquery · optional | string | Publisher identifier obtained from a source. |
release_familyquery · optional | string | Registered release-family identifier obtained from an event or source. |
source_classificationquery · optional | fixture, historical, live | Exact-match filter; omit to include all supported values. |
certification_statequery · optional | fixture, provisional, certified, degraded | Exact-match filter; omit to include all supported values. |
Source details
Current source policy, registry versions and observed health.
Response shape: SourceDetail in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
source_idpath · required | string | Physical source ID obtained from /sources. |
Source health
Bounded observations for one physical source. Unknown is not healthy.
Response shape: Health in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
source_idpath · required | string | Physical source ID obtained from /sources. |
as_ofquery · optional | string | ISO-8601 UTC instant: return records knowable at this cutoff, not a claim of original publisher vintage. |
dimensionquery · optional | reachability, freshness, schedule_adherence, clock_consistency, structure, parse, extraction, summary | Exact-match filter; omit to include all supported values. |
limitquery · optional | integer Default: 50 | Page/observation size: 1–500, default 50. |
Network health
Aggregate observed source health; not a platform uptime or latency guarantee.
Response shape: Health in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
as_ofquery · optional | string | ISO-8601 UTC instant: return records knowable at this cutoff, not a claim of original publisher vintage. |
Release calendar
Publisher-stated schedule projection. Date filters use scheduled time, with inclusive bounds.
Response shape: CalendarPage in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
include_date_onlyquery · optional | boolean Default: false | Opt into verified date-only initial schedule slots when using from/to. Their publisher calendar dates are compared with the inclusive ISO date portions of the bounds. Unknown/rescheduled untimed records are excluded; no UTC instant is invented. Cursor scope includes this selection. |
cursorquery · optional | string | Opaque next_cursor from the same endpoint and filter scope. Omit on the first request. |
limitquery · optional | integer Default: 50 | Page/observation size: 1–500, default 50. |
fromquery · optional | string | Inclusive scheduled-time lower bound, ISO-8601 UTC. Undated rows excluded when a range is requested. |
toquery · optional | string | Inclusive scheduled-time upper bound, ISO-8601 UTC. Must not precede from. |
source_idquery · optional | string | Physical source ID obtained from /sources. |
event_scope_idquery · optional | string | Logical release stream; may span different physical sources. |
release_familyquery · optional | string | Registered release-family identifier obtained from an event or source. |
statusquery · optional | string | Derived calendar status: announced, rescheduled, published, cancelled or expired. Revised/corrected/retracted lifecycles derive published; rescheduled applies only to announced events. |
source_classificationquery · optional | fixture, historical, live | Exact-match filter; omit to include all supported values. |
as_ofquery · optional | string | ISO-8601 UTC instant: return records knowable at this cutoff, not a claim of original publisher vintage. |
List events
Latest known version per event lineage, or the version visible at as_of. Ordered by effective availability and version ID.
Response shape: EventPage in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
cursorquery · optional | string | Opaque next_cursor from the same endpoint and filter scope. Omit on the first request. |
limitquery · optional | integer Default: 50 | Page/observation size: 1–500, default 50. |
source_idquery · optional | string | Physical source ID obtained from /sources. |
event_scope_idquery · optional | string | Logical release stream; may span different physical sources. |
publisher_idquery · optional | string | Publisher identifier obtained from a source. |
release_familyquery · optional | string | Registered release-family identifier obtained from an event or source. |
topicquery · optional | inflation, labor, growth, liquidity, rates_policy, fiscal_policy, trade, financial_stability, other | Exact-match filter; omit to include all supported values. |
min_urgencyquery · optional | routine, notable, high, critical | Exact-match filter; omit to include all supported values. |
lifecyclequery · optional | announced, published, revised, corrected, retracted, cancelled, expired | Exact-match filter; omit to include all supported values. |
schedule_statusquery · optional | scheduled, unscheduled, rescheduled, schedule_unknown | Exact-match filter; omit to include all supported values. |
processing_statequery · optional | complete, degraded, parse_failed, summary_abstained, review_required | Exact-match filter; omit to include all supported values. |
delivery_eligibilityquery · optional | eligible, withheld_reinterpretation, withheld_quality, withheld_rights, withheld_schedule_noise, withheld_context, eligible_to_prior_recipients, withheld_no_prior_delivery | Exact-match filter; omit to include all supported values. |
publication_onlyquery · optional | boolean Default: false | Only published, revised, corrected and retracted lineages. Combine with a pinned as_of cutoff for a current-news queue; default false preserves corpus browsing, including notices. Retractions are warnings, not publishable stories. |
substantive_onlyquery · optional | boolean Default: false | Require an anchored non-null numeric claim other than publication/document. Depth filter only—not semantic verification, freshness, source health, rights or editorial clearance. Retractions with retained facts remain warnings; use an unfiltered change poll too. |
deliverable_onlyquery · optional | boolean Default: false | Filter by event eligibility; not proof a specific customer has received or can receive it. |
reference_periodquery · optional | string | Exact provider reference-period identifier. |
source_classificationquery · optional | fixture, historical, live | Exact-match filter; omit to include all supported values. |
orderquery · optional | asc, desc Default: asc | Exact-match filter; omit to include all supported values. |
as_ofquery · optional | string | ISO-8601 UTC instant: return records knowable at this cutoff, not a claim of original publisher vintage. |
Event details
Canonical event, provenance, evidence, adjacent versions, prior comparable values and change set where available.
Response shape: EventDetail in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
source_event_idpath · required | string | Stable event lineage ID obtained from an event. |
as_ofquery · optional | string | ISO-8601 UTC instant: return records knowable at this cutoff, not a claim of original publisher vintage. |
Event history
All immutable versions visible at as_of, ordered by event-version ordinal ascending.
Response shape: EventPage in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
source_event_idpath · required | string | Stable event lineage ID obtained from an event. |
as_ofquery · optional | string | ISO-8601 UTC instant: return records knowable at this cutoff, not a claim of original publisher vintage. |
cursorquery · optional | string | Opaque next_cursor from the same endpoint and filter scope. Omit on the first request. |
limitquery · optional | integer Default: 50 | Page/observation size: 1–500, default 50. |
Exact version
One immutable version belonging to the specified lineage. No as_of parameter.
Response shape: VersionDetail in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
source_event_idpath · required | string | Stable event lineage ID obtained from an event. |
source_event_version_idpath · required | string | Immutable sev_ version ID from event history. |
List SEC filing packages
Group independently anchored SEC facts by CIK and accession. Exact periods remain separate; conflicting values are withheld. Prior-year comparisons require the same issuer, form family, subject, measure, unit and comparable exact duration. Packages are not earnings announcements or original filing vintages.
Response shape: FilingPackagePage in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
cursorquery · optional | string | Opaque next_cursor from this endpoint with the identical filter scope. |
limitquery · optional | integer Default: 50 | Page size: 1–500, default 50. |
issuer_cikquery · optional | string | SEC CIK, padded or unpadded. |
accessionquery · optional | string | Exact SEC accession in 0000000000-00-000000 format. |
filing_formquery · optional | 10-K, 10-Q, 10-K/A, 10-Q/A | Verified filing form. |
content_depthquery · optional | filing_package_sparse, filing_package_partial, filing_package_core_results, filing_package_deep | Mechanical fact coverage, not editorial or publication clearance. |
min_supported_factsquery · optional | integer Default: 1 | Minimum deduplicated, anchored, non-conflicting facts. |
min_distinct_metricsquery · optional | integer Default: 1 | Minimum distinct declared SEC financial metrics. |
include_conflictsquery · optional | boolean Default: true | Include packages with disclosed conflicts; conflicted observations never enter supported facts. |
orderquery · optional | asc, desc Default: desc | Order by filed date and stable package ID. |
as_ofquery · optional | string | ISO-8601 UTC knowledge cutoff applied to every component event. |
SEC filing package details
Return exact fact cohorts, source-event version and claim references, disclosed conflicts, mechanically comparable prior-year facts and SEC filing link. No source prose is returned.
Response shape: FilingPackageDetail in the OpenAPI specification.
| Parameter | Type / allowed values | Meaning |
|---|---|---|
package_idpath · required | string | Stable sfp_ package ID returned by the package list. |
as_ofquery · optional | string | ISO-8601 UTC knowledge cutoff applied to every component event. |
Pagination, revisions & historical research
Paginated sources, events, calendar and version history return data, count, has_more and next_cursor. count is this page’s size, not a total-dataset count. Default page size is 50; maximum is 500. Health reads are bounded observations or aggregates, not cursor pages.
{
"object_kind": "source_event",
"data": [],
"count": 0,
"has_more": false,
"next_cursor": null,
"as_of": null,
"sources": {},
"documents": {},
"source_contract_version": "OA-C005",
"time_contract_version": "OA-C001",
"data_is_fixture": false,
"fixture_notice": null
}Publisher metadata and story depth
Lists and history include a research_assessments map keyed by immutable event-version ID. Details includeresearch_assessment. Read content_depth, fact counts and comparison claim IDs beside the canonical event. These labels mean anchored extraction, not independent fact-checking or permission to publish. Optional substantive_only=trueselects numeric-fact records; it does not imply a complete story.
Event lists, details and version lists expose an additive documents map, keyed by the event’s evidence.document_version_id. It resolves the pinned title, original document URL, document type, publication revision, publisher time and Atlas first-seen time. It never changes canonical event bytes. Publisher time can be null. Current link-only policies omit title text; excerpt policies cap it. Metadata does not grant article reproduction rights.
A publication claim with measure publication, unit document and no reported figure is a discovery notice—not enough material for a financial explainer. Non-null financial claims provide extracted facts; comparisons require the same stream, subject, measure, claim type and unit, with explicit reporting periods. Confidence describes processing/evidence, not a market direction. Read Evidence and permissions before publishing; Orion should retain a review queue.
Weekly DOL claims now includes seasonally adjusted headline levels, source-stated weekly changes and available original/revised prior figures. Initial claims and continuing claims refer to different weeks; use each claim’s period. Percent rate levels and percentage-point changes are different units. Coverage is specific to this report’s headline prose, not every table or state. Filing and speech families may remain discovery-only. Claim values are integers, decimal strings or null—not free-form prose.
Health checks and release freshness
Health exposes each check’s state, observation time, reason and whether it was checked. Unknown is not a failure or success. The strict healthy flag still requires all eight dimensions to be explicitly OK. Schedule applicability is separate: not applicable or not configured never silently turns unknown into OK. A validated fact can coexist with an unchecked schedule; your review policy must decide which checks are required, not infer that from a legacy confidence label.
For calendars, include_date_only=true includes verified untimed initial schedule slots inside date bounds. Read scheduled_date, time_precision and schedule_timezone. A date-only meeting has null timestamp fields. Do not schedule a timed post from an assumed release hour; genuinely undated or rescheduled untimed records remain unknown.
Pass next_cursor back as cursor while has_more is true. Treat it as opaque: don’t edit it, move it to another endpoint or change selecting filters/order/cutoff. Use URL encoding. Cursors are not a persistent live-feed subscription.
For news available now, use publication_only=true,source_classification=live, order=descand a current UTC as_of cutoff, pinned across pages. This excludes announcement, cancellation and expiry notices. Retractions remain in the queue as warnings: never republish them as active facts. The unfiltered endpoint browses the research corpus, including upcoming notices; use Calendar for release planning. “Available” refers to Atlas knowledge, not a guarantee of story depth, permissions, delivery eligibility or complete publisher coverage.
A cutoff is not a recency window. Check the pinned document’spublished_at against your lookback before calling a record breaking news. Null publisher times require another review path. Atlas first-seen and processing availability are not substitutes for publisher time. Reprocessing an old release can create a newly available interpretation without a new publisher release.
For reproducible event/history traversal, pin an as_of UTC cutoff and retain it across every page. The default event list is the head version per lineage; it is not a complete revision log. Use /source-events/{id}/versions to reconcile corrections, retractions and other changes. Store immutable version IDs and do not silently overwrite prior evidence.
Poll changes without substantive_only ordeliverable_only as well: corrections can remove facts and retractions must reach your review queue. Compare stored immutable version IDs, then retrieve the lineage’s versions to reconcile missed intermediate changes. Start each polling sweep without an old cursor, pin a new cutoff, and overlap your retained monitoring window.atlas_reprocessing is not a publisher correction and is normally withheld from new-alert delivery.
import json, os, time
from datetime import datetime, timezone
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
base = os.getenv("OLYMPUS_ATLAS_API_BASE_URL", "https://www.olympusatlas.com/api/v1")
headers = {"Authorization": "Bearer " + os.environ["OLYMPUS_ATLAS_API_KEY"]}
# Pin the cutoff and keep every selecting filter unchanged for this traversal.
query = {"limit": 100, "order": "asc", "source_classification": "live",
"as_of": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")}
def get_page():
for attempt in range(4):
try:
request = Request(base + "/source-events?" + urlencode(query),
headers=headers)
with urlopen(request, timeout=15) as response:
return json.load(response)
except HTTPError as error:
if error.code != 429 or attempt == 3:
raise
time.sleep(max(1, int(error.headers.get("Retry-After", "60"))))
for _ in range(1000): # Explicit client safety bound; not an Atlas page limit.
page = get_page()
for event in page["data"]:
print(event["source_event_version_id"]) # Upsert/deduplicate this ID.
if not page["has_more"]:
break
if not page["next_cursor"]:
raise RuntimeError("Missing continuation cursor")
query["cursor"] = page["next_cursor"]
else:
raise RuntimeError("Traversal safety bound reached; save progress")
Historical provider snapshots are useful for research, but their Atlas availability starts when Atlas actually acquired them. An archive acquired today is not evidence Atlas operated years ago or knew today’s revised figures at the original release time. Event as_of does not promise a complete point-in-time vintage of every adjacent source-policy field.
Read the data correctly
Event pages contain canonical payloads in data[]. Event/detail-version responses contain the same event object in event, with provenance and source metadata beside it. Calendar rows are schedule projections—not full canonical events. Aggregate health returns sources[]; per-source health returns states and bounded observations[].
| Canonical field | Interpretation |
|---|---|
source_event_id | Stable event lineage. A later correction does not create a new story identity. |
source_event_version_id / event_version | Immutable version ID and increasing ordinal. Deduplicate/upsert by version ID; use /versions to reconcile changes. |
source | Physical source ID, logical event scope and pinned registry version. Consult the response’s adjacent source metadata for attribution and rights. |
lifecycle / version_cause / version_actor | Announced, published, revised, corrected, retracted, cancelled or expired; distinguish publisher changes from Atlas reinterpretation. |
summary / claims | Observational summary and structured claims. Values can be unavailable; do not fill missing numbers or invent consensus. |
prior_comparable / change_set | Comparison and change metadata when supported. Null is meaningful, not zero or “unchanged.” |
times / availability | Detection, revision, schedule and effective availability—not the same clock. UTC ISO strings and decimal-string epoch nanoseconds preserve point-in-time truth. |
confidence / evidence_quality | Evidence/interpretation quality, not directional trading confidence or a probability of profit. |
delivery.eligibility | Eligibility or a withholding reason. Eligibility alone is not a customer receipt or dispatch guarantee. |
payload_fingerprint | SHA-256 canonical payload fingerprint. Exact raw bytes matter for webhook verification; arbitrary JSON serialization is not canonical. |
Preserve decimal strings and nanosecond strings; do not coerce them into floating-point numbers. A null schedule, number or comparison is unknown/unavailable, not a zero. Read fixture flags, source classification, processing state, evidence quality, rights and delivery eligibility together.
source_classification=live classifies a source, not an event’s age or delivery status. deliverable_only=true filters record eligibility but does not activate a rule or prove a receipt. Context-only, archived, fixture, rights-held and Atlas-reinterpretation records must not be presented as fresh publisher alerts.
Attribution and redistribution restrictions remain applicable to public first-party information. Access does not license every underlying article for republication. Link to the official source and respect its current policy. Raw provider bodies and credentials are not exposed. Unknown health is not healthy. Atlas publishes observations, not guaranteed trades or price forecasts.
V1 URLs are versioned under /api/v1; canonical events identify their own contracts. Clients should tolerate additional fields and fail safely on unfamiliar statuses. Downloadable OpenAPI response schemas document selected fields, not an exhaustive typed SDK or a compatibility SLA.
Errors, limits & polling
The customer budget is 120 requests per fixed UTC minute per key, durably counted. This is not a rolling-minute window or guaranteed throughput. Successful authorized responses include Atlas-RateLimit-Limit and Atlas-RateLimit-Remaining. A quota refusal includes Retry-After in seconds.
Start with modest polling (for example every 15–30 seconds), bounded pages and retries. Fetch individual histories when a lineage changes rather than repeatedly downloading the full archive. Source cadence varies; polling faster does not make a publisher release data sooner. Signed webhooks are the push option, subject to release activation.
| HTTP | Meaning | Action |
|---|---|---|
400 | Invalid filters, cursor or cutoff | Correct the parameters. On invalid_cursor, restart that traversal without a cursor. |
401 | Credential refused | Check the whole key, exactly one auth header, expiry/revocation and current Pro entitlement. Do not retry unchanged. |
403 | Paid authorization refused | Check access. An API key cannot authorize admin or proprietary strategy operations. |
404 | Not found / not knowable at cutoff | Verify source, lineage and version IDs, path and as_of. |
405 | Method not allowed | Use the documented method. Historical quote and hosted Checkout POST routes remain gated. |
422 | Type or bounds invalid | Use limit 1–500 and correctly typed query values. |
429 | Key rate budget exhausted | Wait the Retry-After seconds, then retry with bounded backoff. |
500 / 503 | Request failed / integration unavailable | Retry with bounded backoff; retain Atlas-Request-Id when returned. No availability SLA is promised in preview. |
{
"error": "Key is inactive, expired, revoked or not entitled."
}Check the HTTP status first. Gateway errors use a readable error string; canonical errors use error.code, error.message and error.request_id. Preserve request IDs when available, but redact authentication headers. Network timeouts can occur without a JSON response.
Signed event webhooks
Pro customers configure a destination and filters in Integrations. Rules start disabled. A webhook signing secret is separate from your REST key because it verifies messages sent to you—it is not a second credential required for API requests. Copy it once into the receiving server’s secret manager.
Destinations require public HTTPS on port 443, no URL credentials/fragments, and public DNS. Atlas revalidates public addresses, pins the TLS connection and does not follow redirects. Localhost and private-network destinations are not accepted. Activation only covers newly recorded, effectively available, eligible records; it never sends the entire archive.
Atlas-Signature: t=<unix-seconds>,v1=<hex-hmac>
Atlas-Delivery-Id: <stable-delivery-id>
Atlas-Event-Id: <lineage-id>
Atlas-Event-Version-Id: <immutable-version-id>
Atlas-Attempt: <attempt-number>
signed_bytes = UTF8("v1." + timestamp + ".") + exact_raw_body
signature = HMAC-SHA256(signing_secret, signed_bytes)The body is the exact canonical event object, not a REST-page envelope. Verify the raw request bytes before JSON parsing, compare signatures in constant time and reject timestamps outside ±5 minutes.
import hashlib, hmac, re, time
def verify_atlas(raw_body: bytes, signature_header: str, signing_secret: str):
match = re.fullmatch(r"t=(\d+),v1=([0-9a-f]{64})", signature_header)
if not match:
raise ValueError("Malformed signature")
timestamp, signature = match.groups()
if abs(int(time.time()) - int(timestamp)) > 300:
raise ValueError("Stale or future signature")
signed_bytes = ("v1." + timestamp + ".").encode("utf-8") + raw_body
expected = hmac.new(signing_secret.encode("utf-8"), signed_bytes,
hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature):
raise ValueError("Invalid signature")
# Parse JSON only now. Transactionally deduplicate Atlas-Delivery-Id.
# Return 2xx only after durable acceptance, including known duplicates.
Delivery is at least once: transactionally deduplicate Atlas-Delivery-Id. Retries retain that ID. Return 2xx only after durable acceptance; five automatic attempts use bounded exponential backoff and deterministic jitter. Exhausted attempts remain visible in account delivery history for eligible owner recovery. No persistent customer streaming or programmatic rule-management endpoint is advertised in V1.
Rights, current paid access, destination, suppression, filters and event availability are checked again before sends. Prior-recipient withdrawals require an actual delivered receipt for that lineage/rule. Email goes only to the verified account address; provider acceptance is not delivery or an inbox guarantee.
External customer dispatch is disabled in this private preview. Configuring a rule does not prove that outbound delivery is active or that production callbacks have passed acceptance.
