Skip to content

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

VerdictMeaningAction
validPoH signature, registry record, and exact audio binding passed.Accept the credential; apply your own policy to report-only analysis.
audioChangedLegacy audio bytes do not match the .poh.Reject and request the matching pair.
tamperedThe proof, embedded identity, or signature changed.Reject.
unregisteredThis is not a registered PoH-issued proof or credential.Reject.
unreadableNo readable proof was found, or the embedded hard binding failed.Reject and confirm the correct file.
local_sealAn 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=1 every five minutes.
  • Alert on sustained 5xx responses, p95 latency above your threshold, repeated 429s, and low quota headroom.
  • Include X-Request-Id and UTC time in support reports.