Triple Key API
Post-quantum multi-layer digital signatures combining Ed25519 + Dilithium-5 (ML-DSA-87) + FALCON-512 into a single unified signing and verification API. Three algorithms, one API call.
Ed25519
Dilithium-5
FALCON-512
Post-Quantum Secure
v1.0
Authentication
All requests to the Triple Key API require an API key passed via the X-API-Key header. You can generate an API key from your dashboard.
X-API-Key: h33_pk_your_api_key_here
i
Demo Key Available
Use h33_demo_triple_key_public for testing. Limited to 100 operations per day. Do not use in production.
Example Request
curl -X POST https://api.h33.ai/api/v1/triple-key/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: h33_pk_your_api_key_here" \
-d '{"label": "my-first-keypair"}'
Rate Limits
Rate limits are applied per API key. Exceeding the limit returns a 429 status. The response includes X-RateLimit-Remaining and X-RateLimit-Reset headers.
| Plan |
Rate Limit |
Burst |
Daily Ops |
| Starter |
10 req/sec |
20 |
10,000 |
| Pro |
50 req/sec |
100 |
500,000 |
| Enterprise |
500 req/sec |
1,000 |
Unlimited |
Error Codes
The API uses standard HTTP status codes. All error responses include a JSON body with error and message fields.
{
"error": "invalid_base64",
"message": "The message_b64 field contains invalid base64 encoding.",
"status": 400
}
| Status |
Error Code |
Description |
400 |
invalid_base64 |
Request contains malformed base64 data |
400 |
key_not_found |
The specified key_id does not exist |
400 |
invalid_security_level |
security_level must be standard, high, or critical |
400 |
missing_field |
A required field is missing from the request body |
400 |
key_revoked |
The specified key has been revoked |
401 |
unauthorized |
Missing or invalid API key |
429 |
rate_limited |
Too many requests. Check X-RateLimit-Reset header |
500 |
internal |
Unexpected server error. Contact support if persistent |
Generate Keypair
Generate a new Triple Key keypair. Creates linked Ed25519, Dilithium-5 (ML-DSA-87), and FALCON-512 key material. The private keys are stored server-side in an HSM-backed vault. Public keys are returned in the response.
Request Body
| Field |
Type |
Required |
Description |
label |
string |
optional |
Human-readable label for the keypair |
security_level |
string |
optional |
standard | high | critical. Defaults to standard |
rotation_period_days |
integer |
optional |
Auto-rotation period in days. Defaults to 90 |
Example Request
{
"label": "production-signing-key",
"security_level": "high",
"rotation_period_days": 30
}
Response
| Field |
Type |
Description |
key_id |
string |
Unique identifier for the keypair |
ed25519_public_key |
string |
Ed25519 public key (base64) |
dilithium_public_key |
string |
Dilithium-5 public key (base64, 2592 bytes) |
falcon_public_key |
string |
FALCON-512 public key (base64, 897 bytes) |
security_level |
string |
Applied security level |
rotation_period_days |
integer |
Configured rotation period |
created_at |
string |
ISO 8601 timestamp |
latency_us |
integer |
Server-side latency in microseconds |
Example Response
{
"key_id": "tk_9f8a7b6c5d4e3f2a1b0c",
"ed25519_public_key": "MCowBQYDK2VwAyEAGb1gauf...base64...",
"dilithium_public_key": "MIIFIDAHBgUrzg8D...base64...2592bytes",
"falcon_public_key": "MIICIjANBgkqhkiG...base64...897bytes",
"security_level": "high",
"rotation_period_days": 30,
"created_at": "2026-02-22T12:00:00Z",
"latency_us": 4820
}
Sign Message
Sign a message with all three algorithms in a single API call. The message is signed with Ed25519, Dilithium-5, and FALCON-512 sequentially, producing a unified composite signature.
Request Body
| Field |
Type |
Required |
Description |
key_id |
string |
required |
The keypair identifier returned from /generate |
message_b64 |
string |
required |
Base64-encoded message to sign (max 10MB) |
Example Request
{
"key_id": "tk_9f8a7b6c5d4e3f2a1b0c",
"message_b64": "SGVsbG8sIFRyaXBsZSBLZXkh"
}
Response
| Field |
Type |
Description |
signature_b64 |
string |
Composite signature (base64). Contains Ed25519 + Dilithium + FALCON signatures concatenated |
version |
string |
Signature format version (e.g. "1.0") |
algorithm |
string |
Always "triple-key-v1" |
key_version |
integer |
Key version used for signing (increments on rotation) |
latency_us |
integer |
Server-side latency in microseconds |
Example Response
{
"signature_b64": "MEUCIQC7...composite...base64...",
"version": "1.0",
"algorithm": "triple-key-v1",
"key_version": 1,
"latency_us": 1240
}
Verify Signature
Verify a Triple Key composite signature against a message. All three signature layers (Ed25519, Dilithium-5, FALCON-512) are verified independently. The signature is valid only if all three layers pass.
Request Body
| Field |
Type |
Required |
Description |
message_b64 |
string |
required |
Base64-encoded original message |
signature_b64 |
string |
required |
Composite signature from /sign endpoint |
ed25519_public_key |
string |
required |
Ed25519 public key (base64) |
dilithium_public_key |
string |
required |
Dilithium-5 public key (base64) |
falcon_public_key |
string |
required |
FALCON-512 public key (base64) |
Example Request
{
"message_b64": "SGVsbG8sIFRyaXBsZSBLZXkh",
"signature_b64": "MEUCIQC7...composite...base64...",
"ed25519_public_key": "MCowBQYDK2VwAyEAGb1gauf...",
"dilithium_public_key": "MIIFIDAHBgUrzg8D...",
"falcon_public_key": "MIICIjANBgkqhkiG..."
}
Response
| Field |
Type |
Description |
valid |
boolean |
true if all three layers verified successfully |
algorithm |
string |
Always "triple-key-v1" |
layers_verified |
array |
List of algorithms that passed verification |
latency_us |
integer |
Server-side latency in microseconds |
Example Response
{
"valid": true,
"algorithm": "triple-key-v1",
"layers_verified": [
"ed25519",
"dilithium-5",
"falcon-512"
],
"latency_us": 890
}
Rotation Status
Check the current rotation status of a keypair. Returns whether the key needs rotation, the current version, and the next scheduled rotation date.
Query Parameters
| Parameter |
Type |
Required |
Description |
key_id |
string |
required |
The keypair identifier |
Example Request
GET /api/v1/triple-key/rotate/status?key_id=tk_9f8a7b6c5d4e3f2a1b0c HTTP/1.1
Host: api.h33.ai
X-API-Key: h33_pk_your_api_key_here
Response
| Field |
Type |
Description |
key_id |
string |
The keypair identifier |
key_version |
integer |
Current key version number |
needs_rotation |
boolean |
true if the key has exceeded its rotation period |
rotation_in_progress |
boolean |
true if a rotation is currently being executed |
next_rotation |
string |
ISO 8601 timestamp of next scheduled rotation |
last_rotated |
string |
ISO 8601 timestamp of most recent rotation |
Example Response
{
"key_id": "tk_9f8a7b6c5d4e3f2a1b0c",
"key_version": 3,
"needs_rotation": false,
"rotation_in_progress": false,
"next_rotation": "2026-03-01T00:00:00Z",
"last_rotated": "2026-02-22T08:30:00Z"
}
Execute Rotation
Manually trigger an immediate key rotation. New key material is generated for all three algorithms. Previous key versions remain available for signature verification but can no longer sign new messages.
Request Body
| Field |
Type |
Required |
Description |
key_id |
string |
required |
The keypair identifier |
reason |
string |
optional |
Reason for manual rotation (logged in audit trail) |
Example Request
{
"key_id": "tk_9f8a7b6c5d4e3f2a1b0c",
"reason": "Scheduled compliance rotation"
}
Response
| Field |
Type |
Description |
status |
string |
"rotated" on success |
rotation_id |
string |
Unique rotation event identifier |
new_key_version |
integer |
The new key version number |
ed25519_public_key |
string |
New Ed25519 public key (base64) |
dilithium_public_key |
string |
New Dilithium-5 public key (base64) |
falcon_public_key |
string |
New FALCON-512 public key (base64) |
latency_us |
integer |
Server-side latency in microseconds |
Example Response
{
"status": "rotated",
"rotation_id": "rot_a1b2c3d4e5f6",
"new_key_version": 4,
"ed25519_public_key": "MCowBQYDK2VwAyEA...new...base64...",
"dilithium_public_key": "MIIFIDAHBgUrzg8D...new...base64...",
"falcon_public_key": "MIICIjANBgkqhkiG...new...base64...",
"latency_us": 5130
}
Rotation History
Retrieve the complete rotation history for a keypair. Returns a chronological list of all rotation events, including the reason, trigger type, and version transitions.
Query Parameters
| Parameter |
Type |
Required |
Description |
key_id |
string |
required |
The keypair identifier |
Example Request
GET /api/v1/triple-key/rotate/history?key_id=tk_9f8a7b6c5d4e3f2a1b0c HTTP/1.1
Host: api.h33.ai
X-API-Key: h33_pk_your_api_key_here
Response
| Field |
Type |
Description |
key_id |
string |
The keypair identifier |
current_version |
integer |
Current active key version |
events |
array |
Array of rotation event objects |
events[].rotation_id |
string |
Unique rotation event identifier |
events[].from_version |
integer |
Previous key version |
events[].to_version |
integer |
New key version after rotation |
events[].trigger |
string |
"manual" | "scheduled" | "policy" |
events[].reason |
string |
Reason for rotation (if provided) |
events[].timestamp |
string |
ISO 8601 timestamp of rotation |
Example Response
{
"key_id": "tk_9f8a7b6c5d4e3f2a1b0c",
"current_version": 3,
"events": [
{
"rotation_id": "rot_x1y2z3",
"from_version": 1,
"to_version": 2,
"trigger": "scheduled",
"reason": "Auto-rotation (30-day policy)",
"timestamp": "2026-01-23T00:00:00Z"
},
{
"rotation_id": "rot_a1b2c3d4e5f6",
"from_version": 2,
"to_version": 3,
"trigger": "manual",
"reason": "Scheduled compliance rotation",
"timestamp": "2026-02-22T08:30:00Z"
}
]
}
Code Examples
Complete working examples for the generate, sign, and verify flow in multiple languages.
curl
# 1. Generate a keypair
KEY_RESPONSE=$(curl -s -X POST https://api.h33.ai/api/v1/triple-key/generate \
-H "Content-Type: application/json" \
-H "X-API-Key: $H33_API_KEY" \
-d '{"label": "demo-key", "security_level": "standard"}')
KEY_ID=$(echo $KEY_RESPONSE | jq -r '.key_id')
ED25519_PK=$(echo $KEY_RESPONSE | jq -r '.ed25519_public_key')
DILITHIUM_PK=$(echo $KEY_RESPONSE | jq -r '.dilithium_public_key')
FALCON_PK=$(echo $KEY_RESPONSE | jq -r '.falcon_public_key')
echo "Key ID: $KEY_ID"
# 2. Sign a message
MESSAGE_B64=$(echo -n "Hello, Triple Key!" | base64)
SIGN_RESPONSE=$(curl -s -X POST https://api.h33.ai/api/v1/triple-key/sign \
-H "Content-Type: application/json" \
-H "X-API-Key: $H33_API_KEY" \
-d "{\"key_id\": \"$KEY_ID\", \"message_b64\": \"$MESSAGE_B64\"}")
SIGNATURE=$(echo $SIGN_RESPONSE | jq -r '.signature_b64')
echo "Signature: ${SIGNATURE:0:40}..."
# 3. Verify the signature
curl -s -X POST https://api.h33.ai/api/v1/triple-key/verify \
-H "Content-Type: application/json" \
-H "X-API-Key: $H33_API_KEY" \
-d "{
\"message_b64\": \"$MESSAGE_B64\",
\"signature_b64\": \"$SIGNATURE\",
\"ed25519_public_key\": \"$ED25519_PK\",
\"dilithium_public_key\": \"$DILITHIUM_PK\",
\"falcon_public_key\": \"$FALCON_PK\"
}" | jq .
Python
import requests
import base64
API_KEY = "h33_pk_your_api_key_here"
BASE_URL = "https://api.h33.ai/api/v1/triple-key"
HEADERS = {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
}
# 1. Generate a keypair
gen = requests.post(
f"{BASE_URL}/generate",
headers=HEADERS,
json={"label": "python-demo", "security_level": "high"},
).json()
key_id = gen["key_id"]
print(f"Generated key: {key_id}")
# 2. Sign a message
message = base64.b64encode(b"Hello, Triple Key!").decode()
sig = requests.post(
f"{BASE_URL}/sign",
headers=HEADERS,
json={"key_id": key_id, "message_b64": message},
).json()
print(f"Signed with algorithm: {sig['algorithm']}")
# 3. Verify the signature
verify = requests.post(
f"{BASE_URL}/verify",
headers=HEADERS,
json={
"message_b64": message,
"signature_b64": sig["signature_b64"],
"ed25519_public_key": gen["ed25519_public_key"],
"dilithium_public_key": gen["dilithium_public_key"],
"falcon_public_key": gen["falcon_public_key"],
},
).json()
print(f"Valid: {verify['valid']}")
print(f"Layers verified: {verify['layers_verified']}")
Node.js
const API_KEY = "h33_pk_your_api_key_here";
const BASE = "https://api.h33.ai/api/v1/triple-key";
async function tripleKeyDemo() {
const headers = {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
};
// 1. Generate a keypair
const gen = await fetch(`${BASE}/generate`, {
method: "POST",
headers,
body: JSON.stringify({
label: "node-demo",
security_level: "standard",
}),
}).then(r => r.json());
console.log("Key ID:", gen.key_id);
// 2. Sign a message
const messageB64 = Buffer.from("Hello, Triple Key!").toString("base64");
const sig = await fetch(`${BASE}/sign`, {
method: "POST",
headers,
body: JSON.stringify({
key_id: gen.key_id,
message_b64: messageB64,
}),
}).then(r => r.json());
console.log("Algorithm:", sig.algorithm);
// 3. Verify the signature
const result = await fetch(`${BASE}/verify`, {
method: "POST",
headers,
body: JSON.stringify({
message_b64: messageB64,
signature_b64: sig.signature_b64,
ed25519_public_key: gen.ed25519_public_key,
dilithium_public_key: gen.dilithium_public_key,
falcon_public_key: gen.falcon_public_key,
}),
}).then(r => r.json());
console.log("Valid:", result.valid);
console.log("Layers:", result.layers_verified);
}
tripleKeyDemo();
Rust
use base64::{engine::general_purpose::STANDARD, Engine};
use reqwest::Client;
use serde_json::{json, Value};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let api_key = "h33_pk_your_api_key_here";
let base = "https://api.h33.ai/api/v1/triple-key";
// 1. Generate a keypair
let gen: Value = client
.post(format!("{base}/generate"))
.header("X-API-Key", api_key)
.json(&json!({
"label": "rust-demo",
"security_level": "standard"
}))
.send().await?
.json().await?;
let key_id = gen["key_id"].as_str().unwrap();
println!("Key ID: {key_id}");
// 2. Sign a message
let message_b64 = STANDARD.encode(b"Hello, Triple Key!");
let sig: Value = client
.post(format!("{base}/sign"))
.header("X-API-Key", api_key)
.json(&json!({
"key_id": key_id,
"message_b64": message_b64
}))
.send().await?
.json().await?;
println!("Algorithm: {}", sig["algorithm"]);
// 3. Verify the signature
let result: Value = client
.post(format!("{base}/verify"))
.header("X-API-Key", api_key)
.json(&json!({
"message_b64": message_b64,
"signature_b64": sig["signature_b64"],
"ed25519_public_key": gen["ed25519_public_key"],
"dilithium_public_key": gen["dilithium_public_key"],
"falcon_public_key": gen["falcon_public_key"]
}))
.send().await?
.json().await?;
println!("Valid: {}", result["valid"]);
println!("Layers: {}", result["layers_verified"]);
Ok(())
}