For the brave.
No exercises and no congratulations at the end — just the endpoints, in order, with examples that actually run.
The API is hosted at api.goatech.ai during the rebrand to Sheepit. Both hosts will be aliased once DNS cuts over.
API key types
Sheepit uses bearer tokens. Every key is prefixed by what it can do, so you can tell at a glance whether you've checked the right one into the right place.
lp_pub_…PublishableClient-side SDK key. Safe to ship in browser and mobile bundles. Can read /v1/config and post events. Cannot touch admin routes.
lp_sec_…SecretServer-side SDK key with full project access. Used by server SDKs. Never embed client-side.
lp_dev_…Dev / CLIRead-only access to schemas and definitions. Powers @goatech/cli codegen. Safe for dev shell + CI secrets, not client bundles.
Send the key as Authorization: Bearer <key>. Every request that needs auth needs this header.
Send one event
Paste this into a terminal. Replace the key. If the response is { "data": { "accepted": 1 } }, you're done — the event is in the dashboard.
curl -X POST https://api.goatech.ai/v1/ingest \
-H "Authorization: Bearer lp_pub_xxx_…" \
-H "Content-Type: application/json" \
-d '{
"events": [{
"event": "signup",
"anonymous_id": "anon-abc",
"properties": { "source": "docs" },
"timestamp": "2026-05-26T18:00:00Z"
}]
}'That's the whole loop. Everything else in this page is a variation on the same shape.
Endpoints
The endpoints the SDKs call today. New ones land here as we ship them.
/v1/devices/registerpublishable keyRegister an anonymous device on app boot. Returns a device ID you store locally.
/v1/devices/:deviceId/identifypublishable keyAttach a user ID to a previously-registered device.
/v1/configpublishable keySnapshot of all flags + experiment assignments for the current device / user. Cache it; refresh on app foreground.
/v1/ingestpublishable keySend one or many events in a single batch. Fire-and-forget; client SDKs queue and retry.
/v1/crashes/reportpublishable keySubmit a crash report. Used by the mobile SDKs.
/v1/performance/ingestpublishable keyBatched performance metrics (startup time, frame drops, ANR, network spans).
What can go wrong
All errors come back as { "error": { "code", "message" } }. The code is stable; the message is human-readable.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_input | Body didn't parse, or required fields were missing. |
| 401 | unauthorized | Missing or malformed Authorization header. |
| 403 | forbidden | Key is real but doesn't have permission for this route (e.g. pub key on admin route). |
| 404 | not_found | Resource doesn't exist or isn't visible to your project. |
| 409 | conflict | Idempotency or uniqueness conflict (e.g. event_id already ingested). |
| 429 | rate_limited | You're sending too fast. Back off and retry with jitter. |
| 5xx | server_error | Our fault. SDKs already retry; if it persists, email us. |
Missing an endpoint? More are landing here as we ship them.
Ask us about one →