Skip to main content

Server-Side Events

Send events from your backend to TraceLog using the server-to-server (S2S) webhook API. Use it to track backend outcomes like purchases, signups, subscriptions, refunds, or any event that originates outside the browser.

Endpoint

POST /webhooks/events

Base URL: https://api.tracelog.io

Authentication

Include your project API key in the x-api-key header:

x-api-key: your-project-api-key

You can find your API key in the TraceLog dashboard under Project Settings.

Request Body

FieldTypeRequiredDescription
event_idstringYesUnique event ID, used as idempotency key
event_namestringYesEvent name (e.g., purchase, signup)
timestampstringYesISO 8601 timestamp (must not be in the future)
customer_idstringNoYour system's user identifier
session_idstringNoTraceLog browser session ID for attribution linking
referrerstringNoAttribution source (fallback when session has no attribution)
utmobjectNoUTM parameters (fallback when session has no attribution)
metadataobjectNoArbitrary key-value payload

UTM Object

{
"source": "google",
"medium": "cpc",
"campaign": "spring-sale",
"term": "analytics",
"content": "banner-a"
}

Examples

Stripe Purchase

curl -X POST https://api.tracelog.io/webhooks/events \
-H "Content-Type: application/json" \
-H "x-api-key: your-project-api-key" \
-d '{
"event_id": "pi_3abc123",
"event_name": "purchase",
"timestamp": "2026-03-15T10:30:00Z",
"customer_id": "cus_xyz",
"session_id": "tl_sess_abc123",
"metadata": {
"amount": 49.99,
"currency": "USD",
"items": [{ "name": "Pro Plan", "quantity": 1 }]
}
}'

PayPal Purchase

curl -X POST https://api.tracelog.io/webhooks/events \
-H "Content-Type: application/json" \
-H "x-api-key: your-project-api-key" \
-d '{
"event_id": "PAY-1AB23456CD789012E",
"event_name": "purchase",
"timestamp": "2026-03-15T11:00:00Z",
"customer_id": "paypal-buyer@example.com",
"metadata": {
"amount": 29.99,
"currency": "EUR",
"gateway": "paypal"
}
}'

User Signup

curl -X POST https://api.tracelog.io/webhooks/events \
-H "Content-Type: application/json" \
-H "x-api-key: your-project-api-key" \
-d '{
"event_id": "signup-usr-456",
"event_name": "signup",
"timestamp": "2026-03-15T09:00:00Z",
"customer_id": "usr-456",
"session_id": "tl_sess_def789",
"metadata": {
"plan": "free",
"source": "organic"
}
}'

Server Event Without Session (with attribution)

When you don't have a browser session ID, you can provide referrer and utm fields for attribution:

curl -X POST https://api.tracelog.io/webhooks/events \
-H "Content-Type: application/json" \
-H "x-api-key: your-project-api-key" \
-d '{
"event_id": "sub-renewal-789",
"event_name": "subscription_renewal",
"timestamp": "2026-03-15T12:00:00Z",
"customer_id": "usr-789",
"referrer": "email-campaign",
"utm": {
"source": "email",
"medium": "newsletter",
"campaign": "march-renewal"
},
"metadata": {
"plan": "pro",
"amount": 19.99,
"currency": "USD"
}
}'

Refunds

TraceLog does not have a separate refund event type today. To make refunds subtract correctly from your revenue, AOV, and revenue-by-channel metrics, send them through this endpoint using your configured purchase event name with a negative amount.

Recipe

  1. Use the same event_name you have configured for purchases in your project's revenue tracking (typically purchase). Do not invent a separate refund event name — it would appear in the events catalog but would not subtract from revenue.
  2. Set the revenue field (amount, or whatever field you configured in revenue tracking) to a negative value.
  3. Use the refund ID from your payment processor as event_id so retries are safely idempotent.
  4. Optional but recommended: add type: "refund" to metadata so you can filter refunds vs sales in the Events explorer.
  5. If you stored the session_id of the original purchase, include it to preserve campaign attribution on the refund.

Example

curl -X POST https://api.tracelog.io/webhooks/events \
-H "Content-Type: application/json" \
-H "x-api-key: your-project-api-key" \
-d '{
"event_id": "re_3abc123",
"event_name": "purchase",
"timestamp": "2026-03-15T10:30:00Z",
"customer_id": "cus_xyz",
"session_id": "tl_sess_abc123",
"metadata": {
"amount": -49.99,
"currency": "EUR",
"type": "refund",
"reason": "customer_request",
"original_order_id": "ORD-789"
}
}'
tip

For partial refunds, use the partial amount in negative. For full refunds, mirror the original amount exactly.

Behavior

Idempotency

Duplicate event_id values are silently ignored and return { "processed": false }. Use natural identifiers from your payment processor or system (e.g., Stripe payment intent ID, order number) as event IDs to guarantee safe retries.

Session Linking

When session_id is provided, TraceLog links the event to the corresponding browser session and automatically inherits the session's UTM parameters and referrer. This means the event carries the same campaign attribution as the browsing session that originated the visit — no need to pass utm or referrer in the request.

If the session has no UTM data, the referrer and utm fields from the request body are used as a fallback.

tip

To get the session ID on the client side, call tracelog.getSessionId() and pass it to your backend during the checkout or signup flow. This is what links server-side conversions to browsing sessions and enables campaign revenue attribution in your dashboard.

Without Session

When no session_id is provided, TraceLog creates a synthetic single-event session. If referrer and/or utm fields are included, they are stored for attribution on that synthetic session.

info

Events without a session ID still appear in your analytics and can be classified as conversions in the Event Catalog. The only difference is that they won't be connected to a browsing session, so they won't appear in session-based metrics like conversion rate by traffic source.

Rate Limits

The endpoint allows 100 requests per 60 seconds per API key.

warning

If you exceed the rate limit, requests will return 429 Too Many Requests. For high-volume backends, implement a queue or batch processing to stay within the limit.