Authentication
The REST API gives scripts and dashboards the same data as the app. A script reaches it with a workspace API key sent as a bearer token. This page covers keys, their access levels and the errors you can get back.
Base address and format
https://teddit.io/api
- Requests and responses are JSON. Send
Content-Type: application/jsonwith every body. A request body may be up to 4 MB. - Ids are numbers. The API calls a workspace an organisation (
/orgs/:orgId) and a site a project (/projects/:id). - Times are ISO 8601 in UTC. Weeks and other periods are given as a date,
YYYY-MM-DD.
The list of addresses is on the Endpoints page.
API keys
Create a key in the app: gear icon → API & MCP → Create key. Any role can; the key gets at most the access of yours.
- A key looks like
tdt_followed by 40 letters, digits,-and_. - It is shown once, when it is created. Teddit stores a hash of it, not the key, so a lost key cannot be recovered. Create a new one instead.
- A key belongs to one workspace and can reach every site in it.
- The Keys list shows each key’s name, its first characters, its access, who created it and when it was last used. “Last used” is updated at most once every five minutes.
- A key does not expire. Revoke it with the bin icon; it stops working with the next request.
The same keys open the MCP server.
Sending the key
Put the key in the Authorization header of every request:
curl https://teddit.io/api/whoami \ -H "Authorization: Bearer tdt_…"
GET /api/whoami is the call to start with. It says which workspace the key belongs to and what it may do:
{
"kind": "token",
"tokenName": "Reporting script",
"user": { "id": 7, "name": "Dana Whitfield", "email": "dana@brightloop.example" },
"org": { "id": 3, "name": "Brightloop", "plan": "free" },
"role": "viewer"
}Use org.id in the /orgs/:orgId/… addresses. user is the person who created the key: actions taken with the key, such as starting a scan, are recorded under that name.
Access levels of keys
A key has one of three access levels. Each is a workspace role, and each includes the one above it.
| Access in the app | role | May call |
|---|---|---|
| Read | viewer | Everything that reads: reports, prompts, answers, competitors, pages, scans, members. Also the scan cost estimate. |
| Read + edit | member | Also: create, change and delete prompts, categories and competitors; import; change a site’s names, language and country. |
| Read + scan | admin | Also: start and cancel scans, switch the schedule on and off, change the monthly cap and scan settings, add sites, invite and remove members. |
- There are no keys with the Owner role. Topping up, deleting a site and renaming a workspace stay with a signed-in Owner.
- You cannot create a key with more access than your own role gives you.
- A key follows the person who created it: lowered with their role, stopped when they leave the workspace.
What a key cannot do
Some actions need a person signed in to the app in a browser. Called with a key, they answer 403 with “This action needs a signed-in person, not an API token.”
- Creating, listing and revoking API keys.
- Changing your name, email or password, and deleting your account.
- Creating a workspace, deleting one, switching between workspaces and leaving one.
- Accepting an invitation.
A key also sees nothing outside its workspace. A site or workspace id that belongs to someone else answers 404, the same as an id that does not exist.
Errors
Every error has the same body: a message for a person in error, and fields with a message per field when the problem is in the input, otherwise null.
HTTP/1.1 409 Conflict
{
"error": "This prompt already exists in the project.",
"fields": { "text": "Already tracked" }
}| Status | When |
|---|---|
| 400 | The request is well formed but refused: a workspace limit is reached, a scan cannot start (another one is running, no active prompts, the balance does not cover it, the monthly cap is spent), or an address is not a domain. The message says which. |
| 401 | No key, a key in the wrong form, or a revoked key. The message is “Sign in to continue.” |
| 403 | The key’s access level is too low for the action, or the action needs a signed-in person. |
| 404 | The address or the id does not exist, or it belongs to another workspace. |
| 409 | A duplicate: a prompt with the same text, a competitor or category with the same name, an invitation for someone who is already a member. |
| 422 | The body or the query string failed validation. fields names each field that is wrong. |
| 429 | Too many requests to an address with its own limit, such as sign-in, invitations or reading the sitemap. Wait and try again. |
| 500, 502 | Something failed on our side, or an assistant failed while the request was being handled. |
Successful calls answer 200 with JSON. Deleting a site, a member or an invitation answers 204 with no body.
Rate and workspace limits
- Most requests made with a key have no rate limit. A few actions have their own: inviting people, reading the sitemap again and rewriting queries. Going over answers 429.
- The workspace limits apply to the API exactly as they do in the app: sites, prompts per site, scans per month and members. A call that would pass a limit answers 400 with the limit in the message.
- List addresses are paged. The prompt list takes
pageandperPage(5 to 200); asking for more answers 422.