Migrating from Opsgenie

Moving off Opsgenie? This brings your on-call schedules across — the rotations, the turn lengths, the coverage hours and the people — so you don't rebuild months of carefully-tuned coverage by hand and hope you got it right.

It works in two stages. First you run a check, which reads your Opsgenie configuration and shows you exactly what would be created, what it can't bring across, and — most usefully — the coverage you'd actually end up with. Nothing is written to your account during this stage. Then you confirm, and it builds everything in one go.

Where this is today. The check is live and complete: you can point it at your Opsgenie account right now and get the full report, and that report is worth having on its own — it will find problems in your current setup that are worth fixing whether or not you migrate. The one-click Import button that acts on the report is the next thing we're shipping. If you want your schedules moved before then, run the check and send us the report; we'll take it from there.

Opsgenie closes on 5 April 2027, and Atlassian deletes any configuration left behind. Sales ended in June 2025. There's no rush on any given day, but there is a hard deadline, and schedules are the part that takes longest to rebuild manually.


The good news about vocabulary

You don't have to relearn the model. Ours maps to Opsgenie's one-for-one:

In OpsgenieHere
ScheduleScheduleThe thing a flow points at. Owns a timezone and a set of rotations.
RotationRotationA layer inside a schedule: its own people, turn length, and coverage hours.
Rotation participantsRotation membersThe people, in order.
weekday-and-time-of-day restrictionCoverage hoursStored the same way — a weekly window with a start day/time and end day/time.
OverridesOverridesSomeone covering for someone else over a date range.

The concepts you already have in your head all still apply. If you built a follow-the-sun schedule in Opsgenie, it stays a follow-the-sun schedule here.

One behaviour worth knowing: Opsgenie schedules are cumulative — if two rotations both cover 3pm on a Tuesday, both of those people are on call. We support that too, and the import always sets your schedules to cumulative so they behave exactly as they did in Opsgenie. You'd otherwise end up with one person on call where Opsgenie had two.


What comes across, and what doesn't

Comes across:

  • Schedules, with their name, description and timezone
  • Rotations, in order, with their turn length (hourly / daily / weekly) and handoff time
  • Coverage hours, including overnight and multi-day windows
  • Participants, in order — including Opsgenie's "no one" slots, which stay deliberate gaps rather than becoming mistakes
  • Teams used as participants, expanded into their individual members
  • Overrides, and the people in them
  • People — matched to existing accounts by email address, so re-running the check never creates duplicates

Doesn't come across:

  • Escalation policies used as rotation participants. If a rotation says "page whatever this escalation policy resolves to", we won't guess who that is. Replace it with the actual people in Opsgenie first.
  • Another schedule used as a participant. Same reasoning: flattening a live schedule into a fixed list of names would look right on day one and quietly drift the first time that other schedule changed.
  • Per-rotation overrides stay whole-schedule. Opsgenie can override one rotation and leave the others alone; ours apply to the schedule. Yours will be imported as schedule-wide, which covers slightly more than the original did. The report tells you which ones.
  • Alerts, alert policies, integrations and routing rules. This is schedules only.

What you'll need

  1. An Opsgenie owner or admin, to create a read-only API key.
  2. Admin access here, since importing creates users.
  3. Enough seats on your plan for everyone in your schedules. The check tells you the exact number before anything happens, so you'll never get halfway and hit a wall.

Step 1 — Get your configuration out of Opsgenie

Two exports work. A third one — the one you'll find first by clicking around — does not. Start here so you don't lose an afternoon to it.

⚠️ Not the calendar export

Opsgenie's Export team schedule produces an .ics calendar file. It lists who was on call for the next twelve months, but not the rules that produced that list. Rotations can't be rebuilt from it — a follow-the-sun schedule or anything with coverage hours collapses entirely.

If you upload one, we'll tell you rather than guess. But it's the obvious-looking option, so it's worth knowing in advance.

Fastest, most complete, and nothing to install. You paste the key into the import screen yourself; you never send it to anyone.

  1. In Opsgenie, go to Settings → API key management and create a key with Read access.
  2. Check which Opsgenie you're on. Look at the address bar:
    • app.opsgenie.comUS
    • app.eu.opsgenie.comEU
  3. Here, open On-Call → Import from Opsgenie.
  4. Paste the key, select the matching region, and click Check my Opsgenie setup.
  5. When you're done migrating, delete the key in Opsgenie.

