REST API

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) or admin (Read + scan). A higher role may always call it too.
  • :orgId is the workspace id from GET /whoami. :id is a site id from GET /orgs/:orgId/projects.
  • Period parameters. The report endpoints take period (day, week, month or quarter; default week) and start (any date inside the period you want, YYYY-MM-DD; default the latest period). Their responses repeat period and start and list every period that has data in periods.
  • In responses, “named” is mentioned, “linked” is ownCited, your place is brandRank, visibility is the visibility score, and an assistant is a provider with the key openai, anthropic, perplexity, gemini, google_aio or google_ai_mode.

The MCP tools return the same data, so a tool’s description also describes the matching endpoint.

Workspace

MethodPathAccessPurpose
GET/whoamiviewerThe workspace, the role and the name of the key.
GET/orgs/:orgIdviewerThe workspace: its name and the role of the caller.
GET/orgs/:orgId/dashboardviewerEvery site with its current numbers, the connected assistants, and the workspace limits with the scans used this month.
GET/orgs/:orgId/projectsviewerThe sites of the workspace.
GET/orgs/:orgId/usageviewerThe 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/projectsadminAdd a site.
GET/orgs/:orgId/providersviewerThe assistants, the model each answers with, and whether each is connected.
GET/orgs/:orgId/membersviewerMembers, pending invitations and the workspace’s member limit.
POST/orgs/:orgId/invitationsadminInvite a person by email.
DELETE/orgs/:orgId/invitations/:invitationIdadminCancel a pending invitation.
PATCH/orgs/:orgId/members/:userIdadminChange a member’s role.
DELETE/orgs/:orgId/members/:userIdadminRemove 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

MethodPathAccessPurpose
GET/projects/:idviewerThe site, the caller’s role and the number of stored answers.
PATCH/projects/:idmemberChange 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/scheduleadminSwitch scheduled scans on or off.
POST/projects/:id/reanalysememberRe-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 a reanalysis summary.
  • industry, language, location (the country).
  • scanFrequencyDays (1 to 365): the gap between scheduled scans.
  • monthlyCapUsd: the site’s monthly cap in US dollars. null or 0 removes it.
  • scanSettings: the saved scan settings, replaced as a whole. An object with providers (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) and skipAtCap (false lets 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.

PathReturns
/projects/:id/reportThe 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/trendsTen 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/sentimentTone 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/sourcesEvery 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/competitorsThe tracked competitors, how often each brand is named overall and per assistant, head-to-head counts, and suggestions of untracked names.
/projects/:id/competitors/:competitorIdOne 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

MethodPathAccessPurpose
GET/projects/:id/promptsviewerThe prompt list with each assistant’s latest verdict and the history squares.
GET/projects/:id/prompts/export.csvviewerThe same list as a CSV file.
POST/projects/:id/promptsmemberAdd one prompt.
PATCH/projects/:id/prompts/:promptIdmemberEdit one prompt.
POST/projects/:id/prompts/bulkmemberSet a status or a category on many prompts, or delete them.
POST/projects/:id/prompts/importmemberImport prompts from CSV text.
POST/projects/:id/prompts/rewriteadminRewrite imported search queries as full questions. Not charged; needs a balance above zero. Up to 10 calls an hour.
GET/projects/:id/prompts/rewrite/pendingviewerHow many imported prompts are still raw queries.
GET/projects/:id/prompts/:promptIdviewerOne prompt: the latest verdict per assistant, every answer over time, the week-by-week history.
GET/projects/:id/prompts/:promptId/answerviewerOne answer word for word, with brands named, sources and web searches.
GET/projects/:id/categoriesviewerThe categories with their prompt counts.
POST/projects/:id/categoriesmemberAdd an empty category.
POST/projects/:id/categories/mergememberRename, 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

MethodPathAccessPurpose
POST/projects/:id/competitorsmemberTrack a competitor.
PATCH/projects/:id/competitors/:competitorIdmemberChange a competitor. Only the fields sent change.
GET/projects/:id/eventsviewerThe site’s events (releases, campaigns, model updates) drawn on its trend charts.
POST/projects/:id/eventsmemberAdd an event: title, date (YYYY-MM-DD), type (site, model, campaign or other) and an optional note.
DELETE/projects/:id/events/:eventIdmemberRemove an event.
DELETE/projects/:id/competitors/:competitorIdmemberStop tracking a competitor. Stored answers are kept.
GET/projects/:id/pagesviewerYour pages from the sitemap with their titles, and whether a current answer links to each.
GET/projects/:id/crawlersviewerWhat robots.txt lets each AI crawler read, the deciding line, llms.txt, and the history of checks.
POST/projects/:id/crawlers/checkmemberRead robots.txt and llms.txt again now; returns the same as the GET.
GET/projects/:id/searchesviewerThe web searches the assistants ran for the active prompts, most common first.
GET/projects/:id/pages/:pageId/promptsviewerThe prompts whose current answers link to one page.
POST/projects/:id/pages/import-sitemapmemberRead 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

MethodPathAccessPurpose
GET/projects/:id/scan-optionsviewerThe 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/estimateviewerThe expected cost of a scan as configured.
POST/projects/:id/scansadminStart a scan.
GET/projects/:id/scans/liveviewerThe scan in progress, if any, with pace and time left.
POST/projects/:id/scans/:scanId/canceladminStop a running scan.
GET/projects/:id/scansviewerThe last 30 scans.
GET/projects/:id/scans/:scanIdviewerOne 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 in scan-options. chatgpt-app and gemini-app (fast: answered at once) and chatgpt-app-queue and gemini-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: true takes 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) and label.

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"