# Get the platform's operational health

> The platform.system.get operation: GET /api/v1/platform/system in the REST API and the platform_system_get tool in the MCP server.

The System page (spec §39.1) in one read, with a status per area (`ok`, `warning`, `critical`) and overall:

- **Job queue** (§30.1): jobs by status, how many are due and how long the oldest has waited (`warning` at 5
  minutes), running jobs whose lease lapsed, and dead jobs (dead letters) by type with the newest 25 (`critical`
  while any exist; retry them as `docs/runbooks/jobs.md` describes).
- **Outbox:** undispatched rows and the oldest one's age (`warning` at 5 minutes).
- **Webhooks:** deliveries over the last 24 hours by status, the failure rate in parts per million of finished
  deliveries (`warning` at 5 %), and the endpoints failing most.
- **Processors** (§15): connections by status across organizations and every degraded or disconnected one
  (`warning`). Labels and statuses only: never a key.
- **FX** (§8.3): the newest ECB publication day loaded (`stale` after 4 days, `missing` without any).

Operational facts only: no job payloads, event bodies or customer data.

## At a glance

- **REST:** `GET /api/v1/platform/system`
- **MCP tool:** `platform_system_get`
- **Operation ID:** `platform.system.get`
- **Scope:** Platform
- **Permission:** `platform:read`
- **Risk tier:** `read`
- **Dry run:** Not supported
- **Idempotency:** Not needed (read only)
- **Modes:** Test and live
- **Authentication:** API key with the `platform:read` scope
- **Since:** M12

## Request

### Query parameters

This operation takes no query parameters.

## Response

`200 OK` with a JSON object:

| Field                                    | Type                               | Description                                      |
| ---------------------------------------- | ---------------------------------- | ------------------------------------------------ |
| `object`                                 | `"platform_system"`                |                                                  |
| `at`                                     | date-time                          |                                                  |
| `status`                                 | one of `ok`, `warning`, `critical` |                                                  |
| `jobs`                                   | object                             |                                                  |
| `jobs.status`                            | one of `ok`, `warning`, `critical` |                                                  |
| `jobs.counts`                            | object                             |                                                  |
| `jobs.dueQueued`                         | integer                            |                                                  |
| `jobs.lagSeconds`                        | integer or null                    | How long the oldest due job has waited.          |
| `jobs.lapsedRunning`                     | integer                            |                                                  |
| `jobs.deadByType`                        | array of object                    |                                                  |
| `jobs.deadByType[].type`                 | string                             |                                                  |
| `jobs.deadByType[].count`                | integer                            |                                                  |
| `jobs.dead`                              | array of object                    |                                                  |
| `jobs.dead[].id`                         | `job_…` ID                         |                                                  |
| `jobs.dead[].type`                       | string                             |                                                  |
| `jobs.dead[].attempts`                   | integer                            |                                                  |
| `jobs.dead[].maxAttempts`                | integer                            |                                                  |
| `jobs.dead[].lastError`                  | string or null                     |                                                  |
| `jobs.dead[].finishedAt`                 | date-time or null                  |                                                  |
| `jobs.dead[].createdAt`                  | date-time                          |                                                  |
| `outbox`                                 | object                             |                                                  |
| `outbox.status`                          | one of `ok`, `warning`, `critical` |                                                  |
| `outbox.pending`                         | integer                            |                                                  |
| `outbox.lagSeconds`                      | integer or null                    | How long the oldest undispatched row has waited. |
| `webhooks`                               | object                             |                                                  |
| `webhooks.status`                        | one of `ok`, `warning`, `critical` |                                                  |
| `webhooks.since`                         | date-time                          |                                                  |
| `webhooks.total`                         | integer                            |                                                  |
| `webhooks.byStatus`                      | object                             |                                                  |
| `webhooks.failurePpm`                    | integer or null                    |                                                  |
| `webhooks.failingEndpoints`              | array of object                    |                                                  |
| `webhooks.failingEndpoints[].org`        | object or null                     |                                                  |
| `webhooks.failingEndpoints[].orgId`      | `org_…` ID                         |                                                  |
| `webhooks.failingEndpoints[].brandId`    | `brd_…` ID                         |                                                  |
| `webhooks.failingEndpoints[].endpointId` | `we_…` ID                          |                                                  |
| `webhooks.failingEndpoints[].livemode`   | boolean                            |                                                  |
| `webhooks.failingEndpoints[].failed`     | integer                            |                                                  |
| `webhooks.failingEndpoints[].total`      | integer                            |                                                  |
| `processors`                             | object                             |                                                  |
| `processors.status`                      | one of `ok`, `warning`, `critical` |                                                  |
| `processors.counts`                      | object                             |                                                  |
| `processors.unhealthy`                   | array of object                    |                                                  |
| `processors.unhealthy[].id`              | `pcon_…` ID                        |                                                  |
| `processors.unhealthy[].org`             | object or null                     |                                                  |
| `processors.unhealthy[].orgId`           | `org_…` ID                         |                                                  |
| `processors.unhealthy[].entityId`        | `ent_…` ID                         |                                                  |
| `processors.unhealthy[].livemode`        | boolean                            |                                                  |
| `processors.unhealthy[].processor`       | string                             |                                                  |
| `processors.unhealthy[].label`           | string                             |                                                  |
| `processors.unhealthy[].status`          | string                             |                                                  |
| `processors.unhealthy[].statusReason`    | string or null                     |                                                  |
| `processors.unhealthy[].lastCheckedAt`   | date-time or null                  |                                                  |
| `fx`                                     | object                             |                                                  |
| `fx.status`                              | one of `ok`, `stale`, `missing`    |                                                  |
| `fx.latestDate`                          | string or null                     |                                                  |
| `fx.ageDays`                             | integer or null                    |                                                  |
| `fx.fetchedAt`                           | date-time or null                  |                                                  |

