Authentication
Choose the right credential for server, tool, or device requests.
Every request to the Voidhash API carries a credential. Voidhash has three programmatic credential types, each meant for a different kind of caller. Use the narrowest one that fits.
| Credential | Header | Use |
|---|---|---|
| User API key | x-api-key | CLI and tools acting as a signed-in user across projects. |
| Project secret key | x-secret-key | Server-to-server requests for one project, including event capture. |
| Publishable key | x-publishable-key + x-distinct-id | Official SDKs and distributed clients. |
Project secret keys
A project secret key authorizes your backend to act on one project. Send it in the x-secret-key
header:
curl https://api.voidhash.com/api/v1/persons \
-H "x-secret-key: $VOIDHASH_SECRET_KEY"A project secret key grants broad access to the project. Do not put it in a mobile app, web bundle, public repository, or analytics event property. Rotate it immediately after exposure.
Limit what a secret key can do
A new secret key is restricted: under Settings → API keys → New secret key, choose None, Read or Write for each part of the project the key needs, such as customers, paywalls or analytics. Write includes Read. A few actions are granted separately, on top of Write: erasing customers, publishing paywalls and sending notifications. Every key can read its own project.
To start quickly, pick a template and adjust it:
| Template | Grants |
|---|---|
| Backend integration | Write customers, entitlements, purchases and events; read products. |
| Read-only analytics | Read analytics reports and ad campaigns with their spend (project:analytics:read, project:ads:read). |
| Read-only | Read everything except store credentials. |
| Paywall publishing | Write and publish paywalls; read products. |
Choose Full access instead only for a server you trust: the key can then read and change everything in the project, including store credentials and webhooks.
Keys are created, rotated and deleted in Studio, signed in as yourself. A secret key, the CLI and AI agents can list keys but cannot create, rotate or delete them, so no key or agent can give itself more access or outlive its removal.
A key's permissions are fixed when it is created. Rotating the key keeps them, and nothing can
widen them later; create a new key when you need different access. A key never gets a permission
that the person creating it does not have, so the dashboard only offers what your role allows. Listing keys returns each key's scopes, which is
null for a full-access key.
Rotating or deleting a key follows the same rule: you can rotate or delete only keys whose access you
also have. Listing raw events (GET /api/v1/events) requires
project:events:read (Events: Read), which the read-only analytics template leaves out because
events carry data about individual end users. Connecting or disconnecting an ad account requires
project:ads:manage (Ads: Write), which that template also leaves out.
A request that needs a permission the key lacks is answered with 403. Event capture rejects a
restricted key without project:events:write (Events: Write) as unauthorized.
User API keys
A user API key acts as a signed-in user. It is useful for local tools and automation that need
access to more than one project. Send it in the x-api-key header:
curl https://api.voidhash.com/api/v1/auth/session \
-H "x-api-key: $VOIDHASH_API_KEY"The CLI obtains and stores this credential for you when you run voidhash-cli auth login.
Publishable keys
A publishable key is safe to ship inside an app. It only authorizes the device-facing SDK surface,
and it must be paired with a customer identity in the x-distinct-id header:
curl https://api.voidhash.com/api/v1/sdk/person \
-H "x-publishable-key: vh_pk_..." \
-H "x-distinct-id: user_123"The official SDKs also send platform and client metadata that these endpoints require. Prefer the SDK over calling them directly.
Distinct ids outside printable ASCII
HTTP header values are limited to printable ASCII. When a distinct id contains any other character,
such as an accented letter or an emoji, send its UTF-8 bytes percent-encoded and add
x-distinct-id-encoding: percent:
curl https://api.voidhash.com/api/v1/sdk/person \
-H "x-publishable-key: vh_pk_..." \
-H "x-distinct-id: Zo%C3%AB" \
-H "x-distinct-id-encoding: percent"Voidhash decodes the header only when that marker is present. Without it, the value is used exactly
as sent, so an id that contains a literal % keeps its identity. Send printable ASCII ids as they
are.
A distinct id is at most 255 characters and must not be blank or contain a NUL character. A missing,
blank or malformed x-distinct-id is answered with 400 and an Api/SdkValidationError body, not
401. A 401 always means the publishable key itself was rejected.
Verify a credential
Call GET /api/v1/auth/session with any credential. The response shows how the key was resolved
and which project it can access.
A valid key can still receive a 403 when it lacks permission for a specific operation.
Event capture
The event capture endpoints, /i/v1/capture and /i/v1/batch, accept either a secret key or a
publishable key. Which one you send depends on where the request comes from.
From a backend, send the project secret key as x-secret-key. No x-distinct-id header is
needed, because each event carries its own distinct_id.
From a distributed client that cannot hold a secret, send the publishable key as a token field in
the JSON body instead.
Send one or the other. When both are present, the body token wins. See
Event Capture for request examples.