POST /api/crypto/encrypt
Encrypt data, optionally minting a new key.
Encrypts data. If ttag is omitted the key server mints a new key, and the ttag
in the response is the only handle to it -- without it the ciphertext cannot ever be
decrypted. minted in the response says which happened.
WARNING: ttag: "" is refused rather than treated as omitted. An empty string reaches
the wire as the zero-length buffer that means "mint a new key", so a caller who sent one
by accident would silently mint a key instead of using theirs. Omit the field entirely to
mint deliberately.
The ttag is echoed in the response because the underlying binding bolts it onto the
ciphertext buffer as a property rather than returning a pair, and any copy of that buffer
loses it.
On a scoped credential the ttag must be in the credential's object list. A mint (no
ttag) names no object and is therefore not scope-checked.
Authentication
Send the session id as Authorization: Bearer <session id>, and an RFC 9449 DPoP proof in the DPoP header if your session is bound to a key. The two are required together, not as alternatives — see Authenticating and Proving you hold your key.
There is no session cookie on any response and none is read on any request. Do not set credentials: "include" on a browser fetch.
Request
| Field | Type | Required | Description |
|---|---|---|---|
data | string | yes | Canonical base64. |
ttag | string | no | Canonical base64 hidden link. OMIT to mint a new key. Do not send an empty string. |
iv | string | no | Canonical base64. Optional. |
Example
{
"data": "...",
"ttag": "...",
"iv": "..."
}
Responses
200
Encrypted.
| Field | Type | Required | Description |
|---|---|---|---|
ciphertext | string | yes | base64 |
ttag | string | yes | base64. When minted is true this is the ONLY handle to the new key. Store it before doing anything else. |
minted | boolean | yes | |
ivSupplied | boolean | no | |
plaintextBytes | integer | no | |
ciphertextBytes | integer | no | |
detail | string | yes |
Example
{
"ciphertext": "...",
"ttag": "...",
"minted": true,
"ivSupplied": true,
"plaintextBytes": 0,
"ciphertextBytes": 0,
"detail": "..."
}
400
BAD_REQUEST -- data absent or not canonical base64, ttag empty-string, or a malformed iv.
401
The session, or the DPoP proof, or SCOPED_CREDENTIAL_EXPIRED. See the shared Unauthorized description.
403
OBJECT_NOT_IN_CREDENTIAL_SCOPE -- this scoped credential was not minted to cover that ttag. This is not a statement about your rights: whether the principal may reach the object is the key server's answer and it has not been asked; nothing was sent. Or ACCESS_DENIED from the key server itself.
500
A fault rather than a refusal.
OP_FAILED is the catch-all: the key server refused in words that match no classified
pattern, so the Gateway cannot say more than that the operation did not happen. Some key
server refusals that are conceptually a caller error arrive here rather than as a 4xx,
because the wire carries no distinguishing code -- where a route can recognise one from
its message it maps it, and each such mapping is documented on the operation.
503
A capacity ceiling or a missing deployment prerequisite. retryable says which.
A scope of session or process names the ceiling that was hit, and the response
carries Retry-After.
Error handling
Every failure answers JSON carrying at least code and detail. Match on code — detail is written for a human debugging the call and its wording is not part of the contract. See the error model.
| Status | Meaning |
|---|---|
400 | BAD_REQUEST -- data absent or not canonical base64, ttag empty-string, or a malformed iv. |
401 | The session, or the DPoP proof, or SCOPED_CREDENTIAL_EXPIRED. See the shared Unauthorized description. |
403 | OBJECT_NOT_IN_CREDENTIAL_SCOPE -- this scoped credential was not minted to cover that ttag. This is not a statement about your rights: whether the principal may reach the object is the key server's answer and it has not been asked; nothing was sent. Or ACCESS_DENIED from the key server itself. |
500 | A fault rather than a refusal. OP_FAILED is the catch-all: the key server refused in words that match no classified pattern, so the Gateway cannot say more than that the operation did not happen. Some key server refusals that are conceptually a caller error arrive here rather than as a 4xx, because the wire carries no distinguishing code -- where a route can recognise one from its message it maps it, and each such mapping is documented on the operation. |
503 | A capacity ceiling or a missing deployment prerequisite. retryable says which. A scope of session or process names the ceiling that was hit, and the response carries Retry-After. |