# Orbit integration API

Read-only API that the Orbit app (`orbit.codebros.cz`) calls to pull
site-monitoring data from **care** (`api.care.codebros.cz`) into its Work module.

- **Base URL:** `https://api.care.codebros.cz`
- **OpenAPI spec:** [`/openapi.json`](https://api.care.codebros.cz/openapi.json) (OpenAPI 3.1)
- **Style:** server-to-server, JSON, read-only. No CORS.
- **Version:** `1.0.0`

## Authentication

Every endpoint requires a personal API key sent as a bearer token:

```
Authorization: Bearer <apiKey>
```

- The key is **per user**. A signed-in user generates it in care settings
  (Nastavení → Integrace → Orbit). The plaintext is shown **once** on creation;
  care stores only a hash.
- A missing, invalid, or revoked key returns **HTTP 401**
  `{ "error": "unauthorized" }`.
- All returned data is **scoped to the user that owns the key**. An admin key
  sees every monitored site; a client key sees only that client's sites.
- Endpoints are read-only. When there is nothing to report they return empty
  arrays or `null`, never `404`.

## Endpoints

All endpoints live under `GET /api/orbit`.

### GET /api/orbit/ping

Health and identity check.

```bash
curl -s https://api.care.codebros.cz/api/orbit/ping \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

```json
{
  "ok": true,
  "service": "care",
  "version": "1.0.0"
}
```

### GET /api/orbit/summary

Monitoring snapshot for the authenticated user.

```bash
curl -s https://api.care.codebros.cz/api/orbit/summary \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

```json
{
  "sites": 12,
  "sitesDown": [
    {
      "name": "Acme web",
      "url": "https://acme.cz",
      "since": "2026-07-14T08:03:00Z"
    }
  ],
  "openIncidents": [
    {
      "site": "Acme web",
      "title": "HTTP 500 na homepage",
      "since": "2026-07-14T08:05:00Z"
    }
  ],
  "jobsToday": {
    "done": 4,
    "pending": 1
  },
  "uptime24hPct": 99.8
}
```

#### Field reference

| Field | Type | Notes |
|---|---|---|
| `sites` | integer | Total number of monitored sites in scope. |
| `sitesDown` | array | Sites currently down (availability outage). Empty when all up. |
| `sitesDown[].name` | string | Site name. |
| `sitesDown[].url` | string \| null | Site URL, or `null` if unknown. |
| `sitesDown[].since` | string (date-time) | ISO 8601 UTC, when the site went down. |
| `openIncidents` | array | All currently open incidents in scope. Empty when none. |
| `openIncidents[].site` | string | Name of the affected site. |
| `openIncidents[].title` | string \| null | Incident summary, or `null` if none was recorded. |
| `openIncidents[].since` | string (date-time) | ISO 8601 UTC, when the incident opened. |
| `jobsToday.done` | integer | Maintenance jobs completed today (Europe/Prague). |
| `jobsToday.pending` | integer | Maintenance jobs scheduled for today and not yet finished. |
| `uptime24hPct` | number \| null | Uptime over the last 24 h across all in-scope sites, in percent. `null` when there are no checks. |

### GET /api/orbit/clients/{id}/summary

Same monitoring snapshot as `/summary`, but scoped to a **single client**. `id`
is the client's **link contact id** — the reference key Orbit holds (link is the
system of record for client identity; care references clients by this id). Used
by Orbit's per-client dashboard.

```bash
curl -s https://api.care.codebros.cz/api/orbit/clients/3f2504e0-4f89-41d3-9a0c-0305e82c3301/summary \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

Response is identical in shape to `/api/orbit/summary` (see field reference
above), covering only that client's sites. A `client` key may only request its
own client; an unknown or non-owned `id` returns **HTTP 404**
`{ "error": "not found" }`.

## Errors

| Status | Body | Meaning |
|---|---|---|
| `401` | `{ "error": "unauthorized" }` | Missing, malformed, invalid, or revoked bearer key. |
| `404` | `{ "error": "not found" }` | `/clients/{id}/summary` for a client id unknown or not owned by the key. |

The `/summary` and `/ping` endpoints do not use `404` to signal empty state — a
valid key with no data returns `sites: 0`, empty arrays, and `uptime24hPct: null`.
Only the per-client endpoint 404s, and only for an unknown/non-owned client id.
