Compatibility: legacy and canonical names
Satsignal's public API and dashboard speak the canonical vocabulary —
proof,folder,proof_id,folder_slug,proof_url. The legacy names —receipt,matter,bundle_id,matter_slug,receipt_url— are inbound-only compatibility shims: requests, routes, query parameters, and scopes written against them keep working forever, but responses emit the canonical names only. This page is the single reference for the mapping. Requests using legacy spellings are never rejected for the spelling; new code should use the canonical names.
Companion docs: API reference · Production checklist · OpenAPI spec
1. Why both vocabularies coexist
The wire format and database schema were built around the nouns receipt and matter. In May 2026 Satsignal flipped its public-facing vocabulary to proof and folder — clearer, less legal-jargon, easier to talk about with non-lawyer integrators. The new vocabulary lives in the UI, the marketing copy, the docs, and is the recommended set of field names for new code.
Breaking inbound traffic written against the old names would have required every existing client to re-deploy in lockstep, with zero buyer-visible value. Instead, the boundary accepts both spellings on request bodies, routes, and query parameters, treats the scope strings as bidirectional aliases, and folds everything into the canonical names before any handler runs. Responses emit the canonical names only (superseding the earlier "mirror both spellings in responses" posture). Old code that sends legacy names keeps working forever; code that reads responses uses the canonical names. There is no deprecation timeline for the inbound aliases.
2. The mapping at a glance
| Concept | Canonical (public, new code, UI, docs) | Legacy (wire, DB, CLI flags) |
|---|---|---|
| The logical record | proof | receipt |
| Dashboard namespace | folder | matter |
| Marketing / landing term | project | (n/a — pure UI label, not on the wire) |
| The downloadable file | .mbnt bundle | .mbnt bundle (no rename) |
| Combined zip + proof page | proof package | (n/a) |
| Workflow names | Standard / Sealed / Mirror / Blind | (same) |
3. Endpoint paths
Both forms route to the same handler. New code should call the canonical paths; legacy paths remain stable.
| Canonical path | Legacy alias |
|---|---|
POST /api/v1/anchors | (no legacy form — this path was canonical from day one) |
GET /api/v1/anchors | GET /api/v1/receipts |
GET /api/v1/anchors/{id} | GET /api/v1/receipts/{id} |
GET /api/v1/proofs/{id} | GET /api/v1/receipts/{id} |
PATCH /api/v1/anchors/{id} | PATCH /api/v1/receipts/{id} |
POST /api/v1/folders | POST /api/v1/matters |
GET /api/v1/folders | GET /api/v1/matters |
GET /api/v1/folders/{slug}/anchors | GET /api/v1/matters/{slug}/anchors |
A response from any legacy path is byte-identical to the response from its canonical sibling — the alias is route-level, not response-level.
4. Request body fields
The boundary folds the legacy request alias into the canonical slot before any handler reads the body, so downstream code sees the canonical spelling regardless of which name the client sent.
| Canonical | Legacy | Notes |
|---|---|---|
folder_slug | matter_slug | Use either; sending both with conflicting non-empty values returns 400 conflicting_alias. Sending both with identical values is accepted. |
In practice: pick one name per integration and stick with it. If your codebase is migrating piecemeal, the safe pattern is to set folder_slug everywhere new and leave any legacy matter_slug references alone — both routes accept both names.
/lookup_hash accepts both ?sha= and ?sha256_hex=
JSON request bodies everywhere in the API use sha256_hex for a 64-char hex commitment. The auth-free lookup endpoint GET /lookup_hash historically accepted only ?sha=<hex> as its query parameter — a small inconsistency. As of the 2026-05-26 docs sprint, the endpoint accepts EITHER name:
# Both forms now work identically
curl -sS "https://app.satsignal.cloud/lookup_hash?sha=$SHA"
curl -sS "https://app.satsignal.cloud/lookup_hash?sha256_hex=$SHA"
The OpenAPI spec lists both sha and sha256_hex as optional query parameters; the operation description specifies that exactly one must be supplied (or both with identical values). If both are supplied with different values, the response is 400 conflicting_alias — the same convention /api/v1/anchors uses for matter_slug vs folder_slug. Error messages name both parameters: e.g. ?sha or ?sha256_hex query parameter is required.
5. Response body fields
Every 2xx response emits the canonical spelling ONLY — the legacy response keys were dropped when responses went canonical-only. If your code still reads a legacy key from the table below, switch it to the canonical sibling (the value is identical; only the key name changed).
| Canonical (emitted) | Legacy (no longer emitted) |
|---|---|
proof_id | bundle_id |
proof_url | receipt_url |
proof_kind | receipt_kind |
folder_slug | matter_slug |
folder_id | matter_id |
folder_name | matter_name |
folder_anchors_url | matter_anchors_url |
folder_anchor_count | matter_anchor_count |
folders[] | matters[] (in list responses) |
folder | matter (in create responses) |
A snippet of a real response:
{
"proof_id": "abc123def456...",
"txid": "5e9a...c4f1",
"folder_slug": "acme-events",
"proof_url": "https://app.satsignal.cloud/w/.../r/abc123def456",
"bundle_url": "https://app.satsignal.cloud/bundle/abc123def456.mbnt"
}
URL-valued fields are also re-pointed at the canonical routes: folder_anchors_url points at /api/v1/folders/..., and a proof_url carrying the legacy /api/v1/receipts/... or /receipt/<id> form is rewritten to /api/v1/proofs/... / /proof/<id> — so a client that follows a response link never re-enters the legacy vocabulary.
One frozen exception: the annotation field superseded_by_bundle_id (the proof id of a superseding anchor) keeps its legacy spelling on the wire, in both requests and responses — it is a stable wire literal, not aliased.
bundle_url vs proof_url — they're not the same URL
bundle_url is the programmatic download for the .mbnt zip. Authenticate with Authorization: Bearer <key> and you get a 200 with the bundle bytes. This is the field a CI runner, agent, or webhook consumer should consume.
proof_url (spelled receipt_url by pre-flip clients) points at the human web UI for that proof on app.satsignal.cloud. The route expects a logged-in browser session — a Bearer-authed curl against https://app.satsignal.cloud/proof/<id> (or the legacy /receipt/<id> alias) returns HTTP 303 and redirects to /login. The field is still useful (you can share that URL with a teammate to view in a browser), but API clients should treat bundle_url as the only programmatic-grade URL in the response.
| Field | Auth model | What you get |
|---|---|---|
bundle_url | Bearer-auth | .mbnt zip (200) |
proof_url | Browser session | HTML proof page (303 → /login under Bearer) |
For all programmatic verification flows, see guide-files §11.
6. API key scopes
Scope aliases are bidirectional — a key minted with one form satisfies a requirement for the other. Newly minted keys store the canonical proofs:* spellings; keys whose stored scopes still say receipts:* keep working untouched.
| Canonical scope | Legacy alias |
|---|---|
proofs:read | receipts:read |
proofs:annotate | receipts:annotate |
anchors:create | (no legacy form — canonical from day one) |
admin | (no alias) |
Concretely: a key minted with ["anchors:create", "receipts:read"] can service a code path that asks for proofs:read, and vice versa. has_scope(key, "proofs:read") and has_scope(key, "receipts:read") return the same boolean for any given key.
7. CLI flags
The satsignal-cli tool accepts both forms on every command that takes a folder argument.
| Canonical | Legacy |
|---|---|
--folder <slug> | --matter <slug> |
SATSIGNAL_FOLDER env var | SATSIGNAL_MATTER env var |
Mixing forms within a single invocation (one flag canonical, one env var legacy) is allowed — the CLI normalizes before dispatch. For scripted use, pick one form per script and stay consistent.
8. MCP tool input names
The satsignal-mcp tool surface uses the legacy matter form for its input field names. The MCP wire contract is a stability surface in its own right — clients that hard-coded the matter field continue working without change.
Tool authors integrating with satsignal-mcp from a canonical-vocab codebase can map their internal names at the MCP boundary; the tool inputs themselves stay on the legacy spelling.
9. Error codes
Error codes use the canonical vocabulary. The codes that previously carried the legacy noun were renamed when responses went canonical-only (an error code is a response surface):
folder_not_found(previouslymatter_not_found) — the named folder doesn't exist, or is out of the API key's scope. Returned as404; deliberately not403, to avoid enumeration of folder names against scoped keys.missing_folder_slug(previouslymissing_matter_slug) — neitherfolder_slugnor its legacy aliasmatter_slugwas supplied in a request that required one. The error message reads:folder_slug is required (matter_slug accepted as a legacy alias).conflicting_alias— bothfolder_slugandmatter_slugwere supplied with different non-empty values. Send onlyfolder_slug.idempotency_key_reuse_body_mismatch— unchanged; never carried a legacy noun.
If your error handling matched on the old code strings, update it — the error-code rename shipped together with the canonical-only response flip.
10. What does NOT change
Despite the dual vocab, these are stable single names. No alias, no mirror — the canonical form is the only form, and it has always been the only form.
.mbntfile extension.- The bundle's internal manifest field names (
canonical.json,manifest.json,proofs.json). - The
proof_setenvelope's keys (byte_exact,chunk_merkle,content_canonical). - The canonical-doc schema identifier (
satsignal.provenance.v1). - HTTP header names —
Authorization,Idempotency-Key,X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset,X-RateLimit-Window,X-Idempotent-Replayed,X-Satsignal-Signature. - The transaction shape — one
OP_RETURNoutput carrying the 20-byte truncated hash of the canonical doc.
If a piece of the protocol below the HTTP boundary is not in the mapping tables above, it does not have an alias.
11. Migration guide (if you have legacy code)
Your existing integration written against receipt_url / matter_slug / /api/v1/receipts/... keeps working. There is no deprecation timeline. Migrate at your own pace.
If you choose to migrate:
- Replace request-body fields.
matter_slug→folder_slug. Both are accepted; the canonical form is recommended for new code and reads more naturally to non-lawyer collaborators. - Read responses by canonical names.
proof_id,proof_url,proof_kind,folder_slug,folder_id,folder_name. Responses emit only the canonical keys, so a reader still on the legacy spellings sees missing fields — this is the one part of the migration that is required, not optional. - Update CLI flag spellings.
--matter→--folder. The legacy--matterflag stays accepted, so this is also at-your-leisure. - Update scope strings when minting new keys.
receipts:read→proofs:read. Existing keys keep their stored scopes — you do not need to revoke + re-mint to "upgrade" a key's scope spelling. - Dashboard URLs are unchanged. The
/w/<ws>/m/<slug>/r/<id>path shape (with its/m/segment) is a frozen URL contract — existing bookmarks and emailed links keep resolving. The short HTML alias is/proof/<id>(legacy/receipt/<id>still routes).
Migrating what you send is optional — the two request vocabularies will coexist for the indefinite future, and a mixed codebase (some files using folder_slug, some still on matter_slug) is a supported state. Migrating what you read is required, since responses emit the canonical keys only.
12. Where this fits
- Path guides: Files · Webhooks · Agents · CI/CD · Sealed · Manifest
- Reference: What to hash · Production checklist
- Machine-readable: OpenAPI spec (legacy names documented inline in field descriptions)
Questions about this specification? Email hello@satsignal.cloud.