Skip to content

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 privacyinput_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.

Encryptionparameters.action is encrypt or decrypt, with optional associated_data. Input is {"plaintext": "..."} or {"ciphertext": "<base64>"}. Ciphertext is base64 so it survives JSON.

Key managementparameters.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.