View this page as Markdown • #docs #ingest #overview

Ingest API v3

Use the TelemetryDeck Ingest API v3 to send flat events to TelemetryDeck

Usually you’ll send events to TelemetryDeck using one of our SDKs. However, if you’re working with a language or framework that we don’t have an SDK for, you can send events directly to our Ingest API.

Ingest API v3 is the newest version of the API. It differs from v2 in two ways:

  • Events are flat. There is no payload object. Every parameter sits at the top level of the event.
  • Values keep their JSON type. A number stays a number, and a boolean stays a boolean.

The v2 API stays available.

Endpoints

The v3 API has two endpoints. Both live on https://nom.telemetrydeck.com.

EndpointPurposeRequest body
POST /v3/{namespace}/Events from apps, games, and serversAn array of events
POST /v3/w/Website events, as sent by the Web SDKA single event object

Send the headers Content-Type: application/json and charset=utf-8. The trailing slash is optional. The path segment w is reserved for the web endpoint, so you cannot use w as a namespace.

Events Endpoint

Send your events as a POST request to https://nom.telemetrydeck.com/v3/{namespace}/.

Replace {namespace} with your organization’s TelemetryDeck namespace. You can find your namespace in the TelemetryDeck Dashboard. The namespace is required in v3. There is no endpoint without one.

Here’s an example in cURL:

curl -X "POST" "https://nom.telemetrydeck.com/v3/your-namespace/" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d $'[
        {
          "appID": "AAAA-BBBBBBBB-CCCC-DDDD",
          "clientUser": "myClientUserHash",
          "receivedAt": "2026-09-24T10:15:00+00:00",
          "type": "Actions.LoginView.loginButtonSucceeded",
          "sessionID": "mySessionID",
          "isTestMode": "false",
          "floatValue": 3.14159,
          "TelemetryDeck.RunContext.locale": "en_US",
          "TelemetryDeck.Device.architecture": "x86_64"
        }
      ]'

Body Structure

The post body must be an array of JSON objects, because you can send multiple events at once. Each event is a flat object. Required properties, optional properties, and your own parameters all sit at the top level.

Each event must have these properties. All three must be strings.

PropertyTypeDescription
appIDstringYour app’s ID. We recommend always setting it. The server accepts an empty string only because the namespace in the URL already identifies your organization.
clientUserstringAn identifier for the user, for example a hash of their user ID. This should always be the same for the same user. The server salts and hashes this value with SHA256 before it stores the event.
receivedAtstringThe date and time at which the event happened, as an ISO 8601 string with time zone, for example 2026-09-24T10:15:00+00:00. Unlike v2, the server stores this value as sent and does not move it into the last 24 hours.

These properties are optional:

PropertyTypeDescription
typestringThe type of event. The server accepts an event without a type, but the dashboard needs one, so always send it. We recommend structuring your event names in scopes separated by dots, with the event type beginning with a lowercase letter and any scope beginning with an uppercase letter.
sessionIDstringThe user’s session ID. This should be the same value for the same session/user combination. Unlike v2, the server does not generate a session ID when this is missing.
isTestModestringSend "true" to exclude the event from production queries, otherwise "false". Always send this value: the server adds no default in v3, and every dashboard query filters on it, so an event without it does not show up in the dashboard.
floatValuenumberA numeric measurement. Use for any numeric operations, such as building averages or sums.
any other keyany JSON valueYour own parameters. See below.

Custom Parameters

Add your own parameters as further top-level keys of the event. Keys should be in the format Scope.OptionalSubScope.key, with the scopes capitalized and the key starting with a lowercase letter. This is not enforced but helps you organize your dimensions and fit in better with TelemetryDeck’s internal keys.

Values keep their JSON type. Strings, numbers, and booleans are stored as sent. The event must not contain nested objects. The behavior of arrays is left undefined and should be avoided (except if you have a deep knowledge of multi-value dimensions in Apache Druid).

The server does not rename or clean your keys in v3. Use only letters, digits, dots, and underscores in key names.

Properties Added by the Server

The server changes or adds these properties before it stores the event. Everything else passes through untouched.

PropertyValue
clientUserReplaced by the salted SHA256 hash of the value you sent.
TelemetryDeck.API.namespaceThe namespace from the URL.
TelemetryDeck.API.Ingest.versionevents.v3

Unlike v2, the server does not add the legacy payload list or the telemetryAPIVersion property.

Responses

StatusBodyMeaning
200The number of accepted events, for example 2All events were accepted. An empty array returns 0.
422A JSON error messageThe body is not a JSON array, or at least one event is invalid. The server checks the whole batch before it stores anything, so a single invalid event rejects the whole request and nothing is stored.
503queue is full, retry laterThe server cannot accept events right now. The response carries a Retry-After: 5 header. Wait 5 seconds and send the batch again.

An event is invalid if:

  • appID, clientUser, or receivedAt is missing or not a string,
  • appID is empty and the namespace in the URL is blank,
  • receivedAt is not a valid ISO 8601 date/time.

Web Events Endpoint

Send website events as a POST request to https://nom.telemetrydeck.com/v3/w/. This is the endpoint the Web SDK 3.0 uses. The server derives browser, system, location, and campaign data from the request, so the client only needs to send the URL.

The endpoint takes exactly one event per request. The body is a single JSON object, not an array.

The server parses the body as JSON no matter which Content-Type header the request carries. The Web SDK uses this to send its last event with navigator.sendBeacon() as text/plain, which needs no CORS preflight and therefore survives the page unload. The endpoint answers CORS preflight requests for any origin.

Here’s an example in cURL:

