API overview
The base URL, conventions, errors, limits and versioning of the Voidhash HTTP API.
The Voidhash HTTP API is for server integrations and custom tooling. Use it when you need to read or change project data from your own backend or scripts. Mobile apps should use one of the mobile SDKs instead. The SDKs handle device headers, identity, caching, and store transactions for you.
Base URL
All requests go to the same host:
https://api.voidhash.comThe management API lives under /api/v1, and the client API the SDKs call under /api/v1/sdk.
Event capture is under /i/v1 on the same host.
Every management path names what it acts on. A project's resources live under
/api/v1/projects/{projectId}/..., a team's (an organization in the API) under
/api/v1/organizations/{organizationId}/..., and your own under /api/v1/me/.... A project or
team your credential cannot use answers 404, like one that does not exist.
First request
Create a project secret key in Studio. Then call the session endpoint to confirm the key works and see what it resolves to:
curl https://api.voidhash.com/api/v1/session \
-H "Authorization: Bearer $VOIDHASH_SECRET_KEY"For a secret key, projects in the response holds the one project the key belongs to. Its id is
the projectId of every project endpoint:
curl https://api.voidhash.com/api/v1/projects/$VOIDHASH_PROJECT_ID/products \
-H "Authorization: Bearer $VOIDHASH_SECRET_KEY"Keep secret keys on the server. See Authentication for the headers each credential uses.
Endpoint groups
| Group | Use |
|---|---|
| Projects and keys | Projects, their settings and audit log, and their API keys. |
| Persons | Look up customers with their access, purchases and subscriptions, and erase their data. |
| Products and perks | The project catalog and the perks each product grants. |
| Payment providers | Store and payment source connections, product mappings, history imports and payments. |
| Paywalls and locations | Paywalls with their builds and deploys, and the locations that show them. |
| Components | Paywall components, your team's registry and the components a project installs. |
| Feature flags and experiments | Flags with their variants and overrides, and experiments with their results. |
| Analytics and ads | Reports, stored events, the ingest policy, tracking domains, and ad accounts and reports. |
| Push notifications | Provider configurations, and notifications with their deliveries. |
| Webhooks | Manage endpoints, inspect deliveries, rotate secrets, and retry events. |
| Organizations | Teams, their members and invitations, and their Voidhash Cloud billing. |
| Your account | The session, your profile, notices, connected apps and the Terms; most need you signed in. |
| Schema and SDK | The consolidated project schema, and the client API the SDKs call. |
Each endpoint page shows its parameters, request and response schemas with every field described, its errors, and a client to try it. Most also show a complete example request and response.
Conventions
- Lists answer
{ "data": [...], "pageInfo": { "endCursor", "hasNextPage" } }. Passlimit, from 1 to 100 (default 50), and for the next page the previous page'sendCursorascursor. A cursor from another list fails withinvalid_cursor. Filters are plain query parameters named after the field. - Creating answers
201with the new object and aLocationheader. Deleting answers204. Work that continues in the background, such as a paywall build, answers202. Archiving is an action,POST .../{id}/archive, never a delete. - Objects carry their own
id. Field names are camelCase, booleans start withisorhas, enumerations are snake_case strings, times are ISO 8601, and money is an integer number of minor units next to itscurrency.
Retries and idempotency
GET requests are safe to repeat, and so are reports and queries sent with POST, such as
.../analytics/reports/charts. A repeated PUT or DELETE changes nothing more, though a repeated
DELETE can answer 404.
Payment source reports are keyed by your own id (PUT .../transactions/{externalId}), so a
repeated report records nothing twice. Sending a push notification takes an Idempotency-Key
header: repeating the send with the same key returns the first notification instead of sending
again. No other endpoint reads Idempotency-Key yet, so check before you repeat any other POST
that creates something.
Errors
Every management API error has the same JSON body:
{
"error": {
"type": "not_found",
"code": "product_not_found",
"message": "This project has no product prod_123.",
"param": "productId"
}
}type is the broad outcome and matches the HTTP status. code is the specific, machine-readable
reason. param, when present, names the field at fault. Branch on type and code; never parse
message, which can change.
| Status | type | Meaning |
|---|---|---|
400 | invalid_request | The request is malformed or breaks a rule. |
401 | unauthenticated | The credential is missing, invalid or expired. |
403 | permission_denied | The credential does not permit the action. |
404 | not_found | The resource does not exist in this scope. |
409 | conflict | The request conflicts with the current state. |
429 | rate_limited | A limit is reached; see Limits. |
500 | internal | Server failure. Retry safe requests with backoff. |
503 | unavailable | This deployment or a service it depends on cannot do it now. |
Codes that any endpoint can return:
code | type | Meaning |
|---|---|---|
invalid_body, invalid_query, invalid_path, invalid_headers | invalid_request | That part of the request doesn't match the endpoint's schema. |
invalid_cursor | invalid_request | The cursor came from another list. |
missing_credential, invalid_api_key, expired_api_key, … | unauthenticated | The credential was refused; see Authentication. |
permission_denied | permission_denied | The key lacks a permission the endpoint needs. |
person_credential_required | permission_denied | Only a signed-in person can do this, not a project secret key. |
project_not_found, organization_not_found | not_found | No such project or team, or the credential can't use it. |
internal_error, authentication_unavailable | internal | Something failed on our side, or the credential couldn't be checked. |
Other codes name the resource or rule, such as product_not_found or product_slug_taken. Each
operation's page lists the codes it adds in its Errors table, and Error codes
lists them across the API, the SDKs and the server libraries.
Every response carries a Request-Id header. Include it when you contact support about a request.
Limits
The management API has no general request rate limit. These limits answer 429 with
rate_limited:
| What | Limit | code |
|---|---|---|
| VoidQL queries | 4 running at once per team, and 60 queries a minute and 1,000 an hour per team. See VoidQL limits. | voidql_quota |
| Team invitations | 50 per team and 100 per person in 24 hours. | invitation_limit_reached |
These responses have no Retry-After header: retry a query once one of yours finishes or the
minute is over, and send invitations again the next day.
The client API limits POST /api/v1/sdk/sync-transaction to 300 requests a minute from one IP
address per project. Past that it answers 429 with an Api/SdkRateLimitedError body and a
Retry-After header, in seconds; the SDKs wait and resend. Event capture has its own limits; see
Event capture.
Versioning
v1 is the only version, and it's part of every path. New endpoints, optional parameters,
response fields and enumeration values can appear in it, so write clients that ignore fields and
values they don't know. Voidhash hasn't published a deprecation policy for v1 yet.
The OpenAPI document at GET /api/openapi.json always describes the API the server runs, including
the client API. The endpoint pages here are generated from the same contracts.
Next steps
- Authentication: the headers each credential uses, and its errors.
- API keys: create, restrict, roll and expire secret keys.
- Event capture: send analytics events from your backend.
- List persons: a first endpoint to call.
- Webhook delivery: get notified of purchases instead of polling.
Something wrong or missing on this page? Tell us by email or on Discord.