Create a scoped API key
Use least-privilege scopes. Candidate reads need candidates:read, score lookups need scores:read, webhook registration needs webhooks:write, and private agent reports need agent-decisions:write.
Manage API keysDeveloper docs
Use Humanproof's public API, sandbox fixtures, and signed webhooks to plug a credit score for your skills into search, profile, marketplace, and agent workflows.
A practical order for getting from dashboard setup to a production integration.
Use least-privilege scopes. Candidate reads need candidates:read, score lookups need scores:read, webhook registration needs webhooks:write, and private agent reports need agent-decisions:write.
Manage API keysUse signed-in dashboard routes with fictional candidates and scores before touching live metered endpoints. Sandbox calls are never billed.
Open sandboxSend your API key as a bearer token. Include Humanproof-Version when you want explicit version pinning.
Open OpenAPIRegister an HTTPS endpoint, store the one-time signing secret, send a test event, then monitor recent delivery attempts.
Manage webhooksPOST private decision reports with an idempotency key. Final outcomes feed the dashboard unlock preview for approved paid-read rate-limit boosts and future API discounts.
View reportsThe OpenAPI document is the source of truth for route schemas. This table is the operator view.
/api/v1/candidates/searchcandidates:read or x402Search public candidate previews by skill, display name, title, or handle.
/api/v1/candidates/{username}candidates:read or x402Read one public candidate profile. Private evidence and worker ids are never returned.
/api/v1/scores/{scoreId}scores:read or x402Read one active public score envelope for an onboarded public profile.
/api/v1/score-vc/verifypublic, optional scores:readVerify a presented Score VC with issuer pinning, Ed25519 signature checks, and revocation lookup.
/api/v1/agent-decisionsagent-decisions:writeReport a private decision or final outcome after an agent uses candidate or score data.
/api/v1/webhooks/endpointswebhooks:writeList active webhook endpoints owned by the API key user. Signing secrets are never returned after creation.
/api/v1/webhooks/endpointswebhooks:writeCreate an HTTPS webhook endpoint and receive the one-time signing secret.
/api/v1/webhooks/endpoints/{endpointId}webhooks:writeDisable a webhook endpoint. Disabled endpoints stop receiving future deliveries.
Use these from the signed-in dashboard to build search, profile, and score flows before switching to metered v1 endpoints.
/api/account/developer/sandbox/candidates/search?q=react&limit=2Dashboard sessionSearch fictional candidate previews without an API key or credit metering.
/api/account/developer/sandbox/candidates/{username}Dashboard sessionRead a fictional candidate profile with the same public envelope shape as v1 candidate detail.
/api/account/developer/sandbox/scores/{scoreId}Dashboard sessionRead a fictional score envelope with VC metadata and status URLs for client wiring.
These same-origin routes power the signed-in developer dashboard for webhook diagnostics, test events, and agent report review.
/api/account/webhooks/endpointsDashboard sessionList active webhook endpoints for the signed-in developer dashboard.
/api/account/webhooks/endpointsDashboard session, same originCreate a webhook endpoint from the dashboard and show the signing secret once.
/api/account/webhooks/endpoints/{endpointId}/testDashboard session, same originQueue one synthetic webhook event for an endpoint. Test events are limited to one per minute.
/api/account/webhooks/endpoints/{endpointId}/deliveries?limit=5Dashboard sessionRead recent delivery attempts for the dashboard diagnostics view.
/api/account/agent-decisions?limit=10Dashboard sessionList private agent decision reports owned by the signed-in developer.
/api/account/agent-decisions/unlock-reviewDashboard session, same originRequest Humanproof review for an agent reporting unlock.
Copy these shapes into your client, then swap in your saved API key and endpoint URL.
Bearer auth works across paid v1 reads. Version pinning is optional, but recommended for production clients.
curl "https://humanproof.io/api/v1/candidates/search?q=react&limit=5" \ -H "Authorization: Bearer hp_live_..." \ -H "Humanproof-Version: 2026-05-14"
Sandbox routes use your signed-in dashboard session, return synthetic data, and do not consume API credits.
const response = await fetch(
"/api/account/developer/sandbox/candidates/search?q=react&limit=2",
{
headers: { accept: "application/json" },
credentials: "include",
},
);
const data = await response.json();Use an idempotency key when creating endpoints. Store the returned signing secret immediately.
curl "https://humanproof.io/api/v1/webhooks/endpoints" \
-X POST \
-H "Authorization: Bearer hp_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: endpoint-prod-001" \
-d '{
"url": "https://api.example.com/humanproof/webhooks",
"description": "Production events",
"events": ["score.updated", "score.revised"]
}'Dashboard routes let signed-in developers inspect recent deliveries and queue test events without pasting an API key.
const endpointId = "00000000-0000-4000-8000-000000000000";
const response = await fetch(
`/api/account/webhooks/endpoints/${endpointId}/deliveries?limit=5`,
{
headers: { accept: "application/json" },
credentials: "include",
},
);
const { deliveries } = await response.json();
await fetch(`/api/account/webhooks/endpoints/${endpointId}/test`, {
method: "POST",
headers: { "content-type": "application/json" },
credentials: "include",
body: JSON.stringify({ eventType: "score.updated" }),
});Use this after an agent shortlists, rejects, contacts, or otherwise acts on Humanproof data.
curl "https://humanproof.io/api/v1/agent-decisions" \
-X POST \
-H "Authorization: Bearer hp_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: decision-req-frontend-123" \
-d '{
"subject": { "kind": "candidate", "username": "maya-chen" },
"decision": "shortlisted",
"outcome": "pending",
"agentName": "Talent routing agent",
"jobRef": "req-frontend-123",
"reasonCodes": ["react_match", "verified_score"]
}'Every event has a stable id, type, creation timestamp, and event-specific data.
{
"schemaVersion": "humanproof.webhook_event.v1",
"id": "evt_score_test_00001",
"type": "score.updated",
"createdAt": "2026-06-01T00:00:00.000Z",
"data": {
"workerId": "00000000-0000-4000-8000-00000000f001",
"snapshotId": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"score": 742,
"confidenceLow": 710,
"confidenceHigh": 774,
"evidenceCount": 12,
"sourceCount": 4,
"scoreVcSha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"scoreVcStatusToken": "status_test_0001",
"issuedAt": "2026-06-01T00:00:00.000Z"
}
}Compute HMAC SHA-256 over timestamp.rawBody and compare it with the v1 signature.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyHumanproofWebhook(rawBody, signatureHeader, secret) {
if (typeof rawBody !== 'string' || typeof signatureHeader !== 'string') return false;
if (signatureHeader.trim() === '' || typeof secret !== 'string' || secret === '') return false;
const parts = Object.fromEntries(
signatureHeader.split(',').map((part) => {
const [key, value] = part.split('=');
return [key, value];
}),
);
const timestamp = parts.t;
const received = parts.v1;
if (!timestamp || !received) return false;
const timestampSeconds = Number(timestamp);
if (!Number.isFinite(timestampSeconds)) return false;
if (!/^[0-9a-f]+$/i.test(received)) return false;
if (Math.abs(Date.now() / 1000 - timestampSeconds) > 300) return false;
const expected = createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
const expectedBytes = Buffer.from(expected, 'hex');
const receivedBytes = Buffer.from(received, 'hex');
return expectedBytes.length === receivedBytes.length
&& timingSafeEqual(expectedBytes, receivedBytes);
}Humanproof signs every delivery. Your endpoint should verify the signature before processing event data.
score.updatedA worker score has a new issued value.
score.revisedA previously issued score was corrected or replaced.
evidence.revokedA source record was removed from the active evidence set.
dispute.openedA worker opened a review or score dispute.
dispute.resolvedA dispute reached a terminal decision.
candidate.consent_changedA candidate sharing permission changed.
Humanproof-Webhook-IdStable event id. Use it for idempotent processing.
Humanproof-Webhook-EventEvent type, for example score.updated.
Humanproof-Webhook-DeliveryUnique delivery attempt row id.
Humanproof-Webhook-TimestampUnix timestamp used in the signed payload.
Humanproof-Webhook-SignatureHMAC header in the form t=<timestamp>,v1=<hex digest>.