TapCub is live — analytics, insights and live chat, free on one platform
Help center

How do I send events with the HTTP API?

Post business events and profile updates to /api/v1/track without an SDK: authentication, a first request in debug mode, fields and event types, the response, and errors, limits and retries.

Getting started4 min readLast updated Nov 6, 2026TapCub team

Short answer

Send a POST to https://api.pathclue.com/api/v1/track with a key that has the Server track scope in the Authorization: Bearer header and a JSON body {"events": [ … ]} holding 1 to 1,000 events. Add ?debug=1 while integrating: the server validates every event and returns per-item results without storing anything.

Use the HTTP API when there is no server SDK for your language, or when you send from a gateway or a job runner. If an SDK exists for your stack (Node.js, Python, PHP, Java, Go), prefer it: it already batches, retries and flushes. See Send events from your server.

Before you start

  • Create a project API key with the Server track (track:write) scope: Create and manage API keys.
  • Keep the key on the server only, for example in TAPCUB_API_KEY.
  • Keep pageviews on the website script. The HTTP API is for business events (orders, payments, sign-ups) and profile updates, not for page views.

Send your first event

curl -X POST "https://api.pathclue.com/api/v1/track?debug=1" \
  -H "Authorization: Bearer $TAPCUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [{
      "type": "track",
      "event": "purchase",
      "login_id": "u_1001",
      "insert_id": "ord_1001",
      "time": 1759363200123,
      "properties": { "revenue": 19.9, "currency": "USD" },
      "context": { "platform": "server" }
    }]
  }'

A debug response has debug: true and one entry in results per event, with any warnings. When it is clean, remove ?debug=1 and send again. The event appears in All-platform analytics › Data › Events & properties.

Event fields

FieldNotes
typeDefaults to track. See the table below
eventEvent name, 1 to 100 characters. Required for track
login_id / device_idWho did it. Use login_id for signed-in users; device_id (up to 72 characters) for anonymous ones
timeUnix milliseconds. More than 72 hours from the server clock is replaced with the current time and returned as a warning
insert_idUp to 36 characters. Idempotency key: the first event with this ID is kept. Use the order or payment ID
session_idUp to 32 characters. Without it the event is stored but does not join session metrics
propertiesEvent or profile properties
grouptype:id, for example company:acme, to attach the event to an account
contextip, user_agent, url, platform, country, lang, and campaign for sign-up attribution

Event types

typeUse it to
trackRecord a business event (the default)
track_signupRecord a sign-up and link the anonymous device to the new login_id
bind / unbindAdd or remove identities such as email or mobile (sent in identities)
profile_set, profile_set_once, profile_unset, profile_increment, profile_appendUpdate user profile properties
item_set / item_deleteWrite dimension rows such as products or articles, with item_type and item_id
track_update / track_overwriteMerge into or replace a stored event's properties; insert_id is required
group_setSet traits of an account (group)

Example: update a profile and bind an email in one request.

{ "events": [
  { "type": "profile_set", "login_id": "u_1001", "properties": { "plan": "pro", "$name": "Ada" } },
  { "type": "bind", "login_id": "u_1001", "identities": { "email": "ada@example.com" } }
] }

An email or mobile that is not already a 64-character hex hash is hashed by the server before storage, and the item returns the warning plaintext_identity_hashed. Hash it yourself (SHA-256) to avoid sending plaintext at all.

Read the response

A successful call returns received, accepted, rejected, events (rows queued) and results. Outside debug mode results lists only items that failed or produced a warning: index is the item's position in events, and ok: false means that item was not stored. Other items in the same request are still accepted.

Add validation_behavior=enforce to the query to reject any item that produces a warning, for example to make sure no plaintext email is ever accepted.

Errors, limits and retries

ResponseMeaningWhat to do
400 VALIDATIONThe body breaks the schemaRead issues; the whole request is rejected
401 NO_API_KEY / BAD_API_KEYKey missing, wrong, revoked or expiredCheck the header and the key
403Key lacks the Server track scopeUse a key with track:write
413 PAYLOAD_TOO_LARGEBody over 2 MBSplit into smaller batches
429 RATE_LIMITOver 600 requests per minute for this keyWait retryAfter seconds, then retry with backoff
5xxServer errorRetry with exponential backoff

Retry rules: keep the same insert_id on every retry so nothing is counted twice, back off exponentially, cap the number of attempts, and batch events (up to 1,000 per request) instead of sending one request per event.

Related

Did this answer your question?

We use your answers to fix and expand this page.

See your data clearly. Find your growth.

Every click, backed by data. Install one line of code and see your first numbers in a minute.

No credit card · Free plans for analytics and chat · Cookieless analytics