VaultProof Documentation

Everything you need to store, protect, and proxy your API keys with zero-knowledge security.

What is VaultProof?

VaultProof is a security layer for API keys. It splits your keys using Shamir Secret Sharing, encrypts the shares separately, and reassembles them only for the milliseconds it takes to make a proxied API call. Your raw API key is never stored whole on any server.

It is built for developers who work with third-party API keys -- OpenAI, Anthropic, Google AI, Together.ai, and more. If you have ever committed a key to GitHub, emailed a key to a teammate, or stored a key in plaintext in a .env file on a server, VaultProof solves that problem.

The problem is real: In 2024, GitHub detected 39 million leaked secrets in public repositories. API keys are the number one attack vector for credential theft. One leaked OpenAI key can cost you thousands of dollars in minutes.

Store

Split and encrypt API keys with Shamir Secret Sharing. No one -- including us -- can see the full key.

Proxy

Make API calls through VaultProof. The key is reconstructed in memory for ~100ms, then destroyed.

Audit

Every proxied call is logged with timestamp, endpoint, status code, and latency. Full audit trail.

Quick Start

Three ways to get started. Pick the one that fits your workflow.

RECOMMENDED

Path A: SDK (for applications)

terminal
npm install @vaultproof/sdk
app.js
import VaultProof from '@vaultproof/sdk'

// Initialize with your developer API key
const vault = new VaultProof(process.env.VAULTPROOF_API_KEY)

// Store an API key (split + encrypted automatically)
const key = await vault.store('sk-openai-key-here', 'openai', 'Production')

// Make a proxied API call (key reconstructed for ~100ms, then zeroed)
const res = await vault.proxy(key.id, '/v1/chat/completions', {
  model: 'gpt-4',
  messages: [{ role: 'user', content: 'Hello!' }]
})

Path B: CLI (for terminal and CI/CD)

terminal
npm install -g @vaultproof/cli
terminal
# Authenticate
vaultproof login

# Store a key (you'll be prompted to paste it securely)
vaultproof store --provider openai --label "Production"

# Make a proxied API call
vaultproof proxy --key KEY_ID --path /v1/models --method GET

Path C: Dashboard (for manual management)

  1. Go to vaultproof.dev/app and create an account or log in
  2. Navigate to Keys and click Add Key
  3. Paste your API key, select the provider, and add a label
  4. Click Test Key to verify it works through the proxy
  5. Go to Settings → API Keys to create a vp_live_ developer key for SDK use

How It Works

A deep dive into the cryptographic pipeline that protects your keys.

3.1 Key Storage Flow

When you call vault.store(), here is exactly what happens:

You provide the raw API key

You call vault.store('sk-openai-key', 'openai', 'Production'). The SDK receives the raw key in local memory.

Shamir Secret Sharing splits the key

The SDK uses Shamir Secret Sharing over GF(256) with polynomial interpolation to split the key into exactly 2 shares. Each share alone is cryptographic garbage -- indistinguishable from random bytes. Neither share reveals any information about the original key.

Share 1 is encrypted with the server key

Share 1 is sent to the VaultProof server, where it is encrypted with AES-256-GCM using the server-side VAULT_ENCRYPTION_KEY. A unique IV and salt are generated per encryption. The ciphertext and auth tag are stored in PostgreSQL.

Share 2 is encrypted with your developer key

Share 2 is encrypted with AES-256-GCM using a key derived from your vp_live_ developer API key. This encrypted share is also stored server-side, but it cannot be decrypted without your developer key.

Raw key is destroyed

The original API key is zeroed from memory immediately after splitting. It never leaves your machine whole. From this point forward, the key only exists as two separately encrypted shares.

Key slot ID returned

The server returns a keyId (UUID). You use this ID for all future proxy calls. The SDK caches Share 2 locally for subsequent requests.

Key point: At no point does the VaultProof server possess enough information to reconstruct your API key on its own. The server holds encrypted Share 1 (locked with the server key) and encrypted Share 2 (locked with your developer key). Both decryption keys are needed.

3.2 Proxy Call Flow

