Skip to navigation

Authentication

The API accepts an organization-scoped API key as a bearer token:

Authorization: Bearer tk_live_...

Create keys in Settings → API keys. The secret is shown once, at creation: Taktoria stores only a SHA-256 hash of it, so a lost key must be rotated rather than recovered.

Scopes

A key carries a list of scopes, each resource:verb. * grants everything; resource:* grants every verb on one resource, such as launches:*. The key form in Settings → API keys offers exactly these, grouped by app. GET /me needs none: any valid key may ask what it is. Nor does /me/notification-preferences, how the key’s maker is told about each kind of notification: it is theirs alone.

Only a workspace admin can create a key, so a key’s scopes are a workspace admin’s to give. The workspace settings a key can reach (the organization, billing, email domains and partner domains, and app domains) are the ones only workspace admins can change in the app.

AppScopeGrants
Platformapps:read / apps:writeWhich apps this workspace subscribes to, and which give new members a seat
Platformmembers:readWho is in the workspace
PlatformauditLogs:readEvery change made in the workspace: who, what, when and from where
Platformseats:read / seats:writeWhich apps a person holds a seat on, and who is waiting for one
PlatformappRoles:writeWhat a person may do in each app: Admin, Member or Viewer (read with members:read)
Platformteams:read / teams:writeFunctional and organizational teams
Platformorganization:read / organization:writeThe workspace’s name, address, fiscal year and sign-in policy
Platformbilling:read / billing:writeThe subscription: the apps paid for, their seats, and monthly or yearly
Platformdomains:read / domains:writeEmail domains: joining automatically, closing the workspace, and who follows go links and joins events
PlatformappDomains:read / appDomains:writeHostnames of the workspace’s own that serve its apps
PlatformmcpConnections:read / mcpConnections:writeAI assistants connected through MCP, and whether the workspace allows them
PlatformslackConnections:read / slackConnections:writeSlack accounts connected with Google, which let Slack commands act as their owners
LaunchCallaunches:read / launches:writeLaunches, their dates, their status and going live
LaunchCalsteps:read / steps:writeReview steps, their decisions and nudges
LaunchCalinsights:read / insights:writeInsights recorded against a launch
LaunchCalartifacts:read / artifacts:writeA launch’s press release, dashboard and learnings, and the links kept beside them
LaunchCaltemplates:read / templates:writeLaunch templates and their steps, which launches copy their steps from
Doryevents:read / events:writeEvents, their codes and their settings
Doryquestions:read / questions:writeQuestions asked, answered and dismissed
Dorypolls:read / polls:writePolls, quizzes and their results
Doryparticipants:readWho took part, and the numbers an event produced, or all of them together
Go Linksgolinks:read / golinks:writeShort links, where they point, who may follow them and who may change them
Go Linksclicks:readHow often a link is followed, and when
OKR Hubobjectives:read / objectives:writeObjectives and the quarter they belong to
OKR HubkeyResults:read / keyResults:writeKey results and their targets
OKR HubcheckIns:read / checkIns:writeProgress recorded against a key result
OKR Hubgrades:read / grades:writeThe scorecard: grades set at a checkpoint, comments and who changed them
Memegenmemes:read / memes:writeMemes, their captions and the feed
MemegenmemeTemplates:read / memeTemplates:writeThe backgrounds memes are made from

Signed-in sessions

A signed-in person’s session cookie authenticates too. A key acts for the whole workspace, within its scopes; a session gets no more than the app would give that person:

  • Reads are filtered to what they may see. A private objective, and its key results, are there only for its owners, its team, whoever created it and the people holding one of its key results.
  • Writes are refused with 403 read_only_session, except on Dory’s events, questions and polls, Go Links’ links, Memegen’s memes and templates, OKR Hub’s objectives, key results, check-ins and grades, and LaunchCal, which check who is asking (below), and the person’s own notification preferences (PATCH /me/notification-preferences) and MCP and Slack connections (their own; a workspace admin’s, anybody’s). Changing seats, apps, the workspace’s settings, its subscription or its domains takes a key.
  • The subscription, email domains, partner domains and app domains are read only by a workspace admin’s session, as their settings pages are only a workspace admin’s; anybody else gets 403 admin_required.
  • An app’s endpoints answer only if the person holds a seat on the app (403 seat_required).
  • A Viewer of an app reads it as a member would and changes nothing: every write scope of the app’s resources is refused for their session with 403 viewer_only, before the endpoint runs. See App roles, below.
  • In a workspace that requires signing in with Google, a session made any other way is refused at every endpoint with 403 google_sign_in_required. Keys are not a sign-in and are unaffected.
  • A person in several workspaces picks one with the X-Organization-Id header; otherwise it is the workspace they last opened.

