# Maintenance windows

We occasionally take the platform down for planned work. During a window, **every endpoint
answers 503** with the code `maintenance`:

```http
HTTP/1.1 503 Service Unavailable
Content-Type: application/problem+json
Retry-After: 300
```

```json
{
  "type": "https://docs.genuineai.app/errors/maintenance",
  "title": "Under maintenance",
  "status": 503,
  "detail": "Upgrading the database. Back at 5:00 PM ET.",
  "instance": "/api/v1/files",
  "code": "maintenance"
}
```

`detail` carries the message written for the window and is meant to be shown to a person.
It is prose. Branch on `code`, not on it.

Windows are announced ahead of time on the [status page](https://status.genuineai.app),
which is also where to confirm one has finished. You can subscribe there to be told when a
window opens and closes rather than discovering it from a failed request.

## Nothing you sent was applied

A blocked request is refused before it reaches any handler. It creates nothing, changes
nothing, and consumes no credits, so there is no partial write to reconcile and no need
to check whether something landed before you send it again.

**Replay the whole request once the window ends.** That holds for writes as much as reads:
a `POST` refused with `maintenance` is a `POST` that never happened.

## Handle it

Treat `maintenance` as a signal to pause the integration, not as a per-request failure to
log and move past. Every subsequent call will fail the same way until the window closes,
so a queue that drops failures will drain itself into nothing.

<CodeTabs syncKey="lang">

```js title="JavaScript"
if (res.status === 503 && err.code === "maintenance") {
  const wait = Number(res.headers.get("Retry-After") ?? 300);
  pauseQueue(wait);           // stop sending; keep the work
  return;                     // replay in full when it resumes
}
```

```python title="Python"
if res.status_code == 503 and err["code"] == "maintenance":
    wait = int(res.headers.get("Retry-After", 300))
    pause_queue(wait)         # stop sending; keep the work
    return                    # replay in full when it resumes
```

</CodeTabs>

`Retry-After` is how long to wait before trying again, in seconds. It is not how long the
window will last. Expect to be told `maintenance` more than once. Wait the interval out each time
rather than polling tightly; the answer will not change until the work is finished.

<Callout type="note">
`maintenance` is a 503, but it is not `service_unavailable`. This one is planned and comes
with a `Retry-After` we chose deliberately; `service_unavailable` is an unplanned failure.
Check the [status page](https://status.genuineai.app) first, and tell us if what you are
seeing is not on it. See [errors](/errors).
</Callout>

## What else stops

The window covers the whole platform, not only the API. Share links and public upload
links are unavailable, and an embedded chat widget shows its unavailable state instead of
starting a conversation. People signing in to the app reach a maintenance page carrying
the same message rather than a half-working workspace.

A window applies to every workspace at once. It is a property of the platform, not
something scheduled per customer.
