# Send events

> POST /v1/events

Source: https://docs.onari.xyz/docs/api/events

```http
POST https://api.onari.xyz/v1/events
```

Send one event, or up to 100 in one request. Each is processed straight away; the response has every player's progress and any rewards won.

## Body

| Field | Type | |
|---|---|---|
| `type` | string, required | An event on your events list, e.g. `order.placed`. |
| `player_id` | string, required | Your ID for the player (1–128 characters). |
| `amount` | integer | Money in minor units (`250000` = ₦2,500). Also read from `properties.amount`. |
| `properties` | object | Anything else you want stored with the event. |
| `idempotency_key` | string | Unique per action (up to 128 characters). Repeats are ignored. |
| `occurred_at` | ISO 8601 | When it happened, if not now. |
| `referred_by` | string | The inviting player's ID, for referral campaigns. Set once. |

To send several, wrap them: `{ "events": [ {…}, {…} ] }` (1–100).

## Example

```bash
curl https://api.onari.xyz/v1/events \
  -H "Authorization: Bearer $ONARI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "order.placed",
    "player_id": "user_8a21",
    "amount": 1840000,
    "properties": { "channel": "app" },
    "idempotency_key": "order_SE-88213"
  }'
```

## Response

`202 Accepted`

```json
{
  "event_id": 1042,
  "player_id": "user_8a21",
  "campaigns": [
    { "campaign_id": "6f1c…", "progress": 3, "goal": 3 },
    { "campaign_id": "b207…", "score": 2 }
  ],
  "rewards": [
    {
      "id": "a91e…",
      "campaign_id": "6f1c…",
      "campaign": "October challenge",
      "reason": "challenge",
      "kind": "voucher",
      "value": 200000,
      "currency": "NGN",
      "code": "SAVE-7QX4-M9",
      "status": "delivered"
    }
  ]
}
```

- `campaigns` lists every running campaign this event counted toward: `progress`/`goal` for challenges and streaks, `score` for leaderboards.
- `rewards` is empty unless the player just won. For several events, the response is `{ "results": [ … ] }` in the same order.
- A repeated `idempotency_key` returns `{ "duplicate": true }`.

## Errors

| Status | Code | Why |
|---|---|---|
| 400 | `invalid_request` | The body isn't an event or `{ events: [...] }`. `issues` says what's wrong. |
| 401 | `invalid_api_key` | Missing, malformed, revoked or expired key. |
| 402 | `player_limit_reached` | Free plan, live: 1,000 players are already active this month and this is a new one. |
| 422 | `unknown_event_type` | Not on your events list. `did_you_mean` suggests the closest one. |
| 429 | `rate_limited` | Too many requests per second for this key. |

In a batch, events before the failing one are already processed: the error includes `index` (the failing event) and `processed`. Resend from `index` with the same idempotency keys.
