# Send events from a server

> Send events that happen on your servers, such as payments, with an API key, so they count in goals and funnels next to website events.

Source: https://docs.bifrostorbit.com/insights/developers/server-api/

Some things happen on a server rather than in a browser: a payment your payment provider confirms, an order your shop system ships, a booking another system makes. The server API takes those events, so they count in goals, revenue and the monthly events like events from the script. It works on every plan.

## Make a key

An Admin opens **API keys** under **Developers**, selects **New API key**, names it after the server, such as **Shop server**, and ticks **Send events**. The key, starting with `ins_live_`, is shown once: keep it in your server's settings, never in a web page or an app. Make one key per server, so you can remove one without stopping the others. See [API keys](https://docs.bifrostorbit.com/insights/developers/api-keys/).

## Send events

```sh
curl https://api.bifrostorbit.com/insights/v1/server/events \
  -H "Authorization: Bearer ins_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "site": "SITE_KEY",
    "events": [
      { "id": "order-1042", "name": "Order paid", "revenue": 129.5, "currency": "EUR", "properties": { "items": 3 } }
    ]
  }'
```

It answers `202` with how many events were taken: `{ "data": { "accepted": 1, "repeated": 0 } }`. While the organisation's Insights Orbit trial or plan has ended, it answers `204` with no body and stores nothing, so your server needs no special handling.

| Field | What it is |
| --- | --- |
| `site` | The site's key, from **Install**. The site must be in the key's organisation. |
| `events` | One to 100 events. The whole request can be up to 256 KB. |
| `name` | The event's name, such as `Order paid`, as in `insights.track`. Required. |
| `id` | Your own id for the event, such as the order number, up to 80 letters, digits, `.`, `_`, `:` or `-`. An event with an id already sent for the site in the last eight days is counted once, so you can safely send again after a timeout. |
| `timestamp` | When it happened, as a time such as `2026-10-21T09:30:00Z` or milliseconds since 1970. Up to seven days back. Now when left out. |
| `properties` | Details, as in `insights.track`: up to 30, each text, a number or true or false. |
| `revenue`, `currency` | Money, with a three-letter currency code, as in `insights.track`. |
| `url` | The page it belongs to, on one of the site's addresses. The site's address when left out. |
| `country` | A two-letter country code, such as `DE`, if you know it. |
| `userId` | Your user id for the person, used only when the site has [known users](https://docs.bifrostorbit.com/insights/everyone/known-users/) switched on and kept only in a scrambled form. |

## What is different from the script

- There is no visitor and no visit. Insights Orbit doesn't read an address or a browser from your server's request, so server events don't change the numbers of visitors, visits or bounce rate. In reports and the raw event API their device is `server`.
- Each server event counts as one goal completion of its own, so ten paid orders are ten completions.
- With known users switched on and a `userId`, a server event belongs to the person, so a funnel counted by known users can start on a page and end with a payment.

## Errors

| Status | Why |
| --- | --- |
| `400` | The body isn't JSON or the events aren't valid. The message says which field. |
| `401` | No key, or a key that was removed. |
| `403` | The key may only read events. |
| `404` | The site isn't in the key's organisation, or is in the bin. |
| `413` | The request is over 256 KB. |
| `429` | More than 600 requests a minute with one key. Wait a minute, or send more events in each request. |
