Authentication
Every request to https://api.akteora.com/v1 carries an API key as a bearer token:
curl https://api.akteora.com/v1/submissions \
-H "Authorization: Bearer rk_live_7Hq2mV9xT4bN8cR1wK6pZ3sD5fG0jL2y"
(The Akteora dashboard calls the same routes with a signed-in session instead of a key. It has no other way in. People signing in to the dashboard may use an email and a password or a Google or GitHub account; none of that applies to an integration, which always uses a key.)
API keys
Keys are made in the dashboard, under Developers → API keys, by an owner or admin of the organisation, on a plan with API access (Core or Plus).
rk_live_7Hq2mV9xT4bN8cR1wK6pZ3sD5fG0jL2y
└┬┘ └┬─┘ └──────────────┬───────────────┘
│ │ 32 random characters
│ live or test
Akteora key
- The whole key is shown once, when it is made. Akteora keeps only a SHA-256 hash of it, so nobody — Akteora included — can show it again. Store it in a secret manager or your server's environment. If it is lost, revoke it and make another.
- The prefix is deliberately recognisable. Secret scanners can match
rk_live_and flag a key committed to a repository or pasted into a ticket. The dashboard shows each key's first characters (rk_live_7Hq2…) so you can tell keys apart. - Keys cannot be changed. To change a key's scopes, or to rotate it, make a new one, deploy it, then revoke the old one. Revoking takes effect on the very next request.
- An expiry is optional. A key made with
expires_atstops working at that moment. - Last used is recorded to the minute and shown beside each key, so a key nobody uses stands out and can be revoked.
- Keep keys on a server. A key in a browser, a mobile app or a public repository is a key anyone can use. The API does not accept keys from web pages on other sites (no CORS), which is a guard, not a reason to try.
A key belongs to the organisation, not to the person who made it: it keeps working if they leave. It acts with an admin's permissions, narrowed to its scopes. An organisation can have 50 keys.
Scopes
A key can do only what its scopes allow. Each route names the one it needs in the
API reference; a key without it gets 403:
{
"type": "https://docs.akteora.com/errors/insufficient_scope",
"title": "Missing scope",
"status": 403,
"detail": "This API key does not have the \"brands:write\" scope, which POST /v1/brands needs. Create a key that includes it (keys cannot be changed once made).",
"required_scope": "brands:write",
"request_id": "01K5C1…"
}
| Scope | Allows |
|---|---|
brands:read |
reading brands and widgets, and previewing a widget |
brands:write |
creating, changing and deleting brands and widgets, uploading a logo |
links:read |
reading collect links |
links:write |
creating, changing, duplicating and deleting collect links |
submissions:read |
reading testimonials, their transcripts, tags and media |
submissions:write |
correcting a transcript, or a respondent's title and company |
submissions:moderate |
approving, rejecting, publishing, tagging and deleting testimonials; managing tags |
reels:read |
reading reels and the music they can use |
reels:write |
creating, editing, rendering, sharing and deleting reels |
exports:write |
starting exports, and reading them to download the file |
webhooks:manage |
webhook endpoints, their delivery log, test events and replays |
Give each key the fewest scopes that do its job: a key that only publishes testimonials to a
website needs submissions:read and nothing else.
No key can reach these, whatever its scopes — they are for a signed-in person in the dashboard:
billing and plans, members and invitations, the account, and API keys themselves (a key that could
make keys could make one stronger than itself). A key gets 403 there:
{
"type": "https://docs.akteora.com/errors/forbidden",
"title": "Not available to API keys",
"status": 403,
"detail": "GET /v1/billing is not available to API keys. It is done in the dashboard, by a signed-in member.",
"request_id": "01K5C1…"
}
When a key is refused
| Status | detail says |
What to do |
|---|---|---|
401 |
This API key is not valid | Check it was copied whole, with its rk_ prefix, and sent as Authorization: Bearer … |
401 |
This API key was revoked on … | Make a new key |
401 |
This API key expired on … | Make a new key |
403 |
This API key does not have the "…" scope | Make a key with that scope |
403 |
… is not available to API keys | Do it in the dashboard |
402 |
API keys are not included on the … plan | Only when making a key; keys already made keep working after a plan change |
429 |
Too many attempts | After many unknown keys from one address, that address waits (rate limits) |
A 401 for a key never says whether the key exists in another organisation: an unknown key and a
key from nowhere read the same.
Test mode
A key that starts rk_test_ works on your organisation's test-mode sandbox: a second, separate
set of brands, collect links, testimonials, widgets, reels, exports and webhook endpoints. The
sandbox is made with your first test key, and starts with one brand.
The same API. Every route, shape, error and limit behaves as it does live — the same code runs on both. Code written against test mode works unchanged with a live key.
Nothing live, in either direction. A test key cannot read or change a single live record, and a live key — or the dashboard — cannot see test data. Asking for another mode's record by id gets
404, as for any id that is not yours.Real testimonials. A test collect link opens the real capture page; what someone records or writes there lands in test mode. That is how you try the whole loop without a customer seeing anything.
Webhooks by mode. Events from test-mode activity carry
"mode": "test"and go only to endpoints made with a test key; live events go only to live endpoints.Small allowances of its own, counted separately from your plan's live ones, which test mode never uses up:
In test mode Brands 5 Testimonials a month 50 Render minutes a month 5 Storage 1 GB Exports a month 20 A plan's own limit still applies if it is lower (Free renders no reels, in test mode too). Going over one is
402 plan_limit_exceededwithupgrade_to: null— no plan raises a test-mode allowance.No public walls. A test-mode brand cannot be made public on akteora.com (
422).The same features as your plan. Test mode is not a way to try features your plan does not include.
Test data is never deleted automatically. Delete what you no longer need, as you would live.