Skip to main content

Key Management API

The Key Management API lets you generate, rotate, list, and retire your PQC cryptographic keys. Qpher supports four algorithms: Kyber768 and X-Wing for encryption, Dilithium3 and Composite-ML-DSA for digital signatures.

Public keys only

The Key Management API returns public key material only. Private keys are stored exclusively inside the Qpher secure enclave and are never exposed through any API endpoint.

Hybrid algorithms (Starter+)

The algorithm parameter now also accepts "X-Wing" (hybrid KEM) and "Composite-ML-DSA" (hybrid signatures), in addition to "Kyber768" and "Dilithium3".

Hybrid keys follow the same lifecycle rules as PQC-only keys: explicit key_version, active/retired/archived states, and no implicit "latest" default.


Generate Key​

POST/api/v1/kms/keys/generateGenerate a new PQC key pair for the specified algorithm.

Creates a new key pair and sets it to active status. If an active key already exists for the given algorithm, the request is rejected β€” use Rotate Key to replace the active key instead.

Request body​

FieldTypeRequiredDescription
algorithmstringYesThe PQC algorithm: "Kyber768", "Dilithium3", "X-Wing", or "Composite-ML-DSA".

Response (201 Created)​

FieldTypeDescription
data.key_versionintegerThe version number assigned to this key.
data.algorithmstringThe algorithm used: "Kyber768", "Dilithium3", "X-Wing", or "Composite-ML-DSA".
data.statusstringAlways "active" for a newly generated key.
data.public_keystring (base64)The public key, base64-encoded.
data.created_atstring (ISO 8601)When the key was generated.

Example​

RequestPOST/api/v1/kms/keys/generate
X-API-Key: qph_your_key_here
Content-Type: application/json
{
  "algorithm": "Kyber768"
}
Response201
{
  "data": {
    "key_version": 1,
    "algorithm": "Kyber768",
    "status": "active",
    "public_key": "cHVibGljX2tleV9ieXRlcy4uLg==",
    "created_at": "2026-01-15T10:00:00.000Z"
  },
  "request_id": "e5f6a7b8-c9d0-1234-5678-90abcdef0123",
  "timestamp": "2026-01-15T10:00:00.000Z"
}
Generate key
curl -X POST https://api.qpher.ai/api/v1/kms/keys/generate \
  -H "X-API-Key: qph_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"algorithm": "Kyber768"}'

Errors​

HTTP StatusError CodeDescription
400ERR_INVALID_001Invalid request β€” unsupported algorithm or active key already exists (use Rotate instead).
401ERR_AUTH_001Missing or invalid API key.
429ERR_RATE_LIMIT_001Rate limit exceeded β€” reduce request frequency or upgrade your plan.

Rotate Key​

POST/api/v1/kms/keys/rotateRotate to a new key version, retiring the current active key.

Generates a new active key and moves the previous active key to retired status. Retired keys can still be used for decryption and signature verification but not for new encrypt or sign operations.

Request body​

FieldTypeRequiredDescription
algorithmstringYesThe PQC algorithm: "Kyber768", "Dilithium3", "X-Wing", or "Composite-ML-DSA".

Response (201 Created)​

FieldTypeDescription
data.public_keystring (base64)The public key of the new active key, base64-encoded.
data.key_versionintegerThe version number of the new active key.
data.algorithmstringThe algorithm used.
data.old_key_versionintegerThe version number of the previously active key (now retired).

Example​

RequestPOST/api/v1/kms/keys/rotate
X-API-Key: qph_your_key_here
Content-Type: application/json
{
  "algorithm": "Kyber768"
}
Response201
{
  "data": {
    "public_key": "bmV3X3B1YmxpY19rZXkuLi4=",
    "key_version": 2,
    "algorithm": "Kyber768",
    "old_key_version": 1
  },
  "request_id": "f6a7b8c9-d0e1-2345-6789-0abcdef01234",
  "timestamp": "2026-02-01T12:00:00.000Z"
}
Rotate key
curl -X POST https://api.qpher.ai/api/v1/kms/keys/rotate \
  -H "X-API-Key: qph_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"algorithm": "Kyber768"}'

Errors​