When you call vault.proxy(), the key is temporarily reconstructed to make the API call on your behalf:

You initiate the proxy call

You call vault.proxy(keyId, '/v1/chat/completions', body). The SDK sends your developer key in the X-API-Key header over HTTPS.

Edge proxy validates and forwards

The request hits Cloudflare's edge network. The edge worker HMAC-signs the request with HMAC-SHA256 and forwards it to the backend. Unsigned or rate-limited requests are rejected at the edge.

Server decrypts Share 1

The backend retrieves the encrypted Share 1 from PostgreSQL and decrypts it using VAULT_ENCRYPTION_KEY with AES-256-GCM. The auth tag is verified to detect tampering.

Server decrypts Share 2

The backend decrypts Share 2 using a key derived from your vp_live_ developer key (sent in the request header). Both shares are now in plaintext in server RAM.

Shamir reconstruction

The two shares are combined via Shamir polynomial interpolation to reconstruct the original API key. The full key now exists in RAM.

API call made to provider

The server makes the HTTP request to the provider (OpenAI, Anthropic, etc.) using the reconstructed key in the appropriate auth header. Streaming (SSE) is supported for LLM APIs.

Key zeroed from memory

Immediately after the API call completes, the reconstructed key and both plaintext shares are overwritten with zeros in memory. The key existed in RAM for approximately 100ms. It never touches disk, logs, or persistent storage.

Response forwarded to you

The provider's response is forwarded directly to your application. For streaming responses, SSE events are piped through in real time.

Access logged

The call is logged with: timestamp, endpoint path, HTTP method, response status code, latency (ms), provider, and key ID. The request/response body is never logged.

3.3 What Happens in a Breach

VaultProof is designed so that compromising any single component does not expose your API keys. Here is what an attacker gets in each scenario:

Scenario What Attacker Gets Can They Reconstruct Keys?
Database breached Two encrypted blobs per key (AES-256-GCM ciphertext). Without either decryption key, this is indistinguishable from random data. No
VAULT_ENCRYPTION_KEY leaked Can decrypt Share 1. But Share 2 is still encrypted with the user's vp_live_ key. One share alone reveals nothing (Shamir property). No
vp_live_ key leaked Can decrypt Share 2. But Share 1 is still encrypted with VAULT_ENCRYPTION_KEY. One share alone reveals nothing. No
Database + VAULT_ENCRYPTION_KEY Decrypted Share 1. Encrypted Share 2 (still locked). No
Database + vp_live_ key Encrypted Share 1 (still locked). Decrypted Share 2. No
All three compromised Both shares decrypted. Shamir reconstruction possible. Yes -- requires all three

Three independent secrets must all be compromised simultaneously to reconstruct any API key: (1) the database contents, (2) the server-side VAULT_ENCRYPTION_KEY, and (3) the user's vp_live_ developer key. These are stored in different systems with different access controls.

3.4 Shamir Secret Sharing Explained

The simple version

Think of it like tearing a photo in half. Each half looks like random noise -- you cannot tell what the photo is from either piece alone. Only when you put both halves together do you see the picture. VaultProof tears your API key into two pieces of cryptographic noise. Each piece is then locked in a separate safe with a separate key. To see the photo again, you need to open both safes.

The technical version

Shamir Secret Sharing (SSS) works over a finite field -- in VaultProof's case, GF(256) (the Galois Field with 256 elements, where each element fits in one byte).

For each byte of the secret, the algorithm constructs a random polynomial of degree k-1 (where k=2 is the threshold). The constant term of the polynomial is the secret byte. The shares are evaluations of this polynomial at distinct non-zero points in GF(256).

With a 2-of-2 threshold scheme, this means: a random polynomial f(x) = a1*x + s is constructed for each byte s of the key, where a1 is a random coefficient. Share 1 = f(1), Share 2 = f(2). Given only one share, the attacker has one equation with two unknowns -- every possible value of the secret is equally likely.

Reconstruction uses Lagrange interpolation over GF(256) to recover the original polynomial from 2 evaluation points, then reads the constant term (the secret byte).

3.5 Zero-Knowledge Proofs

