Skip to main content

What this is

The Server-to-Server (S2S) source lets your backend send customer events, user profiles, and non-customer entity data directly to Zeotap CDP over HTTP. You create the source in the Sources application, receive a write key and API URL, and then POST JSON payloads from your server — either one event at a time (Real Time API) or bundled together (Batch API). Use this source when you own the emitting system and want an authenticated, JSON-first ingestion path without an intermediary file drop or SDK.

Prerequisites

Before you begin, confirm the following:
  • You have access to the Sources application in the Zeotap CDP App with permission to create a source.
  • You know which region your data must be stored in (for example, EU) and which Data Entity applies — Customer Data or Non Customer Data. See Supported data entities.
  • Your server can make authenticated HTTPS POST requests and build a Base64-encoded Authorization header.
  • Every event your server sends will include at least one user identifier and the user’s country — Zeotap cannot infer cookies, MAIDs, or IP-derived country in server-to-server calls.

Create the Server-to-Server source

Perform these steps in the Zeotap CDP App:
  1. Open the Sources application and click CREATE SOURCE.
  2. Choose Server to Server as the Category, then click HTTP API as the Data Source.
    Choosing Server to Server as the Category in the source creation flow
    Selecting HTTP API as the Data Source
  3. In the source creation window, enter:
    1. A short, descriptive name for the source.
    2. The region of upload where the data will be stored. See Region of storage for guidance.
    3. Under Data Entity, choose Customer Data or Non Customer Data depending on the payload you plan to send.
    Source creation window with the name, region, and Data Entity fields
  4. Click + Create Source. The new source appears on the source listing page with the Created status.
    Source listing page showing the new source with the Created status
  5. Open the IMPLEMENTATION DETAILS tab. Copy the write key and API URL — these are the credentials your server uses to authenticate and the endpoint it will call.
    IMPLEMENTATION DETAILS tab showing the write key and API URL
Wait 30 minutes after source creation before using the write key. Requests made before the key propagates will fail authentication.

Send data with the HTTP API

After the write key is active, your server can send data through the Real Time API (one event per call) or the Batch API (an array of events per call). The endpoint, authentication, and headers are identical for both — the difference is the payload shape.

Build the request

  1. Use the API URL from the IMPLEMENTATION DETAILS tab as the endpoint URL.
  2. Add the following query parameters to the URL:
    • region — the region code matching the source (for example, EU).
    • eventType — set to s2s.
    Params section showing the region and eventType query parameters
  3. Set the request headers:
    • Content-Type: application/json; charset=UTF-8
    • Authorization: Basic base64(w_k:<your_write_key>)
To construct the Authorization header value, prefix your write key with w_k: (no spaces), Base64-encode the result, and prepend Basic (with a trailing space). For example, if your write key is fc3ab803-5762-44d3-88d3-7fbc94bca074:
Authorization header with the Base64-encoded write key entered in the request headers
When you test the request in a tool such as Postman, set the Authorization tab’s Auth Type to Inherit auth from parent so the Authorization header you defined above is used as-is.
Postman Authorization tab with Auth Type set to Inherit auth from parent

Send a Real Time API request

The Real Time API accepts a single event per request. Skeletal payload:

Send a Batch API request

The Batch API wraps an array of events under a top-level events key. Setup and authentication are identical to Real Time — only the body shape changes:
Keep each Batch payload at or below 20 MB.

Verify the integration

Send a test request from your server (or from an API tool such as Postman). You have integrated the source correctly when all three of the following are true:
  • The API returns HTTP 204 No Content.
  • On the source listing page, the source transitions from Created to INTEGRATED.
  • The PREVIEW tab of the source shows the incoming records.
Successful test request returning HTTP 204 No Content
Source listing page showing the source in the INTEGRATED state
If the response is not 204, work through the troubleshooting section below.

Troubleshoot request failures

Zeotap returns these HTTP responses for S2S requests: When you receive 400 Bad Request, work through these checks in order:
  1. Query parameters — confirm region is set to a valid region code (for example, EU) and eventType is set to s2s.
  2. Endpoint and headers — confirm the request was POSTed to the API URL from the IMPLEMENTATION DETAILS tab, and that the Authorization header follows the Basic base64(w_k:<your_write_key>) format shown in Build the request.
  3. Request body — validate the JSON payload against a JSON linter, and confirm each event includes a user identifier and the user’s country.
  4. Debug detail — read the value of the x-zeo-debug response header. It contains the specific error string the API returned for this request; use it as the starting point for the next fix.
If the request still fails after these checks, contact the Zeotap Support team at support@zeotap.com. Include in your request: the source name, the region and eventType you posted with, the exact value of the x-zeo-debug response header, an anonymized copy of the request body, and the timestamp of the failing request.

JSON payload structuring guidelines

Structure the payload body around the type of data you are sending:
  • Event data — send event information in the event object. eventName and eventTimestamp are the primary fields. Additional event attributes (for example, "discountSelected": "SPL25" or "cartVal": 100) belong inside the same event object.
  • Page data — send page metadata such as URL, referrer, category, domain, and path in the page object.
  • User data — send user identifiers and profile fields in the user object. To attach profile information to an ID without a separate business event, set eventName to setUserProperties.
  • Consent data — send per-purpose consent values, together with the applicable regulation, in the consent object.
  • Device data — send OS, browser, device model, and similar attributes in the device object.
  • User identification — Zeotap does not fetch cookies or MAIDs automatically in server-to-server calls, so every payload must carry at least one user ID. For known users, attach hashed email, loginID, or phone number along with any device-based IDs. For anonymous users, attach device-based IDs such as first-party cookies, third-party cookies, or MAIDs.
  • Country identification — Zeotap does not infer country from IP in server-to-server calls. Every payload must include a country value; when country is absent from the source data, hard-code it in the mapping and ingestion configuration for the source.
Zeotap supports flexible, configurable mapping of JSON structures from external systems. Ensure your data includes:
  • User information — user identifier(s).
  • Personal information — the personal fields you want ingested.
  • Event data — event name and timestamp. Use either a UNIX timestamp or a fully time-zone-qualified ISO 8601 value (for example, 2024-09-05T11:02:44Z, 2024-09-04T23:02:44−12:00, or 2024-09-05T11:02:44+00:00).
Use data types that match the source data — numeric for numbers, strings for text, booleans for true/false, JSON objects for structured data, arrays for lists, and null where applicable.

Sample payloads

Real Time API payload

Batch API payload

NCE Batch API payload

Non-Customer Entity (NCE) payloads carry only the event object per event — user, consent, and page are not required.

Performance

Query per second

The ingestion cluster auto-scales, so it supports high query-per-second (QPS) volumes. Contact your Zeotap point of contact ahead of time to enable active monitoring if you expect sustained QPS above 200.

Batch size

Keep each Batch API payload at or below 20 MB.

FAQ

Newly issued write keys need 30 minutes to propagate before Zeotap accepts them for authentication. Wait 30 minutes after clicking + Create Source, then retry the request.
A successful call returns HTTP 204 No Content, the source transitions from Created to INTEGRATED on the source listing page, and the records appear in the source’s PREVIEW tab.
Every payload must carry at least one user identifier and a country value. For known users, attach hashed email, loginID, or phone number alongside any device-based IDs. For anonymous users, attach a device-based ID such as a first-party cookie, third-party cookie, or MAID.
No. The Batch API uses the same endpoint, Authorization header, and Content-Type as the Real Time API. The only difference is the body shape — batched events are wrapped in a top-level events array.

Next steps

Last modified on September 8, 2026