REVU Behavior Ingest API#

The single endpoint every REVU SDK targets to push captured events.

REVU SDKs capture behavioral events client-side, batch them, and POST them to this endpoint. The SDK only captures; the server validates, attributes, and stores. Authentication is a public, browser-embeddable write key (revu_pk_...) carried in the request body, not a secret header: it is a tenant identifier that grants only append access to one organization's event log. Ingest is idempotent on (organization, event_id), so retried batches are de-duplicated server-side.

This page is generated from the OpenAPI specification. Download it as openapi.json to drive a client generator, a mock server, or an AI agent integration.

Servers#

  • https://api.revu.ai - Production ingest
  • https://{host} - First-party ingest through your own domain (reverse proxy). See the web SDK first-party-ingest guide.

Authentication#

Authentication is a public write key (revu_pk_...) sent in the request body as api_key, not an Authorization header. The key is a tenant identifier safe to embed in client bundles; it grants only append access to one organization's event log. There are no cookies and no session.

POST /v1/behavior/events#

Ingest a batch of behavioral events

Accept a batch of captured events from a REVU SDK. The body carries the public api_key and a batch of 1 to 200 events. Returns 204 with an empty body on success. The SDK sends Content-Type: application/json; on page unload it uses navigator.sendBeacon with an application/json Blob so the terminal batch still parses.

Request body#

Content type: application/json

IngestBody#

FieldTypeRequiredConstraintsDescription
api_keystringyespattern: ^revu_pk_[A-Za-z0-9_-]{8,120}$Public ingest write key (prefix revu_pk_).
batcharray<BehaviorEvent>yesitems 1-200Up to 200 events per request.

BehaviorEvent#

FieldTypeRequiredConstraintsDescription
event_idstringyesformat: uuidClient-generated UUID. Unique per organization; the idempotency / dedupe key for retried batches.
anonymous_idstringyeslength 1-128First-party anonymous visitor (device) id assigned by the SDK.
user_idstring | nullnolength 0-128Identified user id, if any. Null when the visitor is not yet identified.
session_idstringyeslength 1-128Per-session id.
sequence_nointegeryesmin: 0Per-page-load monotonic counter starting at 0. Gaps indicate dropped events within a page load.
platformenumyesone of: web, ios, androidCapture platform.
event_typestringyeslength 1-120Event type: '$pageview', '$autocapture', or a custom name.
screenstringyeslength 0-2048Route / path at capture time.
fingerprintobject | nullnoElement descriptor, present for $autocapture interactions. Used server-side to name the interacted element.
propertiesobjectyesEvent payload: capture-layer fields (path, url, depth_percent, form structure, ...) plus caller-supplied custom properties. Client-side masked, PII-free, never input values.
contextobjectnoEngine environment bucket (unprefixed): user_agent, language, timezone, screen_ / viewport_, online, connection_*, environment, sdk_version, consent, gpc, sample_rate, and first/last-touch attribution. Optional: a client that omits it still validates.
device_timestringyesformat: date-timeISO-8601 capture timestamp from the client device.
BehaviorEvent.fingerprint#
FieldTypeRequiredConstraintsDescription
tagstringyesElement tag, e.g. 'button'.
textstring | nullnoVisible text (truncated; masked if sensitive).
rolestring | nullnoARIA role / type.
idstring | nullnoElement id, if present.
classesarray | nullnoClass list.
selectorstringyesBest-effort CSS selector (fragile; a tiebreaker).
ordinalnumbernoPosition among siblings.

Example requests#

A curl call (the SDK does this for you, batched and retried):

curl -X POST https://api.revu.ai/v1/behavior/events \
  -H "Content-Type: application/json" \
  -d '{"api_key":"revu_pk_example12345678","batch":[{"event_id":"f1d2c3b4-a5e6-4789-9abc-de0123456789","anonymous_id":"a0e1d2c3-b4a5-4677-8899-aabbccddeeff","user_id":null,"session_id":"11112222-3333-4444-5555-666677778888","sequence_no":0,"platform":"web","event_type":"$pageview","screen":"/pricing","properties":{"path":"/pricing","url":"https://acme.com/pricing"},"context":{"user_agent":"Mozilla/5.0 ...","language":"en-US","timezone":"Europe/Berlin","environment":"production","sdk_version":"0.1.0"},"device_time":"2026-06-21T18:04:05.123Z"}]}'

A single $pageview event#

{
  "api_key": "revu_pk_example12345678",
  "batch": [
    {
      "event_id": "f1d2c3b4-a5e6-4789-9abc-de0123456789",
      "anonymous_id": "a0e1d2c3-b4a5-4677-8899-aabbccddeeff",
      "user_id": null,
      "session_id": "11112222-3333-4444-5555-666677778888",
      "sequence_no": 0,
      "platform": "web",
      "event_type": "$pageview",
      "screen": "/pricing",
      "properties": {
        "path": "/pricing",
        "url": "https://acme.com/pricing"
      },
      "context": {
        "user_agent": "Mozilla/5.0 ...",
        "language": "en-US",
        "timezone": "Europe/Berlin",
        "environment": "production",
        "sdk_version": "0.1.0"
      },
      "device_time": "2026-06-21T18:04:05.123Z"
    }
  ]
}

An $autocapture click with an element fingerprint#

{
  "api_key": "revu_pk_example12345678",
  "batch": [
    {
      "event_id": "0a1b2c3d-4e5f-4061-8273-8495a6b7c8d9",
      "anonymous_id": "a0e1d2c3-b4a5-4677-8899-aabbccddeeff",
      "user_id": "user_8675309",
      "session_id": "11112222-3333-4444-5555-666677778888",
      "sequence_no": 4,
      "platform": "web",
      "event_type": "$autocapture",
      "screen": "/pricing",
      "fingerprint": {
        "tag": "button",
        "text": "Start free trial",
        "role": "button",
        "selector": "main > section.cta button.primary",
        "ordinal": 0
      },
      "properties": {
        "path": "/pricing"
      },
      "context": {
        "environment": "production",
        "sdk_version": "0.1.0"
      },
      "device_time": "2026-06-21T18:04:11.880Z"
    }
  ]
}

Responses#

StatusMeaning
204Batch accepted. Empty body. Already-seen event_ids in the batch are de-duplicated.
401The api_key is unknown, or its environment is inactive.
403The api_key is valid but the request Origin is not in the key's allowed-origins allowlist.
422The body failed schema validation (a missing or malformed field, or a batch outside 1 to 200 events).
429The api_key's per-minute rate limit is exhausted. Carries a Retry-After header (seconds). SDK transport treats this as a backoff-and-retry signal; events stay queued.
500Unexpected server error. The SDK backs off and retries; events stay queued client-side.

Every non-204 response carries this body:

Error#

FieldTypeRequiredConstraintsDescription
errorstringyesHuman-readable error message.
codestringyesStable machine-readable code: UNAUTHORIZED, FORBIDDEN, VALIDATION_ERROR, RATE_LIMIT_EXCEEDED, or OPERATION_FAILED.
timestampstringyesformat: date-timeISO-8601 time the error was produced.