Developers
Verify a track. One file.
A production quickstart for PoH credentialed audio, the legacy sidecar fallback, and the monitoring your integration should keep. The contract remains the live, model-generated API reference.
Integrate on beta first. https://beta.api.proofofhuman.fm/v1 runs the same contract and authentication as production on isolated pre-production infrastructure: separate API keys, a separate registry, disposable test proofs. Ask for a beta key alongside your production key — they are different secrets and never interchangeable. Point staging at beta (new PoHClient({ apiKey, baseUrl: "https://beta.api.proofofhuman.fm/v1" })), then move to https://api.proofofhuman.fm/v1 with your production key at go-live.
01 · Core flow
Upload, then verify
Keep the API key in a server-side secret manager. Ask for a short-lived upload slot, post every returned form field plus the WAV, then verify with only the upload ID.
import { readFile } from "node:fs/promises";
import { PoHClient } from "@proof-of-human/ts-sdk";
const poh = new PoHClient({ apiKey: process.env.POH_API_KEY! });
const upload = await poh.createUpload();
const bytes = await readFile("credentialed-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" }), "credentialed-song.wav");
const posted = await fetch(upload.url, { method: "POST", body: form });
if (!posted.ok) throw new Error(`upload failed: ${posted.status}`);
const result = await poh.verify({ uploadId: upload.uploadId });
if (!result.good || result.verdict !== "valid") {
throw new Error(`proof rejected: ${result.verdict}`);
}Legacy fallback: base64 the separate .poh and call verify({ uploadId, poh }). One-file delivery is currently WAV/BWF, up to 65 MiB in a verification slot. AIFF, CAF, MP3, and M4A keep using the legacy pair.
02 · Decision
Branch on the verdict
| Verdict | Meaning | Action |
|---|---|---|
| valid | PoH signature, registry record, and exact audio binding passed. | Accept the credential; apply your own policy to report-only analysis. |
| audioChanged | Legacy audio bytes do not match the .poh. | Reject and request the matching pair. |
| tampered | The proof, embedded identity, or signature changed. | Reject. |
| unregistered | This is not a registered PoH-issued proof or credential. | Reject. |
| unreadable | No readable proof was found, or the embedded hard binding failed. | Reject and confirm the correct file. |
| local_seal | An intact artist-device seal was never registered with PoH. | Do not accept it as PoH-issued. |
classification, grade, and interpretation are report-only. They may be absent on older proofs and do not change credential validity. A valid proof is a signed account of the editing PoH witnessed—not an “AI-free” certificate.
03 · Operations
Monitor without copying proof data
Capture status, latency, request ID, and rate-limit headers in your existing APM. Never log the key, audio, proof, presigned form fields, request URL containing a proof ID, or full response body.
const monitoredFetch: typeof fetch = async (input, init) => {
const started = performance.now();
const response = await fetch(input, init);
yourApm.record("poh.api", {
status: response.status,
latencyMs: Math.round(performance.now() - started),
requestId: response.headers.get("x-request-id"),
quotaRemaining: response.headers.get("x-ratelimit-remaining"),
retryAfter: response.headers.get("retry-after"),
});
return response;
};
const poh = new PoHClient({
apiKey: process.env.POH_API_KEY!,
fetch: monitoredFetch,
});- Probe authenticated
GET /partner/usage?days=1every five minutes. - Alert on sustained 5xx responses, p95 latency above your threshold, repeated 429s, and low quota headroom.
- Include
X-Request-Idand UTC time in support reports.