Skip to content

Zero-Knowledge Encryption API ​

Endpoints for managing encryption keys and storing/retrieving encrypted prompts and responses.

Authentication ​

Endpoint groupAuth methodHeader
Bootstrap, Shares, Company/Project settingsSession cookieCookie: next-auth.session-token=...
Encrypted Prompts, Encrypted ResponsesBearer API keyAuthorization: Bearer <api-key>

Key Bootstrap ​

POST /api/v1/pzk/bootstrap ​

Initialize, retrieve, or rotate encryption keys.

Auth: Session cookie

Request body:

json
{
  "action": "initialize",
  "repositoryIds": ["repo-id-1", "repo-id-2"],
  "clientPublicKey": "<base64-encoded-public-key>"
}
FieldTypeRequiredDescription
action"initialize" | "get" | "rotate"No (default: get)initialize creates new keys, get retrieves existing, rotate generates new versions
repositoryIdsstring[]NoSpecific repositories to bootstrap. Omit for company-level only.
clientPublicKeystringYesYour client's base64-encoded public key for key wrapping

Response (200):

json
{
  "keys": [
    {
      "keyId": "key-uuid",
      "encryptedKey": "<wrapped-key-material>",
      "algorithm": "AES-GCM",
      "expiresAt": "2026-06-05T12:00:00.000Z",
      "repositoryId": "repo-id-1",
      "serverPublicKey": "<base64-server-public-key>",
      "handshakeAlgorithm": "ECDH"
    }
  ],
  "action": "initialized"
}

The action field in the response reflects what was performed: "initialized", "retrieved", or "rotated".

GET /api/v1/pzk/bootstrap ​

Check zero-knowledge bootstrap status for the current company.

Auth: Session cookie

Response (200):

json
{
  "initialized": true,
  "companyKeyId": "key-ref-string",
  "repositoriesWithZK": 3,
  "enabled": true,
  "features": {
    "clientEncryption": true,
    "keyRotation": true,
    "secureSharing": true,
    "auditLogging": true
  }
}

Error responses:

StatusCondition
401Not authenticated
403Zero-knowledge not enabled for this company
400Missing clientPublicKey (POST only)
404No active company found

Encrypted Prompts ​

POST /api/v1/pzk/encrypted-prompts ​

Store a client-side encrypted prompt.

Auth: Authorization: Bearer <api-key>

Request body:

json
{
  "repositoryId": "repo-public-id",
  "encryptedUserPrompt": {
    "alg": "AES-GCM",
    "iv": "<base64-iv>",
    "ct": "<base64-ciphertext>",
    "tag": "<base64-tag>"
  },
  "encryptedSystemPrompt": {
    "alg": "AES-GCM",
    "iv": "<base64-iv>",
    "ct": "<base64-ciphertext>",
    "tag": "<base64-tag>"
  },
  "encryptedName": {
    "alg": "AES-GCM",
    "iv": "<base64-iv>",
    "ct": "<base64-ciphertext>",
    "tag": "<base64-tag>"
  },
  "name": "Fallback plaintext name",
  "encryptionAlg": "AES-GCM",
  "encryptionKeyRef": "key-uuid",
  "encryptedKeyMaterial": "<optional-wrapped-key>",
  "keySalt": "<optional-salt>",
  "promptHash": "<sha256-hex-of-plaintext>",
  "tags": ["production"],
  "category": "summarization",
  "branch": "main",
  "metadata": {}
}
FieldTypeRequiredDescription
repositoryIdstringYesPublic repository identifier
encryptedUserPromptobjectYesEncrypted user prompt {alg, iv, ct, tag?}
encryptedSystemPromptobjectNoEncrypted system prompt (same shape)
encryptedNameobjectNoEncrypted prompt name (same shape)
namestringNoPlaintext fallback name (prefer encryptedName)
encryptionAlgstringNo (default: AES-GCM)Encryption algorithm used
encryptionKeyRefstringYesKey ID used for encryption (from bootstrap)
encryptedKeyMaterialstringNoClient-wrapped key material
keySaltstringNoKey derivation salt
promptHashstringYesSHA-256 hex digest of the plaintext (min 32 chars)
tagsstring[]NoCategorization tags
categorystringNoPrompt category
branchstringNo (default: main)Version branch
metadataobjectNoAdditional metadata

Response (201):

