> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Monthly SLA and availability report

> Pull the monthly SLA report for your organization — how per-channel availability is computed from declared incidents, what delivery success and delivery health mean, how incidents pro-rate across a month boundary, and how to use the report in an SLA claim.

# Monthly SLA and availability report

The monthly SLA report is the availability attestation for your organization:
one response per calendar month that shows, per channel, the measured
availability, the declared incidents that caused any downtime, and your
delivery success rate. It answers three questions at once — *was the channel
measured up*, *why was it down*, and *did my messages actually get delivered*.

The same report powers the **Settings → Reliability** page in the dashboard
and is exportable as CSV, so the number you read, the number you attach to a
claim, and the number support quotes are always the same figure.

## Access and role gates

The report endpoint is restricted to the **owner** and **admin** roles. An
availability attestation is an org-level document a customer may share with
their own customers or procurement team, so it is scoped to roles trusted to
export org data. Other roles get a `403`.

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/organizations/sla-report?period=2026-04" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

`period` is a calendar month in `YYYY-MM` form. Omit it to get the current
month. A malformed value (`2026-4`, `04-2026`, `2026-13`) returns
`400 INVALID_PERIOD`.

The endpoint is `GET /api/v1/organizations/sla-report`. Export the same
report as CSV with `?format=csv`:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/organizations/sla-report?period=2026-04&format=csv" \
  -H "X-API-Key: $ORBIT_API_KEY" -o sla-report-2026-04.csv
```

The CSV is a one-row-per-channel table with the period bounds, whether the
period is `complete` or `month-to-date`, and the report's refresh time on
every row. A metric-definitions block is appended below the table so the file
still states how every figure was derived when it is detached from the
dashboard — useful when you attach it to a claim.

Owner/admin are also the only roles that can open **Settings → Reliability**
in the dashboard, which renders this same report with a month picker and an
export button.

## What the report is a read-model of

The report does not maintain its own telemetry store. It is a read-model —
a deterministic assembly — over two inputs you already have other views of:

1. **The public incident feed.** The same declared incidents Orbit publishes
   on the status page. Availability, downtime minutes, and the incident
   windows in the report are all derived from this feed.
2. **Your own outbound message records.** Delivery success is aggregated
   from your organization's message log over the period — the same
   outbound-scoped view the analytics dashboard reads.

Because both inputs are fixed historical records and the derivation is pure,
the report is reproducible: for a complete month, regenerating it next week
returns the same figures. The one deliberate exception is the *current*
month, which is a month-to-date snapshot — see [Boundary conditions](#boundary-conditions).

If the delivery-aggregate half of the read ever fails while the incident
feed is fine (for example your organization's data store is briefly
unavailable), the report still renders: availability comes from the incident
feed and delivery columns degrade to empty rather than failing the whole
response.

## Reading per-channel availability

Each channel row carries:

| Field              | Meaning                                                                                   |
| ------------------ | ----------------------------------------------------------------------------------------- |
| `availability_pct` | Percentage of the reporting window the channel was free of a declared incident, or `null` |
| `measured`         | Whether the report has any evidence for the channel (traffic or an incident)              |
| `downtime_minutes` | Minutes of the window covered by a declared incident for the channel                      |
| `incident_count`   | Declared incidents attributed to the channel                                              |

The formula, per channel, is one line:

```
availability_pct = (period_minutes − downtime_minutes) ÷ period_minutes × 100
```

* `period_minutes` is the reporting window in minutes — the full calendar
  month in UTC for a complete month, or elapsed month-to-date minutes for the
  current month.
* `downtime_minutes` is the union of all incident windows attributed to the
  channel, clamped to the period. Overlapping incidents are counted once —
  two incidents affecting SMS at the same hour deduct that hour once.
* Incidents are attributed per channel from their declared affected
  component. A platform-wide incident is attributed to every channel; an
  unrecognised component is conservatively treated as platform-wide so it is
  never silently dropped from the math.
* Scheduled maintenance and informational notices do **not** count against
  availability; minor, major, and critical incidents do.

Worked example. April 2026 spans 30 days = 43,200 minutes. Two incidents
affected the SMS channel: one of 95 minutes, one of 45 minutes, disjoint.
SMS downtime is 140 minutes:

```
(43,200 − 140) ÷ 43,200 = 99.6759% availability
```

If those two incidents had overlapped for 30 of their minutes, the union
would be 110 minutes and SMS would read 99.7454% — overlap never
double-counts.

**"Not measured", never 100%.** A channel with no terminal message traffic
**and** no declared incident in the period shows `availability_pct: null`
and `measured: false` — rendered as *Not measured* in the dashboard and
`"not measured"` in the CSV. There is no evidence it was up, so the report
does not attest to it; reading 100% would turn "nothing observed" into
"verified up." Unmeasured channels are also excluded from the overall
availability mean, so a quiet month on one channel cannot mask a real
incident on another.

**Overall availability** is the unweighted mean of the *measured* channels'
percentages — each measured channel counts equally, so a single-channel
incident moves the mean less than a platform-wide one.

## Reading delivery success and delivery health

Availability and delivery success measure different things. Availability
covers declared platform incidents; delivery success is the end-to-end
outcome of your outbound traffic:

```
delivery_success_rate = delivered ÷ terminal messages × 100
```

The **denominator** (`messages_terminal`) counts your outbound messages that
reached a final state in the period — delivered, failed, undelivered, or
rejected. Messages still in flight are excluded. The **numerator**
(`messages_delivered`) counts messages the recipient side confirmed. The
same status sets power the analytics dashboard, so the figure here matches
there: an unknown or in-flight outcome drags the rate down rather than
reading as success.

Delivery success can be low even at 100% availability — invalid recipients,
an unregistered sender, filtered content, carrier rejection, or insufficient
balance are not platform incidents. To make that signal visible instead of
silent, each channel row also carries a `delivery_health` tier:

| Tier                | Rule                            |
| ------------------- | ------------------------------- |
| `healthy`           | At or above 90% delivered       |
| `degraded`          | Below 90%                       |
| `critical`          | Below 50%                       |
| `insufficient-data` | Fewer than 10 terminal messages |
| `not-measured`      | No terminal traffic             |

Below 10 terminal messages the rate is intentionally not tiered — a single
failed test send is not a Degraded alert. No channel with real volume and a
collapsing delivery rate goes unflagged just because no incident was
declared.

## Operator playbook

**Pull a complete month and sanity-check the headline.**

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/organizations/sla-report?period=2026-04" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

Optionally pretty-print the key figures:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/organizations/sla-report?period=2026-04" \
  -H "X-API-Key: $ORBIT_API_KEY" | jq '.overall, .incidents'
```

