# Status feed

> The public status feed behind the status page, the RSS, Atom and JSON incident feeds, email updates, and how to read them.

Source: https://tickwire.io/docs/status-feed/

The [status page](https://tickwire.io/status/) reads one public JSON document from the Tickwire status service. The
service runs apart from the API, so it keeps answering when the platform doesn't. You can read the
same feed to show Tickwire's status in your own dashboard, or follow incidents in a feed reader.

```
GET https://status.tickwire.io/api/v1/status.json
```

The [status page](https://tickwire.io/status/) shows the feed's current address. Every endpoint on this page is
public, needs no key and allows cross-origin reads.

**What's available now:** the JSON feed, RSS, Atom and JSON Feed. **Not yet:** email updates. They
switch on when an email provider is configured. Until then, subscribing answers
[`email_notifications_unavailable`](https://tickwire.io/docs/errors/email_notifications_unavailable/) and the feed says
`"subscribe": {"email": false}`.

## What it measures

Each component's status comes from real probes run every 30–60 seconds from outside the platform:

| Component | Probe |
|---|---|
| API gateway | the API's front door answers its health check |
| Control plane | account and key management answers through the API |
| Stream hub | WebSocket streaming answers through the API |
| Webhook delivery | every 5 minutes a test event is triggered for a canary organisation, and its correctly signed webhook must arrive within 2 minutes; if the test event cannot be triggered, the component shows unknown, not an outage |
| Dashboard | the dashboard page loads |
| Website and docs | the website's home page loads |
| MT5 trading, MT4 trading | a canary broker account's health, read through the API, is `healthy` and can trade |
| Sandbox | a sandbox account's health, read with a sandbox key |

A component with no probe set up yet is listed separately as **Not monitored yet** (the feed's
`not_monitored` list). We have no evidence either way for it, so it is never shown green or red and
it does not count towards the overall status. A probed component with no recent result shows
**unknown**, and **no data** in its daily bars. Services we don't run yet are not listed.

## Endpoints

| Path | What |
|---|---|
| `GET /api/v1/status.json[?history_days=N]` | the full feed (N from 0 to 400; default 90) |
| `GET /api/v1/summary.json` | the feed without daily history |
| `GET /api/v1/components/{id}` | one component |
| `GET /api/v1/incidents[?days=14]` | incidents and maintenance, newest first |
| `GET /api/v1/incidents/{id}` | one incident, with its postmortem once published |
| `GET /api/v1/postmortems` | published postmortems, newest first |
| `GET /api/v1/feed.rss` | incidents and maintenance as RSS 2.0 |
| `GET /api/v1/feed.atom` | the same as Atom 1.0 |
| `GET /api/v1/feed.json` | the same as [JSON Feed 1.1](https://jsonfeed.org/version/1.1) |
| `POST /api/v1/subscriptions` | email updates (when available; see below) |

The JSON endpoints are cacheable for 15 seconds, the incident feeds for 60.

## Shape (`tickwire.status.v1`)

```json
{
  "schema": "tickwire.status.v1",
  "generated_at": "2026-09-27T12:00:30Z",
  "page": { "name": "Tickwire", "url": "https://status.tickwire.io" },
  "status": { "indicator": "none", "description": "All Systems Operational" },
  "components": [
    {
      "id": "gateway",
      "name": "API gateway",
      "group": "Platform",
      "description": "The public REST and WebSocket entry point.",
      "region": null,
      "account_class": null,
      "status": "operational",
      "measured_status": "operational",
      "updated_at": "2026-09-27T12:00:21Z",
      "probes": [
        { "id": "gateway-healthz", "name": "Gateway liveness", "kind": "http", "state": "up",
          "fresh": true, "checked_at": "2026-09-27T12:00:21Z", "latency_ms": 41.2, "detail": "HTTP 200",
          "region": null, "account_class": null }
      ],
      "uptime": { "24h": 100.0, "7d": 99.98, "30d": null, "90d": null },
      "history": [
        { "date": "2026-09-26", "uptime_pct": null, "status": "no_data",
          "samples": { "up": 0, "degraded": 0, "down": 0, "paused": 0 }, "avg_latency_ms": null },
        { "date": "2026-09-27", "uptime_pct": 100.0, "status": "operational",
          "samples": { "up": 2400, "degraded": 0, "down": 0, "paused": 0 }, "avg_latency_ms": 44.0 }
      ]
    }
  ],
  "not_monitored": [
    { "id": "webhooks", "name": "Webhook delivery", "group": "Platform",
      "description": "Signed webhook events reaching a canary endpoint." }
  ],
  "groups": [ { "name": "Platform", "status": "operational", "components": ["gateway"] } ],
  "regions": [],
  "account_classes": [],
  "incidents": { "active": [], "recent": [] },
  "maintenances": { "active": [], "upcoming": [] },
  "postmortems": [],
  "subscribe": {
    "email": false,
    "rss": "https://status.tickwire.io/api/v1/feed.rss",
    "atom": "https://status.tickwire.io/api/v1/feed.atom",
    "json": "https://status.tickwire.io/api/v1/feed.json"
  },
  "power": {
    "configured": true, "paused": false, "state": "running",
    "since": null, "checked_at": "2026-09-23T12:00:00Z", "description": null
  }
}
```

| Field | Values |
|---|---|
| component `status` | `operational`, `degraded_performance`, `partial_outage`, `major_outage`, `under_maintenance`, `unknown` |
| component `measured_status` | what the probes alone say; `status` can be worse when we declare an incident, and is better only during a planned pause (see `power`) |
| component `in_maintenance` | `true` while a maintenance window covers the component. During maintenance a degraded or partial outage shows as `under_maintenance`; a `major_outage` or `unknown` is always shown as it is, with this flag as the note |
| `updated_at` | the newest fresh probe result; `null` when there is none |
| `not_monitored` | components with no probe set up yet (`id`, `name`, `group`, `description`). They are not in `components`, `groups` or the overall `status`. Show them as "Not monitored yet", never as up or down. Older feeds lack this field |
| day `status` | the component statuses, or `no_data` for a day without a single measurement |
| `uptime` | percentages over 24 h, 7, 30 and 90 days; `null` means no data, never 100 |
| incident `status` | `investigating`, `identified`, `monitoring`, `resolved`; maintenance: `scheduled`, `in_progress`, `completed` |
| incident `impact` | `none`, `minor`, `major`, `critical`, `maintenance` |
| incident `automatic` | `true` when our probes opened it |
| incident `postmortem` | `null` until a postmortem is published; then when it was published. The text is in `GET /api/v1/incidents/{id}` |
| `power.paused` | `true` while the platform is paused on purpose before launch. It wakes on the first request, in about 2 minutes. While paused, components that are asleep show `under_maintenance` and the headline reads "Paused (sleeping to save cost; wakes on first use)". `power.since` is when the pause began |

`history` is oldest first and covers 90 days by default. Uptime counts `degraded` as available. A check that finds something down while the platform is paused on purpose counts under `samples.paused` and is left out of every uptime figure: a planned sleep is not downtime.
The full JSON Schema is published at [/schemas/status-feed.schema.json](https://tickwire.io/schemas/status-feed.schema.json).

## Truth rules

The status page applies these, and we recommend you do the same:

1. If `generated_at` is more than **5 minutes** old, treat everything as `unknown`.
2. A component that says `operational` or `degraded_performance` but whose `updated_at` is more
   than **5 minutes** old, or missing, is `unknown`.
3. A day with `uptime_pct: null` is "no data", never green.
4. An unrecognised status value is `unknown`.
5. The overall status is the worst component status, and `unknown` ranks worse than `operational`.
   Only `components` count; `not_monitored` entries never do. With no monitored component at all,
   the overall status is `unknown`.
6. If the feed can't be fetched, or isn't a `tickwire.status.v1` document, say the feed is
   unreachable. Don't show the last state you saw as current.

## Incident feeds

`feed.rss`, `feed.atom` and `feed.json` carry one entry per incident or maintenance, newest activity
first (up to 50). An entry's updated time is its latest update, so your reader shows it again when it
changes. Its text lists every update and, once published, links the postmortem. An empty feed means
we haven't posted an incident.

## Email updates

When email is available (`subscribe.email` is `true`):

```bash
curl -X POST https://status.tickwire.io/api/v1/subscriptions \
  -H 'content-type: application/json' -d '{"email":"you@example.com"}'
```

- The answer is always `202` with the same body, whether or not the address is already subscribed.
- We send a confirmation link. Nothing else is sent until you confirm it. The link expires in 48 hours.
- Every incident email has an unsubscribe link.
- Limits: 5 requests per hour from one IP address (IPv6: per /64)
  ([`rate_limited`](https://tickwire.io/docs/errors/rate_limited/)). One address gets at most one confirmation email
  every 10 minutes and 3 a day, whoever asks. Requests beyond that still get the same `202`, and no
  email is sent.

When email isn't available the endpoint answers `503`
[`email_notifications_unavailable`](https://tickwire.io/docs/errors/email_notifications_unavailable/), and its message
lists the feed URLs.

## Postmortems

After a significant incident we publish a postmortem on the incident's page (`/status/incident/?id=N`
on this site). Published postmortems appear in the feed's `postmortems` list and in the incident
feeds. None have been published yet.
