deed.page has no signup, no email, and no password reset. Your first anonymous publish returns a deed_tok_… Bearer token, and that token *is* your account. It owns every slug you publish with it. deed.page stores only a SHA-256 hash of it, so nobody can look it up or send it back to you. This post covers how an agent should handle that token from the first call onward.
Every example below was run against production on October 9, 2026. The test sites used X-Ttl: 900 and were deleted afterwards.
Capture it on the first publish
The token shows up exactly once, in the response to the first publish made without a token:
curl -sS -X PUT --data-binary @index.html \
-H "Content-Type: text/html" -H "X-Ttl: 900" \
"https://deed.page/v1/sites/acme-notes-4k2q"
{"ok":true,"url":"https://acme-notes-4k2q.deed.page/", ..., "version":"v1",
"token":"deed_tok_…",
"token_note":"Shown once. Store it (for example env DEEDPAGE_TOKEN). There is no recovery if you lose it: we keep only a SHA-256 and do not collect an email. ..."}Read the token out of the response in the same step and write it straight to your secret store. Don't echo it to stdout:
resp=$(curl -sS -X PUT --data-binary @index.html \
-H "Content-Type: text/html" "https://deed.page/v1/sites/acme-notes-4k2q")
umask 077
printf '%s' "$resp" | jq -r '.token // empty' > ~/.deedpage-token
export DEEDPAGE_TOKEN=$(cat ~/.deedpage-token)If .token is missing, the request either failed or already carried a token. Check ok before you overwrite a token you saved earlier.
Reuse one token for every site
You don't need a token per site. Send the one you have with each new publish. The new slug joins the same principal, and the response has no token field because none was minted:
curl -sS -X PUT --data-binary @index.html \
-H "Content-Type: text/html" \
-H "Authorization: Bearer $DEEDPAGE_TOKEN" \
"https://deed.page/v1/sites/acme-notes-4k2q-b"Keeping one token per agent (or per deployment environment) is the simplest model to reason about. Your plan limits (Free is 25 sites) count against the principal, not against each request. GET /v1/sites returns everything the token owns:
curl -sS https://deed.page/v1/sites -H "Authorization: Bearer $DEEDPAGE_TOKEN"An agent that publishes without its token on every call ends up with many unrelated tokens. Each one owns a single slug and gets forgotten, and those sites can never be updated again.
Check the token before you rely on it
GET /v1/whoami is a free health check for your credentials:
curl -sS https://deed.page/v1/whoami -H "Authorization: Bearer $DEEDPAGE_TOKEN"
{"ok":true,"authenticated":true,"principal":"prin_…","plan":{"id":"free",...},
"sites":2,"site_limit":25,"email":null,"note":"deed.page never asks for an email."}With no header you get "authenticated":false. With a malformed or unknown token you get 401 unauthorized ("Unknown bearer token."). Run whoami at agent startup so that a missing or mistyped secret fails loudly before the agent tries a publish.
Read the error codes
The status codes tell you which credential problem you have:
- 401
unauthorized: no token was sent where one is required (list, delete), or the token is unknown. Fix the secret. - 403
forbidden: the token is valid but doesn't own the slug you tried to delete ("This token does not own that slug."). You're using the wrong token for that site. - 409
slug_taken: you published to a slug owned by a different token ("belongs to another token"), or to a taken slug with no token at all. If the slug is yours, send the right token. If it isn't, use thesuggestionfield.
A refused request never mints a token and never changes the site.
The same rules over MCP
The MCP server at https://deed.page/mcp accepts the token two ways: an Authorization: Bearer header on the HTTP connection, or a token argument on each tool call. Prefer the header. It keeps the secret out of tool-call arguments, which many clients log or show in transcripts.
curl -sS https://deed.page/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer $DEEDPAGE_TOKEN" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"whoami","arguments":{}}}'whoami returns "authenticated":true with your principal and site count. list_sites called with no token at all returns an isError result: "Token required: pass the token from your first publish." publish_site behaves like the REST call. Its first anonymous call returns token in the result, so the same capture-once rule applies.
What there isn't (yet)
deed.page has no endpoint today for rotating or revoking a token, and no recovery if one is lost. Plan for that:
- Treat the token like a deploy key. Keep it in a secret manager or a
0600file, never in a repo, a public page, a prompt, or a log line. - Scope by token. Give separate agents or environments separate tokens, so a leak exposes only that token's sites.
- If a token leaks, use it yourself to
DELETE /v1/sites/{slug}the sites it owns. Then publish from a fresh anonymous call, which mints a new token, and point your links at the new slugs. - If a token is lost, its permanent sites stay online but can't be changed. Sites with an
X-Ttlexpire on schedule and free their slugs.
One token, captured once, stored like a secret, and checked with whoami covers nearly every credential problem an agent will hit on deed.page.