HTTP StatusError CodeDescription
400ERR_INVALID_001Invalid request β€” unsupported algorithm.
401ERR_AUTH_001Missing or invalid API key.
404ERR_NOT_FOUND_001No active key found for the specified algorithm. Generate one first.
429ERR_RATE_LIMIT_001Rate limit exceeded β€” reduce request frequency or upgrade your plan.

List Keys​

GET/api/v1/kms/keysList all PQC keys for the authenticated tenant.

Returns all keys for your tenant, optionally filtered by algorithm.

Query parameters​

ParameterTypeRequiredDescription
algorithmstringNoFilter by algorithm: "Kyber768", "Dilithium3", "X-Wing", or "Composite-ML-DSA".
statusstringNoFilter by status: "active", "retired", or "archived".

Response (200 OK)​

FieldTypeDescription
data.keysarrayArray of key objects.
data.keys[].key_versionintegerKey version number.
data.keys[].algorithmstring"Kyber768", "Dilithium3", "X-Wing", or "Composite-ML-DSA".
data.keys[].statusstring"active", "retired", or "archived".
data.keys[].public_keystring (base64)The public key, base64-encoded.
data.keys[].created_atstring (ISO 8601)When the key was generated.
data.totalintegerTotal number of keys returned.

Example​

RequestGET/api/v1/kms/keys?algorithm=Kyber768
X-API-Key: qph_your_key_here
Response200
{
  "data": {
    "keys": [
      {
        "key_version": 2,
        "algorithm": "Kyber768",
        "status": "active",
        "public_key": "bmV3X3B1YmxpY19rZXkuLi4=",
        "created_at": "2026-02-01T12:00:00.000Z"
      },
      {
        "key_version": 1,
        "algorithm": "Kyber768",
        "status": "retired",
        "public_key": "cHVibGljX2tleV9ieXRlcy4uLg==",
        "created_at": "2026-01-15T10:00:00.000Z"
      }
    ],
    "total": 2
  },
  "request_id": "a7b8c9d0-e1f2-3456-7890-abcdef012345",
  "timestamp": "2026-02-01T12:05:00.000Z"
}
List keys
curl -X GET "https://api.qpher.ai/api/v1/kms/keys?algorithm=Kyber768" \
  -H "X-API-Key: qph_your_key_here"

Errors​

HTTP StatusError CodeDescription
401ERR_AUTH_001Missing or invalid API key.
429ERR_RATE_LIMIT_001Rate limit exceeded β€” reduce request frequency or upgrade your plan.

Get Active Key​

GET/api/v1/kms/keys/activeGet the current active key for a specific algorithm.

Returns the single active key for the specified algorithm. Each algorithm has exactly one active key at any time.

Query parameters​

ParameterTypeRequiredDescription
algorithmstringYesThe algorithm: "Kyber768", "Dilithium3", "X-Wing", or "Composite-ML-DSA".

Response (200 OK)​

Same shape as a single key object from the list endpoint.

Example​

RequestGET/api/v1/kms/keys/active?algorithm=Dilithium3
X-API-Key: qph_your_key_here
Response200
{
  "data": {
    "key_version": 1,
    "algorithm": "Dilithium3",
    "status": "active",
    "public_key": "ZGlsaXRoaXVtX3B1YmxpY19rZXkuLi4=",
    "created_at": "2026-01-15T10:00:00.000Z"
  },
  "request_id": "b8c9d0e1-f2a3-4567-8901-bcdef0123456",
  "timestamp": "2026-01-15T10:05:00.000Z"
}

Errors​

HTTP StatusError CodeDescription
400ERR_INVALID_001Invalid or missing algorithm parameter.
401ERR_AUTH_001Missing or invalid API key.
404ERR_NOT_FOUND_001No active key found for the specified algorithm. Generate one first.
429ERR_RATE_LIMIT_001Rate limit exceeded β€” reduce request frequency or upgrade your plan.

Retire Key​

POST/api/v1/kms/keys/retireRetire a specific key version, preventing new encrypt/sign operations.

Moves a key from active to retired status. Retired keys can still be used for decryption and verification, but not for new encryption or signing.

Request body​