For advanced security, VaultProof uses zero-knowledge proofs (ZK proofs) written in Noir and verified with Barretenberg. The ZK circuit proves three things without revealing any sensitive data:

1. Ownership

You own the key slot you are requesting access to. The proof verifies your vault commitment hash matches without revealing the key material.

2. Authorization

The requesting application has been granted access to this key slot. The proof checks the app grant without exposing the grant chain.

3. Freshness

The request is fresh and not replayed. Each proof includes a unique nullifier that is stored server-side. If the same nullifier appears twice, the request is rejected.

Note: When using the SDK, ZK proof generation is handled automatically. You do not need to interact with the Noir circuit directly. The SDK generates proofs client-side before each proxy call.

SDK Reference

The JavaScript/TypeScript SDK for storing keys and making proxied API calls.

Installation

terminal
npm install @vaultproof/sdk
# or
yarn add @vaultproof/sdk
# or
pnpm add @vaultproof/sdk

Constructor

new VaultProof(apiKey: string, apiUrl?: string)
ParameterTypeRequiredDescription
apiKey string Yes Your vp_live_ or vp_test_ developer API key
apiUrl string No Custom API URL. Default: https://api.vaultproof.dev
example
import VaultProof from '@vaultproof/sdk'

// Production
const vault = new VaultProof(process.env.VAULTPROOF_API_KEY)

// Custom API URL (self-hosted or staging)
const vault = new VaultProof('vp_test_...', 'https://staging-api.vaultproof.dev')

Methods

vault.store(apiKey, provider, label?)

Splits an API key using Shamir Secret Sharing, encrypts both shares, and stores them on the VaultProof server. The raw key is destroyed after splitting.

ParameterTypeRequiredDescription
apiKey string Yes The raw API key to store
provider string Yes 'openai' | 'anthropic' | 'google' | 'together'
label string No Friendly name (e.g., "Production", "Staging")

Returns:

{ id: "uuid", provider: "openai", label: "Production" }

vault.proxy(keyId, path, body?, method?)

Makes a proxied API call through VaultProof. The key is reconstructed in server RAM for approximately 100ms, then zeroed. The provider's response is returned directly.

ParameterTypeRequiredDescription
keyId string Yes Key slot ID returned from store()
path string Yes API endpoint path (e.g., '/v1/chat/completions')
body object No Request body forwarded to the provider
method string No HTTP method. Default: 'POST'

Returns:

{ status: 200, data: { /* provider response */ }, ok: true }

vault.keys()

Lists all stored keys associated with your developer API key.

Returns:

[
  { id: "uuid", provider: "openai", label: "Production", createdAt: "2026-03-24T..." },
  { id: "uuid", provider: "anthropic", label: "Staging", createdAt: "2026-03-22T..." }
]

vault.revoke(keyId)

Permanently destroys both encrypted shares on the server. This is irreversible. The key can never be reconstructed after revocation.

ParameterTypeRequiredDescription
keyId string Yes Key slot ID to revoke

Returns: void

Supported Providers

ProviderValueBase URLAuth Header
OpenAI 'openai' api.openai.com Authorization: Bearer
Anthropic 'anthropic' api.anthropic.com x-api-key
Google AI 'google' generativelanguage.googleapis.com x-goog-api-key
Together.ai 'together' api.together.xyz Authorization: Bearer

CLI Reference

Command-line tool for managing keys from your terminal or CI/CD pipelines.

Installation

terminal
npm install -g @vaultproof/cli

Global Flags

FlagDescription
-h, --helpShow help for any command
-v, --versionShow CLI version
--jsonOutput results as JSON (works on all list commands)
--api-url <url>Override API URL for this command
examples
$ vaultproof -h                  # overview + quick start guide
$ vaultproof store -h            # detailed help for store command
$ vaultproof keys --json | jq    # pipe JSON output to jq

Authentication

vaultproof login alias: l

Log in to your VaultProof account. Stores JWT token at ~/.vaultproof/config.json. Token expires after 7 days.

