pixellint

Blog · TikTok Events API

TikTok Events API 2.0 is one endpoint. Web, app, offline, and CRM are event_source, not three hosts.

TikTok Events API 2.0 posts one JSON body to open_api/v1.3/event/track. Web, app, offline, and CRM are event_source values on that body. They are not three hosts.

The first integration most stacks will ship is the old pixel/track worker with the path rewritten, or a Meta Conversions API worker with the host rewritten. Both look close enough to ship. The live host is still business-api.tiktok.com. The field that tells TikTok which pipe this is sits at the root as event_source, not as three URLs.

TikTok for Business help still sells the consolidation: one API for websites, mobile apps, physical stores, and CRM systems. The help URL for a 2.0 setup walkthrough 404s. The contract is the live Events API 2.0 track page. App through that page is allowlist. Dedup is event_id plus event, with event_source_id, inside the window TikTok's Event Deduplication writeup still describes as 48 hours. ISO time on the old pixel path versus Unix seconds on 2.0 is still the dialect.

One path, four event_source values

POST https://business-api.tiktok.com/open_api/v1.3/event/track/ with Access-Token and Content-Type application/json. event_source is required. web means the events took place on a website and are measured by a Pixel Code. app means a TikTok App ID. offline means an Offline Event Set ID for a physical store. crm means a CRM Event Set ID from /crm/list/. event_source_id is required and has to match that enum. Putting a Pixel Code on event_source app is a miss that can still parse.

data is an object array. One event is one object. A batch can hold up to 1,000 events. More than 1,000 rejects the entire request. page is required for web. app is required for app. lead is required for CRM, including lead_id exported from TikTok. Offline events may only be Standard Events. CRM events may only be Custom Events. Web and app may be Standard or Custom. Do not copy Meta Purchase onto an offline set and assume the enum traveled.

user is the match object. email and phone are SHA-256 after the documented normalize. ip and user_agent stay plaintext. Hashing the IP because a Meta helper hashed em is how the event becomes unmatchable. ttclid is web only. ttp is the _ttp cookie Pixel SDK writes when cookies are on. You extract it and attach it. The server will not invent it.

App through 2.0 is allowlist

The track page says it twice. Reporting App Events using Events API 2.0 is currently an allowlist-only feature. Contact a TikTok representative. Posting event_source app with a TikTok App ID, an app object, and idfa is not a self-serve upgrade from web. A 200 with code 0 is still not permission you were never granted.

The app object needs app_id. iOS uses the App Store id. Android uses the Play package or the package name. att_status DENIED means TikTok will not use the PII in that app event for user-level matching. Copying a web body and flipping event_source to app leaves page.url hanging and drops the app object. The MMP postback you already run is not this endpoint. If you are not on the allowlist, keep event_source web for the pixel you actually have.

Unix on 2.0, ISO on the old pixel path

event_time is required on every 2.0 event. It is an integer Unix timestamp in seconds, UTC+0. The sample is 1687758765. Date.now() is milliseconds. Math.floor(Date.now() / 1000) is the helper 2.0 wants. Sending thirteen digits as event_time is the wrong unit. Sending an ISO string as event_time is the 1.0 field on the 2.0 clock.

Events API 1.0 still posts to /open_api/v1.3/pixel/track/ with pixel_code at the root and timestamp as an ISO 8601 string such as 2020-12-14T09:49:27Z. If timestamp is omitted, TikTok stamps the time it received the event. Events API for Web now says /event/track/ is the recommended endpoint. The clocks did not merge when the path did. ISO on the pixel-shaped body, Unix on 2.0.

A shared helper named event_time that already floors to seconds for Meta will look right on 2.0 and look like arrival time on 1.0 if you still POST timestamp as that integer. Keep both conversions at the edge. Do not store one string and hope the vendor infers the unit.

The body people will send first

An Events API 1.0 web body. This is not an Events API 2.0 track call.

{
  "pixel_code": "BU35TSQHT2A1QT375GMG",
  "event": "CompletePayment",
  "event_id": "order-123",
  "timestamp": "2025-11-12T18:04:00Z",
  "context": {
    "user": { "email": "64ec88ca..." },
    "page": { "url": "https://shop.example/checkout" }
  }
}

That object is a legal 1.0 pixel/track event if the hash is right. Posted to /event/track/ it is the wrong envelope: no event_source, no event_source_id, no data array, a string clock on a field 2.0 named event_time.

The 2.0 shape is event_source web, event_source_id as the Pixel Code, data[] with event, event_time as ten-digit seconds, and event_id when the browser pixel is also firing. page.url is required for web. 2.0 samples use Purchase. Browser ttq.track and 1.0 examples still use CompletePayment. Same event_id with different event names will not dedupe.

Names that do not translate

Dedup is event_id plus event, inside 48 hours

event_id is conditional and then required. If event_source is web and you send the same conversion from the browser pixel and Events API, event_id is required. If event_source is crm and you also upload CSV on Events Manager, event_id is required. TikTok uses event_source_id, event_id, and event to deduplicate the same event sent multiple times from one channel or across channels. The id may be hashed or unhashed. It has to be identical on both pipes. Two random UUIDs generated in GTM and in the worker are two purchases.

Adobe's TikTok Web Events API extension, which points at TikTok's Event Deduplication page, still states the window: duplicated events within five minutes are merged; any duplicate received within 48 hours is removed. Pixel detail still splits Browser, Server, and Server and Browser (counted once). If Server and Browser is near zero, the event_id values do not match.

TikTok for Business help lists the hybrid as the recommended web setup: Pixel plus Events API plus deduplication, consistent events and parameters, match keys passed back. It does not publish a conversion lift percentage. Agency recaps that invent a 15 to 25 percent lift are not a source. The help sentence is qualitative: Events API reports conversions the Pixel missed. Lint the envelope. Do not paste a lift number into a QBR.

TikTok uses the event_source_id, event_id and event to deduplicate the same event sent multiple times from a single channel or across multiple channels (for instance browser pixel and Events API).

TikTok Events API 2.0: report app, web, offline, or CRM events

What to do

Keep one internal event: name, UTC instant, order id, hashed email, landing URL, ttclid, ttp. At the edge, emit the 2.0 envelope. Convert the clock there: floor milliseconds to Unix seconds for event_time. Reuse the pixel event_id as the API event_id. Align the event string with the 2.0 supported list, then put that same string on ttq.track.

Do not point a shared CAPI JSON at a new path. App stays off this endpoint until TikTok allowlists you. Offline uses a Standard Event and an Offline Event Set ID. CRM uses a Custom Event, a CRM Event Set ID, and lead_id. A code other than 0 is the error; HTTP 200 with a non-zero code is not success.

The contract page for the field list is the Events API 2.0 track guide. This post is the market fact: web, app, offline, and CRM share one host, and the dialect is event_source plus Unix seconds, not three pixel/track clones. Pixellint is not affiliated with TikTok. Passing a linter means the artifact matches the published envelope. It does not mean Events Manager attributed the order.

Checklist

Sources

Contract pages

The dated argument is above. These pages are the field lists.

Open the TikTok Events API pack Docs