# SDK health & verification (/docs/api/concepts/sdk-health)



When a partner installs the Layers SDK in an end-customer's app, four signals tell you whether tracking is working. Each surfaces a different layer of the pipeline. Pick the right one for the question you're asking.

## The four signals [#the-four-signals]

| Signal          | Endpoint                                                                                                | What it tells you                                                                                                                                                     | Latency                                   |
| --------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `lastEventAt`   | [`GET /v1/projects/:id/sdk-apps/:appId`](/docs/api/reference/sdk-apps/get-sdk-app)                      | Wall-clock of the most recent event Layers received from this SDK app. &#x2A;*Passive.**                                                                              | Real-time.                                |
| Event timeline  | [`GET /v1/projects/:id/events`](/docs/api/reference/telemetry/events)                                   | The actual stream of events with timestamps, properties, user identity. &#x2A;*Passive.**                                                                             | Real-time.                                |
| CAPI status     | [`GET /v1/projects/:id/ads/capi-status`](/docs/api/reference/ads/capi-status)                           | Whether the CAPI relay is forwarding events to Meta / TikTok, including the per-platform `events_received` count from the platform side. &#x2A;*Passive, CAPI-only.** | 5–15 min lag (platform-side aggregation). |
| Verify-tracking | [`POST /v1/projects/:id/sdk-apps/:appId/verify-tracking`](/docs/api/reference/sdk-apps/verify-tracking) | Active probe — sends a synthetic test event tagged `test_event_code`; reports whether it was received and which platforms would forward it.                           | \< 30s.                                   |

## When to use which [#when-to-use-which]

**"Is the SDK installed at all?"** → check `lastEventAt`. If `null`, the SDK has never sent a single event from this app. If recent, the SDK is at least booting and emitting `app_open`.

**"Is the SDK emitting the events we expect?"** → list `events` filtered by `name`. Confirms specific events (`Purchase`, `Subscribe`, custom events) are firing in the right shape.

**"Is CAPI forwarding to Meta / TikTok?"** → `capi-status`. Returns per-platform configuration health (`pixel_id`, `access_token_vault_id`, `enabled`) plus `events_received` from the platform's perspective. A drift between Layers' send count and the platform's received count indicates a forwarding problem.

**"Is tracking healthy end-to-end *right now* — including for a quiet app?"** → `verify-tracking`. The active probe sends a synthetic event tagged `test_event_code` that Meta and TikTok both render in their event-debugger UIs. The partner doesn't need real user traffic; the probe round-trips in seconds and returns a structured `status` field.

## Verify-tracking response shape [#verify-tracking-response-shape]

```json
{
  "status": "healthy",
  "lastEventAt": "2026-05-08T17:02:11.123Z",
  "expectedEvents": ["app_open", "Purchase", "Subscribe"],
  "observedEvents": ["app_open", "Purchase", "Subscribe", "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 }
  ]
}
```

`status` enum: `"healthy"`, `"missing_events"`, `"schema_drift"`, `"no_install"`. Use it as a single boolean-ish gate; render the per-check breakdown as the diagnostic detail when not `"healthy"`.

## Pattern: partner dashboard widget [#pattern-partner-dashboard-widget]

```ts
async function renderSdkHealthBadge(projectId: string, appId: string) {
  const app = await fetch(`/v1/projects/${projectId}/sdk-apps/${appId}`).then(r => r.json());

  if (!app.lastEventAt) return { color: 'red', label: 'No events received' };

  const ageMs = Date.now() - new Date(app.lastEventAt).getTime();
  if (ageMs > 24 * 60 * 60 * 1000) {
    return { color: 'amber', label: `Last event ${Math.round(ageMs / 3600_000)}h ago` };
  }

  // For ads-running customers, also check CAPI:
  const capi = await fetch(`/v1/projects/${projectId}/ads/capi-status`).then(r => r.json());
  if (capi.meta?.enabled && capi.meta.events_received_24h === 0) {
    return { color: 'amber', label: 'Meta CAPI configured but receiving 0 events' };
  }

  return { color: 'green', label: 'SDK healthy' };
}
```

For the active probe path (e.g. a "Test connection" button in your dashboard):

```ts
const verify = await fetch(
  `/v1/projects/${projectId}/sdk-apps/${appId}/verify-tracking`,
  { method: 'POST' }
).then(r => r.json());

if (verify.status !== 'healthy') {
  showInstallTroubleshooting(verify.checks.filter(c => !c.passed));
}
```

## See also [#see-also]

* [`POST /v1/events`](/docs/api/reference/events/forward) — server-side event forwarding (when partners can't / won't ship the client SDK)
* [`POST /v1/projects/:id/sdk-apps/:appId/verify-tracking`](/docs/api/reference/sdk-apps/verify-tracking) — the active probe
* [SDK guides](/docs/sdk/quickstart)
* [Webhooks](/docs/api/operational/webhooks) — `sdk.tracking_unhealthy` event when health drifts