Get the region right. Opsgenie runs the US and EU as separate installations. A perfectly valid EU key used against the US endpoint is rejected with exactly the same error as a mistyped key — so if your key is refused and you're certain it's correct, try the other region before you do anything else.

Option B — export the files yourself

Use this if your security policy won't allow a live API key to be entered into another product. Run this in PowerShell on any machine that can reach Opsgenie; it writes a folder you can then upload.

$Key  = Read-Host "Opsgenie API key"
$Base = "https://api.opsgenie.com"        # EU customers: https://api.eu.opsgenie.com
$H    = @{ Authorization = "GenieKey $Key" }
$Out  = "OpsgenieExport"

New-Item -ItemType Directory -Force `
  "$Out\schedules","$Out\users","$Out\teams","$Out\overrides" | Out-Null

# Schedules. ?expand=rotation is essential — without it the rotations are left
# out and the schedules arrive looking empty.
$schedules = Invoke-RestMethod -Headers $H -Uri "$Base/v2/schedules?expand=rotation&limit=100"
$schedules | ConvertTo-Json -Depth 20 | Set-Content "$Out\schedules\schedules.json" -Encoding utf8

# Overrides, one file per schedule named after the schedule's id — that name is
# how they get matched back up, since an override doesn't say which schedule
# it belongs to.
foreach ($s in $schedules.data) {
  Invoke-RestMethod -Headers $H -Uri "$Base/v2/schedules/$($s.id)/overrides" |
    ConvertTo-Json -Depth 20 | Set-Content "$Out\overrides\$($s.id).json" -Encoding utf8
}

# People, 100 at a time.
$offset = 0
do {
  $page = Invoke-RestMethod -Headers $H -Uri "$Base/v2/users?limit=100&offset=$offset"
  $page | ConvertTo-Json -Depth 20 | Set-Content "$Out\users\users-$offset.json" -Encoding utf8
  $offset += 100
} while ($page.data.Count -eq 100)

# Teams. The team list doesn't include members, so each team needs its own call —
# skip this and any rotation that uses a team will look empty.
$teams = Invoke-RestMethod -Headers $H -Uri "$Base/v2/teams?limit=100"
foreach ($t in $teams.data) {
  Invoke-RestMethod -Headers $H -Uri "$Base/v2/teams/$($t.id)" |
    ConvertTo-Json -Depth 20 | Set-Content "$Out\teams\$($t.id).json" -Encoding utf8
}

Write-Host "Done. Upload the $Out folder."

Then choose Upload a backup folder → Choose folder and select OpsgenieExport.

If you export by hand, include the overrides folder. Anyone currently standing in for a colleague lives in an override, not in the rotation itself. If the upload has no overrides/ folder the report will say so rather than quietly reporting none — but it's easier to just include them.

Atlassian's own opsgenie-configuration-backup tool also produces a folder we can read (OpsGenieBackups, with schedules/, users/ and teams/ inside). It doesn't export overrides, so the script above is the better option if you use them.


Step 2 — Read the report

The check writes nothing. It reads your configuration, works out exactly what it would create, and then — this is the part worth slowing down for — runs the resulting schedules through the same engine that decides who gets paged, so what you see is genuinely what you'd get.

The report has three parts.

Counts

How many schedules, rotations and people, how many of those people are new versus already here, and how many seats the import needs. Check this against your plan before going further.

Blocking items — fix these first

Shown in their own section, because they stop the import. Each one names the object and what to do about it.

What it saysWhat to do
Needs more seats than your plan allowsBuy more seats on /billing, or move to a plan whose maximum covers the stated number.
This email is already used by an account outside your organisationEmail addresses are unique across the whole platform. Use a different address for that person, or contact support to move the existing account.
Participant is an escalation policy / another scheduleReplace it with the individual people in Opsgenie and export again, or leave that schedule out.
Timezone not recognisedSet a standard timezone on the schedule in Opsgenie.
A coverage window we can't readUsually a window that starts and ends on the same day with the end before the start (Mon 22:00 → Mon 02:00), which could mean four hours or almost a week. Split it across days: Mon 22:00 → Tue 02:00.
More than 20 rotations on one scheduleSplit it into two schedules in Opsgenie.
Rotation has nobody in it / no start date / an unrecognised turn lengthFix the rotation in Opsgenie, or remove it before exporting.

Fix what it lists, then run the check again. You can re-run as many times as you like.

Warnings — worth reading, but not blockers

What it saysWhat it means
These people have no phone numberOpsgenie doesn't include phone numbers in its export, so everyone arrives without one. This is the one most likely to cause a missed alert — an unreachable person still burns a full escalation window before the next person is tried. See "After the import" below.
This rotation includes a teamWe've expanded it into its individual members. The rotation won't automatically follow future changes to that team — add and remove people here instead.
SMS is off for everyoneExpected, and not an oversight. See "About SMS" below.
This schedule has N hours with nobody on callThe important one. Read on.
A rotation puts nobody on callUsually a coverage window that never comes round, or a rotation with no people in it. Worth checking in Opsgenie before importing.
Overrides that apply to specific rotationsYours will become schedule-wide, covering a little more than the original.
This upload didn't include any overridesWe're telling you we couldn't see them, rather than reporting none. Harmless if you don't use overrides; otherwise re-run with an API key, which collects them automatically.
This schedule is disabled in OpsgenieIt'll be imported switched off. Turn it on when you're ready.

"Download what we read"

Next to the counts there's a button that saves the raw Opsgenie data the report was built from, as a single JSON file.

You don't need it for a normal migration. It's there for two situations:

  • You're working with our support team. Sending this file lets us reproduce exactly what you're seeing, rather than guessing from a screenshot.
  • Something in the report looks wrong. The file is what we actually read, so it settles whether the problem is in your Opsgenie configuration or in our reading of it.

It contains your colleagues' names and email addresses, so open it and have a look before sending it anywhere. We don't keep a copy — it's generated in your browser from the report you just ran.

The coverage preview — don't skip this

For each schedule, you'll see the rotations you'd end up with, how much each one actually contributes, and how many hours in the next fortnight would have nobody on call.

A schedule can import perfectly cleanly and still have nobody on call every single night. That usually isn't an import error — it's that Opsgenie had a separate escalation rule quietly covering those hours, and that rule isn't part of your schedule. Worth catching now rather than at 3am.

If you see uncovered hours, the standard fix is an always-on rotation at the bottom of the list as a catch-all. See Coverage Gaps.


Step 3 — Import

Confirm, and everything is created in a single operation: people, team groups, schedules, rotations. All of it or none of it — you'll never be left with a half-built schedule.

Nothing is sent to anyone about being on call. Importing a schedule doesn't page anybody, and it doesn't start alerting until you point a flow at it.


After the import — three things that make it real

1. Add the missing phone numbers. Nobody can be called or texted without one. People can add their own under Settings, or an admin can do it from Users. Email works immediately either way.

2. Point a flow at the schedule. This is the step most likely to catch you out coming from Opsgenie, where schedules attach to alert policies. Here, a schedule is just a definition of who's on call — it doesn't do anything until something targets it. Open a flow, choose the schedule as the recipient, done. See On-Call Schedules.

3. Send a test alert. The only way you'll trust it.


About SMS

Everyone is imported with SMS switched off, and we won't turn it on for them.

That's a consent requirement, not an oversight. Bulk-importing a list of people and immediately texting them isn't something anyone can consent to on their behalf. Instead, each person is asked the first time they sign in — which is also a much stronger basis, because it comes from them and it's timestamped.

Calls, email and push all work from the moment the import finishes. Only SMS waits.


Troubleshooting

"Opsgenie rejected the API key." Check the region first, before you re-check the key. A valid EU key against the US endpoint fails identically to a wrong key. Then confirm the key has Read access and hasn't been deleted.

"These schedules came through without their rotations." The schedule list was fetched without ?expand=rotation. If you used the script above, make sure that parameter survived the copy/paste.

"No members for this team were in the export." The team list doesn't include members — each team needs its own API call. The script above does this in its foreach loop; if you exported by hand, that's the step that's missing.

"This is a calendar export." You've uploaded the .ics. See the warning at the top of Step 1 — use an API key or the script instead.

The check times out or Opsgenie rate-limits you. Wait a minute and try again. Very large accounts occasionally trip Opsgenie's rate limit partway through.


  • On-Call Schedules — the model your imported schedules land in, and how to point a flow at one
  • Rotations & Coverage Hours — different people for different hours, and what happens when rotations overlap
  • Coverage Gaps — closing the uncovered hours the report finds
  • Escalation Policies — the closest equivalent to the Opsgenie escalation policies this import deliberately leaves behind