API Reference

The Overscore API powers query execution and dashboard deployment. All endpoints are served from overscore.dev.

Authentication

Requests are authenticated using one of two methods:

  • API key — passed in the request body as apiKey. Used by deployed dashboards to execute queries.
  • Session cookie — set automatically when you sign in to the Hub via Google OAuth. Used by the Hub UI and CLI.

API keys are scoped to a project. A valid API key can execute any registered query within that project.

POST /api/query

Execute a registered query against BigQuery and return the results. This is the endpoint that the useQuery hook calls under the hood.

Request

POST https://overscore.dev/api/query
Content-Type: application/json

Body:

{
  "projectSlug": "acme",
  "dashboardSlug": "sales-dashboard",
  "queryName": "revenue_by_month",
  "apiKey": "os_live_abc123..."
}

| Field | Type | Required | Description | |-------|------|----------|-------------| | projectSlug | string | Yes | Your project's unique slug | | dashboardSlug | string | Yes | The dashboard this query belongs to | | queryName | string | Yes | The registered query name to execute | | apiKey | string | Yes | Your project's API key |

Response

Success (200):

{
  "data": [
    { "month": "2025-01", "total_revenue": 52400 },
    { "month": "2025-02", "total_revenue": 61300 },
    { "month": "2025-03", "total_revenue": 58900 }
  ],
  "metadata": {
    "rowCount": 3,
    "executionTimeMs": 1240,
    "cached": false,
    "cacheUrl": null
  }
}

When caching is enabled and the cache is fresh:

{
  "data": [
    { "month": "2025-01", "total_revenue": 52400 },
    { "month": "2025-02", "total_revenue": 61300 }
  ],
  "metadata": {
    "rowCount": 2,
    "executionTimeMs": 12,
    "cached": true,
    "cacheUrl": "https://overscore.dev/cache/acme/sales-dashboard/revenue_by_month.parquet",
    "cacheTtl": 3600,
    "cacheExpiresAt": "2025-06-15T13:00:00Z"
  }
}

| Field | Type | Description | |-------|------|-------------| | data | array | Array of row objects. Each key is a column name. | | metadata.rowCount | number | Total number of rows returned | | metadata.executionTimeMs | number | Time to execute (BigQuery time, or cache retrieval time) | | metadata.cached | boolean | Whether the result was served from cache | | metadata.cacheUrl | string or null | URL to the Parquet file, if cached | | metadata.cacheTtl | number | Cache TTL in seconds (only present when cached) | | metadata.cacheExpiresAt | string | ISO 8601 expiration timestamp (only present when cached) |

Error responses

401 Unauthorized — invalid or missing API key:

{
  "error": "Invalid API key"
}

404 Not Found — query not registered:

{
  "error": "Query 'revenue_by_month' is not registered for dashboard 'sales-dashboard'"
}

500 Internal Server Error — BigQuery execution failure:

{
  "error": "Query execution failed",
  "detail": "BigQuery error: Table not found: my-project.analytics.orders"
}

POST /api/deploy

Deploy a built dashboard to Overscore. This endpoint accepts a multipart upload containing the build artifacts.

Request

POST https://overscore.dev/api/deploy
Content-Type: multipart/form-data
Authorization: Bearer <session-token>

Form fields:

| Field | Type | Required | Description | |-------|------|----------|-------------| | projectSlug | string | Yes | Your project's unique slug | | dashboardSlug | string | Yes | The dashboard slug to deploy to | | bundle | file | Yes | Gzipped tar of the dist/ build output |

The Authorization header uses the session token obtained from overscore login. The CLI handles this automatically.

Response

Success (200):

{
  "success": true,
  "url": "https://acme.overscore.dev/sales-dashboard/",
  "deployment": {
    "id": "dep_abc123",
    "createdAt": "2025-06-15T12:30:00Z",
    "sizeBytes": 245760
  }
}

| Field | Type | Description | |-------|------|-------------| | success | boolean | Whether the deployment succeeded | | url | string | The live URL of the deployed dashboard | | deployment.id | string | Unique deployment identifier | | deployment.createdAt | string | ISO 8601 timestamp of the deployment | | deployment.sizeBytes | number | Total size of the uploaded bundle |

Error responses

401 Unauthorized — missing or expired session:

{
  "error": "Authentication required. Run 'overscore login' to sign in."
}

403 Forbidden — user is not an admin or owner of the project:

{
  "error": "You do not have permission to deploy to this project"
}

413 Payload Too Large — bundle exceeds the size limit:

{
  "error": "Bundle size exceeds the 50MB limit"
}

Rate limits

API requests are rate-limited per project:

| Endpoint | Limit | |----------|-------| | POST /api/query | 100 requests per minute | | POST /api/deploy | 10 deployments per hour |

When rate limited, the API returns 429 Too Many Requests with a Retry-After header indicating how many seconds to wait.

Next steps