# Chronatum — partner integration guide

> Verify a Chronatum credentialed WAV by itself, retain the legacy audio + .poh fallback, and monitor the integration without copying proof data into telemetry.

Production base URL: `https://api.chronatum.com/v1`
Beta (integration testing) base URL: `https://beta.api.chronatum.com/v1`

The former hostnames `api.proofofhuman.fm` and `beta.api.proofofhuman.fm` serve the identical API
from the same infrastructure and keep working — an existing integration needs no change.

Integrate on beta first: it runs the same contract and authentication as production on isolated
pre-production infrastructure — separate API keys, a separate registry, disposable test proofs.
Beta and production keys are different secrets and never interchangeable; pass the beta base URL
via `new PoHClient({ apiKey, baseUrl })` in staging and switch to the production URL and key at
go-live.

- [API reference](/developers)
- [OpenAPI](https://chronatum.com/openapi.json)
- [TypeScript SDK](https://www.npmjs.com/package/@proof-of-human/ts-sdk)
- [Changelog](/developers/changelog)

## Core flow

> **The package is being renamed.** Install @proof-of-human/ts-sdk — that is the published package, currently 2.7.0, and its client export is PoHClient. It is being renamed @chronatum/ts-sdk (client export ChronatumClient), but that scope is not on npm yet, so installing it fails. The wire contract is identical either way: same base URLs, same x-api-key header, same request, response, verdict, and evidence values, so an existing integration needs no change and switching later is one import line.

Keep `POH_API_KEY` in a server-side secret manager. Never ship it in browser code or log it.

```ts
import { readFile } from "node:fs/promises";
import { PoHClient } from "@proof-of-human/ts-sdk";

const chronatum = new PoHClient({ apiKey: process.env.CHRONATUM_API_KEY! });
const upload = await chronatum.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 chronatum.verify({ uploadId: upload.uploadId });
```

Legacy fallback: base64 the separate `.poh` and call `verify({ uploadId, poh })`. One-file delivery is currently WAV/BWF and accepts up to 65 MiB in a verification slot. AIFF, CAF, MP3, and M4A use the legacy pair.

## Verdicts

- `valid` — signature, registry record, and exact audio binding passed.
- `audioChanged` — legacy audio does not match the sidecar.
- `tampered` — proof, embedded identity, or signature changed.
- `unregistered` — not a registered Chronatum-issued credential.
- `unreadable` — no readable proof, or embedded hard binding failed.
- `local_seal` — an artist-device seal was never registered with Chronatum.

`evidenceReport` is the current report-only contract and does not change credential validity. Legacy `classification`, `grade`, and older `interpretation` fields are compatibility-only behavioral calibration data; do not render them as authorship or labor percentages. A valid proof is not an authorship or “AI-free” certificate.

## Monitoring

Record HTTP status, latency, `X-Request-Id`, `X-RateLimit-*`, and `Retry-After` in your APM. Never log the key, audio, proof, presigned fields, proof IDs in URLs, or response bodies.

- Probe authenticated `GET /partner/usage?days=1` every five minutes.
- Alert on sustained 5xx responses, latency regression, repeated 429s, and low quota headroom.
- Include request ID and UTC time in every support report.

Current embedded assets are **C2PA · Chronatum verified**. Public Trust List / timestamp enrollment is not complete, so `publiclyTrusted` correctly remains false.

---

More: [llms.txt](https://chronatum.com/llms.txt) · [sitemap](https://chronatum.com/sitemap.md)