FlagDescription
-e, --email <email>Email address (skips prompt)
examples
$ vaultproof login
$ vaultproof login -e you@example.com
$ vaultproof l
vaultproof logout

Log out and clear stored credentials from ~/.vaultproof/config.json. Does not affect your VAULTPROOF_API_KEY env var.

vaultproof register alias: signup

Create a new VaultProof account. Password must be at least 8 characters. Automatically logs you in after registration.

FlagDescription
-e, --email <email>Email address (skips prompt)
vaultproof whoami alias: me

Display the currently authenticated user's email and creation date.

vaultproof status alias: st

Check connection, authentication, and API key status at a glance.

example output
$ vaultproof status

VaultProof Status

API: https://api.vaultproof.dev (vaultproof-edge)
  Auth:    Logged in as you@example.com
  API Key: vp_live_abc1...ef89
  Config:  ~/.vaultproof/config.json

Key Management

vaultproof store alias: add

Store an API key with Shamir splitting. The key is split locally -- the server never sees the full key.

FlagDescriptionRequired
-p, --provider <name>API provider (openai, anthropic, google, etc.)Yes
-l, --label <text>Label for this keyNo
examples
$ vaultproof store -p openai
API Key: ************************
Key stored: vk_8f3a2b1c (openai)
  Key was Shamir-split locally. Server never saw the full key.

$ vaultproof store -p anthropic -l "Production Claude"
$ vaultproof add -p google -l "Vertex AI"
vaultproof keys alias: ls

List all stored API keys with provider, label, and creation date.

FlagDescription
--jsonOutput as JSON for scripting
examples
$ vaultproof keys
ID          Provider      Label                   Created
------------------------------------------------------------
vk_8f3a2b   openai        Production GPT-4        2d ago
vk_c91ef4   anthropic     Claude Sonnet           5h ago

2 keys total

$ vaultproof keys --json | jq '.[].provider'
vaultproof revoke <keyId> alias: rm

Permanently revoke a key. Both encrypted shares are zeroed on the server. This cannot be undone.

FlagDescription
-y, --yesSkip confirmation prompt
examples
$ vaultproof revoke vk_8f3a2b1c
Permanently revoke key vk_8f3a2b1c? This cannot be undone. (y/N) y
Key vk_8f3a2b1c revoked. Both shares destroyed.

$ vaultproof rm vk_8f3a2b1c -y    # skip confirmation

Proxy Calls

vaultproof proxy alias: call

Make a proxied API call. The server decrypts both shares, reconstructs the key for ~100ms, makes the call, then zeros everything.

FlagDescriptionRequired
-k, --key <keyId>Key ID from vaultproof keysYes
--path <path>API path (e.g., /v1/chat/completions)Yes
-m, --method <method>HTTP method (default: POST)No
-d, --body <json>Request body as JSON stringNo
-f, --file <path>Read request body from a JSON fileNo
examples
# GET request
$ vaultproof proxy -k vk_8f3a2b1c --path /v1/models -m GET

# POST with inline JSON body
$ vaultproof proxy -k vk_8f3a2b1c --path /v1/chat/completions \
  -d '{"model":"gpt-4","messages":[{"role":"user","content":"Hello"}]}'

# POST with body from file
$ vaultproof proxy -k vk_8f3a2b1c --path /v1/chat/completions -f request.json

# Using the alias
$ vaultproof call -k vk_8f3a2b1c --path /v1/models -m GET

Access Logs

vaultproof logs

View recent access logs for all proxied API calls.

FlagDescriptionDefault
-k, --key <keyId>Filter by key IDAll keys
-n, --limit <n>Number of entries20
--jsonOutput as JSON--
examples
$ vaultproof logs
$ vaultproof logs -n 50
$ vaultproof logs -k vk_8f3a2b1c
$ vaultproof logs --json | jq '.[] | .endpoint'

Developer API Keys

Developer keys (vp_live_ / vp_test_) authenticate your SDK and CLI requests. They are different from the API keys you store in the vault.

vaultproof dev-key create parent alias: dk

Create a new developer API key. The full key is shown once -- save it immediately.

