Keys
The secret and publishable keys, where each one goes, and how to add, reset, rotate and delete them.
Every request to https://data.shipmantis.com carries a project key. The key says which project
the request is for and what it may do. There are two kinds, and they always come as a pair.
| Secret key | Publishable key | |
|---|---|---|
| Starts with | mk_secret_ | mk_pub_ |
| Lives in | Your server, the CLI, your agent | Your app in the browser |
| Environment variable | MANTIS_SECRET_KEY | MANTIS_PUBLISHABLE_KEY |
| Queries and files | Every row and every file. Access rules are skipped. | Only what your access rules allow. Nothing by default. |
| Schema, branches, rewind | Yes | No |
A project starts with one pair, made with the project. Each machine that runs init against
that project later gets its own pair.
Which key a request needs
| Request | Secret key | Publishable key |
|---|---|---|
POST /v1/query, and live queries over /v1/live | Yes | Yes, through the rules |
/v1/storage/* (files) | Yes | Yes, through the file rules |
/v1/schema/*: read, plan, apply, undo | Yes | No |
/v1/branches/*: list, create, promote, delete | Yes | No |
/v1/changes/{id} | Yes | No |
/v1/rewind/* | Yes | No |
A publishable key sent where the secret key is needed is refused with 403, before the request
does anything.
Sending a key
The SDK sends the key for you. Pass the one that fits where the code runs:
import { createClient } from "@shipmantis/sdk";
import schema from "../mantis/schema";
export const mantis = createClient({
url: process.env.MANTIS_URL!,
key: process.env.MANTIS_SECRET_KEY!,
schema,
});Without the SDK, send the key as a bearer token. Mantis-Branch picks a
branch; leave it out for main.
curl https://data.shipmantis.com/v1/schema \
-H "Authorization: Bearer $MANTIS_SECRET_KEY" \
-H "Mantis-Branch: try-tags"| Header | What it holds |
|---|---|
Authorization | Bearer <key>. Required on every /v1 request. |
Mantis-Branch | A branch name. Optional; main without it. |
Mantis-User-Token | The signed-in user's JWT, for the rules. Only the publishable key needs it. |
A live query sends the key once, when its connection opens, and the branch as a connection parameter. The SDK does both.
A pair per machine
Every key has a name, and the two keys of a pair share it. The first pair has no name; the dashboard lists it as Made with the project.
Running init on a project that already has keys makes a new pair named after the machine,
like work-laptop, mantis init, and writes it to that folder's .env.local. The keys on every
other machine keep working.
To make a pair yourself, open the project in the dashboard, type a name under New key pair (up to 64 characters), and press Add. A pair for your production server, one for CI and one per teammate's laptop means any one of them can be reset or deleted without touching the others.
Shown once
Mantis keeps a SHA-256 hash of each key, never the key itself. The full key is shown exactly
once: in the init output and .env.local, or in the dashboard right after you add or reset
it. After that the dashboard shows only its first 16 characters, like mk_secret_BS5QFt…, to
tell keys apart.
A lost key can't be recovered. Reset it, or add a new pair.
Reset or delete
Both are on the project's page in the dashboard, next to each key, and both ask before they do anything.
| Reset | Delete | |
|---|---|---|
| The key | Stops working at once | Stops working at once |
| A replacement | A new key of the same kind and name, shown once | None |
| Use it when | The key leaked, but the place that used it still needs one | The machine or service is gone, or you rotated it out |
| The other key of the pair | Untouched | Untouched |
Neither can be undone. To get a deleted key's place back, add a new pair.
Deleting every key leaves the project unreachable from code until you add a new pair. The dashboard and your data are not affected.
Rotating without downtime
A reset stops the old key before you have put the new one in place. To swap a key on a running service without a single refused request, overlap them:
Add a new pair
Under New key pair, name it after the service and today's date, like production 2026-10.
Copy both keys.
Deploy with the new keys
Set MANTIS_SECRET_KEY and MANTIS_PUBLISHABLE_KEY on the service and deploy. Both pairs work
in the meantime.
Delete the old pair
Once every instance runs the new keys, delete the old pair's two keys. Anything still on them is refused from its next request.
If a key leaks
A leaked secret key can read and change every row, change the schema and rewind. Treat it as an incident.
Reset it
Reset the key in the dashboard. It stops working on its next request.
Put the new key where the old one was
Update .env.local, your host's environment variables and CI. Requests with the old key are
refused until they have the new one.
Check what happened
Mantis records every write. Preview a rewind to the time the key leaked to see what has changed since, and apply it if the key was used against you.
A leaked publishable key is expected: every visitor to your site has it. What protects your data is the access rules. Reset it only if you want to cut off a copy of your app that uses it.
When a reset or delete takes effect
Every HTTP request looks its key up again, so the next request with a reset or deleted key is refused.
A live query checks its key when its connection opens. A connection that is already open keeps receiving updates until it closes, for example when the page is reloaded; it can't reconnect with the old key.
Keys and branches
Every key belongs to its project's main. There are no branch keys: any key can reach any
branch by naming it, through Mantis-Branch, --branch, MANTIS_BRANCH or
createClient({ branch }). A request for a branch that doesn't exist is refused with 404.
Keys and your agent
The MCP server and the CLI read MANTIS_SECRET_KEY from .env.local, then
.env. The agent works with the secret key, so its queries skip the rules; a risky change on
main still waits for a person in the dashboard.
init adds .env.local to .gitignore, and the instructions it writes for the agent tell it
never to print or commit the key. If it ever does, reset the key.
Errors
The SDK throws a MantisError with the status and the message:
import { MantisError } from "@shipmantis/sdk";
try {
await mantis.from("todos").select();
} catch (error) {
if (error instanceof MantisError && error.status === 401) {
// The key is missing, mistyped, reset or deleted.
}
throw error;
}| Status | Message | What to do |
|---|---|---|
401 | Send a valid project key as Authorization: Bearer <key>. | The key is missing, mistyped, reset or deleted. Copy the current one, or add a new pair. |
403 | This needs the project's secret key, not the publishable one. | Run that call on your server, with the secret key. |
404 | There is no branch "…". | Check the branch name with npx shipmantis branch list. |
400 | Send one Mantis-Branch header. | The request sent the header twice. |