The API v2 does everything the maintenance and status-page screens do. Nobody has to open the control panel. A deploy job can open a window, announce the work, post progress and close both out. The control-panel versions of these flows live in Maintenance Windows and Status Pages, and every endpoint is listed in The Uptimia API v2 Endpoint Map.
Before You Start
- An API key that can manage monitoring and status pages. An owner key clears both, and so does a key minted by an Admin or Editor seat. A Read-only seat's key can read these endpoints and nothing else. See Getting Started with the Uptimia API for authentication and the host-aware base URL.
- Every time value you send is wall clock in your account's time zone, not UTC. So is every human-readable time the API sends back. The machine-readable fields (
occurrences,current_occurrence,next_occurrence,next_update_atand the list'smetadata.now) are absolute epoch seconds. The list and preview responses return the account time zone by name, so your pipeline can assert it. - Monitor group ids, if you plan to scope the window by group.
GET /api/v2/groupsreturns them, andmetadata.totalcounts what came back. It needs an owner or Admin key. A key minted by an Editor or Read-only seat is refused there with HTTP 403 andcode: "forbidden". Those two seat types are the ones that can be limited to specific groups. A group-limited seat reads its own permitted groups fromGET /api/v1/groupsinstead. Itsmetadata.total_groupscounts the groups that seat is allowed to see.
The Order That Avoids a False Alert
Run the steps in this order. Reversing the first two produces a down alert for planned work.
- Create the maintenance window first, and only then start the deploy. Creating a window whose start time has already passed applies it during the same request. Uptimia runs its maintenance pass inline on save rather than waiting for the next minute. The covered monitors leave the check queue immediately.
- Deploy.
- Post status updates as the work progresses.
- Post the terminal update to close the public thread. For a recurring window, leave the thread open and post a non-terminal update instead.
- Let the window expire, or end it early. The per-minute maintenance pass releases a window that reaches its end time, so checks resume within 1 minute of the end time you set. Ending early through the API is immediate.
Give the window a few minutes of slack at both ends. A deploy that overruns its window gets checked, and a real failure at that moment is a real alert.
Step 1: Dry-Run the Schedule
POST /api/v2/maintenance/preview validates a draft against the same schedule rules as the create call. It expands the draft into its next occurrences and saves nothing. Use it in CI to fail the pipeline on a mis-specified recurring schedule instead of discovering it a week later.
curl -sS -X POST https://www.uptimia.com/api/v2/maintenance/preview \
-H "Authorization: Bearer $UPTIMIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Nightly database failover",
"type": "weekly",
"time_start": "0130",
"time_end": "0300",
"days": ["3"],
"selection_mode": "by_group",
"individual_groups": [77]
}'
Preview always answers HTTP 200. The verdict is in the body, so check data.valid, not the status code.
| Response field | What it tells you |
|---|---|
valid |
true when the schedule would save. false puts the reason in error_code and message. |
occurrences |
Up to 5 upcoming occurrences as {start, end} epoch seconds, computed over the next 400 days in your account time zone. An empty list means the schedule never fires. |
overlap |
The first other window this draft collides with, as {id, name, at}, or null. |
timezone |
{name, offset_label}. Assert this in CI so a time zone change on the account is caught. |
warnings |
Non-blocking announcement problems: invalid_name, invalid_title, invalid_summary. Preview downgrades these to warnings because it checks schedules, not announcements. Create rejects them. |
The blocking codes you will hit are invalid_type, invalid_time_range, invalid_days, invalid_weeks and invalid_selection.
Step 2: Create the Window
POST /api/v2/maintenance returns 201 with {"data":{"id":5120}}.
curl -sS -X POST https://www.uptimia.com/api/v2/maintenance \
-H "Authorization: Bearer $UPTIMIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Release 4.18 deploy",
"type": "once",
"time_start": "2026-09-14 02:00",
"time_end": "2026-09-14 02:45",
"selection_mode": "by_group",
"individual_groups": [77],
"status_page": 1,
"status_summary": "We are deploying release 4.18. Checkout stays available throughout."
}'
| Field | What it does | Notes |
|---|---|---|
name |
Window name, and the public headline when you announce it | Required, 1–255 characters. At least 5 characters when status_page is 1 |
type |
once, daily, weekly or monthly |
Required |
time_start / time_end |
For once, a wall-clock datetime such as 2026-09-14 02:00. For the recurring types, an HHMM string such as 0130 |
End must be after start. A recurring end past midnight is encoded as hour + 24, so 0230 the next day is 2630 |
days |
Weekly: 1–7, where 1 is Monday. Monthly: 1–31 | Required for weekly and monthly |
weeks |
Weekly only: the Nth occurrence of that weekday in the month, 1–5 | Optional |
selection_mode |
all, by_type, by_group or individual |
Defaults to all when omitted |
uptime, ssl, domain, virus, fpl, transaction, rum, heartbeat, blacklist, dns, api |
Per-family flags for by_type |
Set to 1 to include that family. Speed is fpl here |
individual_groups |
Group ids for by_group |
— |
individual_monitors |
`type | idstrings such asuptime |
status_page |
1 publishes a public maintenance thread for this window |
Requires status_summary |
status_summary |
The public summary and the thread's first update | At least 10 characters when status_page is 1 |
status_page_ids |
Status pages the thread should publish to | Omit to fall back to publishing on every page that lists an affected monitor |
Server monitors cannot be selected by type. A by_type payload carrying "server": 1 is rejected with invalid_selection rather than silently dropping the servers. Attach them with individual selection or through a group.
Warning: PATCH /api/v2/maintenance/{id} replaces the window's configuration. If you omit selection_mode, Uptimia rebuilds the selection from the stored row, so a rename cannot silently widen the window to every monitor. If you send selection_mode, whatever you send wins, so read the window back with GET /api/v2/maintenance/{id} and patch from that shape.
What a Running Window Does to Your Data
While the window runs, the covered monitors leave the check queue. A result already in flight is dropped on arrival, without writing a check-log row, opening an incident or firing an alert. Open incidents on those monitors are force-closed when the window starts, and you can expect a gap in the check log for the length of the window; that gap is the window working. Maintenance Windows has the full table.
Step 3: Announce the Work
Setting status_page: 1 on the create call opens the public maintenance thread for you, at the Scheduled stage, with status_summary as its first update. That is the shortest path.
To post the thread on its own (a general announcement, or an incident you are narrating), call the threads endpoint directly:
curl -sS -X POST https://www.uptimia.com/api/v2/status-pages/threads \
-H "Authorization: Bearer $UPTIMIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"thread_type": "maintenance",
"maintenance_id": 5120,
"title": "Release 4.18 deploy",
"summary": "We are deploying release 4.18. Checkout stays available throughout.",
"initial_status_update": "Maintenance is scheduled and will start at 02:00.",
"status_page_ids": [314]
}'
title needs 5 characters, summary 10, initial_status_update 5. thread_type is general, incident or maintenance. A general thread needs a status_page_id, and an incident thread needs incident_id plus monitor_type (uptime, speed or transaction).
Call GET /api/v2/status-pages/notify-reach to see how many people the announcement reaches before you send it, passing status_page_id, or monitor_type and monitor_id. Uptimia returns the confirmed subscriber count per page and a total, counting 0 for pages that have subscriptions switched off. See Status Page Subscribers.
Reusing a Thread Instead of Opening a Duplicate
A pipeline that posts a thread on every run risks a second thread for work already being narrated. Uptimia refuses the duplicate:
- A second maintenance thread for the same window comes back as HTTP 409 with
code: "thread_exists"and athread_idfield. Post your update into that thread id and carry on. The same applies to a second incident thread for a monitor that already has one open. - For incidents,
GET /api/v2/status-pages/threads/lookup?monitor_type=uptime&monitor_id=91234answers before you write anything. Add&incident_id=…to pin the answer to one incident.monitor_typeandmonitor_idare required, and anincident_idon its own always comes back empty. An open thread comes back asdata.thread. The most recent closed one comes back withdata.resolved: true, so you can decide whether to reopen it.{"thread": null, "resolved": false}means nothing matches. Lookup covers monitors and incidents, not maintenance windows. For maintenance, readthread_idfrom the window itself.
GET /api/v2/maintenance carries thread_id on every window: a non-zero value is the window's live public thread, and 0 means it has none.
curl -sS -H "Authorization: Bearer $UPTIMIA_API_KEY" \
"https://www.uptimia.com/api/v2/maintenance?horizon_days=1"
horizon_days defaults to 14 and is clamped to 1–31. Each window also carries computed_status (running, recurring, scheduled, expired or invalid), plus current_occurrence, next_occurrence and every occurrence inside the horizon, so a pipeline can assert "the window is running" before it starts deploying.
Step 4: Post Progress and Close Out
POST /api/v2/status-pages/threads/{threadId}/updates appends an update and advances the thread's stage.
curl -sS -X POST https://www.uptimia.com/api/v2/status-pages/threads/8813/updates \
-H "Authorization: Bearer $UPTIMIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"in_progress","message":"Deployment started. Checkout is unaffected."}'
message needs at least 10 characters. next_update_at optionally sets the "next update by" time visitors see, as epoch seconds.
The stage has to belong to the thread type's own lifecycle, or the call is refused with invalid_status:
| Thread type | Stages, in order | Terminal stage |
|---|---|---|
| Maintenance | scheduled → in_progress → monitoring → completed |
completed |
| Incident | acknowledged → investigating → identified → in_progress → monitoring → resolved |
resolved |
| General announcement | open → update → closed |
closed |
Posting the terminal stage closes the thread: it moves to Closed in the control panel and stamps the end time. Posting any non-terminal stage to a closed thread reopens it, which is the supported undo and the trap a retrying pipeline falls into. Make the close-out call idempotent, or check is_resolved on the thread before posting.
Ending the maintenance window itself is separate from closing its thread. Let the window expire on its own end time, or release named monitors immediately with the bulk maintenance call:
curl -sS -X POST https://www.uptimia.com/api/v2/dashboard/bulk/maintenance \
-H "Authorization: Bearer $UPTIMIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"monitors":[{"type":"uptime","id":91234},{"type":"speed","id":4412}]}'
That takes the named monitors out of maintenance now, returns {"status":"success","affected":2}, and for a recurring window suppresses only the occurrence running now. The next occurrence applies as scheduled. Deleting the window instead (DELETE /api/v2/maintenance/{id}) releases its monitors and removes every future occurrence with it.
Recurring Windows and Their Rolled-Forward Thread
A recurring window publishes one thread, not one per occurrence, and every occurrence rolls through it. Re-saving the window with status_page: 1 updates that thread in place and moves its public start and end to the next computed occurrence, which works only while the thread is still open. The per-minute maintenance pass does the same roll-forward on its own once an occurrence ends. Post the terminal completed update and the thread closes, so the next re-save publishes a brand-new one. Leave the thread open. Post non-terminal updates into it each cycle rather than closing it out. If the schedule has no upcoming occurrence, Uptimia publishes no thread at all.
A nightly job should post its progress updates into the thread id the window reports, rather than POST a new thread each night.

Setting status_page: 0 on a PATCH un-publishes the window: the active thread and its updates are deleted. A thread you already closed is public history and survives.
What This Does to Your Uptime Numbers
On the private side, Uptimia removes maintenance seconds from both sides of the availability fraction, so a window counts as neither downtime nor free uptime in the charts, the SLA figures and scheduled reports. The public status page differs. Its 90-day availability ribbon excludes maintenance seconds from the denominator, but the percentage printed beside each individual service does not subtract them at all. No checks run inside the window, so there is no data for it either. The arithmetic is in How Uptime Is Calculated.
Cleaning Up Expired Windows
A pipeline that creates a one-time window per deploy accumulates rows. DELETE /api/v2/maintenance/expired deletes every one-time window of the account whose end time has passed and returns {"data":{"deleted":42}}. Resolved status threads and their update history survive the sweep, and only unresolved announcement threads go with their windows.
This is an account-wide bulk action, so a team member limited to specific monitor groups is refused with selection_out_of_scope and HTTP 403.
Which Role Each Call Needs
Owner-authority keys skip the role check. A key minted by a team-member seat runs with that seat's role. A refusal comes back as HTTP 403 with code: "forbidden" and a required_capability field naming what was missing.
| Call | Roles allowed |
|---|---|
GET /api/v2/maintenance, /maintenance/{id}, /maintenance/monitors |
Owner, Admin, Editor, Read-only |
POST /api/v2/maintenance/preview, create, PATCH, DELETE, POST /dashboard/bulk/maintenance |
Owner, Admin, Editor |
GET on status pages, threads and notify-reach |
Owner, Admin, Editor, Read-only |
POST/PATCH/DELETE on threads and updates |
Owner, Admin, Editor |
A seat limited to specific monitor groups cannot create a window covering all monitors or a whole type; both are refused with selection_out_of_scope, because both reach monitors the seat cannot see. For by_group and individual selections, Uptimia keeps only the monitors that are in the seat's own groups. A window reaching outside those groups answers 404 on read, edit and delete alike.
To mint a key with exactly that authority, see Read-Only and Group-Limited API Keys.