## Examples

### One dead job and a degraded connection

```http
GET /api/v1/platform/system
Authorization: Bearer or_test_…
```

Response (`200`):

```json
{
  "object": "platform_system",
  "at": "2026-11-03T09:00:00.000Z",
  "status": "critical",
  "jobs": {
    "status": "critical",
    "counts": {
      "queued": 3,
      "running": 1,
      "done": 18220,
      "dead": 1
    },
    "dueQueued": 1,
    "lagSeconds": 12,
    "lapsedRunning": 0,
    "deadByType": [
      {
        "type": "send_email",
        "count": 1
      }
    ],
    "dead": [
      {
        "id": "job_01m5wvkry2exrtkrtdj4j17k3w",
        "type": "send_email",
        "attempts": 8,
        "maxAttempts": 8,
        "lastError": "Resend answered 422: invalid recipient",
        "finishedAt": "2026-11-03T08:40:12.000Z",
        "createdAt": "2026-11-03T06:10:00.000Z"
      }
    ]
  },
  "outbox": {
    "status": "ok",
    "pending": 0,
    "lagSeconds": null
  },
  "webhooks": {
    "status": "ok",
    "since": "2026-11-02T09:00:00.000Z",
    "total": 940,
    "byStatus": {
      "succeeded": 921,
      "failed": 7,
      "pending": 12
    },
    "failurePpm": 7543,
    "failingEndpoints": [
      {
        "org": {
          "id": "org_01m5wvkry1e6w94sjxgme33fs5",
          "slug": "acme",
          "name": "Acme"
        },
        "orgId": "org_01m5wvkry1e6w94sjxgme33fs5",
        "brandId": "brd_01m5wvkry1e6w94sjxgme33fsh",
        "endpointId": "we_01m5wvkry2exrtkrtdj4j17k3z",
        "livemode": true,
        "failed": 7,
        "total": 63
      }
    ]
  },
  "processors": {
    "status": "warning",
    "counts": {
      "active": 41,
      "degraded": 1,
      "disconnected": 0
    },
    "unhealthy": [
      {
        "id": "pcon_01m5wvkry2exrtkrtdj4j17k3y",
        "org": {
          "id": "org_01m5wvkry1e6w94sjxgme33fs5",
          "slug": "acme",
          "name": "Acme"
        },
        "orgId": "org_01m5wvkry1e6w94sjxgme33fs5",
        "entityId": "ent_01m5wvkry1e6w94sjxgme33fsf",
        "livemode": true,
        "processor": "stripe",
        "label": "Stripe (live)",
        "status": "degraded",
        "statusReason": "The restricted key lost the Refunds write permission.",
        "lastCheckedAt": "2026-11-03T08:00:00.000Z"
      }
    ]
  },
  "fx": {
    "status": "ok",
    "latestDate": "2026-11-02",
    "ageDays": 1,
    "fetchedAt": "2026-11-02T15:31:07.000Z"
  }
}
```

## Errors

| Code                                                                                   | HTTP status | When                                                                | What to do                                                                      |
| -------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied) | 403         | You aren't platform staff with read access to the platform console. | Ask an organization owner or admin for a role or scope that allows this action. |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed), [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`authentication_required`](https://ownrecord.io/docs/reference/errors.md#authentication_required), [`api_key_invalid`](https://ownrecord.io/docs/reference/errors.md#api_key_invalid), [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found), [`dry_run_not_supported`](https://ownrecord.io/docs/reference/errors.md#dry_run_not_supported), [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