curl -X "POST" "https://nom.telemetrydeck.com/v3/w/" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' \
     -d $'{
        "appID": "AAAA-BBBBBBBB-CCCC-DDDD",
        "url": "https://example.com/blog/post?utm_source=newsletter",
        "referrer": "https://news.example.org/",
        "locale": "en-US",
        "isTestMode": "false"
      }'

Body Structure

Each web event must have these properties:

PropertyTypeDescription
urlstringThe full URL of the page, including the query string. Must not be empty. The server splits the URL into its parts and stores it without the query string and fragment.
appID or namespacestringYour app’s ID, or your organization’s namespace. At least one of the two must be a non-empty string. You can send both. The server uppercases appID. It stores namespace as TelemetryDeck.API.namespace and removes the namespace key.

These properties are optional:

PropertyTypeDescription
typestringThe type of event. Defaults to pageview.
receivedAtstringThe date and time at which the event happened, as an ISO 8601 string. Defaults to the time the server received the event.
isTestModeboolean or stringIf true or "true", the event is excluded from production queries. The server stores the value as the string "true" or "false". Defaults to "false".
referrerstringThe URL of the page that referred the visitor. Used to build TelemetryDeck.Navigation.identifier.
localestringThe visitor’s locale, for example en-US.
any other keyany JSON valueYour own parameters, stored as sent. See Custom Parameters above for the naming rules.

Do not send clientUser or sessionID. The server replaces both with its own visitor identifier, see below.

Properties Derived by the Server

The server adds these properties to every web event. If your event already contains one of these keys, the server value wins.

From the User-Agent header:

  • platform, systemVersion, majorSystemVersion, majorMinorSystemVersion
  • browser, browserVersion, device, modelName
  • isMobile, isTablet, isTouchCapable, isDesktop, isBot (booleans)

From the url:

  • url without query string and fragment, host, path, scheme
  • combinedSource, plus each of ref, source, src, utm_source, utm_medium, utm_campaign, utm_term, utm_content, MSCLKID, and GCLID that appears in the query string. All other query parameters are dropped.

From the visitor’s IP address:

  • country.isoCode, country.isInEuropeanUnion, continent.code

The server reads the IP address from the leftmost entry of the X-Forwarded-For header, or from the connection when that header is missing. The IP address itself is never stored.

Other properties:

  • TelemetryDeck.API.Ingest.version is set to web.v3.
  • TelemetryDeck.Navigation.identifier is set to referrer -> url, with the cleaned url.

See Default Parameters for a description of each property.

Visitor Identifiers

Web events use no cookies and no fingerprinting. The server builds clientUser from the app ID (or the namespace when there is no app ID), the visitor’s IP address, the User-Agent string, and a salt that changes every day. It hashes this with SHA256, then hashes the result again with a secret salt. The same visitor of the same site gets the same identifier within a day, and a new one the next day.

sessionID is set to the same value as clientUser.

This is the same construction that the v2 web endpoint uses, so user counts stay continuous when a site moves from an older Web SDK to version 3.0.

Responses

StatusBodyMeaning
200OKThe event was accepted.
422A JSON error messageThe body is not a JSON object, url is missing or empty, neither appID nor namespace is set, or receivedAt is not a valid ISO 8601 date/time.
503queue is full, retry laterThe server cannot accept events right now. The response carries a Retry-After: 5 header.

Events Sent by the Web SDK

Web SDK 3.0 sends two event types per page load to the web events endpoint. You can send the same events from your own code.

Every event from the Web SDK contains appID, url, referrer, locale, isTestMode (as the string "true" or "false"), TelemetryDeck.SDK.name (WebSDK), TelemetryDeck.SDK.version, and TelemetryDeck.SDK.nameAndVersion.

pageview

Sent when the page loads. The Web SDK sends no type, so the server sets it to pageview.

TelemetryDeck.Web.pageLeave

Sent once per page load, the first time the page is hidden or unloaded: tab switch, tab close, navigation away, or app switch on mobile. It does not fire again if the visitor returns to the tab. It carries these engagement parameters in addition to the base parameters:

PropertyTypeDescription
TelemetryDeck.PageEngagement.scrollDepthnumberThe deepest point of the page that has been in the viewport, as a percentage of the page height from 0 to 100. A page that fits in the viewport reports 100.
TelemetryDeck.PageEngagement.scrollDepthMilestonestringThe scroll depth rounded down to one of "0", "25", "50", "75", or "100". Use this for grouping.
TelemetryDeck.PageEngagement.engagedSecondsnumberWhole seconds the page was visible in the foreground. Time in a background tab is not counted.

Site owners can turn these events off with data-page-engagement="false", see the Web SDK guide.

Differences from v2

Topicv2v3
Custom parametersInside the payload objectAt the top level of the event
Value typesConverted to strings, except numbers inside payloadStored as sent
NamespaceOptional: URL path or TelemetryDeck.API.namespace in the payloadEvents: required in the URL path. Web: optional namespace property
receivedAtOptional, moved into the last 24 hoursEvents: required, stored as sent. Web: optional, defaults to now
sessionIDGenerated once a day when missingEvents: stored as sent, never generated. Web: always set by the server
isTestModeDefaults to "false"Events: no default, always send it. Web: defaults to "false"
Web request bodyOne object with a payloadOne flat object
Legacy payload list and telemetryAPIVersionAdded by the serverNot added
TelemetryDeck.API.Ingest.versionv2 for events, v2web for web eventsevents.v3 for events, web.v3 for web events
Response body on successOKEvents: the number of accepted events. Web: OK

Reserved Keys

Some keys are reserved for internal use by TelemetryDeck. See the complete list of reserved parameters which you’re not allowed to include in your events.

In general, avoid using parameter names that begin with the TelemetryDeck. scope, as this is reserved for parameters set by TelemetryDeck SDKs and the ingestion server.