json
{
  "ok": true,
  "prompt": {
    "id": "cuid",
    "promptId": "prompt_1709654321_abc12345",
    "name": "[ENCRYPTED]",
    "tags": ["production"],
    "category": "summarization",
    "createdAt": "2026-03-05T12:00:00.000Z",
    "encryptionAlg": "AES-GCM",
    "encryptionKeyRef": "key-uuid",
    "promptHash": "abc123...",
    "encryptedName": { "alg": "AES-GCM", "iv": "...", "ct": "...", "tag": "..." },
    "encryptedSystemPrompt": null,
    "encryptedUserPrompt": { "alg": "AES-GCM", "iv": "...", "ct": "...", "tag": "..." },
    "encryptionKeyId": "key-uuid",
    "repository": { "repositoryId": "repo-public-id", "name": "My Repo" },
    "metadata": { ... },
    "encryptedPayload": { ... }
  }
}

GET /api/v1/pzk/encrypted-prompts ​

Retrieve an encrypted prompt by its public prompt ID.

Auth: Authorization: Bearer <api-key>

Query parameters:

ParameterTypeRequiredDescription
promptIdstringYesThe public prompt ID (e.g. prompt_1709654321_abc12345)

Response (200):

json
{
  "ok": true,
  "prompt": {
    "id": "cuid",
    "promptId": "prompt_1709654321_abc12345",
    "tags": ["production"],
    "category": "summarization",
    "repository": { "repositoryId": "repo-public-id" },
    "createdAt": "2026-03-05T12:00:00.000Z",
    "promptHash": "abc123...",
    "encryptionAlg": "AES-GCM",
    "encryptionKeyRef": "key-uuid",
    "encryptedName": null,
    "encryptedSystemPrompt": null,
    "encryptedUserPrompt": { "alg": "AES-GCM", "iv": "...", "ct": "...", "tag": "..." },
    "metadata": { ... },
    "encryptedPayload": { ... }
  }
}

Encrypted Responses ​

POST /api/v1/pzk/encrypted-responses ​

Store an encrypted AI response with execution metadata.

Auth: Authorization: Bearer <api-key>

Request body:

json
{
  "executionId": "exec-uuid",
  "promptId": "prompt_1709654321_abc12345",
  "provider": "openai",
  "model": "gpt-4",
  "inputTokens": 150,
  "outputTokens": 300,
  "totalTokens": 450,
  "costCents": 12,
  "executionTime": 2500,
  "encryptionAlg": "AES-GCM",
  "encryptedContent": {
    "alg": "AES-GCM",
    "iv": "<base64-iv>",
    "ct": "<base64-ciphertext>",
    "tag": "<base64-tag>"
  },
  "encryptionKeyRef": "key-uuid",
  "keySalt": "<optional-salt>"
}
FieldTypeRequiredDescription
executionIdstringYesUnique execution identifier
promptIdstringNoAssociated prompt's public ID
providerstringYesAI provider name
modelstringYesModel identifier
inputTokensintegerYesInput token count
outputTokensintegerYesOutput token count
totalTokensintegerYesTotal token count
costCentsintegerYesCost in cents
executionTimeintegerYesExecution time in milliseconds
encryptionAlgstringNo (default: AES-GCM)Encryption algorithm
encryptedContentobjectYesEncrypted response {alg, iv, ct, tag?}
encryptionKeyRefstringYesKey ID used for encryption
keySaltstringNoKey derivation salt

Response (201):

json
{
  "ok": true,
  "response": {
    "executionId": "exec-uuid",
    "promptId": "prompt_1709654321_abc12345",
    "createdAt": "2026-03-05T12:00:00.000Z"
  }
}

Key Sharing ​

GET /api/v1/pzk/shares ​

List encryption key shares.

Auth: Session cookie

Query parameters:

ParameterTypeDefaultDescription
role"granted" | "received"receivedView shares you granted or received
statusstringactiveFilter by share status

Response (200):

