Reporting API
The Reporting API gives you programmatic, read-only access to your ad revenue and performance data — the same data that powers the publisher dashboard.
| Endpoint | Use it for |
|---|---|
| Impression-level report | One row per impression, with CPM, ad unit, format, country, OS, and your user ID. Ideal for revenue attribution and data-warehouse ingestion. |
| Aggregate report | Grouped metrics (revenue, impressions, fill rate, …) by date, ad unit, format, country, OS, or status. Ideal for dashboards and finance reporting. |
Base URL
https://simula-api-701226639755.us-central1.run.app/reporting/v1/publisherAuthentication
Every request requires a reporting API key in the Authorization header:
Authorization: Bearer <your-reporting-key>Keys are issued by your Simula account manager and are scoped to one or more publisher IDs. If you haven't received yours, reach out over your usual channel — Email, Slack, WhatsApp, or WeChat.
Conventions
- Timezone — all timestamps are UTC, and daily buckets are UTC calendar days. A trailing
Zon datetimes is accepted. - Currency — all monetary values are USD.
- Date range — each request may span at most 31 days. For longer windows, issue multiple requests.
- Impressions — an ad counts as an impression only once it is actually displayed to the user. Ads served but never shown count toward
SERVED, earn no revenue, and never appear in the impression-level report.
Estimated vs. Final Revenue
Every impression carries a status:
| Status | Meaning |
|---|---|
estimated | Serve-time revenue estimate, available immediately. |
final | Settled revenue. Settlement completes 7 days after the impression is served; the final value then supersedes the estimated value. |
Syncing revenue into your own systems
Data starts as estimated and becomes final 7 days after serve. Re-pull the last 7 days on each sync and overwrite rows by key (impression ID, or dimension combination for aggregates) rather than appending, so finalized values replace estimates.
Pagination
Both endpoints use cursor-based pagination. Each response includes:
{
"pagination": {
"next_cursor": "eyJvIjo1MDAwLCJlIjoi...",
"has_more": true
}
}Omit cursor on the first request. While has_more is true, repeat the request with cursor set to next_cursor, keeping all other parameters identical.
- Cursors are bound to the exact query that produced them — changing any parameter invalidates the cursor (
400 Invalid cursor). - Cursors expire after 24 hours.
Rate Limits
| Scope | Limit |
|---|---|
| Per API key | 60 requests / minute |
| Per IP (unauthenticated) | 20 requests / minute |
Exceeding a limit returns 429. Back off and retry after a short delay — with page sizes of up to 10,000 rows, most workloads fit comfortably under the limit.
Errors
| Status | Meaning |
|---|---|
400 | Invalid request — malformed dates, date_end not after date_start, range over 31 days, invalid or expired cursor, or an unsupported metric/dimension combination. The detail field explains the problem. |
401 | Missing or unknown API key. |
403 | Key is not authorized for the requested publisher_id. |
429 | Rate limit exceeded. |
{
"detail": "Date range exceeds 31 days"
}