@proof-of-human/ts-sdk
v2.4.2
Published
TypeScript SDK for the Proof of Human API — verify credentialed audio or legacy .poh pairs and manage partner keys. Generated from the PoH TypeSpec model.
Downloads
2,569
Maintainers
Readme
@proof-of-human/ts-sdk
TypeScript SDK for the Proof of Human API — verify a
credentialed WAV by itself or a legacy audio + .poh pair, read process records, and manage your
partner API keys.
Model-first: every type in this SDK is generated from the PoH TypeSpec model
(model/main.tsp → OpenAPI → src/generated/api-types.ts), so the SDK cannot drift from the API.
Regenerate with npm run model at the repo root.
Install
npm install @proof-of-human/ts-sdkQuickstart
import { readFile } from 'node:fs/promises';
import { PoHClient, PoHError } from '@proof-of-human/ts-sdk';
const poh = new PoHClient({ apiKey: process.env.POH_API_KEY! });
// 1. Get a short-lived verification upload slot (65 MiB maximum).
const upload = await poh.createUpload();
// 2. Post every returned field plus the audio file to the presigned URL.
const bytes = await readFile('song.wav');
const form = new FormData();
for (const [key, value] of Object.entries(upload.fields)) form.append(key, value);
form.append('file', new Blob([new Uint8Array(bytes)], { type: 'audio/wav' }), 'song.wav');
const posted = await fetch(upload.url, { method: 'POST', body: form });
if (!posted.ok) throw new Error(`audio upload failed: ${posted.status}`);
// 3. A PoH-credentialed WAV verifies with its uploadId alone.
const result = await poh.verify({ uploadId: upload.uploadId });
console.log(result.verdict); // "valid" | "tampered" | "audioChanged" | "unregistered" | "unreadable" | "local_seal"
console.log(result.grade); // report-only process breakdown
// Legacy fallback: base64 the separate .poh and add it to the same request.
// const pohFileBase64 = (await readFile('song.poh')).toString('base64');
// await poh.verify({ uploadId: upload.uploadId, poh: pohFileBase64 });
// Read the evidence-selected process note (may be pending — poll)
if (result.proofId) {
const interp = await poh.getInterpretation(result.proofId);
console.log(interp.status);
}One-file credentials currently use WAV/BWF. AIFF, CAF, MP3, and M4A continue through the legacy
audio + .poh flow. A valid result checks PoH's signature, registry entry, and exact audio
binding; it does not mean “AI-free.” grade and interpretation are report-only and may be absent
on older proofs.
Key self-service
// See your keys (metadata only — secrets are never retrievable)
const { keys } = await poh.partner.listKeys();
// Zero-downtime rotation: the new secret is returned exactly once;
// your old key keeps working until previousKeyExpiresAt (72h).
// A newly minted key goes live within ~1 minute (gateway propagation) —
// keep using the old key until the new one authenticates.
const rotated = await poh.partner.rotateKey();
console.log(rotated.apiKey, new Date(rotated.previousKeyExpiresAt * 1000));
// Usage against your quota, per UTC day
const usage = await poh.partner.usage({ days: 30 });Behavior
- Auth:
x-api-keyheader on every request. - Retries: transport failures and 429/5xx are retried with backoff — honoring the server's
Retry-Afterwhen present (default 2 retries; configure viaretries). Non-idempotent calls stay safe:rotateKey()sends anIdempotency-Keyautomatically, so a retried rotation replays instead of minting twice. PassrotateKey({ idempotencyKey })to recover the same rotation across process restarts. - Errors: non-2xx throws
PoHErrorwith.status,.message, and.code— a stable, machine-readable slug (forbidden,not_found,rate_limited,conflict, …) to branch on instead of the message. 4xx (except 429) is never retried.
try {
await poh.partner.rotateKey();
} catch (e) {
if (e instanceof PoHError && e.code === 'rate_limited') { /* back off */ }
}Monitoring
Use a custom fetch to send non-sensitive client telemetry to your existing logger or APM. Record
status, latency, request ID, and rate-limit headers; never log the API key, audio, .poh, upload
form fields, or response bodies.
const monitoredFetch: typeof fetch = async (input, init) => {
const started = performance.now();
const response = await fetch(input, init);
console.info('PoH API', {
status: response.status,
latencyMs: Math.round(performance.now() - started),
requestId: response.headers.get('x-request-id'),
quotaLimit: response.headers.get('x-ratelimit-limit'),
quotaRemaining: response.headers.get('x-ratelimit-remaining'),
quotaReset: response.headers.get('x-ratelimit-reset'),
retryAfter: response.headers.get('retry-after'),
});
return response;
};
const monitored = new PoHClient({
apiKey: process.env.POH_API_KEY!,
fetch: monitoredFetch,
});
await monitored.health();
await monitored.partner.usage({ days: 7 });Recommended alerts: sustained 5xx responses, p95 latency above your product threshold, repeated
429s, and quota headroom below your expected peak. GET /health tests public reachability;
GET /partner/usage returns the gateway's per-day metering view. Include PoHError.requestId in
support reports so PoH can trace the exact failed request.
What a valid proof means
A valid credential attests PoH's signature and the binding to the exact audio file — a recorded process account, not an "AI-free" certification. The grade is report-only; screening policy stays yours.
