Docs
APIAPI referenceSDK apps

POST /v1/projects/:projectId/sdk-apps/:appId/verify-tracking

Active probe — writes a synthetic event into Layers and returns whether the SDK install is healthy, plus whether each CAPI destination is configured.

View as Markdown
POST/v1/projects/:projectId/sdk-apps/:appId/verify-tracking
Phase 1stableidempotent
Auth
Bearer
Scope
sdk:write

Active probe of an SDK install. Writes a synthetic event into Layers and reads it back; returns a structured health report including whether each CAPI destination is configured.

This is the "is tracking healthy right now?" check. The probe writes a synthetic event into Layers, polls until it is readable, and returns a structured report.

The synthetic event stays inside Layers. It is written straight to your event store and is never forwarded to Meta, TikTok, or any other ad platform, so it cannot appear in a debugger UI and cannot touch an advertiser's reporting. That is deliberate: Meta's Conversions API documents that a test-coded event is not isolated — "Events sent with test_event_code are not dropped. They flow into Events Manager and are used for targeting and ads measurement purposes." (Meta docs) A probe that reached Meta would therefore skew the very numbers you are trying to verify.

What the probe proves is the Layers half of the pipeline — the app is recognized, events round-trip, real traffic exists — plus, statically, whether your Meta and TikTok CAPI credentials are complete. To confirm a platform is actually receiving forwarded conversions, use GET /v1/projects/:id/ads/capi-status, which reports each platform's own received count.

Use this for:

  • A "Test connection" button in your partner dashboard.
  • Post-deploy verification — fire after rolling a new SDK install.
  • Customer support — a structured diagnostic better than "send me a screenshot of Meta's debugger."

For passive signals (no synthetic event), see SDK healthlastEventAt, the events list, and capi-status are the right tools when you don't want to inject a test event.

Path parameters

  • projectId
    string (uuid)required
    Project the SDK app belongs to.
  • appId
    stringrequired
    SDK app id.

Body

Body (all optional)
  • expectedEvents
    string[]optional
    Event names you expect the SDK to be firing. Default: `["app_open"]`. The probe checks the timeline for each in the recent past and reports any missing in `missing[]`.
  • eventName
    stringoptionaldefault: "layers_verify_tracking"
    Event name for the synthetic test. Must start with `layers_`, so your own analytics can filter synthetic events out without matching a real event name.

Request

curl -X POST https://api.layers.com/v1/projects/$PROJECT_ID/sdk-apps/$APP_ID/verify-tracking \
  -H "Authorization: Bearer $LAYERS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "expectedEvents": ["app_open", "Purchase"]
  }'

Response

200Synchronous — the route waits up to 30s for round-trip confirmation.
{
  "status": "healthy",
  "lastEventAt": "2026-05-08T17:02:11.123Z",
  "expectedEvents": ["app_open", "Purchase"],
  "observedEvents": ["app_open", "Purchase", "session_start"],
  "missing": [],
  "samples": [
    {
      "event": "Purchase",
      "receivedAt": "2026-05-08T17:01:55.000Z",
      "payload": { "value": 9.99, "currency": "USD" }
    }
  ],
  "checks": [
    { "name": "ingest_endpoint_reachable", "passed": true },
    { "name": "app_id_recognized", "passed": true },
    { "name": "capi_meta_configured", "passed": true },
    { "name": "capi_tiktok_configured", "passed": true },
    { "name": "test_event_round_trip", "passed": true }
  ],
  "testEventCode": "TEST123",
  "syntheticEventId": "0f7c1d5e-2b64-4a19-9d2f-7c3a55e18b40"
}
200Status `no_install` — the SDK has never sent a single event.
{
  "status": "no_install",
  "lastEventAt": null,
  "expectedEvents": ["app_open"],
  "observedEvents": [],
  "missing": ["app_open"],
  "checks": [
    { "name": "ingest_endpoint_reachable", "passed": true },
    { "name": "app_id_recognized", "passed": true },
    { "name": "capi_meta_configured", "passed": false, "remedy": "Patch the SDK app's CAPI config: PATCH /v1/projects/:id/sdk-apps/:appId with capi.meta.{enabled, pixel_id, access_token_vault_id}." },
    { "name": "test_event_round_trip", "passed": false }
  ]
}

status values

StatusMeaningTypical remedy
healthySynthetic event arrived, expected events recently observed, all relays configured and dispatching.None — you're done.
missing_eventsTest event arrived but one or more expectedEvents is absent from the recent timeline.The SDK is installed but is not firing the events you expect. Check the SDK init code.
schema_driftEvents arrive but with property shapes Meta / TikTok will reject (missing revenue on Purchase, missing currency, etc.).Update the SDK call sites to include canonical properties.
no_installNo events ever, or test event never arrived.The SDK is not installed or not initialized. Walk through the install guide.

Per-check breakdown

Every response carries checks[] regardless of status. Each check has name, passed, and (when failed) remedy — a one-line fix description.

CheckWhat it confirms
ingest_endpoint_reachableLayers' ingest URL responds with 2xx. (Almost always passes — fails only during a Layers outage.)
app_id_recognizedThe appId exists in sdk_apps and is not soft-deleted.
capi_meta_configuredIf the project has a Meta CAPI config, it's complete (pixel id, vault token resolvable, enabled). Skipped if no Meta layer.
capi_tiktok_configuredSame for TikTok.
test_event_round_tripThe synthetic event arrived and was visible in sdk_events within the timeout.

Probe semantics

  • The probe writes the synthetic event straight into your Layers event store and never forwards it to Meta, TikTok, or any other ad platform. Nothing it does can reach a platform debugger or a platform's reporting.
  • testEventCode, when you supply one, is recorded on the synthetic event's properties and echoed back in the response so you can correlate it in your own downstream analytics. It stays inside Layers. It is a Layers-local correlation tag; Meta's own test_event_code is a different field with different semantics, and Meta states that events carrying it "are not dropped. They flow into Events Manager and are used for targeting and ads measurement purposes."
  • The probe does NOT count against the project's daily event quota.
  • Multiple concurrent probes are fine — each uses a unique testEventCode.

Errors

CodeWhen
NOT_FOUND:projectId or :appId doesn't exist in this org.
FORBIDDEN_SCOPEKey lacks sdk:write (or legacy projects:write).
RATE_LIMITEDMore than 10 probes per minute per app.

See also

On this page