# Flaunt Data API > Programmatic, read-only access to your Flaunt data warehouse — for building live dashboards and agentic workflows. Authenticate with a Bearer API key scoped to either one organization (all its brands) or a single brand. Base URL: `https://api.flaunt.xyz` · Read-only (a single SELECT/WITH statement). Send `Authorization: Bearer `. ## Typical flow 1. `GET /v1/data/brands` — the brands your key can access (each with its `dataset`). 2. Reuse proven queries: `GET /v1/data/reports?brandId=…` → `GET /v1/data/reports/{reportId}/queries?brandId=…`, or `GET /v1/data/queries` for standalone saved queries. 3. `POST /v1/data/query` — run a query: either `{ "sql": "…" }` or `{ "queryId": "…", "period": { "cadence": "MONTHLY" } }`. 4. If the data looks wrong: `POST /v1/data/feedback` with a `{ "summary": "…" }` (+ optional `expected`/`observed`/`brandId`) to file it with the Flaunt data team — the key's recent queries are attached automatically. ## Conventions - Read-only: a single `SELECT`/`WITH` statement. Reference tables as `` `flaunt-v1..` `` using the `dataset` from `GET /v1/data/brands`. - Discover tables (no schema endpoint): `` SELECT table_name, layer, data_source FROM `flaunt-v1..table_metadata` ``. - `"dryRun": true` estimates bytes scanned without running or billing. - Each key has a rolling-24h usage limit (`429 USAGE_LIMIT_EXCEEDED`). - Every response carries an `x-request-id` header; errors are `{ error: { code, message, requestId } }`. Machine-readable spec: https://api.flaunt.xyz/v1/data/openapi.json --- ## API reference ### `GET /v1/data/brands` — List brands Returns the brands this API key can access, each with its brandId, name, and dataset. ### `GET /v1/data/reports` — List reports Returns the reports (curated, repeatable query definitions) this key can access, as metadata. Includes both your own/organization reports and Flaunt's shared reports, which run against each brand's own data and so appear once per brand. For org keys, omit `brandId` to list across all the org's brands, or pass it to narrow to one. Use `type` to filter by ownership. Results are cursor-paginated: read `nextCursor` from the response and pass it back as `cursor` until it's `null`. ### `GET /v1/data/reports/{reportId}` — Get a report Returns one report's full detail — its metadata plus the markdown `instructions` and the `dashboardConfig` (tile/layout JSON). `brandId` is required only for an org key viewing an org-/all-brands or shared Flaunt report (which has no single owning brand). ### `GET /v1/data/reports/{reportId}/queries` — List a report's queries Returns the report's queries (sections) in order. Each is runnable via POST /query by its `id` (parameterized queries also accept a `period`). ### `GET /v1/data/queries` — List saved queries Returns standalone proven queries a brand has saved (not part of a report). Concrete and runnable by id via POST /query as-is. ### `POST /v1/data/query` — Run a query Runs a read-only (SELECT/WITH) query against a brand's dataset. Provide **either** raw `sql` **or** a proven `queryId` (from GET /reports/{reportId}/queries or GET /queries). A parameterized report query also accepts a `period` (`cadence`, or `startDate`/`endDate`) — omitted, it defaults to the last full month. For org keys, `brandId` is required unless it's inferable (single-brand key, brand-owned query). Use `dryRun` to estimate bytes scanned before running. ### `POST /v1/data/feedback` — Report a data issue Reports that data looks wrong so the Flaunt data team can investigate. Provide a `summary` of the discrepancy and, ideally, `expected` vs `observed` values, the affected `brandId`, and a `transcript` of the relevant conversation turns. The recent queries this key ran are attached automatically as an audit trail. Returns a `feedbackRef` to quote in support. --- # Flaunt Data API — Quickstart Programmatic, **read-only** access to your Flaunt data warehouse. Built for trusted partners powering dashboards and agentic workflows on live Flaunt data. - **Interactive docs (Scalar):** https://developers.flaunt.xyz - **OpenAPI spec:** https://api.flaunt.xyz/v1/data/openapi.json > The API is served on the **`api.`** subdomain. Base URL: `https://api.flaunt.xyz`. ## Authentication Every request needs your API key as a Bearer token: ``` Authorization: Bearer flnt_live_xxxxxxxxxxxx ``` A key is scoped to **either** an organization (can access all brands in the org) **or** a single brand. You never pass an org id — the key determines what you can reach. ## 1. List the brands your key can access ```bash curl https://api.flaunt.xyz/v1/data/brands \ -H "Authorization: Bearer $FLAUNT_KEY" ``` ```json { "brands": [ { "brandId": "zettler-coffee", "name": "Zettler Coffee", "dataset": "zettler_coffee" }, { "brandId": "zettler-tea", "name": "Zettler Tea", "dataset": "zettler_tea" } ] } ``` Use `dataset` to fully-qualify tables in your SQL: `` `flaunt-v1..
` ``. ## 2. Run a query ```bash curl -X POST https://api.flaunt.xyz/v1/data/query \ -H "Authorization: Bearer $FLAUNT_KEY" \ -H "Content-Type: application/json" \ -d '{ "brandId": "zettler-coffee", "sql": "SELECT * FROM `flaunt-v1.zettler_coffee.report__skio_overview_monthly` ORDER BY month DESC LIMIT 12" }' ``` ```json { "brandId": "zettler-coffee", "rows": [ { "month": "2026-04-01", "mrr": 84210.55, "active_subscribers": 4120 } ], "rowCount": 12, "truncated": false, "stats": { "totalBytesBilled": 10485760, "totalBytesProcessed": 10485760 } } ``` - **Org-scoped keys** must include `brandId`. **Single-brand keys** may omit it (defaults to the key's brand). - Only a single, read-only statement is allowed (`SELECT` / `WITH`). - Pass `"dryRun": true` to validate and estimate `totalBytesProcessed` **without** running or being billed — useful before an expensive query. - Large result sets are capped; when `truncated` is `true`, page with `LIMIT` / `OFFSET`. ## Build from a proven query (no SQL required) Flaunt already contains queries that have run successfully against your data. Reuse them instead of writing SQL from scratch: list them, then run one **by id**. ### List your reports A **report** is a curated, repeatable definition (e.g. "Monthly Retention"). List the ones your key can see: ```bash curl "https://api.flaunt.xyz/v1/data/reports?brandId=zettler-coffee" \ -H "Authorization: Bearer $FLAUNT_KEY" ``` ```json { "reports": [ { "reportId": "rpt_retention", "brandId": "zettler-coffee", "name": "Monthly Retention", "description": "Cohort retention by month", "queryCount": 4 } ] } ``` ### Get a report's queries ```bash curl "https://api.flaunt.xyz/v1/data/reports/rpt_retention/queries?brandId=zettler-coffee" \ -H "Authorization: Bearer $FLAUNT_KEY" ``` ```json { "queries": [ { "id": "rs_9f2c…", "name": "Returning revenue by month", "description": "Revenue from returning customers in the period", "sql": "SELECT … WHERE order_date BETWEEN {start_date} AND {end_date}", "tables": null, "parameterized": true, "parameters": ["creator_schema_name", "start_date", "end_date"], "ordinal": 0 } ] } ``` `GET /v1/data/queries` returns standalone **saved queries** (not part of a report) in the same shape. ### Run a query by id Pass `queryId` instead of `sql`. For a **parameterized** query (`"parameterized": true`), add a `period` so the server fills in the date window — omit it and it defaults to the last full month. This is what makes a report query *repeatable*: store `queryId + period`, and every load returns a fresh window. ```bash curl -X POST https://api.flaunt.xyz/v1/data/query \ -H "Authorization: Bearer $FLAUNT_KEY" \ -H "Content-Type: application/json" \ -d '{ "queryId": "rs_9f2c…", "period": { "cadence": "MONTHLY" } }' ``` - `period` accepts either `{ "cadence": "DAILY" | "WEEKLY" | "MONTHLY" }` or an explicit `{ "startDate": "2026-01-01", "endDate": "2026-01-31" }`. - A **saved query** (`"parameterized": false`) is concrete — run it by `queryId` with no `period` (it returns the same window it was written against). - `brandId` is inferred when unambiguous (single-brand keys, and queries that belong to one brand); pass it for an org key running a report that applies to multiple brands. ## Discovering tables and columns There is no separate schema endpoint — introspect with a query: ```sql -- Tables in a dataset, with their layer and source (Flaunt's catalog) SELECT table_name, layer, data_source FROM `flaunt-v1..table_metadata`; -- Columns for a specific table SELECT column_name, data_type FROM `flaunt-v1.`.INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'report__skio_overview_monthly'; ``` The `report__*`, `fact__*`, `dim__*`, and `agg__*` tables are the dashboard-ready marts. ## Reporting a data issue If a number looks wrong, send it back to the Flaunt data team with `POST /v1/data/feedback`. The report goes to the same triage pipeline that powers in-app feedback, and the recent queries this key ran are attached automatically as an audit trail — so include a clear `summary` (and ideally the `expected` vs `observed` values) and we can reproduce it without a screen-share. Flaunt never sees the conversation an AI agent had with its user, so pass a **`transcript`** — the relevant turns, verbatim — to give us the full picture. It's the single most useful signal for diagnosis. ```bash curl -X POST https://api.flaunt.xyz/v1/data/feedback \ -H "Authorization: Bearer $FLAUNT_KEY" \ -H "Content-Type: application/json" \ -d '{ "brandId": "zettler-coffee", "summary": "Monthly revenue is ~2x the Shopify dashboard", "expected": "$48,210 for May 2026", "observed": "$95,400", "severity": "high", "transcript": [ { "role": "user", "content": "What was May revenue?" }, { "role": "assistant", "content": "May 2026 revenue was $95,400 (from rs_9f2c)." }, { "role": "user", "content": "That is double what Shopify shows ($48,210)." } ] }' ``` ```json { "feedbackRef": "clx3f9k2a0001qz8yb4d7e2h9" } ``` Only `summary` is required; `transcript` is an ordered array of `{ role, content }` turns (`role` is `user`, `assistant`, or `tool`). If you only have a free-form narrative, put it in the `summary` or a single transcript turn. Quote the returned `feedbackRef` in any follow-up. (AI agents get the same thing via the MCP `report_data_issue` tool, which is told to forward the verbatim transcript.) ## MCP server (for AI agents) The same capabilities are available over the **Model Context Protocol** at `https://api.flaunt.xyz/v1/data/mcp` (Streamable HTTP). Authenticate one of two ways: **OAuth** for claude.ai custom connectors (no key to manage — see [Connecting claude.ai](#connecting-claudeai-oauth) below), or the **same API key** as a Bearer token for Claude Code, Claude Desktop, and headless clients. **Claude Code** (API key) — add it in one command: ```bash claude mcp add --transport http flaunt https://api.flaunt.xyz/v1/data/mcp \ --header "Authorization: Bearer $FLAUNT_KEY" ``` **Claude Desktop** — the native connector GUI is OAuth-only, so bridge the Streamable-HTTP server with [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) (needs Node.js). Open **Settings → Developer → Edit Config** — that's `claude_desktop_config.json` (`~/Library/Application Support/Claude/` on macOS, `%APPDATA%\Claude\` on Windows) — and add: ```json { "mcpServers": { "flaunt": { "command": "npx", "args": [ "-y", "mcp-remote", "https://api.flaunt.xyz/v1/data/mcp", "--header", "Authorization:${FLAUNT_AUTH}" ], "env": { "FLAUNT_AUTH": "Bearer flnt_live_…" } } } } ``` The Bearer token is passed via an `env` var because Claude Desktop splits each `args` entry on spaces — keeping the `Authorization:${FLAUNT_AUTH}` argument space-free avoids a truncated header. Fully quit and reopen Claude Desktop, then the `flaunt` tools appear in the tools (🔨) menu. Tools (feature-parity with the REST API): `list_brands`, `list_reports`, `list_report_queries`, `list_saved_queries`, `run_query` (raw `sql` or a `queryId` + `period`, with `dryRun`), and `report_data_issue` (file a report when the data looks wrong). The same scoping, hardening, and daily usage limit apply. ### Connecting claude.ai (OAuth) claude.ai's custom connectors authenticate with OAuth, so there's no key to copy or store. **Only Flaunt admins can connect** — the connection uses your existing admin login and is limited to the brands you manage (read-only). 1. In claude.ai, open **Settings → Connectors → Add custom connector**. 2. Paste the MCP server URL `https://api.flaunt.xyz/v1/data/mcp` and add it. 3. Claude opens a Flaunt authorization screen. Sign in with your Flaunt admin login if prompted, review what the assistant can access, and click **Approve**. ![The Flaunt authorization screen shown when connecting an AI assistant](/img/mcp-oauth-consent.png) The connection then acts as you, with the same read-only access and brand scoping as your admin account — the OAuth token resolves to the same tools and the same daily usage limits as an API key. **Managing connections.** See and revoke your connected assistants any time in your Flaunt admin under **API Keys → Connected AI assistants**. Revoking cuts off access immediately (the assistant must reconnect and be re-approved), and access is revoked automatically if you lose admin access to Flaunt. ## Errors Every error returns a stable shape; quote `requestId` in support: ```json { "error": { "code": "QUERY_TOO_EXPENSIVE", "message": "Query would scan more than the allowed bytes…", "requestId": "f1c2…" } } ``` | code | HTTP | meaning | | --- | --- | --- | | `UNAUTHORIZED` | 401 | Missing / invalid / revoked key | | `FORBIDDEN_BRAND` | 403 | The key can't access that `brandId` | | `FORBIDDEN_TABLE` | 403 | The query referenced a table/dataset outside this brand's access | | `VALIDATION` | 400 | Bad body, or `brandId` missing for an org key | | `INVALID_SQL` | 400 | Not read-only, or multiple statements | | `QUERY_TOO_EXPENSIVE` | 400 | Exceeds the per-key byte-scan ceiling | | `QUERY_FAILED` | 400 | The query was rejected (syntax, etc.) | | `REPORT_NOT_FOUND` | 404 | No such report is visible to this brand | | `QUERY_NOT_FOUND` | 404 | The `queryId` is unknown or not visible to this brand | | `USAGE_LIMIT_EXCEEDED` | 429 | The key hit its daily usage limit (resets on a rolling 24-hour basis) | Every response (success or error) includes an `x-request-id` header.