REST API¶
A single endpoint executes every operation.
| Method | Endpoint | Description |
|---|---|---|
POST |
/cryptography |
Execute a cryptographic operation |
GET |
/health |
Liveness and available operations |
Request¶
| Field | Type | Required | Notes |
|---|---|---|---|
operation |
string | yes | differential_privacy, encryption, key_management, homomorphic_encryption, smpc |
backend |
string | yes | pydp, tink, pyfhel, mpyc |
input_data |
object | yes | Data to process |
parameters |
object | no | Operation-specific; see below |
key_config |
object | no | Key generation or loading |
output_format |
string | no | json (default and currently the only value) |
metadata |
object | no | Additional execution metadata |
Authorization |
header | yes | Bearer <token> |
Unknown fields are rejected rather than ignored, so a typo in a parameter name fails loudly instead of silently changing what runs.
Differential privacy — input_data: {"data": [...]}, and in parameters:
query_type (Count, Max, Min, Median, BoundedMean, BoundedSum,
BoundedStandardDeviation, BoundedVariance), epsilon_cost, and
lower_bound / upper_bound. Every query except Count requires bounds: they
determine sensitivity, and letting the backend infer them would spend privacy
that was never accounted for.
Encryption — parameters.action is encrypt or decrypt, with optional
associated_data. Input is {"plaintext": "..."} or
{"ciphertext": "<base64>"}. Ciphertext is base64 so it survives JSON.
Key management — parameters.action is generate_key, rotate_key or
key_info. Keysets are supplied through key_config as either
{"keyset": "<json>"} or {"keyset_path": "..."}.
This component stores no key material. generate_key returns the keyset to
the caller, who is responsible for keeping it and passing it back on every
subsequent call. Any operation that consumes a key requires one to be supplied:
generating a key implicitly would produce ciphertext that nobody could ever
decrypt, while reporting success.
A typical exchange:
# 1. Create a keyset and keep it. This is the only time it is handed out.
KEYSET=$(curl -s -X POST http://127.0.0.1:8000/cryptography \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"operation":"key_management","backend":"tink","input_data":{},
"parameters":{"action":"generate_key"}}' | jq -r .result.keyset)
# 2. Encrypt, passing the keyset back in key_config.
curl -X POST http://127.0.0.1:8000/cryptography \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d "$(jq -n --arg ks "$KEYSET" '{operation:"encryption",backend:"tink",
input_data:{plaintext:"sensitive"},
parameters:{action:"encrypt",associated_data:"ctx"},
key_config:{keyset:$ks}}')"
rotate_key returns the keyset with a new primary key added and the previous
keys retained, so ciphertext produced before the rotation still decrypts
afterwards. Keysets never appear in audit records.
Because the keyset travels in the request body, deployments handling real data should terminate TLS in front of the service, and would be better served by a keyset wrapped with a key management service. Tink supports GCP KMS, AWS KMS and Vault natively, so that is an extension rather than a redesign.
Response¶
| Field | Type | Notes |
|---|---|---|
status |
string | Workflow outcome |
result |
any | Output of the operation |
metadata |
object | Operation-specific, e.g. remaining_epsilon |
execution_time |
number | Seconds |
audit_id |
string | Identifier of the audit record for this request |
errors |
string | null | Populated on failure |
Status Codes¶
| Code | Workflow status | Condition |
|---|---|---|
| 200 | SUCCESS |
Completed |
| 400 | VALIDATION_ERROR |
Parameters or configuration invalid |
| 400 | INSUFFICIENT_BUDGET |
Requested cost exceeds remaining budget |
| 403 | UNAUTHORIZED |
Token missing or invalid |
| 413 | PAYLOAD_TOO_LARGE |
Request body exceeds the configured limit |
| 429 | BUDGET_EXHAUSTED |
No privacy budget remains |
| 500 | FAILED |
Backend raised during execution |
| 501 | NOT_IMPLEMENTED |
Operation recognised but not yet available |
Interactive documentation
A running instance serves FastAPI's generated OpenAPI explorer at /docs,
which is the authoritative description of the live schema.