Tracking pixels
These four endpoints manage a store's tracking pixels, the same list the merchant edits on the dashboard's pixel page (/dashboard/pixels). A store can hold seven types of pixel: Meta (Facebook), TikTok, Snapchat, Pinterest, Google Analytics, Google Tag Manager and Google Ads. What each platform needs, and how to check that its events arrive, is in the pixels guide.
The checks are syntactic only. A 201 means the ids are well formed, not that the ad platform accepted them. The server-side access token is write-only: no endpoint returns it, and has_token tells you whether one is stored.
Before you start
GETneedspixels:read.POST,PATCHandDELETEneedpixels:writeand anIdempotency-Key(see Idempotency). Keys created from the dashboard (Settings → API,/dashboard/api) carry both scopes. Scopes are frozen when a key is created, so an older key that lacks the one it needs answers403 forbidden: create a new key from the dashboard.- The plan sets how many pixels a store can hold: none on Free, one of each type on Pro, no limit on Unlimited and Enterprise. A personal key works only on a store with an active Enterprise plan. An installed app can also reach stores on Free or Pro, where the limit applies.
- A merchant can assign a pixel to products, categories or landing pages on the dashboard. The API neither reads nor changes these assignments.
| Scope | Description |
|---|---|
pixels:read | Read the store's tracking pixels. Access tokens are never returned. |
pixels:write | Add, update and delete tracking pixels. |
The pixel object
| Field | Type | Notes |
|---|---|---|
id | int | The pixel's id on DZBuild, used in the path of PATCH and DELETE. |
pixel_type | string | One of the seven types below. Fixed at creation. |
pixel_id | string | The pixel, tag or measurement id from the ad platform. Fixed at creation. |
pixel_name | string or null | Display name. |
has_token | bool | true when a server-side access token is stored. |
test_event_code | string or null | The test events code typed on the dashboard. The API cannot set it, and a PATCH that writes a field clears it. |
ad_account_id | string or null | The Pinterest ad account id. |
conversion_label | string or null | The Google Ads conversion label. |
is_active | bool | false keeps the pixel and stops its browser and server-side events. |
is_default | bool | Setting it to true clears it on the store's other pixels of the same type. Where a pixel loads does not depend on it. |
created_at, updated_at | string | YYYY-MM-DD HH:MM:SS, Algeria time. |
Pixel types
pixel_type | Platform | Server-side events |
|---|---|---|
facebook | Meta (Facebook) | Yes, when the pixel has an access token. |
tiktok | TikTok | Yes, when the pixel has an access token. |
snapchat | Snapchat | Yes, when the pixel has an access token. |
pinterest | Yes, when the pixel has an access token and an ad_account_id. | |
google_analytics | Google Analytics | No. |
gtm | Google Tag Manager | No. |
google_ads | Google Ads | No. conversion_label is read for this type only. |
A token sent for a type without server-side events is stored and never used.
Where a pixel loads
An active pixel with no assignments loads on every storefront page, landing pages included. A pixel the merchant assigned to products, categories or landing pages loads only on the matching pages, and its server-side events follow the same rule. A pixel created through the API starts with no assignments.
The access token
access_token is the server-side token copied from the ad platform's events manager. The API removes invisible characters and the spaces and quotes around it, then refuses the token with 422 invalid_access_token when it still contains <, a space or a line break, when it equals pixel_id, or when a facebook token is shorter than 40 characters.
- No endpoint returns the token. The change history keeps the mask
••••••••in its place. - On
PATCH, an empty string,nullor a value containing that mask keeps the stored token. A token can be replaced but not removed through the API: to drop it, delete the pixel and add it again without a token, which also drops its assignments.
GET /v1/pixels
The store's pixels, newest first, with the plan allowance in limits.
Auth: platform key with pixels:read.
Query parameters
| Param | Type | Default | Notes |
|---|---|---|---|
pixel_type | string | none | Only pixels of this type. An unknown type returns an empty list. |
limit | int | 50 | 1 to 200. |
cursor | string | none | next_cursor of the previous page. See Pagination. |
Request
curl 'https://api.dzbuild.app/v1/pixels?pixel_type=facebook' \
-H "Authorization: Bearer $DZ_KEY"
Response 200
{
"data": {
"items": [
{
"id": 12,
"pixel_type": "facebook",
"pixel_id": "123456789012345",
"pixel_name": "Main ad account",
"has_token": true,
"test_event_code": null,
"ad_account_id": null,
"conversion_label": null,
"is_active": true,
"is_default": false,
"created_at": "2026-10-01 14:20:05",
"updated_at": "2026-10-01 14:20:05"
}
],
"next_cursor": null,
"has_more": false,
"limits": {
"plan": "enterprise",
"can_add": true,
"per_type_limit": null,
"total_limit": null,
"counts": {
"facebook": 1,
"tiktok": 1,
"snapchat": 0,
"pinterest": 0,
"google_analytics": 1,
"gtm": 0,
"google_ads": 0
},
"total": 3
}
}
}
limits
limits comes with every page and describes the whole store, whatever pixel_type you filter on.
| Field | Meaning |
|---|---|
plan | The store plan the allowance comes from. |
can_add | false when the plan allows no pixels at all. It ignores the counts, so compare counts with per_type_limit before you add a pixel. |
per_type_limit | Pixels allowed per type, null for no limit. |
total_limit | Pixels allowed in total, null for no limit. |
counts | Pixels per type, with a key for each of the seven types. |
total | All the store's pixels, active or not. |
POST /v1/pixels
Adds a pixel and answers 201 with it.
Auth: platform key with pixels:write. Requires Idempotency-Key.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
pixel_type | string | yes | One of the seven types, in any letter case. type is accepted too. |
pixel_id | string | yes | 1 to 100 letters, digits, - or _. A facebook id is 15 to 17 digits, copied from Events Manager. |
pixel_name | string | no | Cut to 100 characters. name is accepted too. |
access_token | string | no | Follows the access token rules above. Omit it or send "" for a pixel without server-side events. |
ad_account_id | string | no | Cut to 64 characters. |
conversion_label | string | no | Cut to 64 characters. |
is_active | bool | no | Defaults to true. |
is_default | bool | no | Defaults to false. |
What the call checks
The checks run in this order, and the first one that fails gives the error. A refusal is stored against its Idempotency-Key for 24 hours: once you fix the cause, send the call again with a new Idempotency-Key.
pixel_typeis one of the seven types, otherwise422 invalid_pixel_type.pixel_idhas the right format, otherwise422 invalid_pixel_id.- The plan allows another pixel of this type, otherwise
409 limit_reached. - The store has no pixel of the same type with the same
pixel_id, otherwise409 pixel_exists. access_token, when sent, follows the access token rules, otherwise422 invalid_access_token.
Request
curl -X POST 'https://api.dzbuild.app/v1/pixels' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pixel-meta-main-1" \
-d '{"pixel_type": "facebook", "pixel_id": "123456789012345", "pixel_name": "Main ad account", "access_token": "EAAGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}'
Response 201
{
"data": {
"id": 12,
"pixel_type": "facebook",
"pixel_id": "123456789012345",
"pixel_name": "Main ad account",
"has_token": true,
"test_event_code": null,
"ad_account_id": null,
"conversion_label": null,
"is_active": true,
"is_default": false,
"created_at": "2026-10-01 14:20:05",
"updated_at": "2026-10-01 14:20:05"
}
}
PATCH /v1/pixels/{id}
Changes only the fields you send and answers 200 with the pixel. An empty body changes nothing.
Auth: platform key with pixels:write. Requires Idempotency-Key.
Body
| Field | Type | Notes |
|---|---|---|
pixel_name | string or null | Cut to 100 characters. null or "" clears it. |
access_token | string | A new token replaces the stored one. An empty string, null or the mask keeps it. |
ad_account_id | string or null | Cut to 64 characters. null or "" clears it. |
conversion_label | string or null | Cut to 64 characters. null or "" clears it. |
is_active | bool | false pauses the pixel and keeps it. |
is_default | bool | true clears it on the store's other pixels of the same type. |
pixel_type, type and pixel_id cannot be sent, even with their current value: the call answers 422 immutable_field. To change them, delete the pixel and add a new one.
Request
curl -X PATCH 'https://api.dzbuild.app/v1/pixels/12' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pixel-12-pause-1" \
-d '{"is_active": false}'
Response 200
{
"data": {
"id": 12,
"pixel_type": "facebook",
"pixel_id": "123456789012345",
"pixel_name": "Main ad account",
"has_token": true,
"test_event_code": null,
"ad_account_id": null,
"conversion_label": null,
"is_active": false,
"is_default": false,
"created_at": "2026-10-01 14:20:05",
"updated_at": "2026-10-02 09:05:41"
}
}
DELETE /v1/pixels/{id}
Deletes the pixel and its assignments to products, categories and landing pages.
Auth: platform key with pixels:write. Requires Idempotency-Key.
Request
curl -X DELETE 'https://api.dzbuild.app/v1/pixels/12' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: pixel-12-delete-1"
Response 200
{
"data": {
"deleted": true,
"id": 12
}
}
Undo
Each pixel write made through the API is recorded in the store's change history. The write answer carries no change id: find it with GET /v1/changes?entity=pixels, newest first, which needs store:read. POST /v1/changes/{id}/undo reverts one change and needs pixels:write and an Idempotency-Key. See Changes and undo.
- Undoing an update restores
pixel_name,ad_account_id,conversion_label,is_activeandis_default. The token is not in the history, so it stays as it is now. - Undoing a delete adds the pixel back with its old fields, and with its old
idwhen that id is still free, but without its access token and without its assignments. The plan limit and the duplicate check still apply, so this undo can answer409 limit_reachedor409 pixel_exists. - An added pixel cannot be undone: the undo answers
422 nothing_to_restore. Delete the pixel instead. - Undoing an update of a pixel deleted since then answers
422 restore_target_missing. - Pixel changes saved on the dashboard are not recorded, so they cannot be undone through the API.
- An installed app's token cannot read or undo changes: both answer
403 forbidden.
Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | bad_request | The body is not valid JSON, the pixel id in the path is not all digits, or Idempotency-Key is missing or malformed on POST, PATCH or DELETE. |
| 401 | unauthorized | Bad or missing key. |
| 402 | quota_exceeded | The store's monthly request quota is used up. See Rate limits. |
| 403 | forbidden | Missing scope: pixels:read or Missing scope: pixels:write, or API access requires an active Enterprise plan for a personal key whose store is not on an active Enterprise plan. |
| 404 | not_found | No pixel with this id in the store. A pixel of another store answers the same way. |
| 409 | limit_reached | The plan allows no more pixels of this type. |
| 409 | pixel_exists | The store already has a pixel of this type with this pixel_id. |
| 413 | payload_too_large | The body is over 1 MB. |
| 422 | invalid_pixel_type | pixel_type is missing or not one of the seven types. |
| 422 | invalid_pixel_id | pixel_id is missing, longer than 100 characters, holds a character other than letters, digits, - and _, or is a facebook id that is not 15 to 17 digits. |
| 422 | invalid_access_token | The token breaks one of the access token rules. |
| 422 | immutable_field | A PATCH sent pixel_type, type or pixel_id. |
| 422 | pixel_write_failed | The write was refused after the checks above passed. The message gives the reason and can be in Arabic. |
| 422 | idempotency_key_reuse | The same Idempotency-Key was used with a different method, path or body. |
| 429 | rate_limited | Too many requests. Wait for Retry-After. |
| 500 | server_error | The request failed. Retry with the same Idempotency-Key. |