Firemark API
Read your published results, prompts, run logs and stored answers as JSON, for your own dashboards and scripts. The API is read-only and comes with every paid plan.
What the API is
A key reads one workspace's published results: its brands, their results and prompts, their run logs and a prompt's stored answers. Nothing in the API starts a run or changes a brand.
The API is included on every paid plan. It is not part of the free first run. A workspace whose payment is past due keeps reading, and so does a workspace in the 90 days its data stays readable after it cancels. To ask about your results in Claude or ChatGPT instead, use MCP, which signs in with your account and needs no key.
Getting a key
- Any member creates a key on API keys in the account menu. The key is shown once, with Copy. Firemark cannot show it again, so a lost key is revoked and replaced.
- Every new key emails the workspace's owners, with its name and who created it.
- A workspace can have up to 10 active keys. Revoke one to make room for another.
- Any member can revoke any of the workspace's keys. A revoked key stops working at its next request and cannot be restored.
- When a member leaves the workspace, the keys they created are revoked at once.
- The API keys page shows the day each key was last used.
Authentication
Send the key in an Authorization header as a Bearer token on every request. Requests are GET only and answers are JSON. A request without a valid key gets 401 and is never sent to a sign-in page.
https://app.tryfiremark.com/api/v1curl https://app.tryfiremark.com/api/v1/brands \ -H "Authorization: Bearer fmk_xxxxxxxx_…"
The key above is a placeholder. Real keys start with fmk_.
Routes
Every route is under the base URL. {brand} is a brand's id from GET /brands, {group} a prompt group's id from the same list, and {prompt} a prompt's id from its prompts document, such as P001.
| Route | Returns |
|---|---|
GET /brands | The brands of your workspace, each with its website, schedule, state, prompt groups and latest publication (null before its first run publishes). Removed brands are left out. |
GET /brands/{brand}/results | The brand's latest published results: the same counts, ranks and sentences the app's screens show. |
GET /brands/{brand}/prompts | The brand's latest published prompts, each with its verdict per engine. |
GET /brands/{brand}/results?group={group} | One prompt group's results, counted by the same rules as the app. Never filter a whole-brand document to get a group's figures: counts, ranks and claims differ. |
GET /brands/{brand}/prompts?group={group} | That group's prompts. |
GET /brands/{brand}/publications/{version} | One publication: its version, reason, date and run. |
GET /brands/{brand}/publications/{version}/results | That version's results. A published version never changes. |
GET /brands/{brand}/publications/{version}/prompts | That version's prompts. |
GET /brands/{brand}/runs | The run log, as the Runs screen shows it, with the next run and the schedule. The latest published run is marked. |
GET /brands/{brand}/prompts/{prompt}/answers | One prompt's stored answers in a run, per engine: the full answer text, a snippet, its sources, the model and where each name was found. Without a query it reads the latest published run; ?run= names another published run. |
"Latest" is the newest version of the brand's latest run, as on the app's screens. A recount publishes an older run again under a higher version, so the highest version is not always the latest: use the latest publication on GET /brands, the run log's latest mark or the latest routes. A document may gain an optional field without notice, so ignore fields you do not know.
ETags and caching
Every successful answer has an ETag. Send the ETag you hold for a URL as If-None-Match, and an unchanged answer comes back as 304 with no body. Keep ETags per URL, since the same value can appear on different URLs. A published version's results and prompts never change and are marked immutable. Results and prompts are gzipped when you send Accept-Encoding: gzip. Errors are never cached.
Rate limits
Each key can make 60 requests a minute, and a workspace 300 a minute across all its keys. Over either limit, the answer is 429 rate_limited with a Retry-After header in seconds. Refused requests count too, so wait for Retry-After before you try again. Pace a backfill: reading every run of a brand takes one request for the run log and two for each published run.
Errors
An error is JSON with error, a sentence for a person, and code, which your code should branch on. A code never changes its status and is never renamed or removed. A new code may be added, so treat an unknown one by its status. A 5xx or a timeout has no code: retry it with backoff.
| Status | Code | Means | What to do |
|---|---|---|---|
| 401 | unauthorised | The key is missing, malformed, unknown or revoked, or the member who created it has left the workspace. | Do not retry. Check the key on the API keys page, and create a new one if it was revoked. |
| 403 | plan_required | The workspace has no paid plan. The API is included on every paid plan. | Choose a plan in Billing, then use the key again. |
| 429 | rate_limited | The key, or the workspace's keys together, are over their requests per minute. | Wait for Retry-After, then go on. |
| 429 | too_many_failures | Too many failed requests came from your address. A valid key from that address is refused too. | Wait for Retry-After, and fix the key that failed. |
| 400 | bad_run_id | ?run= on the answers route is not shaped like a run id. | Fix the request. Do not retry. |
| 404 | no_brand | No such brand in your workspace. A brand you removed adds removed: true and the dates it was removed and will be deleted. | Stop asking for it. |
| 404 | not_published | The brand's first run has not published yet. | Ask again later. |
| 404 | no_publication | No publication of that version. | Check the version against the run log. |
| 404 | document_missing | The publication exists and its document could not be read. Not expected. | Retry with backoff a few times, then email us. |
| 404 | no_answers | The run is not a published run of the brand, the prompt was not asked in it, or the answers are past the 13 months they are kept. | Show it as not available. Do not retry. |
| 404 | no_group | ?group= names no live group of the brand. | Read the groups on GET /brands again. |
| 404 | group_empty | The group has nothing in the latest published run. | Ask again after the next run. |
Retention
Full answers are kept for 13 months, and the answers route returns no_answers after that. Counts, verdicts and snippets in the results and prompts documents are kept for the life of your account.
Keeping keys safe
- A key gives read access to your workspace's results until it is revoked. Treat it like a password.
- Never paste a key into a chat with an AI assistant, a public repository or a screenshot. Keep it in your script's secret store or environment.
- If a key leaks, revoke it at once on the API keys page and create another.
- Keys start with fmk_ so you can spot them. GitHub secret scanning does not yet report Firemark keys, so a key pushed to GitHub is not flagged to you.
Questions about the API? Email support@tenpointlabs.com.