The difference shows in Dory. An event can be closed to a list of people who may run it, and a session reaches only the events that person could run in the app: an event with no list, one they are on (themselves, or through a team on its list or a team inside one), one they created, or any event if they are an app admin of Dory. The API and the app ask one rule for this, so the answer is the same in both. Every other event is a 404 at every endpoint, and is left out of GET /dory/events, exactly as an event in another workspace would be. A key reaches every event in its workspace.

Go Links works as the Go Links app does. A session may create links, and may change, publish, archive or delete the ones that person may edit: a link that names no editors, one they are named on, one they created, or any link if they are an app admin of Go Links. Any other link is 403 forbidden to PATCH and DELETE, though it is still listed and read. The editors a request names must be members of the workspace, for a session and a key alike: anybody else is a 422, and nothing is saved. A draft’s url, and any link’s access.domains, are null to a session that may not edit the link, and q does not match a draft’s destination for it. A key changes and sees every link in its workspace.

Memegen takes a session’s writes on the app’s terms too. A session makes a meme as that person, as the app’s composer does: the captions are fitted to the template’s boxes, and a meme with no words is refused (422). It deletes the person’s own memes, and anybody’s for an app admin of Memegen; anybody else’s is 403 forbidden. The template library is Memegen’s app admins’, as in the app: adding, uploading, changing or archiving a template takes an app admin’s session (403 admin_required otherwise), and archived templates and one-off backgrounds are listed only for an app admin. A key keeps the API’s own rules and writes anything in its workspace, as sent.

OKR Hub works as the OKR Hub app does. A session may create objectives, for anybody in the workspace. Changing an objective, or adding, changing, reordering or deleting its key results, is for its owner, its team (and the teams inside it), whoever created it, or an app admin of OKR Hub. Checking in, setting a key result’s score and writing its scorecard cells are also for the key result’s own owners, directly or through a team. Any other change is 403 forbidden, and an objective the person may not see, or a key result of one, is a 404 before anything else is asked. That holds for app admins too: a private objective an app admin has no part in is not there for them. A key changes everything in its workspace.

LaunchCal takes a session’s writes on the person’s own terms, as the app does. Anybody with a LaunchCal seat adds, edits, publishes, launches and deletes any launch of the workspace, adds and decides its steps, and writes its artifacts, links, comments, updates and insights, all in their own name. A comment or an update is changed only by its author (403 forbidden), and an insight is recorded as the person: naming somebody else in byUserId is 403 forbidden. The process (launch templates and their steps, functional teams and who is on them) is LaunchCal’s app admins’ to change, and a new organizational team, which is the workspace’s, a workspace admin’s: anybody else gets 403 admin_required, and reads them as before.

App roles

Each person has a role in each app, on top of their role in the workspace:

  • Admin: the app’s admin powers, in that app only. LaunchCal’s process (launch templates, their steps, functional teams), editing any objective they can see in OKR Hub, running any Dory event, editing any go link, and Memegen’s template library and moderation. Wherever this page says “an app admin”, it means an admin of that app; “a workspace admin” is an owner or admin of the workspace. It gives nothing in the workspace’s settings.
  • Member: the app as it has always been. Everybody is a Member unless somebody chooses otherwise.
  • Viewer: reads what a member would, and changes nothing. A Viewer’s session gets 403 viewer_only on every write; an MCP connection of theirs is read-only whatever it was granted, and the consent page offers them only Read only (see MCP servers).

Workspace owners and admins are Admin of every app, always: their app roles cannot be changed (409 workspace_admin). A key acts for the workspace and is never a Viewer.

GET /members returns every member’s appRoles, one per app. PUT /members/{userId}/app-roles/{app} with { "role": "admin" | "member" | "viewer" } sets one, with appRoles:write: a key and a workspace admin’s session in any app, an app admin’s session in that app alone (403 forbidden elsewhere). A role neither gives nor takes a seat, and a Viewer still needs one.

To automate, use a key. Taktoria’s own sign-in endpoints (/api/auth/*) are protected by Google reCAPTCHA and refuse a request without a token from the sign-in page, so a script cannot sign in with a password to get a session.

Subscriptions

App endpoints also require the organization to hold a subscription for that app that is active, trialing or past due: a payment Stripe is still retrying does not stop anything. Without one, or with one cancelled, paused, unpaid or incomplete, you get 402 subscription_required, whose message says which. details.status is the app’s subscription status, and details.paymentIssue is unpaid when Stripe stopped retrying a failed payment and the app is locked until a workspace admin updates the payment details, as paymentIssue on GET /subscription says it.