API reference
The ROASaurus REST API, webhooks, SQL, warehouse exports, Google Sheets and Looker Studio.
Authentication
Create API keys under Store settings › API & data. Each key belongs to one store and has scopes. Send it as Authorization: Bearer rsk_…. Keys can be revoked at any time; the list shows when each was last used. The older store key pair (X-Roasaurus-Key plus Authorization: Bearer <key>) keeps working with every scope except pii.
| Scope | Gives |
|---|---|
orders:read | Orders with attribution and profit per order, order items |
customers:read | Customers with LTV and predicted LTV |
ads:read | Ad spend per platform, campaign and day |
attribution:read | Attribution by channel and campaign under any model |
profit:read | P&L by day, products and cohorts |
subscriptions:read | Subscription analytics |
leads:read | Leads, pipeline and lead attribution |
events:read | Storefront and offline events of consenting visitors |
metrics:read | Custom dashboards and metrics |
reports:read | Ready-made reports as JSON or CSV (Looker Studio, Sheets); each report also needs its area scope |
sql:read | Read-only SQL over the store views |
mcp | The MCP server (the Ask AI tools) |
pii | Unmasked emails, phone numbers, names, addresses, IP addresses and user agents |
write | POST orders, offline events, survey answers and expenses |
actions:write | MCP clients may propose ad changes to the Actions inbox (an owner or admin, or a rule, still applies them) |
Conventions
- Pagination. Lists return
{ "data": [...], "has_more": true, "next_cursor": "…" }. Passnext_cursorascursoruntilhas_moreis false.limitsets the page size. - Dates.
fromandtotake a store-local day (YYYY-MM-DD;toincludes that whole day) or an ISO 8601 timestamp.updated_sincereturns what changed, for incremental syncs. Amounts are in the store currency. - Errors.
{ "error": "readable message", "code": "invalid_parameter" }with the HTTP status: 401 bad key, 403 missing scope, 404, 422 bad parameter, 429 rate limited. - Rate limits. 120 read requests a minute per key (1000 for writes). Every response carries
X-RateLimit-Limit,X-RateLimit-RemainingandX-RateLimit-Reset; a 429 carriesRetry-After. - Personal data and consent. Without the
piiscope, emails are masked (j***@example.com) and given asemail_sha256; phone numbers, names, addresses, IP addresses and user agents are left out. Visitor ids, clicks and storefront events exist only for visitors who gave consent. - OpenAPI. The machine-readable description is at
/api/v1/openapi.json(OpenAPI 3.1): import it into Postman, Insomnia or a client generator.
Endpoints
Account
GET /api/v1/openapi.json · no key
This OpenAPI document.
GET /api/v1/me · scope any
The store and scopes of the key. Works with a key of any scope.
Returns: store, key
Orders
GET /api/v1/orders · scope orders:read
Orders with attribution and profit. Oldest first. Each order carries its profit (revenue, COGS, fees, gross profit, contribution margin), line items with their costs, and its attribution: the model credits plus first and last click inside the lookback.
from | Start: a store-local day (YYYY-MM-DD) or an ISO 8601 timestamp. |
to | End (exclusive for timestamps; a day includes that whole day). |
updated_since | Only rows changed at or after this time (incremental sync). |
model | Attribution model. (last_click, first_click, last_non_direct, linear, linear_paid, position, time_decay, markov, shapley, total_impact, any_click, clicks_views) |
lookback | Click lookback in days (1–365) or "all"; default the store setting. |
limit | Page size (1–1000). |
cursor | The next_cursor of the previous page. |
Returns: has_more, next_cursor, data[].id, data[].name, data[].created_at, data[].updated_at, data[].currency, data[].financial_status, data[].fulfillment_status, data[].cancelled_at, data[].sales_channel, data[].order_type, data[].total_price, data[].gross_sales, data[].discounts, data[].shipping_charged, data[].taxes, data[].tips, data[].new_customer, data[].profit, data[].customer, data[].discount_codes, data[].tags, data[].utm, data[].landing_site, data[].referring_site, data[].client, data[].attribution, data[].items
GET /api/v1/orders/{id} · scope orders:read
One order.
id * | Order id |
model | Attribution model. (last_click, first_click, last_non_direct, linear, linear_paid, position, time_decay, markov, shapley, total_impact, any_click, clicks_views) |
lookback | Click lookback in days (1–365) or "all"; default the store setting. |
Returns: id, name, created_at, updated_at, currency, financial_status, fulfillment_status, cancelled_at, sales_channel, order_type, total_price, gross_sales, discounts, shipping_charged, taxes, tips, new_customer, profit, customer, discount_codes, tags, utm, landing_site, referring_site, client, attribution, items
Customers
GET /api/v1/customers · scope customers:read
Customers with LTV and predicted LTV. `from`/`to` filter on the first order, `updated_since` on the last order.
from | Start: a store-local day (YYYY-MM-DD) or an ISO 8601 timestamp. |
to | End (exclusive for timestamps; a day includes that whole day). |
updated_since | Only rows changed at or after this time (incremental sync). |
limit | Page size (1–1000). |
cursor | The next_cursor of the previous page. |
Returns: has_more, next_cursor, data[].id, data[].email, data[].email_sha256, data[].orders, data[].revenue, data[].gross_profit, data[].contribution, data[].aov, data[].first_order_at, data[].last_order_at, data[].first_order_id, data[].last_order_id, data[].first_order, data[].predicted_ltv, data[].expected_next_12m
GET /api/v1/customers/{id} · scope customers:read
One customer with their orders.
id * | Customer id |
Returns: id, email, email_sha256, orders, revenue, gross_profit, contribution, aov, first_order_at, last_order_at, first_order_id, last_order_id, first_order, predicted_ltv, expected_next_12m, recent_orders
GET /api/v1/cohorts · scope customers:read
Cohorts by first-order period.
by | Cohort period. (month, week, quarter, year) |
metric | Cohort metric (revenue, gross_profit, contribution, retention, ...). |
count | Number of cohorts (1–60). |
Returns: by, metric, currency, customers, average_cac, payback_period, average, data[].cohort, data[].start, data[].customers, data[].cac, data[].spend, data[].repeat_rate, data[].first_order, data[].payback_period, data[].values, data[].predicted
Ads
GET /api/v1/ad-spend · scope ads:read
Ad spend per platform, campaign and day.
from | First store-local day (YYYY-MM-DD). |
to | Last store-local day (YYYY-MM-DD). |
platform | Only this platform (meta, google, tiktok, ...). |
limit | Page size (1–5000). |
cursor | The next_cursor of the previous page. |
Returns: has_more, next_cursor, data[].day, data[].platform, data[].campaign_id, data[].campaign, data[].spend, data[].impressions, data[].clicks, data[].account_id, data[].account_currency, data[].spend_original, data[].manual
GET /api/v1/campaigns · scope ads:read
Spend, clicks, CTR and CPC per campaign.
period | A period like the dashboard; from and to (days) win over it. (today, yesterday, 7, 14, 30, 90, mtd, last_month, ytd, 365) |
from | First store-local day (YYYY-MM-DD). |
to | Last store-local day (YYYY-MM-DD). |
platform | Only this platform. |
Returns: from, to, currency, data[].platform, data[].campaign_id, data[].campaign, data[].spend, data[].impressions, data[].clicks, data[].ctr, data[].cpc, data[].first_day, data[].last_day, data[].days
Attribution
GET /api/v1/attribution · scope attribution:read
Attribution by channel and campaign.
period | A period like the dashboard; from and to (days) win over it. (today, yesterday, 7, 14, 30, 90, mtd, last_month, ytd, 365) |
from | First store-local day (YYYY-MM-DD). |
to | Last store-local day (YYYY-MM-DD). |
model | Attribution model. (last_click, first_click, last_non_direct, linear, linear_paid, position, time_decay, markov, shapley, total_impact, any_click, clicks_views) |
lookback | Click lookback in days (1–365) or "all"; default the store setting. |
date_basis | Count conversions on the order date or the click date. (order, click) |
conversion | What counts as a conversion: orders (default) or a lead stage such as leads or won. |
views | Include view-through credit (1 or true). |
view_weights | Per-platform view weights, e.g. meta:30. |
view_window | View window in days. (1, 7) |
survey_lookback | Total Impact survey lookback. |
position | Position-based weights, e.g. 40,20,40. |
half_life | Time decay half-life in days. |
Returns: currency, from, to, model, modelLabel, additive, totals, channels, campaigns
GET /api/v1/view-through · scope attribution:read
View-through conversions per platform and campaign. Reported by the platforms, placed on orders (modelled or verified) and credited after the view weights.
period | A period like the dashboard; from and to (days) win over it. (today, yesterday, 7, 14, 30, 90, mtd, last_month, ytd, 365) |
from | First store-local day (YYYY-MM-DD). |
to | Last store-local day (YYYY-MM-DD). |
lookback | Click lookback in days (1–365) or "all"; default the store setting. |
view_weights | Per-platform view weights, e.g. meta:30. |
view_window | View window in days. (1, 7) |
GET /api/v1/leads · scope leads:read
Leads and pipeline by channel and campaign. Leads, cost per lead, MQL/SQL/win rates, pipeline and won revenue, and leads per channel and campaign under any attribution model.
period | A period like the dashboard; from and to (days) win over it. (today, yesterday, 7, 14, 30, 90, mtd, last_month, ytd, 365) |
from | First store-local day (YYYY-MM-DD). |
to | Last store-local day (YYYY-MM-DD). |
model | Attribution model. (last_click, first_click, last_non_direct, linear, linear_paid, position, time_decay, markov, shapley, total_impact, any_click, clicks_views) |
lookback | Click lookback in days (1–365) or "all"; default the store setting. |
Returns: currency, from, to, model, note, totals, channels, campaigns, sources
Profit
GET /api/v1/profit · scope profit:read
P&L totals and days for a period.
period | A period like the dashboard; from and to (days) win over it. (today, yesterday, 7, 14, 30, 90, mtd, last_month, ytd, 365) |
from | First store-local day (YYYY-MM-DD). |
to | Last store-local day (YYYY-MM-DD). |
Returns: currency, from, to, totals, metrics, days
GET /api/v1/profit/daily · scope profit:read
P&L by day.
period | A period like the dashboard; from and to (days) win over it. (today, yesterday, 7, 14, 30, 90, mtd, last_month, ytd, 365) |
from | First store-local day (YYYY-MM-DD). |
to | Last store-local day (YYYY-MM-DD). |
limit | Page size (1–366). |
cursor | The next_cursor of the previous page. |
Returns: has_more, next_cursor, data[].day, data[].currency, data[].orders, data[].revenue, data[].cogs, data[].ad_spend, data[].gross_profit, data[].contribution_margin, data[].net_profit, data[].total_costs, currency
GET /api/v1/products · scope profit:read
Units, revenue, COGS and profit per product or variant.
period | A period like the dashboard; from and to (days) win over it. (today, yesterday, 7, 14, 30, 90, mtd, last_month, ytd, 365) |
from | First store-local day (YYYY-MM-DD). |
to | Last store-local day (YYYY-MM-DD). |
by | Group by product (default) or variant. (product, variant) |
limit | Page size (1–1000). |
cursor | The next_cursor of the previous page. |
Returns: has_more, next_cursor, data[].key, data[].product_id, data[].variant_id, data[].title, data[].sku, data[].units, data[].orders, data[].revenue, data[].refunds, data[].cogs, data[].gross_profit, data[].net_profit, data[].gross_margin, from, to, currency, by
GET /api/v1/subscriptions · scope subscriptions:read
Subscription analytics.
months | Months of MRR history. |
days | Days for churn and conversion. |
Events
GET /api/v1/events · scope events:read
Storefront events of consenting visitors, or offline events. `source=storefront` (default): page views, product views, adds to cart, checkouts and purchases from the store, only for visitors who consented; contact fields, IP and user agent need `pii`. `source=offline`: events sent to POST /api/v1/events.
source | Which events. (storefront, offline) |
name | Only this event name. |
from | Start: a store-local day (YYYY-MM-DD) or an ISO 8601 timestamp. |
to | End (exclusive for timestamps; a day includes that whole day). |
limit | Page size (1–1000). |
cursor | The next_cursor of the previous page. |
Returns: has_more, next_cursor, data[].id, data[].name, data[].event_id, data[].visitor_id, data[].url, data[].created_at, data[].data, data[].ip, data[].user_agent, data[].email_sha256, data[].value, data[].currency, data[].properties, data[].occurred_at
Metrics
GET /api/v1/metrics · scope metrics:read
Built-in and custom dashboard metrics.
Returns: data[].key, data[].label, data[].format, data[].category, data[].description, data[].custom, data[].formula
GET /api/v1/metrics/{key} · scope metrics:read
Evaluate a metric.
key * | A built-in or custom metric key. |
period | A period like the dashboard; from and to (days) win over it. (today, yesterday, 7, 14, 30, 90, mtd, last_month, ytd, 365) |
compare | Comparison period. (previous, yoy, none) |
channel | Only orders whose last ad click was on this channel. |
sales_channel | Only this sales channel. |
country | Only this shipping country. |
customer | New or returning customers. (new, returning) |
Returns: metric, label, format, currency, period, comparison, value, formatted, previous, change
GET /api/v1/dashboards · scope metrics:read
Custom dashboards shared with the workspace.
Reports
GET /api/v1/reports · scope reports:read
The ready-made reports.
Returns: data[].key, data[].label, data[].description, data[].scope, data[].available, data[].params, data[].columns
GET /api/v1/reports/{report} · scope reports:read
Run a report (JSON or CSV). Also needs the report's own scope. Reports: `pnl_daily` (profit:read), `attribution_channels` (attribution:read), `attribution_campaigns` (attribution:read), `ad_spend_daily` (ads:read), `campaigns` (ads:read), `orders` (orders:read), `products` (profit:read), `customers` (customers:read), `cohorts` (customers:read).
report * | Report key. (pnl_daily, attribution_channels, attribution_campaigns, ad_spend_daily, campaigns, orders, products, customers, cohorts) |
period | A period like the dashboard; from and to (days) win over it. (today, yesterday, 7, 14, 30, 90, mtd, last_month, ytd, 365) |
from | First store-local day (YYYY-MM-DD). |
to | Last store-local day (YYYY-MM-DD). |
model | Attribution model. (last_click, first_click, last_non_direct, linear, linear_paid, position, time_decay, markov, shapley, total_impact, any_click, clicks_views) |
lookback | Click lookback in days (1–365) or "all"; default the store setting. |
by | Cohorts: month, week, quarter or year. |
metric | Cohorts: the cohort metric. |
format | json (default) or csv. (json, csv) |
Returns: report, label, currency, from, to, columns, rows
GET /api/v1/feeds/{file} · no key
A signed CSV link (for Google Sheets IMPORTDATA). Created under Store settings › API & data. The URL carries the report parameters and an HMAC signature (`sig`); changing a parameter or revoking the link makes it invalid. No API key needed.
file * | <link id>.csv |
sig * | Signature |
SQL
POST /api/v1/sql · scope sql:read
Run a read-only SQL query over the store views. One SELECT over the views orders, order_items, refunds, customers, ad_spend, touches, events, offline_events, products and survey_responses. Read-only, at most 5000 rows, cost-limited and time-limited.
Body: sql, max_rows
Returns: columns, rows, row_count, truncated, elapsed_ms
Write
POST /api/v1/orders · scope write
Send a paid order.
Body: order_id, total, currency, email, phone, first_name, last_name, country, visitor_id, click_ids, client_ip, user_agent, created_at, items, subtotal, discounts, shipping, tax, discount_codes, order_type, test
POST /api/v1/events · scope write
Send an offline event.
Body: event, email, phone, value, currency, event_id, occurred_at, properties
POST /api/v1/expenses · scope write
Send costs (bills, subscriptions) to the P&L. From Zapier, Make or an accounting tool. Amounts in another currency are converted at the day's ECB rate.
Body: id, date, amount, currency, name, category, net_of_vat, expenses
Returns: saved
DELETE /api/v1/expenses/{eid} · scope write
Remove an expense sent through the API.
eid * | The id it was sent with |
Returns: deleted
POST /api/v1/surveys · scope write
Send a post-purchase survey answer.
Body: order_id, question, answer, visitor_id
Extension
GET /api/v1/extension/stores · browser extension key
Stores, attribution models and periods for the browser extension.
Returns: workspace, stores, models, periods
GET /api/v1/extension/metrics · browser extension key
ROASaurus numbers per campaign, ad set or ad id, for the ads managers.
store * | Store id |
platform * | Ad platform |
level * | Entity level (campaign, adset, ad) |
ids * | Comma-separated campaign, ad set or ad ids |
model | Attribution model. (last_click, first_click, last_non_direct, linear, linear_paid, position, time_decay, markov, shapley, total_impact, any_click, clicks_views) |
period | Period |
Returns: store, currency, rows, unmatched
Webhooks
Under API & data › Webhooks, subscribe an https URL to events. ROASaurus POSTs JSON { "id", "type", "created_at", "store": { "id", "domain", "currency" }, "data": { … } }:
order.attributed | An order was recorded and matched to its clicks (last click, first click, number of touches) |
daily_summary.ready | Yesterday's revenue, orders, ad spend, MER and net profit, each morning |
alert.raised | A new alert: orders or ROAS drop, spend spike, tracking outage, failed deliveries, spend sync |
spend.synced | Ad spend was synced, with spend per platform for the synced days and any errors |
Each request carries X-Roasaurus-Signature: t=<unix time>,v1=<hex>: v1 is the HMAC-SHA256 of "<t>.<raw body>" with the endpoint's signing secret. Compare in constant time and reject timestamps older than 5 minutes. Answer with a 2xx within 10 seconds. Other answers are retried after 1 minute, 5 minutes, 30 minutes, 2, 6, 12 and 24 hours; every attempt is in the delivery log, where a delivery can be sent again. The same event id is never delivered twice to one endpoint unless you resend it.
SQL
Reports › SQL in the dashboard and POST /api/v1/sql run one read-only SELECT over these views of the store: orders, order_items, refunds, customers, ad_spend, touches, events, offline_events, products, survey_responses. Other tables, system catalogs, writes and most functions are refused; a query whose plan is too expensive is refused before it runs, and one that runs longer than 10 seconds is stopped. At most 5,000 rows come back.
Warehouse exports
Under API & data › Warehouse, export to BigQuery, Snowflake, Amazon Redshift, Amazon S3, Google Cloud Storage or Azure Blob Storage, hourly or daily. Each run replaces the days that changed since the last run, so repeating a run is safe. Tables:
orders | Every order with profit and attribution (last and first click, touches, match method). Partitioned by order_day. |
order_items | Order lines with their product cost (COGS) and handling. Partitioned by order_day. |
ad_spend | Spend, impressions and clicks per platform, campaign and day (store currency). Partitioned by day. |
touches | Ad and UTM clicks of consenting visitors, the steps of each journey. Partitioned by day. |
customers | Every identified customer with LTV and predicted LTV (full snapshot each run; emails as hashes). Full snapshot. |
daily_pnl | Every P&L line and the derived profit figures per store-local day. Partitioned by day. |
On S3, Cloud Storage and Azure each table is a folder with _schema.json and one file per day: <prefix>/orders/order_day=2026-10-01/part-00000.parquet (Parquet with gzip or uncompressed pages), or .jsonl.gz / .csv.gz. Customers are in customers/snapshot/.
Google Sheets
Two ways: connect Google under API & data › Google Sheets and pick a report or saved SQL query to keep a tab up to date hourly or daily; or create a signed CSV link under CSV links and use =IMPORTDATA("https://…") in any sheet.
Looker Studio
Looker Studio reads ROASaurus through a community connector, which Google runs as Apps Script in your own account. Download Code.gs and appsscript.json from API & data › Google Sheets & Looker Studio, paste them into a new project at script.google.com, create a test deployment, and open https://datastudio.google.com/datasources/create?connectorId=<deployment id>. Paste an API key with reports:read and the scopes of the reports you use, then pick a report and an attribution model. The data source's date range sets the period.