# REST API

HTTP endpoints for server-side integrations.

The SDK uses these HTTP endpoints under the hood. You can call them directly from your server for backend integrations, async conversion tracking, or non-browser surfaces like native apps and email.

The REST API mirrors what the SDK does on the client. Every call needs your project API key in the request body (the same key that's in your snippet) so we can attribute the call to the right project. The visitor UUID returned by `/sdk/init` is the linking identifier you carry through subsequent calls — including server-side conversion attribution.

For full request and response schemas, parameter types, and a try-it-out console, visit the [API Reference](https://www.otterab.com/api-docs) page. The summary table below is the quick orientation.

## Endpoints

| Method | Endpoint | Description |
| --- | --- | --- |
| POST | `/sdk/init` | Initialize visitor, get test config |
| POST | `/sdk/track` | Track custom events |
| POST | `/sdk/convert` | Record conversions |
| POST | `/sdk/identify` | Send user properties |
| GET | `/sdk/active/:key` | Verify snippet installation |

## Frequently asked questions

### When should I call the REST API directly instead of using the SDK?

Server-side workflows: tracking conversions that happen in your backend (post-purchase webhooks, async order completions), running tests across non-browser surfaces (email, push, native apps), or augmenting the SDK with server-rendered variant decisions. For client-side websites, the SDK does everything the REST API does plus DOM management.

### Do REST API calls need authentication?

Yes. Pass your project key in the request body (key field) just like the SDK does. The key is project-scoped, not account-scoped — it identifies which project the call belongs to. The key is safe to expose in browser code (it's already in your snippet) but treat it like any project identifier.

### What's the response shape of /sdk/init?

JSON with: visitor_uuid (string), tests (array of active tests for this visitor with their assigned variant, DOM changes, redirect URL if applicable), and goals (array of click/pageview/event goals to watch for). The SDK uses this to render variants and start tracking. If you're calling it server-side, you'll typically only need visitor_uuid and tests.

### How do I record a conversion from my backend?

POST to /sdk/convert with body { key: 'YOUR_KEY', visitor_uuid: '...', test_id: '...', goal_id: '...', value: optional_revenue }. The visitor_uuid is what you got from the original /sdk/init call — you need to plumb it through your system (cookies, JWT claims, etc.) so server-side conversion attribution finds the right visitor.

### Are there rate limits?

Free and Starter plans allow up to 50 requests per second per project. Growth and Scale plans are higher. If you hit the limit you'll get 429 responses; back off exponentially. For high-volume server-side workloads, contact us — we can raise the limit for your account.

### Is there an OpenAPI spec?

Yes. The full OpenAPI spec is at /api-docs (the API Reference page on this site). It covers every endpoint, parameter, response shape, and error code with a try-it-out console.

### Does the REST API enforce bot detection?

Yes. Every request checks the user-agent against known bot signatures and excludes bot traffic from variant assignment and reporting, just like the SDK. If you're integrating from a known-good server, you can pass user_agent: 'YourBackend/1.0' to make this explicit.

---

Canonical page: https://www.otterab.com/docs/developer-reference/rest-api
