Documentation
Implement UniKey Cloud
Add agent verification to any service that receives agent traffic. Forward the incoming Trust Packet to one endpoint and get a cryptographic verdict — before you execute the action.
Overview
Your service receives a request from an AI agent that carries a Trust Packet — a signed JSON object asserting identity, authority, and scope. You POST that packet to UniKey Cloud, which verifies the signature against the signer's DNS-published key, checks expiry, audience, scope, and any delegation chain, and returns a verdict. There are two endpoints:
POST /v1/verify-packet
Verify a self-contained Trust Packet (JSON body).
POST /v1/verify
Verify a signed HTTP request via X-UniKey-* headers.
Base URL: https://api.unikeycloud.com
Quickstart
-
1
Create an API key
From the dashboard, create a key in test mode. Test keys are unlimited and never billed.
-
2
Send your first verification
POST a Trust Packet to
/v1/verify-packetwith your key as a bearer token. -
3
Act on the verdict
Reject the action unless
validistrue. Switch to a live key when you ship.
Authentication
Authenticate every request with your secret API key as a bearer token. Keys are environment-scoped:
uk_test_… for development,
uk_live_… for production. Never expose a live key in client-side code.
Authorization: Bearer uk_live_4f8c2a1e9b…
Publish your key (signers only)
If your service signs packets (acts on behalf of users/agents), publish your Ed25519 public key as a DNS TXT record so any verifier can find it — the same mechanism DKIM uses for email. Verifiers don't need to publish anything.
unikey._domainkey.yourdomain.com. IN TXT "v=DKIM1; k=ed25519; p=MCowBQYDK2VwAyEA…"
Verify a Trust Packet
Forward the packet you received to /v1/verify-packet:
curl https://api.unikeycloud.com/v1/verify-packet \ -H "Authorization: Bearer $UNIKEY_API_KEY" \ -H "Content-Type: application/json" \ -d @trust-packet.json
require "net/http" require "json" res = Net::HTTP.post( URI("https://api.unikeycloud.com/v1/verify-packet"), packet.to_json, "Authorization" => "Bearer #{ENV['UNIKEY_API_KEY']}", "Content-Type" => "application/json" ) result = JSON.parse(res.body) head :forbidden unless result["valid"]
const res = await fetch("https://api.unikeycloud.com/v1/verify-packet", { method: "POST", headers: { Authorization: `Bearer ${process.env.UNIKEY_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify(packet), }); const result = await res.json(); if (!result.valid) return reject();
import os, requests res = requests.post( "https://api.unikeycloud.com/v1/verify-packet", headers={"Authorization": f"Bearer {os.environ['UNIKEY_API_KEY']}"}, json=packet, ) result = res.json() if not result["valid"]: abort(403)
The Trust Packet body
The packet you forward looks like this (you receive it from the agent — you don't build it):
{
"header": { "tp_version": "1.0", "packet_id": "pkt_9a4f…", "issued_at": "2026-05-26T18:04:00Z", "expires_at": "2026-05-26T18:09:00Z", "nonce": "b7e2…" },
"claims": { "subject": "claude@acme.ai", "issuer": "acme.ai", "audience": "store.example", "scope": ["charge:60"] },
"payload": { "action": "purchase_item", "params": { "item": "Air Max", "amount": 55 } },
"signatures": [{ "algorithm": "ed25519", "signer": "acme.ai", "key_selector": "unikey", "signature": "MEUCIQ…" }]
}
Successful response
{
"valid": true,
"packet_id": "pkt_9a4f…",
"subject": "claude@acme.ai",
"issuer": "acme.ai",
"audience": "store.example",
"action": "purchase_item",
"scope": ["charge:60"],
"signer": "acme.ai",
"dns_hardened": true,
"verified_at": "2026-05-26T18:04:22Z"
}
Verify a signed request
When an agent signs an HTTP request directly (DKIM-over-HTTPS) instead of sending a packet, relay the
signature headers to /v1/verify:
X-UniKey-Signature: <base64 Ed25519 signature> X-UniKey-Signer: acme.ai X-UniKey-Timestamp: 1769450662 X-UniKey-Body-Hash: <base64 SHA-256 of body> X-Agent-Email: claude@acme.ai
Responses & errors
Every response includes a boolean valid.
Failures return a stable error code and a human-readable message.
| HTTP | error | Meaning |
|---|---|---|
| 200 | — | Verified. Check the valid field. |
| 422 | invalid_signature | Signature did not verify against the DNS key. |
| 422 | expired_packet | Packet is outside its issued_at / expires_at window. |
| 400 | invalid_packet | Malformed or missing required fields. |
| 403 | untrusted_signer | Signer is not in your allowlist. |
| 422 | dns_lookup_failed | No UniKey key found for the signer domain. |
| 422 | dns_inconsistency | Resolvers disagreed — failed closed (hardening). |
| 409 | replay_detected | This packet was already verified in its window. |
| 401 | invalid_api_key | Missing or invalid API key. |
| 402 | quota_exceeded | Monthly included volume reached. |
| 429 | rate_limited | Too many requests — retry after the header. |
Libraries
Prefer to verify in-process without the hosted API? The open-source verifier libraries implement the full protocol. UniKey Cloud runs the hardened infrastructure around them — see self-hosted.
Ruby
gem "unikey"
Node
npm i @unikey/verify
Python
pip install unikey-tp
Ready to verify your first agent?
Create a free account and grab a test key — 10,000 verifications a month, no card.
Start free