Authentication
The API accepts an organization-scoped API key as a bearer token:
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.
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-Idheader; 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_onlyon 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.