SDK health & verification
Four signals partners can read to know whether an SDK install is healthy — `lastEventAt`, `events.list`, `capi-status`, and the active `verify-tracking` probe.
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
| Signal | Endpoint | What it tells you | Latency |
|---|---|---|---|
lastEventAt | GET /v1/projects/:id/sdk-apps/:appId | Wall-clock of the most recent event Layers received from this SDK app. Passive. | Real-time. |
| Event timeline | GET /v1/projects/:id/events | The actual stream of events with timestamps, properties, user identity. Passive. | Real-time. |
| CAPI status | GET /v1/projects/:id/ads/capi-status | Whether the CAPI relay is forwarding events to Meta / TikTok, including the per-platform events_received count from the platform side. Passive, CAPI-only. | 5–15 min lag (platform-side aggregation). |
| Verify-tracking | POST /v1/projects/:id/sdk-apps/:appId/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
"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
{
"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
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):
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
POST /v1/events— server-side event forwarding (when partners can't / won't ship the client SDK)POST /v1/projects/:id/sdk-apps/:appId/verify-tracking— the active probe- SDK guides
- Webhooks —
sdk.tracking_unhealthyevent when health drifts
Ads write model
How partner ad writes are gated — bucket-mode authority, customer controls, partner inheritance, kill-switch contract, and what's never partner-writable.
Provision and fund a customer
Six calls to a funded, capped, observable customer — create a child org, mint its key, allocate credits, set spend limits, and subscribe the firehose.