API Overview
Use the Framedash REST API to retrieve and analyze telemetry data.
Base URL
Section titled “Base URL”| Service | URL |
|---|---|
| Web API (Projects, Maps, Content, Query, Analytics, Alerts, Data) | https://app.framedash.dev/api |
| Ingest API (Event Ingestion) | https://ingest.framedash.dev |
Authentication
Section titled “Authentication”The REST API under /api/v1 accepts either an API key or an OAuth 2.1 Bearer token. If a request sends both, the X-API-Key header takes precedence. Most integrations use an API key, sent via the X-API-Key header:
X-API-Key: fd_your_api_key_hereCreate API keys from the project’s “API Keys” page in the dashboard. New keys use
the neutral fd_ prefix; authorization comes from the key’s stored scopes, not
from the prefix.
On the Free plan, a project can have at most 2 active API keys, and each key value is shown only once at creation. If you hit the cap, deactivate an unused key before creating a new one.
Endpoints that are not scoped to a project in the URL path (such as the Content Registry endpoints under /v1/content) also require an X-Project-Id header naming the target project:
X-Project-Id: your-project-uuidAPI Key Presets
Section titled “API Key Presets”| Preset | Scopes | Usage |
|---|---|---|
| Ingest | events:write | SDK event ingestion only |
| Read-only | analytics:read | Dashboard/status/analytics reads, CLI reads, and MCP tools except raw SQL |
| Read & Write | analytics:read, resources:write | Read access plus map, content, and alert resource changes |
| Full | analytics:read, resources:write, data:admin | Read/write access plus raw SQL query, data export, and player erasure |
Validating a key
Section titled “Validating a key”GET /v1/whoami validates any active API key and returns non-sensitive metadata about it, without requiring a particular scope. This lets you confirm that a key works even when it cannot reach any read endpoint, such as an Ingest key that only carries events:write. Only the X-API-Key header is accepted here; an OAuth Bearer token is not.
curl https://app.framedash.dev/api/v1/whoami \ -H "X-API-Key: fd_your_api_key_here"The response is tiered by scope. A key with a read or management scope (analytics:read, resources:write, or data:admin) returns full metadata { projectId, projectName, tenantId, planId, scopes }; a data-plane-only key returns just { projectId, scopes }. The raw key value is never returned, and a missing or invalid key returns 401.
This endpoint has its own rate limit of 60 requests per hour per tenant, separate from your plan quota; exceeding it returns 429 with a Retry-After header.
OAuth 2.1
Section titled “OAuth 2.1”The REST API also accepts an OAuth 2.1 Bearer token in place of an API key:
Authorization: Bearer <access-token>Framedash is an OAuth 2.1 authorization server. Clients discover its endpoints from {origin}/.well-known/oauth-authorization-server, where {origin} is https://app.framedash.dev:
| Endpoint | URL |
|---|---|
| Authorization | {origin}/oauth/authorize |
| Token | {origin}/api/oauth/token |
| Dynamic client registration (RFC 7591) | {origin}/api/oauth/register |
| Revocation | {origin}/api/oauth/revoke |
Only the authorization code flow with PKCE (S256) is supported, for public clients (a token_endpoint_auth_method of none). The grant types are authorization_code and refresh_token.
An OAuth token can carry only the analytics:read and resources:write scopes; when a client requests no scope, it is granted analytics:read. The data:admin, events:write, and events:synthetic scopes are never granted over OAuth, so operations that need them stay API-key-only. For example, POST /v1/query needs data:admin, so it cannot be called with an OAuth token.
Connected apps
Section titled “Connected apps”Authorized OAuth apps are listed under Settings -> Connected apps in the dashboard. Each entry shows the client name, granted scopes, consented projects, and its created and last-used times, and can be revoked individually.
Querying telemetry
Section titled “Querying telemetry”Ingested events are queryable with SQL. Send project_id in the JSON body (not a header) and authenticate with X-API-Key. Raw SQL requires the data:admin scope (the Full preset):
curl -X POST https://app.framedash.dev/api/v1/query \ -H "X-API-Key: fd_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "project_id": "your-project-uuid", "sql": "SELECT event_name, count() AS events FROM events WHERE timestamp >= today() GROUP BY event_name ORDER BY events DESC", "limit": 100 }'The response is { "success": true, "data": { "rows": [...], "rowCount": N } }. A rejected query returns HTTP 400 with the ClickHouse diagnostic message (unknown column, table, or function; syntax errors; type mismatches; forbidden operations); only infrastructure failures return 500. See the Events Schema for the columns and the validator rules, and Troubleshooting to confirm events arrived first.
Ingesting events
Section titled “Ingesting events”The Ingest endpoint (POST /v1/events) accepts only application/x-protobuf (a JSON body returns 415). Events are produced by the official Unity, UE5, and Godot SDKs, which encode the protobuf TelemetryBatch and set the required headers for you. Hand-posting an event means encoding that protobuf schema yourself and sending X-API-Key (events:write scope), Content-Type: application/x-protobuf, Content-Length, and X-SDK-Version. For nearly all integrations, use an SDK rather than posting directly.
Rate Limits
Section titled “Rate Limits”The API rate limit is enforced per account (tenant) and counted as requests per hour. All projects and API keys belonging to the same account share one limit. The Free plan allows 100 requests per hour; paid plans allow more.
Every response carries these three headers:
X-RateLimit-Limit: 100X-RateLimit-Remaining: 99X-RateLimit-Reset: 1782968400000X-RateLimit-Reset is a Unix timestamp in milliseconds, not seconds.
Exceeding the limit returns 429. On that response, X-RateLimit-Remaining is 0 and a Retry-After header (the number of seconds to wait) is added:
X-RateLimit-Limit: 100X-RateLimit-Remaining: 0X-RateLimit-Reset: 1782968400000Retry-After: 3400The limit is computed with a sliding window. As a result, requests can still be limited right after the time X-RateLimit-Reset advertises, and Retry-After can jump to nearly a full hour. Honor the Retry-After on the 429 response rather than scheduling a retry for the reset time. On normal responses, read X-RateLimit-Remaining and space out requests before you hit the limit.
Response Format
Section titled “Response Format”The Web API (app.framedash.dev/api) and the Ingest API (ingest.framedash.dev) return different error shapes. Do not assume a single parser handles both; handle each endpoint’s shape separately.
Web API
Section titled “Web API”On success:
{ "success": true, "data": { ... }}On error, the API returns RFC 9457 Problem Details with the application/problem+json content type:
{ "type": "about:blank", "title": "Forbidden", "status": 403, "detail": "Plan limit reached.", "error_category": "authorization", "retryable": false}| Member | Description |
|---|---|
type | Problem type URI; about:blank when no specific type applies. |
title | Short, human-readable summary of the HTTP status. |
status | HTTP status code. |
detail | Human-readable explanation of this specific error. |
error_category | One of authentication, authorization, validation, rate_limit, not_found, conflict, payload, internal. |
retryable | Whether retrying may succeed (true for 429 and 503). |
retry_after | Optional. Suggested retry delay in seconds. |
Ingest API
Section titled “Ingest API”On success:
{ "status": "accepted"}On error:
{ "error": "Error message"}OpenAPI Spec
Section titled “OpenAPI Spec”The API specification is available for download in OpenAPI 3.1 format.
Endpoints
Section titled “Endpoints”See the auto-generated API reference in the sidebar for full details.
Projects
Section titled “Projects”| Endpoint | Method | Description |
|---|---|---|
/v1/projects | GET | List the project bound to the API key |
/v1/projects/{id}/status | GET | Get project status |
Key validation
Section titled “Key validation”| Endpoint | Method | Description |
|---|---|---|
/v1/whoami | GET | Validate an API key and return non-sensitive key metadata |
Analytics
Section titled “Analytics”| Endpoint | Method | Description |
|---|---|---|
/v1/projects/{id}/dashboard | GET | Get dashboard metrics (DAU, MAU, sessions, events) |
/v1/projects/{id}/builds | GET | List build IDs with performance data |
/v1/projects/{id}/builds/compare | GET | Compare performance between two builds |
/v1/projects/{id}/heatmap | GET | Get heatmap data for a map |
/v1/projects/{id}/retention | GET | Get player retention cohorts |
/v1/projects/{id}/funnels | GET | Get funnel conversion analysis |
/v1/projects/{id}/insights | GET | Get aggregated analytics by dimension |
Alerts
Section titled “Alerts”| Endpoint | Method | Description |
|---|---|---|
/v1/projects/{id}/alerts | GET | List alert rules |
/v1/projects/{id}/alerts | POST | Create an alert rule |
/v1/projects/{id}/alerts/{alertId} | GET | Get an alert rule |
/v1/projects/{id}/alerts/{alertId} | PATCH | Update an alert rule |
/v1/projects/{id}/alerts/{alertId} | DELETE | Deactivate an alert rule |
/v1/projects/{id}/alerts/history | GET | List alert evaluation history |
/v1/projects/{id}/threshold-profiles | GET | List threshold profiles |
| Endpoint | Method | Description |
|---|---|---|
/v1/projects/{id}/maps | GET | List maps |
/v1/projects/{id}/maps/{mapId} | DELETE | Delete a map |
/v1/maps/upload | POST | Upload a map |
Content Registry
Section titled “Content Registry”| Endpoint | Method | Description |
|---|---|---|
/v1/content | GET | List content entries |
/v1/content | POST | Create or update content entries |
/v1/content | DELETE | Delete a content entry |
| Endpoint | Method | Description |
|---|---|---|
/v1/query | POST | Execute an analytics query |
| Endpoint | Method | Description |
|---|---|---|
/v1/data/export | GET | Export accessible project data |
/v1/data/erase | POST | Erase telemetry for one player |
Event Ingestion
Section titled “Event Ingestion”| Endpoint | Method | Description |
|---|---|---|
/v1/events | POST | Ingest telemetry events |