FlagDescriptionDefault
-l, --label <text>Label for this key"default"
-m, --mode <mode>live or testlive
examples
$ vaultproof dev-key create
Developer API key created:
  vp_live_a8Kj3mNp9xRt2wQz7vBc...

  Save this key -- you won't see it again!

Write to .env file in current directory? (y/N) y
  Written to .env

$ vaultproof dk create -l "CI/CD" -m test
$ vaultproof dk create -l "Production" -m live
vaultproof dev-key list alias: dk ls

List all developer API keys (masked).

FlagDescription
--jsonOutput as JSON
vaultproof dev-key revoke <id>

Revoke a developer API key. All SDK/CLI calls using this key will immediately stop working.

FlagDescription
-y, --yesSkip confirmation prompt

Configuration

vaultproof config

Show current CLI configuration: API URL, auth status, developer key, and config file path.

vaultproof config set <key> <value>

Update a config value.

examples
$ vaultproof config set api-url https://api.vaultproof.dev
$ vaultproof config set api-url http://localhost:3333
vaultproof config reset

Clear all configuration (token, email, preferences). Asks for confirmation.

Environment Variables

VariableDescriptionDefault
VAULTPROOF_API_KEY Developer API key -- required for store, keys, proxy, revoke, and logs commands --
VAULTPROOF_API_URL Custom API base URL (overrides config file and default) https://api.vaultproof.dev
quick start
# 1. Create an account and log in
$ vaultproof register
$ vaultproof login

# 2. Create a developer API key
$ vaultproof dev-key create
# writes VAULTPROOF_API_KEY to .env

# 3. Load the env var
$ export VAULTPROOF_API_KEY=vp_live_...

# 4. Store an API key
$ vaultproof store -p openai -l "GPT-4 Production"

# 5. Make proxied calls
$ vaultproof proxy -k vk_8f3a --path /v1/models -m GET

# 6. Check everything is working
$ vaultproof status

Dashboard

Web interface for managing keys, viewing logs, and monitoring usage at vaultproof.dev/app.

Overview Page

Your home screen after login. At a glance you see:

  • Total keys stored -- active key count across all providers
  • API calls this month -- total proxied requests with trend indicator
  • Usage chart -- daily call volume for the past 30 days
  • Key health -- per-key error rates and last-used timestamps
  • Recent activity -- last 10 proxy calls with status

Keys Page

Full key management interface:

  • Add Key -- paste a key, select provider, add a label. Shamir splitting happens in-browser.
  • Test Key -- one-click test that makes a lightweight proxy call to verify the key works.
  • Rotate -- replace the stored shares with a new API key without changing the key slot ID.
  • Revoke -- permanently destroy both shares. Irreversible.
  • Code snippets -- copy-paste SDK and cURL examples for each key.

Logs Page

Complete audit trail of every proxied API call:

  • Search -- filter by key, provider, status code, date range
  • Details -- timestamp, endpoint, method, status, latency (ms)
  • Export CSV -- download logs for external analysis or compliance

Settings Page

Account and security configuration:

  • Profile -- email and account details
  • Password -- change password (requires current password)
  • Developer API Keys -- create, list, and revoke vp_live_ keys
  • Plan -- view current tier (Free/Pro/Team/Enterprise) and usage limits

API Reference

Base URL: https://api.vaultproof.dev

All requests go through Cloudflare's edge network (330+ cities). HMAC-signed and rate-limited. All request and response bodies are JSON (Content-Type: application/json).

Authentication

POST /api/v1/auth/register

Create a new account.

// Request
{ "email": "you@example.com", "password": "min8chars" }

// Response (200)
{ "token": "eyJ...", "user": { "id": "uuid", "email": "you@example.com" } }

// Error (409)
{ "error": "Email already registered" }
POST /api/v1/auth/login

Login and receive a JWT token (valid 7 days).

// Request
{ "email": "you@example.com", "password": "yourpass" }

// Response (200)
{ "token": "eyJ...", "user": { "id": "uuid", "email": "you@example.com" } }

// Error (401)
{ "error": "Invalid credentials" }
GET /api/v1/auth/me Auth required

Get current user profile.

