HTTP API
Send events from any language or platform with a single HTTP request. No library needed
Base URL and keys#
- Base URL:
https://events.sfere.io - Key: a server key for backend code. See Write keys.
Authenticate with Basic auth: the key is the username and the password is empty. In curl that is -u 'keyId:secret:'. You can also send the key in an X-Write-Key header.
Send one event#
POST /api/s/s2s/{type}, where {type} is track, page, screen, identify, group or alias.
curl https://events.sfere.io/api/s/s2s/track \
-u 'YOUR_SERVER_KEY:' \
-H 'Content-Type: application/json' \
-d '{
"messageId": "order-98765-purchase",
"userId": "user_1234",
"event": "purchase",
"timestamp": "2026-10-21T10:00:00.000Z",
"properties": {
"transaction_id": "order_98765",
"currency": "USD",
"value": 313,
"items": [{ "item_id": "sku_221", "item_name": "Linen Shirt", "price": 149, "quantity": 1 }],
"sfere_dedup_id": "order-98765-purchase"
},
"context": {
"ip": "203.0.113.7",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)",
"traits": { "email": "customer@example.com", "phone": "+15555550123" },
"page": { "url": "https://shop.example.com/checkout/thanks" }
}
}'Replace YOUR_SERVER_KEY with the full keyId:secret value. The trailing colon is the empty password.
Identify a customer:
curl https://events.sfere.io/api/s/s2s/identify -u 'YOUR_SERVER_KEY:' -H 'Content-Type: application/json' \
-d '{ "userId": "user_1234", "traits": { "email": "customer@example.com", "first_name": "Sara" } }'Send a batch#
POST /v1/batch takes many events in one request. Each item needs a type, and a top-level context applies to every item. Keep each event under 1 MB.
curl https://events.sfere.io/v1/batch -u 'YOUR_SERVER_KEY:' -H 'Content-Type: application/json' \
-d '{
"batch": [
{ "type": "identify", "messageId": "m-1", "userId": "user_1234", "traits": { "email": "customer@example.com" } },
{ "type": "track", "messageId": "m-2", "userId": "user_1234", "event": "add_to_cart",
"properties": { "currency": "USD", "value": 149, "items": [{ "item_id": "sku_221", "price": 149, "quantity": 1 }] } }
],
"context": { "ip": "203.0.113.7", "userAgent": "Mozilla/5.0" }
}'Fields#
| Field | Required | Notes |
|---|---|---|
type |
Batch only | On / the path sets it. |
userId or anonymousId |
One of them | Use anonymousId for visitors who have not signed in. |
messageId |
Recommended | Unique per event: letters, digits, ., _ and -, up to 64 characters. Make it stable, such as order-98765-purchase, so a retried request is not counted twice. |
event |
For track |
A GA4 name such as purchase, up to 128 characters. See Track events. |
timestamp |
No | ISO 8601. Defaults to when Sfere received the event. |
properties, traits |
No | Plain values. Do not hash email or phone. |
context.ip, context.userAgent |
Yes, from a backend | The customer’s, taken from their original request. Sfere cannot fill these in for server events, and ad platforms need them to match conversions. |
context.clientIds |
Recommended | Ad identifiers from the customer’s cookies and landing URL, such as fbp, fbc, ttp and gclid. |
properties.sfere_dedup_id |
When the browser sends the same event | Use the same value on both sides so destinations count the conversion once. |
Every distinct property name becomes a column in your warehouse, so keep payloads flat and consistent.
Responses#
| Endpoint | Success | Failure |
|---|---|---|
/ |
200 {"ok":true,"receivedEvents":2,"okEvents":2} |
401 for an invalid key. okEvents lower than receivedEvents means some events were rejected. |
/ |
200 |
A wrong or missing key also returns 200, with the reason in the body. Read the body, or use / when you need a clear error. |
Retry only on 429 and 5xx, with backoff. Events over 1 MB are rejected.