The KEM (Key Encapsulation Mechanism) API provides post-quantum encryption and decryption using the Kyber768 algorithm. Qpher uses a hybrid KEM-DEM scheme: Kyber768 encapsulates a shared secret, which is then used with HKDF-SHA256 and AES-256-GCM to encrypt your data.
đ Private keys never leave Qpher
All decryption operations happen inside the Qpher secure enclave. Your private keys are never exposed or exported.
âšī¸ X-Wing hybrid KEM (Starter+)
Pass "algorithm": "X-Wing" in encrypt/decrypt requests to use hybrid KEM (X25519 + ML-KEM-768).
If omitted, the default is "Kyber768" (PQC-only, backward-compatible).
X-Wing provides defense-in-depth by combining the post-quantum security of ML-KEM-768
with the battle-tested classical security of X25519. This construction follows the
IETF CFRG X-Wing draft (draft-connolly-cfrg-xwing-kem).
See Security Architecture for details.
Encryptâ
POST /api/v1/kem/encrypt Encrypt plaintext using Kyber768 KEM-DEM hybrid encryption.
Encrypts the provided plaintext using the KEM-DEM scheme with the specified key version. The key must be in active status.
Request bodyâ
Field Type Required Description plaintextstring (base64) Yes Base64-encoded data to encrypt. Maximum size: 1 MB. key_versioninteger Yes The version of the Kyber768 key to use. Must reference an active key. algorithmstring No "Kyber768" (default) or "X-Wing" (hybrid, Starter+). If omitted, defaults to Kyber768.modestring No Encryption mode: "standard" (default) or "deterministic". saltstring (base64) Conditional Base64-encoded salt. Required when mode is "deterministic".
â ī¸ Deterministic mode
Deterministic encryption (mode: "deterministic") produces identical ciphertext for the same plaintext and salt. Use it only when you need equality checks on encrypted data. Standard mode is recommended for all other use cases.
Response (200 OK)â
Field Type Description data.ciphertextstring (base64) The encrypted data, base64-encoded. data.key_versioninteger The key version used for encryption. data.algorithmstring "Kyber768" or "X-Wing", matching the algorithm used for the operation.
Exampleâ
X-API-Key: qph_your_key_here
Content-Type: application/json{
"plaintext": "SGVsbG8sIFdvcmxkIQ==",
"key_version": 1
}{
"data": {
"ciphertext": "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5...",
"key_version": 1,
"algorithm": "Kyber768"
},
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"timestamp": "2026-01-15T10:30:00.000Z"
}
curl -X POST https://api.qpher.ai/api/v1/kem/encrypt \
-H "X-API-Key: qph_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"plaintext": "SGVsbG8sIFdvcmxkIQ==",
"key_version": 1
}'Copy
HTTP Status Error Code Description 400 ERR_KEM_001Invalid encryption request â missing plaintext, invalid key_version, or bad encoding. 401 ERR_AUTH_001Missing or invalid API key. 404 ERR_NOT_FOUND_001Key version not found or key is not in active status. 429 ERR_RATE_LIMIT_001Rate limit exceeded for your plan tier.
Decryptâ
POST /api/v1/kem/decrypt Decrypt ciphertext using Kyber768 KEM-DEM hybrid decryption.
Decrypts ciphertext that was previously encrypted with the KEM encrypt endpoint. The referenced key must be in active or retired status.
Request bodyâ
Field Type Required Description ciphertextstring (base64) Yes Base64-encoded ciphertext returned by the encrypt endpoint. key_versioninteger Yes The key version that was used to encrypt this data. algorithmstring No "Kyber768" (default) or "X-Wing" (hybrid, Starter+). If omitted, defaults to Kyber768.
Response (200 OK)â
Field Type Description data.plaintextstring (base64) The decrypted data, base64-encoded. data.key_versioninteger The key version used for decryption. data.algorithmstring "Kyber768" or "X-Wing", matching the algorithm used for the operation.
Exampleâ
X-API-Key: qph_your_key_here
Content-Type: application/json{
"ciphertext": "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5...",
"key_version": 1
}{
"data": {
"plaintext": "SGVsbG8sIFdvcmxkIQ==",
"key_version": 1,
"algorithm": "Kyber768"
},
"request_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"timestamp": "2026-01-15T10:30:01.000Z"
}
curl -X POST https://api.qpher.ai/api/v1/kem/decrypt \
-H "X-API-Key: qph_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"ciphertext": "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5...",
"key_version": 1
}'Copy
HTTP Status Error Code Description 400 ERR_KEM_002Invalid decryption request â corrupt ciphertext or wrong key_version. 401 ERR_AUTH_001Missing or invalid API key. 404 ERR_NOT_FOUND_001Key version not found or key is in archived status. 429 ERR_RATE_LIMIT_001Rate limit exceeded for your plan tier.
Encapsulateâ
POST /api/v1/kem/encapsulate Encapsulate a shared secret using Kyber768 KEM â for client-side (zero-trust) encryption.
Returns a KEM ciphertext and a 32-byte shared secret. The plaintext never leaves your environment. Use the shared secret as an AES-256-GCM key to encrypt data locally, then store the KEM ciphertext for later decapsulation.
đ Zero-trust encryption
With encapsulate/decapsulate, Qpher never sees your plaintext. You perform AES-256-GCM encryption locally using the shared secret. This is the most privacy-preserving mode.
Request bodyâ
Field Type Required Description key_versioninteger Yes The version of the KEM key to use. Must reference an active key. algorithmstring No "Kyber768" (default) or "X-Wing" (hybrid, Starter+).
Response (200 OK)â
Field Type Description data.kem_ciphertextstring (base64) The KEM ciphertext. Store this â you need it for decapsulate. data.shared_secretstring (base64) 32-byte shared secret (base64). Use as your AES-256-GCM key. Ephemeral â Qpher does not store this. data.key_versioninteger The key version used. data.algorithmstring "Kyber768" or "X-Wing".
Exampleâ
curl -X POST https://api.qpher.ai/api/v1/kem/encapsulate \
-H "X-API-Key: qph_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"key_version": 1
}'Copy
HTTP Status Error Code Description 400 ERR_KEM_001Invalid encapsulate request â invalid key_version. 401 ERR_AUTH_001Missing or invalid API key. 404 ERR_NOT_FOUND_001Key version not found or key is not in active status. 429 ERR_RATE_LIMIT_001Rate limit exceeded for your plan tier.
Decapsulateâ
POST /api/v1/kem/decapsulate Decapsulate a shared secret using Kyber768 KEM â for client-side (zero-trust) decryption.
Returns the same 32-byte shared secret that was produced during encapsulation. Use it to decrypt data that was encrypted client-side. The referenced key must be in active or retired status.
Request bodyâ
Field Type Required Description kem_ciphertextstring (base64) Yes The KEM ciphertext from the encapsulate response. key_versioninteger Yes The key version used during encapsulation. algorithmstring No "Kyber768" (default) or "X-Wing" (hybrid, Starter+).
Response (200 OK)â
Field Type Description data.shared_secretstring (base64) The same 32-byte shared secret from the original encapsulate call. data.key_versioninteger The key version used. data.algorithmstring "Kyber768" or "X-Wing".
Exampleâ
curl -X POST https://api.qpher.ai/api/v1/kem/decapsulate \
-H "X-API-Key: qph_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"kem_ciphertext": "a2VtX2NpcGhlcnRleHRfZnJvbV9lbmNhcHN1bGF0ZS4uLg==",
"key_version": 1
}'Copy
HTTP Status Error Code Description 400 ERR_KEM_002Invalid decapsulate request â invalid kem_ciphertext size or key_version. 401 ERR_AUTH_001Missing or invalid API key. 404 ERR_NOT_FOUND_001Key version not found or key is in archived status. 429 ERR_RATE_LIMIT_001Rate limit exceeded for your plan tier.
Key Wrapâ
POST /api/v1/kem/key/wrap Wrap a symmetric key using Kyber768 KEM-DEM hybrid encryption.
Wraps (encrypts) a symmetric key using the KEM-DEM scheme with the specified key version. Use this to protect existing AES keys, HMAC secrets, or other symmetric material with quantum-safe encryption. The key must be in active status.
Request bodyâ
Field Type Required Description symmetric_keystring (base64) Yes Base64-encoded symmetric key to wrap. Supported sizes: 16, 24, 32, 48, or 64 bytes. key_versioninteger Yes The version of the Kyber768 key to use. Must reference an active key. algorithmstring No "Kyber768" (default) or "X-Wing" (hybrid, Starter+). If omitted, defaults to Kyber768.
Response (200 OK)â
Field Type Description data.wrapped_keystring (base64) The wrapped (encrypted) symmetric key, base64-encoded. data.key_versioninteger The key version used for wrapping. data.algorithmstring "Kyber768" or "X-Wing", matching the algorithm used for the operation.data.wrapping_methodstring The wrapping method used, e.g. "KEM-DEM".
Exampleâ
curl -X POST https://api.qpher.ai/api/v1/kem/key/wrap \
-H "X-API-Key: qph_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"symmetric_key": "c3ltbWV0cmljX2tleV8zMl9ieXRlcw==",
"key_version": 1
}'Copy
HTTP Status Error Code Description 400 ERR_KEM_010Invalid wrap request â missing symmetric_key, invalid key_version, bad encoding, or unsupported key size. Supported sizes: 16, 24, 32, 48, or 64 bytes. 401 ERR_AUTH_001Missing or invalid API key. 404 ERR_NOT_FOUND_001Key version not found or key is not in active status. 429 ERR_RATE_LIMIT_001Rate limit exceeded for your plan tier.
Key Unwrapâ
POST /api/v1/kem/key/unwrap Unwrap a symmetric key using Kyber768 KEM-DEM hybrid decryption.
Unwraps (decrypts) a symmetric key that was previously wrapped with the Key Wrap endpoint. The referenced key must be in active or retired status.
Request bodyâ
Field Type Required Description wrapped_keystring (base64) Yes Base64-encoded wrapped key returned by the wrap endpoint. key_versioninteger Yes The key version that was used to wrap this key. algorithmstring No "Kyber768" (default) or "X-Wing" (hybrid, Starter+). If omitted, defaults to Kyber768.
Response (200 OK)â
Field Type Description data.symmetric_keystring (base64) The unwrapped symmetric key, base64-encoded. data.key_versioninteger The key version used for unwrapping. data.algorithmstring "Kyber768" or "X-Wing", matching the algorithm used for the operation.
Exampleâ
curl -X POST https://api.qpher.ai/api/v1/kem/key/unwrap \
-H "X-API-Key: qph_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"wrapped_key": "d3JhcHBlZF9rZXlfZGF0YV9oZXJl...",
"key_version": 1
}'Copy
HTTP Status Error Code Description 400 ERR_KEM_011Invalid unwrap request â missing wrapped_key, bad base64 encoding, or data too short. 400 ERR_KEM_012Wrapped key integrity check failed â corrupt data or wrong key_version. 401 ERR_AUTH_001Missing or invalid API key. 404 ERR_NOT_FOUND_001Key version not found or key is in archived status. 429 ERR_RATE_LIMIT_001Rate limit exceeded for your plan tier.
Key Version Requirementsâ
The key_version field is mandatory on all KEM operations. There is no implicit "use latest key" behavior.
Operation Allowed Key Statuses Encrypt active onlyDecrypt active or retiredEncapsulate active onlyDecapsulate active or retiredKey Wrap active onlyKey Unwrap active or retired
Use the Key Management API to list your keys and find the current active version.