// Headers
Authorization: Bearer <jwt_token>

// Response (200)
{ "id": "uuid", "email": "you@example.com", "plan": "free", "createdAt": "..." }
POST /api/v1/auth/password Auth required

Change password.

// Request
{ "currentPassword": "oldpass", "newPassword": "newpass8+" }

// Response (200)
{ "status": "updated" }
DELETE /api/v1/auth/account Auth required

Delete account and all stored keys. Irreversible.

Key Management

All key endpoints require Authorization: Bearer <jwt>.

POST /api/v1/keys/store

Store a Shamir-split API key.

// Request
{
  "provider": "openai",
  "label": "Production GPT-4",
  "share1": "base64...",            // Shamir Share 1
  "vaultCommitment": "hex...",    // Hash commitment for ZK
  "appId": "my-app",               // optional
  "appName": "My App"              // optional
}

// Response (201)
{ "keySlotId": "uuid", "grantId": "uuid", "status": "stored" }
GET /api/v1/keys/list

List all keys with app grants.

// Response (200)
{
  "keySlots": [{
    "id": "uuid",
    "provider": "openai",
    "label": "Production GPT-4",
    "status": "ACTIVE",
    "createdAt": "2026-03-24T...",
    "appGrants": [{ "id": "uuid", "appId": "my-app", "appName": "My App" }]
  }]
}
POST /api/v1/keys/revoke/:keySlotId

Revoke a key. Destroys Share 1 (zeroed in DB). Irreversible.

POST /api/v1/keys/:keySlotId/grant

Grant an application access to a key slot.

// Request
{ "appId": "new-app", "appName": "New App" }

// Response (201)
{ "grantId": "uuid", "status": "granted" }
POST /api/v1/keys/:keySlotId/revoke-app

Revoke an application's access to a key slot.

// Request
{ "appId": "old-app" }

// Response (200)
{ "status": "revoked" }
GET /api/v1/keys/:keySlotId/logs

Get access logs for a specific key.

// Query params: ?page=1&limit=50

// Response (200)
{
  "logs": [{
    "id": "uuid",
    "endpoint": "/v1/chat/completions",
    "method": "POST",
    "statusCode": 200,
    "latencyMs": 847,
    "createdAt": "2026-03-24T..."
  }],
  "total": 1284,
  "page": 1
}
POST /api/v1/keys/:keySlotId/rotate

Rotate the stored shares with a new API key. The key slot ID stays the same.

// Request
{
  "share1": "base64...",           // new Shamir Share 1
  "vaultCommitment": "hex..."   // new commitment
}

// Response (200)
{ "status": "rotated" }
GET /api/v1/keys/:keySlotId/logs/export

Export access logs as CSV for compliance and external analysis.

SDK Endpoints

Authenticated with X-API-Key: vp_live_... header.

POST /api/v1/sdk/store

Store an API key via the SDK. The server handles Shamir splitting and encryption.

// Request
{
  "apiKey": "sk-...",
  "provider": "openai",
  "label": "Production"
}

// Response (201)
{ "keyId": "uuid", "status": "stored" }
POST /api/v1/sdk/call

Make a proxied API call. Key is reconstructed ephemerally.

// Request
{
  "keyId": "uuid",
  "share2": "base64...",
  "path": "/v1/chat/completions",
  "method": "POST",
  "body": { "model": "gpt-4", "messages": [...] }
}

// Response: provider's response forwarded directly
GET /api/v1/sdk/keys

List all stored keys for this developer API key.

POST /api/v1/sdk/revoke

Revoke a stored key.

// Request
{ "keyId": "uuid" }

// Response (200)
{ "status": "revoked" }

Developer Key Management

Authenticated with Authorization: Bearer <jwt>.

POST /api/v1/dev-keys/create

Create a new developer API key.

// Request
{ "label": "Production", "mode": "live" }

// Response (201) -- key shown ONCE
{
  "id": "uuid",
  "key": "vp_live_abc123...",
  "label": "Production",
  "createdAt": "2026-03-24T..."
}
GET /api/v1/dev-keys/list

List all developer API keys (masked).

