API keys and authentication
How StickyPrompts API keys work - format, lifecycle, the exact bearer header, the error responses you can get and how to keep keys safe.
Every REST call and every MCP session authenticates with an API key that you create in the app. A key acts as you, limited to the permissions you give it. There is one kind of key and one header, for both the REST API and the MCP server.
Create a key
- Open Settings > API keys
Go to Settings and select API keys.
- Generate a key
Select Generate key. Give it a name that says where it will be used (for example Northwind CRM sync) and tick the permissions it needs - see the permissions reference.
- Copy the key
The full key is shown exactly once, right after you create it. It cannot be retrieved later, by you or by StickyPrompts. Put it straight into your secret manager.
Keys can only be created by a signed-in user in the app. The key-management endpoints cannot be called with an API key, so a key can never create, list or change keys.
Key format
STICKY-API-<64 characters>
- The prefix is always
STICKY-API-, followed by 64 random characters. The full key is 75 characters long. - The random part uses digits, consonants (no vowels),
-and_. - StickyPrompts stores only a hash of the secret, plus its first 16 characters to find it. That is why a lost key cannot be shown again.
Lifecycle
| What you want | What to do |
|---|---|
| Expiry | Keys do not expire. They stay valid until you delete them. |
| Revoke a key | Delete it. Deletion is permanent and takes effect immediately. |
| Rename a key or change its permissions | Edit it. The secret stays the same, so nothing needs redeploying. |
| Rotate a key | Create a new key with the same permissions, switch your integration over, then delete the old one. |
| See whether a key is in use | Each key records when it was last used (updated at most once a minute). |
Send the key
Send the key as a bearer token in the Authorization header on every request:
Authorization: Bearer STICKY-API-...
The prefix Bearer STICKY-API- is case-sensitive and must be exact. There is no query-string or cookie alternative.
curl https://api.stickyprompts.com/api/v1/workspace \
-H "Authorization: Bearer $STICKY_API_KEY"import os
import requests
r = requests.get(
"https://api.stickyprompts.com/api/v1/workspace",
headers={"Authorization": f"Bearer {os.environ['STICKY_API_KEY']}"},
)
print(r.status_code, r.json())const res = await fetch("https://api.stickyprompts.com/api/v1/workspace", {
headers: { Authorization: `Bearer ${process.env.STICKY_API_KEY}` },
});
console.log(res.status, await res.json());(GET /workspace needs the organization_get permission.)
What a key can see
A key acts as the user who created it. It sees exactly what that user sees - their workspace, their projects, and whatever has been shared with them - and its permissions narrow that further. There is no per-workspace or per-project scoping on a key.
If your account stops being active, your keys stop working with it. If you leave a workspace or lose access to a project, your keys lose that access too.
How a request is checked
Every request goes through these checks, in this order. The first one that fails decides the response.
| Step | Check | Response when it fails |
|---|---|---|
| 1 | The header starts with Bearer STICKY-API- | Not treated as an API-key request at all, so it is rejected as unauthenticated: 401, sometimes with an empty body (over MCP: 401 {"error":"unauthorized"}) |
| 2 | The key exists, the secret matches and its owner still exists | 401 {"error":"Invalid API key"} |
| 3 | The owner’s account is active | 403 {"error":"user is not verified"} |
| 4 | The key holds at least one of the permissions the route accepts | 403 {"error":"This api key does not have any of the required permissions. You need at least one of: <permission>"} |
| 5 | The route is open to API keys at all | 403, either the message above with an empty list, or {"error":"This endpoint cannot be accessed with an api key"} |
Separately, requests from a region the service does not serve are refused with 403 {"error":"access from your region is not supported"}, for both REST and MCP.
The permission error names the permission you are missing, so the fix is usually to edit the key and tick it:
{"error": "This api key does not have any of the required permissions. You need at least one of: prompts_get"}
Over MCP, step 4 works differently: any valid, active key connects, and tools the key has no permission for are simply hidden. See MCP overview.
Routes keys can never use
Some parts of the API are reserved for a signed-in person in the app. An API key gets 403 on them whatever permissions it has:
- Account, sign-in and authentication routes.
- Billing and subscription routes.
- API-key management (creating, listing, editing and deleting keys).
- StickyPrompts staff administration routes.
- A few routes that are registered without an API-key permission, for example the single-prompt read
GET /prompt/:idand agent sharing (GET /agents/:id/sharesand thePATCH /agents/:id/share_with_*routes). Sharing agents is done in the app.
Keep keys safe
- Server side only. Keep keys in environment variables or a secret manager. Never commit them, log them, or paste them into tickets or chats.
- Least privilege. Tick only the permissions the integration uses. A reporting bot does not need
integration_email_manage. Start from the suggested sets. - One key per integration. Name each key after the system that uses it. You can then revoke one integration without touching the others, and see from its last-used time whether it is still active.
- Rotate. Replace keys on a schedule that suits you, and immediately when someone who had access leaves or a key might have leaked. Create the new key first, switch over, then delete the old one.
- Remember who the key is. A key acts as you. For a shared integration, consider creating the key from an account whose access matches what the integration should see.