How Renovara SQL works
The Renovara SQL API runs read-only DuckDB SQL over Australian electricity and gas market data from AEMO, from your own code and AI agents. Below is the whole API, its endpoints, sign-in, how statements run, the SQL dialect, limits, errors and the tables.
What the Renovara SQL API is
The Renovara SQL API gives an organisation's own software read-only SQL access to the Australian National Electricity Market (NEM) and east coast gas market tables that Renovara holds. The data is AEMO's published market data, cleaned and refreshed daily: electricity dispatch at AEMO's five-minute interval, much of it from January 2019, and AEMO Gas Bulletin Board data by gas day.
You send one DuckDB SELECT over HTTPS. A quick query answers in the same call; a slow one returns a statement ID to poll. Results come back as rows, and every result is also a Parquet file.
It is built for organisations that serve many clients and systems from their own code: client reporting and data products, scheduled jobs and notebooks, and AI agents that write and run their own SQL. It is an enterprise plan, separate from the subscription that connects Claude or ChatGPT to Renovara through an MCP server (see How Renovara works). Both read the same tables and the same analyst guide, so a table means the same thing in each. The plan and its trial are described at renovara.co/sql-api.
Where to start
An agent or program needs nothing but the base URL to learn the API and the data. These calls need no credentials:
GET https://sql.api.renovara.co/v1/says what the service is, the SQL dialect and its version, how to sign in, the trial's limits, and links to everything below.GET /v1/guide?domain=nem(ordomain=gas) returns the analyst guide: which table answers which question, the traps in each table, worked SQL, and the DuckDB translations. Read it before the first query.GET /v1/tableslists every table;GET /v1/tables/{table}gives one table's columns and their meaning.- With an access token,
POST /v1/statementsruns a query.
The API's own description is OpenAPI 3.1 at https://sql.api.renovara.co/v1/openapi.json, with a plain-English description of every operation, field and error. Agent frameworks can build tools straight from it.
Base URL and endpoints
The base URL is https://sql.api.renovara.co/v1. Every path below is relative to it. Requests and responses are JSON, except the guide, which is markdown.
Public routes
These need no credentials.
| Route | What it returns |
|---|---|
GET / | What the service is, the SQL dialect and version, the market time zone, how to authenticate (token URL, scope, where to get credentials), the trial's limits, and links to the routes below. |
GET /openapi.json | The OpenAPI 3.1 description of the API. |
GET /.well-known/oauth-protected-resource | OAuth 2.0 Protected Resource Metadata (RFC 9728): the authorization server that issues tokens for this API and the scope to ask for. |
GET /guide?domain=nem | The analyst guide as markdown. domain is nem (electricity, the default) or gas. |
GET /tables | Every table you can query, with a one-line description. |
GET /tables/{table} | One table: its columns with their types and meaning, primary key, update frequency and measured coverage. |
GET /reference?path=references/schema-index.md | A reference file the guide points to, by its references/ path. Optional domain (nem or gas). |
Statement routes
These need an access token (see Authentication).
| Route | What it does |
|---|---|
POST /statements | Runs one read-only SQL statement and waits briefly for its result. |
GET /statements/{statement_id} | A statement's state, and its result once it has succeeded. |
POST /statements/{statement_id}/cancel | Stops a pending or running statement. |
Credentials requested by an agent
These need no credentials. See Credentials for an agent's person.
| Route | What it does |
|---|---|
POST /trial/requests | Asks for credentials (and a trial, if needed) for a named person, who approves. |
GET /trial/requests/{device_code} | The request's status; once approved, the credentials, returned once. |
Authentication
The API uses OAuth 2.0 client credentials.
- Get credentials. On the Renovara credentials page, which the welcome email links to, the person who manages your organisation's account creates a set of credentials and downloads them as a file,
renovara-sql.json. The secret is shown once and never emailed. An organisation can hold several sets, one per system, and revoke any of them. - Exchange them for an access token at the token URL,
https://auth.api.renovara.co/oauth2/token, withgrant_type=client_credentialsand scoperenovara-sql/query. The token URL is also in your credentials file and inGET /v1/underauthentication.token_url. - Send the token on every statement call as
Authorization: Bearer <token>.
A token lasts 60 minutes. Cache it and reuse it for its hour, then fetch a new one: tokens are issued at a cost, so fetching one per query is wasteful and slower. The Python client does this for you.
The credentials file looks like this. Keep it private: anyone holding it can query as your organisation.
{
"api_url": "https://sql.api.renovara.co/v1/",
"token_url": "https://auth.api.renovara.co/oauth2/token",
"client_id": "...",
"client_secret": "...",
"scope": "renovara-sql/query"
}
Credentials for an agent's person
An AI agent without credentials can ask for them on its person's behalf. It never signs anyone up itself: the person approves.
- The agent sends
POST /v1/trial/requestswith{"email": "<the person's work email>", "agent": "<the agent's name>", "credentials_name": "<a name for the set>"}. Nothing is emailed. - The response has a
user_code, a link (verification_uri_complete) and adevice_code. The agent shows the person the link, which opens renovara.co/sql-api-approve. Thedevice_codeis the agent's secret: never show it. - The person signs in as the email the agent named, sees which agent asked and for what, and approves or denies. If they have no organisation, approving first sends them through Stripe Checkout to start a 30-day free trial (no card; Stripe asks for an address for tax), then back to the request, which is approved once the trial is set up. Until then the agent's poll answers
pending. - The agent polls
GET /v1/trial/requests/{device_code}everyintervalseconds. Once approved, the response holds the credentials, in the same form as the file above, returned once.
A request expires after 30 minutes.
Running a statement
Statements are submit-and-poll, so a long query never holds a connection open.
- Submit.
POST /v1/statementswith{"sql": "SELECT ...", "wait_seconds": 20}.wait_secondsis how long the call waits for the result, from 0 to 25; the default is 20. The SQL can be up to 100,000 bytes. - Read the state. If the statement finished in that time, the response has
"state": "SUCCEEDED"and the result, or"state": "FAILED"and anerror. Otherwise it isPENDINGorRUNNING, with astatement_id. - Poll.
GET /v1/statements/{statement_id}, with a short pause between calls, until the state isSUCCEEDEDorFAILED. - Cancel if you need to.
POST /v1/statements/{statement_id}/cancel. Itscancelfield iscancelled,requested(the query stops within a few seconds; keep polling) orfinished(it had already finished).
A statement is visible only to the client that submitted it, and lasts 24 hours. A statement's response carries statement_id, state, submitted_at (Unix seconds), started_at, finished_at and query_ms once known, then result or error.
Retries. Send an Idempotency-Key header (1 to 200 characters) with each submit. A retry with the same key returns the statement already made instead of running, and counting, it twice. Use a new key for each new statement and the same key only to retry it. The Python client sends one for you.
Dry runs. EXPLAIN SELECT ... returns DuckDB's query plan without running the query. EXPLAIN ANALYZE SELECT ... runs the query and returns the plan with its timings, not the rows.
Usage. Each submit's response includes usage: your plan, the query time used and allowed, statements today and the daily limit, the statements you may run at once and, on a trial, when it ends.
Results
result.columnslists each column'snameandtype;result.row_countis the number of rows.- A result of up to 10,000 rows and 4 MB comes back inline as
result.rows, an array of rows, each an array of values in column order, withrows_included: true. - Every successful result is also a Parquet file at
result.parquet_url. The link works for an hour; get the statement again for a fresh link. Results last 24 hours. - A result over 5,000,000 rows is refused with
RESULT_TOO_LARGE. Aggregate in SQL instead. - A statement stops at 300 seconds with
QUERY_TIMEOUT. Narrow the time range or the units, or aggregate before joining; see Writing fast queries.
DuckDB SQL
The API runs DuckDB, not Databricks SQL. The exact version is in GET /v1/ under dialect. The analyst guide's worked examples are written in Databricks SQL, because the guide is shared with Renovara's other services; the guide served by this API opens with the translations below, which override it where they differ.
- One read-only
SELECTper statement, orEXPLAIN/EXPLAIN ANALYZEof one. Anything else is refused withQUERY_REJECTED, as is a call to a function that reports the server's configuration. - Table names work bare (
silver_dispatchis_reports_dispatch_price) or fully qualified (external_data.nemweb.silver_dispatchis_reports_dispatch_price). SETTLEMENT_DAY. Every time-series table has this extra integer column first, soSELECT *returns one more column than the same table does through the MCP subscription's Databricks SQL. See Writing fast queries.- Market time. Market timestamps, such as
SETTLEMENTDATE, carry no time zone: they are plainTIMESTAMPvalues holding AEST wall-clock time (Australia/Brisbane, UTC+10, no daylight saving). Do not shift them. Columns ending_UTC, such asSETTLEMENTDATE_UTC, are real moments,TIMESTAMP WITH TIME ZONE, shown with+00. The session runs in UTC, sonow()is UTC: "the last hour" isSETTLEMENTDATE_UTC >= now() - INTERVAL 1 HOUR, and "now" in market time isCAST(current_timestamp AS TIMESTAMP) + INTERVAL 10 HOUR. - Quotes. Strings take single quotes. Double quotes name columns.
- NULLs.
ORDER BYputs NULLs last by default. Databricks puts them first in ascending order. - Rounding and approximate percentiles can differ from Databricks in the last digit.
- Traps. The guide sets out each table's traps, such as intervention pricing and market time. Read it before the first query.
| Databricks SQL | DuckDB |
|---|---|
unix_timestamp(ts) | epoch(ts) |
date_format(ts, 'yyyy-MM') | strftime(ts, '%Y-%m') |
to_timestamp(s, fmt) | strptime(s, fmt), with %-style formats |
date_add(d, n) | d + INTERVAL (n) DAY |
collect_list(x) | list(x) |
collect_set(x) | list(DISTINCT x) |
percentile_approx(x, p) | approx_quantile(x, p) |
named_struct(...) | struct_pack(...) |
from_utc_timestamp(current_timestamp(), 'Australia/Brisbane') | CAST(current_timestamp AS TIMESTAMP) + INTERVAL 10 HOUR |
date_trunc, max_by, min_by, hour, year, concat_ws, coalesce, QUALIFY and window functions work as written.
Writing fast queries
Every time-series table the SQL API serves is a plain copy whose first column is SETTLEMENT_DAY: an INTEGER in the form yyyymmdd (for example 20261020) holding the date of the table's main timestamp. That timestamp is whichever of SETTLEMENTDATE, INTERVAL_DATETIME, DATETIME, GasDate, EFFECTIVEDATE or START_DATE the table has.
- Filter on
SETTLEMENT_DAYas well as the timestamp. It lets the server skip whole files without reading them, and it is the main way to make a query fast. Keep the timestamp filter for the exact boundaries. - It is the timestamp's calendar date, not AEMO's trading day. The interval ending 2026-10-20 00:00 has
SETTLEMENT_DAY20261020. When you select by trading day, make theSETTLEMENT_DAYrange cover every timestamp you want, and let the timestamp filter make the exact cut. - Filter on units, constraints and regions where you can. Each copy is also clustered on whichever of
DUID,CONSTRAINTIDorREGIONIDit has, so a filter on that column lets the server skip files too. - Name the columns you need.
SELECT *returnsSETTLEMENT_DAYas well, one more column than the same table through the MCP subscription's Databricks SQL, and reading fewer columns is quicker. - Aggregate in SQL, and aggregate before joining large tables, rather than fetching rows to aggregate yourself.
For example, the average price in each region for October 2026. SETTLEMENTDATE marks the end of its 5-minute interval, as the guide explains, so October runs from the interval ending at 00:05 on 1 October to the one ending at 00:00 on 1 November, and SETTLEMENT_DAY reaches 20261101 to include that last one:
SELECT REGIONID, round(avg(RRP), 2) AS avg_price
FROM silver_dispatchis_reports_dispatch_price
WHERE SETTLEMENT_DAY BETWEEN 20261001 AND 20261101
AND SETTLEMENTDATE > TIMESTAMP '2026-10-01 00:00' AND SETTLEMENTDATE <= TIMESTAMP '2026-11-01 00:00'
AND INTERVENTION = 0
GROUP BY 1 ORDER BY 1
EXPLAIN SELECT ... shows the plan before you run a query, without running it.
Limits and the trial
The trial lasts 30 days. Its allowance is measured in query time, the time your statements spend running, not in a count of queries, because one query can take a hundred times as long as another. Limits apply to the whole organisation, across all its credentials.
| Trial limit | Value |
|---|---|
| Length | 30 days |
| Query time | 10 hours in total |
| Statements a day | 2,000, counted on Brisbane time (AEST) and reset at midnight |
| Statements running at once | 5 |
Limits on every plan:
| Limit | Value |
|---|---|
| Statements per request | One SELECT (or EXPLAIN of one) |
| SQL length | 100,000 bytes |
wait_seconds | 0 to 25 seconds |
| Statement run time | 300 seconds |
| Inline result | 10,000 rows and 4 MB; larger results as Parquet only |
| Result size | 5,000,000 rows |
| Parquet link | Valid for an hour |
| Statements and results | Kept for 24 hours |
A statement that fails through Renovara's fault (INTERNAL_ERROR) is not charged to your allowance. When a limit is reached, the error says which one and what to do; see Errors. Prices are on renovara.co/pricing.
Examples
Python
The Python client is renovara-sql on PyPI. It caches the token for its hour, polls slow statements, sends an idempotency key with every query, and returns rows, a pandas data frame or the Parquet file.
pip install renovara-sql
from renovara_sql import Client
# What the data is: no credentials needed.
public = Client("https://sql.api.renovara.co/v1")
print(public.guide()[:2000])
for t in public.tables():
print(t["table"], "-", t["description"][:80])
# Queries: the credentials file from the Renovara credentials page.
client = Client.from_file("~/.config/renovara-sql/acme.json")
result = client.query("""
SELECT REGIONID, round(avg(RRP), 2) AS avg_price
FROM silver_dispatchis_reports_dispatch_price
WHERE SETTLEMENT_DAY BETWEEN 20261020 AND 20261027
AND SETTLEMENTDATE > TIMESTAMP '2026-10-20 00:00' AND SETTLEMENTDATE <= TIMESTAMP '2026-10-27 00:00'
AND INTERVENTION = 0
GROUP BY 1 ORDER BY 1
""")
print(result.column_names, result.rows)
print(result.usage) # query time used, statements today
frame = result.to_pandas() # needs pandas
result.download("prices.parquet") # the whole result as Parquet
Client.from_env() reads RENOVARA_SQL_API_URL, RENOVARA_SQL_TOKEN_URL, RENOVARA_SQL_CLIENT_ID and RENOVARA_SQL_CLIENT_SECRET instead of a file. For control over a long query, use submit(sql), status(statement_id) and cancel(statement_id). A statement that ran and failed raises QueryFailed; a refused request raises RenovaraError. Both carry the error's code and docs_url.
curl
# From your credentials file
API_URL=https://sql.api.renovara.co/v1/
TOKEN_URL=https://auth.api.renovara.co/oauth2/token
CLIENT_ID=...
CLIENT_SECRET=...
# 1. An access token. Keep it for its hour: not one per query.
TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" -d grant_type=client_credentials \
-d scope=renovara-sql/query "$TOKEN_URL" | jq -r .access_token)
# 2. Submit a statement and wait up to 20 seconds for it.
curl -s -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"sql": "SELECT count(*) FROM silver_dispatchis_reports_dispatch_price WHERE SETTLEMENT_DAY = 20261020", "wait_seconds": 20}' \
"${API_URL}statements"
# -> {"statement_id": "...", "state": "SUCCEEDED", "result": {"columns": ..., "rows": ...}}
# or "state": "RUNNING": poll until it is SUCCEEDED or FAILED.
# 3. Poll a slow statement, or cancel it.
curl -s -H "Authorization: Bearer $TOKEN" "${API_URL}statements/<statement_id>"
curl -s -X POST -H "Authorization: Bearer $TOKEN" "${API_URL}statements/<statement_id>/cancel"
Data source
The market data comes from the Australian Energy Market Operator (AEMO) and is used under AEMO's copyright permissions. Some reference data comes from other public sources, such as the Australian Energy Regulator; their terms continue to apply to that data. Renovara loads the data as AEMO publishes it and refreshes it daily. Where you show the data to others, credit AEMO as its source, and the Australian Energy Regulator for data that comes from it. You may pass results on to any number of your own clients, in reports, portals, AI assistants and data products; you may not hand out your credentials or resell the API itself. Use of the API is covered by the terms of service.
The data does not include the Western Australian electricity or gas markets, today's intervals before the daily refresh has loaded them, or anyone's private data, such as meter reads or settlement statements.
Tables
The tables Renovara serves, grouped by what they cover. Query each by the name under its dataset, bare or as external_data.nemweb.<name>. GET /v1/tables returns the live list, and GET /v1/tables/{table} each table's columns and their meaning.
Electricity: prices, demand and dispatch
| Dataset | What it answers | Rows | From |
|---|---|---|---|
Dispatch pricessilver_dispatchis_reports_dispatch_price | Regional energy and frequency control (FCAS) prices for every five-minute interval. | 4.2 million | Jan 2019 |
Regional dispatch summarysilver_dispatchis_reports_dispatch_regionsum | Demand, generation, interchange and frequency control requirements per region, every five minutes. | 4.2 million | Jan 2019 |
Price settersilver_pricesetter_price_setter | Which unit set each region's price in each five-minute interval. | 86.8 million | Jan 2019 |
Unit output (SCADA)silver_dispatch_scada_dispatch_unit_scada | Measured output in MW of each dispatchable unit at the start of every interval. | 347.5 million | Jan 2019 |
Unit dispatch targetssilver_next_day_dispatch_dispatch_unit_solution | Each unit's dispatch target and frequency control enablement, every five minutes. | 359.1 million | Jan 2019 |
Bid trackingsilver_next_day_dispatch_dispatch_offertrk | Which bid or offer each unit was dispatched against, every five minutes. | 1.2 billion | Jan 2019 |
Interconnector flowssilver_dispatchis_reports_dispatch_interconnectorres | Flow, losses and limits on each interconnector, every five minutes. | 5.1 million | Jan 2019 |
Inter-regional flowssilver_dispatchis_reports_dispatch_interconnection | Flows and losses between regions, every five minutes. | 736,181 | Sep 2024 |
Local price adjustmentssilver_dispatchis_reports_dispatch_local_price | Local pricing offsets at each unit's connection point, every five minutes. | 10.3 million | Aug 2024 |
Dispatch run summarysilver_dispatchis_reports_dispatch_case_solution | One row per dispatch run, including interventions and solution status. | 229,021 | Sep 2024 |
Operational demandsilver_operational_demand_actual_operational_demand_actual | Measured operational demand per region, every half hour. | 199,245 | Aug 2024 |
Rooftop solar (estimated actual)silver_rooftop_pv_actual_rooftop_actual | AEMO's estimate of rooftop solar output per region, every half hour. | 2.7 million | Jan 2019 |
Electricity: forecasts
| Dataset | What it answers | Rows | From |
|---|---|---|---|
Rooftop solar forecastsilver_rooftop_pv_forecast_rooftop_forecast | AEMO's half-hourly rooftop solar forecast per region, up to eight days ahead. | 253.0 million | Jan 2019 |
Five-minute predispatch, regionssilver_p5_reports_p5min_regionsolution | Projected regional prices and demand for the next hour, in five-minute steps. | 6.1 million | Nov 2025 |
Five-minute predispatch, interconnectorssilver_p5_reports_p5min_interconnectorsoln | Projected interconnector flows for the next hour. | 7.5 million | Nov 2025 |
Five-minute predispatch, local pricessilver_p5_reports_p5min_local_price | Projected local price adjustments for the next hour. | 62.9 million | Nov 2025 |
Predispatch pricessilver_predispatchis_reports_predispatch_region_prices | Projected regional prices by half hour from each predispatch run. | 4.7 million | Nov 2025 |
Predispatch regional solutionsilver_predispatchis_reports_predispatch_region_solution | Projected regional demand, generation and reserves from each predispatch run. | 4.7 million | Nov 2025 |
Predispatch interconnectorssilver_predispatchis_reports_predispatch_interconnector_soln | Projected interconnector flows and losses from each predispatch run. | 5.8 million | Nov 2025 |
Predispatch local pricessilver_predispatchis_reports_predispatch_local_price | Projected local price adjustments from each predispatch run. | 46.0 million | Nov 2025 |
Electricity: constraints and losses
| Dataset | What it answers | Rows | From |
|---|---|---|---|
Binding constraintssilver_dispatchis_reports_dispatch_constraint | Binding and inter-regional constraints in each dispatch run, with their marginal values. | 218.4 million | Sep 2024 |
Constraint cataloguesilver___gencondata | The generic constraints AEMO uses, with their descriptions. | 98,570 | Jan 2025 |
Constraint setssilver___genconset | Which constraints belong to each constraint set. | 149,171 | Jan 2025 |
Constraint factors, connection pointssilver___spdcpc | The factor each constraint applies to each connection point. | 2.4 million | Jan 2025 |
Constraint factors, regionssilver___spdrc | The factor each constraint applies to regional generation and load. | 6,051 | Jan 2025 |
Marginal loss factorssilver_marginal_loss_factors_daily_mlf | Marginal loss factors by connection point, by effective date and version. | 1.0 million | Jul 2011 |
Electricity: registration and reference
| Dataset | What it answers | Rows | From |
|---|---|---|---|
Unit detailssilver___participant_registration_dudetailsummary | Each dispatchable unit's region, connection point, type and loss factors over time. | 433,915 | Jun 2007 |
Units to gensetssilver___participant_registration_dualloc | Which gensets make up each dispatchable unit, over time. | 27,526 | Oct 1998 |
Gensetssilver___participant_registration_genunits | Every genset AEMO has registered, retired units included. | 8,759 | Nov 2005 |
Market participantssilver___participant_registration_participant | Participant IDs, names and classes. | 24,074 | Jun 1998 |
Unit capacity historysilver___participant_registration_dudetail | Each unit's registered and maximum capacity and storage over time. | 40,055 | Oct 1998 |
Stationssilver___participant_registration_station | Every station AEMO has registered, with its name and address. | 5,823 | Nov 2003 |
Unit registerv_duid_registration | One current row per unit, with its region, station, participant, type, fuel and capacity. | 1,019 | Current list |
Unit fuel (AEMO)v_duid_fuel_aemo | Fuel type for each unit, in AEMO's classification. | 1,020 | Current list |
Unit fuel (AER)v_duid_fuel_aer | Fuel type for each unit, in the Australian Energy Regulator's classification. | 1,019 | Current list |
Gas: AEMO Gas Bulletin Board
| Dataset | What it answers | Rows | From |
|---|---|---|---|
Actual flows and storagesilver_gbb_actual_flow_storage | Daily production, flows and storage by facility. | 453,543 | Daily |
Pipeline connection flowssilver_gbb_pipeline_connection_flow | Daily flows at pipeline connection points. | 1.7 million | Daily |
Nominations and forecastssilver_gbb_nomination_forecast | Facility nominations and forecasts for coming gas days. | 9,355 | Daily |
Short-term capacity outlooksilver_gbb_short_term_capacity_outlook | Facility capacity for the coming days. | 12,028 | Daily |
Medium-term capacity outlooksilver_gbb_medium_term_capacity_outlook | Planned capacity changes over the coming months. | 34,826 | Daily |
Linepack capacity adequacysilver_gbb_linepack_capacity_adequacy | Daily linepack and capacity adequacy status by pipeline. | 3,834 | Daily |
Linepack zonessilver_gbb_linepack_zones | The pipeline segments linepack is reported for. | 56 | Daily |
Facilitiessilver_gbb_facilities | The Bulletin Board's register of facilities. | 159 | Daily |
Participantssilver_gbb_participants | Bulletin Board participants. | 260 | Daily |
Basinssilver_gbb_basins | Gas basins. | 15 | Daily |
Locationssilver_gbb_locations | Bulletin Board locations. | 25 | Daily |
Nodes and connection pointssilver_gbb_nodes_connection_points | Pipeline nodes and connection points. | 775 | Daily |
Errors
Every error carries a stable code, a message that says what to change, and a docs_url that links to the code's entry below. Agents can correct themselves from them.
A refused request returns an HTTP error status with the error as its body:
{"error": {"code": "DAILY_LIMIT", "message": "...", "docs_url": "https://renovara.co/how-renovara-sql-works#error-daily-limit"}}
A statement that ran and failed returns HTTP 200 with "state": "FAILED" and the same object in the statement's error field. DAILY_LIMIT and TOO_MANY_RUNNING responses carry a Retry-After header with the seconds to wait.
Refused requests
BAD_REQUEST
HTTP 400. The request is malformed: send JSON {"sql": "SELECT ..."}.
UNAUTHORIZED
HTTP 401. No valid access token. Exchange your client id and secret for one at the token URL (OAuth client credentials) and send it as a Bearer token.
A token lasts 60 minutes. Fetch a new one when it expires, and reuse it until then. See Authentication.
CLIENT_NOT_REGISTERED
HTTP 403. The credentials are valid but not registered to an organisation. Create credentials on the Renovara credentials page.
CLIENT_REVOKED
HTTP 403. These credentials were revoked. Create new ones.
SUBSCRIPTION_PAUSED
HTTP 403. The organisation's subscription is paused. Add a payment method in the Renovara customer portal to resume.
SUBSCRIPTION_ENDED
HTTP 403. The organisation's subscription has ended.
TRIAL_ENDED
HTTP 403. The 30-day trial has ended. Subscribe to continue.
Prices are on renovara.co/pricing.
ALLOWANCE_USED
HTTP 403. The plan's query-time allowance is used up. Subscribe to continue.
The trial's allowance is 10 hours of query time in total. See Limits and the trial.
NOT_FOUND
HTTP 404. No such statement for this client (statements last 24 hours), table, reference or route.
A statement is visible only to the client that submitted it, and lasts 24 hours.
DAILY_LIMIT
HTTP 429. The organisation's statements for today (Brisbane time) are used up. Retry-After says when the count resets.
The trial allows 2,000 statements a day for the whole organisation.
TOO_MANY_RUNNING
HTTP 429. The organisation has its maximum statements running. Wait for one to finish, or cancel one; Retry-After suggests when to try.
The trial allows 5 statements running at once for the whole organisation.
THROTTLED
HTTP 429. Too many requests a second. Back off and retry.
Failed statements
QUERY_REJECTED
Statement state FAILED (HTTP 200). not one read-only SELECT, or it calls a function that reports the server's configuration. Rewrite and resubmit.
EXPLAIN SELECT ... and EXPLAIN ANALYZE SELECT ... are accepted as well as SELECT.
SQL_ERROR
Statement state FAILED (HTTP 200). DuckDB could not run the SQL. The message is DuckDB's; the API runs DuckDB, not Databricks SQL.
The most common cause is Databricks syntax. See DuckDB SQL for the translations.
QUERY_TIMEOUT
Statement state FAILED (HTTP 200). it ran past 300 seconds. Narrow the time range or the units, or aggregate before joining.
Filtering on SETTLEMENT_DAY as well as the timestamp is the main way to make a query faster. See Writing fast queries.
RESULT_TOO_LARGE
Statement state FAILED (HTTP 200). over 5,000,000 rows. Aggregate or page.
CANCELLED
Statement state FAILED (HTTP 200). it was cancelled.
TIMED_OUT
Statement state FAILED (HTTP 200). the worker stopped without recording a result.
Resubmit the statement. If it happens again, email info@renovara.co with the statement ID.
INTERNAL_ERROR
Statement state FAILED (HTTP 200). Renovara's failure, not the query's. Retry; it is not charged to your allowance.
If it happens again, email info@renovara.co with the statement ID.
Try it with your own code.
A 30-day free trial with 10 hours of query time and no card. The guide and the table schemas are open to read before you sign up.