// Response (200)
{
  "keys": [{
    "id": "uuid",
    "maskedKey": "vp_live_abc1...f456",
    "label": "Production",
    "lastUsedAt": "2026-03-24T...",
    "createdAt": "2026-03-24T..."
  }]
}
POST /api/v1/dev-keys/:id/revoke

Revoke a developer API key. All SDK calls using this key stop working immediately.

Proxy

POST /api/v1/proxy/call

Make a proxied API call with ZK proof authorization. Supports SSE streaming.

// Request
{
  "keySlotId": "uuid",
  "share2": "base64...",
  "zkProof": "hex...",
  "nullifier": "hex...",           // unique per request
  "appId": "my-app",
  "targetPath": "/v1/chat/completions",
  "method": "POST",
  "stream": false,
  "body": {
    "model": "gpt-4",
    "messages": [{ "role": "user", "content": "Hello!" }]
  }
}

// Response: provider's response forwarded directly
// If stream: true, SSE events are piped through

Note: The SDK handles ZK proof generation, nullifier creation, and Share 2 management automatically. You only need to use this endpoint directly if you are building a custom client.

Stats & Analytics

Authenticated with Authorization: Bearer <jwt>.

GET /api/v1/stats/overview

Dashboard overview stats.

// Response (200)
{
  "totalKeys": 5,
  "callsThisMonth": 1284,
  "errorRate": 0.02,
  "activeApps": 3,
  "recentActivity": [...]
}
GET /api/v1/stats/usage?days=30

Daily call volume for charting.

// Response (200)
{
  "usage": [
    { "date": "2026-03-24", "calls": 47 },
    { "date": "2026-03-23", "calls": 62 },
    ...
  ]
}
GET /api/v1/stats/by-key

Per-key usage breakdown.

// Response (200)
{
  "keys": [{
    "keyId": "uuid",
    "provider": "openai",
    "label": "Production",
    "totalCalls": 892,
    "errors": 12,
    "lastUsedAt": "2026-03-24T..."
  }]
}

Error Codes

CodeMeaningCommon Cause
400 Bad Request Missing or invalid fields in the request body
401 Unauthorized Missing, expired, or invalid JWT / API key
403 Forbidden ZK proof verification failed, app not authorized, or nullifier replayed
404 Not Found Key slot ID does not exist or has been revoked
409 Conflict Email already registered, duplicate nullifier
429 Too Many Requests Rate limit exceeded (60/min edge, 100/min backend)
500 Internal Server Error Server-side failure. Contact support.
502 Bad Gateway Provider API returned an error during proxy call

All error responses follow the format: { "error": "Human-readable message" }

Security Architecture

Eight layers of defense between your API keys and an attacker.

L1

Shamir Secret Sharing

API keys are split into 2 shares using polynomial interpolation over GF(256). Each share alone is information-theoretically secure -- no amount of computation can extract the secret from a single share. This is not encryption (which can be brute-forced); it is mathematically impossible.

L2

AES-256-GCM -- Share 1 Encryption

Share 1 is encrypted at rest with AES-256-GCM using the server-side VAULT_ENCRYPTION_KEY. Each encryption uses a unique random IV and salt. The GCM auth tag detects any tampering with the ciphertext.

L3

AES-256-GCM -- Share 2 Encryption

Share 2 is encrypted with AES-256-GCM using a key derived from the user's vp_live_ developer key. This means even with full server access, Share 2 cannot be decrypted without the user's key.

L4

HMAC-SHA256 Edge Signing

All requests are HMAC-SHA256 signed at Cloudflare's edge network before reaching the backend. The backend rejects any request without a valid HMAC signature. Direct access to the backend is blocked -- all traffic must flow through the edge.

L5

JWT Authentication

User sessions use JWT tokens with 7-day expiry. Developer API keys (vp_live_) are hashed with bcrypt and stored in the database. The raw key is never stored.

L6

Nullifier Replay Prevention

Every proxy call requires a unique nullifier (a random hex string). Used nullifiers are stored in the database. If an attacker intercepts a request and tries to replay it, the server rejects it because the nullifier has already been consumed.