FieldTypeRequiredDescription
algorithmstringYesThe PQC algorithm: "Kyber768", "Dilithium3", "X-Wing", or "Composite-ML-DSA".
key_versionintegerYesThe key version to retire.

Response (200 OK)​

FieldTypeDescription
data.key_versionintegerThe retired key version.
data.algorithmstringThe algorithm.
data.statusstring"retired".
data.public_keystring (base64)The public key.
data.created_atstring (ISO 8601)Original creation time.

Example​

RequestPOST/api/v1/kms/keys/retire
X-API-Key: qph_your_key_here
Content-Type: application/json
{
  "algorithm": "Kyber768",
  "key_version": 1
}
Response200
{
  "data": {
    "key_version": 1,
    "algorithm": "Kyber768",
    "status": "retired",
    "public_key": "cHVibGljX2tleV9ieXRlcy4uLg==",
    "created_at": "2026-01-15T10:00:00.000Z"
  },
  "request_id": "c9d0e1f2-a3b4-5678-9012-cdef01234567",
  "timestamp": "2026-02-15T08:00:00.000Z"
}

Errors​

HTTP StatusError CodeDescription
400ERR_INVALID_001Invalid algorithm or key_version.
401ERR_AUTH_001Missing or invalid API key.
404ERR_NOT_FOUND_001Key version not found.
429ERR_RATE_LIMIT_001Rate limit exceeded β€” reduce request frequency or upgrade your plan.

Archive Key​

POST/api/v1/kms/keys/archiveArchive a retired key and securely delete the private key material.

Moves a key from retired to archived status and securely deletes the private key file. Archived keys cannot perform any cryptographic operations.

Irreversible operation

Archiving permanently deletes the private key. You will no longer be able to decrypt or verify with this key version.

Portal UI only

Key archival is only available through the Qpher Portal UI at portal.qpher.ai. API calls to this endpoint return 403 ERR_KMS_020. This restriction prevents accidental key destruction by scripts, SDKs, or AI agents.

Request body​

FieldTypeRequiredDescription
algorithmstringYesThe PQC algorithm: "Kyber768", "Dilithium3", "X-Wing", or "Composite-ML-DSA".
key_versionintegerYesThe version number of the retired key to archive.

Response (200 OK)​

Same shape as the key response from other endpoints.

Errors​

HTTP StatusError CodeDescription
400ERR_INVALID_001Invalid algorithm, key_version, or key is not in retired status.
401ERR_AUTH_001Missing or invalid API key.
403ERR_KMS_020Archive is restricted to Portal UI only. API and SDK calls are blocked.
404ERR_NOT_FOUND_001Key version not found.
429ERR_RATE_LIMIT_001Rate limit exceeded β€” reduce request frequency or upgrade your plan.

Get Key by Version​

GET/api/v1/kms/keys/{key_version}Retrieve metadata for a specific key version.

Returns key metadata (public key, status, algorithm) for a specific version. Useful for inspecting individual keys after rotation.

Path parameters​

ParameterTypeRequiredDescription
key_versionintegerYesThe key version number.

Query parameters​

ParameterTypeRequiredDescription
algorithmstringYesThe algorithm: "Kyber768", "Dilithium3", "X-Wing", or "Composite-ML-DSA".

Response (200 OK)​

Same shape as the key response from other endpoints.

Errors​

HTTP StatusError CodeDescription
401ERR_AUTH_001Missing or invalid API key.
404ERR_NOT_FOUND_001Key version not found for the specified algorithm.
429ERR_RATE_LIMIT_001Rate limit exceeded β€” reduce request frequency or upgrade your plan.

Key Lifecycle​

Keys move through three statuses during their lifetime:

ACTIVE ──rotate──► ACTIVE (new version)
β”‚ β”‚
β”‚ └─(old becomes)─► RETIRED ──archive──► ARCHIVED
β”‚
└──retire──► RETIRED ──archive──► ARCHIVED
StatusEncryptDecryptSignVerify
activeYesYesYesYes
retiredNoYesNoYes
archivedNoNoNoNo
Key rotation best practice

Rotate keys periodically (for example, every 90 days). After rotation, update your application to use the new key_version for encrypt and sign operations. Existing ciphertext and signatures remain valid with the retired key.