VoidhashDocs
DocumentationAPI reference
Dashboard
Essentials
API overview
Authentication
Endpoints
Ad_accounts
Analytics
Api_keys
Auth
Component_dev_sessions
Component_registry
Components
Development
Events
Experiments
Feature_flag_overrides
Feature_flag_targets
Feature_flags
Ingest_policy
Notification_sends
Notifications
Organizations
Payment_provider_configurations
Payment_provider_products
Payment_sources
Paywall_locations
Paywalls
Perks
Persons
Products
Projects
Push_notification_configurations
Schema
Sdk
Users
Webhooks
Analytics
Event capture

Event Capture

Send analytics events to Voidhash with a project secret key or a publishable token.

Event capture is how you send analytics events to Voidhash without a mobile SDK. Use it from your backend, or from custom clients that do not run one of the SDKs.

There are two endpoints. POST /i/v1/capture sends one event, and POST /i/v1/batch sends one or more events in a single request.

Choose a credential

Which credential you send depends on where the request comes from. A backend you control sends its secret key in the x-secret-key request header, as x-secret-key: vh_sk_.... A distributed client, such as an app or web bundle, cannot hold a secret, so it sends the publishable key as a token field in the JSON body, as "token": "vh_pk_...".

Send one or the other. Only the x-secret-key header may carry a secret key. A secret key in the body token field is rejected with 401 unauthorized, and a distributed client must not hold a secret key at all.

Voidhash SDKs may also present the publishable key through their usual x-publishable-key header instead of the body. When both the header and the body token are present, the body token wins.

Never expose a secret key

x-secret-key grants broad access to the project. Only send it from a server you control.

Capture one event

From a backend, authorize with the x-secret-key header and send the event in the body:

curl https://api.voidhash.com/i/v1/capture \
  -H "Content-Type: application/json" \
  -H "x-secret-key: $VOIDHASH_SECRET_KEY" \
  -d '{
    "sent_at": "2026-08-14T12:00:01.000Z",
    "uuid": "018f6d2e-4c3a-7b1d-9e5f-2a8c1b0d4e6f",
    "event": "paywall_viewed",
    "distinct_id": "user_123",
    "properties": { "location": "onboarding" },
    "context": { "platform": "ios", "app_version": "2.4.0" },
    "timestamp": "2026-08-14T12:00:00.000Z"
  }'

From a distributed client, drop the header and put the publishable token in the body instead:

curl https://api.voidhash.com/i/v1/capture \
  -H "Content-Type: application/json" \
  -d '{
    "token": "vh_pk_...",
    "sent_at": "2026-08-14T12:00:01.000Z",
    "uuid": "018f6d2e-4c3a-7b1d-9e5f-2a8c1b0d4e6f",
    "event": "paywall_viewed",
    "distinct_id": "user_123",
    "properties": {},
    "context": {}
  }'

Every event must include uuid, event, distinct_id, properties, and context. The request itself must include sent_at and exactly one credential.

The uuid is the deduplication key. Generate it once per event and reuse the same value if you retry, so a retried event is not counted twice.

Batch events

POST /i/v1/batch accepts the same event objects under an events array. The request has one request-level sent_at and the same credential choice as a single capture:

{
  "sent_at": "2026-08-14T12:00:05.000Z",
  "events": [
    {
      "uuid": "018f6d2e-4c3a-7b1d-9e5f-2a8c1b0d4e6f",
      "event": "paywall_viewed",
      "distinct_id": "user_123",
      "properties": {},
      "context": {}
    }
  ]
}

Clients using a publishable token add "token": "vh_pk_..." next to sent_at.

A successful request returns 202 with accepted and rejected counts. Log the x-request-id response header so you can reference it when diagnosing ingestion.

Analytics consent

Send x-analytics-consent: denied or x-analytics-consent: pending when the end user has not granted usage analytics. Voidhash then stores none of the request's events: the response is still 202, with every event counted as rejected, so the client does not retry them. Omit the header, or send granted, to record the events. The Voidhash SDKs send this header for you and stop capturing while consent is withheld.

Retries

Retry network failures, 429, 500, and 503 responses with exponential backoff. Honor the retry-after header when it is present, and resend the same UUIDs so retries deduplicate.

Do not retry 400, 401, or 413 responses. Those indicate a problem with the request itself, so fix it and send again.

See the generated Event Capture endpoint pages for complete schemas and error bodies.

On this page

Choose a credentialCapture one eventBatch eventsAnalytics consentRetries