L7

Rate Limiting

Two layers of rate limiting: 60 requests/minute per IP at the Cloudflare edge, and 100 requests/minute per user at the backend. Brute-force and DDoS attempts are throttled before they reach the application.

L8

Noir ZK Proofs

Zero-knowledge proofs (written in Noir, verified with Barretenberg) cryptographically prove key ownership, app authorization, and request freshness without revealing any sensitive data. Proof verification happens on every proxy call.

Memory Zeroing

After every proxy call, the reconstructed API key and both plaintext shares are explicitly overwritten with zero bytes in memory. The key exists in server RAM for approximately 100ms. It is never written to disk, swap, or logs.

TLS Everywhere

All traffic between the client, Cloudflare edge, and backend uses TLS 1.3. All traffic between the backend and API providers uses TLS. No plaintext transmission anywhere in the pipeline.

Plan Limits

TierPriceKey SlotsProxied Calls/moSupport
Free $0 3 1,000 Community
Pro $12/mo 20 50,000 Email
Team $39/mo 100 200,000 Priority
Enterprise Custom Unlimited Unlimited Dedicated

Frequently Asked Questions

Common questions from developers evaluating VaultProof.

"Can VaultProof see my API keys?"

No -- and this is by design, not by policy. Your API key is split into two shares using Shamir Secret Sharing before it is stored. Share 1 is encrypted with a server-side key. Share 2 is encrypted with your developer key. Neither share alone contains any information about the original key (this is an information-theoretic guarantee, not a computational one). The only time the full key exists is during a proxy call, when both shares are decrypted and combined in RAM for approximately 100ms, then immediately zeroed. There is no "admin mode" that can view stored keys.

"What if I lose my vp_live_ developer key?"

Create a new developer key from the Dashboard (Settings → API Keys). You will need to re-store any API keys that were encrypted with the old developer key, because Share 2 was encrypted using that key and cannot be decrypted without it. This is a security feature -- it means a stolen developer key can be rotated and the old one becomes useless.

"What if VaultProof goes down?"

If the VaultProof server is unavailable, proxied API calls will fail because the key cannot be reconstructed. However, your API keys at the provider (OpenAI, Anthropic, etc.) are completely unaffected. VaultProof does not modify, rotate, or delete your provider keys. You can always use your original API keys directly if needed. We recommend keeping a backup of critical keys in a secure location for disaster recovery.

"Is this open source?"

The Noir ZK circuit is open source so the cryptographic proofs can be independently audited and verified. The SDK and CLI are distributed as npm packages. The backend server and edge proxy are proprietary.

"What providers are supported?"

Currently: OpenAI, Anthropic, Google AI (Gemini), and Together.ai. Each provider has its own base URL and auth header format, which VaultProof handles automatically. More providers are coming -- contact us if you need a specific provider.

"How is this different from 1Password or HashiCorp Vault?"

1Password and HashiCorp Vault store secrets and give them back to you in plaintext when you need them. Your application then uses the key directly, meaning it exists in your app's memory, potentially in logs, and definitely in network traffic. VaultProof never gives you the key back. Instead, it makes the API call for you using the reconstructed key, which only exists in VaultProof's RAM for ~100ms. Your application never touches the raw key after initial storage.

"What about HIPAA / SOC 2?"

Enterprise tier with compliance certifications is coming. The current architecture (encryption at rest, TLS in transit, audit logging, access controls) is designed with compliance in mind. Contact us at team@vaultproof.dev for enterprise inquiries.

"Does VaultProof add latency to my API calls?"

Yes, but it is minimal. The overhead is the time to decrypt both shares and reconstruct the key (a few milliseconds) plus one additional network hop (Cloudflare edge to backend). For most LLM API calls, which take 500ms-5s to complete, VaultProof adds less than 50ms of overhead -- typically under 2% of the total request time.

"Can I use VaultProof in production?"

Yes. VaultProof runs on Cloudflare's edge network (330+ cities worldwide) with multi-region database replication. The SDK uses vp_live_ keys for production and vp_test_ keys for development/staging environments.