**Isolate an availability dip to its incident window.** Say April shows
WhatsApp at 99.6% while every other channel reads 100%. Read the `incidents`
array — each window names the incident, its affected channels, and the
minutes it overlaps the month. The WhatsApp dip will line up with exactly
one window, say a 25-minute WhatsApp outage on April 12:

```
(43,200 − 25) ÷ 43,200 = 99.9421%
```

That window is what you quote back to a customer: a public, declared
incident, not a vague "the platform was down."

**Defend or assess an SLA claim.** Cross-reference three things in one
response: the incident windows (why availability dipped), the per-channel
delivery trend from your analytics (whether your traffic was actually
harmed), and — when the month's uptime target was missed — the credit
endpoint `GET /api/v1/organizations/sla-report/credit`:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/organizations/sla-report/credit?period=2026-04&plan=growth" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

The credit assessment composes the same report with the published SLA
schedule and returns whether the target was breached, the credit percentage
owed, a per-channel breakdown, and a memo-ready summary. Pass
`&monthlySpendCents=…` to also get the credit amount, `&plan=` to assess a
different tier, or `&uptimeTargetPct=` for an explicit target. It computes
an entitlement — it does not post to your wallet.

**Export for the claim.** Attach the CSV (`?format=csv`) — the appended
methodology block lets the reviewer validate every figure without access to
your dashboard.

## Boundary conditions

* **Month-boundary incidents are pro-rated.** An incident from April 30
  23:00 to May 1 02:00 deducts 60 minutes from April and 120 from May — the
  split lands on whichever month each minute of the outage overlaps. An
  incident that starts before the period start (or resolves after the
  period end) is included only for the portion inside the period.
* **Current month is month-to-date.** When you request the month in progress
  (or omit `period`), the reporting window ends at the refresh time, the
  response is flagged `partial: true`, and `as_of` marks the effective
  cut-off (the CSV shows `month-to-date` as the period status). Wait for the
  month to close before using it as an attestation.
* **Still-open incidents.** For a complete month an open incident's end is
  clamped to the period end — not to the time you generated the report — so
  the figure stays stable regardless of when you regenerate.
* **Months before incident publication began** simply show those months
  with fewer (or zero) incident windows; channels with traffic still read as
  measured on their delivery rows.

## See also

* [10DLC registration](/guides/10dlc-registration) — sender registration and
  carrier trust directly affect deliverability, which reads here as delivery
  success
* [Scheduled reports](/guides/scheduled-reports) — email a metrics digest on
  a daily/weekly/monthly cadence instead of pulling on demand
* [Cost intelligence](/guides/cost-intelligence) — pair availability figures
  with unit costs when deciding where to route traffic