json
{
  "shares": [
    {
      "id": "share-uuid",
      "encryptionKeyId": "key-uuid",
      "recipientUserId": "user-uuid",
      "grantedByUserId": "user-uuid",
      "scope": "read",
      "envelope": { ... },
      "status": "active",
      "expiresAt": "2026-12-31T23:59:59.000Z",
      "createdAt": "2026-03-05T12:00:00.000Z",
      "updatedAt": "2026-03-05T12:00:00.000Z",
      "notes": "Sharing for Q1 review",
      "encryptionKey": {
        "id": "key-uuid",
        "keyRef": "key-ref-string",
        "companyId": "company-uuid",
        "repositoryId": "repo-uuid",
        "isActive": true,
        "createdAt": "2026-01-01T00:00:00.000Z"
      },
      "grantedBy": {
        "id": "user-uuid",
        "email": "alice@example.com",
        "firstName": "Alice",
        "lastName": "Smith"
      },
      "recipient": {
        "id": "user-uuid",
        "email": "bob@example.com",
        "firstName": "Bob",
        "lastName": "Jones"
      }
    }
  ]
}

POST /api/v1/pzk/shares ​

Share an encryption key with a team member.

Auth: Session cookie

Request body:

json
{
  "encryptionKeyId": "key-uuid",
  "recipientUserId": "user-uuid",
  "scope": "read",
  "envelope": { ... },
  "expiresAt": "2026-12-31T23:59:59Z",
  "notes": "Sharing for Q1 review"
}
FieldTypeRequiredDescription
encryptionKeyIdstringYesID of the encryption key to share
recipientUserIdstringYesTarget user ID
scopestringNo (default: read)Access scope
envelopeanyNoPre-wrapped key envelope. If omitted, server wraps using recipient's public key.
expiresAtISO 8601 stringNoExpiration date
notesstringNoOptional note (max 500 chars)

Response (201):

json
{
  "share": {
    "id": "share-uuid",
    "encryptionKeyId": "key-uuid",
    "recipientUserId": "user-uuid",
    "grantedByUserId": "user-uuid",
    "scope": "read",
    "envelope": { ... },
    "status": "active",
    "expiresAt": "2026-12-31T23:59:59.000Z",
    "createdAt": "2026-03-05T12:00:00.000Z",
    "updatedAt": "2026-03-05T12:00:00.000Z",
    "notes": "Sharing for Q1 review",
    "encryptionKey": { ... },
    "grantedBy": { ... },
    "recipient": { ... }
  }
}

Error responses:

StatusCondition
404Key not found, inactive, or recipient not found
403Caller is not a member of the key's company
422No envelope provided and recipient has no registered public key

Company ZK Settings ​

GET /api/v1/zero-knowledge/company ​

Get zero-knowledge status for the current company.

Auth: Session cookie (Account Owner, Admin, or Super Admin)

Response (200):

json
{
  "companyId": "company-uuid",
  "globalEnabled": true,
  "zeroKnowledgeEnabled": true
}

PUT /api/v1/zero-knowledge/company ​

Enable or disable zero-knowledge encryption.

Auth: Session cookie (Account Owner, Admin, or Super Admin)

Request body:

json
{
  "enabled": true
}

Project ZK Settings ​

GET /api/v1/zero-knowledge/projects/{projectId} ​

Get zero-knowledge status for a specific project.

Auth: Session cookie

PUT /api/v1/zero-knowledge/projects/{projectId} ​

Enable or disable zero-knowledge for a project.

Auth: Session cookie (requires project edit permissions)

Request body:

json
{
  "enabled": true
}

Dual-Mode Prompt API ​

POST /api/v1/prompts/zk ​

Store a prompt in either encrypted or plaintext mode depending on the company's ZK setting.

Auth: Session cookie or API key

When ZK is enabled, the endpoint expects encrypted fields. When disabled, it works as a standard prompt storage endpoint.


Encrypted Object Format ​

All encrypted fields use a consistent structure:

json
{
  "alg": "AES-GCM",
  "iv": "<base64-encoded-12-byte-IV>",
  "ct": "<base64-encoded-ciphertext>",
  "tag": "<base64-encoded-16-byte-auth-tag>"
}
FieldDescription
algAlgorithm identifier (currently AES-GCM)
ivBase64-encoded initialization vector (12 bytes / 96 bits)
ctBase64-encoded ciphertext
tagBase64-encoded authentication tag (16 bytes / 128 bits). Optional if tag is appended to ct.

Error Codes ​

StatusCodeMeaning
401Invalid or missing API keyBearer token invalid or not provided
403Zero-knowledge is disabledZK not enabled at company or project level
400invalid_requestZod validation failed (details in response)
400clientPublicKey is requiredBootstrap requires client public key
404Not found / Repository not foundResource does not exist or not in caller's company
422Recipient is missing encryption public keyCannot auto-wrap key without recipient's public key
503api_auth_unavailableExternal API auth service temporarily unavailable