# POST /v1/projects/:projectId/sdk-apps/:appId/verify-tracking (/docs/api/reference/sdk-apps/verify-tracking)



<Endpoint method="POST" path="/v1/projects/:projectId/sdk-apps/:appId/verify-tracking" scope="sdk:write" phase="1">
  Active probe of an SDK install. Sends a synthetic test event into the ingest pipeline; returns a structured health report including per-platform CAPI dispatch confirmation.
</Endpoint>

This is the "is tracking healthy *right now*?" check. The probe sends a synthetic event tagged `test_event_code` (visible in Meta's Event Manager debugger and TikTok's Event Manager test view), waits up to 30 seconds for round-trip confirmation, and returns a structured report.

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 health](/docs/api/concepts/sdk-health) — `lastEventAt`, the events list, and `capi-status` are the right tools when you don't want to inject a test event.

## Path parameters [#path-parameters]

<Parameters
  rows="[
  { name: 'projectId', type: 'string (uuid)', required: true, description: 'Project the SDK app belongs to.' },
  { name: 'appId', type: 'string', required: true, description: 'SDK app id.' },
]"
/>

## Body [#body]

<Parameters
  title="Body (all optional)"
  rows="[
  { name: 'expectedEvents', type: 'string[]', description: 'Event names you expect the SDK to be firing. Default: `[&#x22;app_open&#x22;]`. The probe checks the timeline for each in the recent past and reports any missing in `missing[]`.' },
  { name: 'sampleEventName', type: 'string', default: '&#x22;layers_test_event&#x22;', description: 'Event name for the synthetic test. Pick one your team can recognize in platform debuggers.' },
]"
/>

## Request [#request]

```bash
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 [#response]

<Response status="200" description="Synchronous — the route waits up to 30s for round-trip confirmation.">
  ```json
  {
    "status": "healthy",
    "lastEventAt": "2026-05-08T17:02:11.123Z",
    "expectedEvents": ["app_open", "Purchase"],
    "observedEvents": ["app_open", "Purchase", "session_start"],
    "missing": [],
    "samples": [
      {
        "name": "Purchase",
        "receivedAt": "2026-05-08T17:01:55.000Z",
        "platforms": [
          { "platform": "meta", "forwarded": true, "fbtrace_id": "AbCDeFg..." },
          { "platform": "tiktok", "forwarded": true, "request_id": "abc123" }
        ]
      }
    ],
    "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"
  }
  ```
</Response>

<Response status="200" description="Status `no_install` — the SDK has never sent a single event.">
  ```json
  {
    "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 }
    ]
  }
  ```
</Response>

## `status` values [#status-values]

| Status           | Meaning                                                                                                                       | Typical remedy                                                                                       |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `healthy`        | Synthetic event arrived, expected events recently observed, all relays configured and dispatching.                            | None — you're done.                                                                                  |
| `missing_events` | Test 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_drift`   | Events 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_install`     | No events ever, or test event never arrived.                                                                                  | The SDK is not installed or not initialized. Walk through the [install guide](/docs/sdk/quickstart). |

## Per-check breakdown [#per-check-breakdown]

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

| Check                       | What it confirms                                                                                                            |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `ingest_endpoint_reachable` | Layers' ingest URL responds with 2xx. (Almost always passes — fails only during a Layers outage.)                           |
| `app_id_recognized`         | The `appId` exists in `sdk_apps` and is not soft-deleted.                                                                   |
| `capi_meta_configured`      | If the project has a Meta CAPI config, it's complete (pixel id, vault token resolvable, enabled). Skipped if no Meta layer. |
| `capi_tiktok_configured`    | Same for TikTok.                                                                                                            |
| `test_event_round_trip`     | The synthetic event arrived and was visible in `sdk_events` within the timeout.                                             |

## Probe semantics [#probe-semantics]

* The probe injects a synthetic `sample_event` with `test_event_code` set so Meta and TikTok render it in their debugger UIs only — production reporting ignores it.
* The probe does NOT count against the project's daily event quota.
* Multiple concurrent probes are fine — each uses a unique `testEventCode`.

## Errors [#errors]

| Code              | When                                                |
| ----------------- | --------------------------------------------------- |
| `NOT_FOUND`       | `:projectId` or `:appId` doesn't exist in this org. |
| `FORBIDDEN_SCOPE` | Key lacks `sdk:write` (or legacy `projects:write`). |
| `RATE_LIMITED`    | More than 10 probes per minute per app.             |

## See also [#see-also]

* [SDK health concept](/docs/api/concepts/sdk-health)
* [`GET /v1/projects/:id/ads/capi-status`](/docs/api/reference/ads/capi-status) — passive CAPI health
* [`PATCH /v1/projects/:id/sdk-apps/:appId`](/docs/api/reference/sdk-apps/patch-sdk-app) — wire up CAPI config
* [`POST /v1/events`](/docs/api/reference/events/forward) — server-side event forwarding
