REST API and CSV exports
Read-only REST API (v1) with API keys (Growth, Pro and Enterprise), plus CSV downloads and the Excel report (every plan).
- The REST API and API keys are on the Growth (1 key, 1,000 calls per day), Pro (5 keys, 10,000 calls per day) and Enterprise (up to 10 active keys, no daily cap) plans. The trial and Starter have no API.
- CSV downloads and the Excel report are on every plan. To get the report by email on a schedule, see Alerts and notifications.
API keys
An owner creates keys in Settings → API.
- A key looks like
dp_live_…. The full key is shown once. Store it safely. - Keys are read-only. No endpoint changes data.
- The number of active keys depends on your plan: 1 on Growth, 5 on Pro, up to 10 on Enterprise. Revoke a key to stop it at once and free its slot.
- After a downgrade to a plan without the API, keys are kept but every call answers
403 plan_required.
Send the key in the Authorization header:
curl -H "Authorization: Bearer dp_live_…" https://slashpeak.com/api/v1/spend/summary?days=30Rules
- Base path:
/api/v1. A breaking change gets a new version (/api/v2). - All endpoints are
GETand return JSON. Endpoints marked CSV also take?format=csv. - Money is in USD. Days are whole calendar days in your account timezone (Settings → General), today included:
days=7is today and the 6 days before it. - An account can have several connections. Without
?connection=, an endpoint reads your default (newest active) connection. List your connections with/api/v1/connectionsand pass anidas?connection=<id>to read another. Every endpoint takesconnection. - Rate limits: 60 requests per minute per key, plus a daily cap per account (1,000 on Growth, 10,000 on Pro, none on Enterprise; days are UTC). Over a limit you get
429and aRetry-Afterheader. - Errors always have this shape:
{ "error": { "code": "plan_required", "message": "The API needs the Growth, Pro or Enterprise plan." } }| Status | code | Meaning |
|---|---|---|
| 400 | invalid_request | A query parameter is wrong. |
| 401 | unauthorized | No key, a wrong key, or a revoked key. |
| 403 | plan_required | The account is not on Growth, Pro or Enterprise. |
| 404 | no_connection | The account has no active BigQuery connection. |
| 429 | rate_limited | Too many requests for this key. |
| 500 | internal_error | Try again. |
Endpoints
| Endpoint | Parameters | CSV |
|---|---|---|
/api/v1/connections | none | yes |
/api/v1/spend/summary | days (1–90, default 30) | yes |
/api/v1/spend/daily | from, to (YYYY-MM-DD), or days (not both); groupBy = project | user | cost_center | yes |
/api/v1/spend/by-user | days, limit (1–1000) | yes |
/api/v1/tables/top | limit (1–1000) | yes |
/api/v1/storage | datasetId (optional) | no |
/api/v1/reservations | days (1–30, rounded up to 1, 7 or 30), limit | yes |
/api/v1/findings | status = open | all, type, limit (1–200), cursor | yes |
/api/v1/queries/repeated | days, limit | yes |
Spend
- spend/summary: compute and other usage spend per day (other includes network egress, BigQuery Omni and Datastream when you set up the billing export), plus the current storage monthly rate.
- spend/daily: compute spend per day per project, user, or cost center. Cache hits cost 0. The range is at most 90 days and
from/toare inclusive.toafter today counts as today, andfrombefore your data starts moves to the first day of your data, so the reply'sfromcan differ from the one you sent. A range with no days is a400.dayscannot be combined withfromorto; with onlyto, you get the 30 days up to it. If there are more than 100,000 rows the reply has"truncated": true, drops the oldest days, andfrommoves forward. - spend/by-user: compute spend per user in the window.
"truncated": truemeans more users spent thanlimitreturned.
Findings
Findings are sorted by estimated monthly savings. A page has at most 200 rows. When there are more, the reply has nextCursor. Send it back as ?cursor= with the same status and type to get the next page; a cursor used with different filters is a 400. Paging stays correct if findings resolve while you page.
curl -H "Authorization: Bearer $KEY" "https://slashpeak.com/api/v1/findings?status=open&limit=100"Storage and tables
- tables/top: datasets ranked by storage cost (a monthly rate).
"truncated": truemeans there are more datasets thanlimit. - storage: storage cost by class (active, long-term, time travel, fail-safe) as a monthly rate. Amounts have 4 decimals.
Excel report
The dashboard has an Email report button next to the range buttons. It sends the Excel file to your email. Nothing downloads in the browser. It uses the range, project, region and cost center you picked. It is the same file the report email attaches, with only the parts you get (see Report emails).
- The page tells you that the report is on its way. The email arrives when the file is ready.
- Your Reports setting (Settings → Notifications → Reports) must not be Never. If it is, the page tells you to turn it on first. A viewer can also ask an account owner to turn it on.
- Owners and viewers can use it. An admin who views your account cannot.
One tab per dashboard section, plus Findings:
- Executive summary: the key numbers, daily spend, daily health, spend by cost center and BigQuery SKUs.
- Top offenders: top queries, users, projects, pipelines, datasets and tables, and tables read. Top lists hold the rows the dashboard shows.
- Operational efficiency: savings opportunities, unused tables, failure rate by user, partition use, cache hit ratio and slot utilization.
- Anomalies: every anomaly in the range, except ones marked "Not an anomaly".
- Findings: every open finding of the connection, largest saving first.
The Export CSV button on Findings downloads the open findings as one CSV.
CSV format
UTF-8 with a byte-order mark (for Excel), a header row, and RFC 4180 quoting. A text cell that starts with =, +, -, @, tab, or carriage return gets a leading ', so a spreadsheet does not run it as a formula. SQL comments that start with -- are left as they are. Numbers have at most 8 decimals. A cell is cut at 32,767 characters, the Excel limit. Excel files (.xlsx) hold text as typed text and add no '.