> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flokitai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Server-side events

> Send lifecycle and revenue events to FloKit from your backend.

The FloKit Events API accepts JSON events from your server. Use it to send funnel events, revenue events, or custom events not covered by your subscription platform.

## Authentication

All requests require an API key passed as a Bearer token.

```
Authorization: Bearer $FLOKIT_API_KEY
```

Find or create API keys in FloKit → Settings → API Keys.

**Base URL:** `https://api.flokit.ai`

***

## Send a single event

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.flokit.ai/v1/events \
    -H "Authorization: Bearer $FLOKIT_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "event": "paywall_viewed",
      "user_id": "usr_abc123",
      "anonymous_id": "anon_xyz789",
      "timestamp": "2024-03-15T14:22:00Z",
      "properties": {
        "paywall_id": "pw_annual_v3",
        "offer_id": "offer_intro_50pct",
        "context": "onboarding_step_3"
      }
    }'
  ```

  ```typescript Node.js / TypeScript theme={null}
  const response = await fetch('https://api.flokit.ai/v1/events', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.FLOKIT_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      event: 'paywall_viewed',
      user_id: 'usr_abc123',
      anonymous_id: 'anon_xyz789',
      timestamp: new Date().toISOString(),
      properties: {
        paywall_id: 'pw_annual_v3',
        offer_id: 'offer_intro_50pct',
        context: 'onboarding_step_3',
      },
    }),
  });

  const data = await response.json();
  // { status: 'ok', event_id: 'evt_01hx...' }
  ```
</CodeGroup>

**Response**

```json theme={null}
{
  "status": "ok",
  "event_id": "evt_01hx4j7k9m2n3p5q6r8s"
}
```

***

## Request fields

<ParamField body="event" type="string" required>
  Event name from the [event taxonomy](/send-data/event-taxonomy). E.g. `paywall_viewed`, `subscription_started`.
</ParamField>

<ParamField body="user_id" type="string">
  Your backend user identifier. Required if `anonymous_id` is not present.
</ParamField>

<ParamField body="anonymous_id" type="string">
  Pre-login device or session identifier. Recommended for events that occur before a user account is created. FloKit links `anonymous_id` to `user_id` automatically when both appear together in any event.
</ParamField>

<ParamField body="timestamp" type="string" required>
  ISO 8601 datetime of when the event occurred. Use the event's actual occurrence time, not the time the request is sent.
</ParamField>

<ParamField body="properties" type="object">
  Any additional event properties as key/value pairs. See the [event taxonomy](/send-data/event-taxonomy) for recommended properties per event type.
</ParamField>

***

## Error responses

| Status                  | Meaning                                                         |
| ----------------------- | --------------------------------------------------------------- |
| `200 OK`                | Event accepted                                                  |
| `400 Bad Request`       | Validation error — response body includes `error` and `message` |
| `401 Unauthorized`      | Missing or invalid API key                                      |
| `429 Too Many Requests` | Rate limit exceeded — see headers for retry-after               |

***

## Idempotency

Include an `Idempotency-Key` header to safely retry requests without creating duplicate events. FloKit deduplicates on this key within a 24-hour window.

```bash theme={null}
curl -X POST https://api.flokit.ai/v1/events \
  -H "Authorization: Bearer $FLOKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: usr_abc123-subscription_started-2024-03-15" \
  -d '{
    "event": "subscription_started",
    "user_id": "usr_abc123",
    "timestamp": "2024-03-15T14:25:00Z",
    "properties": {
      "plan_id": "plan_annual_usd",
      "revenue": 49.99,
      "currency": "USD",
      "transaction_id": "txn_3OZ..."
    }
  }'
```

If a duplicate request is received within 24 hours, FloKit returns `200 OK` with the original `event_id` — no duplicate is stored.

***

## Event ordering

Send events in chronological order where possible. Out-of-order events are accepted and will be processed correctly, but funnel metrics may appear inconsistent for a brief period until FloKit's event sorter catches up. For historical imports with large volumes of out-of-order events, use the [batch endpoint](/send-data/batch-events) and sort events by `timestamp` before sending.
