Endpoints
The REST endpoints a workspace API key can call, grouped by what they work on, with the main parameters of each.
Conventions
All paths are relative to https://teddit.io/api. Send the key as described under Authentication.
- Access is the lowest key role that may call the endpoint:
viewer(a Read key),member(Read + edit) oradmin(Read + scan). A higher role may always call it too. :orgIdis the workspace id fromGET /whoami.:idis a site id fromGET /orgs/:orgId/projects.- Period parameters. The report endpoints take
period(day,week,monthorquarter; defaultweek) andstart(any date inside the period you want,YYYY-MM-DD; default the latest period). Their responses repeatperiodandstartand list every period that has data inperiods. - In responses, “named” is
mentioned, “linked” isownCited, your place isbrandRank,visibilityis the visibility score, and an assistant is aproviderwith the keyopenai,anthropic,perplexity,gemini,google_aioorgoogle_ai_mode.
The MCP tools return the same data, so a tool’s description also describes the matching endpoint.
Workspace
| Method | Path | Access | Purpose |
|---|---|---|---|
| GET | /whoami | viewer | The workspace, the role and the name of the key. |
| GET | /orgs/:orgId | viewer | The workspace: its name and the role of the caller. |
| GET | /orgs/:orgId/dashboard | viewer | Every site with its current numbers, the connected assistants, and the workspace limits with the scans used this month. |
| GET | /orgs/:orgId/projects | viewer | The sites of the workspace. |
| GET | /orgs/:orgId/usage | viewer | The balance, top-ups, and what the scans have cost: this month in total and by site with each site’s cap, the last six months, and the price per answer of each assistant’s default model. |
| POST | /orgs/:orgId/projects | admin | Add a site. |
| GET | /orgs/:orgId/providers | viewer | The assistants, the model each answers with, and whether each is connected. |
| GET | /orgs/:orgId/members | viewer | Members, pending invitations and the workspace’s member limit. |
| POST | /orgs/:orgId/invitations | admin | Invite a person by email. |
| DELETE | /orgs/:orgId/invitations/:invitationId | admin | Cancel a pending invitation. |
| PATCH | /orgs/:orgId/members/:userId | admin | Change a member’s role. |
| DELETE | /orgs/:orgId/members/:userId | admin | Remove a member. |
Add a site takes name and url (both required), and optionally industry, brandTerms (other names, up to 50), competitors (objects with name and domain, up to 50), language (default English) and location (default United States).
Invite takes email and role (viewer, member or admin; default member). Change a role takes role. What an admin may and may not do to other members is on the Roles page.
Not available to keys: everything under /auth and /account, creating, deleting and leaving workspaces, renaming a workspace (PATCH /orgs/:orgId, Owner only), topping up and invoices (Owner only) and managing keys (/orgs/:orgId/tokens).
Sites
| Method | Path | Access | Purpose |
|---|---|---|---|
| GET | /projects/:id | viewer | The site, the caller’s role and the number of stored answers. |
| PATCH | /projects/:id | member | Change the site’s settings. The cap, the scan settings and allowedProviders (the assistants the site may ask, null for all) need an admin. |
| PATCH | /projects/:id/schedule | admin | Switch scheduled scans on or off. |
| POST | /projects/:id/reanalyse | member | Re-read every stored answer with the current names and competitors. Calls no assistant. |
Change settings takes any of these fields:
name,brandTerms: the brand name and its other names. Changing either re-reads all stored answers; the response then carries areanalysissummary.industry,language,location(the country).scanFrequencyDays(1 to 365): the gap between scheduled scans.monthlyCapUsd: the site’s monthly cap in US dollars.nullor0removes it.scanSettings: the saved scan settings, replaced as a whole. An object withproviders(assistant keys; left out means all connected),models(assistant key to model),category,budgetUsd(the most one scan may cost; 0 means twice its estimate) andskipAtCap(falselets scans start even when the monthly cap is spent).
Schedule takes enabled (true or false) and optionally batch (batch pricing for scans with the saved settings; on unless you switch it off). With it on, ChatGPT, Claude and Gemini answer for a lower price within hours; the other assistants answer at once. Switching the schedule on sets the first scan for the next night (UTC).
Deleting a site, with its prompts, scans and answers, is for a signed-in Owner and is not available to keys.
Reports
All of these are GET, need viewer, and take the period parameters.
| Path | Returns |
|---|---|
/projects/:id/report | The Dashboard: report with the counts now and before, share of voice, the brand ranking, per-assistant rows, what changed, the most cited sources and the chart series. report is null before the first scan. |
/projects/:id/trends | Ten periods: the site’s shares per period, every active prompt with its per-period verdicts, prompts won and lost, shares per category, and the held, volatile and lost lists. |
/projects/:id/sentiment | Tone per assistant among the answers that name you. Add answers=1 to get those answers one by one, each with its tone and the quoted sentence. |
/projects/:id/sources | Every domain the assistants cited, what kind of site it is and whether the answers citing it name you; and your own pages with the prompts and assistants that link to each. |
/projects/:id/competitors | The tracked competitors, how often each brand is named overall and per assistant, head-to-head counts, and suggestions of untracked names. |
/projects/:id/competitors/:competitorId | One competitor against you: paired numbers, per assistant, per category, the prompts split three ways, and their cited pages. |
curl "https://teddit.io/api/projects/12/report?period=month&start=2026-09-15" \ -H "Authorization: Bearer tdt_…"
How the numbers in these responses are computed: Metrics and statuses.
Prompts and categories
| Method | Path | Access | Purpose |
|---|---|---|---|
| GET | /projects/:id/prompts | viewer | The prompt list with each assistant’s latest verdict and the history squares. |
| GET | /projects/:id/prompts/export.csv | viewer | The same list as a CSV file. |
| POST | /projects/:id/prompts | member | Add one prompt. |
| PATCH | /projects/:id/prompts/:promptId | member | Edit one prompt. |
| POST | /projects/:id/prompts/bulk | member | Set a status or a category on many prompts, or delete them. |
| POST | /projects/:id/prompts/import | member | Import prompts from CSV text. |
| POST | /projects/:id/prompts/rewrite | admin | Rewrite imported search queries as full questions. Not charged; needs a balance above zero. Up to 10 calls an hour. |
| GET | /projects/:id/prompts/rewrite/pending | viewer | How many imported prompts are still raw queries. |
| GET | /projects/:id/prompts/:promptId | viewer | One prompt: the latest verdict per assistant, every answer over time, the week-by-week history. |
| GET | /projects/:id/prompts/:promptId/answer | viewer | One answer word for word, with brands named, sources and web searches. |
| GET | /projects/:id/categories | viewer | The categories with their prompt counts. |
| POST | /projects/:id/categories | member | Add an empty category. |
| POST | /projects/:id/categories/merge | member | Rename, merge or remove categories. |
The list and the export take the same query parameters: q (text search), category, status (draft, active, paused), intent, verdict (named, lost, cited, missing, failed), competitor (a tracked competitor’s name), stability (held, volatile, lost) and scanned (yes, never). The list also takes sort (created, text, category, rank, scanned), dir (asc, desc), page, perPage (5 to 200, default 20) and the period parameters, which set what one history square stands for.
Add takes text (3 to 500 characters, required), category or categories (a list of up to 8), intent (default informational), funnel (default awareness) and status (default active). A text that is already tracked answers 409. Edit takes the same fields, all optional; categories replaces the whole list.
Bulk takes ids (1 to 5000) and status, category or delete: true. Deleting a prompt deletes its answers.
Import takes contents (the text of the file, up to 2,000,000 characters), status (default draft) and dryRun. It returns rows, created, updated, skipped and categories. The file format is on the Importing prompts page.
One answer takes engine (an assistant key; default the first assistant that answered) or r (the id of a past answer, taken from the prompt’s results).
Merge categories takes names (the categories to fold) and into (the name they become). One name is a rename, several are a merge, and an empty into removes the categories from their prompts.
Competitors and pages
| Method | Path | Access | Purpose |
|---|---|---|---|
| POST | /projects/:id/competitors | member | Track a competitor. |
| PATCH | /projects/:id/competitors/:competitorId | member | Change a competitor. Only the fields sent change. |
| GET | /projects/:id/events | viewer | The site’s events (releases, campaigns, model updates) drawn on its trend charts. |
| POST | /projects/:id/events | member | Add an event: title, date (YYYY-MM-DD), type (site, model, campaign or other) and an optional note. |
| DELETE | /projects/:id/events/:eventId | member | Remove an event. |
| DELETE | /projects/:id/competitors/:competitorId | member | Stop tracking a competitor. Stored answers are kept. |
| GET | /projects/:id/pages | viewer | Your pages from the sitemap with their titles, and whether a current answer links to each. |
| GET | /projects/:id/crawlers | viewer | What robots.txt lets each AI crawler read, the deciding line, llms.txt, and the history of checks. |
| POST | /projects/:id/crawlers/check | member | Read robots.txt and llms.txt again now; returns the same as the GET. |
| GET | /projects/:id/searches | viewer | The web searches the assistants ran for the active prompts, most common first. |
| GET | /projects/:id/pages/:pageId/prompts | viewer | The prompts whose current answers link to one page. |
| POST | /projects/:id/pages/import-sitemap | member | Read the site’s sitemap again now and add the pages not listed yet. Up to 10 calls an hour. |
Track takes name (required), domain, aliases (other names, up to 30), color and logo. Change takes the same fields, all optional: only what you send changes, aliases replaces the whole list, and domain: null removes the domain. All three competitor endpoints re-read the stored answers when the names change and return the result as reanalysis.
Pages takes q, section (the first part of the path), shown (yes or no), page and perPage (5 to 200, default 50).
Scans
| Method | Path | Access | Purpose |
|---|---|---|---|
| GET | /projects/:id/scan-options | viewer | The connected assistants, their models with a cost per answer, active prompts per category, scans used this month and the site’s spend this month. |
| POST | /projects/:id/scans/estimate | viewer | The expected cost of a scan as configured. |
| POST | /projects/:id/scans | admin | Start a scan. |
| GET | /projects/:id/scans/live | viewer | The scan in progress, if any, with pace and time left. |
| POST | /projects/:id/scans/:scanId/cancel | admin | Stop a running scan. |
| GET | /projects/:id/scans | viewer | The last 30 scans. |
| GET | /projects/:id/scans/:scanId | viewer | One scan and the answers it collected, 25 per page. |
Estimate and start take the same body. Every field is optional:
providers: assistant keys. Empty means every connected assistant.promptIds: a chosen set of prompts. Empty means every active prompt. Prompts that are not active are skipped.category: scan one category.sample: scan this many prompts, drawn at random.models: assistant key to model, from the options inscan-options.chatgpt-appandgemini-app(fast: answered at once) andchatgpt-app-queueandgemini-app-queue(slow and cheaper: a few minutes) take the answer as the app shows it.batch: batch pricing. ChatGPT, Claude and Gemini answer for a lower price within hours; the other assistants answer at once.saved:truetakes the assistants, models and category from the site’s saved scan settings instead of from this request. On start it takes the saved limit per scan too.- Start only:
budgetUsd(stop once the scan has cost this much; left out, twice its estimate) andlabel.
Estimate returns prompts, answers, cost and formatted. Start returns the scan and answers 400 with the reason when the scan cannot start. The reasons, and how cost is counted, are on the Balance and spending limits page.
One scan takes tab (all, notNamed, competitorsOnly, errors), engine (an assistant key) and page. Scan statuses are queued, running, cancelling, cancelled, done and failed.
A complete example
Find the site, add a prompt, price a scan of one category, run it and read the result. Starting the scan needs a Read + scan key.
KEY="tdt_…"
API="https://teddit.io/api"
# 1. Which workspace is this key for?
curl "$API/whoami" -H "Authorization: Bearer $KEY"
# → "org": { "id": 3, … }
# 2. The sites of the workspace
curl "$API/orgs/3/projects" -H "Authorization: Bearer $KEY"
# → "projects": [{ "id": 12, "domain": "brightloop.example", … }]
# 3. Add a prompt
curl -X POST "$API/projects/12/prompts" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"text": "What does email automation cost for 10,000 contacts?", "category": "pricing", "intent": "commercial"}'
# 4. What would a scan of that category cost?
curl -X POST "$API/projects/12/scans/estimate" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"category": "pricing"}'
# → { "prompts": …, "answers": …, "cost": …, "formatted": "$…" }
# 5. Run it, and stop at 2 dollars
curl -X POST "$API/projects/12/scans" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"category": "pricing", "budgetUsd": 2}'
# 6. Follow it until "run" is null
curl "$API/projects/12/scans/live" -H "Authorization: Bearer $KEY"
# 7. Read this week's report
curl "$API/projects/12/report" -H "Authorization: Bearer $KEY"