{"openapi": "3.1.0", "info": {"title": "Renovara SQL API", "version": "1", "description": "Read-only SQL over Australian National Electricity Market (NEM) and east coast gas market data from AEMO, five-minute dispatch intervals since 2019. You send DuckDB SQL; a quick query answers in the same call, a slow one returns a statement id to poll. The dialect is DuckDB 1.5.6, not Databricks SQL: read GET /guide first, which lists the differences. Only one read-only SELECT (or EXPLAIN SELECT) per statement.", "contact": {"email": "info@renovara.co", "url": "https://renovara.co"}}, "servers": [{"url": "https://sql.api.renovara.co/v1"}], "externalDocs": {"url": "https://renovara.co/how-renovara-sql-works", "description": "How Renovara SQL works"}, "components": {"securitySchemes": {"oauth2": {"type": "oauth2", "description": "Client credentials from your Renovara credentials page.", "flows": {"clientCredentials": {"tokenUrl": "https://auth.api.renovara.co/oauth2/token", "scopes": {"renovara-sql/query": "Run read-only SQL queries"}}}}}, "schemas": {"Error": {"type": "object", "required": ["error"], "properties": {"error": {"type": "object", "required": ["code", "message"], "properties": {"code": {"type": "string", "enum": ["ALLOWANCE_USED", "BAD_REQUEST", "CANCELLED", "CLIENT_NOT_REGISTERED", "CLIENT_REVOKED", "DAILY_LIMIT", "INTERNAL_ERROR", "NOT_FOUND", "QUERY_REJECTED", "QUERY_TIMEOUT", "RESULT_TOO_LARGE", "SQL_ERROR", "SUBSCRIPTION_ENDED", "SUBSCRIPTION_PAUSED", "THROTTLED", "TIMED_OUT", "TOO_MANY_RUNNING", "TRIAL_ENDED", "UNAUTHORIZED"], "description": "Stable error code; see the API description for each."}, "message": {"type": "string", "description": "What happened and what to do."}, "docs_url": {"type": "string", "format": "uri"}}}}}, "StatementRequest": {"type": "object", "required": ["sql"], "properties": {"sql": {"type": "string", "maxLength": 100000, "description": "One DuckDB SELECT, or EXPLAIN [ANALYZE] SELECT to see the plan without fetching rows."}, "wait_seconds": {"type": "number", "minimum": 0, "maximum": 25, "default": 20, "description": "How long to wait for the result before returning a statement to poll."}}}, "Statement": {"type": "object", "properties": {"statement_id": {"type": "string"}, "state": {"type": "string", "enum": ["PENDING", "RUNNING", "SUCCEEDED", "FAILED"], "description": "Poll GET /statements/{statement_id} until SUCCEEDED or FAILED."}, "submitted_at": {"type": "integer", "description": "Unix seconds."}, "query_ms": {"type": "integer"}, "error": {"$ref": "#/components/schemas/Error/properties/error"}, "result": {"type": "object", "properties": {"columns": {"type": "array", "items": {"type": "object", "properties": {"name": {"type": "string"}, "type": {"type": "string"}}}}, "row_count": {"type": "integer"}, "rows": {"type": "array", "items": {"type": "array"}, "description": "Present when the result is at most 10,000 rows and 4 MB; otherwise fetch parquet_url."}, "rows_included": {"type": "boolean"}, "parquet_url": {"type": "string", "format": "uri", "description": "The whole result as Parquet; valid for an hour."}}}, "usage": {"type": "object", "description": "The organisation's use of its plan, on a submit: query_seconds_used/allowed, statements_today, statements_per_day, concurrent_statements, trial_ends_at."}, "cancel": {"type": "string", "enum": ["cancelled", "requested", "finished"]}}}}}, "paths": {"/statements": {"post": {"operationId": "submitStatement", "summary": "Run one read-only SQL statement", "description": "Waits up to wait_seconds for the result. Send an Idempotency-Key header to make a retry return the same statement instead of running it twice.", "security": [{"oauth2": ["renovara-sql/query"]}], "parameters": [{"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"type": "string", "maxLength": 200}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StatementRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Statement"}}}}, "400": {"description": "BAD_REQUEST: The request is malformed: send JSON {\"sql\": \"SELECT ...\"}.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "401": {"description": "UNAUTHORIZED: 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.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "403": {"description": "ALLOWANCE_USED: The plan's query-time allowance is used up. Subscribe to continue.; CLIENT_NOT_REGISTERED: The credentials are valid but not registered to an organisation. Create credentials on the Renovara credentials page.; CLIENT_REVOKED: These credentials were revoked. Create new ones.; SUBSCRIPTION_ENDED: The organisation's subscription has ended.; SUBSCRIPTION_PAUSED: The organisation's subscription is paused. Add a payment method in the Renovara customer portal to resume.; TRIAL_ENDED: The 30-day trial has ended. Subscribe to continue.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "429": {"description": "DAILY_LIMIT: The organisation's statements for today (Brisbane time) are used up. Retry-After says when the count resets.; THROTTLED: Too many requests a second. Back off and retry.; TOO_MANY_RUNNING: The organisation has its maximum statements running. Wait for one to finish, or cancel one; Retry-After suggests when to try.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}}}, "/statements/{statement_id}": {"get": {"operationId": "getStatement", "summary": "A statement's state and, once it succeeded, its result", "security": [{"oauth2": ["renovara-sql/query"]}], "parameters": [{"name": "statement_id", "in": "path", "required": true, "schema": {"type": "string", "pattern": "^[0-9a-f]{32}$"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Statement"}}}}, "401": {"description": "UNAUTHORIZED: 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.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "403": {"description": "ALLOWANCE_USED: The plan's query-time allowance is used up. Subscribe to continue.; CLIENT_NOT_REGISTERED: The credentials are valid but not registered to an organisation. Create credentials on the Renovara credentials page.; CLIENT_REVOKED: These credentials were revoked. Create new ones.; SUBSCRIPTION_ENDED: The organisation's subscription has ended.; SUBSCRIPTION_PAUSED: The organisation's subscription is paused. Add a payment method in the Renovara customer portal to resume.; TRIAL_ENDED: The 30-day trial has ended. Subscribe to continue.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "404": {"description": "NOT_FOUND: No such statement for this client (statements last 24 hours), table, reference or route.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}}}, "/statements/{statement_id}/cancel": {"post": {"operationId": "cancelStatement", "summary": "Stop a pending or running statement", "security": [{"oauth2": ["renovara-sql/query"]}], "parameters": [{"name": "statement_id", "in": "path", "required": true, "schema": {"type": "string", "pattern": "^[0-9a-f]{32}$"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Statement"}}}}, "401": {"description": "UNAUTHORIZED: 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.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "403": {"description": "ALLOWANCE_USED: The plan's query-time allowance is used up. Subscribe to continue.; CLIENT_NOT_REGISTERED: The credentials are valid but not registered to an organisation. Create credentials on the Renovara credentials page.; CLIENT_REVOKED: These credentials were revoked. Create new ones.; SUBSCRIPTION_ENDED: The organisation's subscription has ended.; SUBSCRIPTION_PAUSED: The organisation's subscription is paused. Add a payment method in the Renovara customer portal to resume.; TRIAL_ENDED: The 30-day trial has ended. Subscribe to continue.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "404": {"description": "NOT_FOUND: No such statement for this client (statements last 24 hours), table, reference or route.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}}}, "/trial/requests": {"post": {"operationId": "requestCredentialsForPerson", "summary": "Ask for a trial (or new credentials) for your person, who approves", "description": "Returns a link and short code to show the person, and a device_code to poll. Nothing is emailed; the request expires in 30 minutes. The person signs in as the email given and approves; without an organisation they get the 30-day trial.", "security": [], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "required": ["email"], "properties": {"email": {"type": "string", "format": "email", "description": "Your person's work email."}, "agent": {"type": "string", "description": "Your name, shown to them."}, "credentials_name": {"type": "string", "default": "agent"}}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {}}}}, "400": {"description": "BAD_REQUEST: The request is malformed: send JSON {\"sql\": \"SELECT ...\"}.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}}}, "/trial/requests/{device_code}": {"get": {"operationId": "pollCredentialsRequest", "summary": "Poll a request; once approved, the credentials (returned once)", "description": "status is pending, approved, denied or delivered. Poll at `interval` seconds.", "security": [], "parameters": [{"name": "device_code", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {}}}}, "404": {"description": "NOT_FOUND: No such statement for this client (statements last 24 hours), table, reference or route.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}}}, "/tables": {"get": {"operationId": "listTables", "summary": "Every table, with a one-line description", "security": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {}}}}}}}, "/tables/{table}": {"get": {"operationId": "describeTable", "summary": "A table's columns with their meaning, primary key and coverage", "security": [], "parameters": [{"name": "table", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {}}}}, "404": {"description": "NOT_FOUND: No such statement for this client (statements last 24 hours), table, reference or route.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}}}, "/guide": {"get": {"operationId": "readGuide", "summary": "The analyst guide: which table answers what, the traps, worked SQL", "description": "Markdown. Read it before the first query.", "security": [], "parameters": [{"name": "domain", "in": "query", "required": false, "schema": {"type": "string", "enum": ["nem", "gas"], "default": "nem"}}], "responses": {"200": {"description": "The guide", "content": {"text/markdown": {"schema": {"type": "string"}}}}}}}, "/reference": {"get": {"operationId": "readReference", "summary": "A file the guide points to, by its references/ path", "security": [], "parameters": [{"name": "path", "in": "query", "required": true, "schema": {"type": "string"}, "example": "references/schema-index.md"}, {"name": "domain", "in": "query", "required": false, "schema": {"type": "string", "enum": ["nem", "gas"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {}}}}, "404": {"description": "NOT_FOUND: No such statement for this client (statements last 24 hours), table, reference or route.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}}}}}