Migrating from OpsGenie to SignedApproval
OpsGenie is shutting down on April 5, 2027. If you have approval or acknowledgment workflows running on OpsGenie, this guide walks you through migrating them to SignedApproval before the deadline.
OpsGenie is an alert management and on-call platform. Many teams use it not just for incident alerts, but as a lightweight approval gate: send an alert, wait for acknowledgment, continue the workflow. SignedApproval covers the same use case with one critical difference: OpsGenie acknowledgment is an audit log entry. SignedApproval approval is a cryptographic proof.
An OpsGenie acknowledgment tells you someone clicked the button. It does not prove who clicked it, that they were authenticated at the time, or that they had actually reviewed the action. A SignedApproval credential records the authenticated decision with an Ed25519 signature that any party can verify, offline, without calling our API, years after the fact.
For teams that only need operational continuity, the migration is a drop-in replacement. For teams with compliance requirements, the migration is actually an upgrade.
The core API difference
The call site is nearly identical. Replace your OpsGenie alert call with a SignedApproval request, wait for the decision, and continue. The difference is in what comes back.
import opsgenie_sdk as og
api = og.AlertApi()
# Create alert and wait for ack
alert = api.create_alert(og.CreateAlertPayload(
message="Deploy to production?",
description=f"Branch: {branch}, SHA: {sha}",
priority="P2",
responders=[{"type": "team", "name": "platform"}],
))
# Poll for acknowledgment (no auth proof)
while True:
status = api.get_alert(alert.data.request_id)
if status.data.acknowledged:
break # Someone clicked. Who? Unknown.
time.sleep(5)import signedapproval as sa
client = sa.Client(api_key="sa_live_...")
# Create request and wait for signed decision
req = client.request(
action=f"Deploy {branch} ({sha}) to production",
approver_email="platform@yourco.com",
ttl_seconds=900,
)
# Poll for decision (returns Ed25519-signed credential)
decision = client.wait_for_decision(req.id)
if decision.status == "approved":
# credential is offline-verifiable proof
store_with_deploy(decision.credential)Create a SignedApproval account
Sign in at signedapproval.net/login with Google OAuth. Create your first API key from Dashboard → API Keys → New Key. Note thesa_live_prefix — this is your caller credential.
Install the SignedApproval SDK
Install the SDK for your language:
# Python pip install signedapproval # Node.js npm install @signedapproval/sdk
Map your OpsGenie workflows to SA requests
For each workflow that creates an OpsGenie alert and waits for acknowledgment:
- Replace
api.create_alert()withclient.request() - Replace on-call team routing with
approver_emailor an approver group - Replace the acknowledgment poll with
client.wait_for_decision() - Store the returned
credentialalongside the action for audit purposes
Install the SignedApproval iOS app
Approvals are delivered as iOS push notifications. The approver reviews the action description and authenticates with Face ID or a passkey — no Slack, no email link. Install the app from TestFlight (public link coming to App Store in Q2 2026) and sign in with the same Google account used to create the approver profile.
Run both systems in parallel
Before decommissioning OpsGenie workflows, run both systems simultaneously for at least two weeks. Use a feature flag to control which path is active:
if feature_flags.use_signedapproval:
decision = sa_client.wait_for_decision(sa_request.id)
else:
decision = opsgenie_ack_poll(og_alert_id)Migrating OpsGenie outbound webhooks
If you use OpsGenie's outbound webhook integrations to notify other systems when an alert is acknowledged, replace them with SignedApproval Log Sinks.
Log Sinks stream approval events (created, approved, rejected, expired) to any HTTPS endpoint via HMAC-signed webhook payloads. Each event includes the full approval context and, for decided events, the Ed25519 credential.
| OpsGenie | SignedApproval |
|---|---|
| Outbound webhook — alert created | Log Sink event: approval.created |
| Outbound webhook — acknowledged | Log Sink event: approval.approved |
| Outbound webhook — closed | Log Sink event: approval.rejected or approval.expired |
| Alert payload (JSON) | Event payload includes Ed25519 credential for decided events |
| HMAC-SHA256 signature header | X-SignedApproval-Signature: sha256={hmac} |
Create a Log Sink from Dashboard → Settings → Log Sinks. Point it at your existing webhook receiver URL. Update your receiver to handle the new event schema (documented at /help/integrations/webhooks).