# Rootly AI
Source: https://docs.rootly.com/ai/ai
An AI responder on your team: grounded in the incident's live context, and never able to do more than the person asking.
## Overview
Rootly AI is an AI responder built into the places your team already works. Ask it what's happening and it answers from the incident's live context. Ask it to do something and it does it, capped at what you can do in Rootly and audited under the name of the person who asked.
Everything below is opt-in and governed from [AI Settings](/ai/ai-settings).
***
## Where It Works
| Surface | What you get | Learn more |
| ---------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| **Slack** | The full agent in your incident channels: it pages responders, updates the incident, assigns roles, and drafts comms | [Rootly AI in Slack](/ai/rootly-in-slack/overview) |
| **Web** | Ask-anything chat on the incident page, read-only by design | [Rootly AI in Web](/ai/ask-rootly-ai) |
| **Mobile** | A live summary card, plus chat that updates the incident with confirmation | [Rootly AI on Mobile](/ai/rootly-ai-on-mobile) |
***
## What It Does
| Feature | In one line | Learn more |
| ------------------------ | ------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| **AI Summaries** | Titles, summaries, catchups, and status write-ups, generated from the incident's own record | [AI Summaries](/ai/ai-summaries) |
| **Related Incidents** | Ranked matches from your incident history, grounded in how each one was resolved | [Related Incidents](/ai/related-incidents) |
| **Meeting Scribe** | Turns the bridge call into a live, speaker-labeled record on the incident | [Meeting Scribe](/ai/meeting-scribe) |
| **AI in Retrospectives** | Drafts retrospective sections from incident data, sources shown and fully editable | [AI in Retrospectives](/ai/ai-in-retrospectives/overview) |
***
## Extend It
| Direction | In one line | Learn more |
| --------------------- | ------------------------------------------------------------------------------------------- | -------------------------------------- |
| **Connectors** | Bring your data to Rootly AI: it investigates with your observability, code, and docs tools | [Connectors](/ai/connectors/overview) |
| **Rootly MCP Server** | Bring Rootly to your AI: query incidents and on-call from Claude, Cursor, or any MCP client | [MCP Server](/integrations/mcp-server) |
***
## Govern It
One switch opts your organization in; per-feature toggles decide where Rootly AI shows up.
| Page | What it covers | Learn more |
| -------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------ |
| **AI Settings** | Every Rootly AI control in one place | [AI Settings](/ai/ai-settings) |
| **Data Privacy for Rootly AI** | The agent's data access, retention, audit, and model details | [Data Privacy for Rootly AI](/ai/data-privacy-for-rootly-ai) |
| **Data Privacy for AI Summaries & Meeting Scribe** | Data handling for the single-turn features and the scribe pipeline | [AI Summaries & Meeting Scribe](/ai/data-privacy-for-ai) |
# Building AI Templates
Source: https://docs.rootly.com/ai/ai-in-retrospectives/building-ai-templates
Add Rootly AI blocks to a retrospective template and preview the output against a past incident before rollout.
## AI Blocks Start in the Template
The fastest way to get Rootly AI-generated retrospectives is to add AI blocks to a **template**. Every retrospective created from that template generates those sections automatically. The quickest start of all is a **[starter template](#start-from-a-starter-template)**, a ready-made, Rootly AI-powered template you can adopt in one click.
You can also drop AI blocks into an individual document on the fly (see [Using AI Blocks](/ai/ai-in-retrospectives/using-ai-blocks)), but templates are where you set the standard for the whole team.
For how templates work in general, including formats, Liquid, data blocks, and defaults, see [Configuring Templates](/retrospectives/configuring-templates).
***
## Start from a Starter Template
Rootly ships four starter templates:
| Starter template | Best for | What's inside |
| :---------------------------------- | :------------------------------------------------- | :---------------------------------------------------------------------------------------------------------- |
| **Standard Incident Retrospective** | A thorough, all-purpose retro | Summary, Impact, Root Cause, Mitigation, and Resolution AI blocks, plus Timeline and Follow-ups data blocks |
| **Quick Retro** | Low-severity incidents and fast write-ups | A Summary AI block, plus Timeline and Follow-ups data blocks |
| **Customer-Facing RCA / COE** | A root-cause analysis you can share with customers | Summary, Impact, Root Cause, and Resolution AI blocks, plus corrective-action Follow-ups |
| **Major Incident (SEV1) Deep-Dive** | High-severity, leadership-visible incidents | All six AI blocks, plus Timeline and Follow-ups data blocks |
You can adopt a starter from two places:
* On the **Retrospectives → Document Templates** page, click **Try template** on a starter to open the builder preloaded with it. Nothing is created until you save.
* Already in the builder? Open the **AI Library** tab in the sidebar and click a starter to insert its content. An empty document is seeded with it; a document that already has content gets the starter appended. Each insert gets fresh blocks, so you can insert more than one without collisions.
***
## Open the Template Builder
To build a template from scratch:
***
## Global
Guardrails for Rootly AI's entire surface area. Every section below, from Features to AI SRE to Connectors, is gated by what you set here.
| Setting | What it controls |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **Opt in to Rootly AI capabilities** | The organization-wide switch. Turning it off disables every Rootly AI feature at once, regardless of the individual toggles under Features. |
***
## Features
Rootly AI's core capabilities are grouped by surface area, so your team decides exactly where Rootly AI shows up.
### Incidents
| Toggle | What it controls | Learn more |
| -------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------ |
| **Incident summarization** | AI-generated summaries that bring your team up to speed on the incident. | [AI Summaries](/ai/ai-summaries) |
| **Related incidents** | Ranked matches from your own incident history, grounded in how each one was resolved. | [Related Incidents](/ai/related-incidents) |
### Slack
| Toggle | What it controls | Learn more |
| ------------------------- | ---------------------------------------------------------- | -------------------------------------------------- |
| **Rootly Agent in Slack** | The AI assistant responders talk to without leaving Slack. | [Rootly AI in Slack](/ai/rootly-in-slack/overview) |
### Retros
| Toggle | What it controls | Learn more |
| ------------------------ | ------------------------------------------------------------- | --------------------------------------------------------- |
| **AI in Retrospectives** | AI help drafting retrospectives, right inside your templates. | [AI in Retrospectives](/ai/ai-in-retrospectives/overview) |
### Web
| Toggle | What it controls | Learn more |
| ----------------------- | ---------------------------------------- | ------------------------------------- |
| **Rootly Agent in Web** | The ask-anything AI chat in the web app. | [Rootly AI in Web](/ai/ask-rootly-ai) |
### Mobile
| Toggle | What it controls | Learn more |
| -------------------------- | ------------------------------ | ---------------------------------------------- |
| **Rootly Agent in Mobile** | The AI chat in the mobile app. | [Rootly AI on Mobile](/ai/rootly-ai-on-mobile) |
***
## AI SRE
Your AI SRE teammate: it autonomously investigates alerts and hands responders the likely root cause with recommended next steps. Your Rootly account team enables it for your organization.
***
## Connectors
You choose the data sources Rootly AI can query during investigations: observability platforms, code hosts, docs, and your own MCP servers. Configure them here, documented in full at [Connectors](/ai/connectors/overview).
***
## Related Pages
Catchup requires permission to generate summaries on the incident or permission to update it.
***
## Generated Titles
Run `/rootly update` in the incident channel and click **Generate with AI**. Rootly AI reads the summary, alerts, and early timeline to produce the title. Regenerate as the picture sharpens.
***
## Status Summaries
When an incident changes status, Rootly AI drafts the explanation, focused on what the transition needs:
| Status | The summary explains |
| ------------- | ----------------------------------- |
| **Mitigated** | What was done to reduce impact |
| **Resolved** | How the incident was fully resolved |
| **Cancelled** | Why the incident was cancelled |
| **Closed** | Why the incident was closed |
In the web app, click **Generate with AI** next to the status message field when updating status. In Slack, `/rootly mitigate` or `/rootly resolve` opens the same dialog. You review and edit the draft before submitting.
***
## Setup
All four features are part of Rootly AI, behind the [organization-wide opt-in](/ai/ai-settings). Only Admins can change AI settings.
1. Open **AI & Agents** and turn on **Opt in to Rootly AI capabilities**. Titles and status summaries are available immediately; they have no separate toggle.
2. Under **Features**, toggle **Incident summarization** on. This enables both summaries and catchup.
For the best results, set **Slack channel message visibility** to **All messages** or **All messages in Public + pinned in Private**, so summaries can draw on channel communications.
You provide the endpoint and the OAuth details. Rootly AI authorizes against your server, then calls tools you've explicitly allowlisted during investigations.
Internal data also carries context no vendor tool has, and Rootly AI reasons over it. Here, customer SLA data becomes business impact and suggested next steps:
### Write Tools
Built-in connectors are strictly read-only. The Custom connector is the one place Rootly AI can act on your systems, and only through a write-capable tool you have deliberately allowlisted. Here, a responder asks Rootly AI to record the incident's findings, and the note lands in the knowledge base for whoever hits this failure mode next:
Newly discovered tools stay unchecked until you enable them, so a write tool is always a deliberate choice. Read the warning at the top of this page before allowlisting one.
***
## Managing the Connection
Open the connection's **Configure** screen to:
* **Change which tools are exposed.** Reopen **Choose tools**, adjust the checkboxes, and click **Save tools**. Unchecking a tool takes effect on the next investigation.
* **Update the endpoint URL.** If you move your MCP server, point Rootly at the new host. Rootly re-authorizes on save.
* **Rotate credentials.** Disconnect and reconnect to trigger a fresh OAuth flow. Old tokens are revoked.
Your server's tool catalog isn't frozen at connect time. Each time you open **Choose tools**, Rootly re-discovers what the server exposes. Ship a new tool and it appears in the list, unchecked, ready to enable when you are:
***
## Best Practices
* **Start with a minimal allowlist.** Only allowlist the tools you're sure Rootly AI should call. It's easier to add later than to explain a surprise tool call.
* **Give the connection a descriptive name.** *"Internal ops MCP"* or *"Finance data MCP"* is more useful than *"Custom MCP"* when Rootly AI cites it in an investigation summary. Use the optional description to record what it exposes.
* **Rotate on personnel changes.** The OAuth grant is tied to whoever authorized it. When that person leaves, disconnect and reconnect from someone else's account so the connection doesn't die silently.
* **Prefer named connectors over Custom when a native one exists.** If Rootly ships a first-class connector for what you're doing, use it. First-class connectors get better UI, tighter tool sets, and validated setup.
***
## Troubleshooting
***
## Setup
Meeting Scribe rides on your existing meeting-platform integration: connect the platform, then enable the scribe toggle.
***
## Multilingual Support
The scribe transcribes 20+ languages, auto-detecting the language spoken and producing the transcript in it. Your Rootly account team enables it for your workspace.
***
## Privacy and Security
**The short version:**
| Guarantee | Detail |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| **Redacted before storage** | Every transcript passes PII redaction across 36 categories before it is stored. |
| **Scoped access** | Meeting data is visible only within the associated incident and team, with audit logging on deletions. |
| **No retention at AssemblyAI or OpenAI** | Neither keeps data after processing. Recall.ai media retention is managed separately by Rootly. |
| **You control deletion** | Recordings and transcripts can be deleted from the **Scribe** tab at any time. |
The full dossier, covering subprocessors, the data flow, every redaction category, and retention per storage location, lives at [Data Privacy for AI Summaries & Meeting Scribe](/ai/data-privacy-for-ai).
***
## Troubleshooting
For platform-specific issues, start with the dedicated pages:
Matches surface right in the incident channel and on demand, whenever a responder asks.
### Acting on a Match
Every match card carries the same set of actions:
| Button | What it does |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Mark as related** | Trains the model that this was a good match, so future recommendations within your team's incident set get better. |
| **Not related** | Trains the model that this was not a good match, so future recommendations within your team's incident set get better. |
| **Channel** | Opens the Slack incident channel for the related incident. |
| **View in Web** | Opens the related incident's details page in Rootly on the web. |
Feedback only shapes recommendations for your own team — it never trains models for other customers (see [Privacy](#privacy)).
***
## Grounded Answers
Ask `what fixed it?` and get an answer you can act on mid-incident:
* **On the record.** The documented resolution is relayed.
* **Nothing recorded.** Rootly AI says so and offers the retrospective or timeline.
Anything beyond your records is labeled inference ("the pattern suggests"), not fact.
***
## Selective by Design
* Reads each incident like a responder would: title, summary, severity, services, and more.
* Keeps only genuine, concrete relationships. Similar wording alone doesn't qualify.
Matching stays live: a new near-duplicate can hit rank #1 within minutes.
### What Qualifies as a Match
| Rule | Detail |
| ----------------------- | ---------------------------------------------------- |
| **Your org only** | Drawn exclusively from your team's incident history. |
| **Confirmed incidents** | Excludes cancelled incidents. |
| **Recent history** | Looks back 180 days by default. |
| **Public incidents** | Only what the whole channel can see. |
Tap the card, or the **Ask Rootly** launcher, to open the full summary in the Rootly AI panel. It breaks the incident down into key points such as the impact, the root cause, the current status, and what's left to do, with suggested questions to dig deeper.
***
## Rootly AI Chat
The **Rootly AI** panel is an AI agent for the incident you're viewing. It answers questions in natural language, grounded in that incident's live context: its timeline, severity, status, roles, alerts, and related Slack discussion.
Tap **Ask Rootly** to open the chat. Four suggested prompts get you started:
* **Catch me up**
* **What's the customer impact**
* **Who is working on what?**
* **Show open action items**
Your conversation is saved per incident and picks up where you left off.
Rootly AI receives your request and responds in the same thread.
You can also talk to Rootly AI privately. Open Rootly from Slack's **Add agent** menu, or DM the Rootly app directly. Both surfaces answer questions only.
### Try These First
* "Catch me up"
* "Who's on call?"
* "Escalate to SEV1"
* "What are the open action items?"
For the full guide to each surface, see [Using Rootly AI in Slack](/ai/rootly-in-slack/using-rootly-in-slack). For the full prompt catalog, see [What to Use Rootly AI For](/ai/rootly-in-slack/what-to-use-rootly-for).
***
## Related Pages
Answers like this one draw on your own tools through [Connectors](/ai/connectors/overview): plug in your observability, code, and docs sources and Rootly AI investigates with them.
### Using Clarification Cards
Based on how much input Rootly AI needs, you'll be able to reply via:
| Options | How you answer |
| :----------------------------------- | :-------------------------------------------------------- |
| Up to 5 | Buttons, with the first highlighted as the primary choice |
| 5 to 25 | A single-select dropdown |
| More than 25, or no fixed answer set | Free text, replied in the thread |
Cards expire after **60 minutes**. Re-ask your question to get a fresh card.
***
## Taking Action with Rootly AI
Ask for an action and Rootly AI runs it, confirming what it did in its reply. When an action is destructive, or Rootly AI wants your sign-off first, it posts the change as a card with a **Confirm** button and runs only after you approve.
| You say | Rootly AI replies |
| :---------------------- | :-------------------------------------------------- |
| "I'll take commander." | *"You're now the commander."* |
| "Escalate to SEV1." | *"Set severity to SEV1."* |
| "Page the SRE on-call." | *"Paged the SRE team via their escalation policy."* |
If anything fails, Rootly AI tells you why in the same thread.
Every action is capped at **your permissions** and attributed to you in the audit trail. Rootly AI cannot perform any action you couldn't perform yourself in the Rootly web app.
***
## Worked Example: Paging an On-Call Team
This shows the clarification flow in action:
* Type `@Rootly page the team` in the incident channel.
* Rootly AI searches your Rootly catalog for the team to page.
* If multiple teams match, Rootly AI posts a clarification card: `"Which team do you want to page?"` with a dropdown. You pick one and click **Confirm**.
* Rootly AI pages via Rootly On-Call to the team's current on-call, using their configured notification preferences. Rootly AI replies: `"Page request submitted to Rootly On-Call for the Rootly team."` The audit trail attributes the page to you, not to Rootly AI.
* **If you don't have permission to page in Rootly, Rootly AI tells you so and stops.**
***
## Related Pages
### Search and Lookups
| **You ask** | **What Rootly AI does** |
| :---------------------------------------------------------- | :---------------------------------------------------------------------------------------------- |
| "Show me open SEV1s" | Filters by status and severity |
| "How many incidents touched checkout-service this quarter?" | Searches by service and date range, counts results |
| "What's our average time-to-mitigate for SEV1s this year?" | Searches incidents and reasons over the result set |
| "What custom fields are on this incident?" | Lists configured custom fields and their values |
| "What status can I move this to from here?" | Lists valid next statuses given the incident's current state, team config, and sub-status rules |
| "List my teams" | Returns teams the requesting user belongs to |
| "What's 3:47 PM UTC in my time zone?" | Converts using your configured zone or a named IANA zone |
***
## More Complex Requests
Rootly AI in Slack can also run several operations at once to answer your question, and it reasons over the results to handle requests that don't map to one specific ask.
### Critical Timeline Analysis
Ask Rootly AI *"What's missing from this timeline? Be critical."*
Rootly AI reads the timeline, channel discussion, roles, and standard process expectations, then identifies gaps a senior responder would catch in a retro. Things like: no commander formally assigned, no root cause documented, the incident was resolved before the fix was merged, no status page update.
### Severity Second Opinion
Ask *"was SEV3 the right call?"*
Rootly AI looks at the affected services, duration, the responder pattern, and customer-impact signals in the channel, then gives a nuanced opinion, pushing back when the evidence supports it.
### Extended Retrospective Conversations
Rootly AI supports back-and-forth conversations during a retrospective. Ask "what could have gone better?" → "how did comms look?" → "who should have taken what role?" → "similar past incidents?" → "was the severity call right?" → "how could we have resolved faster?" Rootly AI maintains context across the thread.
### Adaptive Technical Depth
Rootly AI adapts to the asker. *"Catch me up"* produces a structured exec brief. *"Catch me up, I'm a Staff Engineer"* produces a technical response naming the failing code path, the relevant error codes, and the race condition. Same incident, different audience.
### Multi-Step Actions
Rootly AI can chain multiple write actions in a single conversation. For example: "page the on-call for payments, then mark this SEV1, and create an action item to investigate." Each destructive step confirms separately. The final reply summarizes everything Rootly AI did.
***
## What Rootly AI Can't Do
* **Writes only happen inside incident channels.** The Slack side pane and DMs are read-only by design.
* **Paging is through Rootly On-Call only.** Even if PagerDuty, Opsgenie, or JSM Ops are connected elsewhere in Rootly, Rootly AI will not page through them.
* **No production runtime actions.** Rootly AI won't run kubectl, roll back a deploy, restart a pod, or flip a feature flag. It can create an action item and page someone who will.
* **No code generation or PR creation.** Rootly AI doesn't write code.
* **Reactive by design.** Rootly AI responds when asked; it doesn't interject in your channels uninvited.
* **It won't invent data.** If the answer isn't in your Rootly data, the channel discussion, or a connected external source, Rootly AI says so rather than guessing.
***
## Related Pages
Rootly evaluates rules **top-to-bottom**, so ordering matters.
Use the rule menu (**… → Reorder rule**) to adjust order.
***
## How Rootly Routes Alerts
Rootly evaluates alerts in two sequential stages.
### Stage 1 — Payload-Based Routing
If the alert payload contains a **target ID** (team or service), Rootly immediately routes the alert there without evaluating Alert Routes.
### Stage 2 — Evaluate Alert Routes
If the alert does not specify a target:
### Evaluate Routes
Rootly evaluates **every Alert Route associated with the alert’s source**.
### Evaluate Rules
Within each route, rules are evaluated **from top to bottom**.
* The first matching rule triggers paging
* Rootly stops evaluating additional rules in that route
* Other routes referencing the same source will still run
\
--data redirect_uri= \
--data client_id= \
--data code_verifier=
```
**Confidential client** (authenticate with client secret via HTTP Basic; PKCE still recommended):
```bash theme={null}
curl --request POST \
--url https://rootly.com/oauth/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--user ':' \
--data grant_type=authorization_code \
--data code= \
--data redirect_uri= \
--data code_verifier=
```
Response:
```json theme={null}
{
"access_token": "…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "…",
"id_token": "…",
"scope": "openid profile email ir.incidents:read"
}
```
### 4. Call the Rootly API
```bash theme={null}
curl --request GET \
--header 'Content-Type: application/vnd.api+json' \
--header 'Authorization: Bearer ' \
--url https://api.rootly.com/v1/incidents
```
### 5. Refresh the token
Access tokens expire after **1 hour**. Refresh tokens rotate on use — the old refresh token is invalidated after a short grace period.
**Public client:**
```bash theme={null}
curl --request POST \
--url https://rootly.com/oauth/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=refresh_token \
--data refresh_token= \
--data client_id=
```
**Confidential client:**
```bash theme={null}
curl --request POST \
--url https://rootly.com/oauth/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--user ':' \
--data grant_type=refresh_token \
--data refresh_token=
```
## Client Credentials flow
Use this flow for server-to-server automation where no end user is involved (CI jobs, scheduled tasks, internal services). Requires a **confidential** application created by a team admin.
When the application is created, Rootly auto-provisions a dedicated service user in the team. The service user's `Role` and `OnCallRole` permissions are derived from the app's scopes, so the token's effective access is exactly what the scopes describe.
```bash theme={null}
curl --request POST \
--url https://rootly.com/oauth/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--user ':' \
--data grant_type=client_credentials \
--data scope='ir.incidents:write oc.alerts:read'
```
Client-credentials applications must request at least one resource scope (`ir.*`, `oc.*`, or `ai.*`) or the `all` meta scope.
## Dynamic Client Registration (RFC 7591)
CLIs, desktop apps, MCP clients, and third-party integrations can self-register without authentication. Both public and confidential auth-code clients are supported.
**Public client** (no secret — typical for CLIs and native apps):
```bash theme={null}
curl --request POST \
--url https://rootly.com/oauth/register \
--header 'Content-Type: application/json' \
--data '{
"client_name": "My CLI",
"redirect_uris": ["http://127.0.0.1:7890/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code"],
"response_types": ["code"]
}'
```
Response:
```json theme={null}
{
"client_id": "…",
"client_id_issued_at": 1745000000,
"client_secret_expires_at": 0,
"client_name": "My CLI",
"redirect_uris": ["http://127.0.0.1:7890/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code"],
"response_types": ["code"],
"scope": "openid profile email ir.incidents:read ir.incidents:write …"
}
```
**Confidential client** (secret returned once — typical for server-side web apps):
```bash theme={null}
curl --request POST \
--url https://rootly.com/oauth/register \
--header 'Content-Type: application/json' \
--data '{
"client_name": "My Web App",
"redirect_uris": ["https://myapp.example.com/callback"],
"token_endpoint_auth_method": "client_secret_basic",
"grant_types": ["authorization_code"],
"response_types": ["code"]
}'
```
The response includes a `client_secret` field — **store it immediately**, as it cannot be retrieved again.
Client-credentials apps (server-to-server, no redirect URI) cannot be created via Dynamic Client Registration. A team admin must create them in **Organization Settings → OAuth Applications**.
Rules:
* `token_endpoint_auth_method` must be one of: `none`, `client_secret_post`, or `client_secret_basic`.
* Redirect URIs must use HTTPS. HTTP is allowed for the loopback addresses `127.0.0.1`, `[::1]`, and `localhost` for local development.
* If no `scope` is provided, the app is registered with all supported scopes. Meta scopes are expanded into individual permissions on the consent screen so the user can narrow access.
* Meta scopes (`all`, `ir.all`, `oc.all`) and granular `ir.*`, `oc.*`, and `ai.*` scopes are accepted during registration. For least-privilege AI access, request `ai.chat:read` or `ai.chat:write` instead of `all`.
* Registration is rate-limited to **10 requests per hour per IP**.
* The team the application operates against is assigned when the first user authorizes it.
## UserInfo
```bash theme={null}
curl --request GET \
--header 'Authorization: Bearer ' \
--url https://rootly.com/oauth/userinfo
```
Returned claims depend on the granted OIDC scopes:
| Claim | Requires scope | Description |
| -------------- | -------------- | ----------------------------------------- |
| `sub` | `openid` | Rootly user ID. |
| `email` | `email` | User email. |
| `name` | `profile` | User full name. |
| `team_id` | `profile` | Team the token is scoped to. |
| `role` | `profile` | Incident Response role name on that team. |
| `on_call_role` | `profile` | On-Call role name on that team. |
ID tokens are signed with **RS256**. Fetch signing keys from `https://rootly.com/oauth/discovery/keys`.
## Authenticating API calls
On Rootly's resource API (`https://api.rootly.com/v1/*`), OAuth 2.0 access tokens and API keys use the same `Authorization: Bearer …` header. The API tries API keys first, then OAuth tokens — you never need to tell Rootly which one you are sending.
```bash theme={null}
curl --request GET \
--header 'Content-Type: application/vnd.api+json' \
--header 'Authorization: Bearer ' \
--url https://api.rootly.com/v1/incidents
```
This applies only to resource endpoints under `/v1/*`. The OAuth protocol endpoints on `rootly.com` (`/oauth/token`, `/oauth/authorize`, `/oauth/register`, `/.well-known/*`) use their own authentication rules described above.
Rate limits, pagination, and the JSON:API contract are identical to the API-key path — see the [API Overview](/api-reference/overview).
## Using Rootly tokens with external services
Rootly's OAuth 2.0 + OIDC server isn't only for authenticating to Rootly's API. Any external service that supports OAuth 2.0 token validation can accept Rootly-issued tokens and use Rootly's UserInfo response as the source of truth for user identity, team scope, and role.
The pattern:
1. Your application obtains a Rootly OAuth token using one of the flows above.
2. The application sends the token as `Authorization: Bearer ` to the external service.
3. The external service validates the token by calling `https://rootly.com/oauth/userinfo` with that same `Authorization` header, then reads the returned claims (`sub`, `team_id`, `role`, `on_call_role`) for access decisions.
Because Rootly's UserInfo claims align with the field names most OAuth-aware proxies expect by default, the gateway-side configuration is usually three or four environment variables plus a single config toggle. The example below walks through LiteLLM specifically; the same shape applies to any OAuth 2.0 token-validating proxy.
### Example: LiteLLM AI gateway
[LiteLLM](https://docs.litellm.ai/) is an AI gateway proxy that supports [OAuth 2.0 token validation](https://docs.litellm.ai/docs/proxy/oauth2) as an Enterprise feature. Pointing it at Rootly's UserInfo endpoint lets your team reuse Rootly identities — and the existing Rootly role and team model — for AI-gateway access control, cost attribution, and rate limiting.
Set LiteLLM's environment variables to point at Rootly's UserInfo endpoint and the matching claim names:
```bash theme={null}
export OAUTH_TOKEN_INFO_ENDPOINT="https://rootly.com/oauth/userinfo"
export OAUTH_USER_ID_FIELD_NAME="sub"
export OAUTH_USER_ROLE_FIELD_NAME="role"
export OAUTH_USER_TEAM_ID_FIELD_NAME="team_id"
```
Then enable OAuth 2.0 auth in LiteLLM's `config.yaml`:
```yaml theme={null}
general_settings:
master_key: sk-1234
enable_oauth2_auth: true
```
LiteLLM reads `sub`, `team_id`, and `role` from Rootly's UserInfo response. Those claims require the `openid` and `profile` scopes to be granted on the access token — see [OIDC scopes](#oidc-scopes). A typical scope set for gateway use:
```text theme={null}
openid profile email
```
The token itself does not need any `ir.*` or `oc.*` resource scopes because the request never touches Rootly's resource API — only the UserInfo endpoint, which any valid token can call.
Application code obtains a Rootly access token using whichever flow fits the deployment model:
* **Interactive users** — Authorization Code with PKCE ([above](#authorization-code-flow-with-pkce))
* **Server-to-server automation** — Client Credentials ([above](#client-credentials-flow))
Then forwards the token to LiteLLM unchanged:
```bash theme={null}
curl --request POST \
--url http://your-litellm-host:4000/chat/completions \
--header 'Authorization: Bearer ' \
--header 'Content-Type: application/json' \
--data '{
"model": "gpt-4",
"messages": [{"role": "user", "content": "summarize the incident postmortem"}]
}'
```
LiteLLM calls Rootly's UserInfo endpoint with the same bearer token, extracts the user identity and team, and applies whatever per-user or per-team policies you've configured in LiteLLM (rate limits, allowed models, spend caps).
### Why this is useful
| Outcome | How Rootly OAuth makes it work |
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| One identity surface | A user added to Rootly automatically has gateway access; removal revokes both in lockstep. |
| Per-team cost attribution | LiteLLM's spend tracking groups by `team_id` from the UserInfo response — same `team_id` Rootly already scopes incidents and on-call schedules to. |
| Central revocation | Revoke a Rootly OAuth token via `POST /oauth/revoke` and the gateway stops honoring it immediately. |
| No per-gateway credential sprawl | The gateway never holds long-lived API keys for individual users; it only validates short-lived OAuth tokens at request time. |
LiteLLM's OAuth 2.0 token validation is a paid Enterprise feature. The Rootly-side OAuth 2.0 server is the same one documented above and is included in standard Rootly access — no additional plan tier is required on Rootly's side to use Rootly as the identity provider for an external service.
# Creates an On-Call Pay Report
Source: https://docs.rootly.com/api-reference/oncallpayreports/creates-an-on-call-pay-report
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/on_call_pay_reports
Generates a new on-call pay report for the given date range. The report is generated asynchronously.
# List On-Call Pay Reports
Source: https://docs.rootly.com/api-reference/oncallpayreports/list-on-call-pay-reports
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/on_call_pay_reports
List on-call pay reports
# Regenerate an On-Call Pay Report
Source: https://docs.rootly.com/api-reference/oncallpayreports/regenerate-an-on-call-pay-report
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/on_call_pay_reports/{id}/regenerate
Triggers regeneration of an existing on-call pay report.
# Retrieves an On-Call Pay Report
Source: https://docs.rootly.com/api-reference/oncallpayreports/retrieves-an-on-call-pay-report
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/on_call_pay_reports/{id}
Retrieves a specific on-call pay report by id
# Update an On-Call Pay Report
Source: https://docs.rootly.com/api-reference/oncallpayreports/update-an-on-call-pay-report
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/on_call_pay_reports/{id}
Update a specific on-call pay report by id. Triggers report regeneration.
# Creates an On-Call Role
Source: https://docs.rootly.com/api-reference/oncallroles/creates-an-on-call-role
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/on_call_roles
Creates a new On-Call Role from provided data
# Delete an On-Call Role
Source: https://docs.rootly.com/api-reference/oncallroles/delete-an-on-call-role
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/on_call_roles/{id}
Delete a specific On-Call Role by id
# List On-Call Roles
Source: https://docs.rootly.com/api-reference/oncallroles/list-on-call-roles
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/on_call_roles
List On-Call Roles
# Retrieves an On-Call Role
Source: https://docs.rootly.com/api-reference/oncallroles/retrieves-an-on-call-role
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/on_call_roles/{id}
Retrieves a specific On-Call Role by id
# Update an On-Call Role
Source: https://docs.rootly.com/api-reference/oncallroles/update-an-on-call-role
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/on_call_roles/{id}
Update a specific On-Call Role by id
# List on-calls
Source: https://docs.rootly.com/api-reference/oncalls/list-on-calls
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/oncalls
List who is currently on-call, with support for filtering by escalation policy, schedule, and user. Returns on-call entries grouped by escalation policy level.
# creates an shadow configuration
Source: https://docs.rootly.com/api-reference/oncallshadows/creates-an-shadow-configuration
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/schedules/{schedule_id}/on_call_shadows
Creates a new on call shadow configuration from provided data
# List On Call Shadows for Shift
Source: https://docs.rootly.com/api-reference/oncallshadows/list-on-call-shadows-for-shift
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedules/{schedule_id}/on_call_shadows
List shadow shifts for schedule
# Retrieves an On Call Shadow configuration by ID
Source: https://docs.rootly.com/api-reference/oncallshadows/retrieves-an-on-call-shadow-configuration-by-id
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/on_call_shadows/{id}
Retrieves a specific On Call Shadow configuration by ID
# Update an On Call Shadow configuration
Source: https://docs.rootly.com/api-reference/oncallshadows/update-an-on-call-shadow-configuration
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/on_call_shadows/{id}
Update a specific on call shadow configuration by id
# creates an override shift
Source: https://docs.rootly.com/api-reference/overrideshifts/creates-an-override-shift
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/schedules/{schedule_id}/override_shifts
Creates a new override shift from provided data. If any existing override shifts overlap with the specified time range, they will be automatically deleted and replaced by the new override. This endpoint is idempotent: re-sending an identical override (same user and same start/end time) returns the existing override with a 200 status and does not recreate it.
# Delete an on call shadow configuration
Source: https://docs.rootly.com/api-reference/overrideshifts/delete-an-on-call-shadow-configuration
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/on_call_shadows/{id}
Delete a specific on call shadow configuration by id. Future shadows are hard-deleted. Active shadows (started in the past) have their end time truncated to preserve historical data.
# Delete an override shift
Source: https://docs.rootly.com/api-reference/overrideshifts/delete-an-override-shift
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/override_shifts/{id}
Delete a specific override shift by id
# List override shifts
Source: https://docs.rootly.com/api-reference/overrideshifts/list-override-shifts
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedules/{schedule_id}/override_shifts
List override shifts
# Retrieves an override shift
Source: https://docs.rootly.com/api-reference/overrideshifts/retrieves-an-override-shift
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/override_shifts/{id}
Retrieves a specific override shift by id
# Update an override shift
Source: https://docs.rootly.com/api-reference/overrideshifts/update-an-override-shift
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/override_shifts/{id}
Update a specific override shift by id
# Rootly API overview: authentication and conventions
Source: https://docs.rootly.com/api-reference/overview
Learn how to authenticate with the Rootly API using bearer tokens, work with rate limits, pagination, filtering, and JSON:API endpoints.
Download the OpenAPI/Swagger specification to explore the Rootly API endpoints or generate client libraries.
Use the official Go and Python SDKs to integrate with the Rootly API.
Browser-based login, scoped third-party access, and user-independent client credentials tokens.
## How to generate an API Key?
To generate a new API key, navigate to: **Organization dropdown** > **Organization Settings** > **API Keys > Generate New API Key**.
Rootly supports three scopes of API Keys:
| API Key Type | Permissions |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Global API Key | Global API Keys are assigned an On-Call and Incident Response role when they're generated. The assigned role's permissions control the key's permissions. Global API Keys are able to interact with all entities within your Rootly instance. |
| Team API Key | Team API Keys inherit the same permissions of a Team Admin. They have full read and edit access to any Rootly entity that team owns, such as the team's Schedules and Escalation Policies. |
| Personal API Key | Personal API Keys inherit the permissions of the user who created the API key. |
## JSON:API Specification
Rootly is using the **JSON:API** ([https://jsonapi.org](https://jsonapi.org)) specification:
* JSON:API is a specification for how a client should request that resources be fetched or modified, and how a server should respond to those requests.
* JSON:API is designed to minimize both the number of requests and the amount of data transmitted between clients and servers. This efficiency is achieved without compromising readability, flexibility, or discoverability.
* JSON:API requires use of the JSON:API media type (**application/vnd.api+json**) for exchanging data.
## Authentication and Requests
All API requests use the `Authorization: Bearer` header over HTTPS. Rootly supports two token types:
| Method | Token source | Best for |
| -------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------- |
| **API Key** | Generated in **Organization Settings → API Keys** | Scripts, Terraform, Zapier, quick integrations |
| **OAuth 2.0 Access Token** | Obtained via [OAuth 2.0 / OIDC](/api-reference/oauth2) flows | CLI/TUI tools, third-party apps, MCP clients, CI with scoped access |
Both token types work with the same header — the API detects which one you sent automatically.
```bash theme={null}
curl --request GET \
--header 'Content-Type: application/vnd.api+json' \
--header 'Authorization: Bearer YOUR-API-KEY-OR-OAUTH-TOKEN' \
--url https://api.rootly.com/v1/incidents
```
## Rate limiting
* There is a default limit of **3000** **GET**, **HEAD**, and **OPTIONS** calls **per API key** every minute. The limit is calculated over a **1-minute sliding window** looking back from the current time. While the limit can be configured to support higher thresholds, you must first contact your **Rootly Customer Success Manager** to make any adjustments.
* There is a default limit of **3000** **POST**, **PUT**, **PATCH** or **DELETE** calls **per API key** every minute. Alert creation is limited to 50 per minute per API key. The limit is calculated over a **1-minute sliding window** looking back from the current time. While the limit can be configured to support higher thresholds, you must first contact your **Rootly Customer Success Manager** to make any adjustments.
* Note: The default rate limit for Alert Creation is 50 alerts every minute, per API key or alert source.
* When rate limits are exceeded, the API will return a **429 Too Many Requests** HTTP status code with the response: `{"error": "Rate limit exceeded. Try again later."}`
* Rootly recommends configuring your Alert Sources to handle this response and retry to create your Alert in Rootly.
* **X-RateLimit headers** are included in every API response, providing real-time rate limit information:
* **X-RateLimit-Limit** - The maximum number of requests permitted and the time window (for example, "3000, 3000;window=60" for 3000 requests per minute)
* **X-RateLimit-Remaining** - The number of requests remaining in the current rate limit window
* **X-RateLimit-Used** - The number of requests already made in the current window
* **X-RateLimit-Reset** - The time at which the current rate limit window resets, in UTC epoch seconds
## Pagination
* Pagination is supported for all endpoints that return a **collection** of items.
* Pagination is controlled by the **page** query parameter
## Example
```bash theme={null}
curl --request GET \
--header 'Content-Type: application/vnd.api+json' \
--header 'Authorization: Bearer YOUR-TOKEN' \
--url https://api.rootly.com/v1/incidents?page[number]=1&page[size]=10
```
# Creates a playbook
Source: https://docs.rootly.com/api-reference/playbooks/creates-a-playbook
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/playbooks
Creates a new playbook from provided data
# Delete a playbook
Source: https://docs.rootly.com/api-reference/playbooks/delete-a-playbook
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/playbooks/{id}
Delete a specific playbook by id
# List playbooks
Source: https://docs.rootly.com/api-reference/playbooks/list-playbooks
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/playbooks
List playbooks
# Retrieves a playbook
Source: https://docs.rootly.com/api-reference/playbooks/retrieves-a-playbook
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/playbooks/{id}
Retrieves a specific playbook by id
# Update a playbook
Source: https://docs.rootly.com/api-reference/playbooks/update-a-playbook
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/playbooks/{id}
Update a specific playbook by id
# Creates a playbook task
Source: https://docs.rootly.com/api-reference/playbooktasks/creates-a-playbook-task
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/playbooks/{playbook_id}/playbook_tasks
Creates a new task from provided data
# Delete a playbook task
Source: https://docs.rootly.com/api-reference/playbooktasks/delete-a-playbook-task
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/playbook_tasks/{id}
Delete a specific playbook task by id
# List playbook tasks
Source: https://docs.rootly.com/api-reference/playbooktasks/list-playbook-tasks
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/playbooks/{playbook_id}/playbook_tasks
List playbook tasks
# Retrieves a playbook task
Source: https://docs.rootly.com/api-reference/playbooktasks/retrieves-a-playbook-task
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/playbook_tasks/{id}
Retrieves a specific playbook_task by id
# Update a playbook task
Source: https://docs.rootly.com/api-reference/playbooktasks/update-a-playbook-task
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/playbook_tasks/{id}
Update a specific playbook task by id
# Creates a pulse
Source: https://docs.rootly.com/api-reference/pulses/creates-a-pulse
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/pulses
Creates a new pulse from provided data
# List pulses
Source: https://docs.rootly.com/api-reference/pulses/list-pulses
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/pulses
List pulses
# Retrieves a pulse
Source: https://docs.rootly.com/api-reference/pulses/retrieves-a-pulse
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/pulses/{id}
Retrieves a specific pulse by id
# Update a pulse
Source: https://docs.rootly.com/api-reference/pulses/update-a-pulse
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/pulses/{id}
Update a specific pulse by id
# List retrospective configurations
Source: https://docs.rootly.com/api-reference/retrospectiveconfigurations/list-retrospective-configurations
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_configurations
List retrospective configurations
# Retrieves a Retrospective Configuration
Source: https://docs.rootly.com/api-reference/retrospectiveconfigurations/retrieves-a-retrospective-configuration
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_configurations/{id}
Retrieves a specific retrospective_configuration by id
# Update a retrospective configuration
Source: https://docs.rootly.com/api-reference/retrospectiveconfigurations/update-a-retrospective-configuration
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/retrospective_configurations/{id}
Update a specific retrospective configuration by id
# Creates a retrospective process
Source: https://docs.rootly.com/api-reference/retrospectiveprocesses/creates-a-retrospective-process
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/retrospective_processes
Creates a new retrospective process from provided data
# Delete a retrospective process
Source: https://docs.rootly.com/api-reference/retrospectiveprocesses/delete-a-retrospective-process
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/retrospective_processes/{id}
Delete a specific retrospective process by id
# List retrospective processes
Source: https://docs.rootly.com/api-reference/retrospectiveprocesses/list-retrospective-processes
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_processes
List retrospective processes
# Retrieves a retrospective process
Source: https://docs.rootly.com/api-reference/retrospectiveprocesses/retrieves-a-retrospective-process
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_processes/{id}
Retrieves a specific retrospective process by id
# Update a retrospective process
Source: https://docs.rootly.com/api-reference/retrospectiveprocesses/update-a-retrospective-process
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/retrospective_processes/{id}
Updates a specific retrospective process by id
# Creates a retrospective process group
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroups/creates-a-retrospective-process-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/retrospective_processes/{retrospective_process_id}/groups
Creates a new retrospective process group from provided data
# Delete a Retrospective Process Group
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroups/delete-a-retrospective-process-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/retrospective_process_groups/{id}
Delete a specific Retrospective Process Group by id
# List Retrospective Process Groups
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroups/list-retrospective-process-groups
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_processes/{retrospective_process_id}/groups
List Retrospective Process Groups
# Retrieves a Retrospective Process Group
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroups/retrieves-a-retrospective-process-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_process_groups/{id}
Retrieves a specific Retrospective Process Group by id
# Update a Retrospective Process Group
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroups/update-a-retrospective-process-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/retrospective_process_groups/{id}
Update a specific Retrospective Process Group by id
# Creates a retrospective process group step
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroupsteps/creates-a-retrospective-process-group-step
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/retrospective_process_groups/{retrospective_process_group_id}/steps
Creates a new retrospective process group step from provided data
# Delete a RetrospectiveProcessGroup Step
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroupsteps/delete-a-retrospectiveprocessgroup-step
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/retrospective_process_group_steps/{id}
Delete a specific RetrospectiveProcessGroup Step by id
# List RetrospectiveProcessGroup Steps
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroupsteps/list-retrospectiveprocessgroup-steps
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_process_groups/{retrospective_process_group_id}/steps
List RetrospectiveProcessGroup Steps
# Retrieves a RetrospectiveProcessGroup Step
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroupsteps/retrieves-a-retrospectiveprocessgroup-step
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_process_group_steps/{id}
Retrieves a specific RetrospectiveProcessGroup Step by id
# Update RetrospectiveProcessGroup Step
Source: https://docs.rootly.com/api-reference/retrospectiveprocessgroupsteps/update-retrospectiveprocessgroup-step
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/retrospective_process_group_steps/{id}
Update a specific RetrospectiveProcessGroup Step by id
# Creates a retrospective step
Source: https://docs.rootly.com/api-reference/retrospectivesteps/creates-a-retrospective-step
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/retrospective_processes/{retrospective_process_id}/retrospective_steps
Creates a new retrospective step from provided data
# Delete a retrospective step
Source: https://docs.rootly.com/api-reference/retrospectivesteps/delete-a-retrospective-step
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/retrospective_steps/{id}
Delete a specific retrospective step by id
# List retrospective steps
Source: https://docs.rootly.com/api-reference/retrospectivesteps/list-retrospective-steps
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_processes/{retrospective_process_id}/retrospective_steps
List retrospective steps
# Retrieves a retrospective step
Source: https://docs.rootly.com/api-reference/retrospectivesteps/retrieves-a-retrospective-step
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/retrospective_steps/{id}
Retrieves a specific retrospective step by id
# Update a retrospective step
Source: https://docs.rootly.com/api-reference/retrospectivesteps/update-a-retrospective-step
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/retrospective_steps/{id}
Update a specific retrospective step by id
# Creates a retrospective template
Source: https://docs.rootly.com/api-reference/retrospectivetemplates/creates-a-retrospective-template
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/post_mortem_templates
Creates a new Retrospective Template from provided data
# Delete a Retrospective Template
Source: https://docs.rootly.com/api-reference/retrospectivetemplates/delete-a-retrospective-template
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/post_mortem_templates/{id}
Delete a specific Retrospective Template by id
# List Retrospective Templates
Source: https://docs.rootly.com/api-reference/retrospectivetemplates/list-retrospective-templates
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/post_mortem_templates
List Retrospective Templates
# Retrieves a Retrospective Template
Source: https://docs.rootly.com/api-reference/retrospectivetemplates/retrieves-a-retrospective-template
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/post_mortem_templates/{id}
Retrieves a specific Retrospective Template by id
# Update a Retrospective Template
Source: https://docs.rootly.com/api-reference/retrospectivetemplates/update-a-retrospective-template
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/post_mortem_templates/{id}
Update a specific Retrospective Template by id
# Creates a role
Source: https://docs.rootly.com/api-reference/roles/creates-a-role
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/roles
Creates a new role from provided data
# Delete a role
Source: https://docs.rootly.com/api-reference/roles/delete-a-role
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/roles/{id}
Delete a specific role by id
# List roles
Source: https://docs.rootly.com/api-reference/roles/list-roles
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/roles
List roles
# Retrieves a role
Source: https://docs.rootly.com/api-reference/roles/retrieves-a-role
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/roles/{id}
Retrieves a specific role by id
# Update a role
Source: https://docs.rootly.com/api-reference/roles/update-a-role
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/roles/{id}
Update a specific role by id
# Creates a schedule rotation active day
Source: https://docs.rootly.com/api-reference/schedulerotationactivedays/creates-a-schedule-rotation-active-day
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/schedule_rotations/{schedule_rotation_id}/schedule_rotation_active_days
Creates a new schedule rotation active day from provided data
# Delete a schedule rotation active day
Source: https://docs.rootly.com/api-reference/schedulerotationactivedays/delete-a-schedule-rotation-active-day
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/schedule_rotation_active_days/{id}
Delete a specific schedule rotation active day
# List schedule rotation active days
Source: https://docs.rootly.com/api-reference/schedulerotationactivedays/list-schedule-rotation-active-days
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedule_rotations/{schedule_rotation_id}/schedule_rotation_active_days
List schedule rotation active days
# Retrieves a schedule rotation active day
Source: https://docs.rootly.com/api-reference/schedulerotationactivedays/retrieves-a-schedule-rotation-active-day
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedule_rotation_active_days/{id}
Retrieves a specific schedule rotation active day by id
# Update a schedule rotation active day
Source: https://docs.rootly.com/api-reference/schedulerotationactivedays/update-a-schedule-rotation-active-day
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/schedule_rotation_active_days/{id}
Update a specific schedule rotation active day by id
# Creates a schedule rotation
Source: https://docs.rootly.com/api-reference/schedulerotations/creates-a-schedule-rotation
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/schedules/{schedule_id}/schedule_rotations
Creates a new schedule rotation from provided data
# Delete a schedule rotation
Source: https://docs.rootly.com/api-reference/schedulerotations/delete-a-schedule-rotation
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/schedule_rotations/{id}
Delete a specific schedule rotation by id
# List schedule rotations
Source: https://docs.rootly.com/api-reference/schedulerotations/list-schedule-rotations
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedules/{schedule_id}/schedule_rotations
List schedule rotations
# Retrieves a schedule rotation
Source: https://docs.rootly.com/api-reference/schedulerotations/retrieves-a-schedule-rotation
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedule_rotations/{id}
Retrieves a specific schedule rotation by id
# Update a schedule rotation
Source: https://docs.rootly.com/api-reference/schedulerotations/update-a-schedule-rotation
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/schedule_rotations/{id}
Update a specific schedule rotation by id
# Creates a schedule rotation user
Source: https://docs.rootly.com/api-reference/schedulerotationusers/creates-a-schedule-rotation-user
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/schedule_rotations/{schedule_rotation_id}/schedule_rotation_users
Creates a new schedule rotation user from provided data
# Delete a schedule rotation user
Source: https://docs.rootly.com/api-reference/schedulerotationusers/delete-a-schedule-rotation-user
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/schedule_rotation_users/{id}
Delete a specific schedule rotation user by id
# List schedule rotation users
Source: https://docs.rootly.com/api-reference/schedulerotationusers/list-schedule-rotation-users
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedule_rotations/{schedule_rotation_id}/schedule_rotation_users
# Retrieves a schedule rotation user
Source: https://docs.rootly.com/api-reference/schedulerotationusers/retrieves-a-schedule-rotation-user
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedule_rotation_users/{id}
Retrieves a specific schedule rotation user by id
# Update schedule rotation user
Source: https://docs.rootly.com/api-reference/schedulerotationusers/update-schedule-rotation-user
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/schedule_rotation_users/{id}
Update a specific schedule rotation user by id
# Creates a schedule
Source: https://docs.rootly.com/api-reference/schedules/creates-a-schedule
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/schedules
Creates a new schedule from provided data
# Delete a schedule
Source: https://docs.rootly.com/api-reference/schedules/delete-a-schedule
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/schedules/{id}
Delete a specific schedule by id
# List schedules
Source: https://docs.rootly.com/api-reference/schedules/list-schedules
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedules
List schedules
# Retrieves a schedule
Source: https://docs.rootly.com/api-reference/schedules/retrieves-a-schedule
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedules/{id}
Retrieves a specific schedule by id
# Update a schedule
Source: https://docs.rootly.com/api-reference/schedules/update-a-schedule
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/schedules/{id}
Updates a specific schedule by id
# Official SDKs
Source: https://docs.rootly.com/api-reference/sdks
Official Rootly API client libraries for TypeScript, Rust, Python, Go, Swift, Ruby, Java, and Terraform to automate incident management workflows.
Rootly provides official SDKs to help you integrate with the Rootly API in your preferred programming language.
Official Go client library for the Rootly API
Official Swift client library for the Rootly API
Official Python client library for the Rootly API
Type-safe TypeScript client for the Rootly API
Strongly-typed Rust client for the Rootly API
Follow the links above for installation instructions, usage examples, and detailed documentation — either in the dedicated docs page or the GitHub repository.
# Creates a secret
Source: https://docs.rootly.com/api-reference/secrets/creates-a-secret
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/secrets
Creates a new secret from provided data
# Delete a secret
Source: https://docs.rootly.com/api-reference/secrets/delete-a-secret
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/secrets/{id}
Delete a specific secret by id
# List secrets
Source: https://docs.rootly.com/api-reference/secrets/list-secrets
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/secrets
List secrets
# Retrieves a secret
Source: https://docs.rootly.com/api-reference/secrets/retrieves-a-secret
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/secrets/{id}
Retrieve a specific secret by id
# Update a secret
Source: https://docs.rootly.com/api-reference/secrets/update-a-secret
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/secrets/{id}
Update a specific secret by id
# Bulk delete Services
Source: https://docs.rootly.com/api-reference/services/bulk-delete-services
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/services/bulk_delete
Delete services by external_id list, or prune by managed_by source. Two mutually exclusive modes.
# Bulk upsert Services
Source: https://docs.rootly.com/api-reference/services/bulk-upsert-services
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/services/bulk_upsert
Create or update multiple services by external_id. Only attributes present in the payload are written (managed-fields semantics). Transactional: all succeed or all fail. Requires an API key with both create and update capability across the resource scope (team/org-scoped); record-scoped principals cannot use this endpoint (they receive 404), which also prevents the create-vs-update branch from leaking whether an external_id exists.
# Creates a Catalog Property
Source: https://docs.rootly.com/api-reference/services/creates-a-catalog-property
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/services/properties
Creates a new Catalog Property from provided data
# Creates a service
Source: https://docs.rootly.com/api-reference/services/creates-a-service
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/services
Creates a new service from provided data
# Delete a service
Source: https://docs.rootly.com/api-reference/services/delete-a-service
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/services/{id}
Delete a specific service by id
# Get service incidents chart
Source: https://docs.rootly.com/api-reference/services/get-service-incidents-chart
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/services/{id}/incidents_chart
Get service incidents chart
# Get service uptime chart
Source: https://docs.rootly.com/api-reference/services/get-service-uptime-chart
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/services/{id}/uptime_chart
Get service uptime chart
# List Catalog Properties
Source: https://docs.rootly.com/api-reference/services/list-catalog-properties
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/services/properties
List Service Catalog Properties
# List services
Source: https://docs.rootly.com/api-reference/services/list-services
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/services
List services
# Retrieves a service
Source: https://docs.rootly.com/api-reference/services/retrieves-a-service
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/services/{id}
Retrieves a specific service by id
# Update a service
Source: https://docs.rootly.com/api-reference/services/update-a-service
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/services/{id}
Update a specific service by id
# Creates a severity
Source: https://docs.rootly.com/api-reference/severities/creates-a-severity
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/severities
Creates a new severity from provided data
# Delete a severity
Source: https://docs.rootly.com/api-reference/severities/delete-a-severity
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/severities/{id}
Delete a specific severity by id
# List severities
Source: https://docs.rootly.com/api-reference/severities/list-severities
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/severities
List severities
# Retrieves a severity
Source: https://docs.rootly.com/api-reference/severities/retrieves-a-severity
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/severities/{id}
Retrieves a specific severity by id
# Update a severity
Source: https://docs.rootly.com/api-reference/severities/update-a-severity
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/severities/{id}
Update a specific severity by id
# creates shift coverage requests
Source: https://docs.rootly.com/api-reference/shiftcoveragerequests/creates-shift-coverage-requests
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/schedules/{schedule_id}/shift_coverage_requests
Creates coverage requests for the shifts overlapping the requested time range. A range can span multiple consecutive shifts (e.g. across a handoff), so one or more coverage requests may be created; the response is always a list. A coverage request broadcasts to schedule members so someone can volunteer to cover the shift.
# deletes a shift coverage request
Source: https://docs.rootly.com/api-reference/shiftcoveragerequests/deletes-a-shift-coverage-request
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/shift_coverage_requests/{id}
Deletes a shift coverage request.
# list shift coverage requests
Source: https://docs.rootly.com/api-reference/shiftcoveragerequests/list-shift-coverage-requests
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedules/{schedule_id}/shift_coverage_requests
List active shift coverage requests for a schedule.
# retrieves a shift coverage request
Source: https://docs.rootly.com/api-reference/shiftcoveragerequests/retrieves-a-shift-coverage-request
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/shift_coverage_requests/{id}
Retrieves a specific shift coverage request.
# List shifts
Source: https://docs.rootly.com/api-reference/shifts/list-shifts
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/shifts
List shifts
# Retrieves a schedule shifts
Source: https://docs.rootly.com/api-reference/shifts/retrieves-a-schedule-shifts
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/schedules/{id}/shifts
Retrieves schedule shifts
# Creates an SLA
Source: https://docs.rootly.com/api-reference/slas/creates-an-sla
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/slas
Creates a new SLA from provided data
# Delete an SLA
Source: https://docs.rootly.com/api-reference/slas/delete-an-sla
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/slas/{id}
Delete a specific SLA by id
# List SLAs
Source: https://docs.rootly.com/api-reference/slas/list-slas
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/slas
List SLAs
# Retrieves an SLA
Source: https://docs.rootly.com/api-reference/slas/retrieves-an-sla
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/slas/{id}
Retrieves a specific SLA by id
# Update an SLA
Source: https://docs.rootly.com/api-reference/slas/update-an-sla
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/slas/{id}
Update a specific SLA by id
# List Statuses
Source: https://docs.rootly.com/api-reference/statuses/list-statuses
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/statuses
List Statuses
# Retrieves a Status
Source: https://docs.rootly.com/api-reference/statuses/retrieves-a-status
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/statuses/{id}
Retrieves a specific Status by id
# Creates a status page announcement
Source: https://docs.rootly.com/api-reference/statuspageannouncements/creates-a-status-page-announcement
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/status-pages/{status_page_id}/announcements
Posts an announcement to a status page and notifies its subscribers unless notify_subscribers is false
# Delete a status page announcement
Source: https://docs.rootly.com/api-reference/statuspageannouncements/delete-a-status-page-announcement
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/announcements/{id}
Delete a specific status page announcement by id
# List status page announcements
Source: https://docs.rootly.com/api-reference/statuspageannouncements/list-status-page-announcements
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/status-pages/{status_page_id}/announcements
List status page announcements
# Retrieves a status page announcement
Source: https://docs.rootly.com/api-reference/statuspageannouncements/retrieves-a-status-page-announcement
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/announcements/{id}
Retrieves a specific status page announcement by id
# Update a status page announcement
Source: https://docs.rootly.com/api-reference/statuspageannouncements/update-a-status-page-announcement
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/announcements/{id}
Update a specific status page announcement by id
# Creates a status page component group
Source: https://docs.rootly.com/api-reference/statuspagecomponentgroups/creates-a-status-page-component-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/status-pages/{status_page_id}/component-groups
Creates a new status page component group from provided data
# Delete a status page component group
Source: https://docs.rootly.com/api-reference/statuspagecomponentgroups/delete-a-status-page-component-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/component-groups/{id}
Delete a status page component group together with its components
# List status page component groups
Source: https://docs.rootly.com/api-reference/statuspagecomponentgroups/list-status-page-component-groups
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/status-pages/{status_page_id}/component-groups
List status page component groups
# Retrieves a status page component group
Source: https://docs.rootly.com/api-reference/statuspagecomponentgroups/retrieves-a-status-page-component-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/component-groups/{id}
Retrieves a status page component group
# Update a status page component group
Source: https://docs.rootly.com/api-reference/statuspagecomponentgroups/update-a-status-page-component-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/component-groups/{id}
Update a status page component group
# Creates a status page component
Source: https://docs.rootly.com/api-reference/statuspagecomponents/creates-a-status-page-component
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/status-pages/{status_page_id}/components
Creates a new status page component from provided data
# Delete a status page component
Source: https://docs.rootly.com/api-reference/statuspagecomponents/delete-a-status-page-component
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/components/{id}
Delete a status page component
# List status page components
Source: https://docs.rootly.com/api-reference/statuspagecomponents/list-status-page-components
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/status-pages/{status_page_id}/components
List status page components
# Retrieves a status page component
Source: https://docs.rootly.com/api-reference/statuspagecomponents/retrieves-a-status-page-component
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/components/{id}
Retrieves a status page component
# Update a status page component
Source: https://docs.rootly.com/api-reference/statuspagecomponents/update-a-status-page-component
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/components/{id}
Update a status page component
# Creates a status page
Source: https://docs.rootly.com/api-reference/statuspages/creates-a-status-page
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/status-pages
Creates a new status page from provided data
# Delete a status page
Source: https://docs.rootly.com/api-reference/statuspages/delete-a-status-page
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/status-pages/{id}
Delete a specific status page by id
# Get overall status of a status page
Source: https://docs.rootly.com/api-reference/statuspages/get-overall-status-of-a-status-page
https://rootly-heroku.s3.amazonaws.com/swagger/status_page/v1/swagger.json get /api/v1/status.json
Returns the overall status indicator and active incidents for the status page identified by the custom domain. When the team has the status-page-v3-phase-1 feature enabled, the response additionally carries the page's components and component groups.
# List active incidents for a status page
Source: https://docs.rootly.com/api-reference/statuspages/list-active-incidents-for-a-status-page
https://rootly-heroku.s3.amazonaws.com/swagger/status_page/v1/swagger.json get /api/v1/incidents.json
Returns a paginated list of active incidents for the status page identified by the custom domain.
# List status pages
Source: https://docs.rootly.com/api-reference/statuspages/list-status-pages
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/status-pages
List status pages
# Retrieves a status page
Source: https://docs.rootly.com/api-reference/statuspages/retrieves-a-status-page
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/status-pages/{id}
Retrieves a specific status page by id
# Update a status page
Source: https://docs.rootly.com/api-reference/statuspages/update-a-status-page
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/status-pages/{id}
Update a specific status page by id
# Creates a status page template
Source: https://docs.rootly.com/api-reference/statuspagetemplates/creates-a-status-page-template
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/status-pages/{status_page_id}/templates
Creates a new template from provided data
# Delete a incident event
Source: https://docs.rootly.com/api-reference/statuspagetemplates/delete-a-incident-event
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/templates/{id}
Delete a specific template event by id
# List status page templates
Source: https://docs.rootly.com/api-reference/statuspagetemplates/list-status-page-templates
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/status-pages/{status_page_id}/templates
List status page templates
# Retrieves a status page template
Source: https://docs.rootly.com/api-reference/statuspagetemplates/retrieves-a-status-page-template
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/templates/{id}
Retrieves a specific status_page_template by id
# Update status page template
Source: https://docs.rootly.com/api-reference/statuspagetemplates/update-status-page-template
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/templates/{id}
Update a specific template event by id
# Creates a Sub-Status
Source: https://docs.rootly.com/api-reference/substatuses/creates-a-sub-status
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/sub_statuses
Creates a new Sub-Status from provided data
# Delete a Sub-Status
Source: https://docs.rootly.com/api-reference/substatuses/delete-a-sub-status
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/sub_statuses/{id}
Delete a specific Sub-Status by id
# List Sub-Statuses
Source: https://docs.rootly.com/api-reference/substatuses/list-sub-statuses
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/sub_statuses
List Sub-Statuses
# Retrieves a Sub-Status
Source: https://docs.rootly.com/api-reference/substatuses/retrieves-a-sub-status
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/sub_statuses/{id}
Retrieves a specific Sub-Status by id
# Update a Sub-Status
Source: https://docs.rootly.com/api-reference/substatuses/update-a-sub-status
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/sub_statuses/{id}
Update a specific Sub-Status by id
# Bulk delete Teams
Source: https://docs.rootly.com/api-reference/teams/bulk-delete-teams
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/teams/bulk_delete
Delete teams by external_id list, or prune by managed_by source. Two mutually exclusive modes.
# Bulk upsert Teams
Source: https://docs.rootly.com/api-reference/teams/bulk-upsert-teams
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/teams/bulk_upsert
Create or update multiple teams by external_id. Only attributes present in the payload are written (managed-fields semantics). Transactional: all succeed or all fail. Requires an API key with both create and update capability across the resource scope (team/org-scoped); record-scoped principals cannot use this endpoint (they receive 404), which also prevents the create-vs-update branch from leaking whether an external_id exists.
# Creates a Catalog Property
Source: https://docs.rootly.com/api-reference/teams/creates-a-catalog-property
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/teams/properties
Creates a new Catalog Property from provided data
# Creates a team
Source: https://docs.rootly.com/api-reference/teams/creates-a-team
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/teams
Creates a new team from provided data
# Delete a team
Source: https://docs.rootly.com/api-reference/teams/delete-a-team
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/teams/{id}
Delete a specific team by id
# Get team incidents chart
Source: https://docs.rootly.com/api-reference/teams/get-team-incidents-chart
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/teams/{id}/incidents_chart
Get team incidents chart
# List Catalog Properties
Source: https://docs.rootly.com/api-reference/teams/list-catalog-properties
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/teams/properties
List Group Catalog Properties
# List teams
Source: https://docs.rootly.com/api-reference/teams/list-teams
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/teams
List teams
# Retrieves a team
Source: https://docs.rootly.com/api-reference/teams/retrieves-a-team
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/teams/{id}
Retrieves a specific team by id
# Update a team
Source: https://docs.rootly.com/api-reference/teams/update-a-team
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/teams/{id}
Update a specific team by id
# Creates a user email address
Source: https://docs.rootly.com/api-reference/useremailaddresses/creates-a-user-email-address
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/users/{user_id}/email_addresses
Creates a new user email address from provided data
# Delete user email address
Source: https://docs.rootly.com/api-reference/useremailaddresses/delete-user-email-address
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/email_addresses/{id}
Deletes a user email address
# Resends verification email
Source: https://docs.rootly.com/api-reference/useremailaddresses/resends-verification-email
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/email_addresses/{id}/resend_verification
Resends verification email for an email address
# Retrieves user email addresses
Source: https://docs.rootly.com/api-reference/useremailaddresses/retrieves-user-email-addresses
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/users/{user_id}/email_addresses
Retrieves all email addresses for the specified user
# Show user email address
Source: https://docs.rootly.com/api-reference/useremailaddresses/show-user-email-address
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/email_addresses/{id}
Retrieves a specific user email address
# Update user email address
Source: https://docs.rootly.com/api-reference/useremailaddresses/update-user-email-address
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/email_addresses/{id}
Updates a user email address
# Verifies an email address with token
Source: https://docs.rootly.com/api-reference/useremailaddresses/verifies-an-email-address-with-token
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/email_addresses/{id}/verify
Verifies an email address using a verification token
# Creates an user notification rule
Source: https://docs.rootly.com/api-reference/usernotificationrules/creates-an-user-notification-rule
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/users/{user_id}/notification_rules
Creates a new user notification rule from provided data
# Delete an user notification rule
Source: https://docs.rootly.com/api-reference/usernotificationrules/delete-an-user-notification-rule
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/notification_rules/{id}
Delete a specific user notification rule by id
# List user notification rules
Source: https://docs.rootly.com/api-reference/usernotificationrules/list-user-notification-rules
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/users/{user_id}/notification_rules
List user notification rules
# Retrieves an user notification rule
Source: https://docs.rootly.com/api-reference/usernotificationrules/retrieves-an-user-notification-rule
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/notification_rules/{id}
Retrieves a specific user notification rule by id
# Update an user notification rule
Source: https://docs.rootly.com/api-reference/usernotificationrules/update-an-user-notification-rule
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/notification_rules/{id}
Update a specific user notification rule by id
# Creates a user phone number
Source: https://docs.rootly.com/api-reference/userphonenumbers/creates-a-user-phone-number
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/users/{user_id}/phone_numbers
Creates a new user phone number from provided data
# Delete user phone number
Source: https://docs.rootly.com/api-reference/userphonenumbers/delete-user-phone-number
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/phone_numbers/{id}
Deletes a user phone number
# Resend verification code
Source: https://docs.rootly.com/api-reference/userphonenumbers/resend-verification-code
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/phone_numbers/{id}/resend_verification
Resends a verification code to the phone number. SMS sends are limited per recipient to 3 per hour and 5 per day. An application rate-limit 429 response includes Retry-After with the remaining wait in seconds.
# Retrieves user phone numbers
Source: https://docs.rootly.com/api-reference/userphonenumbers/retrieves-user-phone-numbers
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/users/{user_id}/phone_numbers
Retrieves all phone numbers for the specified user
# Send verification code
Source: https://docs.rootly.com/api-reference/userphonenumbers/send-verification-code
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/phone_numbers/{id}/verify
Sends a verification code to the phone number. SMS sends are limited per recipient to 3 per hour and 5 per day. An application rate-limit 429 response includes Retry-After with the remaining wait in seconds.
# Show user phone number
Source: https://docs.rootly.com/api-reference/userphonenumbers/show-user-phone-number
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/phone_numbers/{id}
Retrieves a specific user phone number
# Update user phone number
Source: https://docs.rootly.com/api-reference/userphonenumbers/update-user-phone-number
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/phone_numbers/{id}
Updates a user phone number
# Delete an user
Source: https://docs.rootly.com/api-reference/users/delete-an-user
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/users/{id}
Delete a specific user by id
# Get current user
Source: https://docs.rootly.com/api-reference/users/get-current-user
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/users/me
Get current user
# List users
Source: https://docs.rootly.com/api-reference/users/list-users
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/users
List users
# Retrieves an user
Source: https://docs.rootly.com/api-reference/users/retrieves-an-user
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/users/{id}
Retrieves a specific user by id
# Update a user
Source: https://docs.rootly.com/api-reference/users/update-a-user
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/users/{id}
Update a specific user by id
# Create a verified domain
Source: https://docs.rootly.com/api-reference/verified-domains/create-a-verified-domain
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/verified_domains
# Delete a verified domain
Source: https://docs.rootly.com/api-reference/verified-domains/delete-a-verified-domain
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/verified_domains/{id}
# List verified domains
Source: https://docs.rootly.com/api-reference/verified-domains/list-verified-domains
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/verified_domains
# Show a verified domain
Source: https://docs.rootly.com/api-reference/verified-domains/show-a-verified-domain
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/verified_domains/{id}
# List webhook deliveries
Source: https://docs.rootly.com/api-reference/webhooksdeliveries/list-webhook-deliveries
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/webhooks/endpoints/{endpoint_id}/deliveries
List webhook deliveries for given endpoint
# Retries a webhook delivery
Source: https://docs.rootly.com/api-reference/webhooksdeliveries/retries-a-webhook-delivery
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/webhooks/deliveries/{id}/deliver
Retries a webhook delivery
# Retrieves a webhook delivery
Source: https://docs.rootly.com/api-reference/webhooksdeliveries/retrieves-a-webhook-delivery
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/webhooks/deliveries/{id}
Retrieves a specific webhook delivery by id
# Creates a webhook endpoint
Source: https://docs.rootly.com/api-reference/webhooksendpoints/creates-a-webhook-endpoint
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/webhooks/endpoints
Creates a new webhook endpoint from provided data
# Delete a webhook endpoint
Source: https://docs.rootly.com/api-reference/webhooksendpoints/delete-a-webhook-endpoint
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/webhooks/endpoints/{id}
Delete a specific webhook endpoint by id
# List webhook endpoints
Source: https://docs.rootly.com/api-reference/webhooksendpoints/list-webhook-endpoints
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/webhooks/endpoints
List webhook endpoints
# Retrieves a webhook endpoint
Source: https://docs.rootly.com/api-reference/webhooksendpoints/retrieves-a-webhook-endpoint
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/webhooks/endpoints/{id}
Retrieves a specific webhook endpoint by id
# Update a webhook endpoint
Source: https://docs.rootly.com/api-reference/webhooksendpoints/update-a-webhook-endpoint
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/webhooks/endpoints/{id}
Update a specific webhook endpoint by id
# Creates a workflow action item form field condition
Source: https://docs.rootly.com/api-reference/workflowactionitemformfieldconditions/creates-a-workflow-action-item-form-field-condition
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/workflows/{workflow_id}/action_item_form_field_conditions
Creates a new workflow action item form field condition from provided data
# Delete a workflow action item form field condition
Source: https://docs.rootly.com/api-reference/workflowactionitemformfieldconditions/delete-a-workflow-action-item-form-field-condition
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/workflow_action_item_form_field_conditions/{id}
Delete a specific workflow action item form field condition by id
# List workflow action item form field conditions
Source: https://docs.rootly.com/api-reference/workflowactionitemformfieldconditions/list-workflow-action-item-form-field-conditions
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflows/{workflow_id}/action_item_form_field_conditions
List workflow action item form field conditions
# Retrieves a workflow action item form field condition
Source: https://docs.rootly.com/api-reference/workflowactionitemformfieldconditions/retrieves-a-workflow-action-item-form-field-condition
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflow_action_item_form_field_conditions/{id}
Retrieves a specific workflow action item form field condition by id
# Update a workflow action item form field condition
Source: https://docs.rootly.com/api-reference/workflowactionitemformfieldconditions/update-a-workflow-action-item-form-field-condition
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/workflow_action_item_form_field_conditions/{id}
Update a specific workflow action item form field condition by id
# Creates a workflow form field condition
Source: https://docs.rootly.com/api-reference/workflowformfieldconditions/creates-a-workflow-form-field-condition
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/workflows/{workflow_id}/form_field_conditions
Creates a new workflow form field condition from provided data
# Delete a workflow_form field condition
Source: https://docs.rootly.com/api-reference/workflowformfieldconditions/delete-a-workflow_form-field-condition
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/workflow_form_field_conditions/{id}
Delete a specific workflow form field condition by id
# List workflow form field conditions
Source: https://docs.rootly.com/api-reference/workflowformfieldconditions/list-workflow-form-field-conditions
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflows/{workflow_id}/form_field_conditions
List workflow form field conditions
# Retrieves a workflow form field condition
Source: https://docs.rootly.com/api-reference/workflowformfieldconditions/retrieves-a-workflow-form-field-condition
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflow_form_field_conditions/{id}
Retrieves a specific workflow form field condition by id
# Update a workflow form field condition
Source: https://docs.rootly.com/api-reference/workflowformfieldconditions/update-a-workflow-form-field-condition
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/workflow_form_field_conditions/{id}
Update a specific workflow form field condition by id
# Creates a workflow group
Source: https://docs.rootly.com/api-reference/workflowgroups/creates-a-workflow-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/workflow_groups
Creates a new workflow group from provided data
# Delete a workflow_group
Source: https://docs.rootly.com/api-reference/workflowgroups/delete-a-workflow_group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/workflow_groups/{id}
Delete a specific workflow group by id
# List workflow groups
Source: https://docs.rootly.com/api-reference/workflowgroups/list-workflow-groups
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflow_groups
List workflow groups
# Retrieves a workflow group
Source: https://docs.rootly.com/api-reference/workflowgroups/retrieves-a-workflow-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflow_groups/{id}
Retrieves a specific workflow group by id
# Update a workflow group
Source: https://docs.rootly.com/api-reference/workflowgroups/update-a-workflow-group
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/workflow_groups/{id}
Update a specific workflow group by id
# Creates a workflow run
Source: https://docs.rootly.com/api-reference/workflowruns/creates-a-workflow-run
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/workflows/{workflow_id}/workflow_runs
Creates a new workflow run from provided data
# List workflow runs
Source: https://docs.rootly.com/api-reference/workflowruns/list-workflow-runs
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflows/{workflow_id}/workflow_runs
List workflow runs
# Creates a workflow
Source: https://docs.rootly.com/api-reference/workflows/creates-a-workflow
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/workflows
Creates a new workflow from provided data
# Delete a workflow
Source: https://docs.rootly.com/api-reference/workflows/delete-a-workflow
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/workflows/{id}
Delete a specific workflow by id
# List workflows
Source: https://docs.rootly.com/api-reference/workflows/list-workflows
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflows
List workflows
# Retrieves a workflow
Source: https://docs.rootly.com/api-reference/workflows/retrieves-a-workflow
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflows/{id}
Retrieves a specific workflow by id
# Update a workflow
Source: https://docs.rootly.com/api-reference/workflows/update-a-workflow
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/workflows/{id}
Update a specific workflow by id
# Creates a workflow task
Source: https://docs.rootly.com/api-reference/workflowtasks/creates-a-workflow-task
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json post /v1/workflows/{workflow_id}/workflow_tasks
Creates a new workflow task from provided data
# Delete a workflow task
Source: https://docs.rootly.com/api-reference/workflowtasks/delete-a-workflow-task
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json delete /v1/workflow_tasks/{id}
Delete a specific workflow task by id
# List workflow tasks
Source: https://docs.rootly.com/api-reference/workflowtasks/list-workflow-tasks
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflows/{workflow_id}/workflow_tasks
List workflow tasks
# Retrieves a workflow task
Source: https://docs.rootly.com/api-reference/workflowtasks/retrieves-a-workflow-task
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json get /v1/workflow_tasks/{id}
Retrieves a specific workflow_task by id
# Update a workflow task
Source: https://docs.rootly.com/api-reference/workflowtasks/update-a-workflow-task
https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json put /v1/workflow_tasks/{id}
Update a specific workflow task by id
# Catalog Sync CLI
Source: https://docs.rootly.com/catalog-sync
Use the rootly-catalog-sync CLI to keep services, teams, and metadata in your Rootly Catalog continuously synced from GitHub, Backstage, APIs, and more.
`rootly-catalog-sync` is a standalone CLI tool that reconciles external sources of truth into Rootly's Catalog. It pulls data from your existing systems — GitHub repos, Backstage, internal APIs, CSV files, or any command — and syncs it one-way into Rootly, keeping services, teams, and metadata up to date automatically.
## Why use Catalog Sync?
* **Single source of truth** — your service catalog lives in GitHub, Backstage, or a database. Rootly mirrors it automatically.
* **No manual data entry** — add a service to your repo, it appears in Rootly on the next sync.
* **Safe by default** — deletes are opt-in, empty sources abort, prune ratio thresholds prevent mass deletion.
* **Terraform-style workflow** — `plan` to preview, `apply` to execute, `status` to check drift.
## Install
```bash theme={null}
# Homebrew
brew install rootlyhq/tap/rootly-catalog-sync
# Go
go install github.com/rootlyhq/rootly-catalog-sync/cmd/rootly-catalog-sync@latest
# Docker (mount your config + catalog data)
docker run --rm -e ROOTLY_API_KEY \
-v $PWD/rootly-catalog-sync.yaml:/config.yaml:ro \
-v $PWD/catalog:/catalog:ro \
rootlyhub/rootly-catalog-sync sync --config=/config.yaml
# Helm (Kubernetes)
helm repo add rootly https://rootlyhq.github.io/helm-charts
helm install catalog-sync rootly/rootly-catalog-sync \
--set rootly.apiKey=$ROOTLY_API_KEY \
--set-file configYaml=rootly-catalog-sync.yaml
```
## Quick start
```bash theme={null}
export ROOTLY_API_KEY=rootly_...
# Option 1: Scaffold a complete working example (recommended)
rootly-catalog-sync init --demo
# Option 2: Create a minimal config to customize
# rootly-catalog-sync init
# Then run:
rootly-catalog-sync doctor # verify auth + connectivity
rootly-catalog-sync plan # preview changes
rootly-catalog-sync sync # apply
```
## Authentication
Two methods are supported, in priority order:
### API key (CI / non-interactive)
```bash theme={null}
export ROOTLY_API_KEY=rootly_...
```
Create an API key at **Settings → API Keys** in your Rootly dashboard.
### OAuth 2.0 (interactive)
```bash theme={null}
# Login via browser (Authorization Code + PKCE)
rootly-catalog-sync login
# Tokens saved to ~/.rootly-catalog-sync/config.yaml
# Auto-refreshed transparently on expiry
# Clear stored tokens
rootly-catalog-sync logout
```
If `ROOTLY_API_KEY` is set, it always takes precedence over OAuth tokens.
## Configuration
The sync tool uses a declarative config file (v2 format) that defines **sync entries** — each entry connects a source to a catalog or native resource target.
```yaml YAML theme={null}
version: 2
sync:
- from:
local:
files: ["catalog/*.yaml"]
to: Services
map:
external_id: "{{ .id }}"
name: "{{ .name }}"
owner: "{{ .owner }}"
tier: "{{ .tier }}"
```
```yaml YAML (v1) theme={null}
version: 1
sync_id: services
pipelines:
- sources:
- local:
files: ["catalog/*.yaml"]
outputs:
- catalog: "Services"
external_id: "{{ .id }}"
name: "{{ .name }}"
fields:
owner: "{{ .owner }}"
tier: "{{ .tier }}"
```
```jsonnet Jsonnet theme={null}
{
version: 2,
sync: [
{
from: {
"local": {
files: ["catalog/*.yaml"],
},
},
to: "Services",
map: {
external_id: "{{ .id }}",
name: "{{ .name }}",
owner: "{{ .owner }}",
tier: "{{ .tier }}",
},
},
],
}
```
```hcl HCL theme={null}
version = 2
sync {
from {
local {
files = ["catalog/*.yaml"]
}
}
to = "Services"
map = {
external_id = "{{ .id }}"
name = "{{ .name }}"
owner = "{{ .owner }}"
tier = "{{ .tier }}"
}
}
```
Config files are detected by extension: `.yaml` (default), `.jsonnet`, or `.hcl`. Credentials use `$(ENV_VAR)` substitution.
## Sources
| Source | Description |
| ----------- | -------------------------------------------------------- |
| `inline` | Entries defined directly in config |
| `local` | YAML/JSON files from disk (glob patterns) |
| `github` | Files from GitHub repositories (supports `**` patterns) |
| `exec` | Run a command, parse stdout as JSON/YAML |
| `backstage` | Backstage catalog API with pagination |
| `graphql` | Arbitrary GraphQL endpoint with cursor/offset pagination |
| `csv` | CSV files with header row |
| `url` | Fetch YAML/JSON from remote URLs |
| `http` | Generic REST API with JSONPath extraction |
### Inline source
```yaml theme={null}
from:
inline:
entries:
- id: payments
name: Payments Service
owner: platform-team
tier: critical
- id: auth
name: Auth Service
owner: security-team
tier: critical
```
### Local source
```yaml theme={null}
from:
local:
files: ["catalog/*.yaml", "services/**/*.json"]
```
### GitHub source
```yaml theme={null}
from:
github:
token: "$(GITHUB_TOKEN)"
owner: acme
repos: ["payments", "auth", "gateway"]
files: ["**/catalog.yaml"]
ref: main
```
Omit `repos` to scan all repositories in the org. Set `archived: true` to include archived repos.
### Backstage source
```yaml theme={null}
from:
backstage:
url: https://backstage.internal.com
token: "$(BACKSTAGE_TOKEN)"
kind: Component
filter: "kind=Component,metadata.annotations.rootly.com/sync=true"
```
### Exec source
```yaml theme={null}
from:
exec:
command: bq
args: ["query", "--format=json", "SELECT id, name, owner FROM dataset.services"]
```
### GraphQL source
```yaml theme={null}
from:
graphql:
url: https://api.internal.com/graphql
headers:
Authorization: "Bearer $(API_TOKEN)"
query: |
query($cursor: String) {
services(after: $cursor) {
nodes { id name owner tier }
pageInfo { hasNextPage endCursor }
}
}
result: data.services.nodes
paginate:
cursor: data.services.pageInfo.endCursor
has_next: data.services.pageInfo.hasNextPage
```
### CSV source
```yaml theme={null}
from:
csv:
files: ["data/services.csv"]
delimiter: ","
```
The first row is used as field names. Each subsequent row becomes an entry.
### URL source
```yaml theme={null}
from:
url:
urls:
- https://internal.company.com/catalog/services.yaml
- https://internal.company.com/catalog/teams.json
headers:
Authorization: "Bearer $(API_TOKEN)"
```
### HTTP source
```yaml theme={null}
from:
http:
url: https://api.internal.com/v1/services
method: GET
headers:
Authorization: "Bearer $(API_TOKEN)"
result: data.services
```
## Output targets
Each sync entry uses `to:` to specify the target. The value of `to:` determines whether entries go to a custom catalog or a native Rootly resource.
* **Native resource**: use a lowercase type name — `to: service`, `to: team`, `to: functionality`, `to: environment`
* **Custom catalog**: use the catalog display name — `to: "Services"`, `to: "Tiers"`
### Custom catalog
Creates entities in a named Rootly catalog with arbitrary fields.
```yaml theme={null}
sync:
- from:
local:
files: ["catalog/*.yaml"]
to: "Services"
map:
external_id: "{{ .id }}"
name: "{{ .name }}"
owner: "{{ .owner }}"
tier: "{{ .tier }}"
```
### Native resources
Sync directly to built-in Rootly resource types.
| Type | Description |
| --------------- | ---------------------- |
| `service` | Rootly services |
| `functionality` | Rootly functionalities |
| `environment` | Rootly environments |
| `team` | Rootly teams |
```yaml theme={null}
sync:
- from:
local:
files: ["catalog/services.yaml"]
to: service
map:
external_id: "{{ .id }}"
name: "{{ .name }}"
description: "{{ .description }}"
pagerduty_id: "{{ .pagerduty_id }}"
github_repository_name: "{{ .repo }}"
```
```yaml theme={null}
sync:
- from:
local:
files: ["catalog/teams.yaml"]
to: team
map:
external_id: "{{ .id }}"
name: "{{ .name }}"
description: "{{ .description }}"
opsgenie_id: "{{ .opsgenie_id }}"
slack_channel: "{{ .slack_channel }}"
```
For native resources, known attributes (like `description`, `pagerduty_id`, `github_repository_name`) are set directly on the resource. Custom properties are auto-created on first sync for SDK-supported kinds (text, boolean, group, service, etc.). Reference properties are auto-created when the referenced catalog exists.
## Custom properties
Native resources (services, teams, functionalities, environments) support custom properties that extend the built-in attributes. These properties are managed automatically during sync.
### Auto-created properties
Text properties are auto-created on first sync. Simply include them in your `map:` and they will appear on the resource:
```yaml theme={null}
sync:
- from:
local:
files: ["catalog/services.yaml"]
to: service
map:
external_id: "{{ .id }}"
name: "{{ .name }}"
description: "{{ .description }}"
cost_center: "{{ .cost_center }}" # Auto-created as text property
documentation_url: "{{ .docs_url }}" # Auto-created as text property
```
### Reference properties
Reference properties link native resources to catalog entities. To use them, first sync the referenced catalog, then reference it in the native resource mapping.
For example, to link services to a "Tiers" catalog:
```yaml tiers.yaml theme={null}
- id: critical
name: Critical
sla: 99.99%
- id: standard
name: Standard
sla: 99.9%
```
```yaml rootly-catalog-sync.yaml theme={null}
version: 2
sync:
- from:
local:
files: ["tiers.yaml"]
to: "Tiers"
map:
external_id: "{{ .id }}"
name: "{{ .name }}"
sla: "{{ .sla }}"
- from:
local:
files: ["catalog/services.yaml"]
to: service
map:
external_id: "{{ .id }}"
name: "{{ .name }}"
tier:
value: "{{ .tier }}"
reference: Tiers
```
The `reference: Tiers` shorthand tells the sync tool to resolve the human-readable tier name to the corresponding catalog entity UUID. Matching is case-sensitive and compares the field value against the catalog entity's `name` (not `external_id`). The referenced catalog ("Tiers" in this example) must exist — sync it in an earlier sync entry so it is available when the service entry runs.
## Template syntax
Field mappings use Go template syntax to transform source entries into output fields.
### Field access
```yaml theme={null}
map:
name: "{{ .name }}" # Direct field access
owner: "{{ get .metadata \"team\" }}" # Nested map access
slug: "{{ .org }}/{{ .name }}" # String concatenation
tier: "{{ default .tier \"unknown\" }}" # Fallback for nil/empty values
region: us-east-1 # Static value (no template needed)
```
### Conditionals
```yaml theme={null}
environment: "{{ if .production }}prod{{ else }}staging{{ end }}"
```
Templates are compiled with `missingkey=error` — a missing field in the source data causes an immediate error rather than a silent empty string.
## Commands
| Command | Description |
| ----------------- | ----------------------------------------------------------------------------------------------------- |
| `plan` | Preview changes (creates a saved plan file) |
| `apply ` | Apply a saved plan (validates freshness first) |
| `sync` | Plan + apply in one step |
| `status` | Read-only drift check (`--fail-on-drift` for CI gates) |
| `init` | Create a config file (add `--interactive` for guided wizard, `--demo` for a complete working example) |
| `init --demo` | Scaffold a complete working example with sample data and config |
| `validate` | Check config syntax |
| `doctor` | Verify API key, connectivity, and permissions |
| `sources inspect` | Dump raw source entries before mapping |
| `explain ` | Trace one entry through source → mapping → diff |
| `adopt` | Claim existing UI entries under sync management |
| `import` | One-shot seed (no prune, no lock) |
| `watch` | Continuous sync loop (`--interval=5m`) |
| `tui` | Interactive terminal UI for selective apply |
| `login` | Authenticate via browser OAuth 2.0 (PKCE) |
| `logout` | Clear stored OAuth tokens |
## Safety guarantees
* **Deletes are opt-in** — `--allow-prune` required, off by default
* **Empty source aborts** — never wipes a catalog on a source failure
* **Prune ratio threshold** — aborts if deletes exceed 20% of live entities (configurable via `--prune-threshold`)
* **Manual entries are safe** — only entries with `external_id` (created by sync) are prunable
* **Order: create/update first, delete last** — no window where entries are missing
* **Plan freshness** — `apply` validates that live state hasn't changed since the plan was created
## CI/CD integration
### GitHub Actions
```yaml theme={null}
name: Catalog Sync
on:
push:
branches: [main]
paths:
- "catalog/**"
- "rootly-catalog-sync.yaml"
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: stable
- run: |
go install github.com/rootlyhq/rootly-catalog-sync/cmd/rootly-catalog-sync@latest
$(go env GOPATH)/bin/rootly-catalog-sync sync
env:
ROOTLY_API_KEY: ${{ secrets.ROOTLY_API_KEY }}
```
### Dry-run on PRs
```yaml theme={null}
- run: rootly-catalog-sync plan --dry-run --output=json
env:
ROOTLY_API_KEY: ${{ secrets.ROOTLY_API_KEY }}
```
### Nightly drift detection
```yaml theme={null}
- run: rootly-catalog-sync status --fail-on-drift
env:
ROOTLY_API_KEY: ${{ secrets.ROOTLY_API_KEY }}
```
## Kubernetes deployment
Deploy catalog sync to Kubernetes using the official Helm chart:
```bash theme={null}
helm repo add rootly https://rootlyhq.github.io/helm-charts
helm install catalog-sync rootly/rootly-catalog-sync \
--set rootly.apiKey=$ROOTLY_API_KEY \
--set-file configYaml=rootly-catalog-sync.yaml
```
By default the chart creates a **CronJob** that runs every 30 minutes.
To run in **watch mode** (continuous sync loop):
```bash theme={null}
helm install catalog-sync rootly/rootly-catalog-sync \
--set rootly.apiKey=$ROOTLY_API_KEY \
--set-file configYaml=rootly-catalog-sync.yaml \
--set mode=watch \
--set watch.interval=5m
```
To include local data files referenced by your config, use a values file:
```yaml theme={null}
# values.yaml
rootly:
apiKey: rootly_...
configYaml: |
version: 2
sync:
- from:
local:
files: ["/data/services.yaml"]
to: service
map:
external_id: "{{ .id }}"
name: "{{ .name }}"
dataFiles:
services.yaml: |
- id: api-gateway
name: API Gateway
```
```bash theme={null}
helm install catalog-sync rootly/rootly-catalog-sync -f values.yaml
```
## Environment variables
| Variable | Description | Default |
| ----------------- | ---------------------------------- | ------------------------ |
| `ROOTLY_API_KEY` | API key (or use `login` for OAuth) | — |
| `ROOTLY_API_URL` | Override base URL | `https://api.rootly.com` |
| `ROOTLY_API_PATH` | Override API path prefix | `/v1` |
## Interactive TUI
The `tui` command launches a full-screen terminal UI for reviewing and selectively applying changes:
* Browse changes with colored badges (CREATE/UPDATE/DELETE/NOOP)
* Toggle individual changes with `space`, expand field diffs with `enter`
* Filter by operation type (`c`/`u`/`d`) or search (`/`)
* Detail pane shows full entity fields on wide terminals
* Apply only selected changes with `A`
## Resources
* [GitHub repository](https://github.com/rootlyhq/rootly-catalog-sync)
* [Helm chart](https://github.com/rootlyhq/helm-charts/tree/master/charts/rootly-catalog-sync)
* [Docker Hub](https://hub.docker.com/r/rootlyhub/rootly-catalog-sync)
* [Troubleshooting guide](https://github.com/rootlyhq/rootly-catalog-sync/blob/master/docs/troubleshooting.md)
* [Template syntax reference](https://github.com/rootlyhq/rootly-catalog-sync/blob/master/docs/templates.md)
* [Working examples](https://github.com/rootlyhq/rootly-catalog-sync/tree/master/docs/examples)
# Catalogs
Source: https://docs.rootly.com/catalogs
Define and manage the entities that matter to your business, like services, teams, and regions, as a structured source of truth for incident response.
Catalog is the central place in Rootly where you define the entities that matter most to your business, things like Services, Teams, Product Areas, Regions, or any other concept that shapes how your organization works and responds to incidents.
Rather than managing this data in spreadsheets or relying on people to fill in the right values from memory, Catalog gives you a structured, reusable source of truth. Once your entities are defined, you can use them everywhere: on incident fields, in workflows, in reports, and more.
**Why this matters**
When an incident hits, responders need to quickly capture what’s impacted — which service, which region, which team. Without Catalog, this is manual and error-prone. With Catalog, that data is structured, consistent, and can even be filled in automatically.
Rootly has always allowed you to manage a catalog of Services, Teams, Functionalities, Types, Environments, and Causes. Now, you’re able to add custom catalogs that represent additional business entities that are relevant to your incident response efforts.
## **Key concepts**
Here are the main building blocks you’ll work with:
* **Catalog**: A collection of related entities. For example, a "Services" Catalog contains all the services your organization runs.
* **Entity**: A single item within a Catalog. For example, "Payments API" is an entity in the Services Catalog.
* **Properties**: Attributes that describe each entity. For example, each Service might have an "Owning Team" property.
## Getting started
Begin setting up your Catalogs by navigating to the **Catalog section** from the left-hand navigation.
When you open the Catalog for the first time, Rootly comes pre-loaded with a set of common Catalogs to help you hit the ground running: Services, Teams, Functionalities, Causes, Types, and Environments.
These should look familiar to you: all of your existing Services, Teams, Functionalities etc. are now accessible from the Catalog page. **You can also access these Catalogs from the Rootly > Configuration section**.
Now, you can continue to use these built-in Catalogs as is, or customize them to match your setup. Nothing is locked in, everything is editable.
# Checklists
Source: https://docs.rootly.com/checklists
Create checklists to verify that every entity in your catalog has the required properties, and run audits to track completeness across your organization.
Checklists help you make sure that every entity in your Catalog has the information it needs to participate in your incident response and on-call processes.
As your organization grows and reorganizes, it’s easy for Catalog data to go stale: teams change ownership, services get deprecated, runbooks go out of date. Checklists give you a structured way to define what "complete" looks like for each type of entity, and to periodically verify that every entity meets that standard.
You can create an "On-Call Ready" checklist for your Teams Catalog, specifying that every Team must have an escalation policy, a goalie, and a support tier defined. You then kick off an audit to check all of your teams at once — any team that’s missing information will show up as incomplete, with a clear owner responsible for filling in the gaps.
## **Key concepts**
* **Checklist**: A definition of the properties that must be filled out on a Catalog entity for it to be considered complete. You give it a name, a description, and select the specific properties it covers.
* **Checklist owner**: The person responsible for completing the checklist for a given entity. This can be a specific user, or dynamically determined from a property on the entity (for example, the entity’s assigned Goalie or Owning Team’s admin).
* **Audit**: An instance of a checklist created for each entity in a Catalog. Triggering an audit kicks off a checklist for every entity at once.
* **Audit status**: Tracks where each entity stands in the review process: Not Started, In Progress, or Complete.
## **Creating a checklist**
You can create checklists on both built-in Catalogs (like Services and Teams) and any custom Catalogs you’ve defined. **For now, you can only create one checklist per Catalog.**
1. Navigate to your Catalog and open the **Checklists** tab, and click **Add checklist**.
2. Give it a name (for example, "On-Call Ready") and optional instructions so others know what it covers.
3. Optionally, assign a checklist owner (see below for more details).
4. Select the properties from that Catalog that must be filled out for an entity to pass the checklist.
5. Save the checklist.
### **Assigning a checklist owner**
The checklist owner is the person responsible for completing the checklist for each entity. You have a few options for how ownership is determined:
* **A specific user:** One person is responsible for completing the checklist for every entity in the Catalog.
* **A team property on the entity:** The owner is the admin of the team associated with the entity. For example, if each Service has an "Owning Team" property, the checklist owner would be the admin of that team.
Checklists can have more than one owner. However, you’re not required to assign ownership if it doesn’t make sense for your workflow.
### **Editing a checklist definition**
As your Catalog evolves (for example, if you add a new "Tier" property to your Services), you can edit an existing checklist to include the new property: you don’t need to create a new checklist.
**Note on in-progress audits**: If you edit a checklist definition while an audit is already in progress, the active audit will not be changed. It will continue to reflect the checklist definition that was in place when that audit was triggered.
### **Deleting a checklist**
You can delete a checklist at any time. When you do, Rootly retains any historical references to it and any active audits will continue and can still be completed. The checklist itself will no longer be available for future audits.
## **Triggering and managing audits**
When it’s time to review and validate all entities in your Catalog, you can kick off an audit! An audit creates a fresh checklist for every entity in a Catalog at once. If you defined a checklist owner, they are all responsible for completing the audit of their entities.
To trigger an audit:
1. Open the Catalog you want to audit. Click the **Checklists** tab from the overview page to see the available checklists.
2. Select the checklist you want to run.
3. Click **Initiate checklist review**.
Rootly will create a new checklist instance for every entity in the Catalog.
**Note on in-progress audits**: If an entity already has a checklist in "In Progress" status when you trigger an audit, Rootly will not create a new one for that entity and will not close the existing one.
## **Completing an audit**
Once an audit has been triggered for your entity, you’ll find it in the Catalog on that entity’s page. Here’s how to work through it.
### **Viewing audit statuses**
On the Catalog’s overview page, you can see the audit status for every entity at a glance. Entities that haven’t been started show a "Start Review" prompt; entities in progress show an "In Progress" indicator.
### **Reviewing and checking off items**
Each item in the audit corresponds to a property from the checklist definition. For each item, you’ll see the current value of that property on the entity.
1. Review the current value for each property. If the value is correct, check it off. Rootly records who checked it off and what the value was at the time.
2. If the value needs to be updated, make the change to the entity and then check off the item.
3. You can save your progress at any point and come back to finish later.
4. Once every item is checked off, click "Complete" to finalize the audit.
**Completed audits are locked**: Once you mark an audit as complete, it cannot be edited by anyone. All checkboxes must be checked before you can complete the audit. Rootly records who completed it and when.
### **Multiple people working on the same audit**
More than one person can work on the same audit at the same time. Rootly tracks who checks off each individual item, so you’ll have a clear record of who reviewed what, even when the work is shared across a team.
## **Tracking audit progress**
Audits can have the following statuses:
* **Not Started:** The audit has been created but no items have been reviewed yet.
* **In Progress**: At least one item has been reviewed and checked off.
* **Complete**: All items have been checked off and the audit has been finalized.
## **Viewing audit history**
Rootly keeps a record of every completed audit for each entity. In the entity’s audit history, you can see:
* Who triggered the audit and when it was started.
* Which properties were included in the checklist at the time of the audit.
* The values those properties had when each item was checked off.
* Who checked off each item, and when.
* Who completed the audit, and when.
This gives you a clear, time-stamped record of the state of each entity at each review point: useful for compliance, retrospectives, or just understanding how your Catalog has evolved over time.
# Exporting Retrospectives
Source: https://docs.rootly.com/collaborative-retrospectives/exporting-retrospectives
Export retrospective content to external documentation providers like Google Docs, Confluence, Notion, SharePoint, Quip, Coda, and other knowledge bases.
## Overview
Rootly can export retrospective content to external documentation providers, allowing teams to use their preferred tools while benefiting from Rootly's incident management features.
### Supported Providers
Rootly supports the following external document providers:
* Google Docs
* Confluence
* Notion
* SharePoint
* Dropbox Paper
* Coda
* Quip
* Datadog
Each provider has its own authentication and configuration requirements. Contact your administrator if you need access to a specific provider.
## Rootly Editor vs External Providers
### When to Use the Rootly Editor
The built-in collaborative editor is ideal when:
* Multiple team members need to edit simultaneously
* You want data blocks and variables that update automatically
* You prefer keeping incident data within Rootly
### When to Use External Providers
External providers work well when:
* Your organization standardizes on a specific documentation tool
* You need to share retrospectives with stakeholders outside Rootly
* You want documents accessible in your existing knowledge base
* Compliance or governance requires specific storage locations
### Using Both
Many teams combine approaches:
1. **Draft in Rootly:** Use the Rootly Editor for initial drafting and collaboration
2. **Export for distribution:** Export to an external provider when ready to share broadly
3. **Link back:** The external document links back to the incident in Rootly
Exporting happens at specific points (when you click Export) rather than in real-time.
***
### What Gets Exported
When exporting to your external providers, Rootly processes your retrospective content to ensure compatibility.
### Content That Exports
| Content Type | How It's Handled |
| :------------------- | :----------------------------------------------------------- |
| **Rich text** | Formatting preserved (bold, italic, headings, lists) |
| **Tables** | Converted to provider-native table format |
| **Data blocks** | Rendered as static content at export time |
| **AI blocks** | Rendered as static text (the generated draft) at export time |
| **Liquid variables** | Resolved to actual values at export time |
| **Code blocks** | Formatted appropriately for each provider |
| **Links** | Preserved as clickable hyperlinks |
### Incident Data Blocks in External Documents
If your retrospective document contains data blocks:
* **Timeline:** Rendered as a formatted table with event date, source, user, and description
* **Follow-ups:** Rendered as a list with title, priority, status, assignee, and due date
Data blocks become static content in external documents. They won't update automatically if the incident data changes after export.
### Provider-Specific Formatting
Rootly adjusts content formatting for each provider:
| Provider | Special Handling |
| :-------------- | :------------------------------------------ |
| **Confluence** | Inline code converted to Confluence macros |
| **Google Docs** | Tables formatted with borders and styling |
| **Notion** | Content structured for Notion's block model |
| **Others** | Standard HTML-to-provider conversion |
***
## How to Export
The **Export** button in the editor header provides access to all export options for your retrospective.
### Export Dropdown
Click **Export** in the editor header to access these options:
| Option | Description |
| :--------------------------- | :--------------------------------------------------------------------------------------------- |
| **Publish retrospective** | Publishes the retrospective, making it accessible via a sharable URL and notifying subscribers |
| **Export to new document** | Opens a modal to create a new export to any connected provider |
| **Update exported document** | Opens a modal to update a previously exported document (only visible if exports exist) |
Once a retrospective is published, the Export dropdown updates to include additional options:
| Option | Description |
| :------------------------------- | :-------------------------------------------------------------------------------------------------------------- |
| **View published retrospective** | Opens the published retrospective in a new tab |
| **Copy link** | Copies the published retrospective URL to your clipboard |
| **Save as PDF** | Downloads the published retrospective as a PDF file |
| **Document settings** | Customize what gets appended to the published document (for example, timeline, action items, incident metadata) |
If you have no external integrations configured, click **Manage integrations** to connect a document provider. Contact your administrator to set up integrations in **Configuration → Integrations**.
***
## Publishing a Retrospective
Publishing makes your retrospective accessible to your team.
### How to Publish
Click **Export** in the editor header.
If the incident has already been resolved, the retrospective is published immediately. If the incident is still active, a confirmation dialog asks you to confirm that you want to publish before the incident is resolved.
### What Happens When You Publish
* The retrospective status changes from **Draft** (yellow chip) to **Published** (green chip) in the editor header
* The published document is accessible via an internal URL for non-private incidents
* Subscribers are notified that the retrospective has been published
* The Export dropdown updates to show additional options: view the published document, copy its link, save as PDF, and access document settings
### Document Settings
After publishing, you can customize the published retrospective by clicking **Document settings** in the Export dropdown. Document settings let you control what gets appended to your published document:
Include the incident timeline in the published document.
Include the incident's action items and follow-ups.
Include severity, services, roles, and timestamps.
This allows teams to tailor what stakeholders see in the published version without modifying the editor content.
### Re-publishing
If you make changes to the retrospective after publishing, your published document gets updated automatically. The published URL remains the same — only the content is updated.
Publishing and exporting are independent actions. Publishing makes the retrospective available via a Rootly URL. Exporting pushes the content to an external provider like Confluence or Google Docs. You can do both.
***
### Exporting to a New Document
To export your retrospective to an external provider for the first time:
Click **Export** in the editor header.
This opens a modal where you can configure the export.
Select the provider (Confluence, Google Docs, Notion, etc.) from the dropdown. Each provider shows its icon for easy identification.
The title defaults to "Retrospective - \[Incident Title]". You can customize it.
Some providers require additional configuration:
* **Confluence:** Select a space key for the destination
* **Notion:** Select a parent page
* Other providers may have their own options
The export is created in the background. You'll be notified when it completes.
### Updating an Existing Export
If you've already exported the retrospective and want to push updated content:
Click **Export** in the editor header.
This option only appears if you have previously exported the retrospective.
Select the export you want to update from the list. Each entry shows the provider name and document title.
A warning confirms that the external document's content will be replaced with the current retrospective content. Click **Update** to proceed.
Updating an export overwrites the external document with the current retrospective content. This is a one-way operation — changes made in the external document will be replaced.
### Working with Exported Documents
Once a retrospective is exported to an external provider:
* A link to the external document is stored on the incident
* The document lives in your external provider's system
* You can open external documents directly from the **More actions** menu in the editor header
* Edits in the external document do **not** sync back to Rootly
### Document Links
After exporting, you can reference external document URLs using Liquid variables:
* `{{ incident.confluence_page_url }}`
* `{{ incident.google_drive_url }}`
* `{{ incident.notion_page_url }}`
* `{{ incident.sharepoint_page_url }}`
### Managing Integrations
Click **Manage integrations** in the Export dropdown to go to **Configuration → Integrations** (Docs & Retrospective category), where you can connect or configure document providers.
### How Workflows and Exporting Work Together
Workflows and the Export button serve different purposes:
* **Workflows** can automatically create external documents (for example, in Confluence or Google Docs) when an incident resolves or another trigger fires. These workflows do not create or modify the Rootly document — they only affect external providers.
* **The Export button** in the editor lets you manually export the Rootly document's content to a new external document or update an existing one at any time.
If you want the Rootly document to be created automatically, set up a separate **Create Rootly Retrospective** workflow. Otherwise, create it manually from the Retrospective tab.
The Rootly document and external documents are independent paths. A workflow that creates a Confluence page will not write to or create the Rootly document, and vice versa. If you create the Rootly document before a workflow fires, the workflow will not override it.
***
### Best Practices
* **Set up workflows for initial creation:** Configure workflows to automatically create external documents when incidents resolve, so you don't have to manually export each time.
* **Use Update for changes:** After editing a retrospective, use **Update external document** to push changes to the existing export.
* **Include data blocks before exporting:** Add Timeline and Follow-ups blocks before exporting so they're rendered in the external document.
* **Verify liquid variables have values:** Empty variables create gaps in the external document. Check that referenced fields exist for the incident.
## Frequently Asked Questions
The connection to the external provider may have expired. Re-authenticate the integration in **Configuration → Integrations** or contact your administrator.
Data blocks must have data to render. If the incident has no timeline events or follow-ups, the blocks may appear empty. Add data to the incident before exporting.
Ensure the incident has the expected data. Variables without values resolve to N/A. Check that referenced fields (Jira ticket, assigned roles, etc.) exist for this incident.
Export is one-way. Edits made directly in the external provider don't sync back to Rootly. Make edits in Rootly and use **Update external document** to push changes.
Click **Export** in the editor header and select **Update external document**. Choose the export you want to update from the list and confirm. The external document will be overwritten with the current retrospective content.
Yes. Use **Export to new document** for each provider you want to export to. Each export is tracked independently and can be updated separately.
***
## Related Pages
The umbrella page covering how the editor works end-to-end.
Author the retrospective content that this page shows how to export.
Variables render to their live values in the exported document.
# Liquid Variables in Retrospectives
Source: https://docs.rootly.com/collaborative-retrospectives/liquid-variables
Use Liquid templating in retrospective documents to dynamically populate incident data, custom fields, action items, and timeline events.
## Overview
Rootly supports the [Liquid](https://shopify.github.io/liquid/) templating engine in retrospective documents and templates. Liquid allows you to insert dynamic placeholders like `{{ incident.title }}` or `{{ incident.severity }}` that automatically resolve to actual incident data when the retrospective is published or exported.
This is especially valuable because retrospective documents often reference the same incident data repeatedly (title, severity, duration, commander, etc.), and the most common failure mode is simple: people copy-paste incorrectly or forget to update values when the incident changes.
Typical uses include:
* Pre-filling retrospective templates with incident metadata
* Referencing incident data without manual copy-paste
* Ensuring consistency when exporting to external systems (Google Docs, Confluence, Notion)
* Creating reusable templates that adapt to each incident automatically
Liquid variables in retrospectives use the same syntax and variable names as Incident Variables in Workflows. If you're familiar with Liquid in Workflows, the same variables are available in the retrospective editor.
## Liquid Variables vs Liquid Blocks
Rootly provides two ways to use Liquid in retrospectives:
| Feature | Liquid Variables | Liquid Blocks |
| -------------- | --------------------------------------- | --------------------------------------------- |
| **Insert via** | Type `{{` | Type `/liquid` |
| **Scope** | Inline (within text) | Block-level (standalone section) |
| **Syntax** | `{{ variable }}` with filters | Full Liquid: `{% if %}`, `{% for %}`, filters |
| **Display** | Inline chip | Edit/Preview panel |
| **Best for** | Inserting dynamic values into sentences | Conditional content, loops, multi-line logic |
**Use Liquid Variables when** you need to insert a single dynamic value into your text, like "The incident commander was `{{ incident.commander.name }}`."
**Use Liquid Blocks when** you need conditional logic, loops, or multi-line templates—for example, showing different content based on severity or listing all action items.
***
## How to Insert Liquid Variables
### In the Editor
1. **Start typing a variable:** Type `{{` anywhere in the editor to trigger the variable autocomplete.
2. **Filter and select:** Continue typing to filter available variables (for example, `{{ incident.ti` shows `incident.title`).
3. **Insert the variable:** Click or press Enter to insert the selected variable.
4. **Variable appears as a chip:** The variable displays as a visual chip in the editor, showing the variable name.
### In Templates
Templates support Liquid variables in the same way. When a template is inserted into a retrospective, variables remain as placeholders until the retrospective is published or exported.
Variables in templates allow you to create reusable structures that automatically adapt to each incident to help eliminate manual data entry and reduce errors.
### Examples
#### Get the incident title and severity
Expression: `{{ incident.title }} ({{ incident.severity }})`
Sample result: "Database connection timeout (SEV1)"
#### Format a timestamp
Expression: `{{ incident.started_at | date: "%Y-%m-%d %H:%M" }}`
Sample result: "2024-03-15 14:32"
[Reference](https://shopify.github.io/liquid/filters/date/)
#### Get the incident commander's name
Expression: `{{ incident.commander.name }}`
Sample result: "Jane Smith"
#### Build a resource link
Expression: `[Slack Channel]({{ incident.slack_channel_url }})`
Sample result: "[Slack Channel](https://slack.com/archives/C123456)"
Liquid variables are organized by the data they reference. For the complete list of available variables use the [Liquid Markup explorer](https://rootly.com/account/help/liquid-explorer).
***
## Liquid Blocks
Liquid Blocks are standalone template sections that support the full Liquid templating language, including conditionals (`{% if %}`), loops (`{% for %}`), and all Liquid filters. They're ideal when you need more than simple variable substitution.
### How to Insert a Liquid Block
1. **Open the slash menu:** Type `/liquid` anywhere in the editor.
2. **Select Liquid Block:** Choose "Liquid Block" from the slash command menu.
3. **Write your template:** Enter your Liquid code in the editor panel that appears.
4. **Preview your output:** Click **Preview** to see the rendered result with real incident data.
5. **Edit as needed:** Toggle back to **Edit** to make changes. The preview updates each time you switch.
The Preview mode renders your template using actual incident data, so you can verify your logic works correctly before publishing.
### When to Use Liquid Blocks
Liquid Blocks are particularly useful for:
* **Conditional content** based on incident properties (severity, status, etc.)
* **Looping through collections** like action items, services, or team members
* **Complex formatting** that requires multiple variables and logic
* **Reusable template sections** that adapt based on incident context
### Examples
#### Conditional severity messaging
```liquid theme={null}
{% if incident.severity == "critical" %}
🚨 **CRITICAL INCIDENT** - This incident required immediate escalation and executive notification.
{% elsif incident.severity == "high" %}
⚠️ **High Priority** - This incident impacted production systems and required urgent response.
{% else %}
📋 This incident followed standard response procedures.
{% endif %}
```
#### Loop through action items
```liquid theme={null}
### Action Items
{% for item in incident.action_items %}
- [{{ item.status }}] {{ item.summary }}
- **Owner:** {{ item.owner.name }}
- **Due:** {{ item.due_at | date: "%B %d, %Y" }}
{% endfor %}
```
#### Conditional sections with fallbacks
```liquid theme={null}
{% if incident.resolved_at %}
**Resolution Time:** {{ incident.resolved_at | date: "%B %d, %Y at %I:%M %p" }}
**Total Duration:** {{ incident.duration }}
{% else %}
⏳ *This incident is still ongoing.*
{% endif %}
```
#### Dynamic team summary
```liquid theme={null}
### Response Team
{% if incident.commander %}
- **Incident Commander:** {{ incident.commander.name }}
{% endif %}
{% if incident.communication_lead %}
- **Communication Lead:** {{ incident.communication_lead.name }}
{% endif %}
{% for responder in incident.responders %}
- {{ responder.name }} ({{ responder.role }})
{% endfor %}
```
Liquid Blocks have access to all the same variables available to Liquid Variables. Use the [Liquid Markup explorer](https://rootly.com/account/help/liquid-explorer) to see the complete list.
### Error Handling
If your Liquid template contains a syntax error, the Preview mode will display an error message describing the issue. Common errors include:
* Unclosed tags (`{% if %}` without `{% endif %}`)
* Undefined variables (check spelling and availability)
* Invalid filter syntax
Fix the error in Edit mode and preview again to verify.
***
## How Variables Resolve
In the editor, variables appear as visual **chips** showing their names, and Liquid Blocks show as editable panels. When you publish or export (to Google Docs, Confluence, etc.), both resolve to their current values, so the final document shows real data instead of placeholders.
Variables always resolve to the **current** value at the time of publish or export. If incident data changes after publishing, the retrospective retains the original resolved values.
## Best Practices
* **Use variables for inline values, blocks for logic:** Keep simple insertions as Liquid Variables; use Liquid Blocks when you need conditionals or loops.
* **Use variables in templates:** Templates with variables create consistent retrospectives that auto-populate incident data, eliminating manual entry and reducing errors.
* **Prefer data blocks for timeline/follow-ups:** The `/timeline` and `/followups` data blocks provide richer, interactive display compared to timeline variables.
* **Use the `default` filter for optional data:** If a variable might be empty (for example, no Jira ticket), use `{{ incident.jira_issue_url | default: "N/A" }}` to provide a fallback.
* **Use role variables for accountability:** Including `{{ incident.commander.name }}` makes ownership clear in the published document.
* **Keep templates DRY:** Define common sections once in a template and let variables fill in the incident-specific details.
* **Preview Liquid Blocks before publishing:** Use the Preview toggle to verify conditional logic and loops render correctly with your incident data.
## Frequently Asked Questions
The referenced data doesn't exist for this incident. For example, `{{ incident.jira_issue_url }}` is empty if no Jira ticket is linked. Use the `default` filter to provide a fallback value.
Yes! Use **Liquid Blocks** for full Liquid logic including conditionals and loops. Type `/liquid` to insert a Liquid Block. Standard **Liquid Variables** (inserted via `{{`) support only variable interpolation and filters.
Yes. Retrospective Liquid variables use the same syntax and variable names as Incident Variables in Workflows. If you're familiar with Liquid in Workflows, the same variables work in retrospectives.
Yes. Use the `date` filter with a format string: `{{ incident.started_at | date: "%B %d, %Y" }}` produces "March 15, 2024". See the [Liquid date filter reference](https://shopify.github.io/liquid/filters/date/) for format options.
Liquid Variables are inline placeholders for single values (inserted via `{{`). Liquid Blocks are standalone sections that support full Liquid templating including conditionals and loops (inserted via `/liquid`). Use variables for simple value insertion; use blocks when you need logic.
No, Liquid Blocks are atomic units in the editor. However, you can use nested Liquid logic (like `{% if %}` inside `{% for %}`) within a single Liquid Block.
***
## Related Pages
The umbrella page covering how the editor works end-to-end.
Insert Liquid variables into the retrospective from the editor toolbar.
Variables render to their live values in the exported document.
# Collaborative retrospective editor overview
Source: https://docs.rootly.com/collaborative-retrospectives/overview
Explore the Rootly collaborative retrospective editor with real-time co-authoring, dynamic data blocks, Liquid variables, and inline action item tracking.
## Writing Retrospectives
Once an incident resolves, you can write your retrospective using either:
1. Rootly's document editor
2. An external document editor like Notion, Confluence or Google Docs.
Many teams use a hybrid approach by drafting in the Rootly document editor and exporting a copy to their external editor of choice.
Integrations are configured by your administrator. Check Configuration → Integrations for a full list of external document providers available to you.
## Using The Rootly Editor
Rootly includes a rich text editor in retrospectives that supports live incident data and real-time collaboration - all without leaving the platform.
When an incident is resolved, the retrospective workflow begins. The editor is where your team can capture what happened, why it happened, and what improvements your team intends to make to prevent the incident from recurring.
## How Teams Collaborate with The Editor
Writing retrospectives is a core part of the incident lifecycle, but it often breaks team momentum. Important context lives across emails, documents, Slack threads, Zoom calls, and knowledge base tools like Notion or Confluence.
Teams are forced to hunt for details, manually copy and paste information into a document, and reformat it every time. As a result, collaboration slows down, context gets lost, and it becomes harder to maintain a single, reliable source of truth for how the incident was resolved.
**The Rootly editor solves these problems by providing:**
* **Incident metadata** that resolves to actual values and stays in sync as you write
* **Dynamic data blocks** that pull in live updates to your incident from Timelines and Action Items
* **Real-time collaboration** so multiple authors can work together and contribute
* **Inline comments** for feedback and discussion in context
* **@mentions** to tag users and reference incidents directly in the document
It's also packed with a host of features to make retrospective documents pleasant to write and collaborate in.
## Key Features at a Glance
| Feature | Description |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| Variable Incident Metadata | Dynamic placeholders like `{{ incident.title }}` that resolve to actual values |
| Complex Incident Metadata | Insert rich liquid variable blocks with conditional syntax that resolve to their actual values |
| Data Blocks | Insert dynamic Timeline and Follow-ups blocks that pull live data from the incident |
| AI Blocks | Auto-draft sections (Summary, Impact, Root Cause, and more) from incident data, Slack, and bridge-call transcripts |
| Real-time Collaboration | Multiple users edit simultaneously with live cursors and presence indicators |
| Comments | Inline feedback and threaded discussions on selected text |
| @Mentions | Tag users and reference incidents directly in the document with interactive popovers |
| Export & Sync | Export content to Google Docs, Confluence, Notion, and other providers. Download as PDF or copy as Markdown |
| Document Status | Draft and Published states with visual status indicators and publish confirmation flows |
| Invite Collaborators | Invite team members via Slack or email to collaborate on the retrospective |
| Templates | Pre-built content structures inserted via slash commands |
| Version history and analytics | Full visibility into viewers and editors of a document. Track document changes and revert to previous versions with a click. |
## Where the Editor Fits in the Incident Lifecycle
The retrospective editor is part of the broader retrospective workflow that begins when an incident is resolved.
The editor is primarily used in the Write the **Retrospective** step, although teams can start writing their document at any point before or after the incident resolves.
### Retrospective Workflow Steps
1. **Gather and Confirm Data:** Collect incident metadata, impacted services, and initial findings
2. **Write the Retrospective:** Write the retrospective document using the Rootly document editor
3. **Create Follow-ups:** Define action items to prevent recurrence
4. **Publish and Export the Retrospective:** Publish the retrospective document to make it accessible, export to external providers, and notify your team to review
## External Document Editors
Rootly supports integrations with Notion, Google Docs, Confluence, SharePoint, Dropbox Paper, Coda and Quip.
If you have workflows set up to create retrospective documents in an external editor, you can find links to your external documents under the Exports section in the Retrospectives tab.
If you'd like to try the Rootly document editor, you can create a Rootly document from the Retrospective tab at any time. The Rootly document and external documents are independent — workflows that create external documents (for example, in Confluence) do not create or modify the Rootly document.
You can choose to use the Rootly document editor, an external document editor, or both depending on your team's needs. External providers are configured in Configuration → Integrations.
### How the Rootly Document Is Created
The Rootly document is created in one of two ways:
* **Manually:** Click the **Create Rootly Document** button in the Retrospective tab to create a document on demand. You can start from a blank document or choose a template.
* **Via workflow:** Set up a **Create Rootly Retrospective** workflow to automatically create the Rootly document when an incident resolves (or another trigger fires).
Workflows that export to external providers (like Confluence or Google Docs) do not create or write to the Rootly document. These are separate paths. If you want both, configure separate workflows for each.
***
## Where to Go Next
These pages provide detailed guidance on specific aspects of the retrospective editor:
* **Using the Editor:** Formatting, slash commands, data blocks, and templates
* **Live Incident Variables:** Dynamic content placeholders and available variables
* **Real-Time Collaboration:** Multi-user editing, comments, and presence
* **Exporting Retrospectives:** Export to external providers, download as PDF, and sync workflows
* **[AI in Retrospectives](/ai/ai-in-retrospectives/overview):** Auto-draft sections with AI blocks and build AI-powered templates
***
## Frequently Asked Questions
Yes. The editor supports real-time collaboration with live cursors showing where each user is working. Changes from all users are merged automatically without conflicts.
The editor automatically saves changes every second. If you lose connection, your changes are preserved locally and will sync when connectivity is restored.
Yes. Rootly supports external document editors like Confluence, Google Docs, and Notion. If you have a workflow that creates documents in an external editor, those will continue to work as before. The Rootly document editor is optional and independent — workflows for external providers don't affect it.
The Rootly document can be created manually by clicking **Create Rootly Document** in the Retrospective tab, or automatically via a **Create Rootly Retrospective** workflow. Workflows that export to external providers (like Confluence) do not create or modify the Rootly document — these are separate paths. If you create the document manually before a workflow fires, the workflow will not override your document.
Click the **Export** button in the editor header and select **Export to new document**. Choose your destination provider, set a title, and configure any provider-specific options. You can also update previously exported documents by selecting **Update external document** from the same dropdown.
Use data blocks by typing /timeline or /followups in the editor. These blocks pull live data from the incident and update automatically. You can also use liquid variables like `{{ incident.title }}` for individual data points, or a liquid variable block to display conditional outputs or data types like arrays.
Yes. Type `@` in the editor to search for and mention users or incidents. User mentions display an interactive popover showing the person's name, avatar, email, teams, and incident roles.
This depends on your team's configuration. Retrospective workflows can be configured to trigger based on severity, incident type, or other conditions. Some steps can be marked as skippable while others are required.
Select any text in the editor and click the comment button to start a discussion thread. Team members can reply, resolve, or delete their comments. Comments are synced in real-time for all collaborators.
Yes. The editor shows presence indicators with user avatars/initials for everyone currently viewing or editing the document. Collaborative cursors with names show exactly where each person is working.
# Real-Time Collaboration
Source: https://docs.rootly.com/collaborative-retrospectives/real-time-collaboration
Work together on retrospectives with real-time editing, collaborative cursors, presence indicators, inline comments, and live co-authoring across teams.
## How Real-Time Collaboration Works
The retrospective editor supports simultaneous editing by multiple team members. Changes sync instantly across all connected users, eliminating version conflicts and enabling true collaborative writing.
Collaboration features include:
* **Real-time editing:** See changes as others make them
* **Collaborative cursors:** See where each person is working
* **@Mentions:** Tag users and reference incidents directly in the document
* **Inline comments:** Discuss specific sections without leaving the editor
* **Invite collaborators:** Share the retrospective via Slack or email
* **Document status:** Visual Draft/Published indicators so teams know where things stand
* **Activity sidebar:** See who recently viewed or edited the document
* **Version history:** See how your document evolved based on edits made by your team
Real-time collaboration uses conflict-free replicated data types (CRDTs) to merge changes automatically. No manual conflict resolution is required.
***
## Collaborative Editing
When multiple users open the same retrospective, all changes sync automatically in real-time.
### What You'll Experience
* **Instant updates** — Text typed by others appears immediately
* **No conflicts** — Edits from all users merge automatically
* **Shared state** — Everyone sees the same document at all times
Even if two users edit the same paragraph simultaneously, changes merge correctly without overwriting each other's work.
### Presence Indicators
Shows who's viewing or editing the retrospective with user avatars, colored indicators, and real-time updates.
### Collaborative Cursors
See exactly where other users are working in the document with real-time feedback for typing, text selection and navigation.
## Inviting Collaborators
You can invite team members to collaborate on the retrospective directly from the editor.
### Invite via Slack
Post an invitation to the incident's Slack channel so team members can quickly jump into the editor.
### Invite via Email
Send an email notification to the incident team with a link to the retrospective editor.
### Copy URL
Copy the retrospective editor URL to share it directly via any channel.
Invite options are available from the editor header. Slack invitations are only available when the incident has a linked Slack channel.
***
## Document Status
Retrospectives have two states that are visible to all collaborators via a status chip in the editor header.
### Draft
A yellow **Draft** chip indicates the retrospective is still being worked on. In this state, the document is only accessible to team members with edit access.
### Published
A green **Published** chip indicates the retrospective has been finalized. Published retrospectives:
* Display the publication timestamp (for example, "Last published at Mar 15, 2026 at 2:30pm UTC")
* Can still be edited and re-published
If the incident has not yet been resolved, publishing requires confirmation. This ensures retrospectives aren't accidentally published for ongoing incidents.
***
## Activity Sidebar
The Activity sidebar shows who has recently viewed or edited the retrospective, giving you visibility into document engagement.
To open the Activity sidebar, click **More actions → Show activity** in the editor header.
***
## Comments
Add inline comments to discuss specific parts of the retrospective with your team.
### Creating a Comment
Highlight the text you want to comment on.
Click the **comment** button in the toolbar, or use the keyboard shortcut.
Type your comment in the dialog that appears.
Press Enter or click Submit to create the comment thread.
### Viewing Comments
Comments appear in three ways:
* **Node indicators:** Comments appear inline, attached to the relevant node in the editor.
* **Highlighted text:** Commented text is highlighted in the document. On narrower screens, click the highlight to view the comment.
* **Comments side panel:** View all open and resolved comment threads via the comments panel triggered from the actions dropdown in the header.
Access resolved threads anytime by clicking **More actions → Show resolved comments** in the editor header.
### Comment Actions
| Action | Description |
| ------------- | ----------------------------------------------------------------------------- |
| **Reply** | Add a response to an existing thread |
| **Resolve** | Mark the comment as addressed (hides from active view) |
| **Unresolve** | Mark the comment as unaddressed (visible in the All Comments side panel view) |
| **Delete** | Remove the comment entirely |
| **Edit** | Modify your own comment text |
### Comments Panel
On wider screens, comments display in a dedicated panel alongside the editor.
* **All threads:** See all active comment threads in one place
* **Click to navigate:** Click a thread to jump to that location in the document
* **Reply inline:** Respond to comments directly in the panel
* **Filter options:** View open/resolved comments
#### What Happens When Someone Comments
* The comment appears immediately for all users viewing the document
* The comments panel updates with the new thread
* The commented text becomes highlighted
#### What Happens When Someone Replies
* The reply appears in the thread for all users
* Users viewing the thread see the new reply instantly
Comments are stored with the document and persist across sessions. Team members who open the document later will see all existing comments.
***
### Collaboration Best Practices
#### For Effective Teamwork
* **Communicate your focus area:** If working with others simultaneously, let them know which section you're editing to avoid stepping on each other's work.
* **Use comments for async feedback:** Comments are ideal for review cycles where not everyone is online at the same time.
* **Resolve comments when addressed:** Keep the comments panel clean by resolving threads once feedback is incorporated.
* **Check presence before major edits:** Glance at who's online before restructuring or deleting large sections.
#### For Comments
* **Be specific:** Select the exact text you're commenting on rather than commenting on a general area.
* **Use threads for discussions:** Reply to existing comments rather than creating new threads for the same topic.
* **Resolve, don't delete:** Resolving preserves the history of feedback; deleting removes it permanently.
* **Tag specific questions:** Make it clear if you need a response by phrasing comments as questions.
***
## Visibility and Permissions
### User Permissions
* All users with **edit access** to the incident can collaborate on its retrospective
* Users with **view-only access** can read but not edit or comment
* **Private incidents** restrict access to assigned users
### Comment Visibility
* Comments are visible to all users who can access the retrospective
* There are no private comments. All threads are shared
Collaboration access is determined by incident permissions. Check with your administrator if you need access to a specific incident's retrospective.
### Troubleshooting
There may be a brief delay (a few seconds) before a user's presence indicator disappears after they close the document. This is normal behavior.
Yes. The editor supports @mentions in the document body — type `@` to mention users or incidents. Hovering over a mention shows a popover with details like name, avatar, teams, and incident roles. @mentions in comment threads are not currently supported.
Users can only edit or delete their own comments. To remove someone else's comment, ask them to delete it or contact an administrator.
***
## Related Pages
The umbrella page covering how the editor works end-to-end.
The features co-authors use while collaborating in the document.
Once collaboration is done, publish the retrospective to an external doc.
# Using the Retrospective Editor
Source: https://docs.rootly.com/collaborative-retrospectives/using-the-editor
Use the collaborative retrospective editor's formatting tools, slash commands, data blocks, and templates for post-incident reviews.
## How the Editor Works
The new retrospective editor provides a rich text editing experience with real-time collaboration, dynamic data blocks, and template support. This page covers everything you need to know to create and edit retrospectives effectively.
The editor is designed to be intuitive. You can type naturally, use slash commands for quick actions, and let autosave handle the rest.
## Getting Started with the Editor
### Where to Find the Editor
Navigate to the incident from the incidents list or a direct link.
Click the **Retrospective** tab on the incident page.
Click anywhere in the document preview to open the editor.
The editor opens with your team's default template pre-appended to the document. Start typing or use slash commands to add content.
Retrospective documents automatically populate with your team's default template. You can configure this template in **Retrospectives → Document Templates**.
### Quick Start
* Type naturally to add text
* Press **Enter** to create new nodes in the document
* Type `/` to open the slash command menu
* Select text and use the toolbar for formatting
* Drag and reposition nodes of content in your document
* All changes save automatically
***
## Rich Text Formatting
The editor supports standard rich text formatting through the toolbar, keyboard shortcuts, and slash commands.
### Text Formatting
| Format | Keyboard Shortcut |
| :---------------- | :--------------------- |
| **Bold** | `Cmd/Ctrl + B` |
| *Italic* | `Cmd/Ctrl + I` |
| ~~Strikethrough~~ | `Cmd/Ctrl + Shift + X` |
| `Inline Code` | `Cmd/Ctrl + E` |
### Headings
| Level | Keyboard Shortcut | **Slash Command** | Description |
| :-------- | :---------------- | :---------------- | :-------------------- |
| Heading 1 | `#` | `/h1` | Main section headers |
| Heading 2 | `##` | `/h2` | Subsection headers |
| Heading 3 | `###` | `/h3` | Minor section headers |
### Lists
| Type | Keyboard Shortcut | Description |
| :------------ | :---------------- | :-------------------------------- |
| Bullet List | `-` | Unordered list with bullet points |
| Numbered List | `1.` | Ordered list with numbers |
### Other Blocks
| Block | Slash Command | Description |
| :--------- | :------------ | :--------------------------------------- |
| Blockquote | `/blockquote` | Indented quote block for callouts |
| Code Block | `/codeblock` | Multi-line code with syntax highlighting |
| Table | `/table` | Insert a 3x3 table (expandable) |
| Image | `/image` | Upload and insert an image |
## Slash Commands
Slash commands provide quick access to all editor features. Type `/` anywhere in the editor to open the command menu.
### AI Blocks
AI blocks are sections Rootly drafts for you from the incident's data, Slack channel, and bridge-call transcripts. Type `/` and choose a block (or `/ai`) to insert one; it generates in place and stays fully editable.
| Block | What it drafts |
| -------------------- | ------------------------------------------------------------------------ |
| **Summary** | A concise overview of what happened, the impact, and how it was resolved |
| **Impact** | Who and what was affected — customers, services, scope, and duration |
| **Root Cause** | The underlying cause and contributing factors |
| **Mitigation** | The immediate steps taken to reduce or stop the impact |
| **Resolution** | How the incident was fully resolved |
| **Curated Timeline** | A readable, narrative timeline of the key moments |
| **Custom** | Any section you define with your own title and prompt |
See [AI in Retrospectives](/ai/ai-in-retrospectives/using-ai-blocks) for the full guide.
### Incident Data Blocks
With incident data blocks, you can insert dynamic content that pulls data from the incident.
| Command | Description |
| ------------------- | -------------------------------------------------------------------------------------------------- |
| `/timeline` | Insert the incident timeline block |
| `/followups` | Insert the follow-ups (action items) block |
| `/liquid-variables` | Insert a single liquid variable into the document |
| `/liquid-block` | Insert a code block that renders outputs from more complex liquid syntax or conditional variables. |
#### Basic Blocks
Basic blocks insert standard document elements.
| Command | Description |
| -------------- | -------------------- |
| `/text` | Insert a paragraph |
| `/h1` | Insert Heading 1 |
| `/h2` | Insert Heading 2 |
| `/h3` | Insert Heading 3 |
| `/bulletList` | Insert bullet list |
| `/orderedList` | Insert numbered list |
| `/blockquote` | Insert blockquote |
| `/code` | Toggle inline code |
| `/codeBlock` | Insert code block |
| `/table` | Insert 3x3 table |
| `/bold` | Toggle bold |
| `/italic` | Toggle italic |
| `/strike` | Toggle strikethrough |
The slash command menu filters as you type. For example, typing /time will show the timeline command at the top.
***
## Incident Data Blocks
Incident Data Blocks are dynamic elements that pull live data from the incident. They update automatically when the underlying data changes.
### Timeline Block
The Timeline block displays all events from the incident timeline, including user actions, system events, and status changes.
#### **To insert a Timeline block:**
1. Type `/timeline` in the editor
2. Press **Enter** or click the command
#### **Timeline block features:**
* Shows event date/time, source, user, and description
* Pagination controls help keep the document compact
* Drag the block to reposition it in the document
* Click the node to select the entire block, then use backspace to delete
The Timeline block pulls live data from the incident. If new events are added to the timeline, the block updates automatically.
### Follow-ups Block
The Follow-ups block displays action items associated with the incident.
#### **To insert a Follow-ups block:**
1. Type `/followups` in the editor
2. Press **Enter** or click the command
#### **Follow-ups block features:**
* Shows action item title, priority, status, assignee, and due date
* Sort options: **Due Date**, **Priority**, or **Status**
* Drag the block to reposition it in the document
* Click the node to select the entire block, then use backspace to delete
When follow-ups are added or updated on the incident, the block reflects those changes automatically.
### Working with AI blocks
Like data blocks, AI blocks live in the document and stay editable — see the [AI Blocks](#ai-blocks) table above for the full list of block types.
#### **To insert an AI block:**
1. Type `/ai` in the editor (or pick a block from the slash menu)
2. The block is inserted and starts generating in place
#### **AI block features:**
* Content streams in live as it generates
* Open the block's details to see its sources and the prompt behind it
* Edit the generated text inline, regenerate it, or convert it to plain text
* Rate the output with 👍 / 👎
AI blocks can also be built into your team's templates so every retrospective generates them automatically. See [AI in Retrospectives](/ai/ai-in-retrospectives/using-ai-blocks) for the full guide.
## How Data Blocks Render on Export
When you publish or export the retrospective to an external provider, data blocks are rendered as static content at the time of export. This includes:
* Timeline events formatted as a table
* Follow-ups formatted as a list with metadata
* Liquid variables or blocks resolved to their actual values
* AI block content rendered as static text (the generated draft is frozen at export time)
***
## Using Templates
Templates provide pre-built content structures that ensure consistency across retrospectives.
### Inserting a Template
Type `/` in the editor.
Click **Template** from the dropdown.
Browse your team's available templates and click to insert.
The template content is inserted at your cursor position. Edit as needed.
### What Templates Can Include
* Headings and sections (Summary, Root Cause, Timeline, etc.)
* Placeholder text to guide authors
* Liquid variables (for example, `{{ incident.title }}`)
* Data blocks (`/timeline`, `/followups`)
* Formatting and structure
Templates are configured by administrators in **Retrospectives → Document Templates**. Contact your admin to create or modify templates.
***
## Liquid Variables
Liquid variables are dynamic placeholders that resolve to actual values from the incident.
### Inserting Liquid Variables
1. Type `{{` to start a liquid variable
2. Continue typing to filter available variables
3. Select from the autocomplete dropdown
4. The variable appears as a chip in the editor
#### Common Variables
| Variable | Description |
| ------------------------------- | ------------------------- |
| `{{ incident.title }}` | Incident title |
| `{{ incident.severity }}` | Severity level |
| `{{ incident.status }}` | Current status |
| `{{ incident.started_at }}` | Start timestamp |
| `{{ incident.resolved_at }}` | Resolution timestamp |
| `{{ incident.duration }}` | Total incident duration |
| `{{ incident.commander.name }}` | Incident commander's name |
| `{{ incident.slack_channel }}` | Slack channel name |
| `{{ post_mortem.title }}` | Retrospective title |
Liquid variables display as visual chips in the editor. On publish or export, they resolve to their actual values.
## Liquid Blocks
Liquid Blocks are standalone template blocks that support the full Liquid templating language, including conditionals, loops, and complex logic.
### Liquid Block vs Liquid Variable
| Feature | Liquid Variable | Liquid Block |
| ------------- | ------------------------ | --------------------------------------------- |
| **Scope** | Inline (within text) | Block-level (standalone) |
| **Syntax** | `{{ variable }}` only | Full Liquid: `{% if %}`, `{% for %}`, filters |
| **Rendering** | Inline chip | Edit/Preview panel with live rendering |
| **Best for** | Inserting dynamic values | Conditional content, loops, complex logic |
Use **Liquid Variables** for simple value substitution inline within your text. Use **Liquid Blocks** when you need conditionals, loops, or multi-line template logic.
### Inserting a Liquid Block
1. Type `/liquid` to open the slash command menu
2. Select **Liquid Block** from the options
3. Write your Liquid template in the editor panel
4. Click **Preview** to see the rendered output with real incident data
5. Toggle back to **Edit** to make changes
#### Example Use Cases
**Conditional severity messaging:**
```liquid theme={null}
{% if incident.severity == "critical" %}
🚨 CRITICAL INCIDENT - Immediate escalation required
{% elsif incident.severity == "high" %}
⚠️ High priority incident - Review within 1 hour
{% else %}
📋 Standard incident - Follow normal procedures
{% endif %}
```
**Loop through action items:**
```liquid theme={null}
{% for item in incident.action_items %}
- [{{ item.status }}] {{ item.summary }} (Owner: {{ item.owner.name }})
{% endfor %}
```
**Conditional content with filters:**
```liquid theme={null}
{% if incident.resolved_at %}
Resolved on {{ incident.resolved_at | date: "%B %d, %Y at %I:%M %p" }}
Duration: {{ incident.duration }}
{% else %}
⏳ Incident is still ongoing
{% endif %}
```
Click **Preview** at any time to see how your template renders with actual incident data. Syntax errors will be displayed with helpful error messages.
### When to Use Each
Use Liquid Variables when:
* Inserting a single dynamic value into a sentence
* You need a simple inline placeholder
* Example: "The incident commander is `{{ incident.commander.name }}`"
Use Liquid Blocks when:
* You need conditional logic (`{% if %}...{% endif %}`)
* You need to loop over collections (`{% for %}...{% endfor %}`)
* You have multi-line template content
* You need complex formatting with multiple variables
* Example: Showing different content based on incident severity
## @Mentions
Mention users and incidents directly in the document to create clear accountability and cross-references.
### Mentioning Users
1. Type `@` anywhere in the editor
2. Search for a user by name
3. Select the user from the dropdown
4. The mention appears as an interactive chip in the document
Hovering over a user mention shows a popover with their avatar, name, email, teams, and incident roles.
### Mentioning Incidents
You can also `@`-mention other incidents to cross-reference related events in your retrospective.
@mentions in the document body are interactive — readers can hover to see details without leaving the editor.
***
## Collaboration
Multiple users can edit the retrospective simultaneously. For full details on collaboration features, see [Real-Time Collaboration](/collaborative-retrospectives/real-time-collaboration).
### What You'll See
* **Presence indicators:** Avatars/initials of users currently viewing the document
* **Collaborative cursors:** Colored cursors showing where each user is working
* **Real-time updates:** Changes from other users appear instantly
* **@mentions:** Tag users and incidents inline with interactive popovers
### Comments
Select text and click the **comment** button to start a discussion:
1. Select the text you want to comment on
2. Click the **comment** button in the toolbar
3. Type your comment and submit
4. Others can reply, creating a threaded conversation
5. Mark comments as **resolved** when addressed
Comments are visible to all collaborators and sync in real-time. Use them for async review and feedback.
***
### Best Practices
* **Use slash commands for speed:** Typing `/` is faster than reaching for the toolbar, especially for common actions.
* **Insert data blocks instead of copying:** Timeline and Follow-ups blocks stay in sync with the incident. Manual copy-paste becomes stale.
* **Use templates for consistency:** Starting from a template ensures all retrospectives follow the same structure.
* **Add comments for review feedback:** Instead of sending feedback in Slack, add comments directly in the document for better context.
* **Use headings to structure content:** Clear section headers (Summary, Timeline, Root Cause, Action Items) make retrospectives easier to scan.
***
### Troubleshooting
Make sure your cursor is in an editable area of the document, not inside a data block or at an invalid position. Try clicking in a paragraph and typing `/` again.
This usually means the block couldn't fetch data from the incident. Check your network connection and refresh the page. If the problem persists, the incident may not have any data for that block type (for example, no timeline events or follow-ups).
Ensure you have permission to access retrospective templates. If templates aren't appearing, contact your administrator to verify templates are configured for your team.
Use `Cmd/Ctrl + Z` to undo recent changes. You can also access version history to restore a previous version of the retrospective.
# Communications
Source: https://docs.rootly.com/communications/overview
Send targeted incident updates to the stakeholders who need them, by email, SMS, or Slack, from templates your team prepared in advance.
The **Communications module** sends incident updates directly to the people who need them — by email, SMS, or Slack — rather than broadcasting to everyone. Responders pick a prepared template, the incident's details fill themselves in, and the message reaches only the stakeholder groups whose conditions the incident matches.
It is the targeted counterpart to a [status page](/configuration/status-pages). A status page tells anyone who looks; Communications tells a specific audience, and can require review before anything goes out.
Communications is enabled per organization. If the **Communications** tab does not appear on your incidents, contact your account team.
***
## Where to Start
The responder flow: pick a template and stage, edit it, send it for review, and send it.
Define who hears about what, and the conditions that decide when they do.
Prepare the messages in advance, one per stage of an incident.
The addresses and numbers your messages come from, and getting them allowlisted.
***
## The Moving Parts
Four pieces fit together. Set them up in this order — each depends on the one before it:
A category of communication, such as customer updates or internal leadership updates. Everything else hangs off a type: groups belong to one, and so do templates.
The phases of an incident you communicate at — for example initial, investigating, resolved. Stages are shared across the organization.
The prepared message for a type, with separate content per stage and per channel. Liquid variables pull in the incident's own details.
Who receives a type of communication, and under what conditions — a severity, a service, a functionality, a team, or an incident type.
With those in place, sending during an incident is a matter of choosing a template and a stage, checking the text, and sending.
***
## What a Responder Does
During an incident, the **Communications** tab lists everything already sent, with its delivery status, and lets you create the next update. The same flow is available in Slack with `/rootly comms new`.
Rootly suggests the template that fits the incident, and the recipients are worked out from the groups whose conditions the incident matches — so a responder is choosing what to say, not who to say it to.
The decision about *who* hears about an incident belongs in your group conditions, made calmly in advance. Leaving it to the person writing an update at 3am is how the wrong stakeholders get paged, or the right ones get missed.
***
## Review Before Sending
Any draft can be shared to a Slack channel for review before it goes out. The request is clearly marked as needing review, so approval happens where your team already works rather than in a separate tool.
A sent communication cannot be recalled. For anything customer-facing, or anything a regulator or executive will read, route it through review — and remember that SMS in particular has no correction path once delivered.
***
## Best Practices
* **Decide your audiences before your messages.** Groups and their conditions are the hard part; templates are easy once you know who is listening.
* **Write one template per type, not per incident.** Stages handle the difference between "we're investigating" and "it's resolved".
* **Use Liquid for anything factual.** Severity, title, summary, and timestamps should come from the incident record rather than being retyped under pressure.
* **Make review the default for external audiences.** Internal updates can go direct; customer-facing ones benefit from a second reader.
* **Allowlist Rootly's sending addresses and numbers early.** Discovering a spam filter mid-incident is an avoidable failure — see [Communication Sources](/communications/sources).
* **Revisit conditions after reorganizations.** Groups scoped to services or teams drift when ownership changes.
***
## Related Resources
Broadcast status publicly, for anyone who looks.
Post incident updates to a status page.
Every incident value a template can pull in.
Automate notifications that do not need a human author.
***
## Frequently Asked Questions
Reach and intent. A status page is public and passive — anyone can look, nobody is notified. Communications is targeted and active: it pushes a message by email, SMS, or Slack to defined groups. Most teams use both, with the status page as the public record and Communications for the audiences who need telling directly.
A [workflow](/workflows/workflows) fires automatically with no author, which suits mechanical notifications. A communication is written or approved by a person, so it suits messages where the wording matters and someone should be accountable for it.
Yes. Groups can contain external members, which is the point — customers, executives, and support leads generally are not Rootly users.
Yes. Types, stages, templates, and groups all have Terraform resources. See [Terraform](/integrations/terraform).
# Recipient Groups
Source: https://docs.rootly.com/communications/recipient-groups
Define who receives each type of incident communication, and the conditions that decide which incidents reach them.
A **recipient group** is a list of people who should hear about a particular kind of incident, plus the conditions that decide which incidents qualify. Groups are what make communications targeted: a responder chooses the message, and the groups decide the audience.
Getting groups right is the substantive work in setting up Communications. Templates are easy once you know who is listening.
***
## What a Group Holds
What this audience is, in the terms your organization uses. "Enterprise customer success" beats "Group 2" when someone is checking who a message reached.
Every group belongs to one [type](/communications/templates-and-stages#types). This is what connects an audience to the messages it can receive — a group under "Customer updates" only ever receives customer-update communications.
Rootly users and external people. External members are the point of the feature: customers, executives, and support leads generally do not have Rootly accounts. A group holds up to 50 participants.
How this group is reached. Match the channel to the audience rather than the message — executives may want SMS for severity 0 and email for everything else, which is two groups, not one.
A **private** group is managed by admins: membership is deliberate. A **public** group can be subscribed to, so stakeholders opt themselves in. Public groups suit broad internal audiences; private groups suit anything external or sensitive.
The 50-participant limit is per group, not per communication. A message reaching several matching groups reaches all of their members. Split large audiences by what they care about — which usually produces better-targeted conditions anyway.
***
## Conditions
Conditions decide which incidents reach a group. Without them, a group would hear about everything.
A condition matches an incident property against values you choose:
| Property | Use it to reach people who care about… |
| ----------------- | ------------------------------------------------------------------------------------------------------- |
| **Severity** | Only serious incidents — the usual first condition for executive or customer audiences. |
| **Service** | A specific system, for the team or customers who depend on it. |
| **Functionality** | A user-facing capability, which often maps better to what customers recognize than a service name does. |
| **Team** | Incidents owned by a particular team. |
| **Incident type** | A class of incident, such as security. |
### All or Any
A group matches on **all** of its conditions or **any** of them, and the difference is large:
* **All** — every condition must match. `Severity is SEV0` *and* `Service is Payments` reaches this group only for severity-0 payments incidents. Narrow and predictable.
* **Any** — one match is enough. The same two conditions now reach the group for *every* SEV0 anywhere, *and* every payments incident at any severity. Much broader than it looks when writing it.
Setting a group to **any** with several conditions is the most common way stakeholders end up over-notified. Start with **all**, confirm the group is being reached when it should be, and widen only if it is missing incidents it should hear about.
***
## Public Groups and Self-Subscription
A public group can be subscribed to rather than administered. This works well when the audience is large, internal, and self-selecting — the people who want to know about payments incidents usually know who they are.
Keep external and sensitive audiences private. Anything a customer receives should have deliberate membership.
Public groups reduce the maintenance burden that kills communication setups. A private group nobody updates after a reorganization quietly sends to the wrong people; a public one lets its members fix that themselves.
***
## Designing a Group Structure
Groups multiply quickly. A structure that stays manageable usually follows the audience, not the org chart:
1. **Start from the question "who needs to know?"** for two or three realistic incidents. That produces your first groups.
2. **Separate by channel only when the channel genuinely differs.** An audience that wants SMS for severity 0 and email otherwise is two groups with different conditions.
3. **Prefer functionality over service for customer-facing groups.** Customers recognize "Checkout" more readily than the services behind it.
4. **Keep executive groups narrow.** A severity condition alone is usually right; adding services tends to produce gaps.
5. **Review after reorganizations.** Conditions referencing services or teams drift when ownership moves.
***
## Troubleshooting
Check the incident against the group's conditions rather than the message. The usual causes: the incident's severity is below the threshold, the affected service or functionality is not attached to the incident, or the group's conditions are set to **all** and only some matched.
Conditions are probably set to **any**. Switch to **all** and add the narrowing condition that was missing, most often severity.
A group holds up to 50 participants. Split it along the lines its conditions already suggest — by service or functionality — rather than raising the count.
Groups belong to a communication type, and a type in use cannot be removed while groups or templates depend on it. Detach or remove those first.
The group is private. Only public groups accept self-subscription.
***
## Related Resources
The messages these groups receive.
How groups are resolved when an update goes out.
# Sending a Communication
Source: https://docs.rootly.com/communications/sending-communications
Create an incident update from a template, edit it with live incident detail, send it for review, and deliver it to the right stakeholders.
During an incident, the **Communications** tab is where updates to stakeholders are written, reviewed, and sent. Everything already sent is listed there with its delivery status, so a responder joining late can see what has gone out before adding to it.
The same flow is available in Slack with `/rootly comms new`, which matters when the incident is being run in a channel rather than in the web interface.
***
## Reviewing What Has Already Gone Out
Before writing anything, check the record. The **Completed** list shows each communication that has been sent, and opening one shows:
* Where it originated
* Which recipient groups received it, including any Slack channels
* Its delivery state — sent, partially sent, or still sending
* Any drafts associated with it
Read the last update before writing the next one. Stakeholder trust is lost faster by contradicting a previous message than by saying nothing, and the previous message is rarely the one you remember sending.
***
## Creating an Update
Select **Create New** in the incident's Communications tab, or run `/rootly comms new` in Slack.
Rootly suggests the template that fits the incident. Every available template is in the dropdown if the suggestion is not the right one.
Stages represent where the incident has reached — an initial notification reads differently from a resolution notice. Selecting a stage loads that stage's prepared content. See [Templates and Stages](/communications/templates-and-stages).
This opens the editor with the template rendered against the live incident.
***
## The Editor
The editor shows the message alongside the facts about it.
**On the left**, the details of the communication itself: its status, the type and template it came from, the stage, who created it, the addresses and numbers it will send from, and the recipient groups it will reach.
**On the right**, the message. Template content arrives already filled in — Liquid variables have pulled the incident's title, summary, severity, and timestamps out of the record rather than asking you to retype them.
Each channel is edited separately, so the email body, the SMS text, and the Slack message can each say what suits that medium. Editing here changes this message only; the template is untouched.
SMS is capped near 160 characters, so the SMS version of an update is not a shortened email — it is a different message. Write it as a pointer: what is wrong, who is affected, and where to read more.
***
## Sending, Saving, or Requesting Review
Three actions, and choosing between them is mostly about audience:
Deliver now, to every group whose conditions the incident matches. Requires permission to send. There is no recall.
Keep the message without sending. Useful when you have written an update ahead of a decision that has not been made yet, or when handing the incident to the next responder.
Send the draft to a Slack channel or specific people for review. The request is clearly marked as needing review, so approvers see it as a task rather than another notification.
***
## Getting a Communication Reviewed
Review exists because the cost of a wrong external message is much higher than the cost of a delayed one.
Choose the channel or people who should read it. They see the message as recipients will.
Discussion happens in Slack, next to the incident, rather than in a separate approval tool.
Apply any changes in the editor, then send. The draft and the sent message both stay on the record.
Review is worth its delay for anything customer-facing, anything a regulator or executive will read, and any message stating a cause or a restoration time. Internal "we are on it" updates rarely need it.
***
## Delivery
Once sent, a communication moves through delivery rather than completing instantly. The Communications tab shows whether it is still sending, fully sent, or only partially delivered.
Partial delivery usually means individual recipients failed rather than the message failing — a bounced address, an unreachable number. Check the affected recipients rather than resending to everyone, which would deliver the message twice to people who already have it.
***
## Troubleshooting
Recipients come from group conditions, not from the message. If no group's conditions match this incident, there is nobody to send to. Check the incident's severity, service, functionality, team, and type against your [group conditions](/communications/recipient-groups#conditions).
A group's conditions are broader than intended. Conditions can require all criteria to match or any of them — a group set to "any" reaches far more incidents than one set to "all".
Almost always filtering rather than delivery. Confirm Rootly's sending addresses are allowlisted — see [Communication Sources](/communications/sources) — and check whether the recipient's provider quarantined it.
A Liquid variable that does not resolve renders empty. Usually the field is genuinely blank on the incident — a summary that was never written, for instance. Fill it on the incident and recreate the communication.
Sending is permission-gated. Save the draft and share it for preview so someone with permission can send it.
***
## Related Resources
Why a given incident reaches a given audience.
Prepare the messages this flow draws on.
# Communication Sources
Source: https://docs.rootly.com/communications/sources
Configure the email addresses and phone numbers your incident communications send from, and get them allowlisted before you need them.
A **communication source** is the address or number a message arrives from. Email communications send from addresses you configure; SMS communications send from numbers Rootly provides.
This is the least interesting part of the module and the most common reason a communication fails. A message that is written, reviewed, and sent still fails if the recipient's mail provider quarantines it.
Allowlist Rootly's sending addresses and numbers as part of setup, not after the first missed update. Filtering is silent — Rootly reports the message as sent, because it was; it simply never reached the inbox.
***
## Email Sources
Email sources are the **from** addresses your communications use. Which address a message arrives from shapes whether it is trusted, read, and replied to correctly.
What recipients see as the sender. One source is selected as the default for outgoing communications.
Choosing an address is mostly about the audience:
* **Customer-facing communications** should come from an address customers recognize and could plausibly reply to. An unfamiliar domain mid-incident invites suspicion at exactly the wrong moment.
* **Internal communications** can use a more operational address, since colleagues will recognize it.
Use an address that is monitored, or one that makes clear it is not. Recipients reply to incident updates — with questions, with impact reports, sometimes with information you need. Replies into an unwatched mailbox are lost signal.
***
## SMS Sources
Rootly provides the phone numbers SMS communications send from. They are listed in the Communications configuration so your team can distribute and allowlist them.
SMS is the highest-attention channel and the least forgiving:
* **It cannot be recalled or corrected.** An email can be followed by a correction that lands in the same thread; an SMS correction is a second alarm.
* **It arrives out of context.** No subject, no thread — just text on a lock screen, often at night.
* **It is length-limited.** Around 160 characters per segment, so it is a pointer rather than a summary.
Reserve SMS for audiences and severities where waking someone is proportionate. An executive group scoped to severity 0 is a good use; a service-team group scoped to any severity will produce fatigue and get muted — after which it carries no signal at all.
***
## Getting Rootly Allowlisted
Do this once, ahead of time, with whoever runs your mail and mobile device management:
Both are listed in the Communications configuration area.
Ask for them to bypass spam filtering and quarantine for internal recipients.
An unknown number sending an urgent message is exactly what people are trained to ignore. Telling stakeholders in advance which numbers are Rootly's makes the difference.
Use a low-severity or test incident and confirm the message arrives in the inbox rather than the spam folder, and that the SMS reaches a real handset.
Test with a recipient outside your own team. Internal mail between colleagues is filtered far more leniently than mail to a customer's provider, so a successful internal test proves less than it appears to.
***
## Troubleshooting
Delivery and receipt are different things. If Rootly reports the message sent, it left successfully — so the problem is downstream. Check the recipient's spam or quarantine folder, confirm the sending address is allowlisted, and ask their mail administrator whether it was filtered.
External providers apply stricter filtering than your own. Sending from a domain the recipient recognizes helps most; consult whoever manages your email authentication about the sending domain's reputation.
Confirm the recipient's number is correct and reachable internationally if they are outside your usual region, and check whether their carrier or device is blocking unknown numbers. Sharing Rootly's numbers with recipients in advance prevents most of this.
Replies go to the from address. If it is unmonitored, either monitor it or choose a source address that routes somewhere a human reads.
Some recipients failed while others succeeded — usually a bad address or unreachable number rather than a problem with the message. Investigate the affected recipients rather than resending to the whole group, which would deliver twice to everyone who already received it.
***
## Related Resources
Who receives communications, and on which channel.
The flow these sources deliver.
# Templates and Stages
Source: https://docs.rootly.com/communications/templates-and-stages
Prepare incident messages in advance: define communication types, map your incident lifecycle to stages, and write templates that fill themselves in.
Templates are the messages your team writes calmly in advance so nobody is drafting customer-facing prose during an incident. Each template belongs to a **type**, carries separate content for each **stage** of an incident, and uses Liquid variables so the incident's own details fill themselves in.
Set these up in order: types, then stages, then templates.
***
## Types
A **communication type** is a category of message with a distinct audience and purpose — customer updates, internal leadership updates, support-team briefings.
Types are the organizing principle for the whole module. Both [recipient groups](/communications/recipient-groups) and templates belong to a type, which is what connects an audience to the messages it can receive.
What this category of communication is. Name it for the audience and purpose together — "Customer status updates" rather than "External".
A visual marker so responders can tell types apart at a glance when choosing a template mid-incident.
A type that has groups or templates attached cannot be deleted. Detach or remove them first — which is deliberate, since deleting a type in use would orphan both an audience and the messages meant for it.
Resist creating a type per team. Types multiply the templates you must maintain, because each type needs its own template with content for every stage. Most organizations need three or four.
***
## Stages
A **stage** is a phase of an incident that you communicate at. Stages are defined once for the organization and shared across every type, so "Resolved" means the same thing everywhere.
Typical stages map to how an incident actually unfolds:
| Stage | What the message does |
| ----------------- | ---------------------------------------------------------------------------------------------------------- |
| **Initial** | Acknowledges the problem and says what is known. Deliberately short — it exists to be first, not complete. |
| **Investigating** | Confirms work is ongoing, states impact more precisely, and sets the next update time. |
| **Monitoring** | A fix is in place and being watched. Signals near-resolution without declaring it. |
| **Resolved** | Service is restored, with a brief statement of what happened. |
| **Follow-up** | Post-incident detail, such as a link to the published retrospective. |
Stages are your own — name them to match how your organization already talks about incidents rather than adopting a standard set that nobody recognizes.
Setting the next update time in every stage before Resolved is what keeps stakeholders from chasing you. A message that says nothing except "still working, next update at 15:00" is a good message.
***
## Templates
A **template** holds the prepared content for one type, with separate text for each stage and each channel.
The type determines which audiences can receive it.
Within the template, each stage gets its own message. A template without content for a stage cannot be used at that stage.
Email subject and body, SMS text, and Slack message are authored independently, because they are read very differently.
Title, summary, severity, affected services, and timestamps should come from the incident record.
### Writing for Each Channel
The same update needs three different shapes:
* **Email** carries the full message — context, impact, what is being done, when the next update comes. Subject lines can be long, but the useful part belongs at the front, since that is all a phone preview shows.
* **SMS** is capped near 160 characters. Treat it as a pointer, not a summary: what is wrong, who is affected, where to read more. Longer messages split into multiple segments.
* **Slack** sits between the two, and can carry links comfortably.
Email subject, header, and footer have generous limits — thousands of characters — so the practical constraint is what a reader will tolerate, not what the field accepts. SMS is the one channel where the limit genuinely bites.
***
## Liquid Variables
Liquid is what makes a prepared template specific to the incident it is sent from. Instead of typing the severity into the message, the template references it and Rootly fills it in at send time.
Use variables for anything that exists on the incident record — title, summary, severity, status, affected services and functionalities, timestamps, and links. [Incident variables](/liquid/incident-variables) lists everything available.
A variable referencing a field the incident has not filled renders empty, which produces a message with a gap where the summary should be. For customer-facing templates, keep the sentence readable if a variable resolves to nothing, and make sure the incident fields your templates depend on are ones your process actually populates.
Preview a template against a real past incident before relying on it. Reading it filled in is the only way to catch a variable that resolves to something technically correct and completely unhelpful — an internal service slug in a customer email, for instance.
***
## Keeping Templates Usable
* **Fewer, better templates.** One well-written template per type covering every stage beats a dozen situational ones nobody can choose between under pressure.
* **Write for the reader, not the responder.** Customer-facing templates should avoid internal service names, severity numbers, and team names.
* **Say what is being done, not how.** "We have identified the cause and are deploying a fix" ages better than implementation detail that may turn out wrong.
* **Review templates after real incidents.** The retrospective is the moment to notice a template that read badly, while the discomfort is fresh.
* **Manage them as code if your configuration is stable.** Types, stages, and templates all have [Terraform](/integrations/terraform) resources.
***
## Troubleshooting
The template has no content for that stage. Add content for it, or pick a stage the template covers.
The variable name does not match an available one, or the syntax is malformed. Check it against [incident variables](/liquid/incident-variables).
A variable resolved to nothing because that field is empty on the incident — most often the summary. Fill it on the incident, then recreate the communication.
Groups or templates still reference it. Remove or reassign those first.
It exceeded a single segment. Rewrite the SMS content as a pointer with a link rather than a condensed version of the email.
***
## Related Resources
The audiences a type's templates reach.
Every incident value a template can reference.
# What Is an Incident Commander?
Source: https://docs.rootly.com/concepts/incident-commander
An incident commander leads the response to an incident—coordinating people, decisions, and communication. Learn the role, skills, and how to assign one.
An **incident commander** is the person who leads the response to an incident. They coordinate responders, drive decisions, and keep the response organized so that everyone else can focus on investigating and fixing the problem. The incident commander does not need to be the most senior engineer in the room—their job is to run the response, not to personally resolve the issue.
The role originated in emergency services (the Incident Command System used by firefighters and disaster responders) and was adopted by software teams because it solves the same problem: when something is on fire, someone needs to be clearly in charge.
## What does an incident commander do?
During an incident, the commander owns the *process* of the response. While a technical lead digs into logs and a communications lead drafts status updates, the incident commander maintains the big picture: What do we know? What are we trying next? Who is doing what? When do we update stakeholders?
Without a commander, incidents tend to drift. Multiple people investigate the same theory, no one updates the status page, and decisions stall because nobody feels authorized to make them. A commander removes that ambiguity—every question about the response has a clear owner.
## Incident commander responsibilities
The exact scope varies by organization, but incident commanders typically:
* **Declare and scope the incident** — confirm severity, impact, and which services are affected.
* **Assemble the response team** — pull in the right responders and assign roles like technical lead, communications lead, and scribe.
* **Drive decisions** — choose between mitigation options, approve risky actions like rollbacks or failovers, and break ties when responders disagree.
* **Manage communication cadence** — make sure stakeholders, support teams, and customers get timely updates, even if someone else writes them.
* **Track the state of the response** — keep a running picture of what has been tried, what is in progress, and what comes next.
* **Manage responder workload** — rotate people out of long incidents and escalate when the team needs more help.
* **Hand off cleanly** — brief the next commander during long-running incidents, and kick off the retrospective once the incident is resolved.
## What makes a good incident commander?
Good incident commanders are calm under pressure, decisive with incomplete information, and comfortable delegating. Deep technical knowledge of the affected system helps but is not required—in fact, commanders who dive into debugging themselves usually stop commanding, which is the failure mode the role exists to prevent.
Look for people who:
* Communicate clearly and summarize well, especially in writing
* Ask direct questions ("What do we know? What's blocking you?") rather than speculating
* Make timeboxed decisions instead of waiting for perfect information
* Stay blameless and keep the response focused on mitigation, not fault
Many teams train a rotating pool of incident commanders rather than relying on one or two heroes. This spreads the load, avoids single points of failure, and builds incident skills across the organization.
## Incident commander vs. incident manager vs. on-call engineer
These titles are often used loosely, but they describe different things:
* **Incident commander** — leads a *specific incident* from declaration to resolution. It's a temporary, per-incident role, not a job title.
* **Incident manager** — often a permanent job function focused on the incident *program*: process design, tooling, metrics, and post-incident follow-through. In some organizations "incident manager" is simply their name for the commander role.
* **On-call engineer** — the person paged first when something breaks. They triage and often resolve small incidents alone. For larger incidents, they may become the incident commander, or they may declare the incident and hand command to someone else while they investigate as technical lead.
The key distinction: on-call determines *who responds first*, while incident command determines *who runs the response*. They can be the same person, but for high-severity incidents it is usually better to separate them.
## How to assign incident commanders automatically
Manually figuring out who should command an incident at 3 a.m. wastes the minutes that matter most. In Rootly, incident commander is a configurable [incident role](/incidents/incident-roles/incident-roles)—alongside roles like technical lead, communications lead, and scribe—with clear ownership visible in the incident sidebar, Slack summaries, and the incident timeline.
You can fill the role automatically using [workflows](/workflows/workflows), Rootly's automation engine. A workflow can assign the incident commander based on severity, impacted services, incident type, or the current on-call schedule—so the moment a SEV1 is declared, command is already assigned and announced in the incident channel. Responders can also assign or reassign the role directly from Slack, and every change is tracked in the timeline for the retrospective.
You can also just ask. Mention `@Rootly` in the incident channel and tell the [Rootly AI agent](/ai/rootly-in-slack/overview) to assign roles—"make me the incident commander" or "assign Priya as communications lead"—and it applies the change and announces it, without opening a form.
To get started, see [Managing Incident Roles Through the Web Interface](/incidents/incident-roles/managing-incident-roles-through-the-web) or [Managing Incident Roles Through Slack](/incidents/incident-roles/managing-incident-roles-through-slack).
# How to Run an Incident Retrospective
Source: https://docs.rootly.com/concepts/incident-retrospective
An incident retrospective is a blameless review of what happened, why, and what to change. Learn how to run one step by step and what to include.
An **incident retrospective** is a structured review that a team runs after an incident to understand what happened, why it happened, and what to change so it happens less often—or hurts less when it does. The output is usually a written document plus a set of owned, dated action items. Done well, retrospectives turn incidents from pure cost into your most reliable source of learning.
The single most important property of a good retrospective is that it is **blameless**. The goal is to understand how reasonable people, given what they knew at the time, made the decisions they made—not to find who to blame. Teams that punish honesty get incomplete timelines and repeat incidents.
## Retrospective vs. postmortem: is there a difference?
In practice, the terms describe the same activity: a post-incident review. "Postmortem" is the older, more common term; "retrospective" has gained ground because it avoids the morbid framing and emphasizes learning over autopsy. Some teams draw a soft distinction—using *postmortem* for the written document and *retrospective* for the meeting and process around it—but there is no industry-standard difference. Pick one term, define it, and use it consistently.
## How to run an incident retrospective
### 1. Schedule it quickly
Hold the retrospective within a few business days of resolution—ideally within a week. Memory decays fast, and the details that matter most (what people saw, what they believed, why they acted) are the first to go. Invite the responders who were actually involved, not just their managers.
### 2. Build the timeline
Reconstruct what happened in order: when the issue started, when it was detected, key decisions, mitigation attempts, and resolution. Pull from your incident channel, monitoring alerts, deploy logs, and the incident timeline. A shared, factual timeline grounds the whole discussion—disagreements about "what happened" should be settled here, before anyone discusses "why."
### 3. Identify contributing factors
Resist the urge to find *the* root cause. Real incidents almost always have several contributing factors: a latent bug, a gap in monitoring, an ambiguous runbook, a risky deploy window. Ask "what made this possible?" and "what made this worse?" for each phase—detection, diagnosis, and mitigation. Slow detection and slow mitigation are findings just as much as the triggering defect.
### 4. Write a blameless narrative
Document the incident from the responders' point of view: what they knew, what they saw, and why their actions made sense at the time. Avoid counterfactuals ("they should have checked the dashboard") and name systems, not people, as points of failure. If the narrative reads like an indictment of a person, rewrite it.
### 5. Assign action items
Turn findings into concrete follow-ups: fix the bug, add the missing alert, update the runbook, add a guardrail to the deploy pipeline. Every action item needs a single owner and a due date—a list of good intentions without owners is where retrospectives go to die. Prioritize ruthlessly; three completed action items beat fifteen abandoned ones.
### 6. Share the learnings
Publish the retrospective where the whole engineering organization can read it, and announce it—in a team meeting, a newsletter, or a dedicated channel. Other teams likely share the same failure modes. An unread retrospective only teaches the people who were already there.
## What to include in the document
A solid retrospective document covers:
* **Summary** — a few sentences: what broke, the impact, and the fix
* **Impact** — duration, affected services, customer-facing effects, and any SLA/SLO implications
* **Timeline** — timestamped sequence from first signal to resolution, including detection and escalation times
* **Contributing factors** — the conditions that made the incident possible and prolonged it
* **What went well** — effective responses worth reinforcing (fast detection, a good runbook, a clean handoff)
* **What could be improved** — gaps in tooling, process, or knowledge
* **Action items** — each with an owner, a due date, and a priority
## Common mistakes
* **Skipping retrospectives for "small" incidents.** Near-misses are cheap lessons. You don't need the full process for every blip, but a lightweight review beats none.
* **Blame in disguise.** "Human error" as a root cause, or timelines written as accusations. If a person "caused" the incident, the system that let one mistake cause an outage is the real finding.
* **Root-cause tunnel vision.** Stopping at the first plausible cause and missing the detection and response gaps around it.
* **Action items with no follow-through.** Unowned, undated items quietly expire. Review open items regularly.
* **Waiting weeks to run it.** Stale memories produce vague timelines and generic conclusions.
* **Writing it and telling no one.** The document is a means; the learning is the point.
## Automating retrospectives in Rootly
Most retrospective failures are process failures—steps forgotten, documents never started, action items never tracked. Rootly automates that scaffolding.
[Retrospective processes](/retrospectives/retrospectives) let you define ordered steps (gather data, write the document, host the review, create action items, share the report) with due dates, assignees based on incident roles, and reminders. You can right-size the process by severity, team, or incident type, so a SEV1 gets a full review while a minor incident gets a lightweight one—see [Configuring Retrospective Processes](/retrospectives/configuring-retrospective-processes).
[Retrospective workflows](/workflows/retrospective-workflows) trigger on retrospective lifecycle events—for example, when a retrospective is published, automatically create the doc in Confluence or Google Docs, notify leadership channels, and open follow-up tickets. And [action items](/incidents/action-items/action-items) give every follow-up an owner, a due date, and a status, with exports and dashboards so open items stay visible long after the incident channel goes quiet.
The biggest time sink—writing the draft—is where [Rootly AI in retrospectives](/ai/ai-in-retrospectives/overview) does the heavy lifting. It drafts the retrospective from the incident's real data (timeline, Slack discussion, and bridge-call transcripts), suggests contributing factors and a summary, and fills AI blocks in your retrospective template, so the review starts from a complete first draft instead of a blank page. Reviewers still edit and own the narrative—the agent removes the busywork, not the judgment.
# Audit Log for compliance and change tracking
Source: https://docs.rootly.com/configuration/audit-log
Track configuration changes, integration updates, and incident actions in Rootly with a filterable audit log and JSON:API export for compliance evidence.
## Overview
Rootly's Audit Log captures every create, update, and delete action across your organization — configuration changes, integration updates, incident actions, workflow edits, role assignments, and more. Each entry records who made the change, what changed, when, from where (web, API, mobile, Slack, SCIM, OAuth), and the exact before-and-after values of the modified fields.
Built on PaperTrail under the hood with \~60 resource types instrumented, the audit log is the compliance evidence layer SOC2 and ISO27001 auditors look for. It's also a real operational tool — answer "who deleted this severity?" or "when did the escalation policy change?" without paging anyone.
Every create, update, and delete across configuration, integrations, incidents, workflows, and on-call settings. Captures before-and-after field values.
Filter by date range, user, source (web/API/mobile/Slack/SCIM/OAuth), item type, action, or API key. Click any row to see the full diff.
Pull audit events programmatically via the public API — useful for compliance archival, custom dashboards, and scheduled exports into long-term storage.
Passwords, tokens, API keys, and other credentials are automatically redacted in the UI and API responses.
***
## Who Can View the Audit Log
Access is role-based. Two paths grant audit-log read access:
Grants visibility into all audit events across the organization. Configured under **Configuration → Roles & Permissions** by enabling the **Audits — read** permission on the role.
Grants visibility into audit events for on-call resources only — Alerts, Alert Routes, Schedules, Escalation Policies, and related items. Useful when on-call leads need visibility into on-call configuration changes without seeing the full organizational audit history.
Users without either permission don't see the **Audit Log** sidebar entry under Configuration → Organization.
***
## What Gets Logged
Roughly 60 resource types are instrumented. Highlights:
API Keys, Secrets, Roles, On-Call Roles, Memberships, Severities, Environments, Custom Fields, Custom Forms.
Incidents, Action Items, Incident Events, Post-Mortems, Incident Permission Sets.
Genius Workflows, Workflow Runs, Workflow Groups — including create, edit, enable/disable.
Slack, PagerDuty, Opsgenie, Jira, Datadog, GitHub, ServiceNow, Zoom, and every other integration's connection and configuration changes.
Schedules, Escalation Policies, Alerts, Alert Routes, Alert Routing Rules.
Services, Functionalities, Groups (Teams), Environments, Causes.
Each entry captures:
| Field | What It Means |
| ------------------------- | ----------------------------------------------------------------------------- |
| `whodunnit` | User ID of the actor who triggered the change |
| `item_type` and `item_id` | The resource that was modified |
| `event` | One of `create`, `update`, `destroy` |
| `source` | Where the action came from — `web`, `api`, `mobile`, `slack`, `scim`, `oauth` |
| `api_key_id` | If the action came from the API, which key triggered it |
| `request_id` | HTTP request ID for tracing through Rootly's logs and external systems |
| `metadata.ip` | IP address of the actor, when available |
| `object_changes` | Before-and-after values for every modified field, with humanized field names |
**Sign-in and sign-out events are tracked separately** from the main audit log, in Rootly's login activity store. The main audit log focuses on configuration and operational changes, not authentication events. For a unified authentication + audit view, pair the JSON:API export with sign-in events from your IdP (Okta, Azure AD, Google Workspace).
***
## View the Audit Log in Rootly
In Rootly, go to **Configuration → Organization → Audit Log**. The full event history loads in reverse-chronological order.
Use the filter row at the top of the table to narrow down:
Start and end timestamps.
Actor who triggered the change.
`web`, `api`, `mobile`, `slack`, `scim`, or `oauth`.
The resource that changed (for example, `Incident`, `EscalationPolicy`, `Severity`).
`create`, `update`, or `destroy`.
Filter by the actions of a specific automation.
Click any audit entry to open the detail drawer. It shows the full before-and-after values for every field that changed, with humanized field names and timezone-aware timestamps.
**Looking for user permission changes specifically?** Set the **Item type** filter to `Role`, `OnCallRole`, or `Membership` — those three resource types capture role assignments, on-call role changes, and team membership updates respectively. If the affected user is managed via SCIM, also try setting **Source** to `scim` to surface IdP-driven provisioning events; web-UI and API changes appear with `source` set to `web` or `api`. Without an item-type filter, role changes can be hard to spot in a busy audit feed full of incident and workflow events.
***
## Programmatic Access via API
For compliance exports, evidence collection, or building your own audit dashboards, query the audit log through the JSON:API endpoint.
```http theme={null}
GET /api/v1/audits
Authorization: Bearer
```
Filter to a specific resource type. Examples: `Incident`, `Severity`, `EscalationPolicy`, `ApiKey`.
Filter to actions taken by a specific user.
Filter to actions triggered by a specific API key — useful for auditing automations.
One of `web`, `api`, `mobile`, `slack`, `scim`, `oauth`.
Supports `gt`, `gte`, `lt`, `lte` operators for time-range queries. Example: `filter[created_at][gte]=2026-01-01T00:00:00Z`.
`created_at` for ascending order, `-created_at` for descending. Default is descending (most recent first).
JSON:API standard pagination. Maximum page size depends on your plan; iterate through pages for full exports.
Response includes all the same fields the UI shows (`whodunnit`, `item_type`, `event`, `source`, `object_changes`, etc.) plus the resource's full prior and current state where applicable. Sensitive fields (passwords, tokens, API keys, OAuth secrets) are redacted by the serializer before the response leaves Rootly.
For full API authentication and pagination details, see the [API Reference](/api-reference/overview).
***
## Sensitive Field Redaction
The UI and API responses redact sensitive field values before they leave Rootly. Redaction applies to fields whose names match common credential patterns — `password`, `api_key`, `token`, `secret`, `credentials`, and similar.
What you'll see in place of redacted values:
* Field appears in the diff but the value is replaced with `[REDACTED]`
* The fact that the field changed is still recorded (useful for "rotated the API key on Oct 5")
* The new value is never visible — only that it was modified
This matters for compliance: rotating a secret or updating an integration's API key still generates a complete audit trail, without exposing the new credential to anyone who can read the audit log.
***
## Retention
Rootly retains audit logs indefinitely by default — there's no automatic deletion policy. For long-term compliance archival, use the JSON:API to pull events on a schedule into storage your auditors already own.
***
## Frequently Asked Questions
No — authentication events are tracked separately from the configuration audit log. For a unified view of auth + audit, pair the JSON:API export with sign-in events from your IdP (Okta, Azure AD, Google Workspace).
Not directly from the UI. Use the JSON:API endpoint (`GET /api/v1/audits`) to pull the data and convert it to CSV in whatever tool fits your workflow. Most teams pull on a schedule for compliance archival rather than ad-hoc CSV export.
No. Passwords, API keys, OAuth tokens, and other credential-like fields are automatically redacted in the UI and API responses. The audit log records that the field was changed — never the new value.
Only if their role has the **Audits — read** permission on the base role. The on-call role's audit permission scopes visibility to on-call resources only (Alerts, Schedules, Escalation Policies). Grant the base-role audit read permission for full visibility.
Yes. Incidents, action items, post-mortems, incident events, and permission sets all generate audit entries on create, update, and delete. Useful for reconstructing exactly what happened during incident response.
Their historical actions stay in the audit log — the user reference is preserved. Future actions can't be attributed to that user because they no longer have access, but everything they did while active remains traceable.
***
## Next Steps
Authenticate and query the `/api/v1/audits` endpoint for programmatic export.
Grant the **Audits — read** permission to roles that need audit visibility.
Configure custom roles with scoped audit permissions for on-call leads, compliance officers, and other audiences.
***
## Related Pages
Broader tenant hardening — SSO, RBAC, API hygiene, session controls, and integration hygiene.
Route incident, alert, workflow, and status-page events out to any HTTP endpoint — the outgoing counterpart to audit visibility.
The umbrella page covering incident properties, fields, and configuration surface.
# Built-In Fields
Source: https://docs.rootly.com/configuration/built-in-fields
The pre-configured incident properties Rootly ships with — Severity, Environments, Services, Teams, Incident Types — and how to enable or rename them.
## Overview
**Built-in fields** are the pre-configured incident properties Rootly ships with — Severity, Environments, Services, Teams, Incident Types, Incident Causes, Functionalities, and a handful of behavioral toggles like `Backfill Incident` and `Mark as Triage`. Every built-in field is designed to capture a common piece of incident metadata that drives workflows, metrics, and status page updates.
You can turn built-in fields on or off, rename them (Severity → "Priority", if that matches your team's vocabulary), and — for many of them — change their behavior (single-select vs multi-select, default values, whether they appear on the incident details page). What you **can't** do is add net-new dimensions to the built-in schema; for that, use [Custom Fields](/configuration/custom-fields).
Access built-in fields in **Configuration → Fields → Built-In Fields**.
**Built-in vs Custom:** Built-in fields are baked into Rootly and integrate with everything (workflows, metrics, retrospectives, status pages) automatically. [Custom Fields](/configuration/custom-fields) are extensions you define — they're just as usable in workflows, but their integration surface is what you wire up yourself. Reach for a built-in field first; drop to a custom field only when the built-in schema doesn't cover what you need.
***
## Built-In Fields Reference
| Field | Type | Purpose | Configurable |
| ----------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
| **[Severity](/configuration/severities)** | Select | How bad the incident is (SEV0–SEV3) | Values, colors, Slack channels, aliases, notify emails |
| **[Environments](/configuration/environments)** | Select or Multi-Select | Which deployment tier is affected (Production, Staging, Dev) | Values, colors, field type (select/multi), attached channels/aliases/emails |
| **[Incident Types](/configuration/incident-types)** | Select or Multi-Select | Category of incident (UI Bug, Infrastructure, Security Event, etc.) | Values, colors, field type (select/multi), attached channels/aliases/emails |
| **[Incident Causes](/configuration/incident-causes)** | Multi-Select | Root causes captured during retrospective | Values, colors |
| **[Services](/configuration/services)** | Select or Multi-Select | Infrastructure components impacted | Values, colors, ownership, field type (select/multi) |
| **[Functionalities](/configuration/functionalities)** | Select or Multi-Select | Product capabilities impacted | Values, colors, field type (select/multi) |
| **[Teams](/configuration/teams)** | Select or Multi-Select | Team ownership and routing | Values, membership, field type (select/multi) |
| **Summary** | Text | Human-readable incident description | Enabled / disabled |
| **Status Page Title** | Text | The incident title as it appears on status pages | Enabled / disabled |
| **Notify Emails** | Multi-Select (emails) | Per-incident additional email recipients | Enabled / disabled |
| **Mark as Triage** | Checkbox | Whether to open the incident in Triage status | Enabled / disabled, default value |
| **Backfill Incident** | Checkbox | Retroactively documenting an already-resolved incident | Enabled / disabled, default value |
| **Private** | Checkbox | Restrict incident visibility (see [Private Incidents](/incidents/private-incidents/private-incidents)) | Enabled / disabled, default value |
| **Not a real emergency** | Checkbox | Marks as test/training without changing Kind | Enabled / disabled, default value |
This reference list captures the most common built-in fields. Your Rootly workspace may show additional fields depending on which integrations are enabled — for example, PagerDuty and Opsgenie integrations expose their own built-in fields for cross-referenced IDs.
***
## Managing Built-In Fields
Navigate to **Configuration → Fields → Built-In Fields** to see the full list. Every built-in field has an enable/disable toggle and — for most fields — an edit pane where you can rename, change the field type, set defaults, and control display behavior.
### Enable Or Disable A Field
Only enabled fields are live — they appear on incident forms, on the incident details page, and can be updated by workflows. Disabled fields are hidden from users and unavailable to workflow actions.
Use the toggle next to the field name in the list view.
Disabling a built-in field that's already referenced by workflows or Liquid templates doesn't remove those references — they just start failing silently. Before disabling a heavily-used field, audit your workflows and templates for references to it.
### Edit A Field's Configuration
Click the edit icon on the right side of any field row to open the Edit Form Field pane.
The edit pane exposes the settings below. Not all settings apply to every field — a checkbox field like `Backfill Incident` has no `Field Type` setting because it's inherently a boolean.
Unique identifier generated at field creation. **Not customizable.** Used in API calls and Liquid references.
Display label shown on incident forms and the incident details page. Renaming affects the **UI only** — Liquid references and API paths remain unchanged.
For example, renaming `Severity` to `Priority` in the UI still leaves the Liquid reference as `{{ incident.severity }}`, not `{{ incident.priority }}`.
For fields that support both modes — Environments, Incident Types, Services, Functionalities, and Teams — you can choose whether responders pick one or many values. Severity is always single-select; Incident Causes is always multi-select; checkbox and text fields don't expose this setting.
Changing the field type is one-way in practice — moving from multi-select to select truncates existing multi-value incidents to their first value.
Default value that pre-populates on new incident forms. Common uses: default Severity to `SEV3`, default Environment to `Production`, default `Mark as Triage` to `true` for a triage-first workflow.
Defaults only apply to new incidents — changing a default doesn't retroactively update existing incidents.
When enabled, the field is live on the incident form, in workflows, and on the incident details page. Disabled fields are hidden from users and inaccessible to workflow actions.
This is the same toggle as the enable/disable switch in the list view.
Controls whether the field appears in the **Details** section of the incident details page. Hiding does **not** disable the field — workflows can still read and write it. Users may still be able to edit the field from other surfaces (creation forms, update forms) unless you also hide or restrict it there.
Common use: a "system-managed" flag that workflows set automatically and shouldn't clutter the Details view. To make it fully non-editable to humans, also remove it from the relevant [Incident Forms](/configuration/built-in-forms) or restrict form access.
***
## Common Configuration Patterns
If your team uses "Priority" or "Impact Level" instead of "Severity", edit the built-in Severity field and change the Name. The values (SEV0–SEV3, or your custom Severity names) stay the same, but the field label changes across every incident form.
Remember: renaming the field name does NOT change the Liquid reference. `{{ incident.severity }}` still works; `{{ incident.priority }}` does not.
If most of your incidents are Production incidents, set the Environment field's default value to Production. Responders only need to change it for the exceptional cases (Staging, Dev). This is one of the fastest ways to reduce the number of unspecified-Environment incidents.
Not every built-in field is relevant to every team. If your team doesn't use Functionalities (because you don't yet have them defined) or Notify Emails (because everything routes through Slack), disable those fields. Fewer fields on the incident form means faster triage and lower cognitive load for responders.
Audit workflow references before disabling, per the warning above.
Some teams use a built-in field as a workflow-controlled system flag — for example, an internal "escalated to exec team" boolean that gets set by a workflow when specific conditions are met. Disable "Display This Field in the Incident Details" to remove it from the Details section. To keep it out of human hands entirely, also remove it from the creation and update [Incident Forms](/configuration/built-in-forms).
Teams sometimes start with multi-select Incident Types and later realize they always want exactly one Type per incident. Switching to Select is a one-way change: existing multi-value incidents get truncated to their first value. Confirm you're ready for the truncation, or bulk-update multi-value incidents to a single Type before switching.
***
## Best Practices
* **Reach for built-in fields first; use custom fields only when built-ins don't cover the case.** Built-in fields have first-class integration with workflows, metrics, retrospectives, and status pages. Custom fields work everywhere too, but you're building the integrations yourself.
* **Rename cautiously.** Renaming a field changes what responders see but not what workflows and Liquid templates reference. If you're changing the display name of a heavily-referenced field, audit the templates that use its old name in prose (not the Liquid reference itself) so they don't drift.
* **Default the fields that are usually the same value.** Environment (usually Production), Severity (usually SEV2 or SEV3 as a default before triage), and Mark as Triage (true if your team starts every incident in Triage) are all good candidates. Defaults reduce keystrokes; unspecified-value incidents route to the wrong workflows.
* **Audit disabled fields quarterly.** Fields that were disabled six months ago and haven't been re-enabled probably aren't coming back. Consider whether the workflow references pointing at them are still needed.
* **Prefer built-in Field Type changes over custom-field replacements.** If a built-in field can be reconfigured (for example, Environment from multi to single), that's simpler than disabling the built-in and creating a custom field to replace it. Every workflow and template that references the built-in continues to work.
***
## Troubleshooting
Check that the field is enabled in Configuration → Fields → Built-In Fields. Also verify the field is enabled on the specific incident form you're using — form-level field configuration can override the built-in-field-level enable state.
Renaming a built-in field affects **only the UI label**, not the Liquid reference. If your template broke after a rename, something else changed — check the actual Liquid syntax against the field's reference (see the individual field docs like [Severity](/configuration/severities) or [Environments](/configuration/environments) for exact syntax).
Working as designed. When you switch a multi-value field to single-select, existing incidents with multiple values keep only their first value. This is not reversible — the additional values are removed at conversion time.
If you need to preserve historical multi-value data, export incident data before switching. Alternatively, bulk-update multi-value incidents to a single canonical value before making the field type change.
Disabling a built-in field doesn't remove workflow references — those references just start failing silently or with runtime errors when the workflow tries to read or write the disabled field.
Re-enable the field, or audit and update the referencing workflows in **Configuration → Workflows** — use the search box to filter by the field's slug or Liquid variable name.
Confirm the default is set on the built-in field configuration (not just the form-level configuration — those are separate). If it's set at the field level and still not applying, check for a workflow that runs on Incident Created and overwrites the default value.
***
## Frequently Asked Questions
**Built-in fields** are pre-configured properties Rootly ships with — Severity, Environments, Services, Teams, Incident Types, and similar. They have first-class integration with workflows, metrics, retrospectives, and status pages.
**[Custom Fields](/configuration/custom-fields)** are extensions you define — same usability in workflows, but you wire up the integrations yourself. Use built-ins for common dimensions (impact, tier, category); use custom fields for organization-specific dimensions the built-in schema doesn't cover.
No. The built-in field set is defined by Rootly. If you need a new dimension, use a [Custom Field](/configuration/custom-fields). Custom fields work in workflows and Liquid templates the same way built-in fields do — the main difference is you configure the integration behavior yourself.
No — built-in fields can be disabled but not deleted. This preserves the field's data on historical incidents. If you don't want a field surfaced anywhere in the UI, disable it and hide it from incident details.
No. API paths and Liquid references are based on the field's stable slug (assigned at creation), not the display name. Renaming Severity to Priority in the UI doesn't change `/incidents/{id}/severity` in the API or `{{ incident.severity }}` in Liquid.
Configurable field type: Environments, Incident Types, Services, Teams, Functionalities. Fixed: Severity is always single-select; Incident Causes is always multi-select; checkbox fields (Backfill Incident, Mark as Triage, Private) are always booleans.
Yes, via form-level configuration. Each incident-creation form can have its own default values that override the field-level defaults. This lets a Frontend team default Environment to `Web`, while an Infra team defaults it to `Production` — with the same underlying built-in field.
Workflows that reference the disabled field will fail or silently no-op at runtime. Rootly does not automatically detect and update dependent workflows. Audit workflow references before disabling any heavily-used built-in field.
***
## Related Pages
Add fields the built-in schema doesn't cover. Both built-in and custom fields work in the same workflows and templates.
Filter workflow runs on built-in field values — the interactive evaluator lets you test conditions against a sample incident.
The umbrella page linking every incident property doc, including all built-in fields covered here.
# Default Forms
Source: https://docs.rootly.com/configuration/built-in-forms
Configure Rootly's built-in forms that guide users through incident creation, updates, resolution, maintenance, and post-incident processes.
## **Overview**
Rootly comes with a set of essential, built-in forms that cannot be deleted. The forms each cover a different stage of an incident and scheduled maintenance lifecycle.
You can access the built-in forms by navigating to **Configuration > Forms**.
## Form Types
The New Incident form is displayed whenever the user first declares an incident on Slack (via `/rootly new` command) or on the Rootly web UI (via `Create Incident` button).
The Update Incident form is displayed whenever the user attempts to update an incident on Slack (via `/rootly update` command or `Update` button) or on the Rootly web UI (via `Edit` button).
The Incident Mitigation form is displayed whenever the user attempts to mitigate an incident on Slack (via `/rootly mitigate` command) or on the Rootly web UI (via `Mitigate` button).
The Incident Resolution form is displayed whenever the user attempts to resolve an incident on Slack (via `/rootly resolve` command) or on the Rootly web UI (via `Resolve` button).
The Incident Cancellation form is displayed whenever the user attempts to cancel an incident on Slack (via `/rootly cancel` command) or on the Rootly web UI (via `Cancel` button).
The Incident Retrospective Form is displayed after the incident is resolved and the user enters the **Gather & Confirm Data** step of the retrospective. This form is only accessible from the Rootly web UI.
The New Maintenance Incident form is displayed whenever the user first declares a scheduled maintenance on Slack (via `/rootly maintenance` command) or on the Rootly web UI (via `Schedule Maintenance` button).
The Update Maintenance Incident form is displayed whenever the user attempts to update a scheduled maintenance on Slack (via `/rootly update` command or Update button) or on the Rootly web UI (via `Edit` button).
The Incident Follow Up form is displayed whenever the user adds or edits a follow-up on an incident, on Slack (via `/rootly followup` or the action items dialog) or on the Rootly web UI (via the **Follow-ups** tab). The follow-up's standard fields (title, description, assignee, priority, status, due date) are always part of the form; the fields you can add and configure on it are **custom fields** — see [Custom Fields on Action Items](/incidents/action-items/action-item-custom-fields).
The Incident Task form is displayed whenever the user adds or edits a task on an incident, on Slack (via `/rootly task` or `/rootly add action item`) or on the Rootly web UI. Like the Incident Follow Up form, its standard fields are always present and the fields you can add and configure on it are **custom fields** — see [Custom Fields on Action Items](/incidents/action-items/action-item-custom-fields). The Task and Follow Up forms are independent, so a field placed on one isn't added to the other. Both forms appear once custom fields for action items are enabled for your organization.
You'll notice that the trigger points for scheduled maintenance are exactly the same as for incidents. Rootly will be able to recognize the context and display the appropriate form. For example, when `/rootly update` is run,
* If it was run **in an incident channel**, then **Update Incident** form will be displayed
* If it was run in a **maintenance channel**, then the **Update Maintenance Incident** form will be displayed
## Sub-Status Forms
If your Rootly instance has access to **Rootly's Custom Lifecycle feature**, which allows you to customize your incident statuses, Rootly will generate default forms for each of your incident substatuses.
This allows you to fully customize the information your responders provide throughout the incident's lifecycle, attuned to your business processes.
You'll find these forms under the **Sub-Status Forms** tab.
Get started with Rootly's custom lifecycle feature by reaching out to your account representative.
## **Edit Form**
To begin editing a form, select the Configure button under the form you'd like to edit.
You'll be navigated to the edit form page of the selected form. The **left side of the page is the edit pane** where you can edit what fields are displayed and how they are displayed. The **right side of the page is the preview** of the form.
You can create separate versions of the form for Slack and Rootly Web/Mobile by toggling between the tabs on the left hand side. To ensure incident data is captured consistently, Rootly recommends keeping the fields for each channel in sync.
## Adding Fields to a Form
Add new fields to your form by selecting the **Add Fields** button. Select all of the fields you'd like to add to the form, then **Add Fields**.
Once these fields are added to your form, you can drag and drop them to reorder the form. Remove a field by selecting the **minus** button on the right hand side of the field.
## Editing Fields on a Form
Once a field is added to a form, you can edit how and when the field is filled out. Select the edit button on the field you want to make changes to.
### Conditionally Display and Require a Field
Once a field is added to a form, you can control when the field is displayed and if it is required. Select the edit button on the field that you want to make changes to.
If you only want the field to display under certain conditions or be required under certain conditions, select the **Conditionally** option under **Display this field** or **Require this field**.
Form fields can be displayed or required conditionally depending on the value of any field set above the field that you're editing. For example, if the first field on your form called "Teams" is set to a certain value, your second field can be conditionally displayed depending on the team's value.
### Read-Only Fields
A field can be set to 'read-only', which means that the value cannot be overwritten by your users. This is particularly useful when you want to set a field value on an incident, but do not want it to be manually set by your team.
When this setting is turned on, the field value will always be set to the default value. You cannot turn this setting on unless the field has a default value: this can be edited in the Fields section of the dashboard.
This setting only impacts the Form experience. Field values can still be overwritten in the Rootly Web UI on the Incident's details page.
## Preview
The preview on the right-hand side is interactive and generated in real-time. This is a great way to test out the user experience of your form, and ensure behavior of each field is correct.
***
## Related Pages
Author additional forms beyond the built-in set — surfaced via buttons and Slack modals.
The umbrella concept covering built-in, custom, and dynamic forms alongside custom fields.
Form variants that adapt based on incident type, team, or severity.
# Incident properties and configuration overview
Source: https://docs.rootly.com/configuration/configuration
Configure incident properties, custom fields, and settings to characterize incidents, trigger workflows, and filter metrics across your organization.
## Overview
Every incident created in Rootly is characterized by a structured set of **properties**. These properties define how an incident behaves, how it progresses through its lifecycle, how it interacts with workflows and automation, and how it appears in reporting and analytics.
Incident properties serve several critical purposes:
* Help characterize each incident (for example, `kind = normal`)
* Trigger workflow automations (for example, Status Updated)
* Define conditional logic for workflow execution (for example, Severity is SEV0)
* Enable filtering and segmentation of metrics
* Allow structured access through **Liquid syntax**
Properties fall into three primary categories:
* **Fixed Properties** — system-defined and not customizable
* **Configurable Properties** — built-in but organization-customizable
* **Custom Fields** — fully defined and managed by your organization
***
## Fixed Properties
Fixed properties are intentionally restricted to maintain lifecycle integrity, automation consistency, and reporting standardization across the Rootly platform.
Fixed properties cannot be modified or deleted. They define the foundational lifecycle and structural behavior of every incident.
***
## Incident Kind
The **Kind** property determines the classification and structural behavior of an incident at creation time — whether it's a real production incident, a test, a backfill, or a scheduled maintenance window. Kind is immutable after declaration and governs workflow execution, status page eligibility, and metrics inclusion.
For the full kind reference (all seven kinds, behavior matrix, choosing the right kind, and Kind-related troubleshooting), see **[Incident Kind](/configuration/incident-kind)**.
***
## Incident Status
The **Status** property defines the lifecycle stage of an incident — from Triage through Started, Mitigated, Resolved, Closed, or Cancelled. Status transitions are validated to preserve chronological and logical integrity. Scheduled Maintenance incidents follow a separate lifecycle (Scheduled / In Progress / Completed) with its own rules.
For the full status reference (transition rules, timestamp validation, sub-statuses, the Scheduled Maintenance lifecycle, and Status-related troubleshooting), see **[Incident Status](/configuration/incident-status)**.
***
## Configurable Properties
Configurable properties are built-in fields that organizations can customize to reflect their operational structure, severity model, and reporting taxonomy.
| Property | Description |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Environments](/configuration/environments) | Characterizes incidents by environment (for example, Development, Staging, Production). Commonly used to prioritize production-impacting incidents and to filter metrics and workflow conditions. |
| [Severities](/configuration/severities) | Defines impact levels (for example, SEV0–SEV3). Drives escalation logic, workflow triggers, and reporting analysis. |
| [Incident Types](/configuration/incident-types) | Custom categorization distinct from Kind. Allows organizations to define taxonomy such as UI Bug, Infrastructure Failure, Security Event, etc. |
| [Incident Roles](/configuration/incident-roles) | Defines structured responder roles (Incident Commander, Communications Lead, etc.) to coordinate responsibilities during response. |
| [Teams](/configuration/teams) | Assigns ownership and organizational routing responsibility to teams or groups. |
| [Services](/configuration/services) | Identifies impacted infrastructure components. Used for service-level reporting and status page communication. |
| [Functionalities](/configuration/functionalities) | Identifies impacted product capabilities (for example, login, checkout). Enables feature-level transparency. |
| [Incident Causes](/configuration/incident-causes) | Categorizes root causes to support retrospective analysis and long-term reliability improvements. |
***
## Property Order
The ordering of values within configurable properties determines how they appear in dropdown menus and forms.
Ordering is **global** and affects all users.
You can:
* Drag and drop values manually
* Sort values alphabetically
***
## Custom Fields
When built-in properties are insufficient to meet your organization’s needs, you can create **Custom Fields** to extend the incident schema.
Custom Fields allow you to:
* Capture structured or unstructured metadata
* Apply validation and defaults
* Power advanced workflow automation
* Reference values using Liquid syntax
* Enforce organization-specific incident taxonomy
For full configuration details, see the [Custom Fields](/configuration/custom-fields) documentation.
***
## Frequently Asked Questions
No. Fixed properties (**Kind** and **Status**) are system-defined and cannot be modified, deleted, or customized. They exist to ensure consistency across the platform and maintain the integrity of workflow automation and reporting.
If you need different categorization options, use **Configurable Properties** (like Incident Types) or **Custom Fields**, which can be fully customized to meet your organization's needs.
Yes. Custom fields can be referenced in workflow run conditions and Liquid templates, allowing you to create sophisticated automation based on organization-specific data.
Custom fields are accessible via Liquid syntax:
```liquid theme={null}
{{ incident.custom_fields | find: 'custom_field.slug', 'your-field-slug' | get: 'value' }}
```
This enables workflows to react to custom field values, trigger actions based on custom data, and include custom field information in notifications and integrations.
Property ordering is **global**, meaning changes affect all users immediately. When you reorder values (for example, Severities or Environments), the new order appears in:
* Dropdown menus when creating or editing incidents
* Form fields across the platform
* Any interface where that property is displayed
You can reorder manually via drag-and-drop or sort alphabetically.
***
**Need help or have a question?**
Contact us anytime at **[support@rootly.com](mailto:support@rootly.com)**, use the `/rootly support` Slack command, or visit **Getting Help** to start a chat.
***
## Related Pages
The fixed set of incident properties Rootly ships with — severity, environment, service, team.
Fully customizable fields for organization-specific incident metadata.
How incident forms are configured, including built-in, custom, and dynamic form variants.
# Creating a Status Page
Source: https://docs.rootly.com/configuration/creating-a-status-page
Set up and customize public status pages in Rootly to communicate service health, incident updates, and scheduled maintenance to your customers.
Creating a status page only takes about a minute. Before you do so, Rootly recommends you have at least one [service](/configuration/services) configured in Rootly that you can display on your status page. You can do this by visiting **Configuration > Services** or if you have the [PagerDuty integration](/integrations/pagerduty/pagerduty) configured, you can easily import services directly from PagerDuty then add them to your status page.
To create a new status page:
In the Rootly navigation bar, click on **Configuration**, then **Status Pages**.
Click **Add New Status Page**.
Give your status page a name and description. These are internal to Rootly, and will not be used on the actual Status Page.
## **Customize Your Status Page**
Once you've created your status page, you're able to customize the look and feel of the page to tailor the contents to your end users.
## **Setup**
Under setup, you're able to make changes to the name and description of your status page. Remember: these are internal only so should be descriptive for other Rootly admins to know what the status page is.
Here, you can also determine if the page will be private or publicly available. Learn more about [public and private status pages](/configuration/status-pages#public-or-private).
In the Advanced Settings, you can also customize the domain name of the status page. By default, Rootly will assign each Status Page a URL in the following format:
`rootly.com/teams/[your-org-name]/status-pages/[status-page-name]/[public/private]`
Configure your own custom domain by following: [Custom Domain Names for Status Pages](/configuration/custom-domain-names-for-status-pages). Note: for custom external domain names, you may need to talk with the team at your organization to have them help you configure a custom domain name and associated DNS.
## **Customize**
Customize the default content and look-and-feel of your status page in the Customize tab. As you make changes to the settings in this tab, the right-hand preview of your status page will reflect your latest updates.
## **Components**
Use the Components section to choose what appears under the 'System Status' section of your page. You can add three kinds of components:
* **Services** — any Rootly [service](/configuration/services).
* **Functionalities** — a [functionality](/configuration/functionalities) represents a higher-level, customer-facing capability (like "Login" or "Checkout") that can be backed by many underlying services. Add a functionality when you want to show a single customer-facing component instead of a long list of internal services.
* **Third party services** — any external service your organization depends on.
Functionalities are useful when you maintain a large number of services but only want to expose a small set of product components publicly. Map your services to a functionality on the [functionality](/configuration/functionalities) itself, then add only that functionality to the page.
A component is shown as impacted under 'System Status' when an incident that is published to this status page is associated with that component. For a functionality, that means the incident is tagged with the functionality (or the component is selected when publishing the status page update). Associating a service with a functionality does not by itself change the functionality's status. The status is always driven by the incident.
If you don't see Functionalities as a component option, reach out to [support](mailto:support@rootly.com) to have the Functionalities field enabled for your organization.
To tag functionalities automatically, use a [workflow](/workflows/workflows) that runs on incident create or update, conditions it on the severities and services you care about, and adds the matching functionality with the Update Incident action. Be aware that this action replaces the incident's entire functionality list rather than adding to it, so it also clears any functionalities set earlier by another workflow or by hand. That reaches beyond the status page — a functionality dropped from an incident also stops driving its [ownership, escalation policy, and notification settings](/configuration/functionalities) for that incident. It is only safe when a single workflow run can determine the complete set of functionalities for the incident. If several workflows could tag different components on the same incident, select the affected components manually when you publish the update instead.
You'll be able to add third party services to your status page after you've created the status page.
## **Templates**
Standardize the incident updates your teams share with Status Templates. When a commander publishes an incident update to a status page, they'll be able to use the templates defined in this section to help write their update.
## Go-Live Checklist
Setup spans several pages. Work through this before you point customers at the page.
Public or private — the choice drives everything below it. See [Overview](/configuration/status-pages).
Add the services, functionalities and third party services customers care about, and put them in the order you want them displayed. A page listing every internal service is harder to read than one listing a handful of customer-facing functionalities.
Templates are what a commander reaches for mid-incident. Writing them under pressure is how inconsistent updates happen.
A private page is limited to people logged in to Rootly, and needs nothing further. A public page is reachable by anyone with the URL — if that is too open, add password or SAML [authentication](/configuration/status-page-authentication-methods), which is available on public pages only.
Public pages usually want a [custom domain](/configuration/custom-domain-names-for-status-pages). Both the CNAME and the CAA record are required, and DNS changes take time to propagate — do this before you need it, not during an incident.
Publish a low-severity incident, confirm it renders the way you expect, then resolve it. See [Publishing Incidents](/configuration/publishing-incidents).
If the test incident appears with the right components marked as impacted, the page is ready.
***
## Related Pages
The umbrella concept — what public and private status pages are and when to use each.
Point your own domain at a Rootly status page with CNAME + CAA records.
How incident updates get pushed to a status page from Web or Slack.
# Custom Domain Names for Status Pages
Source: https://docs.rootly.com/configuration/custom-domain-names-for-status-pages
Configure custom domain names for your public status pages to maintain brand consistency and provide a seamless customer experience.
## Overview
You can attach one or multiple custom domain names such as status.acme.me using the custom domain names input. This allows you to brand your status page with your own domain while maintaining all the functionality of Rootly's status page system.
**Note**: External domain names are only configurable for public status pages. Private status pages cannot use custom domain names and will only be accessible through the default Rootly URL.
## Prerequisites
Before setting up a custom domain, ensure you have:
* Administrative access to your domain's DNS settings
* A public status page configured in Rootly (private pages are not supported)
* Access to your DNS provider's management interface
## Getting Your CNAME Target
Once you save your page, you can obtain the CNAME target by clicking on the link for the status page you want to configure.
The CNAME is shown at the bottom of the screen on the right side.
It provides the **Domain** you entered along with the **Value** needed for your DNS records.
## How Custom Domains Work
1. You set up the CNAME record in your DNS provider with:
* **Domain**: test.statuspage.net
* **Value**: (rootly-provided-value).external-sp.rootly.com
2. When someone visits test.statuspage.net:
* The DNS system looks up the CNAME record and directs the request to (rootly-provided-value).external-sp.rootly.com.
3. Rootly serves the corresponding status page associated with the unique identifier in the CNAME.
## DNS Configuration Steps
Set up the CNAME record in your DNS provider with the values obtained from Rootly:
* **Domain**: Your custom domain (for example, status.your-domain.com)
* **Value**: The Rootly-provided CNAME target (for example, unique-id.external-sp.rootly.com)
You must add a CAA (Certificate Authority Authorization) record to your DNS configuration for SSL certificate validation to work properly.
Add a CAA record to your **parent domain** (not the subdomain) with the following format:
```text theme={null}
0 issue "pki.goog; cansignhttpexchanges=yes"
```
For example, if your custom domain is `status.your-domain.com`, add the CAA record to `your-domain.com`.
**Important**: Place the CAA record on the parent domain because domains with CNAME records cannot have other record types. The Certificate Authority will check for CAA records starting from the subdomain and work up to the parent domain, stopping at the first CAA record it finds.
Test your CAA record configuration using the `dig` command:
```bash theme={null}
dig +short CAA your-domain.com
```
This CAA record authorizes Google's PKI to issue certificates for your domain and enables HTTP Exchange signing, which can improve performance for your status page.
After setting up both records, verify your configuration:
* **Test CNAME resolution**:
```bash theme={null}
dig +short CNAME status.your-domain.com
```
* **Check SSL certificate**:
```bash theme={null}
curl -I https://status.your-domain.com
```
* **Verify page accessibility**: Visit your custom domain in a browser.
## Provider-Specific Configuration Guides
To configure the DNS records, you will need to either work with your company's DNS administrator or configure it yourself if you have access.
Since configuring DNS varies by provider, here are guides for the most common services:
* [Amazon Web Services Route 53](https://aws.amazon.com/premiumsupport/knowledge-center/route-53-create-alias-records/ "Amazon Web Services Route 53")
* [Azure DNS](https://docs.microsoft.com/en-us/azure/dns/dns-web-sites-custom-domain "Azure DNS")
* [Google Cloud Identity](https://cloud.google.com/identity/docs/add-cname "Google Cloud Identity")
* [GoDaddy Domains DNS](https://www.godaddy.com/help/add-a-cname-record-19236 "GoDaddy Domains DNS")
## Troubleshooting
### Common Issues
#### Domain Not Resolving
* Verify CNAME record is correctly configured
* Check DNS propagation (can take up to 48 hours)
* Ensure there are no conflicting A records
* Remember: domains with CNAME records cannot have other record types on the same subdomain
#### SSL Certificate Errors
* Confirm CAA record is properly set on the parent domain (not subdomain)
* Wait for certificate provisioning (can take up to 24 hours)
* Verify the CAA record uses the correct format: `0 issue "pki.goog; cansignhttpexchanges=yes"`
* Check that the CAA record is placed on the parent domain, not the subdomain with the CNAME
#### Page Shows "Not Found" Error
* Double-check the CNAME target value from Rootly
* Ensure the status page is set to public
* Verify the custom domain is correctly entered in Rootly
### DNS Propagation Check
Use these tools to check DNS propagation across different regions:
* [What's My DNS](https://www.whatsmydns.net/)
* [DNS Checker](https://dnschecker.org/)
### Getting Help
If you continue experiencing issues:
1. Check the Rootly status page configuration
2. Verify DNS records with your provider
3. Contact Rootly support with your domain and error details
***
## Related Pages
Set up the status page you'll point your custom domain at.
Password or SAML auth for public status pages behind your custom domain.
The umbrella concept — public vs private status pages.
# Custom incident fields configuration
Source: https://docs.rootly.com/configuration/custom-fields
Create organization-specific incident fields with custom data types, validation rules, and integration mappings to meet unique incident management requirements.
## Overview
Rootly carefully selected the built-in properties based on common attributes used to characterize incidents. However, not all organizations are built the same and sometimes the built-in properties are not enough to meet everyone's requirements.
To enable a fully bespoke experience, Rootly introduced custom properties that can be set up to meet the exact specifications of your organization's incident management requirements.
Custom fields aren't limited to incidents — the same fields can be placed on your action item forms (Incident Task and Incident Follow Up) to capture metadata on tasks and post-incident work. See [Custom Fields on Action Items](/incidents/action-items/action-item-custom-fields).
## Managing Custom Fields
### Create Field
Select the Create New Form Field button to create a new custom field. The following details can be edited on a field:
This is a unique identifier for the form field. It is automatically generated for you upon field creation and cannot be edited. This ID will be used to reference the specific form field in API calls and Liquid syntax.
This field can be edited. The value entered here will be the value that appears on user-facing forms.
Renaming a custom field will change the slug of the field, which in turn **WILL** break any Liquid references that use the previous slug. This is because, unlike built-in fields, a custom field's slug is mutable. Each time the field is renamed, its slug is regenerated from the new name, lower-cased and hyphenated. \
\
Existing references that use the custom field's ID instead of its slug will not be affected.
`{{ incident.custom_fields | find: 'custom_field.slug', 'your-custom-field-slug' | get: 'value' }}`
This field can be used to display a description for the custom field. This is particularly helpful if you want to give your users some instruction on how to fill in the custom field.
This field allows you to select the field type, which will dictate how the user interacts with this field. For example, a checkbox type will be a boolean field while a select type will ask the user to select one out of many options.
For more details on the available field types, please scroll down to the [Supported Field Types](/configuration/custom-fields) section.
This field allows you to define selectable options for Select and Multiple Select field types when the 'Custom text' field value is selected.
1. Enter the **value of the option.**
2. Select the **color of the option.** This is reflected on metrics graphs.
3. Drag and drop to **re-order the options** as they appear in dropdowns.
4. **Delete** an option.
5. **Copy** the `form_field_option_id`. This is used in API calls and Liquid syntax.
6. **Add** more options.
Custom fields can be configured to have a default value. For example, if you want all your incidents to default to Zone 1 for the Zone custom field, then you can set it here.
This is the same setting as the toggle described in the **Enable/Disable Field** section above.
Only enabled fields are considered to be live fields - meaning they can appear on UI screens and be updated during incidents. Disabled fields are NOT usable during incidents and cannot be updated by workflows either.
You can use the toggle switch next to the field name to enable/disable it.
This switch allows you to display or hide the specific field on the **Details** section of the **Incident Details** page.
**Hiding a field** from being displayed in the **Details** section **does not mean this field is turned off**. It just means users cannot edit it from the UI.
This is typically used when teams want to configure a custom flag that gets systematically set by workflows, not manually by users.
This field allows you to select the value type for select and multiple select fields. The following Value types are available: Custom text, Teams, Services, Users, Functionalities, and Catalog.
* **Custom text** allows user input to determine what values are available for selection.
* **Teams, Services, Users, Functionalities, or Catalog** allow the custom field to pull from one of the existing fields populated in Rootly.
For example, an organization may want to identify both an 'Owning Team' as well as a set of 'Impacted Teams.' A new custom field could be created for 'Impacted Teams' and the existing 'Teams' field could be renamed to 'Owning Team.'
### Delete Field
Custom fields can be deleted by clicking the trash symbol.
Deleted fields cannot be recovered. It is highly recommended that you disable unused custom fields instead of deleting them.
Deletion should be reserved for only when you're sure that it won't be used in the response process anymore.
Custom fields can be referenced in Liquid using either the field **slug** or **ID**.\
The `find` filter returns a custom field object, from which you can access different attributes depending on the field type and configured Value Type.
***
## Supported Field Types
Below are all supported custom field types and the recommended Liquid syntax for each.
### Text
A single-line free-form text field that allows users to enter short text values such as names, identifiers, or brief descriptions. This field type is ideal for capturing simple, unstructured text data.
This Liquid syntax retrieves the text value stored in the custom field:
```liquid theme={null}
# By SLUG
{{ incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value'
}}
# By ID
{{ incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value'
}}
```
### Textarea
A multi-line free-form text field that allows users to enter longer text content such as detailed descriptions, notes, or comments. Unlike the Text field, Textarea supports multiple lines of text input.
This Liquid syntax retrieves the multi-line text value stored in the custom field:
```liquid theme={null}
# By SLUG
{{ incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value'
}}
# By ID
{{ incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value'
}}
```
### Rich Text
A formatted text field that supports rich text formatting (bold, italic, lists, links, etc.) using HTML markup. This field type is stored as an HTML string and is ideal for formatted content that needs to preserve styling.
This Liquid syntax retrieves the HTML-formatted text value stored in the custom field:
```liquid theme={null}
# By SLUG
{{ incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value'
}}
# By ID
{{ incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value'
}}
```
Rich text values may contain HTML markup. Be mindful when rendering these values in notifications or external systems.
### Tags
**Tags is no longer available in the field type dropdown when you create a custom field in the UI.** To create a Tags field, use the API: send a `POST` to `/api/v1/form_fields` with `"input_kind": "tags"` (see the [form field API reference](/api-reference/formfields/creates-a-form-field)). To stay in the UI, create a **Multiple Select** field instead — you define the allowed options upfront, so it suits a known set of values rather than free-form tags. Existing Tags fields keep working and use the Liquid syntax below.
A multi-value tag field that allows users to add multiple tags or labels to an incident. Tags are stored as a JSON array string, making them useful for categorization, filtering, or labeling incidents with multiple attributes.
This Liquid syntax retrieves the JSON array string containing all tags:
```liquid theme={null}
# By SLUG
{{ incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value'
}}
# By ID
{{ incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value'
}}
```
Tags values are stored as a JSON array string (for example, `["tag1", "tag2", "tag3"]`). You may need to parse this JSON string depending on your use case.
### Number
A numeric input field that enforces numeric values only. This field type is useful for capturing quantities, counts, percentages, or any numeric data. The value is stored as a string representation of the number.
This Liquid syntax retrieves the numeric value stored in the custom field:
```liquid theme={null}
# By SLUG
{{ incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value'
}}
# By ID
{{ incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value'
}}
```
Number values may be stored as strings. Use Liquid math filters if numeric operations are required.
### Checkbox
A boolean field that stores a checked ("1") or unchecked ("0") state. This field type is ideal for yes/no questions, flags, or binary choices that need to be tracked.
This Liquid syntax retrieves the checkbox value and checks whether it's checked:
```liquid theme={null}
# By SLUG
{% assign v = incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value' %}
# By ID
{% assign v = incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value' %}
{% if v == "1" %}
true
{% else %}
false
{% endif %}
```
### Date
A date picker field that allows users to select a specific date. The value is stored as an ISO date string, making it easy to format and use in date calculations or comparisons.
This Liquid syntax retrieves the date value stored in the custom field:
```liquid theme={null}
# By SLUG
{{ incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value'
}}
# By ID
{{ incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value'
}}
```
This Liquid syntax formats the date value for display:
```liquid theme={null}
# By SLUG
{{ incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value'
| date: '%B %d, %Y'
}}
# By ID
{{ incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value'
| date: '%B %d, %Y'
}}
```
### Datetime
A date and time picker field that allows users to select both a date and a specific time. The value is stored as an ISO datetime string, making it suitable for scheduling, timestamps, or any scenario requiring precise date and time tracking.
This Liquid syntax retrieves the datetime value stored in the custom field:
```liquid theme={null}
# By SLUG
{{ incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value'
}}
# By ID
{{ incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value'
}}
```
This Liquid syntax formats the datetime value for display:
```liquid theme={null}
# By SLUG
{{ incident.custom_fields
| find: 'custom_field.slug', 'your-custom-field-slug'
| get: 'value'
| date: '%B %d, %Y at %I:%M %p'
}}
# By ID
{{ incident.custom_fields
| find: 'custom_field.id', 'your-field-uuid'
| get: 'value'
| date: '%B %d, %Y at %I:%M %p'
}}
```
### Catalog
A Catalog field only accepts the entities configured in the related Catalog. Use this field type when you want to track the impact of an incident against one of your business entities configured as a Catalog, like Teams, Services, or any custom Catalogs.
Catalog Fields can be automatically set based on properties in your Catalog. For example, any `Services` Catalog field could be automatically set by a `Team` Catalog field, as long as the Team Catalog has a Services property. This would allow you to automatically track the Services an incident is impacting as your users add teams to the incident.
### Select
A single-choice field that allows users to select one value from a predefined list of options.
### Multiple Select
A multi-choice field that allows users to select one or more values from a predefined list of options. Storage follows the same pattern as Select, but may contain multiple values. The storage format and available attributes depend on the configured **Value Type**.
## Best Practices
* Prefer referencing custom fields by **ID** in Liquid to avoid breaking changes when field names change.
* Use field **Descriptions** to guide responders toward consistent data entry.
* Hide workflow-managed fields from the Incident Details UI to reduce manual edits.
* Ensure you reference the correct `selected_*` attribute based on the field’s **Value Type**.
***
## Related Pages
The fixed set of Rootly incident properties — the fields you extend with custom ones.
Place custom fields on additional forms beyond the built-in set.
The umbrella page covering incident properties, fields, and configuration surface.
# Custom Forms
Source: https://docs.rootly.com/configuration/custom-forms
Build tailored forms with specific field combinations to collect targeted incident data at different stages of the response lifecycle.
Throughout the lifecycle of an incident, teams might want to prompt responders to input various incident properties outside of the [standard built-in forms](/configuration/built-in-forms). Custom forms enable teams to define their own forms that can be triggered either through a custom Slack command or a button within a custom Slack block.
You can access the custom forms by navigating to **Configuration >** [**Forms**](https://rootly.com/account/forms) and scrolling to the bottom of the page.
## **Example Use Cases**
* **Targeted Data Collection**: Create a form specifically for the Comms Lead, which only displays fields that are important to the leadership (for example, `status`, `summary`, `severity`). This streamlines the communication process by helping teams only focus on the relevant information.
* **Guided Response:** Create various forms that collect specific sets of data at specific points of the incident life cycle. Dynamically display each custom form to guide responders through their response effort.
## **Create Custom Form**
Click on the `Create Form` button to initiate the form creation wizard.
A dialogue will appear requesting the following fields:
Assign the custom form a name.
Define a Slack command that would prompt to open the form in Slack.
The full command you would enter in Slack is `/rootly customform your-custom-slack-command`. You only need to enter the `your-custom-slack-command` portion in this field.
You can provide an optional description for your custom form.
After providing the necessary details, click on `Save`. You’ll be redirected to the following page where you can begin customizing the new form.
## **Edit Custom Form**
To begin editing a form, select the Configure button under the form you'd like to edit.
You'll be navigated to the edit form page of the selected form. The **left side of the page is the edit pane** where you can edit what fields are displayed and how they are displayed. The **right side of the page is the preview** of the form.
You can create separate versions of the form for Slack and Rootly Web/Mobile by toggling between the tabs on the left hand side. To ensure incident data is captured consistently, Rootly recommends keeping the fields for each channel in sync.
## Adding Fields to a Form
Add new fields to your form by selecting the **Add Fields** button. Select all of the fields you'd like to add to the form, then **Add Fields**.
Once these fields are added to your form, you can drag and drop them to reorder the form. Remove a field by selecting the **minus** button on the right hand side of the field.
## Editing Fields on a Form
Once a field is added to a form, you can control when the field is displayed and if it is required. Select the edit button on the field that you want to make changes to.
If you only want the field to display under certain conditions or be required under certain conditions, select the **Conditionally** option under **Display this field** or **Require this field**.
Form fields can be displayed or required conditionally depending on the value of any field set above the field that you're editing. For example, if the first field on your form called "Teams" is set to a certain value, your second field can be conditionally displayed depending on the team's value.
## Preview
The preview on the right-hand side is interactive and generated in real-time. This is a great way to test out the user experience of your form, and ensure behavior of each field is correct.
## Trigger Custom Form
Custom forms can be triggered in various ways: Slack command, custom Slack block, or web UI.
## Prompt Form via Slack Command
A custom form can be prompted in an incident Slack channel via manual command. The command can be found on the edit screen of the specific form.
When you write the command in an incident Slack channel, you'll be prompted with the custom form.
## Prompt Form via Slack Block
A custom form can also be prompted in an incident Slack channel via a button in a custom block.
## Prompt Form via Web UI
Lastly, a custom form can also be prompted from the Rootly web UI. First navigate to a specific incident and then select the Custom Form dropdown at the top. The dropdown will contain all custom forms that have been configured in the organization.
***
## Related Pages
Rootly's ship-with-defaults forms — the baseline custom forms live alongside.
Form variants that adapt based on incident type, team, or severity.
Add organization-specific fields to appear on custom forms.
# Custom Statuses
Source: https://docs.rootly.com/configuration/custom-statuses
Define custom incident lifecycle stages beyond the default Active, Mitigated, and Resolved statuses to match your organization's response processes.
Custom Statuses allow you to fully customize the statuses that represent your incident's lifecycles. By default, Rootly incidents progress through Active > Mitigated > Resolved. However, some organizations have much more granular statuses to represent key moments in the incident's lifecycle.
Custom Statuses allow you to add, reorder, and capture key information on the incident throughout the incident lifecycle.
## Adding and editing statuses
Navigate to **Configuration > Lifecycle** to begin customizing your Rootly statuses.
Each substatus requires a name and description to give your responders context on what the lifecycle stage represents. When an incident's status is updated to reflect a new status, Rootly marks the date and time of the status change and stores it in the status' `Marked At` field to support any postmortem analyses.
When a new status is added, Rootly will generate a new substatus form for you to customize in the Form configuration section. This allows you to capture incident data at any phase of the incident's lifecycle.
## Lifecycle Preferences
Rootly gives you full control over how your incidents progress through the Lifecycle statuses. Control if your responders are able to move an incident across many statuses at once, or if incidents must progress through every status in a defined order.
Navigate to **Configuration > Lifecycle > Preferences** to update these settings.
If your Rootly instance requires incidents to progress through Active or Resolved in order, your responders will only be able to update the incident's status to the next status defined in your Lifecycle configuration.
Responders are able to move an incident backward to any previous status. If they do so, they'll have to progress the incident through each status again.
Get started with Custom Statuses by reaching out to your Rootly account representative today.
***
## Related Pages
Where custom statuses fit in the incident properties model.
The deliberate publish flow for pushing incident updates to a status page.
Retrospectives are created when an incident resolves — pair status design with your retrospective process.
# Dynamic Forms
Source: https://docs.rootly.com/configuration/dynamic-forms
Configure form variations that adapt based on incident properties like type, team, or severity to collect contextually relevant information.
Rootly's dynamic forms allow for more granularity based on different incident types, different teams, or different severities that require different versions of the same forms. You can access the dynamic forms by navigating to **Configuration >** [**Forms**](https://rootly.com/account/forms).
The Dynamic Forms feature is not enabled out of the box, but if you’d like to try it out, reach out to your Rootly point of contact or support team. [Video Example of Use Case](https://www.loom.com/share/11b9503c6bd94043bfafc6cdd5166021?sid=35cd9955-d742-45f3-b99f-b2840b3e0a74)
## Incident Property Field
The incident property is what is used to **base** the dynamic forms from. The options include Incident Type, Team, or Severity.
This field is important — it drives the property you build your dynamic forms from.
Once an incident property is selected, click `+ New Form Set` to create a dynamic form.
## **Creating Form Set**
A unique name for this form set.
The condition that decides when the form set applies — driven off incident type, team, or severity depending on the property you picked above.
Then choose which default forms you would like to customize — only the forms you pick will diverge from the defaults; everything else stays inherited.
### Example Use Case
One of the main use cases for this is when you want to give more granularity on different teams, incident types, or severities, but you want them to have different versions of the same form. For example, when the information I want to collect for the `security teams` incidents is different than the information I want to collect for the `infrastructure teams` incidents. But within that, within the `security teams` forms, I actually want certain fields different based on if it’s a SEV0 incident.
Click 'Create Form Set'. Once created, you'll see the newly built 'Security Team Forms' on the left and the form types you wish to customize. These new forms will only show when `Team` is `Security`.
Next, get more granular and only show these forms when the `Team` is `Security` **AND** the `Severity` is a `SEV0`. To do this, click 'Configure' on the form type you would like to edit.
The form will start empty, minus your incident property field, which in this case is `Teams`.
Add any custom or built-in fields by clicking 'Add Fields'. When the required fields are selected, click 'Add Fields'.
Edit each field and choose when to display and/or require this field — at this stage you can add conditions.
Set the field to only display when the incident is a `SEV0`, and **REQUIRE** the field. Click Save once the conditions are defined.
### To Test
Create a new incident and set the team to `Security`. Once `` is selected, the form will auto-refresh with the dynamic 'Security Team Form'.
### Removing An Existing Dynamic Form
Editing and deleting can be done by clicking on the ellipsis.
Only one property can be selected at a time. Removing the existing incident property selection will delete all existing dynamic forms. You will be prompted with a warning message prior.
### Want to use dynamic forms?
Reach out to your Rootly point of contact or support team to request access.
***
## Related Pages
The baseline concept — dynamic forms are variants of custom forms driven by incident properties.
The default forms dynamic variants extend.
The umbrella concept covering every form variant and custom fields.
# Environments
Source: https://docs.rootly.com/configuration/environments
Define environment values (Production, Staging, Development) to distinguish incident scope, drive workflow conditions, and segment metrics in Rootly.
## Overview
**Environments** classify incidents by the deployment tier they impact — most commonly Production, Staging, and Development, though larger organizations often extend the list to include Sandbox, QA, Preview, or region-specific tiers like `prod-us-east` and `prod-eu-west`.
Environment is often the second field responders reach for after Severity, because it's the fastest way to answer "does this need to page people right now?" A SEV0 in Development is a bug to triage during business hours; the same SEV0 in Production is an all-hands emergency. Environment is what carries that distinction into every downstream automation.
***
## How Environments Are Used
Environments drive routing, urgency, and reporting throughout Rootly:
| Feature | How Environment is used |
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[Workflow conditions](/workflows/conditions)** | The most common paging pattern is "Severity is SEV0 **and** Environments contains Production" — Environment scopes urgency to real customer-impacting tiers. |
| **Slack channel + alias notifications** | Each Environment can be linked to Slack channels and user groups. Workflows use these to route Production incidents to `#incidents-prod` and non-production incidents to a lower-priority channel. |
| **Notify emails** | Each Environment can be linked to email addresses. Useful for stakeholder groups that only care about Production events (executive comms, customer support). |
| **Metrics + reporting** | Environment is a top-level filter in every dashboard. MTTR-by-Environment reveals whether your Production incidents resolve faster than Staging ones (they should — otherwise your Production incident response process isn't working). |
| **Status page publication** | Not automatic — status page publication is decided by workflow conditions that typically check both Severity and Environment. Most teams auto-publish SEV0/SEV1 **in Production only**. |
| **Retrospective triggers** | Different Environments can trigger different retrospective templates. Production incidents get the full customer-impact review; Staging incidents get a lightweight regression tracker. |
Because Environment gates so much automation urgency, **an incorrectly-tagged Environment is the fastest way to page the wrong people (or nobody at all)**. Making sure responders can tell the Environment field from the Severity field on the incident form matters — see Best Practices below.
***
## Choosing Your Environment List
Most teams start with three environments and add more as their infrastructure grows.
### Standard Three-Tier
The default for most SaaS teams:
* **Production** — live, customer-facing infrastructure. All customer-visible urgency lives here.
* **Staging** — pre-production tier used for release verification. Incidents here delay releases but don't affect customers directly.
* **Development** — engineering-owned tier used for feature work. Incidents here are usually contained to internal workflows.
If you're just starting out, three is enough. Adding more environments only pays off when your organization actually operates them distinctly (different on-call rotations, different SLAs, different notification patterns).
### Extended Sets
Larger organizations extend the list for real operational reasons — not just to add labels:
| Additional Environment | When it's worth adding |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sandbox** | You give customers or partners isolated test environments that can have their own incidents. |
| **QA** | Your QA team owns a distinct pre-release tier separate from Staging. |
| **Preview** | Branch- or PR-specific ephemeral environments (Vercel, Netlify, Heroku pipeline apps). Rarely worth incidents unless you have production customers on Preview URLs. |
| **`prod-us-east`, `prod-eu-west`, etc.** | You operate genuinely regional Production stacks with independent on-call rotations. Adding regions as separate Environments lets workflows route by geography. |
| **Internal / Corporate** | Employee-facing internal systems (HR platforms, expense tools) that are distinct from customer-facing infrastructure. |
### Single-Select vs Multi-Select
Environment can be configured as **single-select** (one Environment per incident) or **multi-select** (multiple Environments per incident). Which you choose changes both the picker and the workflow conditions available.
* **Single-select** — cleaner and matches most teams' actual usage. An outage is either in Production or it isn't. Workflows filter with `is` / `is one of`.
* **Multi-select** — useful when incidents span multiple deployment tiers simultaneously (for example, a shared dependency failing across `prod-us-east` and `prod-eu-west`). Workflows filter with `contains any of` / `contains all of`.
Most teams start single-select. Switch to multi-select only when you regularly have incidents affecting more than one tier at once.
***
## Field Type
Configure Environment as either **single-select** or **multi-select** in **Configuration → Environments**. The setting affects all new incidents; historical incidents keep their existing values.
Liquid syntax differs slightly between the two modes. Single-select uses `{{ incident.raw_environments | get: '' }}` for the one value. Multi-select uses `{{ incident.raw_environments[index] | get: '' }}` where `index` references a specific Environment in the list. Both are covered in the attribute reference below.
***
## Configuring Environment Attributes
Each Environment can be configured with the attributes below. All are available in Liquid syntax for use in workflows, retrospective templates, and status page updates.
Unique identifier assigned automatically by Rootly on creation. **Not customizable.** Used in Liquid references and API calls.
```liquid theme={null}
{{ incident.environment_ids }}
{{ incident.raw_environments | get: 'id' }} {/* single-select */}
{{ incident.raw_environments[0] | get: 'id' }} {/* multi-select, first Environment */}
```
The display name shown throughout the Rootly UI. Fully customizable — `Production`, `Prod`, `Live`, `prod-us-east`, whatever your team calls it.
```liquid theme={null}
{{ incident.environments }}
{{ incident.raw_environments | get: 'name' }}
{{ incident.raw_environments[0] | get: 'name' }}
```
Auto-generated by lower-casing and hyphenating the name. Used in Liquid references and in workflow condition matches.
**Slugs regenerate when you rename an Environment.** Anything referencing the old slug — workflow conditions, saved metrics dashboards, third-party integrations that filter by slug — needs to be updated after a rename.
```liquid theme={null}
{{ incident.environment_slugs }}
{{ incident.raw_environments | get: 'slug' }}
{{ incident.raw_environments[0] | get: 'slug' }}
```
Additional context shown alongside the Environment in the UI. Best used to remind responders what "Production" means specifically for your team ("prod-us-east handling all US customer traffic" vs. a vague "Prod").
```liquid theme={null}
{{ incident.raw_environments | get: 'description' }}
{{ incident.raw_environments[0] | get: 'description' }}
```
Six-digit hex color code used for Environment-tinted UI accents and metrics-graph color coding. Convention: red or brand red for Production, orange/yellow for Staging, blue/gray for Development.
```liquid theme={null}
{{ incident.raw_environments | get: 'color' }}
{{ incident.raw_environments[0] | get: 'color' }}
```
Rootly expects six-digit hex codes (for example, `#c4231c`). Use a color picker if you're not sure — [color-hex.com](https://www.color-hex.com/) is a common choice.
One or more Slack channels linked to the Environment. **Linking alone doesn't post to the channels** — a workflow action (typically "Attached Environment Channels") reads this list and performs the notification.
```liquid theme={null}
{{ incident.raw_environments | get: 'slack_channels' }}
{{ incident.raw_environments[0] | get: 'slack_channels' }}
```
One or more Slack user groups (aka aliases) linked to the Environment. **Linking alone doesn't invite users** — a workflow action (typically "Attached Environment Aliases") reads this list and performs the invitation.
```liquid theme={null}
{{ incident.raw_environments | get: 'slack_aliases' }}
{{ incident.raw_environments[0] | get: 'slack_aliases' }}
```
One or more email addresses linked to the Environment. **Linking alone doesn't send email** — a workflow action reads this list and sends the notification.
```liquid theme={null}
{{ incident.raw_environments | get: 'notify_emails' }}
{{ incident.raw_environments[0] | get: 'notify_emails' }}
```
For workflow-driven use, most teams reference the flattened list:
```liquid theme={null}
{{ incident.raw_environments | map: 'notify_emails' | flatten | join: ',' }}
```
***
## Best Practices
* **Always require Environment on incident creation.** An unspecified Environment is the fastest way to route a Production incident to the wrong Slack channel. Make Environment a required field on your incident-creation forms.
* **Use color to reinforce Environment on the incident details view.** Red for Production, orange for Staging, blue for Development is the standard convention. Responders read the color before the label — a mis-colored Environment gets miscategorized more often.
* **Gate every high-urgency workflow on Environment.** Workflows that page on-call, send stakeholder emails, or auto-publish the status page should always include an Environment condition. `Severity is SEV0` alone will page the team for a SEV0 in Dev, which nobody wants.
* **Don't invent Environments for scope you don't operate distinctly.** Adding "QA" as an Environment only pays off if your QA team has an on-call rotation, distinct SLAs, or a separate notification pattern. Otherwise it's just a tag that fragments metrics.
* **Test workflow conditions with Test Incidents in each Environment.** After adding a new Environment or reworking existing ones, `/rootly test` in each Environment and confirm the workflows route correctly. Do this before the next real incident hits the new definitions.
* **Audit rare Environments quarterly.** If an Environment sees fewer than 5% of incidents over 90 days, it's probably not distinct enough — consider merging it with a peer or removing it.
***
## Troubleshooting
Confirm the Environment is enabled under Configuration → Environments. Archived Environments remain visible on historical incidents but don't appear as options on new incidents. Also check team-level restrictions — some teams scope which Environments their responders can select.
Two common causes: (1) the workflow's condition uses `is` on a multi-select Environment field — switch to `contains any of` (see [Workflow Conditions](/workflows/conditions) for the operator reference); (2) the Environment slug was regenerated after a rename and the workflow still references the old slug. Update the workflow condition to match the new slug.
Linking a Slack channel to an Environment doesn't cause auto-notification on its own — a workflow with an "Attached Environment Channels" action is required. Check that the workflow exists, is enabled, and has run conditions that match the Environment you're testing. The Environment Updated trigger is a good candidate.
The metrics dashboard filters by Environment slug (not name). If your dashboard is grouping incidents incorrectly, check the filter query — it may still reference the pre-rename slug. Environment renames don't automatically update saved dashboards.
Two common fixes: (1) Add a description on each Environment that clarifies what qualifies — "Production = live customer traffic. Not Staging, even if Staging is in-warranty." (2) Reorder the picker so Production is at the top (most common) and less-common Environments are further down. Alphabetical ordering isn't always the right default.
***
## Frequently Asked Questions
Most teams start with three (Production, Staging, Development) and add more only when their operations actually differentiate. Adding Environments is only worth it if each new Environment has a distinct on-call rotation, SLA, or notification pattern — otherwise it's just a label that fragments metrics.
Yes. Adding regions as separate Environments (for example, `prod-us-east`, `prod-eu-west`, `prod-asia`) is a common pattern for teams with independent regional on-call rotations. Workflows can then route incidents to the right regional team based on the Environment field.
Yes. Environment is fully mutable — change it via the incident details page or a workflow action. Changes are logged in the incident timeline. This is different from Kind, which is immutable after declaration.
Historical incidents keep the Environment value they were created with, even after the Environment is deleted from the picker. Only new incidents lose access to the removed Environment. For overhauls, archive rather than delete so historical metrics stay readable.
Yes — Environments belong to a Team. Each team maintains its own Environment list, and the picker on an incident form shows the Environments defined for that incident's team. If your workspace uses multiple teams, define the Environments each team actually deploys to; there's no single org-wide Environment list.
No. Test incidents (declared via `/rootly test`) are excluded from production metrics regardless of Environment. This is a Kind-level behavior — see [Incident Kind](/configuration/incident-kind) for the full exclusion matrix.
Yes. In your incident-creation form (Configuration → Forms), mark the Environment field as required. This prevents responders from creating incidents without an Environment tag, which is important because Environment gates so much downstream routing.
***
## Related Pages
The other most-used incident field. Severity + Environment together drive most workflow conditions.
Use Environment in workflow run conditions to route Production incidents differently from non-Production.
The customizable classification for what's broken, complementing Environment's answer to where it's broken.
# Event Payloads
Source: https://docs.rootly.com/configuration/event-payloads
Reference documentation for webhook event payload structures used in Rootly integrations and custom automations, including incident, alert, and pulse events.
## alert.\*
Alert webhook payloads contain the current alert and its timeline in `data.events`. Rootly emits `alert.updated` when the alert itself changes or a timeline event is added.
Use the top-level `event.id` to deduplicate webhook delivery retries. Because the timeline is cumulative, use each `data.events[].id` to avoid reprocessing the same timeline entry across successive payloads. Events are ordered by `created_at`, oldest first. Adding a timeline event emits `alert.updated`; editing or deleting an existing timeline event does not.
### Alert Ownership Changes
Manual ownership transfers preserve the existing `kind: action` and `action: paged` contract. They add `page_reason: manual_reassignment` so consumers can distinguish an explicit destination change from other pages. For multi-target pages, adding or removing a destination counts as an ownership change, and each successful page event from that request includes the reason.
The same `page_reason` discriminator is available on alert events returned by the public API and mobile API.
| `kind` | `action` | `page_reason` | Meaning |
| -------- | -------- | --------------------- | --------------------------------------------------------------------------------------------------- |
| `action` | `paged` | `manual_reassignment` | A user manually changed an existing alert's notification target or target set |
| `action` | `paged` | Not present | An initial or automated page occurred, or the alert progressed within its current escalation policy |
Progression between levels of the current escalation policy does not include `page_reason: manual_reassignment`.
For a manual page, Rootly suppresses intermediate `alert.updated` deliveries and sends one update after the page operation settles. When the page creates a new alert, Rootly emits the normal `alert.created` event and also emits this settled `alert.updated`; subscribe to `alert.updated` for the resulting page event and ownership metadata. For a multi-target page, Rootly determines `page_reason` from the destinations that were successfully paged, and the cumulative timeline contains every successful page event from the request, including corrected metadata on earlier events when a later success changes the batch reason. Use the top-level `event.id` to deduplicate retries and each timeline event's `id` to reconcile the cumulative `data.events` list.
Ownership-change timeline events include:
* `user`: The complete user associated with the event. For an action event this is the actor; for a notification event this is the recipient. `user_id` remains available for compatibility.
* `paged_user`: For a user-group page that fans out to an individual on-call user, the complete recipient user. This keeps the selected group in `notification_target` while identifying who was actually paged. The field is omitted for other target types.
* `notification_target`: On the manual-page event, the notification target originally selected by the actor. Supported manual-reassignment types are `escalation_policy`, `group`, `service`, `functionality`, and `user`.
`group` is the serialized target type for a Team selected in the Rootly interface.
Every `notification_target` includes stable `type` and `id` fields. When the selected resource still exists, Rootly also includes its standard outgoing webhook fields:
| `type` | Additional fields |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `escalation_policy` | `name`, `description`, `created_at`, `updated_at` |
| `group` | `name`, `description`, `color`, notification configuration, integration identifiers, `created_at`, `updated_at` |
| `service` | `name`, `slug`, descriptions, `color`, notification and repository configuration, integration identifiers, `created_at`, `updated_at` |
| `functionality` | `name`, `slug`, descriptions, `color`, notification configuration, integration identifiers, `created_at`, `updated_at` |
| `user` | `name`, `email`, `preferred_name`, `full_name`, `full_name_with_team`, `slack_id` |
Downstream notification events can also identify the channel or space that received a notification. These are not manual-reassignment targets:
| `type` | Additional fields |
| ------------------------- | ----------------- |
| `slack_channel` | `name` |
| `microsoft_teams_channel` | `name` |
| `google_chat_space` | `name` |
If the referenced resource was deleted or is otherwise unavailable when the webhook is generated, `notification_target` remains present with only its stored `type` and `id`. Consumers should therefore treat all additional fields as optional.
When an alert is transferred to an escalation policy with no pageable targets, the manual-page event still identifies the selected policy and the resulting `alert.updated` payload reports `data.status` as `open`. If the alert was previously non-`open`, the timeline also includes a `kind: status_update` event with `action: open`; an alert that was already `open` does not record another status transition.
### `alert.updated` Manual Reassignment Example
The following representative payload shows the output of Rootly's outgoing alert serializer for a manual transfer to an escalation policy with no pageable targets. Optional fields may vary by alert and serializer version:
```json JSON theme={null}
{
"event": {
"id": "39ad7696-7e4c-4114-88c9-258c4211d630",
"type": "alert.updated",
"issued_at": "2026-08-05T17:00:01.000-07:00"
},
"data": {
"id": "826a9d01-3745-468c-977d-05a64202881e",
"source": "datadog",
"status": "open",
"summary": "API latency is above threshold",
"labels": [],
"services": [],
"environments": [],
"data": {},
"started_at": "2026-08-05T16:55:00.000-07:00",
"ended_at": null,
"created_at": "2026-08-05T17:00:00.000-07:00",
"updated_at": "2026-08-05T17:00:01.000-07:00",
"events": [
{
"id": "276e87ef-1f2a-4b54-9267-feba4d7a2960",
"alert_id": "826a9d01-3745-468c-977d-05a64202881e",
"kind": "informational",
"source": "datadog",
"action": "created",
"details": null,
"user": null,
"user_id": null,
"notification_target": null,
"incident_ids": [],
"created_at": "2026-08-05T17:00:00.000-07:00",
"updated_at": "2026-08-05T17:00:00.000-07:00"
},
{
"id": "b722de6d-55a6-4814-a576-e5e5e353745b",
"alert_id": "826a9d01-3745-468c-977d-05a64202881e",
"kind": "status_update",
"source": "datadog",
"action": "triggered",
"details": null,
"user": null,
"user_id": null,
"notification_target": null,
"incident_ids": [],
"created_at": "2026-08-05T17:00:00.001-07:00",
"updated_at": "2026-08-05T17:00:00.001-07:00"
},
{
"id": "e626c88b-1bd7-4856-96c2-f95af0901457",
"alert_id": "826a9d01-3745-468c-977d-05a64202881e",
"kind": "action",
"source": "web",
"action": "paged",
"details": "Escalating to the secondary policy",
"user": {
"id": 129,
"name": "Ada Lovelace",
"email": "ada@example.com",
"preferred_name": null,
"full_name": "Ada Lovelace",
"full_name_with_team": "[Acme] Ada Lovelace",
"slack_id": null
},
"user_id": 129,
"notification_target": {
"type": "escalation_policy",
"id": "9f8c123b-49fa-41c0-8ecf-7b1bef55f99c",
"name": "Secondary escalation policy",
"description": "Fallback ownership policy",
"created_at": "2026-07-15T09:30:00.000-07:00",
"updated_at": "2026-08-05T16:45:00.000-07:00"
},
"incident_ids": [],
"created_at": "2026-08-05T17:00:00.500-07:00",
"updated_at": "2026-08-05T17:00:00.500-07:00",
"page_reason": "manual_reassignment"
},
{
"id": "c213a7f1-9c8e-4c53-a427-ca2f8cb0e8a0",
"alert_id": "826a9d01-3745-468c-977d-05a64202881e",
"kind": "status_update",
"source": "web",
"action": "open",
"details": null,
"user": null,
"user_id": null,
"notification_target": null,
"incident_ids": [],
"created_at": "2026-08-05T17:00:01.000-07:00",
"updated_at": "2026-08-05T17:00:01.000-07:00"
}
]
}
}
```
***
## genius\_workflow\_run.\*
```json JSON theme={null}
{
"event":{
"id":"88a53013-05dc-44df-bb4f-c68d890f8bf9",
"type":"genius_workflow_run.queued",
"issued_at":"2022-12-19T08:02:03.067-08:00"
},
"data":{
"id":"daf992ed-df23-41df-a72c-438616b4f6dc",
"kind":"incident",
"status":"queued",
"status_message": null,
"user_id":3186,
"genius_workflow_id":"a1b76e56-e1ab-4b36-856f-b6481251c698",
"genius_workflow_name":"Send Email when incident starts",
"queued_at":"2022-12-19T08:02:03.031-08:00",
"started_at":null,
"completed_at":null,
"failed_at":null,
"canceled_at":null,
"triggered_by":"system",
"created_at":"2022-12-19T08:02:03.031-08:00",
"updated_at":"2022-12-19T08:02:03.031-08:00",
"incident_id":"5c80f5a1-9389-4970-bb49-8268acf2954f",
"incident_action_item_id":null,
"incident_post_mortem_id":null,
"alert_id":null,
"pulse_id":null
}
}
```
```json JSON theme={null}
{
"event":{
"id":"76376d80-29e4-4aaf-8295-c12f111cf5eb",
"type":"genius_workflow_run.started",
"issued_at":"2022-12-19T08:04:55.249-08:00"
},
"data":{
"id":"ff3021be-6ac2-4253-afbe-ae866c0c75a3",
"kind":"incident",
"status":"started",
"status_message": null,
"user_id":3186,
"genius_workflow_id":"a1b76e56-e1ab-4b36-856f-b6481251c698",
"genius_workflow_name":"Send Email when incident starts",
"queued_at":"2022-12-19T08:04:55.196-08:00",
"started_at":"2022-12-19T08:04:55.220-08:00",
"completed_at":null,
"failed_at":null,
"canceled_at":null,
"triggered_by":"user",
"status":"started",
"created_at":"2022-12-19T08:04:55.196-08:00",
"updated_at":"2022-12-19T08:04:55.226-08:00",
"incident_id":"5c80f5a1-9389-4970-bb49-8268acf2954f",
"incident_action_item_id":null,
"incident_post_mortem_id":null,
"alert_id":null,
"pulse_id":null
}
}
```
```json JSON theme={null}
{
"event":{
"id":"ae55dd1a-9bde-4a98-bd42-61df1e8dd80f",
"type":"genius_workflow_run.completed",
"issued_at":"2022-12-19T08:06:35.911-08:00"
},
"data":{
"id":"4cd6046c-9ed9-423e-8145-a1891f82ac57",
"kind":"incident",
"status":"completed",
"status_message": null,
"user_id":3186,
"genius_workflow_id":"678fbb8a-23bc-4fcf-8d46-b1833698b75b",
"genius_workflow_name":"Send Email when incident starts",
"queued_at":"2022-12-19T08:06:33.493-08:00",
"started_at":"2022-12-19T08:06:33.512-08:00",
"completed_at":"2022-12-19T08:06:35.887-08:00",
"failed_at":null,
"canceled_at":null,
"triggered_by":"user",
"created_at":"2022-12-19T08:06:33.493-08:00",
"updated_at":"2022-12-19T08:06:35.887-08:00",
"incident_id":"5c80f5a1-9389-4970-bb49-8268acf2954f",
"incident_action_item_id":null,
"incident_post_mortem_id":null,
"alert_id":null,
"pulse_id":null
}
}
```
```json JSON theme={null}
{
"event":{
"id":"1562f78b-18fa-4d9f-a765-24e6dfba9794",
"type":"genius_workflow_run.failed",
"issued_at":"2022-12-19T08:08:18.521-08:00"
},
"data":{
"id":"3ceebcf1-e82f-4dfe-97da-69cd0678696d",
"kind":"incident",
"status":"failed",
"status_message": null,
"user_id":3186,
"genius_workflow_id":"a1b76e56-e1ab-4b36-856f-b6481251c698",
"genius_workflow_name":"Send Email when incident starts",
"queued_at":"2022-12-19T08:08:17.890-08:00",
"started_at":"2022-12-19T08:08:17.908-08:00",
"completed_at":null,
"failed_at":"2022-12-19T08:08:18.498-08:00",
"canceled_at":null,
"triggered_by":"user",
"created_at":"2022-12-19T08:08:17.890-08:00",
"updated_at":"2022-12-19T08:08:18.498-08:00",
"incident_id":"5c80f5a1-9389-4970-bb49-8268acf2954f",
"incident_action_item_id":null,
"incident_post_mortem_id":null,
"alert_id":null,
"pulse_id":null
}
}
```
```json JSON theme={null}
{
"event":{
"id":"4b3d9e46-1a59-44a7-914d-b1758216b8d5",
"type":"genius_workflow_run.canceled",
"issued_at":"2022-12-19T11:09:16.508-05:00"
},
"data":{
"id":"e9269feb-1f2b-4d35-9181-f6842361ec62",
"kind":"incident",
"status":"canceled",
"status_message": null,
"user_id":3186,
"genius_workflow_id":"554f0a33-c05b-4352-87d4-1ec0332431bd",
"genius_workflow_name":"Send Email when incident starts",
"queued_at":"2022-12-19T11:02:04.659-05:00",
"started_at":null,
"completed_at":null,
"failed_at":null,
"canceled_at":"2022-12-19T11:09:16.480-05:00",
"triggered_by":"system",
"created_at":"2022-12-19T11:02:04.659-05:00",
"updated_at":"2022-12-19T11:09:16.480-05:00",
"incident_id":"5c80f5a1-9389-4970-bb49-8268acf2954f",
"incident_action_item_id":null,
"incident_post_mortem_id":null,
"alert_id":null,
"pulse_id":null
}
}
```
***
## incident.\*
```json JSON theme={null}
{
"event": {
"id": "9839c4ca-5e7b-416d-ad95-d09ae0c8eead",
"type": "incident.created",
"issued_at": "2022-11-27T19:44:33.633-08:00",
},
"data": {
"id": "b7eed587-50e6-44fe-b010-7a2bb05d737a",
"sequential_id": 19,
"title": "Sparkling Frost",
"slug": "sparkling-frost",
"kind": "normal",
"private": false,
"summary": null,
"status": "started",
"url": "http://localhost:3000/account/incidents/19-sparkling-frost",
"short_url": null,
"mitigation_message": null,
"resolution_message": null,
"cancellation_message": null,
"public_title": null,
"zoom_meeting_id": null,
"zoom_meeting_start_url": null,
"zoom_meeting_join_url": null,
"shortcut_story_id": null,
"shortcut_story_url": null,
"shortcut_task_id": null,
"shortcut_task_url": null,
"asana_task_id": null,
"asana_task_url": null,
"github_issue_id": null,
"github_issue_url": null,
"jira_issue_id": null,
"jira_issue_url": null,
"google_meeting_id": null,
"google_meeting_url": null,
"trello_card_id": null,
"trello_card_url": null,
"linear_issue_id": null,
"linear_issue_url": null,
"zendesk_ticket_id": null,
"zendesk_ticket_url": null,
"slack_channel_name": null,
"slack_channel_id": null,
"slack_channel_url": null,
"slack_channel_short_url": null,
"service_now_incident_id": null,
"service_now_incident_key": null,
"service_now_incident_url": null,
"opsgenie_incident_id": null,
"opsgenie_incident_url": null,
"opsgenie_alert_id": null,
"opsgenie_alert_url": null,
"victor_ops_incident_id": null,
"victor_ops_incident_url": null,
"pagerduty_incident_id": null,
"pagerduty_incident_url": null,
"mattermost_channel_id": null,
"mattermost_channel_name": null,
"mattermost_channel_url": null,
"confluence_page_id": null,
"confluence_page_url": null,
"quip_page_id": null,
"quip_page_url": null,
"airtable_base_key": null,
"airtable_table_name": null,
"airtable_record_id": null,
"airtable_record_url": null,
"google_drive_id": null,
"google_drive_url": null,
"datadog_notebook_id": null,
"datadog_notebook_url": null,
"freshservice_ticket_id": null,
"freshservice_ticket_url": null,
"freshservice_task_id": null,
"freshservice_task_url": null,
"started_at": "2022-11-27T19:36:00.000-08:00",
"detected_at": null,
"acknowledged_at": null,
"mitigated_at": null,
"resolved_at": null,
"cancelled_at": null,
"created_at": "2022-11-27T19:36:49.779-08:00",
"updated_at": "2022-11-27T19:36:49.779-08:00",
"labels": {
},
"severity": null,
"user": {
"id": 7,
"name": "John Doe",
"email": "demo@rootly.com",
"full_name": "John Doe",
"full_name_with_team": "[rootly.com] John Doe",
"slack_id": null
},
"started_by": {
"id": 7,
"name": "John Doe",
"email": "demo@rootly.com",
"full_name": "John Doe",
"full_name_with_team": "[rootly.com] John Doe",
"slack_id": null
},
"mitigated_by": null,
"resolved_by": null,
"cancelled_by": null,
"roles": [
{
"id": "e5c83728-78b9-495f-bdc5-55b3db047339"
},
{
"id": "45602201-6cb9-4567-abd6-293096d880ef"
}
],
"environments": [
],
"incident_types": [
],
"services": [
],
"functionalities": [
],
"groups": [
],
"events": [
{
"id": "01608451-5926-41ea-88b0-5af2f3cf5f79",
"event": "John Doe created this incident",
"event_raw": "John Doe created this incident",
"kind": "event",
"source": "web",
"visibility": "external",
"occurred_at": "2022-11-27T19:36:49.779-08:00",
"created_at": "2022-11-27T19:36:49.779-08:00",
"updated_at": "2022-11-27T19:36:49.884-08:00"
},
{
"id": "42a1a95d-5ae2-4b74-a8dd-af675311769a",
"event": "Started date has been set to November 27 7:36 PM PST",
"event_raw": "Started date has been set to November 27 7:36 PM PST",
"kind": "trail",
"source": "web",
"visibility": "internal",
"occurred_at": "2022-11-27T19:36:49.955-08:00",
"created_at": "2022-11-27T19:36:49.955-08:00",
"updated_at": "2022-11-27T19:36:49.955-08:00"
}
],
"action_items": [
{
"id": "a3121c52-39a8-4ba4-aef4-e33e6c6bcbdc",
"incident_id": "b7eed587-50e6-44fe-b010-7a2bb05d737a",
"description": null,
"summary": "Tasks can be customized in Rootly",
"kind": "task",
"priority": "medium",
"status": "open",
"due_date": null,
"jira_issue_id": null,
"jira_issue_url": null,
"asana_task_id": null,
"asana_task_url": null,
"github_issue_id": null,
"github_issue_url": null,
"shortcut_story_id": null,
"shortcut_story_url": null,
"shortcut_task_id": null,
"shortcut_task_url": null,
"trello_card_id": null,
"trello_card_url": null,
"linear_issue_id": null,
"linear_issue_url": null,
"zendesk_ticket_id": null,
"zendesk_ticket_url": null,
"airtable_base_key": null,
"airtable_table_name": null,
"airtable_record_id": null,
"airtable_record_url": null,
"freshservice_ticket_id": null,
"freshservice_ticket_url": null,
"freshservice_task_id": null,
"freshservice_task_url": null,
"created_at": "2022-11-27T19:15:07.651-08:00",
"updated_at": "2022-11-27T19:15:07.651-08:00"
},
{
"id": "70ef7704-aecb-401a-833d-edaf8aaa9d86",
"incident_id": "b7eed587-50e6-44fe-b010-7a2bb05d737a",
"description": null,
"summary": "Update `/incident summary`",
"kind": "task",
"priority": "medium",
"status": "open",
"due_date": null,
"jira_issue_id": null,
"jira_issue_url": null,
"asana_task_id": null,
"asana_task_url": null,
"github_issue_id": null,
"github_issue_url": null,
"shortcut_story_id": null,
"shortcut_story_url": null,
"shortcut_task_id": null,
"shortcut_task_url": null,
"trello_card_id": null,
"trello_card_url": null,
"linear_issue_id": null,
"linear_issue_url": null,
"zendesk_ticket_id": null,
"zendesk_ticket_url": null,
"airtable_base_key": null,
"airtable_table_name": null,
"airtable_record_id": null,
"airtable_record_url": null,
"freshservice_ticket_id": null,
"freshservice_ticket_url": null,
"freshservice_task_id": null,
"freshservice_task_url": null,
"created_at": "2022-11-27T19:15:07.626-08:00",
"updated_at": "2022-11-27T19:15:07.651-08:00"
},
{
"id": "368921f4-419c-4df3-92a2-006c3882dc70",
"incident_id": "b7eed587-50e6-44fe-b010-7a2bb05d737a",
"description": null,
"summary": "Ensure roles are assigned",
"kind": "task",
"priority": "medium",
"status": "open",
"due_date": null,
"jira_issue_id": null,
"jira_issue_url": null,
"asana_task_id": null,
"asana_task_url": null,
"github_issue_id": null,
"github_issue_url": null,
"shortcut_story_id": null,
"shortcut_story_url": null,
"shortcut_task_id": null,
"shortcut_task_url": null,
"trello_card_id": null,
"trello_card_url": null,
"linear_issue_id": null,
"linear_issue_url": null,
"zendesk_ticket_id": null,
"zendesk_ticket_url": null,
"airtable_base_key": null,
"airtable_table_name": null,
"airtable_record_id": null,
"airtable_record_url": null,
"freshservice_ticket_id": null,
"freshservice_ticket_url": null,
"freshservice_task_id": null,
"freshservice_task_url": null,
"created_at": "2022-11-27T19:15:07.601-08:00",
"updated_at": "2022-11-27T19:15:07.651-08:00"
}
],
"form_field_selections": [
],
"feedbacks": [
],
"incident_post_mortem": null
}
}
```
When [custom fields on action items](/incidents/action-items/action-item-custom-fields) are enabled for your team, each action item in the `action_items` array carries a `custom_field_selections` array for the fields placed on its form. Each entry looks like:
```json JSON theme={null}
"custom_field_selections": [
{
"id": "b1e0c1a2-9f3c-4a7e-8d21-4f2a6b7c8d90",
"value": "Payments",
"form_field": {
"id": "9f3c4a7e-8d21-4f2a-6b7c-8d90b1e0c1a2",
"name": "Business Unit",
"slug": "business-unit"
},
"selected_options": [],
"selected_users": [],
"selected_groups": [],
"selected_services": [],
"selected_functionalities": [],
"selected_catalog_entities": [],
"selected_environments": [],
"selected_causes": [],
"selected_incident_types": []
}
]
```
Free-text, number, and date fields populate `value`; reference-type fields (user, team, service, catalog entity, environment, cause, incident type) populate the matching `selected_*` array instead.
***
## incident\_post\_mortem.\*
```json JSON theme={null}
{
"event": {
"id": "9839c4ca-5e7b-416d-ad95-d09ae0c8eead",
"type": "incident_post_mortem.created",
"issued_at": "2022-11-27T19:36:00.000-08:00",
},
"data": {
"id": "2c7497e5-5d15-4fa4-aeac-cac063aafe19",
"incident_id": "b7eed587-50e6-44fe-b010-7a2bb05d737a",
"title": "Sparkling Frost",
"status": "draft",
"url": "http://rootly.com/account/incidents/19-sparkling-frost/postmortem_url",
"short_url": null,
"content": "{{incident.created_at | date: \"%Y-%m-%d\"}} - {{incident.title}}
\nLeadup
\n
Describe the circumstances that led to this incident
\nFault
\n
Describe what failed to work as expected
\nDetection
\n
Describe how the incident was detected
\nRoot causes
\n
Run a 5-whys analysis to understand the true causes of the incident
\nMitigation and resolution
\n
What steps did you take to resolve this incident?
\nLessons learnt
\n
What went well? What could have gone better? What else did you learn?
",
"published_at": null,
"started_at": "2022-11-27T19:36:00.000-08:00",
"mitigated_at": "2022-11-27T19:44:32.156-08:00",
"resolved_at": "2022-11-27T19:44:32.156-08:00",
"cancelled_at": null,
"show_timeline": true,
"show_timeline_starred_only": false,
"show_timeline_genius": true,
"show_timeline_trail": true,
"show_timeline_tasks": true,
"show_timeline_action_items": true,
"show_functionalities_impacted": true,
"show_services_impacted": true,
"show_groups_impacted": true,
"show_action_items": true,
"created_at": "2022-11-27T19:36:49.779-08:00",
"updated_at": "2022-11-27T19:44:32.177-08:00"
}
}
```
***
## pulse.\*
```json JSON theme={null}
{
"event": {
"id": "9839c4ca-5e7b-416d-ad95-d09ae0c8eead",
"type": "pulse.created",
"issued_at": "2022-11-27T19:15:30.995-08:00",
},
"data": {
"id": "aa1cab03-00e7-4578-b1ae-72ad9ae417c6",
"team_id": 1,
"pulse_trail_id": "b59bfcb7-89ed-4641-b288-5ce1bb3dd801",
"summary": "Deployed to Kubernetes",
"labels": [
{
"key": "label1",
"value": "value1"
},
{
"key": "label2",
"value": "value2"
}
],
"data": {
"hello": "world"
},
"external_id": null,
"started_at": "2022-11-27T19:15:30.995-08:00",
"ended_at": null,
"deleted_at": null,
"created_at": "2022-11-27T19:15:30.995-08:00",
"updated_at": "2022-11-27T19:15:30.995-08:00",
"webhook_type": null,
"webhook_id": null,
"webhook_idempotency_key": null,
"external_url": null,
"source": "k8s",
"refs": [
{
"key": "image",
"value": "registry.rootly.com/rootly/my-service:cd6214"
}
]
}
}
```
# Example Usage With Incidents
Source: https://docs.rootly.com/configuration/example-usage-with-incidents
Learn how playbooks automatically attach relevant action items and response procedures when incident types are assigned during incident response.
This example appends a playbook to a newly created incident. If I was in Slack for example I would do this by clicking the "Update" button (Seen below).
Let's say this was a security related incident. Once I append "Security" to the types field that would then automatically attach the related playbooks that were associated with the "Security" types.
As you can see below the action items have increased from 3 to 6 because the Security type action items were appended. Clicking the Action Items button gives us a full list of all the action items.
You can also modify incidents in the Rootly UI as well by navigating to the Incidents tab and clicking edit on the appropriate incident. Modifying incidents in the UI will also automatically attach any relevant playbooks associated with the changes.
# Forms and custom fields overview
Source: https://docs.rootly.com/configuration/forms-and-fields
Configure incident data collection forms and custom fields in Rootly to control when and how information is captured during the incident response lifecycle.
Use Forms in Rootly to capture incident data throughout your incident's lifecycle. Forms can be filled out at key moments during your incident lifecycle across Slack and web. The form can be completely customized depending on the stage and type of incident using fields.
Start configuring your forms by logging into the Rootly web app and navigating to **Configuration > Forms**.
## **Default Forms**
Rootly comes with a series of built-in forms that cannot be deleted. These forms are used to capture information about your incident at standard moments in your incident lifecycle, such as when the incident is created, updated, or cancelled.
The information captured on these forms can be completely customized by updating the form and adding or removing additional fields.
Learn about customizing these default forms on the [Built-In Forms](/configuration/built-in-forms) page.
## **Custom Forms**
Create a custom form to capture information outside of when your incident progresses or the lifecycle status changes. Custom forms can be opened and filled out through a Slack command or using a Slack block button.
To learn about how to create and manage custom forms, please see the [Custom Forms](/configuration/custom-forms) page.
## Sub-Status Forms
For customers with access to Custom Lifecycles, Rootly creates a separate form for each custom substatus that you configure in the Lifecycle section of the application. These can be edited in the same way that default and custom forms can be under the substatus forms tab.
## Follow-Up Form
The **Incident Follow Up** form controls which custom fields appear when a follow-up is added or edited on an incident—on the web and in Slack. Use it to capture organization-specific metadata (like product area or business unit) on your post-incident work.
To learn how to configure it, see [Custom Fields on Action Items](/incidents/action-items/action-item-custom-fields).
## **Built-In Fields**
Rootly comes with a series of built-in incident properties that are typically collected during incident responses. To learn about what can be customized and how to customize built-in fields, please see the [Built-In Fields](/configuration/built-in-fields) page.
## **Custom Fields**
If the built-in properties are not enough to address your requirements, Rootly offers the ability to create custom incident properties in various data types. To learn about how to create custom fields, please see the [Custom Fields](/configuration/custom-fields) page.
***
## Related Pages
Rootly's default forms.
Author additional forms with your own field selection.
Add organization-specific fields that appear on any form.
# Functionalities
Source: https://docs.rootly.com/configuration/functionalities
Configure functionality categories in Rootly to identify impacted product features during incidents, route to appropriate teams, and surface ownership context.
## Overview
**Functionalities** allow you to specify the impacted features during an incident. This can help you identify which responders to bring in, which on-call to page, which customers to inform, etc. Individual functionalities can be mapped to your status pages.
## Adding Properties
While Functionalities in Rootly comes with built-in properties, additional properties can be added. This allows you to build automations and workflows for your incident response processes using this information: for example, quickly identifying the customer impact of an incident based on the related functionality.
To add custom properties, open **Functionalities**, click **Edit catalog**, and click **Add Property**. You can choose from several property types, including text, boolean, and importantly references to other Catalogs.
For each Functionality, you'll be able to find the values of these properties in the **Custom Properties** tab.
## Configuring Functionalities
Begin editing the properties of your Functionalities by selecting the '...', then Edit.
## Basics
Update the information in this tab to set the fundamental details about your functionality.
Auto-generated. Use it when referring to the functionality from Rootly's API.
A descriptive name other Rootly users see when they select or search for the functionality.
Internal description shown to Rootly users — for example, in the functionality picker.
External-facing description shown to visitors on your Rootly Status Page.
## Ownership
Assign the responsible stakeholders of your functionality. The values in these fields can be used to automate tasks and processes using Workflows in Rootly.
For example, update an incident with the functionality's `Team` when a functionality is added to an incident.
## Connections
Add connections between other entities in Rootly, like Environments, Services, Playbooks, and Escalation Policies. This information can be used to automate tasks and processes using Workflows in Rootly.
For example, post a message in the incident channel linking to the functionality's playbook when a functionality is added to an incident.
### Paging Functionalities
Functionalities can be paged when things go wrong. When a functionality is paged (either by an Alert Source, or manually by another user), the functionality's escalation policy will fire.
Functionalities can only be paged if they have an assigned escalation policy. Make sure to set this up in the Functionality's Connection tab in Rootly.
## Alerting & Notifications
Add relevant channel properties to the functionality to automate communications and processes using Workflows in Rootly.
For example, use the `Slack Channel` property to post a message in a Slack channel dedicated to the functionality when it is added to an incident.
## Custom Properties
Add the values to your custom properties in this section. Learn more about adding custom properties [in this section](/configuration/functionalities).
## On-Call
Configure what happens when this Functionality is paged in Rootly On-Call. When this Functionality is paged either manually by a user, or through an Alert Source, the Escalation Policy selected here will fire.
## Incident Fields
**Functionalities** can be customized to be either a **select** or **multi-select** field type. This means you can configure it to allow only one functionality value to be selected per incident or allow multiple functionality values to be selected per incident.
## Attributes
**Functionalities** can be configured with the following attributes. Each functionality attribute can be referenced via Liquid syntax.
Since the functionality field can be either a **select** or **multi-select** field type, the Liquid syntax to reference each field type will differ.
Select will follow a single-value syntax
`{{incident.raw_functionalities | get: ''}}`
Multi-select will follow an array syntax. Where i references the specific functionality object in the list of functionalities.
`{{incident.raw_functionalities[index] | get: ''}}`
### ID
This is the unique identifier of the functionality. This field **cannot be customized**. Rootly will automatically assign the *ID* upon creation. It is typically used in Liquid references and API calls.
The following Liquid syntax will allow you to list out the functionality *ID*(s) that are selected for an incident:
`{{ incident.functionality_ids }}`
**OR**
* `{{ incident.raw_functionalities | get: 'id'}}` for the select field type
* `{{ incident.raw_functionalities[index] | get: 'id' }}` for a multi-select field type
### Name
This is the value that is displayed on the UI for the functionality. This field is customizable.
The following Liquid syntax will allow you to list out the functionality *name*(s) that are selected for an incident:
`{{ incident.functionalities }}`
**OR**
* `{{ incident.raw_functionalities | get: 'name'}}` for the select field type
* `{{ incident.raw_functionalities[index] | get: 'name' }}` for a multi-select field type
### Slug
This is the string that is used to reference the functionality in Liquid references. This field is automatically generated by lower-casing and hyphenating the functionality *name*.
The following Liquid syntax will allow you to list out the functionality *slug*(s) that are selected for an incident:
`{{ incident.functionality_slugs }}`
**OR**
* `{{ incident.raw_functionalities | get: 'slug'}}` for the select field type
* `{{ incident.raw_functionalities[index] | get: 'slug' }}` for a multi-select field type
### Description
This value is displayed on the UI to further explain each functionality. This field is customizable.
The following Liquid syntax will allow you to list out the functionality *description*(s) that are selected for an incident:
* `{{ incident.raw_functionalities | get: 'description'}}` for the select field type
* `{{ incident.raw_functionalities[index] | get: 'description' }}` for a multi-select field type
### Color
Each functionality can be assigned a color, which will be used for color-coding on metrics graphs.
Rootly uses **color-hex codes**. For example, #000000 is black, #ffffff is white. Use [color-hex.com](https://www.color-hex.com/) to find the exact hex code for the color you want.
The following Liquid syntax will allow you to list out the functionality *color*(s) that are selected for an incident:
* `{{ incident.raw_functionalities | get: 'color'}}` for the select field type
* `{{ incident.raw_functionalities[index] | get: 'color' }}` for a multi-select field type
### Slack Channels
Each functionality can be linked to one or more Slack channels. By default, Rootly does not notify the linked channel(s) when a functionality is selected for an incident. Notification needs to be explicitly called out as Attached Functionality Channels in workflow configurations.
Systematically, each Slack channel is stored as an object containing an ID and name.
The following Liquid syntax will allow you to list out the functionality *Slack Channel*(s) that are selected for an incident:
* `{{ incident.raw_functionalities | get: 'slack_channels'}}` for the select field type
* `{{ incident.raw_functionalities[index] | get: 'slack_channels' }}` for a multi-select field type
### Slack Aliases
Each functionality can be linked to one or more Slack user groups (aka aliases). By default, Rootly does not invite users in the linked user group(s) when a functionality is selected for an incident. Invitations need to be explicitly called out as Attached Functionality Aliases in workflow configurations.
The following Liquid syntax will allow you to list out the functionality *Slack Alias*(es) that are selected for an incident:
* `{{ incident.raw_functionalities | get: 'slack_aliases'}}` for the select field type
* `{{ incident.raw_functionalities[index] | get: 'slack_aliases' }}` for a multi-select field type
### Notify Emails
Each functionality can be linked to one or more emails. By default, Rootly does not send emails to the linked address(es) when a functionality is selected for an incident. Notification needs to be explicitly called out as `{{ incident.raw_functionalities | map: 'notify_emails' | flatten | join: ',' }}` in workflow configurations.
The following Liquid syntax will allow you to list out the functionality *Notify Email*(s) that are selected for an incident:
* `{{ incident.raw_functionalities | get: 'notify_emails'}}` for the select field type
* `{{ incident.raw_functionalities[index] | get: 'notify_emails' }}` for a multi-select field type
## Import Functionalities
Instead of creating functionalities from scratch, Rootly allows you to import functionalities from **PagerDuty** or **Opsgenie**. Imported functionalities will be automatically kept in sync on a daily basis.
The ability to import functionalities will only become available once you have PagerDuty or Opsgenie installed on the [integrations page](https://rootly.com/account/integrations).
The following Liquid syntax will allow you to list out the corresponding IDs from each of the external paging applications:
**PagerDuty**
* `{{ incident.raw_functionalities | get: 'pagerduty_id' }}` for the select field type
* `{{ incident.raw_functionalities\[0\] | get: 'pagerduty_id' }}` for a multi-select field type
**Opsgenie**
* `{{ incident.raw_functionalities | get: 'opsgenie_id' }}` for the select field type
* `{{ incident.raw_functionalities\[0\] | get: 'opsgenie_id' }}` for a multi-select field type
***
## Related Pages
Functionalities group services into higher-level customer-facing capabilities.
Functionalities can be owned by teams that get paged when the functionality is impacted.
Functionalities are the customer-facing components most status pages display.
# GitHub Configuration
Source: https://docs.rootly.com/configuration/github
Configure GitHub integration to automatically capture push events and pull request merges as contextual pulses during incident triage and analysis.
The GitHub integration records repository activity as [pulses](/configuration/pulses) in Rootly, giving responders a timeline of recent code changes alongside their incidents. When something breaks, pulses help you correlate the incident with the pushes and pull requests that landed just before it.
Rootly will **automatically** add the following GitHub events as pulses:
* Push to any repositories
* Merged pull requests
* More to come...
## How It Works
Once the GitHub integration is connected, Rootly receives push, pull request, and issue events from your repositories and surfaces them as pulses on the incident timeline and service activity feed. No extra configuration is needed for individual events — activity is captured automatically as it happens.
Beyond pulses, the GitHub integration also lets you create and update GitHub issues from incident workflows, fetch recent commits across repositories during an incident, and automatically enrich GitHub pull request links shared in incident Slack channels with live status updates.
## Getting the most out of GitHub pulses
* Use pulses during triage to answer "what changed?" — a deploy or merge shortly before an incident is often the fastest lead.
* Pair the integration with [workflows](/workflows/workflows) to automate issue creation and keep GitHub in sync as incidents progress.
Ready to configure the GitHub integration? See [GitHub integration setup](/integrations/github/github).
## Related pages
* [GitHub integration setup](/integrations/github/github) — installation, permissions, and workflow actions
* [Pulses](/configuration/pulses) — how change events appear in Rootly
* [Workflows](/workflows/workflows) — automate incident response with GitHub actions
***
## Related Pages
Where GitHub push and merge events appear as change events on incident timelines.
Link services to specific GitHub repositories so pulses land on the right incident context.
Full installation guide, permissions, and workflow actions.
# GitLab Configuration
Source: https://docs.rootly.com/configuration/gitlab
Configure GitLab integration to automatically track repository pushes and merge requests as contextual pulses for enhanced incident analysis.
The GitLab integration records repository activity as [pulses](/configuration/pulses) in Rootly, giving responders a timeline of recent code changes alongside their incidents. When something breaks, pulses help you correlate the incident with the pushes and merge requests that landed just before it.
Rootly will **automatically** add the following GitLab events as pulses:
* Push to any repositories
* Merged merge requests
* More to come...
## How It Works
Once the GitLab integration is connected, Rootly receives webhook events from your tracked repositories and records them as pulses on the incident timeline and service activity feed. Push events, merged merge requests, and deployment events each produce a pulse with labels and refs identifying the repository, branch, and commit. You can limit tracking to specific repositories in the integration settings to reduce noise.
Beyond pulses, the GitLab integration also lets you create and update GitLab issues from incident and action item workflows, fetch recent commits during an incident, and enrich GitLab merge request links pasted into incident Slack channels with live status cards.
## Getting the most out of GitLab pulses
* Use pulses during triage to answer "what changed?" — a merge or deployment shortly before an incident is often the fastest lead.
* Pair the integration with [workflows](/workflows/workflows) to automate GitLab issue creation and keep issues in sync as incidents progress.
Ready to configure the GitLab integration? See [GitLab integration setup](/integrations/gitlab).
## Related pages
* [GitLab integration setup](/integrations/gitlab) — installation, OAuth setup, and workflow actions
* [Pulses](/configuration/pulses) — how change events appear in Rootly
* [Workflows](/workflows/workflows) — automate incident response with GitLab actions
***
## Related Pages
Where GitLab push and merge events appear as change events on incident timelines.
Link services to specific GitLab repositories so pulses land on the right incident context.
Full installation guide and setup details.
# Heroku Configuration
Source: https://docs.rootly.com/configuration/heroku
Configure Heroku integration to automatically capture build events and release deployments as contextual pulses for incident correlation.
The Heroku integration records build and release events from your Heroku apps as [pulses](/configuration/pulses) in Rootly, so responders can correlate deployments with incidents directly on the incident timeline. If an incident starts shortly after a release, the pulse feed makes that connection obvious.
Rootly will **automatically** add the following Heroku events as pulses:
* A build starts
* A build ends ( Failed or succeeded )
* A release is deployed
* More to come...
## How It Works
Once connected via OAuth, Rootly creates webhooks on the Heroku apps you list in the integration settings and ingests their build and release events. Each pulse includes context like the commit SHA and the user who triggered the build, and pulses are automatically linked to Rootly [services](/configuration/services) with a matching **Heroku App Name** field — set this field on each service you want correlated with deployments.
Only explicitly listed apps are monitored, so you control exactly which deployment activity shows up in Rootly.
Beyond pulses, the integration also provides a **Run Command on Heroku** workflow action that executes one-off commands on a dyno — useful for rollbacks or diagnostic scripts mid-incident — and posts the output to Slack.
Ready to configure the Heroku integration? See [Heroku integration setup](/integrations/heroku).
## Related pages
* [Heroku integration setup](/integrations/heroku) — installation, pulse events, and the Run Command action
* [Pulses](/configuration/pulses) — how deployment events appear in Rootly
* [Services](/configuration/services) — link Heroku apps to the services they power
***
## Related Pages
Where Heroku build and release events appear as change events on incident timelines.
Link services to specific Heroku apps via the Heroku App Name field.
Full installation guide plus the Run Command workflow action.
# Incident Causes
Source: https://docs.rootly.com/configuration/incident-causes
Track root causes across incidents to surface systemic patterns, prioritize reliability work, and give retrospectives a shared, customizable vocabulary.
## Overview
**Incident Causes** are the shared vocabulary your team uses to describe *why* an incident happened. Where [Severity](/configuration/severities) captures how bad an incident was and [Types](/configuration/incident-types) captures what category it fell into, Causes capture the underlying failure mode — `Third-party outage`, `Configuration drift`, `Deployment regression`, `Insufficient monitoring`.
Causes are the field most retrospectives circle back to. Their real value shows up over the long term: three months of tagged Causes reveals whether your team is losing time to the same failure modes repeatedly, and gives reliability planning something concrete to point at.
***
## How Incident Causes Are Used
Unlike Severity or Environment (set at incident creation), Causes are typically populated **during the retrospective process** — after mitigation, when the responding team has enough evidence to say what actually went wrong. The field is a multi-select because most real incidents have more than one contributing cause.
| Feature | How Causes are used |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Retrospective form** | The Causes field is added to the [Incident Retrospective Form](/configuration/built-in-forms) so responders pick Causes during the Gather & Confirm Data step. This is where most Causes get set. |
| **Metrics + reporting** | Causes surface as a top-level filter in metrics dashboards. "Causes over the last 90 days" is one of the most-referenced reliability planning reports. |
| **[Workflow conditions](/workflows/conditions)** | Filter workflows on Cause. Common patterns: auto-add a specific responder team when `Third-party outage` is tagged, or trigger a supplemental review workflow when `Insufficient monitoring` is tagged. |
| **Retrospective templates** | Reference Causes in template Liquid — for example, a `{% if incident.causes contains 'Data integrity' %}` block that expands into a data-loss impact section. |
| **API + Liquid references** | Causes are available as `{{ incident.causes }}` (names) and `{{ incident.cause_ids }}` (IDs) in workflow templates, retrospective templates, and API payloads. |
Because Causes are the primary input to reliability planning, **the shape of your Cause list directly shapes what your team can improve on**. An overly generic list (`Bug`, `Human Error`) hides the actual failure modes; an overly granular one (`OAuth expiry on service X`) splinters data across too many buckets to see patterns.
***
## Choosing Your Cause Taxonomy
Causes should describe **failure modes**, not incidents. The distinction matters — "Payment API returned 500s" is an incident description; `Third-party outage` and `Insufficient retry logic` are causes.
### How Many Causes
Most teams land on **8–15 causes**. Fewer and everything collapses into `Other`. More and the causes stop being meaningfully different — responders default to the top-of-picker choices, and metrics lose signal.
If a Cause hasn't been used in 90 days, retire it. If a single Cause accounts for more than 25% of incidents over 90 days, it's probably too broad and needs to be split.
### Common Cause Categories
Causes that describe how systems broke, regardless of what the trigger was.
| Cause | When to use |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **Third-party outage** | An external service (Stripe, Twilio, an SSO provider, a cloud provider) failed and cascaded. |
| **Deployment regression** | A recent release caused the incident. Recovery usually involves rollback. |
| **Configuration drift** | A settings change (feature flag, DNS, environment variable) caused the incident. Often intentional, unintentionally impactful. |
| **Capacity / scaling** | Traffic or workload exceeded provisioned capacity — auto-scaling failed to keep up, or wasn't configured. |
| **Data integrity** | Data loss, corruption, or unintended exposure occurred. Almost always warrants a dedicated retrospective section. |
| **Race condition** | Concurrent operations produced a wrong result. Hard to reproduce, easy to hand-wave, tag explicitly so you can track. |
Causes that describe what your team could have done differently before the incident.
| Cause | When to use |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| **Insufficient monitoring** | The team didn't know something was broken until a customer reported it. |
| **Insufficient alerting** | Monitors existed, but nobody was paged in time. Threshold too high, wrong severity, alert going to a stale channel. |
| **Runbook gap** | The responder didn't have documented steps for this scenario. Add to the retrospective's action items. |
| **Test coverage gap** | Code that broke wasn't covered by tests that would have caught the failure mode. |
| **Change management** | A change was rolled out without proper review, review didn't catch the issue, or rollout process didn't include a safe rollback path. |
Causes that describe factors outside the team's direct control.
| Cause | When to use |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **Vendor incident** | Different from third-party outage — this is a vendor-side bug or change that impacted your system, not just their infrastructure being down. |
| **Regulatory / compliance change** | An external requirement changed, and your systems weren't updated in time. |
| **User-triggered / expected behavior** | The incident wasn't a bug — a customer's usage pattern crossed a threshold that should have been documented or bounded. |
***
## Creating Incident Causes
Manage Causes from **Configuration → Incident Causes** in the Rootly dashboard sidebar. (The Catalogs section is for service/component catalogs from tools like Backstage and Cortex — it does not create incident causes.)
In the Rootly sidebar, navigate to **Configuration → Incident Causes**. The page lists every cause already defined for your organization.
Click **Add New** (or the equivalent create button at the top of the list). Fill in:
The display label that responders see on the incident form (for example, `Database deadlock`, `Third-party outage`, `Deployment regression`).
Optional context shown when the cause is selected. Best used to disambiguate similar-sounding causes.
Optional visual tag for dashboards and reports.
The **Slug** is generated automatically from the Name by lower-casing and hyphenating — used in Liquid references and the API.
Click **Save**. The new cause becomes immediately available as an option on the incident form's **Causes** multi-select field for all team members.
Causes are multi-select per incident — responders can attach more than one cause when the root cause is genuinely shared between failure modes (for example, `Third-party outage` and `Insufficient monitoring`). Keep the list short and orthogonal to encourage selection rather than freeform notes.
***
## Field Type
**Incident Causes** is a **multi-select** field type only. Every incident can have zero, one, or many causes attached — reflecting the reality that most incidents have multiple contributing factors.
***
## Configuring Cause Attributes
Each Cause can be configured with the attributes below. All are available in Liquid syntax for use in workflows, retrospective templates, and status page updates.
Unique identifier assigned automatically by Rootly on creation. **Not customizable.** Used in Liquid references and API calls.
```liquid theme={null}
{{ incident.cause_ids }}
{%- comment -%} first cause {%- endcomment -%}
{{ incident.raw_causes[0] | get: 'id' }}
```
The display name shown throughout the Rootly UI. Fully customizable — pick names that describe failure modes, not incident descriptions.
```liquid theme={null}
{{ incident.causes }}
{{ incident.raw_causes[0] | get: 'name' }}
```
Auto-generated by lower-casing and hyphenating the name. Used in Liquid references and stable across name changes.
```liquid theme={null}
{{ incident.cause_slugs }}
{{ incident.raw_causes[0] | get: 'slug' }}
```
Additional context shown alongside the Cause in the UI. Best used to disambiguate similar-sounding Causes — for example, "Third-party outage: use when the external service itself is down. Use Vendor incident for cases where the vendor is up but their code introduced a bug in your system."
```liquid theme={null}
{{ incident.raw_causes[0] | get: 'description' }}
```
Six-digit hex color code used for Cause-tinted UI accents and metrics-graph color coding. Group related causes with similar shades (for example, all "system" causes in blue, all "process" causes in orange).
```liquid theme={null}
{{ incident.raw_causes[0] | get: 'color' }}
```
Rootly expects six-digit hex codes (for example, `#c4231c`). Use a color picker if you're not sure — [color-hex.com](https://www.color-hex.com/) is a common choice.
Iterating over all Causes on an incident (for a Liquid template in a retrospective or workflow message):
```liquid theme={null}
{% for cause in incident.raw_causes %}
- {{ cause.name }}: {{ cause.description }}
{% endfor %}
```
***
## Best Practices
* **Populate Causes during the retrospective, not at incident creation.** At creation time you don't know what caused the incident — you know a symptom. Wait until mitigation is done and the responding team has enough evidence to attach real causes.
* **Design Causes to describe failure modes.** `Payment API returned 500s` is an incident description; `Third-party outage` and `Insufficient retry logic` are causes. The rewrite test: if the Cause could describe two different incidents in the same category, it's a good failure-mode Cause.
* **Encourage multi-select.** Most real incidents have more than one cause. A single-cause tagging pattern usually means responders are collapsing complex root causes into whichever tag is dominant, which loses signal.
* **Keep the list short and orthogonal.** Aim for 8–15 causes. If two Causes overlap conceptually (for example, `Deploy failure` and `Deployment regression`), merge them. If a Cause hasn't been used in 90 days, archive it.
* **Retire and split based on data.** Every quarter, look at Cause frequency. Rare Causes (\<5% of incidents) get archived; dominant Causes (>25% of incidents) get split into more specific failure modes.
* **Pair Causes with action items.** Cause tagging without follow-up work isn't reliability improvement — it's data collection. Each recurring Cause should have at least one open action item aimed at reducing its frequency.
***
## Troubleshooting
Confirm the Cause is enabled under Configuration → Incident Causes. Archived Causes remain visible on historical incidents but don't appear as options on new incidents. Also check whether team-level restrictions are in play — some teams scope which Causes their responders can select.
Two common causes: (1) responders are defaulting to a single Cause because the list is too long or badly ordered — reorder so most-common Causes are at the top; (2) responders aren't populating Causes at all because the field isn't on the retrospective flow. Add the Causes field to the [Incident Retrospective Form](/configuration/built-in-forms) so it appears in the Gather & Confirm Data step.
Metrics queries filter by the Cause `slug`, not name. Renaming a Cause keeps the slug stable, so historical incidents remain grouped correctly. If a report is grouping incorrectly after a rename, refresh the dashboard cache — some reports lag one query cycle after configuration changes.
The workflow's trigger needs to be **Causes Added** (or **Causes Updated**), and the run conditions need to reference the specific Cause you're tagging. See [Workflow Conditions](/workflows/conditions) for the operator reference — Causes is a multi-select field, so use `contains any of`, not `is`.
They shouldn't. Deleting a Cause keeps the historical association intact on incidents that had it tagged; the Cause name just won't render on the current UI (it appears as archived). If you're seeing Causes disappear entirely from historical incidents, contact support — that's not expected behavior.
***
## Frequently Asked Questions
**Type** captures *what kind of thing* the incident is — UI Bug, Infrastructure, Security Event. **Cause** captures *why the incident happened* — Third-party outage, Configuration drift, Insufficient monitoring. Type is usually set at incident creation; Cause is usually set during the retrospective. See [Incident Types](/configuration/incident-types) for the Type reference.
After. During an active incident, responders don't yet know what caused the issue — they know symptoms. Wait until mitigation is done and the responding team has enough evidence. Most teams populate Causes as part of the retrospective template.
Most teams land on 8–15. Fewer and everything collapses into `Other`. More and the causes stop being meaningfully different in practice. Audit quarterly and archive rare Causes (\<5% usage).
Yes. Causes can be added programmatically via the incident update API and by workflow actions (Update Incident action → set Causes). This is useful for auto-tagging based on integration data — for example, automatically add `Third-party outage` when a specific external monitor triggered the incident.
The Causes list is org-wide, but teams can restrict which Causes their responders can select. A shared Cause list with team-specific defaults is usually cleaner than maintaining separate lists per team.
No. Test incidents (declared via `/rootly test`) are excluded from production metrics regardless of Cause. This is a Kind-level behavior; see [Incident Kind](/configuration/incident-kind) for the full exclusion matrix.
Yes. Add the Causes field to the [Incident Retrospective Form](/configuration/built-in-forms) and mark it required. Since the form runs during the Gather & Confirm Data step, the retrospective can't advance past that step without at least one Cause selected.
***
## Related Pages
Where most Causes get populated. The retrospective template is your primary Cause-collection surface.
Use Causes in workflow conditions to trigger auto-responses (add responder team, spawn action items) when specific failure modes are tagged.
The what-kind-of-incident field, distinct from Cause (why-it-happened). Read this to disambiguate the two.
# Incident Kind
Source: https://docs.rootly.com/configuration/incident-kind
The Incident Kind property is the immutable classification that decides how an incident behaves, which workflows fire, and status page eligibility.
## Overview
The **Kind** property determines the classification and structural behavior of an incident at the time it is created. It governs workflow triggers, lifecycle expectations, status page eligibility, and whether the incident contributes to production metrics.
Kind is a **fixed property** — it's immutable after declaration. Choosing the right kind at creation matters because there's no way to convert a Test Incident into a Normal Incident, or a Scheduled Maintenance into a standard incident, after the fact.
Kind answers "what kind of incident is this structurally?" — distinct from [Incident Types](/configuration/incident-types), which answers "what category does this incident fall into for our organization?". Types are fully customizable; Kind is system-defined and fixed.
***
## Available Kinds
| Kind | Description | Data Value |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| **Incident** | Standard production incidents declared via `/rootly new`. These represent real operational events requiring coordinated response. They trigger normal workflow execution and are eligible for publication on status pages (when not cancelled). | `normal` |
| **Sub Incident** | Child incidents created under a parent incident using `/rootly sub`. They inherit contextual linkage from the parent incident and are useful for tracking parallel workstreams or related issues within a broader event. Eligible for status page publication (when not cancelled). | `normal_sub` |
| **Test Incident** | Training or simulation incidents declared via `/rootly test`. They behave functionally like normal incidents but are excluded from status page publication and production metrics. Primarily used to test workflows, integrations, and team processes safely. | `test` |
| **Sub Test Incident** | Child incidents created under test incidents. Used exclusively for training and simulation. Not eligible for status page publication. | `test_sub` |
| **Backfill Incident** | Retroactively documented incidents created after resolution has already occurred. Backfill incidents are automatically created in a **resolved** state. Workflows triggered on Incident Created still execute, but active lifecycle stages such as Started or Mitigated are skipped. Eligible for status page publication (when not cancelled). | `backfilled` |
| **Scheduled Maintenance** | Planned maintenance windows declared via `/rootly maintenance`. These incidents follow a distinct maintenance lifecycle separate from normal incident statuses. Used to proactively communicate planned changes via status pages. | `scheduled` |
| **Sub Scheduled Maintenance** | Child incidents created under scheduled maintenance incidents. These follow the same maintenance lifecycle as their parent scheduled incident. | `scheduled_sub` |
Normal incidents default to **in\_triage** status when the team setting "Incidents must start in the In-Triage status" is enabled. Otherwise, they default to **started** status upon creation.
***
## Behavior Differences at a Glance
Each Kind selects a different mix of behavior — knowing the mix up front prevents the most common mistakes (declaring a test incident that pages on-call, declaring a normal incident for a maintenance window).
| Kind | Triggers Workflows | Counts in Metrics | Eligible for Status Page | Has Active Lifecycle (Started/Mitigated) |
| ------------------------- | ------------------ | ----------------- | ------------------------ | ---------------------------------------- |
| Incident (`normal`) | Yes | Yes | Yes (when not cancelled) | Yes |
| Sub Incident | Yes | Yes | Yes (when not cancelled) | Yes |
| Test Incident | Yes | No | No | Yes |
| Sub Test Incident | Yes | No | No | Yes |
| Backfill Incident | Yes (on creation) | Yes | Yes (when not cancelled) | No (created already resolved) |
| Scheduled Maintenance | Yes | No | Yes | No (uses maintenance lifecycle) |
| Sub Scheduled Maintenance | Yes | No | Yes | No (uses maintenance lifecycle) |
***
## Choosing the Right Kind
* **Use `normal` (Incident)** for the vast majority of real production issues — anything you'd want metrics, retrospectives, and on-call paging for.
* **Use `test`** when validating workflows, training a new team member, or running a tabletop. Test incidents fire workflows so you can verify automation end-to-end, but they don't contaminate metrics or page customers via status pages.
* **Use `backfilled`** when documenting an incident that already happened and was resolved outside of Rootly. The incident lands in `resolved` status; workflows that key off Incident Created still run, but Started/Mitigated transitions are skipped because they're already in the past.
* **Use `scheduled`** for planned maintenance windows you want to communicate via status pages. Scheduled Maintenance follows a different lifecycle (Scheduled → In Progress → Completed) — don't try to fit a maintenance window into the normal Started/Mitigated/Resolved flow.
* **Use `normal_sub`, `test_sub`, or `scheduled_sub`** when tracking a parallel workstream under an existing parent incident. Sub-incidents inherit the parent's context and are tracked together.
***
## Best Practices
* **Pick the kind carefully on creation — it's immutable.** If you accidentally declare a real production incident as a Test Incident, you'll need to cancel it and re-declare as `normal`. The metrics and status page implications of getting this wrong are non-trivial.
* **Default to `/rootly new` for ambiguous situations.** A real incident accidentally tagged Test is invisible in metrics. A test accidentally tagged Normal is recoverable by cancelling. Err toward the recoverable failure mode.
* **Lock down `/rootly maintenance` to operators who actually run maintenance.** Status-page-publishing Scheduled Maintenance incidents are customer-facing — limit who can publish.
* **Use Sub Incidents for workstream tracking, not categorization.** If you find yourself creating sub-incidents to label severity or component, you want [Incident Types](/configuration/incident-types) or [Custom Fields](/configuration/custom-fields) instead.
***
## Troubleshooting
Test incidents do trigger workflows by default — if you have a workflow that pages on-call on Incident Created without a Kind filter in its run conditions, it will fire for test incidents too. Scope the workflow to real incidents by filtering on Kind. If you want to page for both top-level incidents *and* sub-incidents, use `Kind is one of: Incident, Sub Incident` (which corresponds to `normal, normal_sub`). If you only want to page for top-level incidents, use `Kind is: Incident` (which corresponds to `normal`) — this excludes sub-incidents, which are often used for parallel workstreams under a parent that already paged.
Check the incident's Kind. Test (`test`, `test_sub`) and Scheduled Maintenance (`scheduled`, `scheduled_sub`) kinds are excluded from production metrics by design. If the incident was accidentally created as a Test, cancel it and re-declare with `/rootly new`.
Kind is immutable. The only path is to cancel the existing incident and declare a new one with the correct kind. If the incident has a long timeline you don't want to lose, document the original incident ID in the new one's description so the history stays traceable.
By design — backfill incidents are created already in `resolved` state, so the Started lifecycle stage is skipped. Only workflows triggered on Incident Created run for backfilled incidents. If you need a workflow to run for backfills, key it off Incident Created and add a `Kind is backfilled` condition.
***
## Frequently Asked Questions
No. The **Kind** property is immutable after an incident is created. It determines the incident's structural behavior, workflow triggers, and status page eligibility at creation time. If you need a different kind, you must create a new incident with the desired kind.
For example, you cannot convert a **Test Incident** to a **normal** incident, or change a **Scheduled Maintenance** to a standard incident after creation.
**Kind** is a fixed, system-defined property that controls how an incident behaves structurally (for example, `normal`, `test`, `scheduled`). It cannot be customized and determines workflow execution, lifecycle, and status page eligibility.
**Type** ([Incident Types](/configuration/incident-types)) is a configurable property that allows organizations to define their own categorization taxonomy (for example, "UI Bug", "Infrastructure Failure", "Security Event"). Types are fully customizable and can be used for filtering, reporting, and workflow conditions, but they don't affect the fundamental behavior of the incident.
Think of **Kind** as "what kind of incident is this structurally?" and **Type** as "what category does this incident fall into for our organization?"
Yes. Test incidents trigger workflows just like normal incidents, allowing you to test workflow automation safely without affecting production metrics or status pages. However, test incidents are excluded from status page publication and production reporting.
This makes test incidents ideal for:
* Validating workflow configurations
* Training team members on incident response
* Testing integrations without production impact
Backfill incidents are designed to document incidents retroactively — after they've already been resolved. Since the incident has already concluded, they are created directly in a **Resolved** state.
Workflows triggered on **Incident Created** still execute for backfill incidents, but active lifecycle stages (like **Started** or **Mitigated**) are skipped because the incident is already resolved.
No. Scheduled Maintenance incidents follow a separate lifecycle with dedicated statuses (**Scheduled**, **In Progress**, **Completed**). They cannot use standard incident statuses like **Started**, **Mitigated**, or **Resolved**.
This separation exists because maintenance windows have different lifecycle requirements than unplanned incidents.
***
## Related Pages
The companion fixed property — controls lifecycle stage and progression rules.
Customizable categorization, distinct from Kind.
The umbrella page for all incident properties and configuration.
# Configuring Incident Roles
Source: https://docs.rootly.com/configuration/incident-roles
Define and manage incident response roles with clear responsibilities, tasks, and hierarchies to ensure effective team coordination during incidents.
When the next incident hits, your team should feel prepared. With Incident Roles, you can quickly and efficiently assign responsibilities to your team and define the hierarchy of command.
A swift response will help reduce the impact. By adding descriptions and tasks ahead of time, you can ensure your team knows exactly what to do.
## Built-in Roles
Rootly comes with four roles that are essential for effective incident response.
### Commander
The individual responsible for the overall management of the incident from start to finish. Delegation of tasks across the response team and final decision-making authority.
### Communications Lead
The individual responsible for managing internal and external communications to stakeholders outside of the response team.
### Executive Sponsor
The individual responsible for complex decision making, often used for high-severity or sensitive incidents.
### Retrospective Owner
The individual responsible for driving the post-incident retrospective process to completion.
## Add an Incident Role
Go to **Configuration** > **Roles.**
Select **+ New Role.**
Add a name, description, and a list of responsibilities for the role.
**Example**
Name: Commander
Description: The person who takes charge of the incident, assigns tasks, and has the deciding vote on proceeding.
Responsibilities:
* Declare and classify the severity of the incident in Rootly
* Assign roles (for example, Communications Lead, Subject Matter Experts)
* Lead regular status updates in the Slack incident channel
* Escalate to executives or external teams if needed
* Make "go/no-go" decisions on customer communications and mitigation steps
Toggle "make this role optional" if it's not required for every incident.
Switch to the *Advanced settings* tab to adjust the incident permission set and "allow multiple users" to be assigned this role.
Select **Create Role** to continue. Tasks can be added after a role has been created.
## Add Tasks to an Incident Role
Go to **Configuration** > **Roles**.
Find the role you want to add tasks to in the table. Click the pencil icon on the left side to edit.
Switch to the Tasks tab to see existing tasks. Click **+ Add Task**.
Add a name (required) and description. Set the Priority to low, medium, or high.
Click **Add** to save.
Example
Name (required): Declare and classify the severity of the incident in Rootly
Description: Review the incident alerts, customer reports, and system status to assign an incident severity.
Priority: High
## Edit an Incident Role
Go to **Configuration** > **Roles.**
Find the role you want to edit in the table. Click the pencil icon on the left side to edit.
There are three tabs:
**Basics**
Auto-generated by Rootly. Use it when referencing the role via API or Liquid.
The role's display name — shown in the responder picker and the role assignment audit trail.
A short summary of the role. Appears next to the name in role pickers.
What the role is expected to do during an incident. Rendered on the responder's role card.
When enabled, responders can leave this role unassigned on incidents where it isn't needed.
**Tasks**
Manage existing tasks or add new ones for this role.
**Advanced**
Which incident actions the role is authorized to take.
When enabled, more than one responder can hold this role on the same incident simultaneously.
Once the desired edits are complete, click **Update** to save.
## Delete an Incident Role
Go to **Configuration** > **Roles.**
Find the role you want to edit in the table. Click the trashcan icon on the left side to delete.
Deleting an incident role will also remove its associated data. This can't be undone. Select **Delete** to delete the role and all associated data, or click **Discard changes** to keep the role.
## **Get Help**
For help, use the slash command **/rootly help** in Slack or email [support@rootly.com](mailto:support@rootly.com).
***
## Related Pages
How the roles configured here get used during incident response.
Roles are typically assigned to team members — Teams is the underlying identity primitive.
The umbrella page covering incident properties and configuration surface.
# Incident Status
Source: https://docs.rootly.com/configuration/incident-status
The Incident Status lifecycle — Triage, Started, Mitigated, Resolved, Closed, Cancelled — with transition rules, timestamps, and sub-statuses.
## Overview
The **Status** property defines the lifecycle stage of an incident and governs how it progresses from investigation through closure. Status transitions are validated to preserve chronological and logical integrity — you can't skip from Triage to Resolved, and `mitigated_at` can never precede `started_at`.
Status is a **fixed property**: the set of statuses (Triage, Started, Mitigated, Resolved, Closed, Cancelled) is system-defined and can't be customized. If you need additional state inside a status, use [Sub-Statuses](#sub-statuses) (this page) or [Custom Statuses](/configuration/custom-statuses).
Scheduled Maintenance incidents follow a separate lifecycle with their own statuses — see [Scheduled Maintenance Statuses](#scheduled-maintenance-statuses) below.
***
## Standard Incident Statuses
| Status | Description | Data Value |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| **Triage** | An investigative state used to determine whether an issue should escalate into an active incident. This allows teams to evaluate signals before formally beginning response. Timestamped at `in_triage_at`. | `in_triage` |
| **Started** | Marks the official activation of incident response. This is the primary active state during which coordination, mitigation, and communication occur. Timestamped at `started_at`. | `started` |
| **Mitigated** | Indicates that user-facing impact has been halted or reduced, but remediation, validation, or cleanup work may still be ongoing. Timestamped at `mitigated_at`, which must be after or equal to `started_at`. | `mitigated` |
| **Resolved** | Signifies the completion of active incident response. At this stage, service impact has ended and retrospective processes typically begin. Timestamped at `resolved_at`. | `resolved` |
| **Closed** | Optional terminal status (team-configurable) used to mark incidents as fully finalized after review. **Requires the incident to already be in Resolved status.** Timestamped at `closed_at`. | `closed` |
| **Cancelled** | Terminal status used for false positives or duplicate incidents. Cancelling prevents further lifecycle progression unless the incident is reopened. Timestamped at `cancelled_at`. | `cancelled` |
***
## Terminal Statuses
**Resolved**, **Closed**, and **Cancelled** are terminal statuses. They prevent further lifecycle progression unless the incident is explicitly reopened to **Started**, which restarts active response tracking.
Cancellation is for incidents that turn out to be false positives or duplicates — they shouldn't appear in production metrics or status pages. Resolution and closure are for incidents that ran their full course.
***
## Status Transition Rules
**Lifecycle Constraints**
* Incidents in **Triage** or **Cancelled** cannot transition directly to **Mitigated**, **Resolved**, or **Closed**.
* **Closed** can only be reached from **Resolved**.
* Terminal statuses (**Resolved**, **Closed**, **Cancelled**) may be reopened to **Started**.
The constraints exist because Rootly's metrics and retrospective workflows assume an incident in a terminal status actually ran through active response. Skipping Started would produce nonsense lifecycle durations (for example, MTTR of zero).
***
## Timestamp Validation Rules
**Chronological Integrity**
Status timestamps are validated to preserve lifecycle order:
* `mitigated_at` ≥ `started_at`
* `resolved_at` ≥ `started_at`
* `closed_at` ≥ `started_at`
If you attempt to set a timestamp that violates this order — for example, backdating `mitigated_at` to before `started_at` — Rootly rejects the change and surfaces a validation error.
***
## Sub-Statuses
When enabled via team configuration, statuses may contain **sub-statuses** for more granular tracking within a parent lifecycle stage.
For example:
* **Started** may include multiple Active sub-statuses (up to 8 per team).
* **Resolved** may include structured post-incident stages such as "Retrospective".
Sub-statuses let teams enforce structured workflows, capture finer lifecycle detail, and introduce controlled progression within major stages. Workflows that trigger on **Status Updated** fire when the parent status changes, regardless of sub-status transitions — but sub-statuses are available in workflow **run conditions**, so you can write workflows that only fire on a specific sub-status.
See [Custom Statuses](/configuration/custom-statuses) for the full sub-status configuration guide.
***
## Scheduled Maintenance Statuses
Scheduled Maintenance incidents follow a separate lifecycle from standard incidents. Their statuses describe the state of the maintenance window itself, not a response process.
| Status | Description | Data Value |
| --------------- | ------------------------------------------------------------------------------------------------------ | ------------- |
| **Scheduled** | Indicates that the maintenance window has been planned and formally created but has not yet begun. | `scheduled` |
| **In Progress** | Indicates that maintenance work is actively underway. | `in_progress` |
| **Completed** | Indicates that maintenance activities have concluded successfully. This is the default terminal state. | `completed` |
Scheduled Maintenance incidents cannot use standard incident statuses (Started, Mitigated, Resolved). The separation exists because maintenance windows have different lifecycle requirements than unplanned incidents.
For more on when to use Scheduled Maintenance, see [Incident Kind](/configuration/incident-kind).
***
## Best Practices
* **Use Triage for ambiguous signals, not for active incidents.** Triage is the "is this even an incident?" stage. Once a responder commits to active mitigation, move it to Started so the lifecycle clock starts.
* **Default to Resolved over Closed for most teams.** Closed adds an extra review step that's only worth the overhead if you have a formal post-incident review gate. If you don't, leave Closed disabled — Resolved is the natural terminal state.
* **Reserve Cancelled for false positives.** Don't use Cancelled to "clean up" a real incident that ended up being minor — that incident still belongs in metrics. Cancelled is for incidents that were never real (duplicates, test fires from monitoring tools).
* **Use sub-statuses for workflow gating, not for taxonomy.** If you want to label incidents as "Investigating", "Mitigating", "Verifying", sub-statuses are the right tool. If you want to label incidents as "Customer Impact", "Infrastructure", "Security" — that's [Incident Types](/configuration/incident-types) or [Custom Fields](/configuration/custom-fields).
* **Reopen instead of re-declaring when an incident recurs.** Reopening preserves the original timeline, action items, and retrospective context. Re-declaring fragments the history into two records.
***
## Troubleshooting
By design — incidents in Triage haven't entered active response yet, so resolving them would produce a zero-duration lifecycle. Move the incident to Started first (even briefly), then to Mitigated and Resolved. If the incident was a false positive that never warranted response, Cancel it instead.
Status timestamps must follow `started_at` ≤ `mitigated_at` ≤ `resolved_at` ≤ `closed_at`. If you're backdating Mitigated to be earlier than Started, the system blocks the save. Either adjust Started earlier or move Mitigated forward to match the actual order of events.
Closed is an optional terminal status controlled by team configuration. If your team hasn't enabled it, Resolved is the only terminal status available. Ask an admin to enable Closed in team settings if you need a two-step Resolved → Closed flow.
Working as designed. **Sub-status-only transitions do not emit the Status Updated trigger.** The trigger fires only when the *parent* status changes (for example, Started → Mitigated). If your incident stays in Started and the sub-status moves from "Investigating" to "Verifying," no Status Updated event is dispatched, and no workflow triggered on Status Updated will run — regardless of what run conditions you add.
Run conditions can only *filter* workflows that were already triggered. So an "only run when sub-status is Verifying" condition narrows a Status Updated workflow to just the parent transitions that also happen to land on the Verifying sub-status; it does not create a trigger for later Verifying → some-other-sub-status shifts inside the same parent status.
If you need automation on sub-status transitions specifically, the current recommendation is to structure your process so sub-status transitions coincide with meaningful parent-status transitions (making the workflow trigger on the parent change), or to run the automation manually via a Slack command workflow.
Reopening to Started overwrites `started_at` to the reopen time. The original `started_at`, `mitigated_at`, and `resolved_at` are preserved in the incident timeline events but not the top-level fields. If you need the original timing for reporting, query the timeline events for the historical status transitions.
***
## Frequently Asked Questions
Yes. Terminal statuses (**Resolved**, **Closed**, **Cancelled**) can be reopened to **Started** status. This restarts active response tracking and allows the incident to progress through its lifecycle again.
Reopening is useful when:
* An incident recurs after resolution
* Additional investigation reveals the original resolution was incomplete
* A cancelled incident turns out to be a real issue
**Resolved** indicates that active incident response has completed and service impact has ended. At this stage, retrospective processes typically begin.
**Closed** (when enabled via team configuration) is an optional terminal status used to mark incidents as fully finalized after review. It requires the incident to already be in **Resolved** status and provides a clear distinction between incidents that are resolved but still under review versus incidents that are completely closed.
Not all teams use the Closed status. If it's not enabled, **Resolved** serves as the terminal status.
Status transitions are validated to preserve logical lifecycle progression. Incidents in **Triage** or **Cancelled** cannot skip directly to **Mitigated**, **Resolved**, or **Closed** because these statuses require the incident to have been actively responded to (in other words, in **Started** status first).
To resolve an incident that's in Triage, you must first transition it to **Started**, then proceed through **Mitigated** (optional) to **Resolved**.
Rootly validates timestamp relationships to maintain chronological integrity. If you attempt to set `mitigated_at`, `resolved_at`, or `closed_at` to a time before `started_at`, the system will reject the change and display a validation error.
Timestamps must follow this order:
* `started_at` ≤ `mitigated_at` ≤ `resolved_at` ≤ `closed_at`
This ensures incident timelines remain accurate and reportable.
Sub-statuses provide granular tracking within parent statuses (like **Started** or **Resolved**) but don't change the fundamental status-based workflow triggers. Workflows that trigger on "Status Updated" will still fire when the parent status changes, regardless of sub-status transitions.
However, you can use sub-statuses in workflow **run conditions** to create more specific automation logic. For example, a workflow could run only when an incident is in **Started** status with a specific Active sub-status.
Sub-statuses are particularly useful for enforcing sequential workflows within a status.
***
## Related Pages
The companion fixed property — controls structural behavior and metrics inclusion.
Add custom sub-statuses within Triage, Started, Mitigated, and Resolved.
The full lifecycle narrative — detection through retrospective.
# Incident Types
Source: https://docs.rootly.com/configuration/incident-types
Configure custom incident type categories to classify incidents by your own taxonomy — customizable, and available in workflow conditions and metrics.
## Overview
**Incident Types** let you classify incidents by a taxonomy that matches how your organization thinks about incident categories — "UI Bug", "API Failure", "Security Event", "Internal Outage", "Customer-Facing", or whatever grouping is meaningful to your team. Types are **fully customizable**: you name them, you pick the colors, you decide how many.
Types are frequently confused with the [Kind](/configuration/incident-kind) property. The distinction matters:
| Property | Nature | Purpose |
| -------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| **Kind** | System-defined, immutable, fixed set (Incident, Sub Incident, Test Incident, Backfill, Scheduled Maintenance) | Structural — governs metrics inclusion, status-page eligibility, and workflow trigger behavior |
| **Type** | Customer-defined, editable, unbounded | Categorical — supports your organization's incident taxonomy for filtering, reporting, and routing |
Think of Kind as answering *"what kind of incident is this structurally?"* and Type as answering *"what category does this incident fall into in our organization's taxonomy?"*.
***
## How Incident Types Are Used
Like Severity, Type is a lever that other Rootly features pull on:
| Feature | How Type is used |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[Workflow conditions](/workflows/conditions)** | Filter workflows so they fire only on specific types. Common patterns: "auto-create a Jira ticket only when Type is 'UI Bug'" or "notify the security team only when Type contains 'Security Event'." |
| **Slack channel + alias notifications** | Each Type can be linked to Slack channels and user groups. Workflows use these to auto-invite the right subject-matter experts (for example, invite the frontend team on "UI Bug" types). |
| **Notify emails** | Each Type can be linked to email addresses. Useful for stakeholder groups that only care about a specific incident category — for example, a legal team on "Data Privacy" types. |
| **Retrospective templates** | Different Types can trigger different retrospective templates via workflow — a "Security Event" retrospective covers regulatory reporting, a "UI Bug" retrospective is lightweight. |
| **Metrics + reporting** | Type is a top-level filter in every metrics dashboard. Segmenting MTTR by Type helps you see whether infrastructure issues take longer to resolve than product bugs. |
| **API + Liquid references** | Type is available as `{{ incident.types }}` (names) and `{{ incident.type_ids }}` (IDs) in every workflow template, retrospective template, and API payload. |
Because Type drives so much automation, the shape of your Type taxonomy directly shapes how well your automation targets the right responders — an overly generic Type ("Bug") lands every notification with everyone, while an overly granular one ("iOS Bug on Login Screen") splinters routing until nothing has enough volume to justify its rule.
***
## Choosing a Type Taxonomy
There's no universal Type taxonomy — but there are patterns that work and patterns that don't. Use these to design or audit your team's list.
### How Many Types
Most teams land on **five to ten types**. Fewer than five and Type becomes redundant with Severity (which you already have). More than ten and calibration breaks down — responders default to whichever Type is at the top of the picker.
If you catch yourself creating a Type that answers "who owns this?" — that's what [Teams](/configuration/teams) or [Services](/configuration/services) are for. If you're creating a Type that answers "how bad is this?" — that's [Severity](/configuration/severities). Type is for **what kind of thing is broken**, not who owns it or how urgently.
### Single-Select vs Multi-Select
Type can be configured as **single-select** (one Type per incident) or **multi-select** (multiple Types per incident). Which you choose changes both the picker UX and the workflow conditions available:
* **Single-select** is simpler to reason about. Responders pick one Type; workflows filter with `is` / `is one of`. Best when your Types are mutually exclusive (an incident is a UI Bug or an Infrastructure issue, not both).
* **Multi-select** captures overlapping taxonomies. Responders can tag both "Security Event" and "Data Privacy" on the same incident; workflows filter with `contains any of` / `contains all of`. Best when Types represent aspects rather than exclusive categories.
Most teams start single-select and switch to multi-select only when they hit real overlap. Switching later is fine — historical incidents preserve their existing Type values.
### Common Taxonomies
Focus on the technical shape of the incident.
| Type | When to use |
| --------------------------- | ----------------------------------------------------------------------- |
| **Infrastructure** | Underlying services (databases, network, hosting) failed. |
| **Application Bug** | A code-level bug — regression, unhandled edge case, logic error. |
| **Performance Degradation** | System is up but slow. Not a hard failure. |
| **Third-Party Dependency** | External service (Stripe, Twilio, an SSO provider) is failing. |
| **Deployment Issue** | Caused by a bad release / rollout. Recovery is usually rollback. |
| **Configuration Error** | A settings change (feature flag, config file, DNS) caused the incident. |
| **Security Event** | Actual or potential unauthorized access, exposure, or breach. |
Focus on how the customer experiences the incident.
| Type | When to use |
| ------------------------- | ---------------------------------------------------------------------- |
| **Customer-Facing** | Users directly notice the issue. |
| **Internal-Only** | Employees affected, no customer impact. |
| **Partner / Integration** | Impacts a business partner or B2B integration, not end users. |
| **Data Integrity** | Data loss, corruption, or exposure — often overrides other taxonomies. |
| **Compliance / Legal** | Regulatory or contractual obligations triggered. |
Focus on which product area is broken. Best paired with Multi-Select so cross-product incidents can be tagged with all affected areas.
| Type | When to use |
| ----------------- | ------------------------------------------------------- |
| **Web App** | Browser-facing product. |
| **Mobile App** | iOS / Android apps. |
| **API** | Programmatic surface used by customers or integrations. |
| **Admin Console** | Internal admin tools. |
| **Data Pipeline** | Batch / streaming data infrastructure. |
| **Analytics** | Reporting, dashboards, exports. |
***
## Field Type
Configure Type as either **single-select** or **multi-select** in **Configuration → Incident Types**. The setting affects every incident going forward — historical incidents keep their existing values.
Liquid syntax differs slightly between the two modes. Single-select uses `{{ incident.types | get: '' }}` for the one value. Multi-select uses `{{ incident.raw_types[index] | get: '' }}` where `index` references a specific Type in the list. The attribute reference below covers both.
***
## Configuring Type Attributes
Each Type can be configured with the attributes below. All are available as Liquid variables for use in workflows, retrospective templates, and status page updates.
Unique identifier assigned automatically by Rootly on creation. **Not customizable.** Used in Liquid references and API calls.
```liquid theme={null}
{{ incident.type_ids }}
{{ incident.raw_types | get: 'id' }} {/* single-select */}
{{ incident.raw_types[0] | get: 'id' }} {/* multi-select, first Type */}
```
The display name shown throughout the Rootly UI. Fully customizable — pick names that match your team's operational vocabulary.
```liquid theme={null}
{{ incident.types }}
{{ incident.raw_types | get: 'name' }} {/* single-select */}
{{ incident.raw_types[0] | get: 'name' }} {/* multi-select, first Type */}
```
Auto-generated by lower-casing and hyphenating the name. Used in Liquid references and in workflow condition matches.
**Slugs regenerate when you rename a Type.** Anything referencing the old slug — workflow conditions, saved metrics dashboards, third-party integrations that filter by slug — needs to be updated after a rename.
```liquid theme={null}
{{ incident.type_slugs }}
{{ incident.raw_types | get: 'slug' }}
{{ incident.raw_types[0] | get: 'slug' }}
```
Additional context shown alongside the Type in the UI. Best used to remind responders what qualifies for each Type — for example, "Any incident affecting customer-facing surfaces (web, mobile, API)."
```liquid theme={null}
{{ incident.raw_types | get: 'description' }}
{{ incident.raw_types[0] | get: 'description' }}
```
Six-digit hex color code used for Type-tinted UI accents and metrics-graph color coding. Pick colors that are meaningful and consistent — reserving red for security-adjacent Types, for example.
```liquid theme={null}
{{ incident.raw_types | get: 'color' }}
{{ incident.raw_types[0] | get: 'color' }}
```
Rootly expects six-digit hex codes (for example, `#c4231c`). Use a color picker if you're not sure — [color-hex.com](https://www.color-hex.com/) is a common choice.
One or more Slack channels linked to the Type. **Linking alone doesn't post to the channels** — a workflow action (typically "Attached Types Channels") reads this list and performs the notification.
```liquid theme={null}
{{ incident.raw_types | get: 'slack_channels' }}
{{ incident.raw_types[0] | get: 'slack_channels' }}
```
One or more Slack user groups (aka aliases) linked to the Type. **Linking alone doesn't invite users** — a workflow action (typically "Attached Types Aliases") reads this list and performs the invitation.
```liquid theme={null}
{{ incident.raw_types | get: 'slack_aliases' }}
{{ incident.raw_types[0] | get: 'slack_aliases' }}
```
One or more email addresses linked to the Type. **Linking alone doesn't send email** — a workflow action reads this list and sends the notification.
```liquid theme={null}
{{ incident.raw_types | get: 'notify_emails' }}
{{ incident.raw_types[0] | get: 'notify_emails' }}
```
For workflow-driven use, most teams reference the flattened list:
```liquid theme={null}
{{ incident.raw_types | map: 'notify_emails' | flatten | join: ',' }}
```
***
## Best Practices
* **Design Types for automation, not documentation.** If a Type doesn't drive at least one workflow condition, alert routing, or metrics filter, it's just a label. Retire it after 90 days if it never gets used.
* **Keep Type distinct from Team, Service, and Severity.** Type is *what's broken*; Team is *who owns it*; Service is *which component is affected*; Severity is *how bad it is*. Overlapping Types with those dimensions leads to the same data being encoded four times.
* **Start single-select, switch to multi-select when overlap is genuine.** Multi-select is more flexible but harder to filter in workflow conditions (you need `contains any of` instead of `is`). Only take the added complexity when you actually have overlapping taxonomies.
* **Colors should be intuitive.** Reserve red for security / data integrity Types. Use warmer colors (orange, yellow) for customer-facing Types and cooler colors (blue, gray) for internal-only Types. Responders read the color before the label.
* **Attach Slack channels + aliases per Type, but require workflow actions to actually use them.** Same principle as Severities. Keeps notification behavior explicit and auditable.
* **Audit quarterly.** Look at Type usage over the last 90 days. Rare Types (\<5% of incidents) either need a rename to broaden their reach or removal from the picker. Dominant Types (>40%) probably need to be split.
***
## Troubleshooting
Confirm the Type is enabled under Configuration → Incident Types. Archived Types remain visible on historical incidents but don't appear as options on new incidents. If it's enabled and still missing, check whether team-level restrictions are in play — some teams scope which Types their responders can select.
Two common causes: (1) the workflow's condition uses `is` on a multi-select Type field — switch to `contains any of` (see [Workflow Conditions](/workflows/conditions) for the operator reference); (2) the Type slug was regenerated after a rename and the workflow still references the old slug. Rename-triggered slug changes are automatic; update the workflow condition to match the new slug.
Linking Slack channels to a Type doesn't cause auto-invitation on its own — a workflow with an "Attached Types Channels" action is required. Check that a workflow exists, is enabled, and has run conditions that match the Type you're testing. The Type-updated trigger is a good candidate for this workflow.
Working as designed. `{{ incident.types }}` returns a joined string; access individual Types via `{{ incident.raw_types[0] | get: 'name' }}` or iterate with `{% for t in incident.raw_types %}...{% endfor %}` when you need per-Type rendering.
Metrics query by the Type's `slug`, and slugs regenerate on rename. Saved dashboards or reports that filtered by the pre-rename slug won't match anymore. Update the dashboard filter to the new slug, or plan the rename around a natural retention boundary if that filter can't be updated cleanly.
***
## Frequently Asked Questions
Most teams land on 5-10. Fewer and Type becomes redundant with Severity. More and calibration breaks down (responders default to whichever Type is at the top of the picker). See Choosing a Type Taxonomy above for detail.
**Kind** is a fixed, system-defined property that controls structural behavior (test vs normal, backfill vs scheduled maintenance, etc.). **Type** is a customer-defined categorical property for your organization's taxonomy. Kind is set once at creation and is immutable; Type can be changed anytime. See [Incident Kind](/configuration/incident-kind) for the full Kind reference.
Yes. Type is fully mutable — change it via the incident details page or a workflow action. Changes are logged in the incident timeline. This is different from Kind, which is immutable after declaration.
Yes — Types belong to a Team. Each team maintains its own Type list, and the picker on an incident form shows the Types defined for that incident's team. If your workspace uses multiple teams, define the Types each team actually uses; there's no single org-wide Type list.
Historical incidents keep the Type value they were created with, even after the Type is deleted from the picker. Only new incidents lose access to the removed Type. For matrix overhauls, archive rather than delete so historical data stays readable.
Yes. Type is one of the most common fields used in workflow run conditions. See [Workflow Conditions](/workflows/conditions) for the operator reference — Type is often used with `contains any of` in multi-select mode.
No. Test incidents (declared via `/rootly test`) are excluded from production metrics regardless of Type. This is a Kind-level behavior; see [Incident Kind](/configuration/incident-kind) for the full exclusion matrix.
***
## Related Pages
The fixed counterpart — governs structural incident behavior. Read this to disambiguate Kind from Type.
The other most-used incident property. Type and Severity are the two dimensions most workflows filter on.
Use Type in workflow run conditions to route different incident categories to different response processes.
# Kubernetes Configuration
Source: https://docs.rootly.com/configuration/kubernetes
Configure Kubernetes integration to monitor cluster resources and automatically generate pulses from pod, deployment, and service changes.
The Kubernetes integration watches events in your clusters — pod crashes, deployment updates, service changes, and more — and records them as [pulses](/configuration/pulses) in Rootly. Pulses give responders infrastructure context directly on the incident timeline, so you can quickly answer the question "what changed?" when investigating an incident.
Kubernetes integration can watch different resources and create pulses.
## How It Works
Cluster events are captured by [kubewatch](https://github.com/robusta-dev/kubewatch), an open-source Kubernetes watcher that you deploy in your cluster, and forwarded to a unique webhook URL that Rootly generates for your workspace. You choose which resource types kubewatch monitors — deployments, pods, services, nodes, jobs, namespaces, and other resource types are supported.
Each event appears as a pulse with a summary in the form `[k8s][{resource kind}] {event text}`, along with labels and refs identifying the resource and namespace.
## Linking Pulses to Services
Rootly automatically associates Kubernetes pulses with your [services](/configuration/services) by matching the **Kubernetes Deployment Name** field on the service against the event's resource name. The match is partial, so a service named `api-server` will match events from any deployment containing `api-server` in its name. Set this field on each service you want correlated with cluster events.
If pulse volume gets noisy, narrow the resource types enabled in your kubewatch configuration — disabling low-signal resources like secrets and ConfigMaps significantly reduces noise.
Ready to configure the Kubernetes integration? See [Kubernetes integration setup](/integrations/kubernetes).
## Related pages
* [Kubernetes integration setup](/integrations/kubernetes) — step-by-step installation and troubleshooting
* [Pulses](/configuration/pulses) — how change events appear in Rootly
* [Services](/configuration/services) — link cluster events to the services they affect
***
## Related Pages
Where Kubernetes cluster events appear as change events on incident timelines.
Link services to Kubernetes deployment names so pulses correlate with the right incident context.
kubewatch installation, resource selection, and troubleshooting.
# Incident response playbooks overview
Source: https://docs.rootly.com/configuration/playbooks
Create and manage response playbooks that automatically attach to incidents based on conditions like severity, service, or team to guide resolution efforts.
## Overview
Playbooks are a great way to create a document that can help speed incident resolution. Think of them as a collection of simple instructions to empower someone to resolve a particular incident (even if they have minimal experience).
Playbooks are **automatically attached** to incidents when they **match a configured condition** (for example: severity, service, functionality, team impacted). If you have Playbooks or supported documentation hosted internally, you can link to them in the "External URL" field and provide detailed instructions in the content field.
On the above example, the **Database outage playbook** will be attached to any incident with the **SEV2 severity or the** **customers-postgresql-db** **microservices.** Please note that this is all OR logic currently, meaning this playbook will be attached to an incident that has just one of those matching conditions, such as SEV2 severity for example.
Additionally, at the bottom of the Playbook details page you have the ability to append any relevant tasking that needs to be done during the incident.
Playbooks are a great way to prevent a single person from becoming the de facto expert on how to resolve a particular problem. One person shouldn't be the only one who knows how to bring a critical system back online.
***
## Related Pages
Walk-through of how playbooks auto-attach based on incident type and other properties.
The adjacent automation surface — event-driven actions that can complement playbooks during response.
The umbrella page covering incident properties and configuration surface.
# Publishing Incidents to Status Pages
Source: https://docs.rootly.com/configuration/publishing-incidents
Publish incidents to your status pages from Slack or the Rootly web UI to keep customers and internal teams updated as an incident progresses.
Publishing an incident to a [status page](/configuration/status-pages) shares its details and progress with stakeholders, keeping affected users informed while you work.
Publishing is deliberate, not automatic. An incident attached to a service or functionality on your status page is **not** published on its own — someone on the response team writes and publishes each update, so every message is reviewed before customers see it.
## What Gets Published
You can publish incidents to status pages to communicate incident details, timeline updates, and resolution status with your external stakeholders such as customers, partners, or internal teams.
When you publish an incident to a status page, it will display:
* Incident title
* Affected Services, Functionalities & External Services
* Timeline of events
* Incident resolution status
## Publishing from Slack
In addition to using the web interface for publishing incidents to status pages, you can also accomplish the same thing without leaving Slack.
To publish an incident using Slack, do the following:
From Slack, navigate to the Slack channel specific to that incident, and type the command:
**/rootly statuspage**
A dialog will be presented for you to choose the appropriate status pages where you want the incident published.
This will also be your chance to add a useful title and description so your external users can better understand. Add the appropriate information in the title and event fields.
Select a status for the incident, and then click **Publish**.
## Publishing from the Web UI
To publish an incident on a status page in Rootly's Web UI:
On the incident's details page, navigate to the **Status Page** tab.
Click **Publish Incident**, and fill out the form to write your incident update.
Use any templates provided to help craft and standardize your message.
Once you've provided all the details, the incident will be published to the status page.
Any Service or [functionality](/configuration/functionalities) attached to the incident that is also a component of that status page will be automatically updated to show that it is currently **Affected** by an incident. Once the status page is updated to indicate that the incident is resolved, the component will be updated to **Operational**.
## Updating a Published Incident
As your incident progresses, you'll need to continually communicate progress to your customers and stakeholders via the status page. You can do so from the same tab in your incident's detail page.
1. Click 'Add to status page' and fill out the necessary information.
2. Rootly will pre-fill the title based on the previous update that was published to the status page.
## Resolving a Published Incident
Once your incident has been resolved, publish your final update to the status page using the same flow above. Make sure to update the status in this form to 'Resolved' so that your stakeholders know the issue has been resolved, and all impacted components will return to operational.
***
## Related Pages
The umbrella concept — where published incidents actually show up.
Set up the page before you can publish updates to it.
Where published-update events surface inside the incident record.
# Pulses
Source: https://docs.rootly.com/configuration/pulses
Track deploys, config changes, and other operational events as pulses — silent context signals that surface in triage to correlate breaks with changes.
## Overview
**Pulses** are lightweight event records that capture *changes* to your systems — deploys, config updates, feature-flag flips, database migrations, CI builds — without paging anyone, creating an incident, or generating a notification.
They exist for a single reason: **when an incident happens, responders need to answer "what changed?" as fast as possible.** Pulses give you a searchable, filterable timeline of every change that landed in the recent past, so triage takes minutes instead of digging through Slack, git logs, and deploy dashboards to reconstruct the timeline.
Pulses are **passive context**, not alerts. They don't trigger notifications, don't page on-call, and don't create incidents on their own. A [Pulse Workflow](/workflows/pulse-workflows) is what turns a pulse into any of those things — but the pulse itself is inert.
***
## How Pulses Are Used
| Feature | How pulses are used |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Incident triage** | The most common use. When a responder opens an incident, Rootly shows pulses that landed in the recent past — filtered by the incident's services, environments, and time window — so "what changed right before this broke" is a one-glance question. |
| **[Pulse Workflows](/workflows/pulse-workflows)** | Trigger a workflow when a pulse arrives that matches specific criteria. Example: auto-post a Slack message when a Production deploy pulse arrives, so the team sees the deploy timeline in-context. |
| **API + CLI** | Any system that knows about a change can send a pulse. CI/CD pipelines, feature-flag services, config-management tools, custom scripts — all common sources. |
Because pulses cost nothing to send and everything to have during triage, **the right pattern is to send more pulses than you think you need**. Pipe every deploy, every feature-flag flip, every config change — filter and narrow at read time via the pulse UI, not at write time.
***
## Sending Pulses
Pulses can be created two ways: through the Rootly API and through the Rootly CLI. Pick whichever matches how your pipeline is already structured — most teams end up using both (API for programmatic sources, CLI for shell scripts and CI).
### API
Every pulse is a `POST /v1/pulses` with a summary and optional metadata. Minimal request:
```bash Linux theme={null}
curl --header "Content-Type: application/json" \
-H "Authorization: Bearer " \
--data '{"data": {"attributes": {"summary": "Deployed website v2.14.1"}}}' \
-X POST https://api.rootly.com/v1/pulses
```
Richer request with metadata for filtering:
```bash Linux theme={null}
curl --header "Content-Type: application/json" \
-H "Authorization: Bearer " \
--data '{
"data": {
"attributes": {
"summary": "Deployed website v2.14.1",
"environments": ["production"],
"services": ["checkout-web", "payments-api"],
"labels": {
"version": "2.14.1",
"author": "alice@example.com",
"commit": "a1b2c3d"
}
}
}
}' \
-X POST https://api.rootly.com/v1/pulses
```
Best used from **CI/CD hooks, feature-flag webhook receivers, and infrastructure-as-code apply hooks**. Wire the pulse creation into your deploy pipeline once and every future deploy is captured automatically.
### CLI
The [Rootly CLI](https://github.com/rootlyhq/rootly-cli) exposes two pulse commands — one that creates a pulse from a summary and one that wraps an arbitrary shell command:
**Simple pulse:**
```bash Linux theme={null}
export ROOTLY_API_TOKEN="your-api-token"
rootly pulse create "Deployed website v2.14.1" \
--services=checkout-web,payments-api \
--labels="env=production,version=2.14.1"
```
**Wrap a shell command as a pulse:**
```bash Linux theme={null}
rootly pulse run \
--summary="Deploy Website" \
--services=checkout-web \
--labels="env=production,version=2" \
-- sh deploy.sh
```
`pulse run` executes the wrapped command and creates a pulse capturing the command, its exit status, and its runtime. Best for CI job wrappers where you want "this thing ran" as pulse metadata automatically.
See the [Rootly CLI docs](/integrations/cli) for the full command reference.
### Pulse Attributes
Every pulse supports the following fields. All are searchable and filterable in the pulses UI and in [pulse variables for workflow templates](/liquid/pulse-variables).
Human-readable one-line description. This is what appears in the triage timeline. Keep it short and specific — "Deploy website v2.14.1" beats "Deployment" or "Prod push".
Which environments the change affects. Matches the [Environments](/configuration/environments) field on incidents, so pulses filter cleanly against incident context.
```bash theme={null}
--environments "production"
--environments "staging, production"
```
Which [Services](/configuration/services) the change touches. This is the single most important field for triage filtering — a pulse tagged with the affected service surfaces in the right place at the right time.
Free-form metadata attached to the pulse. Use for anything that helps at read time — commit hash, deploy author, version, ticket ID, feature-flag name.
```bash theme={null}
--labels "version=2.14.1, author=alice, commit=a1b2c3d"
```
In the JSON API, labels is a flat object: `{"version": "2.14.1", "author": "alice"}`.
Optional link back to the source of the change — Datadog dashboard, GitHub commit, CircleCI build. Renders as a clickable link in the pulses UI so responders can jump straight to the source.
***
## Common Pulse Sources
The single most valuable pulse source. Post a pulse from every deploy job — success and failure both — with the version, commit, and environment as labels. When an incident hits, the responder immediately knows what shipped in the last hour.
Common integrations: GitHub Actions, CircleCI, Jenkins, Buildkite, GitLab CI. Add a step to the deploy job that curls the pulses API.
Every feature-flag flip is a change. Wire your feature-flag service (LaunchDarkly, Statsig, Unleash, PostHog) to POST a pulse when a flag toggles in production. When a customer reports "it worked yesterday and doesn't today," the pulse timeline shows the exact flag that changed between then and now.
Post a pulse on every `terraform apply`, every `kubectl rollout`, every Pulumi update. Include the plan diff (or a link to it) in labels or `external_url` so responders can see what actually changed at the infra level.
Every schema migration is a landmine waiting to be stepped on during triage. Post a pulse from your migration runner with the migration name and target database. If an incident happens 3 hours after a migration, the pulse timeline surfaces the migration immediately.
Any manual change — restarting a service, applying a config patch, running a maintenance script — deserves a pulse. Use the CLI (`rootly pulse create "Restarted elasticsearch-prod"`) as an operator habit. Future you will thank present you when the change becomes relevant during triage.
***
## Best Practices
* **Send more pulses than you think you need.** Filtering out noisy pulses at read time is trivial (label filters, service filters, time-window filters). Reconstructing a change history from scratch during a live incident is not.
* **Wire pulses at the automation layer, not by hand.** A pulse that requires an engineer to remember to send it doesn't get sent when it matters most (during a rushed hotfix). Bake pulse creation into deploy jobs, CI hooks, and feature-flag webhooks so it happens automatically.
* **Use consistent labels across sources.** If your GitHub deploys use `version`, your Terraform runs use `terraform_version`, and your feature flags use `variant`, filtering at read time gets awkward. Standardize on a small label vocabulary and apply it everywhere.
* **Tag `environments` and `services` on every pulse.** Untagged pulses don't surface in incident triage because triage filters by service and environment. A pulse without those tags is a pulse that responders won't see.
* **Include an `external_url` when the pulse links to actionable detail.** A pulse that says "Deploy v2.14.1" is useful; a pulse that says "Deploy v2.14.1" + a link to the CircleCI build page is a rollback candidate in one click.
* **Don't use pulses for alerts.** Pulses are inert by design. If you want an incident to open when a specific change happens, that's a [Pulse Workflow](/workflows/pulse-workflows) with an Incident Created action — not the pulse itself.
***
## Troubleshooting
Two common causes: (1) the pulse's `services` or `environments` don't match the incident's — triage filters by intersection, so a pulse tagged only with `staging` won't appear on a Production incident; (2) the pulse landed outside the triage time window (default is the last few hours before the incident). Widen the window from the triage view's date picker if the pulse is older.
The `Authorization: Bearer ` header is missing or the token is invalid. Generate a token in **Account → Manage API keys → Generate New API Key** and confirm it has API access enabled. If you're using a Team API key, confirm the key's team has permission to write pulses.
The CLI expects labels as comma-separated `key=value` pairs: `--labels "version=2, attempt=1"`. Common mistakes: quoting individual pairs (`--labels "version=2","attempt=1"`), using colons instead of equals (`--labels "version:2"`), or wrapping values in inner quotes.
Check the workflow's run conditions in [Workflows](/workflows/pulse-workflows). Pulse workflows fire on every matching pulse by default — narrow the conditions to filter by `services`, `environments`, or specific label values. The [Workflow Conditions](/workflows/conditions) evaluator lets you test conditions against a sample pulse payload.
Some sources (for example, a chatty CI system) generate too many pulses to be useful during triage. Two options: (1) filter noisy pulses out of the triage view via label filters — the pulse data stays available for post-incident review; (2) reduce the source's pulse volume by only sending on meaningful events (for example, successful deploys, not every retry).
***
## Frequently Asked Questions
**Pulses** capture changes to your systems (deploys, config updates) and are passive — no notifications, no paging, no incident lifecycle. **Incidents** capture problems requiring response — they trigger workflows, page on-call, and follow the full incident lifecycle. Pulses inform incident triage; they don't become incidents on their own unless a [Pulse Workflow](/workflows/pulse-workflows) turns them into one.
Not directly. A pulse itself is inert. To page on-call when a specific pulse arrives, create a [Pulse Workflow](/workflows/pulse-workflows) with matching conditions and an incident-creation or paging action.
Pulses are retained indefinitely by default. If your workspace has a data-retention policy, pulses fall under the same retention window as incidents. Contact support if you need a shorter retention window for pulses specifically.
Yes. The Pulses page in Rootly Web is a searchable, filterable timeline independent of any specific incident. Filter by service, environment, label, or time window.
Pulses use the standard Rootly API rate limits. High-volume pulse sources (for example, a CI system pulsing on every commit) can hit limits — batch or throttle at the source, or use the CLI which handles retries.
Yes. See [Pulse Variables](/liquid/pulse-variables) for the reference — `{{ pulse.id }}`, `{{ pulse.short_id }}`, `{{ pulse.source }}`, `{{ pulse.summary }}`, and `{{ pulse.data }}` (the raw pulse payload). Reach into the payload with `{{ pulse.data | get: 'field_name' }}` for anything not exposed as its own top-level variable.
`rootly pulse create` creates a pulse from a summary and metadata you provide. `rootly pulse run` wraps an actual shell command — it executes the command, captures its exit status and runtime, and creates a pulse with that metadata attached automatically. Use `pulse run` when the pulse *is* the fact that a specific command ran (deploy scripts, migration jobs, backup jobs).
***
## Related Pages
Turn pulses into automation — post to Slack, create tickets, trigger incidents based on pulse content.
Liquid reference for `pulse.id`, `pulse.short_id`, `pulse.source`, `pulse.summary`, and `pulse.data`.
Full command reference for the Rootly CLI, including `pulse create` and `pulse run`.
# Security Best Practices
Source: https://docs.rootly.com/configuration/security-best-practices
Harden your Rootly tenant — identity and SSO, RBAC and least privilege, API hygiene, audit logging, session controls, and integration hygiene.
## Overview
This page walks Rootly administrators through the controls available for hardening a tenant against unauthorized access, lateral movement, and silent configuration drift. It is the recommended checklist when preparing Rootly for an enterprise security review, a SOC 2, or onboarding a new organization.
Every recommendation below is grounded in features Rootly ships today — links lead to the relevant configuration page. The order mirrors how most teams roll out hardening: identity first, then permissions, then API surface, then monitoring.
SAML SSO plus SCIM provisioning so the IdP is the source of truth for who can log in and what role they hold.
Custom roles and on-call seat controls scoped to job function — no blanket admin grants.
OAuth 2.0 over long-lived tokens, scoped permissions, and routine credential rotation.
Indefinite audit log retention with filterable change history across configuration, integrations, incidents, and workflows.
***
## Centralize Identity
The fastest single hardening step for any Rootly tenant is moving authentication behind your IdP. Once SSO is enforced, you control account lifecycle, MFA, and conditional access from one place — Rootly inherits whatever your IdP enforces.
Configure SAML 2.0 with your IdP (Okta, Azure AD, Google Workspace, OneLogin, JumpCloud, Auth0, or any SAML 2.0-compatible provider). See [SSO](/integrations/sso) for the service provider details and IdP-specific walkthroughs.
MFA is enforced at the IdP layer, not in Rootly directly. Use the IdP's conditional access policies to require MFA, device posture checks, or location restrictions before letting users land in Rootly.
Configure SCIM 2.0 so user creation, role assignment, and deactivation are driven by IdP group membership. See [SCIM](/integrations/scim).
SCIM is the most important control for deprovisioning: when an employee leaves and the IdP disables their account, SCIM automatically deactivates their Rootly account on the next sync — closing the gap where a manual admin would otherwise need to remember to revoke access.
With SSO enforced, prefer SCIM-driven provisioning (or Just-In-Time provisioning from the SAML assertion) over manual invite-by-email. Direct email invites create accounts that won't be auto-deprovisioned when the user leaves the organization.
See [SCIM](/integrations/scim) for full lifecycle provisioning and [SSO](/integrations/sso) for the SAML attribute mapping that drives Just-In-Time provisioning. (Rootly also supports manual invites via [Inviting Users via Third-Party Integrations](/managing-users/inviting-users-via-third-party-integrations) for Slack, Opsgenie, PagerDuty, and Splunk On-Call — useful for narrow cases, but not the right primitive for IdP-managed lifecycle.)
***
## Apply Least Privilege
Rootly's role model lets you scope what a user can do down to the action level. Use it — broad admin grants are the largest unforced security risk in most tenants.
Define purpose-built roles ("Incident Responder", "On-Call Operator", "Auditor") instead of granting full admin. See [User Permissions](/managing-users/user-permissions) for the available permission scopes.
Delegate team-scoped configuration to team admins instead of org-wide admins. Team admins can manage their team's schedules, escalation policies, and members without touching org-level settings. See [Configuring Teams](/managing-teams/configuring-teams).
On-call paging requires a separate seat type. Grant on-call seats only to users who actually take pages — users without a seat cannot be added to schedules, eliminating accidental paging exposure to non-responders.
Compliance and security reviewers should hold an Auditor role with read-only access to the audit log and configuration — never an admin role.
Run a quarterly review of admin role assignments. The [Audit Log](/configuration/audit-log) records every role change with before-and-after values, making this a five-minute filter exercise rather than a manual cross-check.
***
## Lock Down API Access
Rootly exposes a public API plus OAuth 2.0 provider endpoints. Both deserve deliberate hardening.
### Prefer OAuth 2.0 Over Long-Lived API Tokens
For machine-to-machine integrations, use [OAuth 2.0](/api-reference/oauth2) rather than static API tokens. OAuth tokens have explicit scopes, short lifetimes, and can be revoked from a single place. Long-lived API tokens are appropriate only for narrow internal tooling, and should be rotated on a fixed cadence.
### Scope API Tokens Tightly
When an API token is necessary, scope it to the minimum permission set the integration needs. A token used by a Datadog → Rootly forwarder should not have the ability to modify escalation policies or user roles.
### Audit Outgoing Webhook Destinations
[Outgoing webhooks](/configuration/webhooks) post to URLs you supply. Review the webhook destinations in your tenant on a recurring cadence and remove ones pointing at decommissioned receivers — orphaned destinations accumulate over time and become exfiltration risks once their hosts change ownership.
***
## Turn On Continuous Audit
Rootly's [Audit Log](/configuration/audit-log) captures every create, update, and delete across \~60 resource types with full before-and-after field values. It is the compliance evidence layer auditors look for.
Walk security and compliance reviewers through **Configuration → Audit Log** so they can self-serve "who changed X, when?" questions without filing tickets to the Rootly admins.
The audit log is available via the [audit log JSON:API endpoint](/configuration/audit-log#programmatic-access-via-api) for scheduled export — useful for backing up evidence into long-term storage your auditors already own, or for ad-hoc queries beyond what the UI filters expose.
Review these events on a routine cadence: role assignments granting admin, API token creation, webhook destination changes, user deletion, escalation policy changes outside change-control windows. These are the events that precede or are part of most security incidents.
***
## Control Session And Device Posture
Configure a default session timeout in your team settings. Shorter timeouts (8 hours or less for high-privilege roles) reduce the scope of impact of a stolen session cookie or unlocked workstation.
Use your IdP's conditional access (Okta, Microsoft Entra Conditional Access, Google Context-Aware Access) to gate Rootly access on device posture — managed device, current OS, antivirus running. Rootly inherits the gate; you don't need to re-implement it.
***
## Harden Third-Party Integration Hygiene
Each integration you connect is a potential blast-radius vector if its credentials leak. Routine hygiene:
* **Rotate integration credentials on a schedule.** Most providers let you regenerate API keys without recreating the integration — schedule a quarterly rotation for high-privilege integrations (PagerDuty, Slack, GitHub, Datadog).
* **Disable integrations you no longer use.** A connected-but-unused integration is still attack surface. Review your integrations list each quarter and disable connections to systems your team no longer relies on. The [Audit Log](/configuration/audit-log) captures recent configuration changes to each integration, which helps confirm whether one has been actively maintained.
* **Limit Slack workspace access.** When configuring the Slack integration, install it as a specific workspace admin rather than a personal account — that way, the integration outlives any individual user's tenure.
* **Review integration scope grants.** When connecting OAuth-based integrations (Google Workspace, Microsoft 365), confirm the requested scopes match what Rootly actually needs for the features you use.
***
## Status Page And Public Surface
If you publish status pages, treat the public surface deliberately:
* Use [Status Page Authentication Methods](/configuration/status-page-authentication-methods) — password protection or SAML SSO — on any status page that should not be world-readable.
* Confirm [Public And Private Status Pages](/configuration/status-pages#public-or-private) classifications match intent — a misclassified private page is a data exposure.
* Use a [Custom Domain](/configuration/custom-domain-names-for-status-pages) for branded status pages so DNS and TLS sit under your control.
***
## Compliance Posture
Rootly maintains SOC 2 Type II. Auditors and customer security teams typically request the following artifacts during review:
| Artifact | Where To Get It |
| ------------------------ | --------------------------------------------------------------------------------------- |
| SOC 2 Type II report | Contact [support@rootly.com](mailto:support@rootly.com) for the latest report under NDA |
| Subprocessor list | Published at [Subprocessors](/configuration/subprocessors) |
| Data processing addendum | Available through your account team |
For tenant-side compliance evidence (who has access, what changed, when), the [Audit Log](/configuration/audit-log) is the system of record — its filterable change history and JSON:API export are designed to satisfy "demonstrate continuous monitoring" controls.
***
## Frequently Asked Questions
MFA is enforced at the identity-provider layer. Once SAML SSO is configured, whatever MFA policy your IdP applies (TOTP, push, FIDO2/WebAuthn, certificate-based) is what controls Rootly login. There is no separate Rootly-native MFA setting — using the IdP's MFA is the recommended pattern because it centralizes policy.
Audit log retention is unlimited by default — every create, update, and delete event is retained for the lifetime of your tenant. For long-term archival outside Rootly, use the [audit log JSON:API endpoint](/configuration/audit-log#programmatic-access-via-api) to export events into compliance storage your auditors already own.
Create the replacement token first, deploy it to the consuming integration, verify traffic is flowing on the new token (visible in audit log events sourced from "API" with the new token's identifier), then revoke the old one. The overlap window is the safe rotation pattern — never delete a token before its replacement is in use.
No. The audit log automatically redacts sensitive fields (passwords, API keys, OAuth tokens, signing secrets) in the UI and API responses. You see that the field changed, but not the value.
Create a custom **Auditor** role with read-only access to configuration, the audit log, and (optionally) incident records. Auditors should never hold an admin role — they need to read, not modify.
***
## Next Steps
SAML 2.0 setup with Okta, Azure AD, Google Workspace, and other identity providers.
Automate user lifecycle from your IdP — the deprovisioning control most worth getting right.
Full change history across configuration, integrations, and incidents — filterable in the UI and exportable via the JSON:API.
Custom roles, team admins, and the permission scopes available for least-privilege design.
***
## Related Pages
The visibility layer — every change to sensitive configuration surfaces here.
Route incident, alert, workflow, and status-page events to external systems — periodically review destinations for orphans.
The umbrella page covering incident properties and configuration surface.
# Services
Source: https://docs.rootly.com/configuration/services
Configure services to identify impacted components during incidents, manage responders, and integrate with status pages and external tools.
## Overview
*Service* allows you to specify the impacted component during an incident. This can help you with identifying which responders to bring in, which on-call to page, which customers to inform, etc. Individual services can be mapped to your status pages.
## Adding Services in Rootly
To add a new Service via the Rootly Web UI, navigate to **Configuration > Services** then click **New Service**.
Assign your new Service with a descriptive Title and Description to help the rest of your team know what the Service represents.
## Editing Services
Services are made up of a number of properties. Each property can be referenced via Liquid syntax and can be set in the Rootly Web UI, [API](/api-reference/services/list-services), or [imported from Opsgenie and PagerDuty](/configuration/services#import-services). This section outlines how to edit the Services in the Rootly Web UI.
## Adding Properties
While Services in Rootly comes with built-in properties, additional properties can be added. This allows you to build automations and workflows for your incident response processes using this information: for example, quickly identifying the customer impact of an incident based on the related service.
To add custom properties, open **Services**, click **Edit catalog**, and click **Add Property**. You can choose from several property types, including text, boolean, and importantly references to other Catalogs.
For each Service, you'll be able to find the values of these properties in the **Custom Properties** tab.
## Basics
Configure the basic details of your Service here.
This is the unique identifier of the service. This field **cannot be customized**. Rootly will auto assign the *ID* upon creation. It is typically used in Liquid references and API calls.
The following Liquid syntax will allow you to list out the service *ID*(s) that are selected for an incident:
`{{ incident.services }}`
OR
`{{ incident.raw_services | get: 'id'}}` for select field type
`{{ incident.raw_services[index] | get: 'id' }}` for multi-select field type
This is the value that is displayed on the UI for the service. This field is customizable.
The following Liquid syntax will allow you to list out the service *name*(s) that are selected for an incident:
`{{ incident.services }}`
OR
`{{ incident.raw_services | get: 'name'}}` for select field type
`{{ incident.raw_services[index] | get: 'name' }}` for multi-select field type
This value is displayed on the UI to further explain each service. This field is customizable.
The following Liquid syntax will allow you to list out the service *description*(s) that are selected for an incident:
`{{ incident.raw_services | get: 'description'}}` for select field type
`{{ incident.raw_services[index] | get: 'description' }}` for multi-select field type
Clear team ownership helps identify service owners and dependencies during incidents. The Owning Team's admins will be able to make changes to the Service.
Add any services that may be related or affected by this service. This is for reference only and won't have any actual impact.
Each service can be assigned a color, which will be used for color-coding on metrics graphs.
Rootly uses **color-hex codes**. For example, #000000 is black, #ffffff is white. Use [color-hex.com](https://www.color-hex.com/) to find the exact hex code for the color you want.
The following Liquid syntax will allow you to list out the service *color*(s) that are selected for an incident:
`{{ incident.raw_services | get: 'color'}}` for select field type
`{{ incident.raw_services[index] | get: 'color' }}` for multi-select field type
## On-Call
Configure what happens when this Service is paged in Rootly On-Call. When this Service is paged either manually by a user, or through an Alert Source, the Escalation Policy selected here will fire.
## Channels
Configure the Channels section to reference the Service's related Slack properties. These Slack properties (like Slack Channel and User Group) can be used in Rootly's Workflows to build powerful Slack automations off of the Service.
Each service can be linked to one or more Slack channels. By default, Rootly does not notify the linked channel(s) when a service is selected for an incident. Notification needs to be explicitly called out as Attached Service Channels in workflow configurations.
Systematically, each Slack channel is stored as an object containing an id and name.
The following Liquid syntax will allow you to list out the service *Slack Channel*(s) that are selected for an incident:
`{{ incident.raw_services | get: 'slack_channels'}}` for select field type
`{{ incident.raw_services[index] | get: 'slack_channels' }}` for multi-select field type
Each service can be linked to one or more Slack user groups (aka aliases). By default, Rootly does not invite users in the linked user group(s) when a service is selected for an incident. Invitations need to be explicitly called out as Attached Service Aliases in workflow configurations.
The following Liquid syntax will allow you to list out the service *Slack Alias*(es) that are selected for an incident:
`{{ incident.raw_services | get: 'slack_aliases'}}` for select field type
`{{ incident.raw_services[index] | get: 'slack_aliases' }}` for multi-select field type
Each service can be linked to one or more emails. By default, Rootly does not send emails to the linked address(es) when a service is selected for an incident. Notification needs to be explicitly called out as `{{ incident.raw_services | map: 'notify_emails' | flatten | join: ',' }}` in workflow configurations.
The following Liquid syntax will allow you to list out the service *Notify Email*(s) that are selected for an incident:
`{{ incident.raw_services | get: 'notify_emails'}}` for select field type
`{{ incident.raw_services[index] | get: 'notify_emails' }}` for multi-select field type
You can also set up default broadcast channels for when the service is either paged, or added to an incident on this page.
Toggle **Set up a default Alerts Channel** On when you want Rootly to automatically post an update to Slack when the service is paged. Toggle **Set up a default Incidents Channel** when you want to post once the service has been added to an incident.
## Services in Fields
*Service* can be customized to be either a **select** or **multi-select** field type. This means you can configure it to allow only one service value to be selected per incident or allow multiple service values to be selected for a single incident.
Since the service field can be either a **select** or **multi-select** field type, the Liquid syntax to reference each field type will differ.
Select will follow a single-value syntax
`{{incident.raw_services | get: ''}}`
Multi-select will follow an array syntax. Where i references the specific service object in the list of services.
`{{incident.raw_services[index] | get: ''}}`
## Import Services
Instead of creating services from scratch, Rootly allows you to import services from **PagerDuty** or **Opsgenie**. Imported services will be automatically kept in sync on a daily basis.
The ability to import services will only become available once you have PagerDuty or Opsgenie installed on the [integrations page](https://rootly.com/account/integrations).
The following Liquid syntax will allow you to list out the corresponding ids from each of the external paging applications:
**PagerDuty**
`{{ incident.raw_services | get: 'pagerduty_id' }}` for select field type
`{{ incident.raw_services\[0\] | get: 'pagerduty_id' }}` for multi-select field type
**Opsgenie**
`{{ incident.raw_services | get: 'opsgenie_id' }}` for select field type
`{{ incident.raw_services\[0\] | get: 'opsgenie_id' }}` for multi-select field type
***
## Related Pages
Group services into higher-level customer-facing capabilities like Login or Checkout.
Assign services to owning teams that get paged when the service is impacted.
Attach an escalation policy to a service so alerts on it actually page someone.
# Severities
Source: https://docs.rootly.com/configuration/severities
Configure incident severity levels, calibrate a severity matrix for your team, and use severities to drive workflows, escalations, and status pages.
## What Are Incident Severity Levels?
**Severity** is the property that expresses how bad an incident is. It's the single number responders reach for first — "is this a SEV0 or a SEV2?" — because so much else in the response process keys off it: who gets paged, how urgently, whether the status page is updated, what the retrospective template looks like, and how the incident is counted in your metrics.
Severity is a **fixed, single-select property**. Every incident carries exactly one severity value, and that value is fully customizable — pick the number of levels, their names, colors, and behavior that matches how your team actually calibrates impact.
***
## How Severities Are Used
Severity isn't just a label — it's a lever that other Rootly features pull on:
| Feature | How severity is used |
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[Workflow conditions](/workflows/conditions)** | Filter workflows so they fire only on specific severities. The most common pattern is "page on-call on SEV0/SEV1" or "auto-create Jira ticket on SEV2+". |
| **Escalation policies** | While escalation policies themselves don't branch on severity directly, workflow-driven paging typically routes different severities to different escalation policies (higher severity = shorter first-step timeout, more responders). |
| **Slack channel + alias notifications** | Each severity can be linked to Slack channels and user groups (aliases). Workflows use these to auto-invite the right responders and post to the right announcement channels when a severity is set. |
| **Notify emails** | Each severity can be linked to email addresses. Workflows use these to send severity-tiered stakeholder notifications. |
| **Status page publication** | Not automatic per severity — status page publication is decided by workflow conditions that check severity. Most teams auto-publish SEV0/SEV1 and manually decide on SEV2. |
| **Metrics + reporting** | Severity is a top-level filter in every metrics dashboard. MTTR-by-severity is one of the most-referenced numbers in incident review programs. |
| **Retrospective templates** | Different severities can trigger different retrospective templates via workflow — SEV0s get the full multi-section review, SEV3s get a lightweight one. |
Because so much automation branches on severity, **the shape of your severity matrix drives the shape of your response process**. That's why the picker below and the matrix-design guidance further down matter as much as the attribute configuration.
***
## Which Severity Should I Pick?
Deciding severity under pressure is the hardest part of severity calibration — new responders default to SEV0 out of caution and burn out the team; old hands default to SEV2 out of habit and miss real emergencies. Use the picker below as a starting point when the answer isn't obvious, then refine against your team's specific severity matrix.
Your team's severity matrix may weight impact dimensions differently (for example, regulated industries treat data exposure as automatic SEV0; ad-supported businesses may treat revenue-blocking outages as SEV1 even at partial scope). The picker offers a common baseline; the final call belongs to the responder declaring the incident.
***
## Designing Your Severity Matrix
There is no universal severity matrix — but there is a small set of patterns that work for most teams. Use these as a starting point, then adjust the wording to match your specific product and customer promises.
### How Many Levels
Most teams land on **four to five severity levels**. Fewer than four and you can't distinguish "everything is broken" from "some things are broken." More than five and calibration becomes fuzzy — SEV4 and SEV5 stop being meaningfully different, and responders default to SEV3 for everything below the top tier.
| Levels | When it fits |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **SEV0–SEV3** (four levels) | Most SaaS teams. Clean top-to-bottom scale with room to distinguish emergency, major, moderate, and minor incidents. |
| **SEV1–SEV5** (five levels) | Larger engineering orgs with formal incident review programs. Extra granularity helps segment metrics. |
| **SEV0–SEV5** (six levels) | Overkill for most teams. Consider consolidating unless you have a documented reason each level is used regularly. |
| **P1–P4** or **Critical/High/Medium/Low** | Named tiers are functionally equivalent to numbered tiers. Match whichever naming convention your team already uses in Jira or your incident channel. |
### Impact Dimensions
A well-calibrated matrix considers multiple dimensions of impact — not just "how many users are affected" but also *what* is affected and for how long. Common dimensions:
* **User scope** — everyone, a large segment, a small segment, individual users
* **Feature scope** — entire product, one workflow, one screen, edge case
* **Data integrity** — data loss / corruption / exposure present or not
* **Workaround availability** — none, painful, minor friction, invisible
* **Duration expectation** — active, transient, self-resolving
Not every dimension needs to weight equally. A regulated financial-services company weights data integrity above everything; an ad-supported consumer app weights user scope more heavily. **Explicit weighting is fine and often better than pretending your team treats all dimensions equally.**
### Response Commitments Per Level
Severity levels should tie to **concrete response commitments** so calibration isn't just a name — it's a promise. Common commitments to attach per severity:
* **Paging urgency** — SEV0 pages all-hands immediately; SEV1 pages the owning team; SEV2 pages during business hours; SEV3 assigns without paging
* **Incident Commander required** — SEV0/SEV1 yes, SEV2/SEV3 optional
* **First status-page update within** — SEV0: 5 min · SEV1: 15 min · SEV2: 30 min · SEV3: not required
* **Retrospective required** — SEV0/SEV1 always, SEV2 if user-visible, SEV3 optional
* **Executive notification** — SEV0 immediately, SEV1 within an hour, SEV2/SEV3 in weekly summary
Documenting these commitments in a shared runbook — not just in your head — is what turns severity from a label into an operating agreement.
### Example Matrices
Common for mid-market SaaS teams with a mix of enterprise and self-serve customers.
| Level | Trigger example | First response |
| -------- | --------------------------------------------------- | ---------------------------------------------------- |
| **SEV0** | Total outage, active data loss, security breach | Page all-hands, IC required, status page in 5 min |
| **SEV1** | Major feature down for large segment, no workaround | Page owning team, IC required, status page in 15 min |
| **SEV2** | Partial degradation, workaround available | Assign to team, business-hours response |
| **SEV3** | Minor bug, cosmetic issue | File a ticket, roadmap-driven fix |
Adds a level explicitly for data-integrity events, which typically override user-scope considerations.
| Level | Trigger example | First response |
| -------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| **SEV0** | Total outage or active security breach | All-hands, exec notification, status page in 5 min |
| **SEV1** | Data integrity event (loss, corruption, exposure) at any scale | Page privacy + security + owning team, mandatory retrospective, regulator-notification review |
| **SEV2** | Major feature broken, large user segment, no workaround | Page owning team, status page in 15 min |
| **SEV3** | Partial degradation, workaround available | Business-hours response |
| **SEV4** | Minor bug or cosmetic issue | File a ticket |
Fewer levels because customer-facing severity nuance doesn't apply the same way.
| Level | Trigger example | First response |
| -------- | ---------------------------------------------------------- | --------------------------------- |
| **SEV1** | Blocking most engineers (CI, deploys, source control down) | Page platform on-call immediately |
| **SEV2** | Impacting some workflows (specific integrations broken) | Assign to team, same-day fix |
| **SEV3** | Nuisance-level issues | Ticket, next sprint |
***
## Configuring Severity Attributes
Configure severities in **Configuration → Severities**. Each severity can be tuned with the following attributes. Every attribute is available in Liquid syntax for use in workflows, retrospective templates, and status page updates.
Unique identifier assigned automatically by Rootly on creation. **Not customizable.** Used in Liquid references and API calls.
```liquid theme={null}
{{ incident.severity_id }}
{{ incident.raw_severity | get: 'id' }}
```
The display name shown throughout the Rootly UI. Fully customizable — most teams use `SEV0`, `SEV1`, `SEV2`, `SEV3` or `P1`, `P2`, `P3`, `P4`.
```liquid theme={null}
{{ incident.severity }}
{{ incident.raw_severity | get: 'name' }}
```
Auto-generated by lower-casing and hyphenating the name. Used in Liquid references and stable across name changes.
```liquid theme={null}
{{ incident.severity_slug }}
{{ incident.raw_severity | get: 'slug' }}
```
Additional context shown alongside the severity in the UI. Best used to remind responders what qualifies for each level — for example, "Total outage or active data loss."
```liquid theme={null}
{{ incident.raw_severity | get: 'description' }}
```
Hex color code used for severity-tinted UI accents and metrics-graph color coding. Convention: red for the highest severity, orange/yellow for middle tiers, blue/gray for the lowest.
```liquid theme={null}
{{ incident.raw_severity | get: 'color' }}
```
Rootly expects six-digit hex codes (for example, `#c4231c` for red, `#ed8f17` for orange). Use a color picker if you're not sure — [color-hex.com](https://www.color-hex.com/) is a common choice.
One or more Slack channels linked to the severity. **Linking alone doesn't post to the channels** — a workflow action (typically "Attached Severity Channels" or "Notify Attached Slack Channels") reads this list and performs the notification.
```liquid theme={null}
{{ incident.raw_severity | get: 'slack_channels' }}
```
One or more Slack user groups (aka aliases) linked to the severity. **Linking alone doesn't invite users** — a workflow action (typically "Attached Severity Aliases") reads this list and performs the invitation.
```liquid theme={null}
{{ incident.raw_severity | get: 'slack_aliases' }}
```
One or more email addresses linked to the severity. **Linking alone doesn't send email** — a workflow action reads this list and sends the notification.
```liquid theme={null}
{{ incident.raw_severity | get: 'notify_emails' }}
```
For workflow-driven use, most teams reference the flattened list:
```liquid theme={null}
{{ incident.raw_severity | map: 'notify_emails' | flatten | join: ',' }}
```
***
## Best Practices
* **Calibrate quarterly.** Look at the last 90 days of incidents and ask: did we call any of these wrong in retrospect? Adjust the matrix language, not just individual calls.
* **Don't add SEV4/SEV5 until SEV3 is used regularly.** Extra levels only work if you actually distinguish between them. If SEV3 is your effective floor, adding SEV4 just creates a level nobody uses.
* **Colors should be intuitive.** Red for the top severity, orange/yellow for middle, blue/gray for the lowest. Don't invent custom mappings — responders read the color before the name and calibration takes twice as long if the color contradicts convention.
* **Downgrading is fine; upgrading is expected.** Encourage responders to over-page at SEV0 and downgrade within 15 minutes if scope narrows. Under-response at declaration is the failure mode you're trying to avoid, not over-response.
* **Keep the picker open during on-call handoffs.** Sharing the picker link (`/configuration/severities#which-severity-should-i-pick`) is one of the fastest ways to onboard new responders to the calibration model.
* **Attach Slack channels + aliases per severity, but require workflow actions to actually use them.** This keeps notification behavior explicit and auditable in the workflow list rather than hidden in severity settings.
* **Test severity changes in a Test Incident first.** If you rework the matrix or add a new severity, declare a `/rootly test` and walk the workflows through their branches before the next real incident hits the new definitions.
***
## Troubleshooting
Confirm the severity is enabled (not archived) under Configuration → Severities. Archived severities remain visible on historical incidents but don't appear as options on new incidents. If it's enabled and still missing, check whether team-level severity restrictions are in play — some teams scope which severities each team can declare.
Linking Slack channels or aliases to a severity **does not** cause auto-invitation on its own. You need a workflow with an "Attached Severity Channels" or "Attached Severity Aliases" action, keyed off a Severity Updated trigger or the initial Incident Created trigger. Check that the workflow exists, is enabled, and has run conditions that match the severity you're testing with.
Metrics bucket incidents by the severity value at the time of the metric query — so if severity was changed mid-incident, the current severity is what's counted (not the initial one). If you need historical severity data, query the incident timeline events, which record every severity transition with timestamps.
Confirm the color is a valid six-digit hex code starting with `#` (for example, `#c4231c`, not `c4231c` or `rgb(196, 35, 28)`). Rootly won't attempt to parse shorthand or non-hex color formats.
Two common causes: (1) the description field for each severity is empty or too vague — expand each severity's description to name concrete example scenarios; (2) the picker on this page isn't linked from your on-call runbook — add a link so responders reach for it during triage. Also review the last 30 days of incidents in a calibration meeting and identify which mis-calls the language could have prevented.
***
## Frequently Asked Questions
Most teams land on four (SEV0–SEV3) or five (SEV1–SEV5). Fewer than four can't distinguish emergency from major from moderate. More than five and the extra levels stop being meaningfully different in practice — see the Designing Your Severity Matrix section above for detail.
Yes, and it's expected. Changing severity logs a timeline event with the transition timestamp, which downstream workflows can trigger off (via the Severity Updated trigger). Most teams see severity change one to two times per incident as scope becomes clearer.
In Rootly, severity is the built-in property. Priority (if you use it) is typically a custom field layered on top — often used to distinguish "how urgent is this to fix" from "how bad is this while it's happening." A minor bug with a big customer implication might be SEV3 severity but P1 priority. Rootly doesn't ship priority as a built-in; add it as a [Custom Field](/configuration/custom-fields) if you want it.
No. Test incidents (declared via `/rootly test`) are excluded from production metrics regardless of the severity assigned. This is enforced at the Kind level — see [Incident Kind](/configuration/incident-kind) for the full behavior matrix.
Yes. Severity is one of the most common fields to filter on in workflow run conditions. The [Workflow Conditions](/workflows/conditions) page has an interactive evaluator you can use to test severity-based conditions against a sample incident before wiring them into a real workflow.
Rootly's severity list is org-wide, but teams can restrict which severities their responders declare. If you need genuinely different severity matrices per team (for example, an infra team using P1–P4 and a product team using SEV0–SEV3), the current recommendation is to unify to one matrix and use naming that works for both — running two parallel matrices is confusing at the org level for metrics and executive reporting.
Deleting (or archiving) a severity leaves historical incidents referencing it intact — the incident keeps its original severity value even after the severity is removed from the picker. Only new incidents lose access to the removed severity. If you're doing a matrix overhaul, archive old severities rather than deleting, so historical incident data stays readable.
***
## Related Pages
Use severity in workflow run conditions to route different severities to different response processes.
The other fixed property — governs whether an incident counts in metrics regardless of severity.
Add a priority field or other custom taxonomy on top of severity.
# Status Page Authentication Methods
Source: https://docs.rootly.com/configuration/status-page-authentication-methods
Configure authentication for public Rootly status pages to control viewer access using password protection or SAML-based single sign-on.
## Overview
Rootly provides multiple authentication methods to secure access to your public status pages. You can choose from no authentication, password protection, or enterprise-grade SAML authentication depending on your security requirements.
Authentication is only available for **public status pages**. Private status pages require users to be logged in to Rootly by default.
## Authentication Methods
Your status page is publicly accessible to anyone with the URL. This is the default setting and is suitable for:
* Public-facing service status pages
* External customer communications
* Maximum visibility during incidents
Protect your status page with a shared password. Anyone with the password can access the page.
**Best for:**
* Partner or vendor portals
* Limited external stakeholder access
* Quick setup without SSO infrastructure
**How to configure:**
1. Navigate to your status page settings.
2. Go to the **Authentication** tab.
3. Select "Password" as the authentication method.
4. Enter your desired password.
5. Save the changes.
Share the password securely with stakeholders who need access.
Enterprise-grade single sign-on using SAML 2.0 protocol. Users authenticate through your identity provider (IdP) without needing separate credentials.
**Best for:**
* Enterprise customers with existing SSO infrastructure
* Compliance requirements (SOC 2, ISO 27001)
* Centralized access control and audit logs
* Multiple status pages with different IdP configurations
**Supported features:**
* SAML 2.0 authentication flow
* Single Logout (SLO)
* Per-status-page IdP configuration
* X.509 certificate validation
* Multiple name identifier formats
## Configuring SAML Authentication
### Prerequisites
Before configuring SAML authentication, you'll need:
* Access to your Identity Provider (IdP) admin console (for example, Okta, Azure AD, Google Workspace)
* Your IdP's SSO Service URL
* Your IdP's X.509 certificate
* Permissions to create SAML applications in your IdP
- Navigate to your status page settings.
- Select the **Authentication** tab.
- Choose "SAML" as the authentication method.
You'll need to create a new SAML application in your IdP with the following information from Rootly.
**Service Provider (SP) Details:**
| Field | Description | Example |
| ---------------------------- | -------------------------------------- | ------------------------------------------ |
| **Entity ID / Audience URL** | Unique identifier for your status page | `https://status.company.com/saml/metadata` |
| **ACS URL / Callback URL** | Where SAML responses are sent | `https://status.company.com/saml/consume` |
| **Metadata URL** | Complete SP metadata (optional) | `https://status.company.com/saml/metadata` |
These URLs are automatically generated after you save your status page and will be displayed in the Authentication tab for easy copying.
Enter the following information from your Identity Provider:
The SAML authentication endpoint provided by your IdP.
**Example:** `https://your-company.okta.com/app/abc123/sso/saml`
The X.509 certificate from your IdP for validating SAML responses. Paste the full certificate including the BEGIN/END lines.
```text theme={null}
-----BEGIN CERTIFICATE-----
MIIDpDCCAoygAwIBAgIGAXoTpGkZMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQG
...
-----END CERTIFICATE-----
```
The format for user identification in SAML assertions.
**Options:**
* Email Address (default)
* Unspecified
* Persistent
* Transient
Optional endpoint for SAML Single Logout functionality.
**Example:** `https://your-company.okta.com/app/abc123/slo/saml`
* Save your SAML configuration.
* Open your status page URL in a private/incognito browser window.
* Click the sign-in option.
* You should be redirected to your IdP for authentication.
* After successful authentication, you'll be redirected back to the status page.
## Common Identity Provider Guides
Configure SAML with Okta using the Entity ID, ACS URL, and download the certificate from your Okta application settings.
Use Azure AD Enterprise Applications to create a custom SAML app. Copy the Login URL and certificate from the SAML Signing Certificate section.
Configure a custom SAML app in the Google Admin console. Use the SSO URL and download the IDP certificate.
Create a SAML application in OneLogin and configure the ACS URL. Download the X.509 certificate from the SSO tab.
## Security Considerations
**Certificate Management:** SAML certificates have expiration dates. Monitor your certificate expiration and update it in Rootly before it expires to prevent authentication failures.
Rootly's SAML implementation includes:
* **X.509 Certificate Validation** - All SAML responses are verified using your IdP's certificate
* **Signature Verification** - Protects against tampering and man-in-the-middle attacks
* **Replay Attack Protection** - SAML assertions are validated for freshness
* **Audit Logging** - All authentication attempts are logged for compliance
* **Secure Session Management** - Encrypted cookies with automatic expiration
## Troubleshooting
### "Invalid SAML Response" Error
* Verify your IdP certificate is correctly formatted with BEGIN/END lines
* Check that the certificate hasn't expired
* Ensure the ACS URL in your IdP matches exactly (including https\://)
### "Authentication Failed" Error
* Confirm the SSO Service URL is correct
* Check that the SAML application is assigned to the correct users in your IdP
* Verify the Name Identifier Format matches your IdP configuration
### Users Cannot Access After Authentication
* Ensure the status page authentication method is set to "SAML"
* Check that your IdP is sending the SAML response to the correct ACS URL
* Verify there are no network/firewall restrictions blocking the SAML flow
### Certificate Expiration
If your SAML certificate expires:
Download the new certificate from your IdP.
Navigate to your status page Authentication settings.
Update the IdP Certificate field with the new certificate.
Save the changes.
Set a calendar reminder 30 days before your certificate expiration date to ensure uninterrupted access.
## Switching Authentication Methods
You can change authentication methods at any time:
Navigate to your status page settings.
Go to the **Authentication** tab.
Select a different authentication method.
Configure any required fields.
Save your changes.
Changing from SAML or Password to "No Authentication" will make your status page publicly accessible immediately.
## API Configuration
Authentication methods can also be configured via the Rootly API:
```json theme={null}
PATCH /v1/status_pages/:id
{
"authentication_method": "saml",
"saml_idp_sso_service_url": "https://your-idp.com/sso/saml",
"saml_idp_cert": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"saml_name_identifier_format": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
}
```
See the [Rootly API documentation](/api-reference/overview) for complete details.
## Related Resources
Learn about the differences between public and private status pages
Get started with creating and managing status pages
***
## Related Pages
Set up the status page you'll add auth to — auth options only apply to public pages.
Point your own domain at the status page users authenticate against.
The umbrella concept — public vs private, and which auth options apply where.
# Status Page Public API
Source: https://docs.rootly.com/configuration/status-page-public-api
Access status and incident information programmatically through public JSON API endpoints exposed on your status page custom domain.
## Overview
Rootly exposes a public JSON API on your status page's custom domain, allowing you to programmatically retrieve current status and incident data. These endpoints are available at your custom domain (for example, `status.example.com`) and respect your status page's existing authentication settings — password-protected and SAML-protected pages are not exposed.
These endpoints are only available on status pages with a [custom domain](/configuration/custom-domain-names-for-status-pages) configured.
## Endpoints
### Get Current Status
Returns the overall status of your services along with any active incidents.
```http theme={null}
GET /api/v1/status.json
```
#### Get Current Status Response
```json theme={null}
{
"page": {
"name": "Acme Status",
"url": "https://status.example.com",
"time_zone": "America/Los_Angeles",
"updated_at": "2026-03-19T12:00:00Z"
},
"status": {
"indicator": "none",
"description": "All Systems Operational"
},
"incidents": []
}
```
The `status.indicator` field can be one of:
| Indicator | Description |
| ------------- | ------------------------------------------------ |
| `none` | All systems operational |
| `minor` | Minor service outage or degraded performance |
| `major` | Major service outage or critical incident active |
| `maintenance` | Scheduled maintenance in progress |
### List Incidents
Returns a paginated list of active incidents, ordered by most recent first.
```http theme={null}
GET /api/v1/incidents.json
```
#### Query Parameters
| Parameter | Type | Default | Description |
| ---------- | ------- | ------- | -------------------------------------- |
| `page` | integer | 1 | Page number |
| `per_page` | integer | 25 | Number of incidents per page (max 100) |
#### List Incidents Response
```json theme={null}
{
"page": {
"name": "Acme Status",
"url": "https://status.example.com",
"time_zone": "America/Los_Angeles",
"updated_at": "2026-03-19T12:00:00Z"
},
"incidents": [
{
"name": "API Degradation",
"status": "started",
"impact": "minor",
"started_at": "2026-03-19T10:30:00Z",
"resolved_at": null,
"url": "https://status.example.com/incidents/abc123",
"incident_updates": [
{
"body": "We are investigating reports of elevated API latency.",
"status": "investigating",
"created_at": "2026-03-19T10:35:00Z"
}
]
}
],
"pagination": {
"current_page": 1,
"per_page": 25,
"total_pages": 1,
"total_count": 1
}
}
```
## Incident Impact Levels
The `impact` field on each incident maps from the incident's severity:
| Severity | Impact |
| -------- | ---------- |
| Critical | `critical` |
| High | `major` |
| Medium | `minor` |
| Low | `minor` |
| None | `none` |
## Authentication
These API endpoints respect the same authentication settings as your status page:
* **Public status pages**: Endpoints are accessible without authentication
* **Password-protected pages**: Endpoints require the same password
* **SAML-protected pages**: Endpoints require SAML authentication
## Example Usage
```bash theme={null}
# Get current status
curl https://status.example.com/api/v1/status.json
# List incidents with pagination
curl "https://status.example.com/api/v1/incidents.json?page=1&per_page=10"
```
***
## Related Pages
The umbrella concept — the public and private pages this API is the JSON surface of.
How updates land on a status page — this API is the read side of the same data.
The API sits on the same domain — auth mirrors the page's auth mode.
# Status pages for internal and customer updates
Source: https://docs.rootly.com/configuration/status-pages
Create and manage status pages to communicate service health and incident information to internal stakeholders and external customers in real-time.
## What's a Status Page?
Status pages allow you to quickly communicate information about the health of your services and applications to internal stakeholders and external customers.
This helps save time for team members who might be actively involved in responding to an incident, or customer support staff who need to direct end users to a centralized place for live updates about your organization.
It only takes about a minute to set up a status page, so set one up soon after you've [signed up](/quick-start-guide).
## Public or Private?
This is the first choice you make, and it shapes everything after it. The page type sets who can reach the page at all; [authentication](/configuration/status-page-authentication-methods) and a [custom domain](/configuration/custom-domain-names-for-status-pages) are options you layer on top of a public page afterwards.
Rootly has two types of status pages available: public status pages and private status pages. Both can be used to communicate relevant information about ongoing or past incidents and the status of incidents and services.
By default, you will have a public and private status page to customize and configure. You can add additional pages from the Status Page section in Rootly.
Private status pages can only be accessed by Rootly users. These are great for communicating important incidents and service statuses to your internal teams.
Users must be logged in to Rootly to access this page.
Public status pages can be accessed by anyone who has access to the status page's URL. These are the perfect option to communicate incident updates and service statuses to your external stakeholders, like customers or partners.
***
## Related Pages
Set up a status page after picking a type.
Push incident updates to a status page from Web or Slack.
Point your own domain at a status page with CNAME + CAA records.
# Subprocessors
Source: https://docs.rootly.com/configuration/subprocessors
The third-party subprocessors Rootly uses to deliver its services, what each one is used for, and the categories of customer data each one processes.
## Overview
A **subprocessor** is a third party Rootly engages to process customer personal data in the course of delivering the Rootly platform. This page lists those subprocessors, grouped by the function they serve.
This list covers processing performed by Rootly. It does not cover integrations you connect yourself — see [Customer-enabled integrations](#customer-enabled-integrations) below for that distinction.
All subprocessors listed here are bound by data processing agreements. Data sent to subprocessors is used solely to provide Rootly services and is not used for model training.
***
## Infrastructure
Core infrastructure that Rootly runs on, including hosting, networking, and data transit.
| Subprocessor | Purpose | Data processed |
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| [Amazon Web Services](https://aws.amazon.com) | Primary cloud infrastructure — compute, application databases, object storage, queuing, and event routing. Rootly runs entirely on AWS. | All customer data stored in Rootly, encrypted at rest |
| [Cloudflare](https://cloudflare.com) | Content delivery, edge networking, and web application firewall | HTTP request data and tenant identifiers |
| [ClickHouse Cloud](https://clickhouse.com/cloud) | Columnar analytics database for AI evaluation and product analytics | AI evaluation datasets and product usage metrics |
| [QuotaGuard](https://www.quotaguard.com) | Static IP proxy for outbound integration traffic | HTTP request payloads transiting to customer-connected integrations |
***
## AI Features
Applies to Rootly AI features. See [Data Privacy for AI](/ai/data-privacy-for-ai) for the full safeguards, retention terms, and bring-your-own-key options.
| Subprocessor | Purpose | Data processed |
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| [OpenAI](https://openai.com) | LLM inference for AI-powered summarization, catchup, and generative features | Incident content submitted for AI processing |
| [Anthropic](https://anthropic.com) | LLM inference for AI-powered summarization, catchup, and generative features | Incident content submitted for AI processing |
| [Amazon Bedrock](https://aws.amazon.com/bedrock/) | Hosted model inference for AI-powered summarization, catchup, and generative features | Incident content submitted for AI processing |
| [Braintrust](https://braintrust.dev) | AI gateway and observability — LLM request routing, tracing, and evaluation | Incident content and other data submitted for AI processing |
| [Recall.ai](https://recall.ai) | Meeting orchestration, recording capture, and platform connectivity for [AI Meeting Scribe](/ai/meeting-scribe) | Meeting audio/video streams, bot lifecycle events |
| [AssemblyAI](https://assemblyai.com) (via Recall.ai) | Speech-to-text transcription, summarization, PII redaction, and speaker identification | Meeting audio for transcription |
***
## Notifications and alerting
How Rootly reaches responders when they are paged.
| Subprocessor | Purpose | Data processed |
| -------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------- |
| [Twilio](https://twilio.com) | SMS and voice call delivery for on-call paging and live call routing | Phone numbers, alert and notification content |
| [SendGrid](https://sendgrid.com) | Transactional and notification email delivery | Email addresses, notification content |
| [Mailgun](https://mailgun.com) (Sinch AB) | Transactional email delivery | Email addresses, notification content |
| [Firebase Cloud Messaging](https://firebase.google.com/products/cloud-messaging) | Push notification delivery to Android devices | Device push tokens, notification content |
| [Apple Push Notification service](https://developer.apple.com/notifications/) | Push notification delivery to iOS devices | Device push tokens, notification content |
| [Pushy](https://pushy.me) | Push notification delivery for devices in regions where FCM is unavailable | Device push tokens, notification content |
***
## Platform Operations
Tooling Rootly uses to keep the service running and reliable. These process operational telemetry, which can incidentally contain user identifiers.
| Subprocessor | Purpose | Data processed |
| ------------------------------------------------------ | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| [Datadog](https://datadoghq.com) | Application performance monitoring, logging, and infrastructure observability | Application logs and telemetry, which may include user and team identifiers |
| [Sentry](https://sentry.io) | Application error and exception tracking | Error traces and request context, which may include user and team identifiers |
| [pganalyze](https://pganalyze.com) (Duboce Labs, Inc.) | Database performance monitoring and query analytics | Database query patterns and telemetry, which may include user and team identifiers |
| [LaunchDarkly](https://launchdarkly.com) | Feature flag evaluation and progressive rollout targeting | Team and user identifiers used as targeting keys |
| [Short.io](https://short.io) | URL shortening for incident and retrospective links (root.ly domain) | Incident and retrospective URLs |
***
## Business Operations and Analytics
Internal tooling Rootly personnel use to support accounts, troubleshoot issues, and analyze product usage.
| Subprocessor | Purpose | Data processed |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| [Google Workspace](https://workspace.google.com) (Alphabet Inc.) | Corporate email, document storage, and productivity tools used by Rootly personnel | Employee and customer communication content, shared documents |
| [Segment](https://segment.com) | Customer data platform for product analytics event routing | User profile data, product usage events |
| [PostHog](https://posthog.com) | Product analytics and user behavior tracking | User and team identifiers, product usage events |
| [HubSpot](https://hubspot.com) | CRM for account management and customer communication | User profile data and account metadata |
| [Salesforce](https://salesforce.com) | CRM for account management and customer communication | User profile data and account metadata |
| [Pylon](https://usepylon.com) | Customer support platform | User profile data, support ticket content |
| [Linear](https://linear.app) (Linear Orbit, Inc.) | Internal support ticket tracking | User profile data, support ticket content |
| [Oliv.ai](https://oliv.ai) | Product and customer analytics | User profile data and product usage metrics |
| [Metabase](https://metabase.com) | Business intelligence. Rootly personnel run read-only queries against production application data to support customer accounts, troubleshoot issues, and analyze product usage. | User profile data (names, email addresses, phone numbers), incident and alert records, and associated metadata |
| [Snowflake](https://snowflake.com) | Data warehouse for aggregated product usage and account health analytics | Product usage metrics and account metadata |
| [Stripe](https://stripe.com) | Subscription billing and payment processing | Billing contact details and payment metadata |
***
## Communication and support
How Rootly personnel communicate internally and with customers.
| Subprocessor | Purpose | Data processed |
| ---------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------------- |
| [Slack](https://slack.com) (Slack Technologies, LLC) | Internal team communication and incident coordination | User identifiers, message content |
| [Intercom](https://intercom.com) (Intercom, Inc.) | In-app live chat and customer support | User profile data, support conversation content |
***
## Customer-Enabled Integrations
Rootly connects to a wide range of third-party tools — Microsoft Teams, Jira, PagerDuty, GitHub, Datadog as an alert source, and [many others](/integrations/overview).
These are **not** Rootly subprocessors. You enable them, you control the credentials, and data flows to them at your direction under your own agreement with that vendor. Rootly acts on your instruction to send data to a destination you chose.
The distinction matters for your own DPA: the vendors listed above process your data because Rootly engaged them. Integration vendors process your data because you did.
***
## Changes to this list
Rootly maintains a data processing agreement covering the processors listed here. To request the current DPA, or to ask about notification of changes to this list, contact your account team or [security@rootly.com](mailto:security@rootly.com).
Additional compliance artifacts — SOC 2 Type II report, penetration test results, and security policies — are available through the [Rootly Trust Center](https://security.rootly.com).
# Teams
Source: https://docs.rootly.com/configuration/teams
Configure team attributes in Rootly including Slack channels, user groups, escalation policies, on-call schedules, and imports from PagerDuty or Opsgenie.
## Overview
Teams in Rootly let you organize your on-call and incident response processes around your organization's teams. Teams can be paged, assigned to an incident, and be used to build powerful workflow automations.
This section outlines how Teams can be used as an attribute in your incident response processes. Learn more about [building and managing Teams](/managing-teams/managing-teams) in the Rootly Admin.
## Field Type
**Teams** can be customized to be either a **select** or **multi-select** field type. This means you can configure it to allow only one team value to be selected per incident or allow multiple team values to be selected for a single incident.
## Attributes
**Teams** can be configured with the following attributes. Each team attribute can be referenced via Liquid syntax.
*Team* originally was called *group*. Hence all data values you see reference groups. Due to the risk of changing data values, Rootly kept referencing teams as groups from a data point of view.
From a UI display point of view, you will see the term "*teams*" being used.
Since the *team* field can be either a **select** or **multi-select** field type, the Liquid syntax to reference each field type will differ.
Select will follow a single-value syntax
`{{incident.raw_groups | get: ''}}`
Multi-select will follow an array syntax. Where i references the specific team object in the list of teams.
`{{incident.raw_groups[index] | get: ''}}`
### ID
This is the unique identifier of the team. This field **cannot be customized**. Rootly will automatically assign the *ID* upon creation. It is typically used in Liquid references and API calls.
The following Liquid syntax will allow you to list out the team *ID*(s) that are selected for an incident:
`{{ incident.group_ids }}`
**OR**
* `{{ incident.raw_groups | get: 'id'}}` for select field type
* `{{ incident.raw_groups[index] | get: 'id' }}` for multi-select field type
### Name
This is the value that is displayed on the UI for the team. This field is customizable.
The following Liquid syntax will allow you to list out the team *name*(s) that are selected for an incident:
`{{ incident.groups }}`
**OR**
* `{{ incident.raw_groups | get: 'name'}}` for select field type
* `{{ incident.raw_groups[index] | get: 'name' }}` for multi-select field type
### Slug
This is the string that is used to reference the team in Liquid references. This field is automatically generated by lower-casing and hyphenating the team *name*.
The following Liquid syntax will allow you to list out the team *slug*(s) that are selected for an incident:
`{{ incident.group_slugs }}`
**OR**
* `{{ incident.raw_groups | get: 'slug'}}` for select field type
* `{{ incident.raw_groups[index] | get: 'slug' }}` for multi-select field type
### Description
This value is displayed on the UI to further explain each team. This field is customizable.
The following Liquid syntax will allow you to list out the team *description*(s) that are selected for an incident:
* `{{ incident.raw_groups | get: 'description'}}` for select field type
* `{{ incident.raw_groups[index] | get: 'description' }}` for multi-select field type
### Color
Each team can be assigned a color, which will be used for color-coding on metrics graphs.
Rootly uses **color-hex codes**. For example, #000000 is black, #ffffff is white. Use [color-hex.com](https://www.color-hex.com/) to find the exact hex code for the color you want.
The following Liquid syntax will allow you to list out the team *color*(s) that are selected for an incident:
* `{{ incident.raw_groups | get: 'color'}}` for select field type
* `{{ incident.raw_groups[index] | get: 'color' }}` for multi-select field type
### Slack Channels
Each team can be linked to one or more Slack channels. By default, Rootly does not notify the linked channel(s) when a team is selected for an incident. Notification needs to be explicitly called out as Attached Teams Channels in workflow configurations.
Systematically, each Slack channel is stored as an object containing an ID and name.
The following Liquid syntax will allow you to list out the team *Slack Channel*(s) that are selected for an incident:
* `{{ incident.raw_groups | get: 'slack_channels'}}` for select field type
* `{{ incident.raw_groups[index] | get: 'slack_channels' }}` for multi-select field type
### Slack Aliases
Each team can be linked to one or more Slack user groups (aka aliases). By default, Rootly does not invite users in the linked user group(s) when a team is selected for an incident. Invitations need to be explicitly called out as Attached Teams Aliases in workflow configurations.
The following Liquid syntax will allow you to list out the team *Slack Alias*(es) that are selected for an incident:
* `{{ incident.raw_groups | get: 'slack_aliases'}}` for select field type
* `{{ incident.raw_groups[index] | get: 'slack_aliases' }}` for multi-select field type
### Notify Emails
Each team can be linked to one or more emails. By default, Rootly does not send emails to the linked address(es) when a team is selected for an incident. Notification needs to be explicitly called out as `{{ incident.raw_groups | map: 'notify_emails' | flatten | join: ',' }}` in workflow configurations.
The following Liquid syntax will allow you to list out the team *Notify Email*(s) that are selected for an incident:
* `{{ incident.raw_groups | get: 'notify_emails'}}` for select field type
* `{{ incident.raw_groups[index] | get: 'notify_emails' }}` for multi-select field type
## Import Teams
Instead of creating teams from scratch, Rootly allows you to import teams from **PagerDuty**, **Opsgenie**, **VictorOps**, or **PagerTree**. Imported teams will be automatically kept in sync on a daily basis.
The ability to import teams will only become available once you have PagerDuty, Opsgenie, VictorOps, or PagerTree installed on the [integrations page](https://rootly.com/account/integrations).
The following Liquid syntax will allow you to list out the corresponding IDs from each of the external paging applications:
**PagerDuty**
* `{{ incident.raw_groups | get: 'pagerduty_id' }}` for select field type
* `{{ incident.raw_groups\[0\] | get: 'pagerduty_id' }}` for multi-select field type
**Opsgenie**
* `{{ incident.raw_groups | get: 'opsgenie_id' }}` for select field type
* `{{ incident.raw_groups\[0\] | get: 'opsgenie_id' }}` for multi-select field type
**VictorOps**
* `{{ incident.raw_groups | get: 'victor_ops_id' }}` for select field type
* `{{ incident.raw_groups\[0\] | get: 'victor_ops_id' }}` for multi-select field type
**PagerTree**
* `{{ incident.raw_groups | get: 'pagertree_id' }}` for select field type
* `{{ incident.raw_groups\[0\] | get: 'pagertree_id' }}` for multi-select field type
***
## Related Pages
Where teams are created, edited, and organized — this page covers Teams as an incident attribute.
Services are typically owned by teams — the link that drives service ownership and paging.
Higher-level customer-facing capabilities that teams own alongside their services.
# Outgoing Webhooks
Source: https://docs.rootly.com/configuration/webhooks
Send real-time event notifications from Rootly to any external HTTP endpoint as incidents, alerts, pulses, and workflows progress through their lifecycles.
## Overview
Outgoing webhooks let you push Rootly events to any system that accepts HTTP POST requests — a custom internal tool, a data pipeline, an audit log, or a third-party service that does not have a native Rootly integration.
Each webhook endpoint you configure receives a JSON payload for the event types you subscribe it to. Rootly signs every delivery so your server can verify the payload came from Rootly.
## Create a Webhook Endpoint
Go to **Settings → Webhooks** and click **New Webhook**.
Give the endpoint a descriptive name and enter the destination URL. The URL must be publicly reachable and accept HTTPS POST requests.
A label for this endpoint, unique within your team.
The HTTPS endpoint that will receive event payloads.
Choose which events this endpoint should receive. If you leave the event types list empty, the endpoint will receive **all** events.
See [Event Types](#event-types) below for the full list.
Click **Save**. Rootly generates a signing secret for this endpoint automatically. Copy it now — it is only shown once. You will use it to verify incoming payloads on your server.
The signing secret cannot be retrieved after you leave this page. If you lose it, you can regenerate it from the endpoint's edit form, which will invalidate the old secret immediately.
***
## Event Types
Subscribe an endpoint to one or more event types. An empty subscription list means the endpoint receives all events.
### Incidents
| Event | When it fires |
| -------------------- | ---------------------------------- |
| `incident.created` | A new incident is opened |
| `incident.updated` | Any field on the incident changes |
| `incident.in_triage` | Incident moves to In Triage status |
| `incident.mitigated` | Incident is marked as mitigated |
| `incident.resolved` | Incident is resolved |
| `incident.cancelled` | Incident is cancelled |
| `incident.deleted` | Incident is deleted |
### Scheduled Incidents
| Event | When it fires |
| -------------------------------- | ----------------------------------- |
| `incident.scheduled.created` | A scheduled incident is created |
| `incident.scheduled.updated` | A scheduled incident is updated |
| `incident.scheduled.in_progress` | A scheduled incident becomes active |
| `incident.scheduled.completed` | A scheduled incident completes |
| `incident.scheduled.deleted` | A scheduled incident is deleted |
### Retrospectives
| Event | When it fires |
| -------------------------------- | ---------------------------- |
| `incident_post_mortem.created` | A retrospective is created |
| `incident_post_mortem.updated` | A retrospective is updated |
| `incident_post_mortem.published` | A retrospective is published |
| `incident_post_mortem.deleted` | A retrospective is deleted |
### Status Page Events
| Event | When it fires |
| ------------------------------------ | ------------------------------ |
| `incident_status_page_event.created` | A status page event is created |
| `incident_status_page_event.updated` | A status page event is updated |
| `incident_status_page_event.deleted` | A status page event is deleted |
### Timeline Events
| Event | When it fires |
| ------------------------ | ---------------------------------------- |
| `incident_event.created` | A timeline event is added to an incident |
| `incident_event.updated` | A timeline event is updated |
| `incident_event.deleted` | A timeline event is deleted |
### Alerts and Pulses
| Event | When it fires |
| --------------- | ----------------------------------------------------------------------------------- |
| `alert.created` | An alert is created in Rootly |
| `alert.updated` | An alert changes or a timeline event is added, including manual ownership transfers |
| `pulse.created` | A pulse is created |
### Workflows
| Event | When it fires |
| ------------------------------- | ------------------------------------- |
| `genius_workflow_run.queued` | A workflow run is queued |
| `genius_workflow_run.started` | A workflow run begins executing |
| `genius_workflow_run.completed` | A workflow run completes successfully |
| `genius_workflow_run.failed` | A workflow run fails |
| `genius_workflow_run.canceled` | A workflow run is cancelled |
For payload examples for the most common event types, see [Event Payloads](/configuration/event-payloads).
***
## Delivery and Retries
Each event triggers a separate HTTP POST to every matching enabled endpoint. Rootly expects a `2xx` response within **10 seconds**. If the delivery fails or times out, Rootly retries automatically on the following schedule:
| Attempt | Delay after previous failure |
| --------- | ---------------------------- |
| 1st retry | 15 seconds |
| 2nd retry | 1 minute |
| 3rd retry | 5 minutes |
After three failed retries the delivery is abandoned. You can inspect delivery history — including response status codes and response bodies — from the endpoint detail page in **Settings → Webhooks**.
Retries use the same payload as the original attempt. If your endpoint processed the event before returning an error, implement idempotency using the event ID in the payload to avoid duplicate processing.
***
## Verifying Webhook Signatures
Every delivery includes an `X-Rootly-Signature` header containing a timestamp and an HMAC-SHA256 signature. Use this to confirm the payload originated from Rootly.
```txt theme={null}
X-Rootly-Signature: t=1492774588,v1=6657a869e8ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
```
To verify:
Extract the timestamp (`t=`) and signature (`v1=`) from the header.
Concatenate the timestamp with the raw request body.
Compute an HMAC-SHA256 digest of that string using your endpoint's signing secret.
Compare the result to the `v1` value. If they match, the payload is authentic.
```ruby Ruby theme={null}
require 'openssl'
require 'rack'
header = request.headers['X-Rootly-Signature']
parts = header.split(',')
timestamp = parts[0].split('t=').last
signature = parts[1].split('v1=').last
secret = 'your_webhook_secret'
expected = OpenSSL::HMAC.hexdigest('SHA256', secret, timestamp + request.body.read)
is_valid = Rack::Utils.secure_compare(expected, signature)
```
```python Python theme={null}
import hmac
import hashlib
header = request.headers['X-Rootly-Signature']
parts = header.split(',')
timestamp = parts[0].split('t=')[1]
signature = parts[1].split('v1=')[1]
secret = "your_webhook_secret"
expected = hmac.new(
key=secret.encode(),
msg=(timestamp + request.data.decode()).encode(),
digestmod=hashlib.sha256
).hexdigest()
is_valid = hmac.compare_digest(expected, signature)
```
```javascript Node.js theme={null}
const crypto = require('crypto');
const header = request.headers['x-rootly-signature'];
const parts = header.split(',');
const timestamp = parts[0].split('t=')[1];
const signature = parts[1].split('v1=')[1];
const secret = "your_webhook_secret";
// Use the raw request body, not the parsed body.
// In Express, configure express.raw({ type: 'application/json' }) and use req.body directly,
// or capture the raw body via a middleware before any JSON parsing.
const rawBody = request.rawBody; // string or Buffer
const expected = Buffer.from(
crypto.createHmac('sha256', secret)
.update(timestamp + rawBody)
.digest('hex')
);
const received = Buffer.from(signature);
const isValid = expected.length === received.length &&
crypto.timingSafeEqual(expected, received);
```
To prevent replay attacks, also check that the timestamp in the header is within a few minutes of the current time before accepting the payload.
***
## Manage Endpoints
From **Settings → Webhooks** you can:
* **Enable or disable** an endpoint without deleting it — disabled endpoints receive no deliveries.
* **Edit** the name, URL, or event subscriptions at any time.
* **View delivery history** for each endpoint, including the HTTP status code and response body for each attempt.
* **Delete** an endpoint to permanently stop deliveries to that URL.
***
## Troubleshooting
Check that the endpoint is **enabled** in **Settings → Webhooks**. Also verify that the event types you expect are included in the endpoint's subscription, or that the subscription list is empty (which receives all events). If the URL requires authentication headers or is behind an IP allowlist, those must be handled at the receiving server — Rootly sends only the `X-Rootly-Signature` header alongside the standard `Content-Type: application/json` header.
Rootly waits up to 10 seconds for a response. If your endpoint takes longer to process, return a `200` immediately and handle the payload asynchronously. Rootly will retry failed deliveries up to three times before abandoning the delivery.
You can regenerate the signing secret from the endpoint's edit form in **Settings → Webhooks**. Regenerating immediately invalidates the old secret, so update your server-side verification logic before regenerating.
Use a tool like [ngrok](https://ngrok.com) or [localtunnel](https://theboroer.github.io/localtunnel-www/) to expose a local port over a public HTTPS URL, then register that URL as a webhook endpoint in Rootly. Trigger a test event by creating or updating an incident, and inspect the delivery in the endpoint detail view.
***
## Related Pages
Payload structure reference for every webhook event type Rootly emits.
HMAC signature verification is one part of a broader tenant-hardening checklist.
The umbrella page covering incident properties and configuration surface.
# Contacting Support
Source: https://docs.rootly.com/contacting-support
How to reach Rootly support: email and status page, what to include in your report, and how to grab a device dump from the mobile app.
Have a question, or something not working? Here's how to reach Rootly support, and what to send so they can help on the first reply.
## How to reach us
* Email [**support@rootly.com**](mailto:support@rootly.com) (in the mobile app, this is **Settings → Email support**).
## What to include
Helpful details to include:
* A **device dump** from the app (see below). It captures the app version, device model, OS, and push provider.
* The **specific alert** that misbehaved: the link (`rootly.com/account/alerts/…`) or the date and time you expected a page.
* **What you saw vs. expected**, for example "the page arrived silently," "the call didn't ring," or "stuck on the login screen."
* For **login issues:** your sign-in method (Okta, Google, Slack, email) and whether signing in at rootly.com in a desktop browser works.
* **What you already tried** from the troubleshooting guide.
* If you can, a **screen recording** of a failed test alert (**Settings → Troubleshooting → Send a test alert**).
## How to grab a device dump
The app can copy a full diagnostic to your clipboard in three taps:
In the Rootly app, open **Settings** and tap **About**.
Tap the **Version** (for example, `v2.14.0`) five times quickly. A **Device Info** panel appears.
Tap **Copy device info**, then paste it into your email to support.
Check the Rootly [status page](https://status.rootly.com/) for platform status and ongoing incidents.
# Rootly Edge Connector for on-premises systems
Source: https://docs.rootly.com/edge-connectors
Securely integrate Rootly with internal systems that cannot accept inbound internet connections using outbound-only polling through the Edge Connector.
## Overview
The Rootly Edge Connector is a lightweight agent that enables secure, bidirectional integration between Rootly and internal or on-premises systems that cannot accept inbound internet connections. It uses an outbound-only polling model to listen for events from Rootly and execute local actions in response.
Edge Connectors are ideal for organizations with strict security requirements where opening inbound firewall ports is not permitted or desirable.
## Key Benefits
* **Enhanced Security**: No inbound firewall rules required - only outbound HTTPS connections
* **Flexibility**: Execute any script or automation in response to Rootly events
* **Auditability**: Full Git-based configuration and comprehensive execution logs
* **Reliability**: Event queueing with retry logic ensures no missed actions
* **Seamless Integration**: Bridge cloud-based Rootly with on-premises systems
## How It Works
```mermaid theme={null}
graph TD
A[Rootly Cloud
rec.rootly.com] -->|HTTPS Outbound Only
Poll every N seconds| B[Corporate Firewall
No inbound ports required]
B --> C[Rootly Edge Connector]
C -->|Polls for events| A
C -->|Executes local scripts| D[Internal Systems]
C -->|Reports results back| A
subgraph "Internal Network / On-Premises"
C
D[Internal Systems
• Monitoring tools
• ITSM platforms
• Automation scripts]
end
style A fill:#8b5cf6,stroke:#7c3aed,stroke-width:2px,color:#fff
style B fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px
style C fill:#10b981,stroke:#059669,stroke-width:2px,color:#fff
style D fill:#3b82f6,stroke:#2563eb,stroke-width:2px,color:#fff
```
### Communication Flow
1. **Polling**: The Edge Connector polls Rootly's API at regular intervals for new events
2. **Event Processing**: When events are received, the connector maps them to configured actions
3. **Execution**: Allowlisted scripts are executed with event context as parameters
4. **Reporting**: Results and logs are sent back to Rootly for visibility and audit
## Security Model
### Why Outbound-Only is More Secure
**Traditional Webhook Approach** (Inbound):
* Requires exposing an endpoint to the internet
* Must configure and maintain TLS termination
* Attack surface for scanning, probing, and DDoS
* Firewall changes and security reviews required
**Edge Connector Approach** (Outbound):
* Only outbound HTTPS (same as normal web browsing)
* No exposed endpoints for attackers to discover
* No firewall changes needed
* Cannot be directly targeted from the internet
### Additional Security Features
* **API Key Scoping**: Create Edge Connector-specific API keys with minimal permissions
* **Script Whitelisting**: Only approved, version-controlled scripts can execute
* **Team-based Authorization**: Map Rootly teams to allowed local actions
* **Audit Trail**: Every action logged with full context (who, what, when)
* **Network Isolation**: Run the connector on a dedicated, isolated host
## Getting Started
### Prerequisites
* Rootly team with Edge Connector feature enabled
* Ability to run a service in your internal network
* API key with Edge Connector permissions
### Request Access
Edge Connector is an enterprise feature that requires enablement by Rootly administrators.
To request access:
1. Navigate to **Settings** → **Edge Connectors** in Rootly
2. Click **Request Access**
3. Your team administrators will be notified
4. Contact [sales@rootly.com](mailto:sales@rootly.com) for feature enablement
### Setup Overview
1. **Create an Edge Connector in Rootly**
* Navigate to Settings → Edge Connectors
* Click "Create Edge Connector"
* Configure name and event subscriptions
* Generate an API key
2. **Install the Edge Connector Agent**
* See the [Installation & Deployment](/edge-connectors-installation) guide for detailed setup instructions
3. **Configure Actions**
* See the [Action Configuration](/edge-connectors-actions) guide to define your automations
4. **Monitor and Maintain**
* View connector status in Rootly dashboard
* Review execution logs
* Update scripts as needed
**Quick Links:**
* [Installation & Deployment](/edge-connectors-installation) - Install and run the Edge Connector
* [Action Configuration](/edge-connectors-actions) - Define script and HTTP actions
* [Template Syntax](/edge-connectors-templates) - Use dynamic values in actions
* [Event Examples](/edge-connectors-event-examples) - See example event payloads
## Action Types
Edge Connector actions fall into two categories:
### Automatic Actions
These run automatically in response to system events, without user interaction. Configured in the `on:` section of `actions.yml`.
**Examples:** Auto-restart services when alerts fire, send notifications when incidents are created, collect diagnostics automatically.
### Callable Actions
These are triggered manually by users from the Rootly UI with interactive buttons and forms. Configured in the `callable:` section of `actions.yml`.
**Examples:** Manual service restart, deploy hotfix, scale infrastructure, clear cache on demand.
For a detailed comparison including UI behavior, registration process, and configuration differences, see the [Action Configuration Guide](/edge-connectors-actions#automatic-vs-callable-actions).
## Supported Event Types
Edge Connectors support two categories of events:
### Automatic Event Types
These events are triggered automatically by system events and can be subscribed to when configuring your Edge Connector:
**Alert Events:**
* `alert.created` - New alert from monitoring system
* `alert.updated` - Alert properties changed
* `alert.acknowledged` - Alert acknowledged by a user
* `alert.resolved` - Alert marked as resolved
* `alert.deleted` - Alert removed
**Incident Events:**
* `incident.created` - New incident started
* `incident.updated` - Incident properties changed
* `incident.in_triage` - Incident moved to triage status
* `incident.mitigated` - Incident mitigated
* `incident.resolved` - Incident marked resolved
* `incident.cancelled` - Incident cancelled
* `incident.deleted` - Incident deleted
### Manual Trigger Event Types
These events are triggered by user actions and are configured per action:
* `action.triggered` - Standalone action triggered by a user
* `alert.action_triggered` - Action triggered from an alert context
* `incident.action_triggered` - Action triggered from an incident context
You can configure which automatic events your Edge Connector subscribes to when creating or editing it in the Rootly UI. Manual trigger events are configured in your action definitions. For detailed payload examples and templating patterns, see the [Event Examples](/edge-connectors-event-examples) page.
## Use Cases
### Automated Remediation
Automatically restart services or run diagnostic scripts when critical alerts are detected. Perfect for known issues that have established remediation procedures.
### Internal System Integration
Create tickets in internal ITSM systems that aren't accessible from the internet. Bridge Rootly with on-premises Jira, ServiceNow, or custom ticketing systems.
### Hybrid Cloud Orchestration
Run Ansible playbooks or other automation tools in response to incident lifecycle events. Trigger infrastructure changes, scaling operations, or deployment rollbacks.
### Diagnostic Collection
Automatically collect logs, metrics, and diagnostics when incidents occur. Gather context automatically to speed up incident investigation.
See the [Action Configuration](/edge-connectors-actions) guide for detailed examples of these use cases with complete action definitions.
## Managing Edge Connectors
### Viewing Connector Status
In the Rootly dashboard, you can monitor:
* **Online Status**: Whether the connector is actively polling
* **Last Poll Time**: When the connector last checked for events
* **Events Pending**: Number of events waiting to be processed
* **Recent Executions**: Logs of recently executed actions
### API Key Management
Each Edge Connector requires an API key:
1. Navigate to **Settings** → **API Keys**
2. Create a new key with type **Edge Connector**
3. Associate it with your Edge Connector
4. Store the key securely on your connector host
API keys should be rotated regularly and stored securely. Never commit API keys to version control.
## Documentation
* **[Installation & Deployment](/edge-connectors-installation)** - Install and configure the Edge Connector in your environment
* **[Action Configuration](/edge-connectors-actions)** - Define script and HTTP actions to automate responses
* **[Template Syntax](/edge-connectors-templates)** - Use Liquid templates for dynamic values in actions
* **[Event Examples](/edge-connectors-event-examples)** - Reference for event payload structures and fields
## Best Practices
**Security:**
* Run the Edge Connector on a dedicated, isolated host
* Store secrets in environment variables, never in configuration files
* Version control all scripts and review through pull requests
* Rotate API keys periodically
**Reliability:**
* Configure appropriate polling intervals (typically 10-30 seconds)
* Set reasonable script timeouts based on expected execution time
* Implement retry logic in your scripts for transient failures
* Monitor connector health and set up downtime alerts
**Configuration:**
* Use descriptive names for connectors and actions
* Document script requirements and dependencies
* Test actions thoroughly before production deployment
* Keep the connector software updated
For detailed troubleshooting, see the [Installation & Deployment](/edge-connectors-installation#troubleshooting) guide.
# Action Configuration
Source: https://docs.rootly.com/edge-connectors-actions
Configure script and HTTP actions for Rootly Edge Connectors to automate responses to events from internal systems behind your firewall using outbound polling.
## Overview
Actions define what your Edge Connector executes in response to events. Each action specifies:
* **Type**: Script or HTTP request
* **Source Type**: Local scripts or Git-based scripts
* **Trigger**: Which events activate this action
* **Parameters**: User-configurable inputs (for manual triggers)
* **Execution details**: Scripts to run or HTTP requests to make
## Automatic vs Callable Actions
Edge Connector actions fall into two categories with different behaviors:
### Automatic Actions (`on:` section)
**What they are:**
* Execute automatically in response to Rootly system events
* Run without user interaction
* Configured in the `on:` section where the event type is the key
**When to use:**
* Auto-remediation (restart services when alerts fire)
* Notifications (send webhooks when incidents are created)
* Data collection (gather logs when alerts trigger)
* Monitoring integration (sync status to external systems)
**Configuration:**
```yaml theme={null}
on:
alert.created: # Event type is the key
script: /opt/scripts/handle-alert.sh
parameters:
alert_id: "{{ id }}"
severity: "{{ labels.severity }}"
timeout: 60
```
**Characteristics:**
* ✅ No `parameter_definitions` needed (no user input)
* ✅ Execute immediately when events occur
* ✅ Registered with backend for visibility/audit
* ✅ Appear in Rootly UI as read-only badges (visible but not clickable)
* ✅ Users can see what automations are configured
**How they appear in Rootly UI:**
* Badge: "🔄 Script: alert.created" or "🌐 HTTP: incident.created"
* Read-only display showing what's automated
* No interaction possible (run automatically only)
### Callable Actions (`callable:` section)
**What they are:**
* Triggered manually by users from the Rootly UI
* Require user input via parameter forms
* Configured in the `callable:` section where the action slug is the key
**When to use:**
* Manual remediation (restart specific services on demand)
* User-initiated operations (deploy hotfixes, scale infrastructure)
* Diagnostic tools (collect logs, run health checks)
* Administrative tasks (clear caches, trigger backups)
**Configuration:**
```yaml theme={null}
callable:
restart_service: # Action slug is the key
name: "Restart Service" # Display name in UI (required)
description: "Restart a production service with graceful shutdown"
trigger: alert.action_triggered # Shows on alerts
script: /opt/scripts/restart.sh
parameter_definitions: # Creates UI form
- name: service_name
type: string
required: true
description: "Service to restart"
timeout: 120
```
**Characteristics:**
* ✅ Require `parameter_definitions` to create UI forms
* ✅ Users provide input values before execution
* ✅ Registered with backend to generate UI buttons
* ✅ Appear in Rootly UI as interactive buttons
* ✅ Can be triggered from alerts, incidents, or standalone
**How they appear in Rootly UI:**
* Button: "Restart Service" with form dialog
* Users click → fill out form → submit → action executes
* Real-time execution status and results shown
### Comparison Table
| Feature | Automatic Actions (`on:`) | Callable Actions (`callable:`) |
| -------------------------- | ----------------------------------------------------- | ------------------------------------------- |
| **Trigger** | System events (alert.created, incident.created, etc.) | User clicks button in Rootly UI |
| **User Input** | None - uses event data only | Yes - users fill out parameter forms |
| **Config Section** | `on:` (event type is key) | `callable:` (action slug is key) |
| **parameter\_definitions** | Not needed | Required to create UI forms |
| **name** | Optional | Required for UI display |
| **UI Appearance** | Read-only badge (visible, not clickable) | Interactive button (clickable with form) |
| **Registration** | Registered for visibility | Registered to generate UI |
| **Execution** | Immediate when event occurs | On-demand when user triggers |
| **Use Cases** | Auto-remediation, notifications, monitoring | Manual operations, diagnostics, admin tasks |
### Registration Behavior
**Both automatic and callable actions are registered with the Rootly backend on connector startup:**
1. **Connector Startup:**
* Reads `actions.yml` configuration
* Sends all actions to `POST /rec/v1/actions` endpoint
* Backend syncs actions for this connector
2. **Backend Processing:**
* **Automatic actions** (no `parameter_definitions`):
* Stored for visibility and audit
* Displayed as read-only badges in UI
* Users can see what automations exist
* **Callable actions** (with `parameter_definitions`):
* UI forms generated from parameter definitions
* Displayed as interactive buttons
* Users can click and provide inputs
3. **Sync Behavior:**
* Backend matches actions by slug
* Creates new actions not seen before
* Updates existing actions with new configuration
* Removes actions no longer in config
**What gets sent to backend:**
* Action slug, name, description (for UI display)
* Action type (script or HTTP) and timeout
* Trigger event types
* Parameter definitions (for callable actions only)
**What stays on connector:**
* Script paths and execution details
* HTTP URLs, headers, and body templates
* Security settings and environment variables
The presence of `parameter_definitions` is what tells the backend whether an action is automatic (read-only) or callable (interactive).
## Action File Structure
Actions are defined in an `actions.yml` file with three main sections:
```yaml theme={null}
# Global defaults (optional)
defaults:
timeout: 30
source_type: local
env:
ENVIRONMENT: production
# Automatic actions - triggered by system events
on:
alert.created:
script: /path/to/script.sh
# ...
# Manual actions - triggered by users from UI
callable:
restart_service:
name: "Restart Service"
# ...
```
## Action Types
### Script Actions
Execute scripts from local filesystem or Git repositories.
#### Local Scripts
Execute scripts stored on the Edge Connector host:
```yaml theme={null}
callable:
restart_service:
name: "Restart Production Service"
description: |
Restarts the specified service with graceful shutdown.
Use when service becomes unresponsive.
trigger: alert.action_triggered
script: /opt/scripts/restart-service.sh
parameter_definitions:
- name: service_name
type: string
required: true
description: "Service to restart"
- name: environment
type: string
required: false
default: "production"
options: ["development", "staging", "production"]
timeout: 300
```
**Key Fields:**
* `script`: Absolute path to the script to execute
* `timeout`: Maximum execution time in seconds
* `parameter_definitions`: User inputs when triggered manually
* `trigger`: Specifies the event type (`alert.action_triggered`, `incident.action_triggered`, or defaults to `action.triggered`)
* `source_type`: `local` (default) or `git`
#### Git-Based Scripts
Execute scripts from a Git repository that the Edge Connector syncs automatically:
```yaml theme={null}
callable:
run_playbook:
name: "Run Incident Playbook"
description: "Execute Ansible playbook from Git repository"
trigger: incident.action_triggered
source_type: git
script: playbooks/incident-response.yml
git_options:
url: "https://github.com/your-org/runbooks.git"
branch: main
poll_interval_sec: 300
parameter_definitions:
- name: playbook
type: list
options: [database, network, application]
required: true
description: "Which playbook to run"
parameters:
incident_id: "{{ entity_id }}"
severity: "{{ severity.slug }}"
timeout: 600
```
**Git Options:**
* `url`: Git repository URL (HTTPS or SSH)
* `branch`: Branch to checkout (default: `main`)
* `poll_interval_sec`: How often to pull updates (default: 300)
Git-based scripts allow you to version control your automation scripts and update them without redeploying the Edge Connector.
### HTTP Actions
Make HTTP/HTTPS requests to external APIs or webhooks.
```yaml theme={null}
on:
alert.created:
http:
url: "https://example.com/webhook"
method: POST
headers:
Content-Type: "application/json"
Authorization: "Bearer {{ env.API_TOKEN }}"
params:
source: "rootly"
body: |
{
"alert_id": "{{ id }}",
"summary": "{{ summary }}",
"severity": "{{ labels.severity }}",
"services": "{{ services | map: 'name' | join: ', ' }}"
}
timeout: 30
```
**HTTP Configuration:**
* `url`: Target endpoint (supports templates)
* `method`: GET, POST, PUT, PATCH, DELETE
* `headers`: HTTP headers (supports templates)
* `params`: Query parameters
* `body`: Request body (supports templates for JSON/text)
## Action Triggers
### Automatic Event Triggers
These actions run automatically when system events occur. They are defined in the `on:` section where the event type is the key.
**Alert Events:**
```yaml theme={null}
on:
alert.created:
# Action configuration here
script: /path/to/handle-alert.sh
```
**Incident Events:**
```yaml theme={null}
on:
incident.mitigated:
# Action configuration here
script: /path/to/handle-mitigation.sh
```
**Available Automatic Triggers:**
* `alert.created`, `alert.updated`, `alert.acknowledged`, `alert.resolved`, `alert.deleted`
* `incident.created`, `incident.updated`, `incident.in_triage`, `incident.mitigated`, `incident.resolved`, `incident.cancelled`, `incident.deleted`
Automatic triggers do not require `parameter_definitions` - they execute automatically with event data.
### Manual Trigger Events
These actions are triggered manually by users from the Rootly UI. They require `parameter_definitions` to create input forms.
**Action on Alert:**
```yaml theme={null}
callable:
restart_affected_service:
name: "Restart Affected Service"
trigger: alert.action_triggered
script: /opt/scripts/restart.sh
parameter_definitions:
- name: service_name
type: string
required: true
- name: force_restart
type: boolean
default: false
```
**Action on Incident:**
```yaml theme={null}
callable:
scale_infrastructure:
name: "Scale Infrastructure"
trigger: incident.action_triggered
script: /opt/scripts/scale.sh
parameter_definitions:
- name: target_capacity
type: number
required: true
```
**Standalone Action:**
```yaml theme={null}
callable:
clear_cache:
name: "Clear Global Cache"
# trigger defaults to: action.triggered
http:
url: "https://api.example.com/cache/clear"
method: POST
parameter_definitions:
- name: cache_type
type: string
required: true
options: ["redis", "memcached", "all"]
```
## Parameter Definitions
Parameters create user input forms for manually triggered actions.
### Parameter Types
**String:**
```yaml theme={null}
- name: service_name
type: string
required: true
description: "Name of the service"
```
**Number:**
```yaml theme={null}
- name: capacity
type: number
required: true
description: "Target capacity percentage"
```
**Boolean:**
```yaml theme={null}
- name: force_restart
type: boolean
default: false
description: "Force restart without graceful shutdown"
```
**List (Dropdown):**
```yaml theme={null}
- name: cache_type
type: list
options: [redis, memcached, all]
default: redis
required: true
description: "Which cache to clear"
```
Use `type: list` with `options` array for dropdown selections. This is preferred over `type: string` with `options` for clarity.
### Parameter Fields
* `name`: Parameter identifier (used in templates as `{{ parameters.name }}`)
* `type`: Data type (string, number, boolean)
* `required`: Whether input is mandatory
* `default`: Default value if not provided
* `options`: List of allowed values (creates dropdown)
* `description`: Help text shown in UI
## Using Templates in Actions
Actions support Liquid templates for dynamic values. See the [Template Syntax](/edge-connectors-templates) guide for detailed documentation.
### Event Data Templates
Access event data in your action configuration:
```yaml theme={null}
parameters:
alert_id: "{{ id }}"
summary: "{{ summary }}"
severity: "{{ labels.severity }}"
service: "{{ services.first.name }}"
```
### User Parameter Templates
Access user inputs in manually triggered actions:
```yaml theme={null}
parameters:
service: "{{ parameters.service_name }}"
env: "{{ parameters.environment }}"
force: "{{ parameters.force_restart }}"
```
### Environment Variables
Access environment variables securely:
```yaml theme={null}
headers:
Authorization: "Bearer {{ env.API_TOKEN }}"
X-API-Key: "{{ env.SECRET_KEY }}"
```
## Complete Examples
### Example 1: Automatic Alert Response
Automatically restart a service when critical alerts are detected:
```yaml theme={null}
on:
alert.created:
script: /opt/scripts/restart-service.sh
parameters:
service: "{{ services.first.slug }}"
environment: "{{ environments.first.slug }}"
alert_id: "{{ id }}"
severity: "{{ labels.severity }}"
timeout: 120
```
### Example 2: Manual Service Scaling
Allow users to manually scale services from incidents:
```yaml theme={null}
callable:
scale_service:
name: "Scale Service Capacity"
description: |
Manually scale service capacity.
Use during incidents to increase capacity.
trigger: incident.action_triggered
script: /opt/scripts/scale-service.sh
parameter_definitions:
- name: target_capacity
type: number
required: true
description: "Target capacity (50-200%)"
- name: scaling_speed
type: string
required: false
default: "normal"
options: ["slow", "normal", "fast"]
description: "Scaling speed"
parameters:
# User inputs: target_capacity and scaling_speed
# are auto-available as {{ parameters.target_capacity }}, etc.
# Add extra context here:
incident_id: "{{ entity_id }}"
triggered_by: "{{ triggered_by.email }}"
timeout: 300
```
### Example 3: Webhook Notification
Send HTTP notification when incidents are mitigated:
```yaml theme={null}
on:
incident.mitigated:
http:
url: "{{ env.SLACK_WEBHOOK_URL }}"
method: POST
headers:
Content-Type: "application/json"
body: |
{
"text": "Incident Mitigated",
"attachments": [{
"color": "good",
"fields": [
{"title": "Incident", "value": "{{ title }}", "short": false},
{"title": "Severity", "value": "{{ severity.name }}", "short": true},
{"title": "Services", "value": "{{ services | map: 'name' | join: ', ' }}", "short": true},
{"title": "Duration", "value": "{{ mitigated_at | date: '%Y-%m-%d %H:%M' }}", "short": true}
]
}]
}
timeout: 10
```
### Example 4: PagerDuty Integration
Create PagerDuty incidents for high-severity Rootly incidents:
```yaml theme={null}
on:
incident.created:
http:
url: "https://api.pagerduty.com/incidents"
method: POST
headers:
Authorization: "Token token={{ env.PAGERDUTY_TOKEN }}"
Content-Type: "application/json"
From: "{{ env.PAGERDUTY_FROM_EMAIL }}"
body: |
{
"incident": {
"type": "incident",
"title": "[{{ severity.name }}] {{ title }}",
"service": {
"id": "{{ env.PAGERDUTY_SERVICE_ID }}",
"type": "service_reference"
},
"urgency": "high",
"body": {
"type": "incident_body",
"details": "{{ summary }}\n\nAffected services: {{ services | map: 'name' | join: ', ' }}"
}
}
}
timeout: 15
```
## Best Practices
### Security
* **Store secrets in environment variables**, never in action configuration
* **Use absolute paths** for scripts to prevent path traversal
* **Validate user inputs** in your scripts
* **Limit script permissions** - run with minimal privileges
* **Audit action execution logs** regularly
### Reliability
* **Set appropriate timeouts** based on expected execution time
* **Implement retry logic** in your scripts for transient failures
* **Handle errors gracefully** and return meaningful error messages
* **Test actions thoroughly** before deploying to production
* **Monitor action execution** via Rootly dashboard
### Configuration
* **Use descriptive IDs** (snake\_case: `restart_production_db`)
* **Provide clear names** for UI display
* **Write helpful descriptions** explaining when to use the action
* **Add parameter descriptions** to guide users
* **Use options** for parameters with limited valid values
### Templates
* **Use `default` filter** for optional fields: `{{ field | default: "N/A" }}`
* **Test templates** with sample event data before deploying
* **Keep templates simple** - complex logic belongs in scripts
* **Document template variables** in action descriptions
## Action Configuration File
Actions are defined in an `actions.yml` file with three main sections:
```yaml theme={null}
# Global defaults (optional) - applied to all actions
defaults:
timeout: 30 # Default timeout for all actions
source_type: local # Default source: local or git
env: # Environment variables for all actions
ENVIRONMENT: production
LOG_LEVEL: info
# Automatic actions - triggered by system events
# Event type is the KEY
on:
alert.created:
script: /path/to/handle-alert.sh
parameters:
alert_id: "{{ id }}"
severity: "{{ labels.severity }}"
timeout: 60
incident.created:
http:
url: "{{ env.SLACK_WEBHOOK_URL }}"
method: POST
body: |
{"text": "Incident: {{ title }}"}
# Manual actions - triggered by users from UI
# Action slug is the KEY
callable:
restart_service:
name: "Restart Service"
description: "Restart a production service"
trigger: alert.action_triggered # Shows on alerts only
script: /path/to/restart.sh
parameter_definitions:
- name: service_name
type: string
required: true
parameters:
# User inputs are auto-available as {{ parameters.service_name }}
# This section adds EXTRA context beyond user inputs:
alert_id: "{{ entity_id }}"
triggered_by: "{{ triggered_by.email }}"
timeout: 120
clear_cache:
name: "Clear Cache"
description: "Clear application cache"
# trigger defaults to: action.triggered (standalone action)
script: /path/to/clear-cache.sh
parameter_definitions:
- name: cache_type
type: list
options: [redis, memcached, all]
run_from_git:
name: "Run Git-based Script"
source_type: git # Override default source_type
script: scripts/automation.sh
git_options:
url: "https://github.com/org/repo.git"
branch: main
poll_interval_sec: 300
```
The Edge Connector reads this file on startup and registers all actions with Rootly.
**Key Concepts:**
* `defaults:` section: Global settings applied to all actions unless overridden
* `on:` section: Automatic actions where event type is the **key**
* `callable:` section: Manual actions where action slug is the **key**
* `source_type`: `local` for filesystem scripts, `git` for repository-based scripts
* `parameter_definitions`: Create user input forms; auto-accessible as `{{ parameters.X }}`
* `parameters:` section: Adds **extra** parameters beyond user inputs
* Scripts receive all parameters as `REC_PARAM_*` environment variables
## Next Steps
* See [Event Examples](/edge-connectors-event-examples) for sample event payloads
* Learn [Template Syntax](/edge-connectors-templates) for dynamic values
* Review the main [Edge Connectors](/edge-connectors) documentation
# Event Examples
Source: https://docs.rootly.com/edge-connectors-event-examples
Real-world examples of event payloads received from Rootly Edge Connectors, showing JSON structures for testing actions, scripts, and Liquid template logic.
## Overview
This page provides real-world examples of event payloads that Edge Connectors receive when polling the Rootly API. These examples show the structure and data available for templating in your action configurations.
## Event Types
Edge Connector events are divided into two categories based on how actions are triggered:
**Understanding Action Types:** Automatic events trigger actions automatically (configured in `on:` section), while manual trigger events are user-initiated actions (configured in `callable:` section). See the [Automatic vs Callable Actions](/edge-connectors-actions#automatic-vs-callable-actions) guide for detailed comparison.
### Automatic Event Types
These events are triggered automatically by system events and can be subscribed to by connectors for monitoring and notifications:
**Alert Events:**
* `alert.created` - New alert from monitoring system
* `alert.updated` - Alert properties changed
* `alert.acknowledged` - Alert acknowledged by a user
* `alert.resolved` - Alert marked as resolved
* `alert.deleted` - Alert removed
**Incident Events:**
* `incident.created` - New incident started
* `incident.updated` - Incident properties changed
* `incident.in_triage` - Incident moved to triage status
* `incident.mitigated` - Incident mitigated
* `incident.resolved` - Incident marked resolved
* `incident.cancelled` - Incident cancelled
* `incident.deleted` - Incident deleted
### Manual Trigger Event Types
These events are triggered by user actions and are managed by actions' `event_types_trigger` field, not connector subscriptions:
* `action.triggered` - Standalone action triggered by a user
* `alert.action_triggered` - Action triggered from an alert context
* `incident.action_triggered` - Action triggered from an incident context
Automatic events can be subscribed to when configuring your Edge Connector. Manual trigger events are configured per action and execute when users trigger them from the UI.
## Event Payload Examples
Below are detailed examples of event payloads for each event type.
### alert.created - Production Database Alert
```json theme={null}
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"event_id": "a3bb189e-8bf9-3888-9912-ace4e6543002",
"event_type": "alert.created",
"timestamp": "2025-10-26T21:30:00Z",
"data": {
"id": "6aeb35ae-ca31-4bcf-91bd-c4ecce44dedc",
"source": "datadog",
"summary": "High database latency detected",
"status": "open",
"labels": {
"severity": "critical",
"component": "database",
"region": "us-west-2"
},
"data": {
"host": "prod-db-01.example.com",
"latency_ms": 1500,
"threshold_ms": 500,
"query_count": 342
},
"started_at": "2025-10-26T21:29:45Z",
"ended_at": null,
"created_at": "2025-10-26T21:29:50Z",
"updated_at": "2025-10-26T21:29:50Z",
"services": [
{
"id": "8e3f9c2a-1d5b-4e8f-9a3c-7b2d4e6f8a1c",
"name": "DB - Production Database",
"slug": "db-production"
}
],
"environments": [
{
"id": "2c4e6a8b-3f5d-4a7c-8b9e-1f3a5c7d9e2b",
"name": "Production",
"slug": "production",
"color": "#E74C3C"
}
]
}
}
```
### Template Usage
```yaml theme={null}
parameters:
alert_id: "{{ id }}"
alert_summary: "{{ summary }}"
severity: "{{ labels.severity }}"
host: "{{ data.host }}"
latency: "{{ data.latency_ms }}"
service_name: "{{ services.0.name }}" # First service
environment: "{{ environments.0.slug }}" # First environment
```
## alert.created - PagerDuty Integration
```json theme={null}
{
"id": "9d4e2f1c-7a8b-4c3d-9e5f-6a7b8c9d0e1f",
"event_id": "5c6d7e8f-9a0b-4c5d-8e9f-0a1b2c3d4e5f",
"event_type": "alert.created",
"timestamp": "2025-10-26T21:35:00Z",
"data": {
"id": "b8c9d0e1-f2a3-4b5c-6d7e-8f9a0b1c2d3e",
"source": "pagerduty",
"summary": "API service is down",
"status": "open",
"labels": {
"severity": "high",
"urgency": "high",
"impact": "critical"
},
"data": {
"incident_key": "PD-12345",
"incident_url": "https://example.pagerduty.com/incidents/12345",
"triggered_by": "monitoring_service",
"escalation_policy": "Engineering On-Call"
},
"started_at": "2025-10-26T21:34:30Z",
"ended_at": null,
"created_at": "2025-10-26T21:34:35Z",
"updated_at": "2025-10-26T21:34:35Z",
"services": [
{
"id": "3f4e5d6c-7b8a-4c9d-0e1f-2a3b4c5d6e7f",
"name": "API Gateway",
"slug": "api-gateway"
},
{
"id": "8a9b0c1d-2e3f-4a5b-6c7d-8e9f0a1b2c3d",
"name": "Authentication Service",
"slug": "auth-service"
}
],
"environments": [
{
"id": "1e2f3a4b-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
"name": "Production",
"slug": "production",
"color": "#E74C3C"
}
]
}
}
```
### Template Usage
```yaml theme={null}
parameters:
pagerduty_key: "{{ data.incident_key }}"
pagerduty_url: "{{ data.incident_url }}"
urgency: "{{ labels.urgency }}"
all_services: "{{ services | join:', ' }}" # "API Gateway, Authentication Service"
```
## alert.updated - Status Change
```json theme={null}
{
"id": "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a",
"event_id": "7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b",
"event_type": "alert.updated",
"timestamp": "2025-10-26T22:00:00Z",
"data": {
"id": "6aeb35ae-ca31-4bcf-91bd-c4ecce44dedc",
"source": "datadog",
"summary": "High database latency detected",
"status": "resolved",
"labels": {
"severity": "critical",
"component": "database"
},
"data": {
"host": "prod-db-01.example.com",
"latency_ms": 150,
"resolution": "auto-scaled database pool"
},
"started_at": "2025-10-26T21:29:45Z",
"ended_at": "2025-10-26T21:59:30Z",
"created_at": "2025-10-26T21:29:50Z",
"updated_at": "2025-10-26T22:00:00Z",
"services": [
{
"id": "8e3f9c2a-1d5b-4e8f-9a3c-7b2d4e6f8a1c",
"name": "DB - Production Database",
"slug": "db-production"
}
],
"environments": [
{
"id": "2c4e6a8b-3f5d-4a7c-8b9e-1f3a5c7d9e2b",
"name": "Production",
"slug": "production",
"color": "#E74C3C"
}
]
}
}
```
## incident.created - Full Example
Based on `EdgeConnectors::IncidentSerializer`:
```json theme={null}
{
"id": "c1d2e3f4-a5b6-7c8d-9e0f-1a2b3c4d5e6f",
"event_id": "2b3c4d5e-6f7a-8b9c-0d1e-2f3a4b5c6d7e",
"event_type": "incident.created",
"timestamp": "2025-10-26T23:00:00Z",
"data": {
"id": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
"sequential_id": 42,
"title": "Production API Gateway Outage",
"slug": "production-api-gateway-outage",
"summary": "Complete outage affecting all customers",
"status": "started",
"kind": "normal",
"private": false,
"detected_at": "2025-10-26T22:58:00Z",
"acknowledged_at": null,
"started_at": "2025-10-26T22:58:00Z",
"mitigated_at": null,
"resolved_at": null,
"cancelled_at": null,
"created_at": "2025-10-26T22:59:00Z",
"updated_at": "2025-10-26T23:00:00Z",
"services": [
{
"id": "3f4e5d6c-7b8a-4c9d-0e1f-2a3b4c5d6e7f",
"name": "API Gateway",
"slug": "api-gateway"
}
],
"environments": [
{
"id": "1e2f3a4b-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
"name": "Production",
"slug": "production",
"color": "#E74C3C"
}
],
"functionalities": [
{
"id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
"name": "API Requests",
"slug": "api-requests"
}
],
"severity": {
"id": "5e4d3c2b-1a09-8f7e-6d5c-4b3a2910fedc",
"name": "SEV1",
"slug": "sev1",
"color": "#FF0000"
}
}
}
```
## alert.action\_triggered - User-Initiated Restart on Alert
```json theme={null}
{
"id": "e6f7a8b9-c0d1-2e3f-4a5b-6c7d8e9f0a1b",
"event_id": "d5e6f7a8-b9c0-1d2e-3f4a-5b6c7d8e9f0a",
"event_type": "alert.action_triggered",
"timestamp": "2025-10-26T23:15:00Z",
"action": {
"id": "7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d",
"name": "Restart Test Service",
"slug": "restart_test_service"
},
"data": {
"entity_id": "f0a1b2c3-d4e5-6f7a-8b9c-0d1e2f3a4b5c",
"parameters": {
"service_name": "api-gateway",
"environment": "production",
"force_restart": true,
"drain_timeout": 30
},
"triggered_by": {
"id": 50,
"name": "Quentin Rousseau",
"email": "quentin@rootly.com"
}
}
}
```
### Template Usage in Actions
```yaml theme={null}
# Script action for alert actions
- name: restart_test_service
type: script
script: /opt/scripts/restart-service.sh
trigger:
event_type: "alert.action_triggered"
parameters:
# Action metadata (from top-level action object)
action_display_name: "{{ action.name }}" # "Restart Test Service"
action_slug: "{{ action.slug }}" # "restart_test_service"
# User inputs (from UI)
service_name: "{{ parameters.service_name }}"
environment: "{{ parameters.environment }}"
force: "{{ parameters.force_restart }}"
# Context data
entity_id: "{{ entity_id }}"
triggered_by_email: "{{ triggered_by.email }}"
# Hardcoded
region: "us-west-2"
timeout: "60"
```
## incident.action\_triggered - Escalation on Incident
```json theme={null}
{
"id": "b9c0d1e2-f3a4-5b6c-7d8e-9f0a1b2c3d4e",
"event_id": "a8b9c0d1-e2f3-4a5b-6c7d-8e9f0a1b2c3d",
"event_type": "incident.action_triggered",
"timestamp": "2025-10-26T23:20:00Z",
"action": {
"id": "6c7d8e9f-0a1b-2c3d-4e5f-6a7b8c9d0e1f",
"name": "Scale Infrastructure",
"slug": "scale_infrastructure"
},
"data": {
"entity_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a",
"parameters": {
"target_capacity": 200,
"scaling_policy": "aggressive"
},
"triggered_by": {
"id": 42,
"name": "Sarah Johnson",
"email": "sarah@example.com"
}
}
}
```
## action.triggered - Standalone Action
```json theme={null}
{
"id": "c3d4e5f6-a7b8-9c0d-1e2f-3a4b5c6d7e8f",
"event_id": "b2c3d4e5-f6a7-8b9c-0d1e-2f3a4b5c6d7e",
"event_type": "action.triggered",
"timestamp": "2025-10-26T23:25:00Z",
"action": {
"id": "5f6a7b8c-9d0e-1f2a-3b4c-5d6e7f8a9b0c",
"name": "Clear Global Cache",
"slug": "clear_global_cache"
},
"data": {
"parameters": {
"cache_type": "redis",
"scope": "global"
},
"triggered_by": {
"id": 50,
"name": "Quentin Rousseau",
"email": "quentin@rootly.com"
}
// No entity_id - this is a standalone action
}
}
```
## Edge Cases
### Alert with No Services
```json theme={null}
{
"event_type": "alert.created",
"data": {
"id": "e9f0a1b2-c3d4-5e6f-7a8b-9c0d1e2f3a4b",
"summary": "Orphaned alert",
"status": "open",
"services": [], // ← Empty array
"environments": [] // ← Empty array
}
}
```
### Alert with Custom Data (Datadog)
```json theme={null}
{
"event_type": "alert.created",
"data": {
"id": "d8e9f0a1-b2c3-4d5e-6f7a-8b9c0d1e2f3a",
"source": "datadog",
"summary": "CPU usage above 90%",
"status": "open",
"data": {
"tags": ["env:production", "service:api", "host:prod-01"],
"metric": "system.cpu.usage",
"value": 94.2,
"threshold": 90.0,
"monitor_id": "12345678",
"monitor_name": "High CPU Usage"
}
}
}
```
### Standalone Action with No Parameters
```json theme={null}
{
"event_type": "action.triggered",
"action": {
"id": "c7d8e9f0-a1b2-3c4d-5e6f-7a8b9c0d1e2f",
"name": "Clear Cache",
"slug": "clear_cache"
},
"data": {
"parameters": {}, // ← No user inputs required
"triggered_by": {
"id": 50,
"name": "Quentin Rousseau",
"email": "quentin@rootly.com"
}
// No entity_id - standalone action
}
}
```
## HTTP Action Examples
### alert.created → Slack Notification
```yaml theme={null}
- name: notify_slack_alert
type: http
trigger:
event_type: "alert.created"
http:
url: "{{ env.SLACK_WEBHOOK_URL }}"
method: POST
headers:
Content-Type: "application/json"
body: |
{
"text": ":warning: New Alert",
"attachments": [{
"color": "danger",
"fields": [
{"title": "Summary", "value": "{{ summary }}", "short": false},
{"title": "Source", "value": "{{ source }}", "short": true},
{"title": "Severity", "value": "{{ labels.severity }}", "short": true},
{"title": "Host", "value": "{{ data.host }}", "short": true},
{"title": "Environment", "value": "{{ environments.0.name }}", "short": true}
]
}]
}
timeout: 10
```
### incident.created → PagerDuty Integration
```yaml theme={null}
- name: create_pagerduty_incident
type: http
trigger:
event_type: "incident.created"
http:
url: "https://api.pagerduty.com/incidents"
method: POST
headers:
Authorization: "Token token={{ env.PAGERDUTY_TOKEN }}"
Content-Type: "application/json"
From: "{{ env.PAGERDUTY_FROM_EMAIL }}"
body: |
{
"incident": {
"type": "incident",
"title": "[{{ severity.name }}] {{ title }}",
"service": {
"id": "{{ env.PAGERDUTY_SERVICE_ID }}",
"type": "service_reference"
},
"urgency": "high",
"body": {
"type": "incident_body",
"details": "{{ summary }}\n\nAffected services: {{ services.0.name }}"
}
}
}
timeout: 15
```
### alert.action\_triggered → Restart Service API
```yaml theme={null}
- name: restart_service_api
type: http
trigger:
event_type: "alert.action_triggered"
action_name: "restart_service_api"
parameter_definitions:
- name: service_name
type: string
required: true
- name: force_restart
type: boolean
default: false
http:
url: "https://api.example.com/v1/services/{{ parameters.service_name }}/restart"
method: POST
headers:
Authorization: "Bearer {{ env.API_TOKEN }}"
Content-Type: "application/json"
X-Triggered-By: "{{ triggered_by.email }}"
body: |
{
"force": {{ parameters.force_restart }},
"reason": "Manual restart via Rootly",
"alert_id": "{{ entity_id }}"
}
timeout: 60
```
### action.triggered → Clear Global Cache
```yaml theme={null}
- name: clear_cache_http
type: http
trigger:
event_type: "action.triggered"
action_name: "clear_cache_http"
parameter_definitions:
- name: cache_type
type: string
options: ["redis", "memcached", "all"]
required: true
http:
url: "https://cache-api.example.com/v1/clear"
method: POST
headers:
X-API-Key: "{{ env.CACHE_API_KEY }}"
params:
type: "{{ parameters.cache_type }}"
body: |
{
"triggered_by": "{{ triggered_by.email }}",
"scope": "global"
}
timeout: 30
```
**HTTP Action Behavior:**
* Exit code = HTTP status code (200, 404, 500, etc.)
* Stdout = Response body + status message
* Stderr = Error message (if request fails)
* Success = 2xx status codes
* Failure = 4xx, 5xx status codes
## Template Access Patterns
### Simple Fields
```yaml theme={null}
alert_id: "{{ id }}"
status: "{{ status }}"
summary: "{{ summary }}"
```
### Nested Objects
```yaml theme={null}
severity: "{{ labels.severity }}"
host: "{{ data.host }}"
metric_value: "{{ data.value }}"
```
### Arrays (First Element)
```yaml theme={null}
service_name: "{{ services.0.name }}"
service_slug: "{{ services.0.slug }}"
environment: "{{ environments.0.slug }}"
```
### Environment Variables
```yaml theme={null}
api_key: "{{ env.DATADOG_API_KEY }}"
region: "{{ env.AWS_REGION }}"
```
### Mixed
```yaml theme={null}
message: "[{{ labels.severity }}] {{ summary }} on {{ data.host }} in {{ environments.0.name }}"
# Result: "[critical] High database latency detected on prod-db-01.example.com in Production"
```
## Testing Locally
Create a test event payload file:
```bash theme={null}
# test-alert.json
{
"events": [{
"id": "b6c7d8e9-f0a1-2b3c-4d5e-6f7a8b9c0d1e",
"event_id": "a5b6c7d8-e9f0-1a2b-3c4d-5e6f7a8b9c0d",
"event_type": "alert.created",
"timestamp": "2025-10-26T23:00:00Z",
"data": {
"id": "9e0f1a2b-3c4d-5e6f-7a8b-9c0d1e2f3a4b",
"source": "test",
"summary": "Test alert for local development",
"status": "open",
"labels": {"severity": "critical"},
"data": {"host": "localhost"},
"services": [{"id": "8d9e0f1a-2b3c-4d5e-6f7a-8b9c0d1e2f3a", "name": "Test Service", "slug": "test"}],
"environments": [{"id": "7c8d9e0f-1a2b-3c4d-5e6f-7a8b9c0d1e2f", "name": "Development", "slug": "dev"}]
}
}]
}
```
Then post to your local mock server to trigger actions.
# Installation & Deployment
Source: https://docs.rootly.com/edge-connectors-installation
Install and deploy the Rootly Edge Connector in your environment using Docker or supported orchestrators to securely poll Rootly without inbound connections.
## Overview
The Rootly Edge Connector is a lightweight agent that runs in your infrastructure to securely integrate with internal systems. This guide covers installation, configuration, and deployment for production environments.
## Prerequisites
Before installing the Edge Connector, ensure you have:
* **Operating System**: Linux (systemd-based distributions recommended)
* **Network Access**: Outbound HTTPS to `rec.rootly.com` (port 443)
* **API Key**: Edge Connector API key from Rootly (see [Getting Started](/edge-connectors#getting-started))
* **Permissions**: Root or sudo access for system installation
The Edge Connector only requires **outbound** network access. No inbound firewall rules are needed.
## Installation Methods
Choose one of the following installation methods based on your environment:
### Option 1: Homebrew (Recommended for macOS/Linux)
```bash theme={null}
# Add Rootly tap
brew tap rootlyhq/tap
# Install Edge Connector
brew install rootly-edge-connector
# Verify installation
rootly-edge-connector --version
```
### Option 2: Go Install
If you have Go 1.24+ installed:
```bash theme={null}
# Install latest version
go install github.com/rootlyhq/rootly-edge-connector/cmd/rec@latest
# The binary will be installed to $GOPATH/bin/rec
```
### Option 3: Build from Source
```bash theme={null}
# Clone repository
git clone https://github.com/rootlyhq/rootly-edge-connector.git
cd rootly-edge-connector
# Build and install
make build
make install
# Verify installation
rootly-edge-connector --version
```
### Option 4: Pre-built Binaries
For enterprise customers with access to private releases:
Contact [support@rootly.com](mailto:support@rootly.com) for access to pre-built binaries and download credentials.
## Quick Start (Development)
For testing and development, run the Edge Connector directly:
### 1. Create Configuration Files
**config.yml:**
```yaml theme={null}
app:
name: "rootly-edge-connector"
rootly:
api_url: "https://rec.rootly.com"
api_path: "/v1"
api_key: "YOUR_REC_API_KEY"
poller:
polling_wait_interval_ms: 5000
visibility_timeout_sec: 30
logging:
level: "info"
format: "json"
metrics:
enabled: true
port: 9090
```
**actions.yml:**
```yaml theme={null}
defaults:
timeout: 30
on:
alert.created:
script: /path/to/test-script.sh
parameters:
alert_id: "{{ id }}"
severity: "{{ labels.severity }}"
timeout: 60
```
### 2. Set API Key
```bash theme={null}
export REC_API_KEY="your-api-key-here"
```
### 3. Run the Connector
```bash theme={null}
./rootly-edge-connector \
-config config.yml \
-actions actions.yml
```
You should see output indicating the connector is polling:
```text theme={null}
INFO Starting Rootly Edge Connector
INFO Registered actions with backend action_count=1
INFO Polling for events poll_interval=10s
```
## Production Installation (Linux/systemd)
For production deployments, install the Edge Connector as a systemd service.
### Step 1: Create System User
Create a dedicated user for the Edge Connector:
```bash theme={null}
sudo groupadd -r rootly
sudo useradd -r -g rootly -s /bin/false -d /opt/rootly-edge-connector rootly
```
### Step 2: Create Directories
Set up the directory structure:
```bash theme={null}
sudo mkdir -p /opt/rootly-edge-connector/bin
sudo mkdir -p /opt/rootly-edge-connector/scripts
sudo mkdir -p /etc/rootly-edge-connector
sudo mkdir -p /var/log/rootly-edge-connector
```
### Step 3: Install Binary
Copy the binary to the installation directory. The binary location depends on your installation method:
```bash theme={null}
# If you built from source or downloaded a binary directly:
sudo cp rootly-edge-connector /opt/rootly-edge-connector/bin/
# If you used Homebrew:
sudo cp $(which rootly-edge-connector) /opt/rootly-edge-connector/bin/
# If you used Go install:
sudo cp $GOPATH/bin/rec /opt/rootly-edge-connector/bin/rootly-edge-connector
# Set permissions
sudo chmod +x /opt/rootly-edge-connector/bin/rootly-edge-connector
```
### Step 4: Create Configuration
Create your configuration files in `/etc/rootly-edge-connector/`:
**`/etc/rootly-edge-connector/config.yml`:**
```yaml theme={null}
app:
name: "rootly-edge-connector"
rootly:
api_url: "https://rec.rootly.com"
api_path: "/v1"
api_key: "YOUR_REC_API_KEY"
poller:
polling_wait_interval_ms: 10000
visibility_timeout_sec: 30
max_number_of_messages: 10
security:
script_timeout: 300
allowed_script_paths:
- /opt/rootly-edge-connector/scripts
logging:
level: "info"
format: "json"
output: "stdout"
metrics:
enabled: true
port: 9090
path: "/metrics"
```
**`/etc/rootly-edge-connector/actions.yml`:**
```yaml theme={null}
# Automatic action - runs when incidents are created
on:
incident.created:
http:
url: "{{ env.WEBHOOK_URL }}"
method: POST
headers:
Content-Type: "application/json"
body: |
{
"incident_id": "{{ id }}",
"title": "{{ title }}",
"severity": "{{ severity.name }}"
}
timeout: 30
# Manual action - triggered by users from Rootly UI
callable:
restart_service:
name: "Restart Service"
trigger: alert.action_triggered
script: /opt/rootly-edge-connector/scripts/restart.sh
parameter_definitions:
- name: service_name
type: string
required: true
timeout: 120
```
### Step 5: Create Environment File
Store the API key and sensitive values securely:
```bash theme={null}
sudo tee /etc/rootly-edge-connector/environment > /dev/null < connector-logs.txt
```
### Checking Metrics
If metrics are enabled (default port 9090):
```bash theme={null}
# View Prometheus metrics
curl http://localhost:9090/metrics
# Common metrics:
# - rec_events_polled_total: Total events polled
# - rec_actions_executed_total: Total actions executed
# - rec_action_duration_seconds: Action execution duration
# - rec_poll_errors_total: Polling errors
```
## Updating
### Update Binary
```bash theme={null}
# Stop the service
sudo systemctl stop rootly-edge-connector
# Backup current binary
sudo cp /opt/rootly-edge-connector/bin/rootly-edge-connector \
/opt/rootly-edge-connector/bin/rootly-edge-connector.backup
# Install new binary
sudo cp new-rootly-edge-connector /opt/rootly-edge-connector/bin/rootly-edge-connector
sudo chmod +x /opt/rootly-edge-connector/bin/rootly-edge-connector
sudo chown rootly:rootly /opt/rootly-edge-connector/bin/rootly-edge-connector
# Start the service
sudo systemctl start rootly-edge-connector
# Verify
sudo systemctl status rootly-edge-connector
```
### Update Configuration
```bash theme={null}
# Edit configuration files
sudo vim /etc/rootly-edge-connector/config.yml
sudo vim /etc/rootly-edge-connector/actions.yml
# Validate configuration (optional)
sudo -u rootly /opt/rootly-edge-connector/bin/rootly-edge-connector \
-config /etc/rootly-edge-connector/config.yml \
-actions /etc/rootly-edge-connector/actions.yml \
-validate
# Restart service to apply changes
sudo systemctl restart rootly-edge-connector
```
## Docker Deployment
For containerized environments:
**Dockerfile:**
```dockerfile theme={null}
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY rootly-edge-connector /usr/local/bin/
RUN chmod +x /usr/local/bin/rootly-edge-connector
USER 1000:1000
ENTRYPOINT ["/usr/local/bin/rootly-edge-connector"]
CMD ["-config", "/etc/rootly/config.yml", "-actions", "/etc/rootly/actions.yml"]
```
**docker-compose.yml:**
```yaml theme={null}
version: '3.8'
services:
edge-connector:
image: rootly-edge-connector:latest
container_name: rootly-edge-connector
restart: always
environment:
- REC_API_KEY=${REC_API_KEY}
volumes:
- ./config.yml:/etc/rootly/config.yml:ro
- ./actions.yml:/etc/rootly/actions.yml:ro
- ./scripts:/opt/scripts:ro
ports:
- "9090:9090" # Metrics port
```
**Run with Docker:**
```bash theme={null}
# Build image
docker build -t rootly-edge-connector:latest .
# Run container
docker run -d \
--name rootly-edge-connector \
--restart always \
-e REC_API_KEY="your-api-key" \
-v $(pwd)/config.yml:/etc/rootly/config.yml:ro \
-v $(pwd)/actions.yml:/etc/rootly/actions.yml:ro \
-v $(pwd)/scripts:/opt/scripts:ro \
-p 9090:9090 \
rootly-edge-connector:latest
# View logs
docker logs -f rootly-edge-connector
```
## Troubleshooting
### Connector Won't Start
**Check configuration syntax:**
```bash theme={null}
sudo -u rootly /opt/rootly-edge-connector/bin/rootly-edge-connector \
-config /etc/rootly-edge-connector/config.yml \
-actions /etc/rootly-edge-connector/actions.yml \
-validate
```
**Check permissions:**
```bash theme={null}
ls -la /opt/rootly-edge-connector/bin/
ls -la /etc/rootly-edge-connector/
```
**View detailed logs:**
```bash theme={null}
sudo journalctl -u rootly-edge-connector -n 50 --no-pager
```
### API Connection Issues
**Test network connectivity:**
```bash theme={null}
curl -v https://rec.rootly.com/health
```
**Verify API key:**
```bash theme={null}
# Check environment file
sudo cat /etc/rootly-edge-connector/environment
# Test with API key
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://rec.rootly.com/rec/v1/health
```
### Actions Not Executing
**Check action registration:**
```bash theme={null}
# Look for registration success in logs
sudo journalctl -u rootly-edge-connector | grep "Registered actions"
```
**Verify script permissions:**
```bash theme={null}
# Scripts must be executable
sudo chmod +x /opt/rootly-edge-connector/scripts/*.sh
# Check script ownership
ls -la /opt/rootly-edge-connector/scripts/
```
**Test script manually:**
```bash theme={null}
sudo -u rootly /opt/rootly-edge-connector/scripts/your-script.sh arg1 arg2
```
### High Memory/CPU Usage
**Check poll interval:**
* Increase `poller.polling_wait_interval_ms` in config.yml (for example, from 5000 to 30000)
**Review action timeouts:**
* Ensure actions complete within their timeout values
* Check for hung processes
**Monitor metrics:**
```bash theme={null}
curl http://localhost:9090/metrics | grep rec_
```
## Security Best Practices
### 1. Run as Dedicated User
Always run the Edge Connector as a non-root user with minimal privileges.
### 2. Protect Sensitive Files
```bash theme={null}
# Environment file should be 600 (owner read/write only)
sudo chmod 600 /etc/rootly-edge-connector/environment
# Config files should be 640 (owner read/write, group read)
sudo chmod 640 /etc/rootly-edge-connector/*.yml
```
### 3. Network Isolation
* Run on a dedicated or isolated host
* Restrict outbound connections to rec.rootly.com only (if using firewall)
* Do not expose metrics port publicly
### 4. Audit Scripts
* Review all scripts before adding to actions.yml
* Use version control for scripts
* Implement pull request approval process
### 5. Rotate API Keys
* Rotate API keys periodically (for example, quarterly)
* Use different keys for dev/staging/production
* Revoke old keys after rotation
### 6. Monitor Logs
* Set up log aggregation (for example, to ELK, Splunk)
* Alert on errors and failures
* Review execution logs regularly
## Next Steps
* Configure [Actions](/edge-connectors-actions) for your use cases
* Learn [Template Syntax](/edge-connectors-templates) for dynamic values
* Review [Event Examples](/edge-connectors-event-examples) for payload structures
* See the main [Edge Connectors](/edge-connectors) documentation for architecture details
# Template Syntax
Source: https://docs.rootly.com/edge-connectors-templates
Use Liquid templates in Rootly Edge Connectors to dynamically insert event data, parameters, and secrets into HTTP and script actions during execution.
## Overview
Edge Connectors use **Liquid templates** to dynamically substitute values from events, user parameters, and environment variables into your action configurations.
Templates allow you to:
* Access event data (alerts, incidents, etc.)
* Use user-provided parameters from manual triggers
* Reference environment variables securely
* Transform data with filters
Edge Connectors use the [osteele/liquid](https://github.com/osteele/liquid) library, a Go implementation of Shopify's Liquid template language.
## Basic Syntax
### Simple Fields
Access top-level fields directly:
```yaml theme={null}
{{ id }} # Event ID
{{ summary }} # Alert/incident summary
{{ status }} # Current status
{{ title }} # Incident title
```
### Nested Fields
Use dot notation for nested objects:
```yaml theme={null}
{{ labels.severity }} # Alert severity label
{{ data.host }} # Custom monitoring data
{{ severity.name }} # Incident severity object
{{ triggered_by.email }} # User who triggered action
```
### Array Access
Access array elements by index or using helpers:
```yaml theme={null}
{{ services[0].name }} # First service (by index)
{{ services.first.name }} # First service (helper)
{{ services.last.slug }} # Last service (helper)
{{ environments[0].slug }} # First environment
```
### Environment Variables
Securely access environment variables:
```yaml theme={null}
{{ env.API_KEY }} # From REC_API_KEY or API_KEY
{{ env.AWS_REGION }} # From REC_AWS_REGION or AWS_REGION
{{ env.WEBHOOK_URL }} # From REC_WEBHOOK_URL or WEBHOOK_URL
```
Store sensitive values like API keys and tokens in environment variables, never in action configuration files.
## Event Data Access
### Alert Events
Common fields available in alert events:
```yaml theme={null}
{{ id }} # Alert UUID
{{ summary }} # Alert summary text
{{ status }} # open, acknowledged, resolved
{{ source }} # datadog, pagerduty, etc.
{{ labels.severity }} # Severity from monitoring system
{{ data.host }} # Custom monitoring data
{{ services[0].name }} # Affected service
{{ environments[0].slug }} # Environment (production, etc.)
{{ started_at }} # When alert started
```
### Incident Events
Common fields available in incident events:
```yaml theme={null}
{{ id }} # Incident UUID
{{ sequential_id }} # Incident number (42, 43, etc.)
{{ title }} # Incident title
{{ summary }} # Incident summary
{{ status }} # started, mitigated, resolved
{{ severity.name }} # SEV1, SEV2, etc.
{{ severity.slug }} # sev1, sev2, etc.
{{ services | map: 'name' }} # All affected services
{{ environments[0].name }} # Environment name
{{ detected_at }} # When detected
{{ mitigated_at }} # When mitigated
{{ resolved_at }} # When resolved
```
### Action Trigger Events
Fields available when users manually trigger actions:
```yaml theme={null}
{{ entity_id }} # Alert or incident ID
{{ action.name }} # Action display name
{{ action.slug }} # Action identifier
{{ parameters.service_name }} # User input parameter
{{ parameters.environment }} # User input parameter
{{ triggered_by.id }} # User ID
{{ triggered_by.name }} # User name
{{ triggered_by.email }} # User email
```
## Filters
Filters transform values using the pipe (`|`) operator.
### Array Filters
**map** - Extract property from objects:
```yaml theme={null}
{{ services | map: "name" }}
# [{name: "DB"}, {name: "API"}] → ["DB", "API"]
```
**join** - Combine array elements:
```yaml theme={null}
{{ services | map: "name" | join: ", " }}
# ["DB", "API", "Cache"] → "DB, API, Cache"
```
**first** - Get first element:
```yaml theme={null}
{{ services | first }}
# Returns first service object
```
**last** - Get last element:
```yaml theme={null}
{{ services | last }}
# Returns last service object
```
**sort** - Sort alphabetically:
```yaml theme={null}
{{ names | sort }}
# ["charlie", "alice", "bob"] → ["alice", "bob", "charlie"]
```
**uniq** - Remove duplicates:
```yaml theme={null}
{{ items | uniq }}
# [1, 2, 2, 3, 1] → [1, 2, 3]
```
**compact** - Remove nil values:
```yaml theme={null}
{{ items | compact }}
# [1, nil, 2, nil, 3] → [1, 2, 3]
```
**reverse** - Reverse order:
```yaml theme={null}
{{ items | reverse }}
# [1, 2, 3] → [3, 2, 1]
```
### String Filters
**upcase** - Convert to uppercase:
```yaml theme={null}
{{ status | upcase }}
# "open" → "OPEN"
```
**downcase** - Convert to lowercase:
```yaml theme={null}
{{ severity | downcase }}
# "CRITICAL" → "critical"
```
**capitalize** - Capitalize first letter:
```yaml theme={null}
{{ name | capitalize }}
# "john doe" → "John doe"
```
**default** - Provide fallback value:
```yaml theme={null}
{{ field | default: "N/A" }}
# If field is empty → "N/A"
```
**truncate** - Shorten text:
```yaml theme={null}
{{ summary | truncate: 50 }}
# "Very long summary text..." → "Very long summary text..."
```
**replace** - Replace all occurrences:
```yaml theme={null}
{{ text | replace: "foo", "bar" }}
# "foo foo" → "bar bar"
```
**remove** - Remove all occurrences:
```yaml theme={null}
{{ severity | remove: "SEV" }}
# "SEV1" → "1"
```
**strip** - Remove whitespace:
```yaml theme={null}
{{ text | strip }}
# " hello " → "hello"
```
**append** - Add to end:
```yaml theme={null}
{{ name | append: ".txt" }}
# "file" → "file.txt"
```
**prepend** - Add to beginning:
```yaml theme={null}
{{ name | prepend: "prefix-" }}
# "name" → "prefix-name"
```
**split** - Split into array:
```yaml theme={null}
{{ "a,b,c" | split: "," }}
# "a,b,c" → ["a", "b", "c"]
```
### Number Filters
**plus** - Add:
```yaml theme={null}
{{ count | plus: 1 }}
# 5 → 6
```
**minus** - Subtract:
```yaml theme={null}
{{ count | minus: 2 }}
# 5 → 3
```
**times** - Multiply:
```yaml theme={null}
{{ value | times: 10 }}
# 5 → 50
```
**divided\_by** - Divide:
```yaml theme={null}
{{ value | divided_by: 2 }}
# 10 → 5
```
**modulo** - Remainder:
```yaml theme={null}
{{ value | modulo: 3 }}
# 10 → 1
```
**abs** - Absolute value:
```yaml theme={null}
{{ value | abs }}
# -5 → 5
```
**round** - Round number:
```yaml theme={null}
{{ value | round: 2 }}
# 3.14159 → 3.14
```
**ceil** - Round up:
```yaml theme={null}
{{ value | ceil }}
# 3.2 → 4
```
**floor** - Round down:
```yaml theme={null}
{{ value | floor }}
# 3.8 → 3
```
### Date Filters
**date** - Format timestamp:
```yaml theme={null}
{{ started_at | date: "%Y-%m-%d %H:%M:%S" }}
# "2025-10-26T21:30:00Z" → "2025-10-26 21:30:00"
{{ started_at | date: "%B %d, %Y" }}
# "2025-10-26T21:30:00Z" → "October 26, 2025"
```
Common date format codes:
* `%Y` - Year (2025)
* `%m` - Month (01-12)
* `%d` - Day (01-31)
* `%H` - Hour 24h (00-23)
* `%M` - Minute (00-59)
* `%S` - Second (00-59)
* `%B` - Full month name (January)
* `%b` - Short month name (Jan)
## Real-World Examples
### Example 1: Alert Notification
Format a Slack message with alert details:
```yaml theme={null}
body: |
{
"text": ":warning: New Alert",
"attachments": [{
"color": "danger",
"fields": [
{"title": "Summary", "value": "{{ summary }}", "short": false},
{"title": "Severity", "value": "{{ labels.severity | upcase }}", "short": true},
{"title": "Host", "value": "{{ data.host | default: 'unknown' }}", "short": true},
{"title": "Services", "value": "{{ services | map: 'name' | join: ', ' }}", "short": false},
{"title": "Environment", "value": "{{ environments.first.name }}", "short": true},
{"title": "Time", "value": "{{ started_at | date: '%Y-%m-%d %H:%M' }}", "short": true}
]
}]
}
```
### Example 2: Incident Summary
Create a concise incident summary:
```yaml theme={null}
message: "[{{ severity.name }}] {{ title }} - {{ services | map: 'name' | join: ', ' }} ({{ environments.first.slug }})"
# Result: "[SEV1] API Gateway Outage - API Gateway, Auth Service (production)"
```
### Example 3: Script Parameters
Pass structured data to a script:
```yaml theme={null}
parameters:
incident_id: "{{ id }}"
incident_number: "{{ sequential_id }}"
severity: "{{ severity.slug }}"
services: "{{ services | map: 'slug' | join: ',' }}"
environment: "{{ environments.first.slug }}"
triggered_by: "{{ triggered_by.email | default: 'system' }}"
timestamp: "{{ started_at | date: '%Y-%m-%d %H:%M:%S' }}"
```
### Example 4: Conditional Values
Use defaults for optional fields:
```yaml theme={null}
parameters:
reason: "{{ parameters.reason | default: 'Manual action triggered' }}"
environment: "{{ parameters.environment | default: 'production' }}"
force: "{{ parameters.force_restart | default: false }}"
host: "{{ data.host | default: 'localhost' }}"
```
### Example 5: Complex Transformation
Chain multiple filters:
```yaml theme={null}
# Extract, sort, and format service names
services_list: "{{ services | map: 'name' | sort | join: ' | ' | upcase }}"
# Result: "API GATEWAY | AUTH SERVICE | DATABASE"
# Format severity without prefix
severity_number: "{{ severity.name | remove: 'SEV' }}"
# "SEV1" → "1"
```
## Advanced Patterns
### Chaining Filters
Combine multiple filters in sequence:
```yaml theme={null}
{{ services | map: "name" | sort | uniq | join: ", " | upcase }}
# Extract names → sort → remove duplicates → join → uppercase
```
### Nested Array Access
Access deeply nested data:
```yaml theme={null}
{{ services[0].tags[0] }} # First service's first tag
{{ data.metrics.values[5] }} # Sixth metric value
{{ environments.first.config.region }} # Environment config
```
### Safe Navigation
Liquid handles missing values gracefully:
```yaml theme={null}
{{ missing.field }} # Returns empty string ""
{{ array[999].name }} # Returns "" (out of bounds)
{{ undefined | default: "N/A" }} # Returns "N/A"
```
## Common Patterns
### Service List
```yaml theme={null}
services: "{{ services | map: 'name' | join: ', ' }}"
# "Database, API Gateway, Cache"
```
### Environment Detection
```yaml theme={null}
env: "{{ environments.first.slug | default: 'unknown' }}"
# "production"
```
### Severity Formatting
```yaml theme={null}
severity: "{{ labels.severity | upcase | default: 'UNKNOWN' }}"
# "CRITICAL"
```
### User Context
```yaml theme={null}
user: "{{ triggered_by.name }} ({{ triggered_by.email }})"
# "John Doe (john@example.com)"
```
### Timestamp Formatting
```yaml theme={null}
time: "{{ started_at | date: '%Y-%m-%d %H:%M:%S UTC' }}"
# "2025-10-26 21:30:00 UTC"
```
## Limitations
To keep templates simple and secure, the following Liquid features are **not** supported:
* **No logic tags**: `{% if %}`, `{% unless %}`, `{% case %}` not supported
* **No loops**: `{% for %}` not supported - use filters like `map` and `join` instead
* **No custom tags**: Only `{{ }}` output tags are supported
* **No assignments**: `{% assign %}` not supported
Use filters and the `default` filter for conditional logic:
```yaml theme={null}
# Instead of {% if field %}{{ field }}{% else %}N/A{% endif %}
# Use:
{{ field | default: "N/A" }}
```
## Tips & Best Practices
### 1. Use Default Filter
Always provide fallback values for optional fields:
```yaml theme={null}
{{ data.host | default: "unknown" }}
{{ parameters.timeout | default: 30 }}
```
### 2. Extract Then Join
For arrays of objects, use `map` + `join`:
```yaml theme={null}
{{ services | map: "name" | join: ", " }}
```
### 3. Test Templates
Test with sample event data before deploying:
* Use the [Event Examples](/edge-connectors-event-examples) for reference payloads
* Verify templates produce expected output
* Handle edge cases (empty arrays, missing fields)
### 4. Keep It Simple
Complex logic belongs in scripts, not templates:
```yaml theme={null}
# Good: Simple data extraction
service: "{{ services.first.name }}"
# Bad: Complex transformation (do this in a script instead)
# Avoid overly complex filter chains
```
### 5. Environment Variables for Secrets
Never hardcode secrets in templates:
```yaml theme={null}
# Good
Authorization: "Bearer {{ env.API_TOKEN }}"
# Bad
Authorization: "Bearer sk-1234567890abcdef"
```
### 6. Format for Readability
Use multiline strings for JSON/YAML bodies:
```yaml theme={null}
body: |
{
"field1": "{{ value1 }}",
"field2": "{{ value2 }}"
}
```
## Troubleshooting
### Template Returns Empty String
* Check field name spelling
* Verify field exists in event payload (see [Event Examples](/edge-connectors-event-examples))
* Use `default` filter: `{{ field | default: "missing" }}`
### Array Access Fails
* Verify array is not empty
* Use `.first` or `.last` helpers for safety
* Check array index is in bounds
### Filter Not Working
* Verify filter name is correct
* Check filter arguments (some require arguments: `{{ value | round: 2 }}`)
* Ensure input type matches filter (can't `upcase` a number)
### Environment Variable Not Found
* Verify variable is set in environment
* Check variable name (case-sensitive)
* Edge Connector supports both `REC_` prefix and plain names
## Next Steps
* See [Action Configuration](/edge-connectors-actions) to use templates in actions
* Review [Event Examples](/edge-connectors-event-examples) for available fields
* Read the main [Edge Connectors](/edge-connectors) documentation
# Frequently Asked Questions
Source: https://docs.rootly.com/faq
Answers to common questions about Rootly incident management: creating incidents from Slack, on-call schedules, alert deduplication, workflows, and Rootly AI.
This page answers the questions teams ask most often when adopting Rootly for incident management, on-call, and alerting. Each answer links to the full documentation page where you can go deeper.
## Incidents
### How do I create an incident from Slack?
Type `/rootly new` in any Slack channel to open the New Incident form, or hover over an existing message, click **More actions** (three dots), and select **Create an incident** to declare an incident from a message, alert, or customer report. You can also mention `@Rootly` and ask the AI agent to create the incident for you in plain language. Slack-based creation supports customizable fields, required-field validation, private incidents, and automatic incident channel creation. Learn more: [Creating Incidents via Slack](/incidents/creating-incidents/creating-incidents-via-slack).
### What's the difference between severity and priority in Rootly?
Severity is Rootly's built-in property describing how bad an incident is while it's happening; priority is typically a custom field layered on top to capture how urgent it is to fix. For example, a minor bug affecting a major customer might be SEV3 severity but P1 priority. Rootly doesn't ship priority as a built-in — add it as a custom field if you need it. Learn more: [Severities](/configuration/severities).
### What's the difference between the Resolved and Closed statuses?
**Resolved** means active incident response has completed and service impact has ended — this is typically when retrospective work begins. **Closed** is an optional terminal status (enabled via team configuration) that marks an incident as fully finalized after review; it requires the incident to already be Resolved. If your team hasn't enabled Closed, Resolved serves as the terminal status. Learn more: [Incident Status](/configuration/incident-status).
### What are private incidents and who can see them?
Private incidents restrict sensitive operational, customer, or security-related information to a limited group of responders, adding a second layer of access control on top of workspace-wide RBAC. Users can access a private incident either through a role that grants private incident read access, or by being explicitly invited through the **Manage Access** dialog in the web UI or Slack. Learn more: [Private Incidents](/incidents/private-incidents/private-incidents).
### Can I split a large incident into sub-incidents?
Yes. A sub-incident is a normal incident linked to a parent via `parent_incident_id`, letting a team investigate and coordinate their scope independently while keeping shared context with the parent. Each parent incident can have multiple sub-incidents, which is useful for large, cross-functional incidents. Learn more: [Creating Sub-Incidents](/incidents/incident-operations/creating-sub-incident).
## Alerts & Noise Reduction
### How does alert deduplication work?
Alert Deduplication collapses repeat events from the same monitor onto a single open Rootly alert, so responders see a rising event count instead of getting paged again. Rootly provides two layers: configurable per–Alert Source deduplication using a stable unique identifier (extracted via JSONPath from the payload or from an alert field, optionally normalized with a regex), plus payload-based exact-body suppression as a backstop. Learn more: [Alert Deduplication](/alerts/alert-deduplication).
### What's the difference between alert deduplication and alert grouping?
Use deduplication when the *same* monitor keeps re-firing while an issue is unresolved; use grouping when *different* monitors all fire on the same underlying problem (for example latency, error rate, and DB health alerts at once). Alert Grouping consolidates related alerts into a single leader alert with member alerts — responders are paged for the leader, and matching alerts join the group silently. You can enable both together. Learn more: [Alert Grouping](/alerts/alert-grouping).
### How does alert routing decide who gets notified?
Alert Routes define when, how, and to whom Rootly sends incoming alerts, evaluating conditions against Alert Sources, normalized Alert Fields, and raw payload values via JSONPath. Matching alerts are routed to teams, services, or escalation policies, giving you one centralized routing layer that works consistently across all your monitoring tools. Learn more: [Alert Routing](/alerts/alert-routing).
### What does alert urgency control?
Alert Urgency controls how quickly responders must act on an alert — how aggressively Rootly pages on-call responders, whether notifications are audible or quiet, and which escalation paths apply during or outside working hours. Rootly ships with High, Medium, and Low urgency levels by default, and you can add, rename, and reorder urgencies. Learn more: [Alert Urgency](/alerts/alert-urgency).
### How do I monitor cron jobs and background workers with Rootly?
Use Heartbeats: they require your systems to "check in" on a regular cadence, and if a heartbeat misses its expected interval, Rootly automatically triggers an alert and notifies the appropriate on-call responders. Each heartbeat cycles through waiting, active, and expired statuses, making it easy to catch silent failures in cron jobs, schedulers, and background workers. Learn more: [Heartbeats](/on-call/heartbeats).
## On-Call & Paging
### How do I set up an on-call schedule?
Navigate to **On-Call → Schedules**, click **+ New Schedule**, name it, and define rotations that determine who is on call and when responsibility hands over. Note that schedules alone don't trigger paging — they must be linked to an Escalation Policy to become part of the alerting process. Creating or editing schedules requires the On-Call Admin or On-Call User role. Learn more: [On-Call Schedules](/on-call/schedules).
### How do escalation policies work?
Escalation Policies define who is notified first when an alert fires, what happens if no one acknowledges it, and how long Rootly keeps escalating before stopping. Policies are assigned to a Team or Service, and each new policy automatically includes a Default Escalation Path with audible notifications that acts as a fallback. Learn more: [Escalation Policies](/on-call/escalation-policies).
### How do I page someone manually?
Manual paging lets you page a specific user, team, service, functionality, or escalation policy directly from Rootly Web, Slack, or the mobile app — useful for escalating to another team or looping in a subject matter expert. Paging a team or service runs the same escalation policy as a programmatic alert, so the behavior is identical to automated paging. Learn more: [Manual Paging](/alerts/manual-paging).
### How do I cover an on-call shift when someone is unavailable?
Create an override: it temporarily assigns a specific shift to a different user while leaving the underlying rotation unchanged, making it the safest way to handle short-term coverage changes. Overrides always apply to individual users, take precedence over rotation-based shifts, and Rootly validates them to prevent overlaps or paging conflicts. Learn more: [Editing Schedules & Overrides](/on-call/edit-schedules).
### Can Rootly route phone calls to on-call engineers?
Yes. Live Call Routing gives you dedicated phone numbers that either connect callers live to the current on-call team member or route to a voicemail where the message is logged and the team is alerted. It also supports IVR calling trees for directing callers to the right team. Learn more: [Live Call Routing](/on-call/live-call-routing).
## Workflows & Automation
### What can I automate with Rootly workflows?
Workflows are Rootly's automation engine: they combine trigger events, run conditions, and actions to remove repetitive coordination work during incident response. Common patterns include creating incident channels in Slack or Microsoft Teams, posting periodic status reminders, notifying legal or support teams on high-impact incidents, creating Jira or Linear tickets, and spinning up Zoom or Google Meet bridges for high-severity incidents. Learn more: [Workflows Overview](/workflows/workflows).
### Can I run a workflow manually?
Yes. Beyond automatic trigger-based execution, workflows can be run on demand via a Slack command, an interactive Slack modal, or directly from an incident in the web UI. Manual runs still respect permissions — if you can't trigger workflows for a given incident, Rootly blocks the action. Learn more: [Manually Running Workflows](/workflows/manually-running-workflows).
### Can workflows keep Jira tickets in sync with incident action items?
Yes. Action item workflows trigger whenever action items are created, updated, assigned, or completed, so you can automatically create or update Jira (or other ticketing) issues, assign tickets based on the Rootly assignee, and notify owners when work is assigned or overdue. They trigger on action item events but can still use incident properties like severity or team as run conditions. Learn more: [Action Item Workflows](/workflows/action-item-workflows).
## Rootly AI
### What is Rootly AI in Slack?
Rootly AI is an AI agent that works inside your Slack incident channels, the Slack assistant pane, and DMs — type `@Rootly` to catch up on an incident, update severity, draft customer comms, or page another team without leaving Slack. It reads from your Rootly data, channel messages, and bridge call transcripts (when available), and it can only take actions that you as a user have permission to perform. Learn more: [Rootly AI in Slack](/ai/rootly-in-slack/overview).
### What data does Rootly AI access?
Rootly AI reads only the incident and conversation context for the request in front of it — never your broader Rootly data or message history. In Slack it does not crawl historical messages, browse channels it hasn't been invited to, or call Slack's `conversations.history` API; in the web and mobile apps it sees only the incident you're viewing and your conversation with it. Learn more: [Data Privacy for Rootly AI](/ai/data-privacy-for-rootly-ai).
### Is my data used to train AI models?
No. Customer data is processed in-context for each request and is not used to fine-tune base models. Rootly AI uses Claude Sonnet 4.6 from Anthropic as the default model with OpenAI's GPT-5 as a fallback, both accessed through a managed gateway. Learn more: [Data Privacy for Rootly AI](/ai/data-privacy-for-rootly-ai).
## Integrations, Retrospectives & Administration
### Does Rootly integrate with tools like Datadog, PagerDuty, and Jira?
Yes. Rootly integrates with a wide range of tools across communication and collaboration, alerting and on-call, observability and monitoring, issue tracking, video conferencing, and automation and AI — including PagerDuty, Jira, Zoom, Kubernetes, GitHub, and Datadog. Each integration section documents setup, workflow actions, and configuration. Learn more: [Integrations Overview](/integrations/overview).
### How do I set up a status page?
Creating a status page takes about a minute: go to **Configuration → Status Pages**, click **Add New Status Page**, and give it a name and description. Rootly recommends configuring at least one service first so you have something to display, and you can then customize branding, components, and visibility for internal stakeholders or external customers. Learn more: [Creating a Status Page](/configuration/creating-a-status-page).
### How do retrospectives work in Rootly?
Rootly lets you define multiple retrospective processes and right-size follow-up work based on severity, incident type, or team, with a default process as a fallback when no custom process matches. Each process contains ordered steps — gathering data, writing the retrospective document, hosting a review meeting, creating action items — that can include due dates, assignees, and reminders. Learn more: [Retrospectives Overview](/retrospectives/retrospectives).
### How are user permissions managed in Rootly?
Permissions are managed through team-scoped roles: each team membership assigns a user two roles, an Incident Response role (governing incident creation, management, configuration, and analytics) and an On-Call role (governing alerting, paging, schedules, and escalation policies). A user can hold different access levels across different teams in the same workspace, and default roles include Owner, Admin, User, Observer, and No Access. Learn more: [User Permissions](/managing-users/user-permissions).
# Incident Management Glossary
Source: https://docs.rootly.com/glossary
Plain-English definitions of incident management terms — incident commander, escalation policy, alert fatigue, MTTR, SEV levels, runbooks, and more.
Clear definitions for the terms you'll meet across Rootly and in incident management
generally. Entries link to the Rootly docs page where you can put the concept to work —
and the most-asked-about terms have full deep-dive entries with formulas, tables, and
worked examples.
## Action item
An action item is a concrete follow-up task that comes out of an incident or
retrospective — fix the bug, add the missing alert, update the runbook. Tracking them to
completion is how incidents actually make systems better. Learn more:
[Action Items & Tasks](/incidents/action-items/action-items).
## Alert
An alert is a signal from a monitoring or observability tool that something may be wrong.
Alerts feed into routing, grouping, and escalation so the right responder is notified.
Not every alert becomes an incident. Learn more: [Alerts](/alerts/alerts).
## Alert deduplication
Alert deduplication collapses repeated notifications for the same underlying problem into
a single alert, so responders see one actionable signal instead of a flood. Learn more:
[Alert Deduplication](/alerts/alert-deduplication).
## Alert fatigue
Alert fatigue is the desensitization responders develop when they receive too many
noisy, low-value, or false-positive alerts — leading to slower responses and missed real
incidents. Deduplication, grouping, routing, and urgency tuning are the main defenses.
Learn more: [Alert Deduplication](/alerts/alert-deduplication) and
[Alert Urgency](/alerts/alert-urgency). Deep dive: [What is alert fatigue?](/glossary/alert-fatigue).
## Alert grouping
Alert grouping bundles related alerts — same service, same time window, similar payloads —
into one group so they can be triaged and resolved together. Learn more:
[Alert Grouping](/alerts/alert-grouping).
## Alert routing
Alert routing evaluates incoming alerts against rules and sends each one to the right
team, service, or escalation path the first time. Routing rules typically match on alert
source, payload fields, and urgency. Learn more: [Alert Routing](/alerts/alert-routing).
## Error budget
An error budget is the amount of unreliability an SLO allows — the gap between your
target and 100%. It's SRE's tool for balancing reliability work against shipping speed.
Full entry: [What is an error budget?](/glossary/error-budget).
## Escalation policy
An escalation policy is the ordered chain of people or teams to notify when an alert
isn't acknowledged in time — for example, page the on-call engineer, then their backup,
then the team lead. It guarantees nothing falls through the cracks. Learn more:
[Escalation Policies](/on-call/escalation-policies).
## Heartbeat monitoring
A heartbeat is an expected periodic signal from a system ("I'm alive"). When the signal
stops arriving, an alert fires — catching silent failures that produce no error at all.
Learn more: [Heartbeats](/on-call/heartbeats).
## Incident
An incident is any unplanned disruption or degradation of a service that requires a
response — from a full outage to elevated error rates or a security event. In Rootly,
an incident is a structured record with a severity, status, timeline, roles, and
follow-ups. Learn more: [Incident Management](/incidents/incidents).
## Incident channel (war room)
An incident channel — commonly called a war room — is the dedicated space, physical or
virtual, where responders coordinate during a major incident. Rootly favors the calmer
"incident channel" over the militaristic framing. Full entry:
[What is an incident channel?](/glossary/war-room).
## Incident commander
The incident commander (IC) is the single person accountable for driving an incident to
resolution: coordinating responders, making decisions, and keeping communication flowing.
The IC directs the response but doesn't have to fix the issue personally. Rootly assigns
incident roles like IC automatically when an incident starts. Learn more:
[Incident Roles](/incidents/incident-roles/incident-roles).
## Incident management
Incident management is the end-to-end discipline of detecting, responding to, resolving,
and learning from incidents — the processes, roles, and tooling that keep services
reliable. Full entry: [What is incident management?](/glossary/incident-management).
## Incident response
Incident response is the hands-on work of an incident: triaging, mitigating,
communicating, and resolving. It's the "doing" inside the broader incident management
discipline. Full entry: [What is incident response?](/glossary/incident-response).
## Incident roles
Incident roles are the named responsibilities in a response — incident commander,
communications lead, scribe, operations lead — so everyone knows who is doing what.
Rootly assigns and tracks roles per incident. Learn more:
[Incident Roles](/incidents/incident-roles/incident-roles).
## Incident severity (SEV levels)
Severity expresses how much impact an incident has, usually on a scale from SEV1
(critical, all-hands) down to SEV4/SEV5 (minor). Severity drives who gets paged, how fast,
and what gets communicated. Rootly lets you define your own severity levels and tie
automation to them. Learn more: [Severities](/configuration/severities). Deep dive: [SEV levels explained](/glossary/sev-levels) and [severity vs priority](/glossary/severity-vs-priority).
## Incident timeline
The incident timeline is the chronological record of everything that happened during an
incident — status changes, key decisions, messages, and events — captured automatically
so the retrospective starts from facts instead of memory. Learn more:
[Incident Timeline](/incidents/incident-timeline/incident-timeline).
## Incident triage
Triage is the first-pass assessment of an incoming incident or alert: how bad is it, who
does it affect, and how urgently does it need a response. Full entry:
[What is incident triage?](/glossary/incident-triage).
## Live call routing
Live call routing gives your customers or internal users a phone number that rings the
current on-call responder directly, following your schedules and escalation policies.
Learn more: [Live Call Routing](/on-call/live-call-routing).
## MTBF (mean time between failures)
MTBF measures the average time a system runs between failures — a reliability indicator
that pairs with MTTR to express availability. Full entry: [MTBF explained](/glossary/mtbf).
## MTTA (mean time to acknowledge)
MTTA measures the average time between an alert firing and a responder acknowledging it.
It's the primary signal of how quickly your paging and escalation setup actually reaches
humans. Learn more: [On-Call Metrics](/on-call/on-call-metrics). Deep dive: [MTTA explained](/glossary/mtta) and [MTTA vs MTTR](/glossary/mtta-vs-mttr).
## MTTR (mean time to resolution)
MTTR measures the average time from incident start to resolution. It's the most common
top-level indicator of incident response health, and shrinking it is the goal of most
process and tooling investments. Learn more: [Analytics & Dashboards](/metrics/default-metrics). Deep dive: [MTTR explained](/glossary/mttr) and [MTBF](/glossary/mtbf).
## On-call schedule
An on-call schedule defines who is responsible for responding to alerts at any given
time, rotating responsibility across a team in shifts. Good schedules balance coverage
with responder health. Rootly supports rotations, overrides, and shift swaps. Learn more:
[On-Call Schedules](/on-call/schedules).
## Paging
Paging is the act of actively notifying an on-call responder — by push notification,
SMS, or phone call — that they're needed now. A "page" cuts through normal notification
channels. Learn more: [Manual Paging in Rootly](/alerts/manual-paging).
## Problem management (incident vs problem)
In ITIL terms, an incident is the disruption; a problem is its underlying cause. Problem
management hunts root causes across incidents. Full entry:
[Incident vs problem](/glossary/incident-vs-problem).
## Retrospective (postmortem)
A retrospective (also called a postmortem) is the structured review after an incident:
what happened, why, how the response went, and what will prevent recurrence. Blameless
retrospectives focus on systems rather than individuals. Learn more:
[Retrospectives](/retrospectives/retrospectives). Deep dive: [retrospective vs postmortem](/glossary/retrospective-vs-postmortem) and [how to run a retrospective](/concepts/incident-retrospective).
## Runbook / playbook
A runbook (or playbook) is a predefined set of steps for handling a specific scenario —
what to check, who to involve, and how to mitigate. Rootly playbooks attach those steps
directly to incidents so responders don't work from memory. Learn more:
[Playbooks](/configuration/playbooks). Deep dive: [What is a runbook?](/glossary/runbook) and [runbook vs playbook](/glossary/runbook-vs-playbook).
## Service catalog
A service catalog is the inventory of your services and their metadata: owners, teams,
dependencies, and tooling. Incident response uses it to answer "what is affected and who
owns it?" instantly. Learn more: [Catalog](/catalogs).
## SLA / SLO / SLI
An SLI measures service behavior, an SLO is your internal target for that measurement,
and an SLA is the external contract with consequences. Full entry:
[SLA vs SLO vs SLI](/glossary/sla-vs-slo-vs-sli).
## Status page
A status page communicates service health and incident updates to customers or internal
stakeholders. Public status pages reduce support load during incidents; private ones keep
internal teams aligned. Learn more: [Status Pages](/configuration/status-pages).
## Sub-statuses
Sub-statuses add organization-specific stages to the incident lifecycle (for example
"investigating — vendor engaged") beyond the standard started/mitigated/resolved flow,
so reporting reflects how your team actually works. Learn more:
[Statuses & Sub-Statuses](/incidents/incident-lifecycle).
## Workflow
In Rootly, a workflow is an automation rule: when conditions match (an incident is
created, a severity changes, an alert fires), Rootly performs actions — creating Slack
channels, notifying stakeholders, filing Jira tickets, or updating status pages — the
same way every time. Learn more: [Workflows](/workflows/workflows).
# What Is Alert Fatigue?
Source: https://docs.rootly.com/glossary/alert-fatigue
Alert fatigue is the desensitization that sets in when responders receive too many alerts, causing real problems to be missed. Learn the causes and the fixes.
**Alert fatigue** is the desensitization that sets in when responders receive so many alerts—especially noisy, low-value, or false ones—that they begin to ignore, mute, or slow-walk them. It is dangerous because it degrades exactly the behavior alerting exists to create: fast, attentive response. A team suffering from alert fatigue will eventually sleep through the one page that actually mattered.
## What causes alert fatigue?
Alert fatigue is rarely caused by one bad alert. It accumulates from systemic problems:
* **Noise.** Alerts that fire for conditions nobody needs to act on—a CPU spike that self-resolves, a threshold set years ago and never revisited.
* **False positives.** Alerts that cry wolf. Each one teaches responders that pages can be safely ignored, and that lesson is hard to unteach.
* **Duplication.** One underlying failure triggering twenty alerts from different monitors, each paging separately.
* **Over-paging.** Routing everything to a human pager regardless of urgency, so a full disk on a staging server interrupts dinner the same way a production outage does.
* **Wrong recipients.** Alerts sent to people who can't act on them, who then either ignore them or spend effort re-routing them by hand.
The common thread is a broken signal-to-noise ratio: when most alerts don't require action, responders rationally stop treating any alert as if it does.
## What are the consequences of alert fatigue?
The costs show up in two places—systems and people:
* **Missed or delayed incidents.** The real SEV1 arrives looking exactly like the fifty ignorable pages before it. Detection-to-response time stretches, and outages run longer.
* **On-call burnout.** Interrupted sleep and constant context-switching are among the most-cited reasons engineers leave on-call rotations, and sometimes teams entirely.
* **Eroded trust in monitoring.** Once engineers believe the alerting system is noise, they stop improving it, which makes it noisier—a self-reinforcing spiral.
* **Alert-handling theater.** Teams start bulk-acknowledging pages without reading them, which looks fine on dashboards while providing zero actual coverage.
A realistic example: a platform team's disk-usage alert fires nightly at 3 a.m. because a log-rotation job briefly crosses 85%. After three weeks, the on-call engineer creates a mental rule—"the 3 a.m. page is always the log thing"—and starts acknowledging it from bed without looking. On night 24, the 3 a.m. page is a genuine database disk exhaustion. It gets acknowledged and ignored, and the outage is discovered by customers four hours later.
## How do you fix alert fatigue?
The fixes attack noise at different points in the pipeline:
* **Deduplication.** Collapse repeated firings of the same alert into one incident-worthy notification instead of a page-storm. Rootly supports this via [alert deduplication](/alerts/alert-deduplication).
* **Grouping.** Bundle related alerts—same service, same failure window—so responders see one coherent event, not twenty fragments. See [alert grouping](/alerts/alert-grouping).
* **Routing.** Send each alert to the team that owns the affected service, so alerts land with people who can act. See [alert routing](/alerts/alert-routing).
* **Urgency tuning.** Not every alert deserves a phone call. Map alerts to urgency levels—page immediately, notify during business hours, or just log—so interruptions are reserved for problems that need a human now. See [alert urgency](/alerts/alert-urgency).
* **Ruthless pruning.** Regularly review which alerts fired, which were actionable, and delete or fix the rest. An alert that has never led to action is a candidate for removal, not a keepsake.
## How do you know if your team has alert fatigue?
Watch for these signals: pages routinely acknowledged in under ten seconds (nobody reads that fast), recurring alerts with no linked follow-up work, on-call handoff notes that say "you can ignore X," and engineers negotiating to avoid rotations. A useful metric is the actionable-alert rate—the fraction of pages that led to real action. Healthy teams push this well above half; fatigued teams often sit below one in ten.
## Related terms
* [What Is Incident Triage?](/glossary/incident-triage)
* [What Is MTTR?](/glossary/mttr)
* [What Is Incident Management?](/glossary/incident-management)
Browse all definitions in the [incident management glossary](/glossary).
# What Is an Error Budget?
Source: https://docs.rootly.com/glossary/error-budget
An error budget is the amount of unreliability an SLO allows — 100% minus the SLO target. How to calculate it, track burn rate, and set error budget policies.
An error budget is the amount of unreliability a service is allowed before it violates its service level objective (SLO). It equals 100% minus the SLO target: a service with a 99.9% availability SLO has a 0.1% error budget. The budget can be "spent" on incidents, risky deploys, and planned maintenance — and when it runs out, the team shifts focus from shipping features to restoring reliability.
## How do you calculate an error budget?
```text theme={null}
Error budget = 100% − SLO target
```
Applied to a time window, the percentage converts into concrete minutes of allowed downtime (or a count of allowed bad requests, for request-based SLOs).
### Worked example
A service has a 99.9% availability SLO measured over a 30-day window.
* Error budget = 100% − 99.9% = 0.1%
* Minutes in 30 days = 30 × 24 × 60 = 43,200
* Budget in minutes = 43,200 × 0.001 = **43.2 minutes** (about 43 minutes 12 seconds per month; often rounded to \~43.8 minutes when quoted per average calendar month of 30.44 days)
If the service has already had a 20-minute outage this window, roughly 23 minutes of budget remain. A second incident of similar size would nearly exhaust it.
For a request-based SLO the same logic applies to counts: at 99.9% success over 10 million monthly requests, the budget is 10,000 failed requests.
## What is burn rate?
Burn rate measures how fast you are consuming the budget relative to the pace that would exactly exhaust it at the end of the window:
```text theme={null}
Burn rate = Actual error rate / Allowed error rate
```
A burn rate of 1 means you will land exactly on budget. A burn rate of 14.4 against a 30-day, 99.9% SLO means the entire month's budget will be gone in about 50 hours.
Burn rate is the basis for modern SLO alerting. Instead of paging on raw error percentages, teams page on fast burn (for example, a high burn rate sustained for an hour — something is actively wrong) and ticket on slow burn (a modest burn rate sustained for days — reliability is quietly eroding). This keeps pages tied to real budget impact rather than momentary blips.
## What is an error budget policy?
An error budget policy is a pre-agreed document that says what happens as the budget depletes. Deciding this in advance — before anyone is angry — is the whole point. A typical policy might look like:
| Budget remaining | Action |
| ---------------- | ----------------------------------------------------------------------------------------------- |
| > 50% | Ship normally; budget may be spent on risky launches and experiments |
| 10–50% | Heightened review for risky changes; prioritize reliability action items |
| Exhausted | Feature freeze on the service; engineering effort goes to reliability until the budget recovers |
The policy is a contract between product and engineering. Product gets a guarantee that reliability work won't be invoked arbitrarily to block launches; engineering gets an objective trigger for prioritizing stability that doesn't depend on winning an argument.
## How do error budgets relate to SLOs?
An error budget is simply an SLO viewed from the other side. The SLO states the reliability floor ("99.9% of requests succeed"); the error budget states the failure allowance that floor implies ("0.1% may fail"). This reframing does two useful things:
1. **It makes reliability spendable.** Instead of treating every incident as a moral failure, teams treat downtime as a resource: spend it on velocity when the budget is healthy, conserve it when it isn't.
2. **It acknowledges that 100% is the wrong target.** Users cannot tell the difference between 99.999% and 100%, but the engineering cost of chasing the last fraction is enormous. The budget makes that trade-off explicit.
Error budgets only work when the underlying SLO is measured from a well-chosen SLI and set at a level users actually need — see [SLA vs SLO vs SLI](/glossary/sla-vs-slo-vs-sli) for how the three fit together.
Rootly's incident data feeds budget tracking naturally: incident duration and severity metrics (see [default metrics](/metrics/default-metrics)) show exactly which incidents consumed the budget and where reliability effort should go next.
## Related terms
* [SLA vs SLO vs SLI](/glossary/sla-vs-slo-vs-sli)
* [MTBF (mean time between failures)](/glossary/mtbf)
* [MTTR (mean time to resolution)](/glossary/mttr)
Browse the full [incident management glossary](/glossary).
# What Is Incident Management?
Source: https://docs.rootly.com/glossary/incident-management
Incident management is the practice of detecting, responding to, resolving, and learning from unplanned service disruptions. Lifecycle, roles, and tooling.
**Incident management** is the end-to-end practice of detecting, responding to, resolving, and learning from unplanned disruptions to a service. It covers everything from the alert that wakes an engineer up to the retrospective that prevents the same failure from happening again. The goal is not to eliminate incidents—complex systems will always fail—but to make each failure shorter, less damaging, and more instructive than the last.
## What counts as an incident?
An incident is any unplanned event that degrades a service or puts it at risk. That includes obvious outages, but also partial failures that only some users notice:
* A checkout API returning errors for 5% of requests
* A background job queue silently backing up for hours
* A certificate expiring on an internal service
* A security event, such as leaked credentials
If customers are affected—or could be soon—it's an incident. Teams that only declare incidents for full outages tend to under-count, which hides real reliability problems from leadership and from their own metrics.
## What are the stages of the incident lifecycle?
Most incidents move through the same broad stages, even when the details differ:
1. **Detection.** Monitoring fires an alert, or a customer reports a problem. Faster detection means everything downstream starts sooner.
2. **Declaration and triage.** Someone confirms the problem is real, declares an incident, and assigns a severity so the response is proportional to the impact.
3. **Response.** Responders assemble, investigate, and communicate. Roles are assigned, hypotheses are tested, and stakeholders get regular updates.
4. **Mitigation and resolution.** The team stops the bleeding first—often with a rollback or failover—then restores full service.
5. **Learning.** A retrospective (or postmortem) examines what happened, why, and what should change. Action items are tracked to completion.
The lifecycle is a loop, not a line: what a team learns in stage five should improve detection, triage, and response for the next incident.
## Why does incident management matter?
Downtime has a direct cost—lost revenue, missed SLAs, churned customers—but the indirect costs are often larger. Engineers pulled into a chaotic, unstructured scramble lose focus for days. Repeated incidents with no follow-through erode trust between teams and burn out on-call staff.
Consider a mid-size SaaS company whose payments service fails at 2 a.m. Without a process, the on-call engineer spends 40 minutes figuring out who owns the database, another 20 finding someone with production access, and nobody updates customers until support tickets pile up in the morning. With a working incident management practice, the same failure pages the right person immediately, a severity is assigned within minutes, a status page update goes out, and the retrospective the next week produces a fix for the connection-pool bug that caused it. The failure is identical; the outcome is not.
## What are the key roles in incident management?
Structured teams assign explicit roles during an incident rather than letting everyone do everything:
* **Incident commander** — owns the response process, coordinates people, and drives decisions
* **Technical lead (or ops lead)** — leads the hands-on investigation and mitigation
* **Communications lead** — keeps stakeholders and customers informed so engineers can focus
* **Scribe** — records the timeline, decisions, and actions for the retrospective
On small teams one person may wear several hats, but naming the roles still matters: it makes handoffs and gaps visible. Rootly lets you define and assign these as [incident roles](/incidents/incident-roles/incident-roles) when an incident is declared.
## What tooling does incident management involve?
No single tool covers the whole lifecycle. A typical stack includes:
* **Monitoring and observability** — metrics, logs, and traces that detect problems
* **Alerting and on-call** — paging, escalation policies, and schedules that reach the right human
* **Incident response platforms** — tooling that declares incidents, spins up channels, assigns roles, and tracks timelines
* **Status pages** — external and internal communication during an incident
* **Retrospective and action-item tracking** — turning incidents into lasting improvements
The connective tissue matters as much as any single layer: an alert that never becomes a declared incident, or a retrospective action item that never ships, is where most incident management programs quietly fail.
## Related terms
* [What Is Incident Response?](/glossary/incident-response)
* [What Are SEV Levels?](/glossary/sev-levels)
* [What Is MTTR?](/glossary/mttr)
Browse all definitions in the [incident management glossary](/glossary).
# What Is Incident Response?
Source: https://docs.rootly.com/glossary/incident-response
Incident response is the active work of handling an incident as it happens—mobilizing responders, investigating, mitigating, and communicating until resolved.
**Incident response** is the active, real-time work of handling an incident while it is happening: assembling the right people, diagnosing the problem, mitigating the impact, and communicating with stakeholders until service is restored. Where incident management describes the whole discipline—including prevention, tooling, and learning—incident response is the part that happens under pressure, between the moment an incident is declared and the moment it is resolved.
## How is incident response different from incident management?
The two terms are often used interchangeably, but the distinction is useful:
* **Incident response** is the *doing*: the live effort during an incident. It starts when an incident is declared and ends when it is resolved.
* **Incident management** is the *whole discipline*: the processes, roles, tooling, metrics, and learning loops that surround response. It includes what happens before an incident (on-call schedules, runbooks, severity definitions) and after (retrospectives, action items, trend analysis).
A team can have excellent responders and still have weak incident management—heroic, reactive response with no follow-through. The reverse is also possible: beautiful process documents that fall apart the first time something actually breaks. Strong organizations invest in both.
## What are the phases of incident response?
Once an incident is declared, response typically moves through four phases:
1. **Mobilize.** Page the right responders, open a dedicated channel, and assign roles. The first few minutes set the tone—an [incident commander](/concepts/incident-commander) taking charge early prevents the "everyone watching, nobody driving" failure mode.
2. **Assess.** Establish what is broken, who is affected, and how badly. Assign or confirm a severity. Resist the urge to jump straight to fixes before anyone understands the scope of impact.
3. **Mitigate.** Stop the customer impact first, even if the fix is temporary—roll back the deploy, fail over to a replica, disable the feature flag. Root-cause analysis can wait; bleeding cannot.
4. **Resolve and hand off.** Restore full service, confirm with monitoring (not just a hopeful "looks fine"), communicate the all-clear, and capture the timeline for the retrospective.
## What does good incident response look like in practice?
Imagine a deploy at 4:50 p.m. on a Friday starts returning 500s on the login endpoint. Within two minutes, an alert pages the on-call engineer, who declares an incident. A channel is created automatically, the incident commander role is claimed, and a second responder joins to check the deploy history. By minute ten, the team has rolled back and error rates return to baseline. A communications update goes out at minute twelve, and the incident is resolved with a full timeline already recorded. Nothing about this requires genius—only preparation: alerting that works, a clear declaration path, and roles people already understand.
## What are incident response best practices?
Patterns that consistently separate calm responses from chaotic ones:
* **Declare early and often.** A false alarm costs minutes; a late declaration costs hours. Make declaring an incident cheap and blameless.
* **Assign a single incident commander.** One person owns the process so everyone else can investigate.
* **Mitigate before you diagnose.** Prefer the fastest safe path to reducing impact, then investigate at leisure.
* **Communicate on a cadence.** Post updates at predictable intervals—even "no new information" beats silence for stakeholders.
* **Keep the timeline as you go.** Reconstructing events after the fact is lossy; capturing decisions in the moment makes the retrospective honest.
* **Separate the fix from the follow-up.** Ship the mitigation now; file the durable fix as a tracked action item.
## Who is involved in incident response?
The core responders are usually the on-call engineer for the affected service plus anyone they escalate to. Around them sit the structured roles—commander, communications lead, scribe—and, for severe incidents, stakeholders such as support leads or executives who consume updates but stay out of the technical channel. The response team should be as small as possible while still covering the needed expertise: every extra person in the room adds coordination cost.
## Related terms
* [What Is Incident Management?](/glossary/incident-management)
* [What Is Incident Triage?](/glossary/incident-triage)
* [What Is a Runbook?](/glossary/runbook)
Browse all definitions in the [incident management glossary](/glossary).
# What Is Incident Triage?
Source: https://docs.rootly.com/glossary/incident-triage
Incident triage is the rapid assessment of a new incident—its impact, urgency, and scope—to assign a severity and get the right response started fast.
**Incident triage** is the rapid initial assessment of a newly reported problem: how bad is it, how urgent is it, and how wide does it reach? The output of triage is a severity assignment and a decision about who responds and how fast. Done well, it takes minutes and ensures a proportional response—major failures get immediate mobilization, minor ones don't wake anyone up.
## Where does the term come from?
Triage is borrowed from emergency medicine, where clinicians sort incoming patients by urgency rather than arrival order—treating the critical case first even if someone else has been waiting longer. The insight transfers directly to operations: response capacity is finite, and the order in which you spend it matters more than raw speed. A team that handles alerts strictly first-in-first-out will inevitably burn its best responders on trivia while something serious waits in the queue.
## What questions does triage answer?
Effective triage runs through a short, consistent set of questions:
* **Impact: what is actually broken?** Is functionality degraded or fully down? Is data at risk? Is revenue affected? Distinguish "the dashboard looks weird" from "customers cannot pay us."
* **Urgency: is it getting worse?** A slow memory leak and a cascading failure both matter, but on very different clocks. Urgency determines whether the response starts now or at 9 a.m.
* **Scope: who is affected?** All customers or one? A single region or every region? Internal tooling or customer-facing paths? Scope is the difference between a SEV3 and a SEV1 for the same symptom.
* **Certainty: what do we actually know?** Is this confirmed by monitoring, or a single unverified report? Triage with low certainty should err toward investigating quickly rather than mobilizing everyone.
The questions deliberately avoid *why is it broken*—root cause is a response activity, not a triage one. Trying to diagnose during triage delays the mobilization the diagnosis needs.
## How does severity assignment work?
Triage concludes by mapping the answers onto the organization's severity scale—typically SEV1 (critical) through SEV4 or SEV5 (minor). The severity then drives everything mechanical: who gets paged, whether a dedicated incident channel opens, how often stakeholders get updates, and whether a retrospective is required. This is why severity definitions need to be written down and unambiguous; triage under pressure is exactly the wrong time to debate what "major impact" means. Rootly lets you define these levels—with descriptions and notification behavior—under [severities](/configuration/severities), so the person triaging picks from a shared menu instead of inventing a judgment call.
Two rules keep severity assignment healthy:
* **When unsure, round up.** Downgrading an over-called SEV2 costs a few apologetic messages; upgrading an under-called one costs response time you never get back.
* **Severity is provisional.** Re-triage as facts arrive. An incident that looked contained at declaration can and should be upgraded the moment scope grows.
## Who does the triage?
In most organizations, the first responder triages—usually the on-call engineer who received the alert, since waiting for a designated triager adds latency exactly where it hurts most. Larger organizations sometimes add a dedicated first-line rotation that triages everything and escalates to service owners. Whoever does it needs two things: authority to assign a severity without asking permission, and written severity definitions so their 3 a.m. judgment matches the team's daytime intent.
## What does triage look like in practice?
An on-call engineer is paged at 22:40: elevated error rates on the file-upload service. In four minutes she establishes: uploads are failing for roughly 30% of requests (impact: partial degradation of one feature), the rate has been flat for 20 minutes (urgency: not cascading), it affects all regions but only the upload path (scope: broad but narrow), and it's confirmed by two independent monitors (certainty: high). She assigns SEV2—significant customer impact, not a full outage—which pages the storage team's on-call and opens an incident channel, but doesn't trigger the executive-notification workflow a SEV1 would. Total time from page to proportional response: about five minutes, and nobody was over- or under-mobilized.
## Related terms
* [What Are SEV Levels?](/glossary/sev-levels)
* [Severity vs Priority](/glossary/severity-vs-priority)
* [What Is Alert Fatigue?](/glossary/alert-fatigue)
Browse all definitions in the [incident management glossary](/glossary).
# Incident vs Problem: What's the Difference?
Source: https://docs.rootly.com/glossary/incident-vs-problem
An incident is an unplanned disruption you fix now; a problem is the underlying cause you investigate to stop recurrence. ITIL treats them separately.
An incident is an unplanned interruption or degradation of a service — something is broken for users right now, and the goal is to restore service fast. A problem is the underlying cause (or potential cause) of one or more incidents — the goal is to diagnose it and prevent recurrence. In ITIL terms, incident management optimizes for speed of restoration; problem management optimizes for permanent elimination. One incident can surface a problem, and one problem can spawn many incidents.
## Comparison at a glance
| Dimension | Incident | Problem |
| -------------- | ------------------------------------------------ | ----------------------------------------- |
| Definition | Unplanned service interruption or degradation | Underlying cause of one or more incidents |
| Goal | Restore service as fast as possible | Find root cause and prevent recurrence |
| Time horizon | Minutes to hours | Days to weeks |
| Acceptable fix | Workaround is fine (restart, rollback, failover) | Permanent fix or documented known error |
| Success metric | MTTR, user impact minimized | Incident recurrence eliminated or reduced |
| Typical owner | On-call responder / incident commander | Service owner / problem manager |
## What is incident management?
Incident management is the reactive discipline: detect the disruption, mobilize responders, mitigate impact, and restore normal service. Speed dominates every decision — a restart that buys stability is a perfectly good incident resolution even if nobody yet knows why the service crashed. Incidents are closed when users are no longer affected, not when the cause is understood.
## What is problem management?
Problem management is the investigative discipline that picks up where incidents leave off. It asks why the disruption happened and what will stop it happening again. Its outputs are root cause analyses, permanent fixes, and **known error records** — documented causes with proven workarounds that make the *next* incident faster to resolve even before the permanent fix ships. Problem management can also be proactive: analyzing incident trends or vendor advisories to remove causes before they ever produce an incident.
## Can an incident exist without a problem?
Yes. A one-off disruption with a fully understood, already-remediated cause — say, a bad config push that was rolled back and now has a validation check preventing recurrence — needs no separate problem record. Problems earn their overhead when the cause is unknown, the fix is nontrivial, or the incident keeps coming back. Likewise, a problem can exist without any incident: if a vendor discloses a defect in a library you run, you can open a problem and fix it proactively before it bites.
## Worked example
Over three weeks, a team logs four incidents: the checkout service runs out of memory and restarts, each time causing 5–10 minutes of failed payments. Each incident is resolved the same way — the on-call engineer restarts the pods and confirms recovery. MTTR is good; users barely notice. But the fourth recurrence makes the pattern undeniable, so the team opens a problem record.
The problem investigation takes eight days: a heap analysis reveals a slow memory leak in a session-caching library introduced in a March upgrade. The team documents the known error ("leak in cache library ≥ v4.2; workaround: rolling restart") so any future incident resolves in two minutes instead of ten, then ships the permanent fix — pinning the patched library version and adding a memory-growth alert. The four incidents were each resolved in minutes; the problem took over a week — and eliminated the entire incident class.
## Why keep them as separate processes?
Because their incentives conflict. Incident response rewards the fastest path to restoration, which is usually a workaround; root-causing during an outage prolongs user pain. Problem investigation rewards depth and patience, which you can't have at 3 a.m. with revenue burning. Merging them either slows your incident response ("don't close it until we know the root cause") or guts your investigations ("it's back up, move on"). Link them instead: incidents reference the problems they revealed, and problems track the incidents they caused.
## How this works in Rootly
Rootly tracks each incident as a structured record with a timeline, severity, and linked follow-up actions, so recurring incidents and their underlying causes stay connected. See [Incident Management](/incidents/incidents).
## Related terms
* [Retrospective vs Postmortem](/glossary/retrospective-vs-postmortem)
* [Incident Severity vs Priority](/glossary/severity-vs-priority)
* [Runbook vs Playbook](/glossary/runbook-vs-playbook)
* Browse the full [Incident Management Glossary](/glossary)
# What Is MTBF? Mean Time Between Failures Explained
Source: https://docs.rootly.com/glossary/mtbf
MTBF (mean time between failures) is the average operating time between failures. Formula, examples, and how it relates to MTTR and availability.
MTBF stands for mean time between failures: the average operating time a system runs between one failure and the next. It is calculated by dividing total uptime by the number of failures over a period. Where MTTR measures how fast you recover from incidents, MTBF measures how often they happen — together they determine a system's availability.
## How do you calculate MTBF?
```text theme={null}
MTBF = Total operating (up) time / Number of failures
```
Only count time the system was actually running: downtime spent repairing a failure belongs to MTTR, not MTBF. The metric originated in hardware reliability engineering, where it described physical components; in software operations it is usually applied per service, counting incidents or outages as "failures."
### Worked example
A service is observed for a 30-day month (43,200 minutes) and fails three times, with outages of 60, 30, and 90 minutes.
Total downtime = 60 + 30 + 90 = 180 minutes.
Total uptime = 43,200 − 180 = 43,020 minutes.
MTBF = 43,020 / 3 = **14,340 minutes**, or roughly 9.96 days between failures.
For the same period, MTTR = 180 / 3 = 60 minutes.
## What is the difference between MTBF and MTTR?
MTBF and [MTTR](/glossary/mttr) answer complementary questions:
* **MTBF: how often do we break?** Improving it means preventing failures — better testing, safer deploys, redundancy, capacity planning, and fixing the root causes surfaced in retrospectives.
* **MTTR: how fast do we fix it?** Improving it means recovering faster — better detection, paging, runbooks, and rollback.
A high MTBF with a terrible MTTR describes a system that rarely fails but is catastrophic when it does. A low MTBF with an excellent MTTR describes a system that fails constantly but self-heals quickly. Neither number alone tells you whether users are having a good time — for that you combine them.
Modern reliability thinking (popularized by the DORA research and the SRE community) tends to prioritize reducing MTTR over maximizing MTBF: failures are inevitable in complex systems, and teams that recover in minutes can ship faster than teams that try to prevent every failure. But MTBF still matters — if the same service fails every week, no amount of fast recovery makes that acceptable.
## How do MTBF and MTTR determine availability?
Availability is the fraction of time a system is up, and it falls directly out of the two metrics:
```text theme={null}
Availability = MTBF / (MTBF + MTTR)
```
Intuitively: each failure cycle consists of MTBF minutes of uptime followed by MTTR minutes of repair, so availability is uptime's share of the whole cycle.
Using the worked example above:
| Metric | Value |
| ------------ | ----------------------------------------------------- |
| MTBF | 14,340 minutes |
| MTTR | 60 minutes |
| Availability | 14,340 / (14,340 + 60) = 14,340 / 14,400 = **99.58%** |
The formula also shows two routes to any availability target. To reach 99.9%, you can make failures rarer (raise MTBF) or make recovery faster (cut MTTR). Halving MTTR from 60 to 30 minutes in the example lifts availability to 99.79% — the same effect as roughly doubling MTBF, and often far cheaper to achieve.
## How should you use MTBF in practice?
* **Segment by service and severity.** A fleet-wide MTBF blends critical and trivial services into a meaningless average.
* **Watch the trend, not the absolute.** A declining MTBF for a specific service is an early warning of accumulating tech debt or scaling limits.
* **Pair it with an [error budget](/glossary/error-budget).** MTBF and MTTR describe past reliability; an error budget turns an availability target into a forward-looking spending allowance.
* **Feed it back into planning.** Services with the worst MTBF are the strongest candidates for reliability investment in the next quarter.
Rootly derives failure frequency and duration metrics automatically from your incident data — see [default metrics](/metrics/default-metrics) for the available measures and groupings.
## Related terms
* [MTTR (mean time to resolution)](/glossary/mttr)
* [Error budget](/glossary/error-budget)
* [SLA vs SLO vs SLI](/glossary/sla-vs-slo-vs-sli)
Browse the full [incident management glossary](/glossary).
# What Is MTTA? Mean Time to Acknowledge Explained
Source: https://docs.rootly.com/glossary/mtta
MTTA (mean time to acknowledge) is the average time between an alert firing and a responder acknowledging it. Formula, examples, and how to improve it.
MTTA stands for mean time to acknowledge: the average time between an alert being created and a responder acknowledging that they are handling it. It is calculated by dividing the total time-to-acknowledgment across a set of alerts or incidents by their count. MTTA measures how quickly a team reacts to problems, making it the standard health check for paging, on-call, and escalation systems.
## How do you calculate MTTA?
```text theme={null}
MTTA = Total time from alert to acknowledgment / Number of alerts
```
The clock starts when the alert or incident is created and stops when a human acknowledges it — typically by tapping "acknowledge" in a paging app, claiming the incident in Slack, or otherwise signaling "I've got this." Acknowledgment is not resolution; it just means someone is on it.
### Worked example
An on-call team receives five pages in a week:
* Alert 1: acknowledged after 2 minutes
* Alert 2: acknowledged after 4 minutes
* Alert 3: acknowledged after 1 minute
* Alert 4: acknowledged after 15 minutes (escalated to a secondary responder)
* Alert 5: acknowledged after 3 minutes
Total = 2 + 4 + 1 + 15 + 3 = 25 minutes.
MTTA = 25 / 5 = **5 minutes**.
Notice how one missed page (alert 4) doubles the average. That sensitivity is a feature: MTTA surfaces escalation problems that a median would smooth over. Tracking both, plus the count of alerts that escalated past the primary on-call, gives the fullest picture.
## Why does MTTA matter?
MTTA is a direct read on the health of your paging and escalation setup. Everything it measures happens before anyone has debugged anything, so a bad MTTA almost always points to a process or tooling problem rather than a hard technical one:
* **Notification rules.** Are pages reaching people on channels they actually notice, with sensible retry behavior?
* **Escalation policies.** When the primary doesn't respond, how quickly does the page move to the next person? Long escalation timeouts inflate MTTA on every missed page.
* **Alert quality.** Teams drowning in noisy, non-actionable alerts start ignoring pages. A creeping MTTA is often the first measurable symptom of alert fatigue.
* **Schedule coverage.** Gaps or misconfigured handoffs in on-call schedules show up as outlier acknowledgment times at specific hours.
MTTA is also the first segment of [MTTR](/glossary/mttr): every minute an alert sits unacknowledged is a minute added to total resolution time before diagnosis even begins.
## What is a good MTTA?
For urgent, page-worthy alerts, most teams aim for acknowledgment within a few minutes — fast enough that escalation to a backup responder rarely triggers. But the right target depends on alert urgency (a low-priority ticket queue doesn't need a 5-minute acknowledgment), business hours versus overnight coverage, and whether your escalation timeouts are 5 minutes or 30. Set targets per urgency level, and judge yourself against your own trend rather than someone else's benchmark.
## How do you improve MTTA?
| Lever | What it fixes |
| ---------------------------------------- | ---------------------------------------------------- |
| Multi-channel notifications with retries | Pages that go unseen |
| Tighter escalation timeouts | Long waits before a backup is paged |
| Alert deduplication and grouping | Noise that trains responders to ignore pages |
| Urgency-based routing | Waking people for non-urgent issues (and vice versa) |
| Fair, well-staffed rotations | Burned-out responders who respond slowly |
Start by cutting noise: acknowledgment speed improves almost automatically when every page is real and actionable. Then tune escalation timeouts so a missed page costs minutes, not half an hour. Finally, review outliers — the handful of slowest acknowledgments each month usually share a root cause, like a schedule gap or a responder whose phone silences notifications overnight.
Rootly tracks MTTA per alert, per service, and per on-call shift out of the box — see [on-call metrics](/on-call/on-call-metrics) for the available breakdowns.
## Related terms
* [MTTA vs MTTR](/glossary/mtta-vs-mttr)
* [MTTR (mean time to resolution)](/glossary/mttr)
* [Error budget](/glossary/error-budget)
Browse the full [incident management glossary](/glossary).
# MTTA vs MTTR: What's the Difference?
Source: https://docs.rootly.com/glossary/mtta-vs-mttr
MTTA measures how fast a responder acknowledges an alert; MTTR measures how fast the team restores service. Learn the formulas and how they work together.
MTTA (mean time to acknowledge) measures how long it takes a responder to acknowledge an alert after it fires. MTTR (mean time to resolve) measures how long it takes to fully restore service after an incident begins. MTTA captures the speed of your paging and on-call process; MTTR captures the effectiveness of your entire response, from detection through fix. Both are averages calculated across incidents over a period.
## Comparison at a glance
| Dimension | MTTA | MTTR |
| ---------------- | ------------------------------------------------------- | ----------------------------------------------- |
| Full form | Mean time to acknowledge | Mean time to resolve (also repair or recovery) |
| What it measures | Alert fired → responder acknowledges | Incident start → service restored |
| What it reflects | On-call health: paging, escalation, alert quality | End-to-end response: diagnosis, mitigation, fix |
| Typical scale | Minutes | Minutes to hours |
| Formula | Total time to acknowledge ÷ number of alerts | Total time to resolve ÷ number of incidents |
| Improved by | Better routing, escalation policies, less alert fatigue | Runbooks, better tooling, architecture changes |
## What is MTTA?
MTTA is the average time between an alert firing and a human acknowledging it. The formula:
**MTTA = (sum of time-to-acknowledge across all alerts) ÷ (number of alerts)**
If your team acknowledged 40 alerts this month and the acknowledgment times sum to 120 minutes, MTTA is 3 minutes. A rising MTTA usually points to problems upstream of the actual fix: alerts routed to the wrong team, escalation policies with gaps, notification channels people ignore, or plain alert fatigue from too many low-value pages. MTTA is the clearest single signal of whether your on-call setup is working.
## What is MTTR?
MTTR is the average time from the start of an incident to full resolution:
**MTTR = (sum of time-to-resolve across all incidents) ÷ (number of incidents)**
If you had 5 incidents this quarter totaling 10 hours of downtime, MTTR is 2 hours. MTTR spans everything: detection, acknowledgment, triage, diagnosis, mitigation, and verification. That breadth makes it a useful executive-level indicator of reliability, but a blunt diagnostic tool — a bad MTTR tells you something is slow without telling you what.
## What does the R in MTTR actually stand for?
MTTR's "full form" is genuinely ambiguous, and the ambiguity matters when comparing numbers across teams:
* **Mean time to resolve** — through full resolution, including any follow-up work. The most common meaning in incident management.
* **Mean time to recovery (or restore)** — until service is back for users, even if a permanent fix comes later. Used by DORA metrics ("time to restore service").
* **Mean time to repair** — a hardware and manufacturing term for the time to physically fix a failed component.
Before you benchmark against another team's MTTR or set a target, agree on which definition your clock stops at. A team measuring "recovery" (mitigation) will always look faster than a team measuring "resolution" (permanent fix), even with identical performance.
## When should you track MTTA vs MTTR?
Track both — they answer different questions. Use MTTA to tune the front of your pipeline: if MTTA is high, fix routing, escalation, and alert noise before touching anything else, because nobody can resolve an incident they haven't seen. Use MTTR to evaluate the whole response system and to spot trends after process changes, such as adopting runbooks or adding automation. If MTTA is low but MTTR is high, your paging works and your bottleneck is diagnosis or remediation.
## Worked example
A payment API starts throwing errors at 14:00. The monitor fires at 14:02, and the on-call engineer acknowledges the page at 14:06. She identifies a bad deploy, rolls it back, and the service is confirmed healthy at 14:50.
* Time to acknowledge: 14:02 → 14:06 = **4 minutes** (contributes to MTTA)
* Time to resolve: 14:02 → 14:50 = **48 minutes** (contributes to MTTR)
If the previous month's incidents averaged 6 minutes to acknowledge and 70 minutes to resolve, this incident improves both averages. Notice that only 4 of the 48 minutes were acknowledgment — here, shaving MTTA further buys little, while faster rollback tooling would cut MTTR meaningfully.
## How this works in Rootly
Rootly calculates MTTA and MTTR automatically from alert and incident timestamps, with a pre-built dashboard you can slice by team, service, and severity. See [On-Call Metrics](/on-call/on-call-metrics).
## Related terms
* [SLA vs SLO vs SLI](/glossary/sla-vs-slo-vs-sli)
* [Incident Severity vs Priority](/glossary/severity-vs-priority)
* [Runbook vs Playbook](/glossary/runbook-vs-playbook)
* Browse the full [Incident Management Glossary](/glossary)
# What Is MTTR? Mean Time to Resolution Explained
Source: https://docs.rootly.com/glossary/mttr
MTTR (mean time to resolution) is the average time from when an incident starts to when it is fully resolved. Formula, examples, and how to improve it.
MTTR stands for mean time to resolution: the average time it takes to fully resolve an incident, measured from the moment the incident begins to the moment service is restored and the fix is complete. It is calculated by dividing total resolution time across a set of incidents by the number of incidents. MTTR is the most widely used measure of how quickly a team recovers from failure.
## What does MTTR stand for?
The "R" in MTTR is ambiguous, and the four common expansions measure genuinely different things. When someone quotes an MTTR number, always confirm which definition they mean — comparing "time to respond" against "time to resolution" makes a team look either heroic or terrible for no reason.
| Expansion | What it measures | Clock stops when... |
| --------------------------- | ------------------------------ | ------------------------------------------------------ |
| Mean time to **resolution** | Full incident lifecycle | The incident is fully resolved, including any cleanup |
| Mean time to **repair** | Fixing the failed component | The repair itself is complete |
| Mean time to **recovery** | Restoring service to users | Users can use the service again, even via a workaround |
| Mean time to **respond** | Reaction speed after detection | A responder begins actively working the incident |
Mean time to recovery and mean time to repair often differ: rolling back a bad deploy restores service in minutes (recovery) even if the underlying bug takes days to fix (repair). Mean time to respond is closer to [MTTA](/glossary/mtta) territory — it measures the front end of the incident, not the fix.
## How do you calculate MTTR?
```text theme={null}
MTTR = Total resolution time across incidents / Number of incidents
```
Resolution time for each incident runs from the incident's start time (or detection time, depending on your convention — pick one and apply it consistently) to its resolved timestamp.
### Worked example
A team handles four incidents in a month:
* Incident 1: resolved in 45 minutes
* Incident 2: resolved in 2 hours (120 minutes)
* Incident 3: resolved in 30 minutes
* Incident 4: resolved in 3 hours 25 minutes (205 minutes)
Total resolution time = 45 + 120 + 30 + 205 = 400 minutes.
MTTR = 400 / 4 = **100 minutes**, or 1 hour 40 minutes.
Because it is a mean, one long-running incident can drag the number dramatically. Many teams track the median and the 90th percentile alongside MTTR, and segment by severity, so a single messy SEV1 doesn't hide steady improvement everywhere else.
## What is a good MTTR?
There is no universal benchmark, and be skeptical of anyone selling one. A "good" MTTR depends on:
* **Severity.** A SEV1 outage and a SEV4 cosmetic bug should never share a target. Most teams set per-severity goals.
* **Industry and risk profile.** A payments platform tolerates far less downtime than an internal analytics tool.
* **Architecture.** Systems designed for fast rollback and graceful degradation recover faster by construction.
* **Definition.** Resolution, repair, recovery, and respond produce very different numbers for the same incidents.
The most useful comparison is your own trend line: is MTTR for each severity level going down quarter over quarter?
## How do you reduce MTTR?
MTTR compresses when you shorten each phase of the incident:
1. **Detect faster.** Better alerting and monitoring coverage means the clock starts closer to the actual failure.
2. **Acknowledge and mobilize faster.** Clear on-call schedules and escalation policies reduce the gap between alert and action — this is what [MTTA](/glossary/mtta) measures.
3. **Diagnose faster.** Runbooks, service catalogs, and searchable history of past incidents cut investigation time.
4. **Fix faster.** Practiced rollback procedures, feature flags, and automation beat improvising under pressure.
5. **Learn.** Retrospectives that produce completed action items prevent repeat incidents and make the next one shorter.
Rootly computes MTTR automatically from incident timestamps, segmented by severity, service, and team — see [default metrics](/metrics/default-metrics) for how each duration is derived.
## Related terms
* [MTTA vs MTTR](/glossary/mtta-vs-mttr)
* [MTTA (mean time to acknowledge)](/glossary/mtta)
* [MTBF (mean time between failures)](/glossary/mtbf)
Browse the full [incident management glossary](/glossary).
# Retrospective vs Postmortem: What's the Difference?
Source: https://docs.rootly.com/glossary/retrospective-vs-postmortem
A postmortem analyzes a specific incident after it ends; a retrospective reviews how a team works over time. In incident management the terms overlap.
A postmortem is a structured analysis of a single incident after it's resolved: what happened, why, and what will prevent recurrence. A retrospective is traditionally a recurring team ritual — borrowed from agile — that reviews how the team worked over a period, incident or not. In incident management the two words now largely describe the same artifact, with "retrospective" increasingly preferred because "postmortem" implies death and blame, while the process should be about learning.
## Comparison at a glance
| Dimension | Postmortem | Retrospective |
| ------------------------- | --------------------------------------------- | --------------------------------------------- |
| Origin | Medicine — examination after death | Agile — recurring sprint review |
| Trigger | A specific incident ends | A cadence (sprint, month) or an incident |
| Scope | One incident: timeline, causes, actions | Team practices, process, and outcomes broadly |
| Tone risk | Can sound like an autopsy of a failure | Framed around continuous improvement |
| Typical output | Written report + action items | Discussion notes + process changes |
| In incident tooling today | Often used interchangeably with retrospective | Often used interchangeably with postmortem |
## What is an incident postmortem?
A postmortem is the written record and review meeting produced after a significant incident. A complete one includes a timeline (detection through resolution), user and business impact, contributing causes, what went well and what didn't in the response itself, and concrete action items with owners and due dates. The gold standard is the **blameless postmortem**: the analysis assumes people acted reasonably given what they knew, and asks why the system made the failure possible — because responders who fear blame stop reporting honestly, and the organization stops learning.
## What is a retrospective?
In its original agile sense, a retrospective is a recurring meeting where a team reflects on a recent period of work — what to keep, drop, and try — regardless of whether anything broke. In incident management, the term has been adopted for post-incident review specifically, as a deliberate rebranding: same timeline, same causal analysis, same action items, but a name that signals learning rather than autopsy. Some teams also run genuine periodic incident retrospectives — a monthly review of all incidents in aggregate to spot patterns no single postmortem reveals, like a rising share of deploy-triggered incidents.
## Does the name actually matter?
More than you'd expect. The document is identical either way, but words set the tone of the meeting. "Postmortem" primes participants to explain a death; "retrospective" primes them to improve a process. Teams that struggle with defensive, finger-pointing reviews often find the rename a cheap, effective nudge — especially paired with explicit blameless ground rules. If your culture is already healthy, keep whichever term your team uses consistently; a shared vocabulary beats a fashionable one.
## Worked example
A SEV2 takes checkout down for 38 minutes on Tuesday. On Thursday the team holds its incident review — call it a retrospective or a postmortem, the agenda is the same:
1. **Timeline:** alert at 09:14, acknowledged 09:17, root cause (expired TLS certificate on an internal service) identified 09:35, new cert deployed 09:52.
2. **Impact:** \~4,100 failed checkout attempts, roughly \$18,000 in delayed orders.
3. **Contributing causes:** certificate expiry monitoring covered public endpoints only; the renewal runbook referenced a decommissioned tool.
4. **What went well:** paging worked, the right responder was engaged within 3 minutes.
5. **Action items:** add internal endpoints to cert monitoring (owner: platform, due in 2 weeks); update the renewal runbook; automate renewal for internal certs (due next quarter).
Then, at the end of the month, the team's periodic retrospective reviews all six incidents from the month and notices three involved expired credentials of some kind — elevating "credential lifecycle automation" from a one-off action item to a roadmap priority. The single-incident review and the periodic review answered different questions; healthy teams run both.
## When should you write one?
Not every incident deserves a full review — a blanket rule produces rushed, low-value documents. A common policy: mandatory for SEV1 and SEV2, optional for lower severities unless the incident was novel, customer-visible, or surprising. The trigger worth honoring above all: whenever a responder says "that was weird," schedule the review.
## How this works in Rootly
Rootly generates retrospectives from the incident's actual timeline and supports configurable, step-based retrospective processes per incident type. See [Retrospectives](/retrospectives/retrospectives).
## Related terms
* [Incident vs Problem](/glossary/incident-vs-problem)
* [Runbook vs Playbook](/glossary/runbook-vs-playbook)
* [MTTA vs MTTR](/glossary/mtta-vs-mttr)
* Browse the full [Incident Management Glossary](/glossary)
# What Is a Runbook?
Source: https://docs.rootly.com/glossary/runbook
A runbook is a step-by-step operational guide for handling a specific task or failure scenario, written so any qualified responder can follow it under pressure.
A **runbook** is a step-by-step operational guide for handling a specific task or failure scenario—restarting a service, failing over a database, rotating a certificate. It is written so that any qualified responder can execute it correctly under pressure, without needing the tribal knowledge of the person who wrote it. Good runbooks turn 3 a.m. panic into a checklist.
## What does a good runbook contain?
A runbook is only as useful as it is followable at the worst possible moment. The strong ones share a structure:
* **Trigger conditions.** When to use this runbook—the alert names, symptoms, or dashboards that point here.
* **Preconditions and access.** What permissions, tools, or credentials the responder needs before starting, so step 4 isn't where they discover they lack production access.
* **Numbered steps with exact commands.** Copy-pasteable commands, real hostnames or clear placeholders, and the expected output of each step so responders know whether it worked.
* **Verification.** How to confirm the fix took—which metric should recover, which endpoint should return 200.
* **Rollback and escalation.** What to do if a step fails, and who to page when the runbook runs out.
* **Ownership and last-reviewed date.** A runbook nobody has touched in two years is a liability wearing the costume of an asset.
The test is simple: could a competent engineer who has never touched this system follow it end to end? If a step says "restart the service the usual way," it fails the test.
## How is a runbook different from documentation?
Documentation explains how a system works; a runbook tells you what to do right now. Architecture docs, API references, and design documents are optimized for understanding—they reward slow, careful reading. Runbooks are optimized for execution—they reward scanning, and they assume the reader is stressed, possibly half-asleep, and not in a mood to learn. A page that starts with three paragraphs of background on the caching layer is documentation; a page that starts with "Step 1: check whether the cache hit rate on this dashboard is below 60%" is a runbook. Teams need both, but mixing them produces something that serves neither purpose well.
Closely related is the playbook—a broader response plan that may reference several runbooks. In Rootly, [playbooks](/configuration/playbooks) attach step-by-step guidance directly to matching incidents. The distinction is covered in [runbook vs playbook](/glossary/runbook-vs-playbook).
## What is the runbook automation spectrum?
Runbooks evolve along a spectrum from human-executed to fully automated:
1. **Manual.** A human reads each step and performs it by hand. This is where every runbook starts, and it's where you learn whether the steps are actually correct.
2. **Semi-automated.** The tedious or error-prone steps become scripts or one-click actions, but a human still decides when to run them and reviews the results. Most operational runbooks should live here for a while—automation with human judgment at the decision points.
3. **Fully automated.** The system detects the condition and executes the remediation with no human in the loop—auto-scaling, automatic failover, self-healing restarts. At this point the runbook has effectively graduated into software, and it needs the same testing and review as any other production code.
The spectrum is a maturity path, not a ranking: some procedures (say, anything involving irreversible data operations) should deliberately stay manual or semi-automated. The rule of thumb: automate a step only after it has been executed manually enough times that you trust it completely, and keep the human at every step where judgment beats speed.
## What does a runbook look like in practice?
Consider a "primary database failover" runbook. It names the triggering alerts (`db-primary-unreachable`), lists required access (production SSH plus the `dba` role), then walks through: confirm the primary is truly down (with the exact health-check command and expected failure output), verify replica lag is under 10 seconds, run the promotion script, update the connection string, and watch the error-rate dashboard recover. It ends with an escalation line—"if replica lag exceeds 10 seconds, stop and page the DBA on-call"—that saves a responder from turning an outage into data loss.
## Related terms
* [Runbook vs Playbook](/glossary/runbook-vs-playbook)
* [What Is Incident Response?](/glossary/incident-response)
* [What Is Alert Fatigue?](/glossary/alert-fatigue)
Browse all definitions in the [incident management glossary](/glossary).
# Runbook vs Playbook: What's the Difference?
Source: https://docs.rootly.com/glossary/runbook-vs-playbook
A runbook is a step-by-step procedure for one specific technical task; a playbook is a broader strategy for handling a whole class of situations.
A runbook is a precise, step-by-step procedure for completing one specific technical task — restart this service, rotate this certificate, fail over this database. A playbook is a higher-level guide for navigating an entire class of situations — how to run a SEV1 response, how to handle a security incident — including roles, decision points, and communication. Runbooks tell you exactly what to type; playbooks tell you how to think and coordinate.
## Comparison at a glance
| Dimension | Runbook | Playbook |
| -------------------- | --------------------------------------------------- | ------------------------------------------------- |
| Scope | One specific task or failure mode | A whole scenario or incident class |
| Content | Ordered commands, checks, expected outputs | Roles, phases, decision trees, comms plans |
| Level of judgment | Minimal — follow the steps | Significant — adapt to the situation |
| Primary user | The engineer at the keyboard | The incident commander and responders |
| Automation potential | High — often fully scriptable | Low — coordination resists automation |
| Example | "Recover the payments queue after a poison message" | "Responding to a customer-data security incident" |
## What is a runbook?
A runbook documents the exact procedure for a known task so that any qualified on-call engineer can execute it correctly under pressure, ideally without waking the one person who understands the system. A good runbook includes preconditions ("confirm replication lag is under 10 s before failing over"), numbered steps with exact commands, expected output at each step, and a clear abort path if something looks wrong. Because runbooks are deterministic, the best ones eventually become automation — a script or workflow — with the document remaining as the fallback and the explanation.
## What is a playbook?
A playbook operates one level up. It doesn't assume you know what's broken; it guides you through a category of event. An incident response playbook typically covers who takes which role (commander, communications lead, scribe), what the phases are (detect, triage, mitigate, resolve, review), when to escalate, what to tell customers and when, and which decisions need which approvals. Playbooks contain branch points — "if customer data may be exposed, engage legal and switch to the security playbook" — because the situations they cover are too varied for a single linear script.
## Which one do you need?
Both, at different layers. The playbook is the skeleton of your response; runbooks are the tools it reaches for. During an incident, the playbook tells the commander to assign a responder to mitigate database load — and the responder then opens the "enable read-replica overflow" runbook to actually do it. Teams that only write playbooks have great coordination and slow hands-on fixes; teams that only write runbooks execute known fixes fast but flail when the failure is novel or the incident spans teams.
## Worked example
At 03:10 a checkout-latency alert fires and pages the on-call engineer. She acknowledges and, seeing sustained impact, declares a SEV2. The **SEV2 playbook** kicks in: it assigns her as interim incident commander, opens a dedicated channel, sets a 30-minute status-update cadence, and lists the first triage questions. Triage points to Redis memory exhaustion. She opens the **"Redis memory pressure" runbook**: step 1, confirm `used_memory` above 90%; step 2, identify the top key patterns; step 3, flush the sessions cache with the provided command; step 4, verify latency recovers within 5 minutes. Fix confirmed at 03:41. The playbook then directs the close-out: downgrade severity, post the final update, and schedule the retrospective. One incident, one playbook, one runbook — each doing a job the other couldn't.
## How do you keep them from going stale?
Stale runbooks are worse than none, because responders trust them at the exact moment they can't verify them. Treat both documents as code: review them after every incident where they were used (the retrospective is the natural checkpoint), date-stamp them, assign an owner, and test runbooks during game days rather than discovering the commands changed during a real outage.
## How this works in Rootly
Rootly playbooks attach task lists and procedures directly to incidents based on conditions like severity or affected service, so the right guidance surfaces automatically when an incident starts. See [Playbooks](/configuration/playbooks).
## Related terms
* [Retrospective vs Postmortem](/glossary/retrospective-vs-postmortem)
* [Incident Severity vs Priority](/glossary/severity-vs-priority)
* [Incident vs Problem](/glossary/incident-vs-problem)
* Browse the full [Incident Management Glossary](/glossary)
# What Are SEV Levels? SEV1, SEV2, SEV3 Explained
Source: https://docs.rootly.com/glossary/sev-levels
SEV levels (SEV1, SEV2, SEV3...) classify incidents by severity of impact, driving who responds, how fast, and how the incident is communicated.
**SEV levels** are a numbered scale for classifying incidents by the severity of their impact, with SEV1 conventionally the most critical and higher numbers progressively less serious. Assigning a SEV level at declaration sets the response in motion proportionally: it determines who gets paged, how quickly, whether leadership is notified, and how often updates go out. "SEV" is simply shorthand for "severity."
## Why do SEV levels exist?
Without a shared scale, every incident starts with a negotiation: is this bad? Whom should I bother? SEV levels replace that negotiation with a lookup. Once an incident is labeled SEV1, nobody debates whether it deserves a dedicated incident channel or an executive update—the label carries the playbook with it. The scale also makes reporting possible: "we had three SEV1s this quarter, down from seven" is a meaningful sentence only if SEV1 means the same thing every time.
The numbering convention runs opposite to intuition for newcomers: **lower number = worse incident**. A SEV1 is an emergency; a SEV5 is a note.
## What does a typical SEV scale look like?
There is no universal standard—every organization tunes definitions, and many use only three or four levels. The following five-level scheme is a common starting point:
| Level | Typical meaning | Example | Response expectation |
| -------- | ------------------------------------------------------------------------------------ | ------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| **SEV1** | Critical: full outage, data loss, or security breach affecting most or all customers | Payment processing down for all users | Immediate page, all-hands response, dedicated incident channel, exec notification, frequent public updates |
| **SEV2** | Major: significant degradation or a core feature broken for many customers | Search failing for \~30% of requests | Immediate page to owning team, incident channel, regular stakeholder updates |
| **SEV3** | Moderate: minor feature impaired, or a workaround exists; limited customer impact | Export-to-CSV broken; API works | Response during business hours, owned by one team, tracked to resolution |
| **SEV4** | Low: cosmetic issues or negligible customer impact | Misaligned dashboard widget | Ticketed and prioritized in normal work; no paging |
| **SEV5** | Informational: no impact, but worth recording | Near-miss caught by a canary deploy | Logged for trend analysis and learning |
Two design choices matter more than the exact wording. First, definitions should be observable—"affects more than X% of customers," not "really bad"—so two responders reach the same answer. Second, each level must map to concrete response behavior; a severity that changes nothing about the response is just decoration. In Rootly, severity levels and their notification behavior are configured under [severities](/configuration/severities).
## How are SEV levels used during an incident?
The initial SEV is assigned during triage, in the first minutes, using whatever is known at the time—and it is explicitly provisional. Teams should upgrade or downgrade freely as facts emerge, since scope frequently looks different twenty minutes in. Best practice when uncertain: round up. Over-calling a SEV2 costs some interrupted evenings; under-calling one costs response time during real customer impact.
A realistic sequence: at 14:02 an engineer sees checkout errors in one region and declares a SEV2. At 14:15, monitoring shows the failure spreading to a second region and the error rate doubling—the commander upgrades to SEV1, which automatically pages additional responders and notifies leadership. At 14:40 a rollback contains the issue and impact drops to a single degraded feature; the incident is downgraded back to SEV2 for the remainder of the response. Each change re-tunes the machinery without anyone renegotiating from scratch.
## How do SEV levels differ from P-levels?
Many teams also use P-levels (P1, P2, P3...), and the two scales are easy to conflate. Strictly speaking, **severity measures impact—how bad it is—while priority measures order—what gets worked on first.** They usually correlate but can diverge: a SEV3 bug with a contractual deadline might be P1 work, while a technically severe issue in a deprecated system might be deliberately low priority. In practice, plenty of organizations use "P1" and "SEV1" interchangeably for incidents; what matters is picking one scale for incident classification and defining it precisely. The distinction is unpacked further in [severity vs priority](/glossary/severity-vs-priority).
## Related terms
* [Severity vs Priority](/glossary/severity-vs-priority)
* [What Is Incident Triage?](/glossary/incident-triage)
* [What Is Incident Management?](/glossary/incident-management)
Browse all definitions in the [incident management glossary](/glossary).
# Incident Severity vs Priority: What's the Difference?
Source: https://docs.rootly.com/glossary/severity-vs-priority
Severity measures how bad an incident's impact is; priority determines how urgently your team responds. They usually align — but not always.
Severity describes the impact of an incident — how badly it degrades service and how many users it affects. Priority describes the urgency of the response — how quickly your team should act relative to everything else in flight. Severity is an assessment of the world; priority is a decision about your resources. They correlate strongly, but a low-severity issue can still be high priority, and vice versa.
## Comparison at a glance
| Dimension | Severity | Priority |
| ------------ | ---------------------------------------------------- | ------------------------------------------- |
| Answers | "How bad is the impact?" | "How urgently do we act?" |
| Based on | Scope of degradation, users affected, data risk | Business context, deadlines, who's affected |
| Common scale | SEV1–SEV4 (or SEV0–SEV3) | P1–P4 |
| Set by | Responder assessing the incident | Responder or leadership weighing trade-offs |
| Drives | Escalation, paging, exec notification, comms cadence | Ordering of work and resource allocation |
| Changes when | Impact grows or shrinks | Business context shifts |
## What is incident severity?
Severity classifies impact on a fixed scale so everyone responds consistently. A typical scheme:
* **SEV1** — critical: full outage or data loss risk; most users affected.
* **SEV2** — major: significant degradation or a core feature down for many users.
* **SEV3** — minor: partial degradation, workaround exists, limited user impact.
* **SEV4** — low: cosmetic issues or minor bugs with negligible impact.
Severity should be defined by observable criteria ("checkout error rate above 5%") rather than gut feel, because it triggers concrete machinery: who gets paged, whether executives are notified, how often status updates go out, and whether a retrospective is required.
## What is incident priority?
Priority ranks the response against everything else your team could be doing. It folds in context that severity deliberately ignores: contractual deadlines, which customer is affected, regulatory exposure, upcoming launches, and what else is on fire. Two incidents of identical severity can carry different priorities — one affects a trial user on a Sunday night, the other affects your largest customer during their peak sales event.
## Can a low-severity incident be high priority?
Yes, and this is exactly why the two dimensions exist separately. A typo in your pricing page is SEV4 by any impact rubric — nothing is down, no errors, no data at risk. But if it displays the wrong price and creates legal exposure, fixing it may be P1: drop other work and ship the correction now. Conversely, a SEV2 degradation in an internal batch system at 2 a.m. might be P3 — real impact, but nothing gained by waking anyone when it can be fixed at 9 a.m.
## Worked example
Two incidents open on the same afternoon:
1. **Incident A:** search indexing lags 45 minutes behind. Impact is broad but shallow — every user sees slightly stale results. The team classifies it **SEV3**. No SLA covers search freshness and no revenue path is blocked, so it's **P3**: fix within the sprint.
2. **Incident B:** a single enterprise customer can't export compliance reports. Only one tenant is affected, so it's **SEV3** by the impact rubric. But that customer's regulatory filing is due in 48 hours and the contract includes support commitments — the team sets **P1** and assigns an engineer immediately.
Same severity, opposite priorities. If the team had only one field to express both, they'd either inflate B's severity (breaking their paging and reporting rules) or under-respond to it.
## Should you track both fields?
Smaller teams often start with severity alone and treat it as an implicit priority — for a five-person startup where every SEV1 is all-hands anyway, that's fine. Add a separate priority field once you regularly have multiple concurrent incidents, customer-specific commitments, or a support queue feeding engineering. The test: if you find yourself arguing "it's technically SEV3 but we should treat it like a SEV1," you need a priority field.
## How this works in Rootly
Rootly ships with configurable severity levels that can drive escalations, notifications, and workflows automatically, and you can add a separate priority as a custom field. See [Severities](/configuration/severities).
## Related terms
* [MTTA vs MTTR](/glossary/mtta-vs-mttr)
* [SLA vs SLO vs SLI](/glossary/sla-vs-slo-vs-sli)
* [Incident vs Problem](/glossary/incident-vs-problem)
* Browse the full [Incident Management Glossary](/glossary)
# SLA vs SLO vs SLI: What's the Difference?
Source: https://docs.rootly.com/glossary/sla-vs-slo-vs-sli
An SLI is a measurement, an SLO is your internal target for that measurement, and an SLA is the external contract with consequences. Here's how they stack.
An SLI (service level indicator) is a measurement of service behavior, such as the percentage of requests served successfully. An SLO (service level objective) is the internal target you set for that measurement, such as 99.9% success over 30 days. An SLA (service level agreement) is the external contract that promises customers a level of service, with penalties if you miss it. SLIs feed SLOs, and SLOs are set stricter than SLAs.
## Comparison at a glance
| Dimension | SLI | SLO | SLA |
| ---------------------- | ---------------------------- | ----------------------------------------- | --------------------------------------- |
| What it is | A measurement | An internal target | A customer contract |
| Example | 99.92% of requests succeeded | ≥ 99.9% success over 30 days | 99.5% monthly uptime or service credits |
| Audience | Engineers | Engineering and product teams | Customers and legal |
| Consequence of missing | None — it's just data | Slow feature work, prioritize reliability | Refunds, credits, contractual penalties |
| Who defines it | SRE / platform teams | Engineering with product | Sales, legal, and leadership |
| Changes | Rarely (it's a definition) | Tuned as the service matures | Only via contract renegotiation |
## What is an SLI?
An SLI is a quantitative measure of some aspect of service level — nothing more. Common SLIs include availability (successful requests ÷ total requests), latency (proportion of requests faster than a threshold), and freshness or durability for data systems. A good SLI is expressed as a ratio of good events to total events, because that maps directly to user experience. "CPU utilization" is a metric; "percentage of checkout requests completing under 500 ms" is an SLI.
## What is an SLO?
An SLO attaches a target and a window to an SLI: "99.9% of checkout requests complete successfully, measured over a rolling 30 days." SLOs are internal commitments. Their real power is the **error budget** they imply — at 99.9% over 30 days, you can "spend" about 43 minutes of full downtime before breaching. While budget remains, teams ship freely; when it's exhausted, reliability work takes priority. That trade-off is the core mechanism SRE teams use to balance velocity against stability.
## What is an SLA?
An SLA is a business agreement with customers, typically written by legal and sales rather than engineers. It specifies a service level (often looser than your SLO) and what happens when you miss it: service credits, refunds, or termination rights. Because breaching an SLA costs real money and trust, teams deliberately keep SLOs tighter than SLAs — the SLO acts as an early-warning line you cross internally before customers are affected contractually.
## Why should your SLO be stricter than your SLA?
The gap between them is your safety margin. If your SLA promises 99.5% monthly uptime and your SLO targets 99.9%, an SLO breach triggers internal escalation while you still have roughly 3.2 hours of budget before the contractual line. Setting SLO equal to SLA means every internal miss is instantly a customer-facing breach, with no room to react.
## Worked example
A B2B API team defines the stack like this:
* **SLI:** proportion of API requests returning a non-5xx response within 300 ms.
* **SLO:** 99.9% over a rolling 30-day window — an error budget of about 43 minutes.
* **SLA:** 99.5% monthly, with a 10% service credit for any month below it.
Mid-month, a bad migration causes 25 minutes of elevated errors. The SLI dips, consuming more than half the error budget. The SLO isn't breached yet, but the team freezes risky deploys for the rest of the window and prioritizes the migration fix. The SLA (which allows roughly 3.6 hours of downtime per month) is never in danger — which is exactly the point. The SLO absorbed the incident so the SLA didn't have to.
## Do you need all three?
You always need SLIs and SLOs if you want to manage reliability deliberately — they cost nothing contractually and give teams a shared target. SLAs only make sense when customers demand contractual guarantees, which is common for paid B2B products and rare for internal services. Internal platform teams often run SLIs and SLOs alone, sometimes informally calling the SLO an "internal SLA."
## Related terms
* [MTTA vs MTTR](/glossary/mtta-vs-mttr)
* [Incident Severity vs Priority](/glossary/severity-vs-priority)
* Browse the full [Incident Management Glossary](/glossary)
In Rootly, incidents affecting SLO-backed services can be tracked against severity and service impact from creation onward. See [Incident Management](/incidents/incidents).
# What Is an Incident Channel (aka War Room)?
Source: https://docs.rootly.com/glossary/war-room
An incident channel—often called a war room—is the dedicated space where responders coordinate a major incident, keeping the investigation in one place.
An **incident channel**—widely known as a **war room**—is a dedicated space, physical or virtual, where responders coordinate during a major incident. It concentrates the people, context, and decisions in one place so the investigation moves as a single effort rather than a scatter of side conversations. Today it is almost always virtual: a dedicated chat channel plus a bridge call, spun up the moment a serious incident is declared.
Rootly prefers **incident channel** or **coordination space** over "war room." The work is focused coordination, not combat—and the calmer name sets the tone teams want in the room. This entry uses "war room" because it's the term most people search for, but the plainer language appears throughout Rootly's product and docs.
## Why do teams use a dedicated incident channel?
Major incidents fail in predictable ways without a focal point: three people debug the same hypothesis in different DMs, a critical finding gets posted where half the team never sees it, and nobody can answer "what's the current status?" without interviewing four people. A dedicated channel fixes this by making one place authoritative. Everything important—findings, decisions, status—flows through it, which means the timeline reconstructs itself and new responders get up to speed by reading backward instead of interrupting everyone.
The physical version—engineers around a table with laptops and a whiteboard—still exists, but distributed teams have made the virtual channel the default. The principle is identical either way: one room, one conversation, one source of truth.
## When should you open one?
Not every incident needs one. A single-responder SEV3 handled in twenty minutes gains nothing from ceremony. A dedicated channel earns its overhead when:
* The incident is severe (typically SEV1 or SEV2) or customer-facing
* More than two or three responders are involved, or multiple teams need to coordinate
* The investigation is likely to run longer than an hour
* Executives or support teams need a place to get status without interrupting responders
Many teams remove the judgment call entirely: declaring a SEV1 automatically creates the channel, starts the bridge, and pages the roster. Automation matters here because the minutes after declaration are precisely when nobody has spare attention for logistics. In Rootly, [declaring an incident](/incidents/incidents) can create the dedicated Slack channel and assemble responders automatically.
## Who belongs in the channel?
Small enough to move fast, complete enough to act:
* **Incident commander** — runs the room, tracks the effort, and makes the calls
* **Technical responders** — the engineers actively investigating, usually the service owners
* **Communications lead** — translates the room's progress into stakeholder and customer updates
* **Scribe** — captures the timeline, decisions, and action items as they happen
* **Subject-matter experts** — pulled in for specific questions, released when answered
Everyone else—curious engineers, anxious executives—should follow along from outside, via status updates or a read-only view. A channel with thirty spectators stops being a working space; the commander should feel free to ask observers to leave.
## What makes a virtual incident channel work?
Virtual coordination has its own craft:
* **One dedicated channel per incident.** Never reuse a general channel; the incident's history should live in one scrollable place, uncontaminated by other traffic.
* **A bridge call for high-bandwidth moments.** Voice or video is faster for debate and decisions; the channel is better for commands, links, and the record. Decisions made on the call must be written back into the channel—if it isn't written down, half the responders never heard it.
* **Pinned status.** Keep a regularly updated summary (impact, current hypothesis, next steps, owner) pinned so joiners self-serve context.
* **Threads for side investigations.** Parallel workstreams get threads; conclusions get promoted to the main channel.
* **An explicit end.** When the incident resolves, the commander closes the room with a final summary. The channel is then archived intact as input for the retrospective.
## What does this look like in practice?
A payments provider takes a SEV1 at 09:14 when transaction success rates fall to 60%. Declaration auto-creates `#inc-2091-payments-degraded` and a bridge link. By 09:20 the commander has pinned a status, two engineers are on the bridge comparing deploy timelines, and a third posts in-channel that a partner API's latency tripled at 09:10. The commander declares the working hypothesis in the channel, the communications lead posts a status-page update, and when the partner confirms their fix at 09:58, the resolution and full timeline are already sitting in one place—ready for the retrospective.
## Related terms
* [What Is Incident Response?](/glossary/incident-response)
* [What Are SEV Levels?](/glossary/sev-levels)
* [What Is Incident Management?](/glossary/incident-management)
Browse all definitions in the [incident management glossary](/glossary).
# Welcome to Rootly help and documentation
Source: https://docs.rootly.com/help-and-documentation
Rootly documentation: set up on-call and alerting, run incidents, publish status pages, and learn from retrospectives, with AI throughout every step.
Welcome to Rootly help and documentation.
The all-in-one AI platform for on-call, incident response, status pages, and post-incident learning.
Start with a task
Browse by product area
On-Call
On-call that's built for simplifying paging, scheduling, requesting coverage, and more—so you can stay focused on fixing.
Incident Response
Incident management with built-in AI to automate your workflows for faster resolutions—directly in Slack, Google Chat, and Teams.
Rootly AI
AI that works for you across the incident lifecycle—triage, root cause analysis, response, comms, and retros.
Alerts
Alerts from every tool you run, ingested, deduplicated, grouped, and routed to the right responder the first time.
Automation & Workflows
Automation that runs your response: channels created, stakeholders updated, tickets filed, retros started, the same way every time.
Integrations
Connect all your existing tools—Slack, Jira, Zoom—and extend further with the Terraform provider, API, or MCP server.
Popular articles
Build with Rootly
API
Automate everything Rootly does, programmatically.
Terraform
Manage Rootly as code, versioned and reviewed.
CLI
Drive Rootly from your terminal, from setup to daily tasks.
MCP server
Connect your AI agents directly to Rootly.
Liquid variables
Inject live incident data into any workflow or template.
# Incident Response Setup Checklist
Source: https://docs.rootly.com/incident-response-setup-checklist
Work through the configuration that makes incident response automatic: declaration forms, the incident channel, roles and runbooks, and closing the loop.
Work top to bottom. You'll configure how incidents get **declared**, how the **incident channel** becomes a command center, how **roles, tasks, and runbooks** kick in automatically, and how you **close the loop** with status pages, follow-ups, and retrospectives. Check items off as you go.
## How the pieces fit together
| 1 · Declare & organize | 2 · Respond & communicate | 3 · Learn & improve |
| :-------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------- |
| **How an incident starts.** Forms, severities, roles, and runbooks that kick in the moment it's declared. | **What happens while it's live.** The command center, AI assistance, paging, and stakeholder updates. | **What happens after.** Follow-ups, retrospectives, and the data that makes the next incident faster. |
📌 **Note:** Rootly is highly customizable — forms, fields, severities, and automations are all configured per organization, so what your team sees may look different from any demo or default setup. The incident form is designed to guide responders through what they need to fill out regardless of configuration.
***
## 1. Configure incident declaration
Decide how an incident gets started, and what the form asks for.
1. **Set up the New Incident form** — Most fields are customizable in [Configuration → Forms](https://rootly.com/account/forms). Decide what's required (title, summary, severity, type) before responders ever see it. ([Creating incidents via Slack](/incidents/creating-incidents/creating-incidents-via-slack))
2. **Align your forms across channels** — You can create different forms per channel, but Rootly recommends keeping them in sync so responders have a consistent experience no matter where an incident originates.
1.
3. **Configure your severities** — [Severity](https://rootly.com/account/severities) isn't just a label — it's what triggers automations and workflows behind the scenes, so map out what each severity level should kick off before you go live. ([Incident lifecycle](/incidents/incidents))
4. **Decide on Triage vs. Started** — Choose whether incidents can be declared directly into Started, or must pass through an In Triage state first. ([Incidents](/incidents/incidents))
5. **Set up private incidents** — For security, legal, or customer-sensitive situations. Rootly's AI features (catchup, summaries) still work inside private incidents, so teams don't have to trade confidentiality for speed. ([Managing private incident access](/incidents/private-incidents/manage-via-web))
6. **Learn every command** — `/rootly help` in Slack surfaces every available command, so responders never need to memorize the list.
## 2. Set up the incident channel & command center
Make sure the auto-created Slack channel gives responders everything they need at a glance.
1. **Confirm automatic channel creation** — Rootly should spin up a dedicated channel per incident, with the severity in the name and a link out to the web view.
2. **Link your team's own tools** — Add links to your bridge, ticketing system, and any other tools your responders reach for mid-incident.
3. **Customize the command center block** — This is the pinned message at the top of the channel — walk through what buttons and links show up for your org by configuring your [Integration settings](https://rootly.com/account/integrations) (e.g. conferencing tool, Jira, runbooks, etc.).
4. **Add the bridge transcript / recording** — Enable Meeting Scribe so incident bridge calls (Zoom, Meet, Webex, Teams, GoToMeeting) get recorded, transcribed, and summarized automatically ([Meeting Scribe](/ai/meeting-scribe)). You can do this from the settings of your bridge integration.
1.
## 3. Configure incident roles & tasks
Make sure the right responsibilities — and the right follow-up work — get assigned automatically.
1. **Define your [Incident Roles](https://rootly.com/account/incident-roles)** — e.g. Incident Commander, Comms Lead, Scribe. Configure these in advance so people aren't assigned ad hoc mid-incident. ([Incident roles](/managing-teams/incident-roles))
2. **Attach Default Tasks to each role** — When a role is assigned, its default tasks are automatically created for that person — no one has to remember the checklist.
3. **Use roles as a training tool** — Once roles are assigned, anyone joining the incident can immediately see who's doing what, which doubles as on-the-job training for newer responders.
4. **Test it** — Create a test incident, attach a team, and confirm role assignment and task creation behave the way you configured them.
## 4. Enable AI catch-up & summaries
Let responders get up to speed instantly, without scrolling the whole channel.
1. **Turn on Incident Summarization** — Generates a concise, single-paragraph summary of the incident using metadata, alerts, timeline events, and communications. ([AI Summaries](/ai/ai-summaries))
2. **Use the catchup command** — `/rootly catchup` uses the same summarization technology, aimed at helping a late joiner understand a long-running incident without reading the full history.
3. **Feed it good context** — Summary quality depends on what's in the incident: timeline events, action items, alerts, and Slack communication all improve it. Encourage responders to keep the timeline updated as they go.
4. **Know the private-incident caveat** — For private incidents, confirm Slack channel message visibility settings allow AI access, or summarization won't have enough to work with.
## 5. Connect playbooks to your services
Make sure the right checklist shows up the moment an incident touches a given service.
1. **Build out your [Catalog](https://rootly.com/account/catalogs)** — [Services](https://rootly.com/account/services), and [teams](https://rootly.com/account/teams) live in the Catalog, and it's what powers automatic playbook attachment. ([Catalogs](/catalogs))
2. **Attach [playbooks](https://rootly.com/account/playbooks) to services and incident types** — When a service or type (e.g. "Security") is added to an incident, its associated playbook — and the tasks in it — attach automatically. ([Example usage with incidents](/configuration/example-usage-with-incidents))
1.
3. **Verify the auto-attach behavior** — Add a service to a test incident and confirm the runbook's tasks appear without anyone manually adding them.
## 6. Set up emoji reactions & the timeline
Turn a Slack reaction into a task, a follow-up, or a retrospective note — automatically.
1. **Configure your event emoji** — Choose which emoji create timeline events, tasks, or follow-ups when reacted to a message. Emoji lists for each purpose are separate and can't overlap. ([Adding events to timeline via Slack](/incidents/incident-timeline/adding-events-to-timeline-via-slack))
2. **Set your "pin to retrospective" emoji** — This is the most important one to get right: pinned messages build your retrospective as you go, and can always be edited or pruned later.
3. **Set your "task" and "follow-up" emoji** — So a reaction like ⭐ can create a task, and 📝 can create a follow-up, without anyone leaving the conversation.
## 7. Set up paging & escalation
Make sure responders never have to leave the incident channel to bring in the right people.
1. **Confirm the paging paths all work** — Responders should be able to page via natural-language AI request, `/rootly page`, or the Escalate button in the command center — all three should reach the same on-call rotations.
2. **Tie escalation policies to schedules** — Paging only works end-to-end if your On-Call schedules and escalation policies are already configured. ([Escalation policies](/on-call/escalation-policies))
3. **Confirm the leadership channel gets notified** — Severity changes (e.g. escalating to Sev 2) should automatically post an update to your leadership channel — verify this workflow is wired up.
## 8. Connect status pages
Keep external stakeholders informed without pulling responders out of the incident.
1. **Create your [status page(s)](https://rootly.com/account/status-pages)** — Public for customers, private for internal stakeholders, each with its own components. ([Creating a status page](/configuration/creating-a-status-page))
2. **Know it's not automatic** — Status pages are not 1:1 with incident status by default; someone needs to publish each update. Decide who owns that during an incident. ([Incident status pages](/configuration/publishing-incidents))
3. **Consider a workflow to prompt updates** — e.g. remind the channel to publish a status page update every 30 minutes during a live Sev 1/Sev 2.
## 9. Set up follow-ups & ticketing sync
Make sure action items land somewhere engineers already work.
1. **Connect Jira, Linear, or Asana** — Follow-ups created in Rootly can auto-create tickets in your team's actual backlog instead of getting lost in a doc. ([Jira integration](/integrations/jira/jira))
2. **Confirm two-way sync** — When a ticket status changes in Jira, the corresponding Rootly follow-up should update automatically, and vice versa.
3. **Map custom fields** — If your Jira project uses custom fields, map them so incident data lands in the right place instead of a generic description box.
## 10. Configure retrospectives
Decide what "done" looks like after an incident resolves.
1. **Set your retrospective [process](https://rootly.com/account/retrospective-processes?tab=process) & [template](https://rootly.com/account/retrospective-processes)** — Define the steps, required fields, and Liquid-templated content responders will see. One template can be marked default. ([Retrospectives](/retrospectives/retrospectives))
2. **Decide when a retrospective is required vs. optional vs. skipped** — Not every incident needs a full retro; set thresholds (severity, service, commander discretion) so the process scales.
3. **Set up retrospective-specific workflows** — Trigger actions when a retrospective is created or updated, separate from your incident-level workflows.
4. **Confirm the resolution AI assistance is on** — The resolution form includes AI-suggested resolution summaries — verify this is enabled so responders aren't writing from scratch.
## 11. Build supporting workflows
Automate the repetitive parts once the manual process is proven with [Workflows](https://rootly.com/account/workflows).
1. **Map out triggers → conditions → actions** for your top 2–3 repeated manual steps (e.g. leadership notifications, status page reminders, Jira creation). ([Workflows](/workflows/workflows))
2. **Start narrow, then expand** — A single reliable workflow (e.g. "post to leadership channel when severity ≥ Sev 2") beats a dozen half-configured ones.
3. **Review workflows periodically** — As services, teams, and tools change, workflows can silently stop matching conditions correctly — put a recurring check on the calendar.
***
Congratulations! You've successfully configured your Incident Response process in Rootly. Next up, when things go wrong, learn how Rootly pulls it all together to help you respond in an incident: review the Incident Responder Checklist.
# Custom Fields on Action Items
Source: https://docs.rootly.com/incidents/action-items/action-item-custom-fields
Add custom fields to tasks and follow-ups to capture organization-specific metadata, drive reporting, power workflow automation, and enrich ticketing exports.
## Overview
Custom fields let you attach organization-specific metadata—like product area, business unit, cluster, or infrastructure provider—to the tasks and follow-ups created from your incidents. That metadata then flows everywhere action items go: the web UI, Slack, workflows, ticketing exports, dashboards, the API, and webhooks.
Use custom fields on action items to:
* **Categorize action item work** by the dimensions your organization cares about (owning business unit, product area, affected cluster, etc.)
* **Report on follow-through** — filter and group action items by field values in lists and dashboards
* **Automate with workflows** — trigger on field changes, branch on field values, and write values into Jira, Linear, GitHub, and other ticketing tools
* **Keep exports complete** — include required metadata when action items are exported to external project management tools
Custom fields apply to both kinds of action item: **tasks** (lightweight, in-incident work) and **follow-ups** (post-incident work). Each kind has its own form, so you can surface different fields on tasks than on follow-ups. Only custom fields can be added to these forms—an action item's standard fields (title, description, assignee, priority, status, due date) are always present.
Custom fields for action items are rolling out progressively. If you don't see the **Incident Follow Up** or **Incident Task** forms under **Configuration → Forms**, reach out to your Rootly customer success manager or **[support@rootly.com](mailto:support@rootly.com)** to have it enabled.
***
## How It Works
Action items use the same custom field library as incidents. A single field definition—say, *Business Unit Owner*—can be placed on your incident forms, your action item forms, or both, so your reporting categories stay consistent: one name, one slug, one set of options. Each action item stores its **own value** for the field—seeded from the parent incident at creation where fields are shared, but fully independent after that (see [Pre-Filled from the Parent Incident](#pre-filled-from-the-parent-incident)).
There are three moving parts:
1. **Fields** — created and managed under **Configuration → Fields**, exactly like [custom incident fields](/configuration/custom-fields). All custom field types are supported: text, textarea, rich text, number, checkbox, date, datetime, select, and multiple select—including select fields backed by Teams, Users, Services, Functionalities, Environments, Causes, Incident Types, or [Catalogs](/catalogs).
2. **The action item forms** — the **Incident Follow Up** and **Incident Task** forms, both under **Configuration → Forms**, control which custom fields appear on follow-ups and tasks respectively. Each has separate **Web** and **Slack** versions you can configure independently.
3. **Values** — set by responders in the web UI or Slack, pre-filled from the parent incident where fields are shared, or written automatically by workflows and the API.
***
## Configuring the Task and Follow-Up Forms
Go to **Configuration → Fields** and create the fields you need, or reuse fields that already exist for your incidents. See [Custom Fields](/configuration/custom-fields) for field types, options, and best practices.
Go to **Configuration → Forms** and select **Configure** on the **Incident Follow Up** form (shown whenever a follow-up is added or edited) or the **Incident Task** form (shown whenever a task is added or edited).
Click **Add Fields** and select the custom fields to display. Drag and drop to reorder them. Use the tabs to configure the **Web** and **Slack** versions of the form separately.
To keep data consistent, Rootly recommends keeping the Web and Slack versions of a form in sync. A field placed only on the Web form won't appear in Slack dialogs (and vice versa).
Edit each field on the form to control whether it is **required**, and whether it is displayed or required **conditionally** based on the value of another field above it—the same conditional logic available on [built-in forms](/configuration/built-in-forms).
The **Incident Task** and **Incident Follow Up** forms are independent, and the Task form starts **empty**—placing a field on the follow-up form does not add it to tasks (or vice versa). Add fields to each form explicitly. Only custom fields can be placed on these forms; an action item's standard fields (title, description, assignee, priority, status, due date) are always present, and built-in incident fields (severity, services, etc.) belong to the incident itself.
If you use [Dynamic Forms](/configuration/dynamic-forms), the action item forms respect your form sets, so different incident types or conditions can present different fields.
***
## Filling In Custom Field Values
## In the Web UI
When creating or editing an action item on an incident, the form displays every custom field placed on the Web version of the matching form (**Incident Task** or **Incident Follow Up**). Values can be added at creation or filled in later by editing the action item. The global **Follow-ups** view under Post-Incident also exposes follow-up custom fields.
## In Slack
Slack action item dialogs display the custom fields placed on the Slack version of the matching form. Required and conditional rules are enforced in the dialog just as on the web.
* **Tasks** — created with `/rootly task` (or `/rootly add action item`); view and manage yours with `/rootly todo` or `/rootly tasks`.
* **Follow-ups** — created with `/rootly followup` (or `/rootly add action item`); manage via `/rootly action items` or the message **More actions** menu.
Follow-ups created instantly from emoji reactions skip the dialog, so their custom fields start empty—fill them in afterward by editing the follow-up from `/rootly action items` or the web UI. Fields shared with the incident are still pre-filled automatically (see below).
Slack notifications sent when a follow-up is assigned also display its custom field values (up to 10 fields) beneath the summary, so assignees get full context without leaving Slack.
## Pre-Filled from the Parent Incident
When a new action item is created, any custom field that is both **placed on the matching action item form** and **already set on the parent incident** is pre-filled with the incident's value. You can edit or clear the pre-filled value before saving. Pre-filling applies to both tasks and follow-ups, however the action item is created—web, Slack, API, or workflows.
Pre-filling is a one-time convenience, not a sync. Once the action item is saved, its field values are fully independent of the incident's—changing one never changes the other.
## Converting Between Tasks and Follow-Ups
Tasks and follow-ups can carry different custom fields, since each has its own form. When you convert an action item from one kind to the other, any field that is on the **source** form but **not** on the **destination** form is hidden—its value is **preserved, not deleted**, and reappears if you convert back. Fields present on both forms stay visible and keep their values. Rootly warns you before converting (in both web and Slack) and lists the fields that will be hidden, but only when the conversion would actually hide something.
***
## Filtering, Columns, and Reporting
**Follow-ups list.** The global Follow-ups view supports follow-up custom fields as table columns and filters:
* Use **Configure View** to add custom field columns to the table. Fields with **Display this field in the incident details** turned off are hidden from the column picker.
* Filter follow-ups by custom field values—including select, user, team, service, functionality, and catalog-backed fields.
* Custom field values are searchable, so follow-ups can be found by the values set on them.
This view lists follow-ups only; task custom fields don't appear here. Use Dashboards for reporting across tasks.
**Dashboards.** [Dashboard](/metrics/customized-dashboards) panels built on action item data can group and filter by custom field values from **both** the task and follow-up forms, letting you chart action item volume and completion by product area, business unit, or any other dimension you track.
***
## Automating with Workflows
[Action item workflows](/workflows/action-item-workflows) get full custom field support for both tasks and follow-ups:
* **Triggers** — each custom field adds a `[CustomField] Updated` trigger, so a workflow can fire the moment a field value is set or changed on an action item.
* **Conditions** — workflows can branch on an action item's custom field values (is, is not, is one of, is set, is unset, plus contains any / all / none of for multi-value fields).
* **Actions** — the **Update Action Item** action can set custom field values, including with Liquid templating (for example, populating a field from `{{ incident.severity }}`).
* **Ticketing exports** — ticketing actions (Jira, Linear, GitHub, Asana, and more) support custom field mappings, so you can write an action item's field values into the external ticket using [Liquid variables](/liquid/action-item-variables).
Example: keep a Jira ticket's *Business Unit* field in sync with the action item.
**Trigger**
* `[CustomField] Business Unit Owner Updated`
**Action**
* **Update Jira Issue**, with a custom field mapping that sets the Jira field to
`{{ action_item.custom_fields_by_slug.business-unit-owner }}`
***
## Referencing Values in Liquid
Action item custom field values are available in Liquid wherever action item variables are supported:
```liquid theme={null}
# Simplest access — by field slug (multi-value fields return an array)
{{ action_item.custom_fields_by_slug.your-field-slug }}
{{ action_item.custom_fields_by_slug.your-multi-select-slug | join: ', ' }}
```
See [Action Item Variables](/liquid/action-item-variables#custom-fields) for the full structure, including the `action_item.custom_fields` array for advanced use.
***
## API and Webhooks
The [incident action items API](/api-reference/incidentactionitems/creates-an-incident-action-item) accepts custom field values through the `form_field_selections` attribute and returns them as `custom_field_selections`:
* **Create/update** — pass a `form_field_selections` array under `data.attributes`, with each entry containing a `form_field_id` and either a `value` (text-like fields) or the relevant `selected_*_ids` (option, user, group, service, functionality, catalog entity, environment, cause, or incident type fields).
* **Read** — responses include the `custom_field_selections` relationship; use `?include=custom_field_selections` to embed full values.
* **Webhooks** — incident [webhook](/configuration/webhooks) event payloads (such as `incident.updated`) embed the incident's action items in an `action_items` array; each embedded action item includes a `custom_field_selections` array with its field values. See [Event Payloads](/configuration/event-payloads) for the payload structure.
***
## Frequently Asked Questions
Yes. Custom fields apply to both tasks and follow-ups. Place the fields you want on tasks on the **Incident Task** form under **Configuration → Forms**—it's separate from the Incident Follow Up form and starts empty, so add fields to it explicitly.
No. Shared fields are **pre-filled** from the incident when the action item is created, but after that the values are independent. This is intentional—an action item's business unit, for example, may legitimately differ from the incident's.
Yes. Each action item form (Incident Follow Up and Incident Task) has separate Web and Slack versions. That flexibility can cause confusion (an item created in Slack may show different fields when edited on web), so Rootly recommends keeping them in sync unless you have a specific reason not to.
Yes. Each field placed on a form can be required always or conditionally, based on the values of fields above it. Required rules are enforced in both the web form and Slack dialogs.
Check that: (1) the feature is enabled for your organization, (2) the fields are **enabled** under Configuration → Fields, (3) the fields are placed on the correct form (Incident Task vs. Incident Follow Up) and the correct version (Web vs. Slack), and (4) any conditional display rules on the placement are met.
API support is available today via the form field placements endpoints. Terraform provider support for placing fields on the action item forms is rolling out—check the Rootly Terraform provider docs for the latest.
***
## Related Pages
The parent concept — tasks and follow-ups these custom fields attach to.
The organization-wide custom fields system these action-item fields are part of.
Trigger workflows off custom field changes and map fields into ticket exports.
# Action Items
Source: https://docs.rootly.com/incidents/action-items/action-items
Understand how action items—including tasks and follow-ups—help teams drive effective incident response and long-term reliability improvements.
## How Action Items Work
Action items are structured pieces of work created during or after an incident. They help teams capture urgent tasks, assign ownership, track accountability, and ensure important follow-up work is completed.
Action items live alongside the incident timeline, Slack workflows, retrospectives, and analytics—providing full visibility into what was done during an incident and what still needs to be done.
This page introduces how action items work, why they matter, and where they fit into the incident lifecycle.
***
## Why Action Items Matter
During fast-moving incidents, it’s easy for important work to be forgotten. Action items help by:
* Capturing tasks needed to investigate or mitigate the issue
* Tracking follow-up work after the incident to prevent recurrence
* Assigning clear ownership so nothing is lost
* Providing structure for retrospectives and improvement planning
* Enabling automation through workflows and integrations
* Improving accountability and long-term system reliability
Common examples include:
* **Task** – “Restart service X on cluster Y.”
* **Task** – “Verify the hotfix on canary pods.”
* **Follow-up** – “Add alerting for cache saturation.”
* **Follow-up** – “Update the API runbook with new mitigation steps.”
Action items are fully customizable and can be created from the Web UI, Slack, API, Workflows, or even tied to specific Incident Roles.
***
## Types of Action Items
Action items come in two forms, each serving a different purpose in the response lifecycle.
### **Tasks — Work During the Incident**
Tasks represent operational or investigative work that helps move the incident toward mitigation or resolution.
Tasks typically include:
* **Title** (required)
* Description (Markdown supported)
* **Assignee** (user or group)
* Priority (High, Medium, Low)
* Status (Open, In Progress, Done, Cancelled)
* Optional reminder (5–180 minutes)
### **Follow-Ups — Work After the Incident**
Follow-ups help teams improve reliability after the incident is over. They are usually completed post-resolution.
Follow-ups include:
* **Title** (required)
* Description (Markdown supported)
* Priority
* **Assignee** (user or group)
* **Due date**
* Status
* **Custom fields** — organization-specific metadata like product area or business unit (see [Custom Fields on Action Items](/incidents/action-items/action-item-custom-fields))
Follow-ups are often reviewed and assigned during retrospectives, making them a critical part of continuous improvement.
***
## Where Action Items Live in Rootly
### **On the Incident Timeline (Web UI)**
Every task or follow-up appears directly on the timeline, keeping work tied to the context of the incident. Responders can:
* Create or edit items
* Assign or reassign owners
* Update status or priority
* Open linked JIRA / Linear / GitHub issues (if integrated)
### **In Slack**
If Slack is integrated, responders can create and manage action items without leaving the incident channel:
* `/rootly task`
* `/rootly followup`
* `/rootly add action item`
* `/rootly action items` (manage existing items)
Slack modals support assignment, priority, reminders, and descriptions.
### **In the Web Interface**
Each incident has an **Action Items** section where teams can:
* Filter by priority, type, or status
* Bulk-review outstanding work
* Export action items to CSV, JSON, or XML
* Manage all items across all incidents from a global dashboard
### **In Workflows**
Workflows can create tasks or follow-ups automatically based on:
* Severity
* Impacted services
* Incident type
* Sub-status changes
* Timeline events
* Role assignments
* Custom logic
Automation ensures important tasks are created consistently and early.
### **Through the API**
Developers can programmatically create or update items:
```http theme={null}
POST /api/v1/teams/:team_id/incidents/:incident_id/action_items
```
The API supports full lifecycle management, including due dates, priority, and linking external issue IDs.
***
## How Action Items Support the Response Process
Action items help orchestrate the human work that happens around incidents:
* Timeline entries show when items were created, updated, or completed
* Slack channel summaries update dynamically as items change
* Workflow triggers can depend on action item status or presence
* Retrospectives include a full list of tasks and follow-ups for review
* Analytics dashboards help track overdue items, recurrence, and team performance
* Permissions determine who can create, edit, or complete action items
When paired with roles and workflows, action items create a structured, predictable response process across teams.
***
## Where to Go Next
These pages will help you manage action items across all interfaces:
* **Add via Slack** – Create tasks or follow-ups using Slack commands
* **Add via Web Interface** – Add items directly from the incident page
* **Add via API** – Programmatically create items from external systems
* **Add via Email** – Append email-based action items when responding to incident emails
* **Custom Fields** – Capture organization-specific metadata on tasks and follow-ups
* **Incident Roles** – Automatically create action items based on role responsibilities
* **Workflows** – Generate tasks and follow-ups automatically based on incident conditions
***
## Best Practices
* **Create tasks early**\
Capture investigative work as soon as it emerges.
* **Use follow-ups for durable improvements**\
These often prevent recurrence.
* **Assign owners immediately**\
Unassigned tasks often go stale.
* **Set due dates for follow-ups**\
This increases accountability and helps with retrospective follow-through.
* **Use priorities intentionally**\
High-priority follow-ups should be reviewed in retrospectives or weekly ops meetings.
* **Automate repetitive items**\
Workflow-generated tasks ensure consistent coverage.
* **Review open follow-ups regularly**\
Keeps your reliability improvement backlog healthy.
***
## Frequently Asked Questions
No. Smaller or operationally simple incidents may not require tasks or follow-ups.
One user may own the item, but **multiple groups** can also be assigned for shared accountability.
Yes. Descriptions fully support Markdown for links, formatting, and structured notes.
Yes — both **tasks** and **follow-ups** support custom fields for organization-specific metadata like product area or business unit. Fields are configured on the Incident Task and Incident Follow Up forms and flow through workflows, exports, dashboards, and the API. See [Custom Fields on Action Items](/incidents/action-items/action-item-custom-fields).
Yes. This is one of the most powerful features of Rootly’s workflows for predictable processes.
Yes. All tasks and follow-ups associated with an incident appear in the retrospective for review.
Yes. Action items support external issue linking for teams who track work in external systems.
Tasks may be completed, and remaining work typically becomes follow-ups. Some orgs disable new task creation after resolution.
***
## Related Pages
Automatic due dates and violation tracking for follow-ups.
Organization-specific metadata for tasks and follow-ups.
Where follow-ups live after resolution — retros are the natural home for long-running work.
# Creating Action Items via Automation & API
Source: https://docs.rootly.com/incidents/action-items/adding-action-items-via-api
Automate action item creation through workflows, incident roles, and direct API integration for scalable incident response processes.
## How Automation Creates Action Items
Action items—tasks and follow-ups—can be generated automatically through **Workflows**, **Incident Roles**, or the **Rootly API**. Automation ensures teams never miss a critical task, follow-up, or improvement opportunity during or after an incident.
Automation is especially powerful for:
* Enforcing consistent response processes
* Creating tasks or follow-ups automatically based on incident conditions
* Routing work to the correct owners
* Producing reliable audit trails
* Integrating with tools such as Jira, GitHub, and Slack
Automation reduces operational overhead and ensures every incident produces actionable, trackable work.
***
## Action Items and Workflows
Workflows can both **create** and **react to** action items using a variety of triggers and conditions.
### Supported Workflow Triggers (Action Item Category)
Rootly supports the following action-item–related triggers:
* `incident_updated`
* `action_item_created`
* `action_item_updated`
* `assigned_user_updated`
* `summary_updated`
* `description_updated`
* `status_updated`
* `priority_updated`
* `due_date_updated`
* `teams_updated`
* `slack_command`
### Workflow Conditions
Workflows can filter based on:
* Action item type (Task / Follow-up)
* Status
* Priority
* Incident severity
* Visibility
* Incident kind
* Incident roles
* Other incident attributes (teams, services, etc.)
Conditions and triggers map directly to code-backed enums and workflow schemas, ensuring strict validation and predictable automation.
***
### Example: Workflow **creates** a task when the Security team is added
**Trigger**
* Teams added
**Conditions**
* Kind → Incident
* Team → is one of → Security
**Action**
* Create a task to alert the Legal team
***
### Example: Workflow **reacts to** a new action item
**Trigger**
* Action item created
**Conditions**
* Type → Task
* Priority → High
**Action**
* Create an external ticket (for example, Jira, GitHub, GitLab, Linear)
Workflow tasks are grouped by integration. Jira actions, for example, appear under the Jira task group and require the Jira integration to be enabled.
***
## Action Items and Incident Roles
Incident Roles can include predefined tasks that are automatically converted into incident action items when an incident is created.
These role-based tasks carry:
* Summary
* Priority
* Role assignment metadata
* Ordering/position
To configure:
Go to **Configuration → Roles**.
Select the role you want to add tasks to.
Open the **Tasks** tab.
Add or reorder tasks as needed.
Role-based action items give each incident a predictable starting checklist and ensure operational discipline.
Learn more about [Incident Roles](/configuration/incident-roles).
***
## Action Items and the API
The Rootly API allows programmatic creation, management, and retrieval of action items.
### Endpoints
* **List incident action items**\
[/api-reference/incidentactionitems/list-incident-action-items](/api-reference/incidentactionitems/list-incident-action-items)
* **Create an incident action item**\
[/api-reference/incidentactionitems/creates-an-incident-action-item](/api-reference/incidentactionitems/creates-an-incident-action-item)
* **Retrieve an incident action item**\
[/api-reference/incidentactionitems/retrieves-an-incident-action-item](/api-reference/incidentactionitems/retrieves-an-incident-action-item)
* **Update an incident action item**\
[/api-reference/incidentactionitems/update-an-incident-action-item](/api-reference/incidentactionitems/update-an-incident-action-item)
* **Delete an incident action item**\
[/api-reference/incidentactionitems/delete-an-incident-action-item](/api-reference/incidentactionitems/delete-an-incident-action-item)
* **List all action items for an organization**\
[/api-reference/incidentactionitems/list-all-action-items-for-an-organization](/api-reference/incidentactionitems/list-all-action-items-for-an-organization)
## Supported API Fields (Create/Update)
* `kind` (`task` or `follow_up`)
* `summary` (required)
* `description` (Markdown supported)
* `assigned_to_user_id`
* `assigned_to_group_ids`
* `priority` (`high`, `medium`, `low`)
* `status` (`open`, `in_progress`, `done`, `cancelled`)
* `due_date` (ISO 8601)
* `form_field_selections` ([custom field](/incidents/action-items/action-item-custom-fields) values — each entry takes a `form_field_id` plus a `value` or the relevant `selected_*_ids`)
* **Jira fields:**
* `jira_issue_id`
* `jira_issue_key`
* `jira_issue_url`
## Response Fields Include
* Kind, priority, status
* Due date
* Assigned user & groups
* Custom field values via the `custom_field_selections` relationship (use `?include=custom_field_selections` to embed them)
* Integration URLs:
* `jira_issue_url`
* `github_issue_url`
* `gitlab_issue_url`
* `linear_issue_url`
* `url` and `short_url`
* Timestamps and metadata
The API follows the JSON:API spec and enforces the same validations as the Web UI and Slack.
***
## Best Practices
* **Automate common tasks** to reduce manual work
* **Use role-based tasks** for consistent incident startup actions
* **Assign owners early** to prevent drift
* **Use priorities intentionally** to structure follow-up workflows
* **Integrate external systems** (Jira, GitHub, etc.) for centralized tracking
* **Review overdue follow-ups regularly** for reliability improvements
***
## Troubleshooting
Confirm the trigger conditions matched the incident and that the user/action had permission to create action items.
Ensure the role is enabled and the role tasks themselves are active. Disabled tasks are not copied over.
Make sure summary is present and enum fields (priority, status, kind) match allowed values. Check Jira fields if provided.
Some organizations disable task/follow-up creation after an incident is resolved, cancelled, or closed.
Slack notifications fire only when:
• The team has a Slack integration\
• The incident has a slack\_summary\_timestamp\
• Notifications aren’t suppressed
These notifications are not workflow-dependent.
# Creating Action Items in Slack
Source: https://docs.rootly.com/incidents/action-items/adding-action-items-via-slack
Create tasks and follow-ups in Slack using slash commands, emoji reactions, or message menus to convert incident discussions into actionable items.
## How Action Item Creation Works in Slack
Slack is where most real-time incident collaboration occurs, which makes it the perfect place to quickly capture tasks and follow-ups as they emerge. Rootly lets you turn conversations directly into structured action items so nothing is missed.
You can create action items using:
* **Slash commands**
* **Emoji reactions**
* **Slack’s More Actions message menu**
All of these features require that you are inside a **Rootly incident channel** and have permission to create or manage action items.\
For private incidents, you must also have access to the incident itself.
***
## Slash Commands
Slash commands are the fastest and most flexible way to create or update action items.
Run these commands **inside an incident channel**:
### Create New Items
**`/rootly task`**\
Creates a new task for the current incident.
**`/rootly followup`**\
Creates a new follow-up item intended for post-incident improvement work.
Slash-command creation opens a Slack modal, allowing you to set priority, assignee, description, reminders, and more before submitting. Task and follow-up modals also display any [custom fields](/incidents/action-items/action-item-custom-fields) placed on the matching Slack form (Incident Task or Incident Follow Up).
### Manage or review items
**`/rootly action`**\
Opens the action-item management menu, allowing you to:
* View all action items for the incident
* Create a new task or follow-up
* Change the status
* Assign or reassign a user or group
* Edit descriptions or details
* Delete action items
* Convert between task ↔ follow-up
**`/rootly todo`**\
Displays tasks assigned **specifically to you**, making personal follow-up easy.
The `/rootly todo` command is especially helpful for engineers rotating through on-call — it ensures no assigned work is forgotten after the incident.
***
## Emoji Reactions
Emoji reactions turn Slack messages directly into action items with minimal interruption to the conversation.
When enabled under **Configuration → Integrations → Slack**, reacting to a message triggers auto-creation:
### Task Creation
React with a ⭐️ **star emoji** to turn the message into a task.
### Follow-Up Creation
React with a 🔧 **wrench emoji** to convert the message into a follow-up.
Rootly will add a **white check mark emoji** on success.
Emoji used for tasks and follow-ups must not overlap with emojis configured for:\
**timeline events**, **incident follow-ups**, or **task creation**.\
Rootly enforces this to ensure each emoji has a single clear purpose.
***
## Slack “More Actions” Menu
You can also create action items using Slack’s built-in message menu:
Hover over any message in the incident channel.
Click **More actions** (•••).
Select **Add Action Item**.
A modal opens with the message text pre-filled as the summary.
This option is ideal when turning longer discussions, decisions, or troubleshooting notes into structured work without retyping.
***
## What Happens When an Action Item Is Created
Action items created from Slack:
* Appear immediately on the **incident timeline**
* Include the original Slack message text when created from a message
* Support Markdown formatting in descriptions
* May trigger workflows (for example, create Jira tickets, notify owners)
* Sync with retrospectives and analytics
* Can be assigned to users or groups
Some organizations restrict task creation after incidents are resolved or closed.\
Follow-ups, however, typically remain available for use in post-incident improvement.
***
## Best Practices
* **Capture tasks early**\
Adding tasks in real time prevents important work from getting lost in conversation.
* **Assign owners immediately**\
Tasks without owners are often forgotten — assignment drives accountability.
* **Use follow-ups for long-term improvements**\
These items support durable reliability gains after the incident.
* **Use priorities intentionally**\
High-priority items should be reviewed in retrospectives, weekly ops syncs, or technical leadership meetings.
* **Keep emoji intuitive**\
Choose emojis your team naturally reaches for during conversations.
* **Use `/rootly todo`**\
Helps responders keep track of what’s on their plate throughout and after the incident.
* **Automate recurring work**\
Use workflows to auto-create tasks like “Prepare retrospective document” or “Notify customer support.”
The strongest incident programs treat action items as part of a continuous improvement loop — not just a list of things to do.
***
## Troubleshooting
Check the following:
* You reacted **inside an incident channel**
* The emoji is configured in the Slack integration settings
* Emoji aren’t conflicting with other trigger types
* Emoji ingestion is enabled for your Slack workspace
This usually means:
* You don’t have permission to create or modify action items
* The incident is in a state where new tasks are restricted
* You're not inside a valid incident channel
* Confirm you created it in the **correct** incident channel
* Ensure the Slack message wasn’t deleted
* Verify the Rootly Slack app has permission to read and react to messages
Often caused by:
* Slack integration not fully installed
* You're not in an incident channel
* Your Slack role/user permissions limit access to message actions
The checkmark is Rootly’s confirmation reaction, letting you know your task or follow-up was created successfully.
This depends on your workspace settings. Some organizations disable new task creation after resolution to preserve process discipline, but follow-ups remain available.
# Creating Action Items in Web Interface
Source: https://docs.rootly.com/incidents/action-items/adding-action-items-via-web-ui
Add tasks and follow-ups to incidents through the web interface, with options for exporting to external tools and manual tracking.
## How Web-Based Action Items Work
From the incident page in the Rootly web app, you can create and manage **tasks** (work done during the incident) and **follow-ups** (work done after the incident to prevent recurrence).
Tasks and follow-ups live in dedicated tabs on the incident and are also reflected in retrospectives, exports, and integrations with external tools.
Use the web interface when you want a complete view of all action items for an incident, need richer editing controls, or want to export items to ticketing/project management tools.
***
## Creating Tasks and Follow-Ups from an Incident
Add a task or follow-up directly from the incident page.
Open the incident in the Rootly web app from your incidents list or a direct link.
Under the incident title, click either the **Tasks** tab (for work done during the incident) or the **Follow-ups** tab (for post-incident work).
Click **+ New Task** or **+ New Followup**.
A form will appear where you can enter details such as:
* **Title** (required)
* Description
* Assignee (person and/or team)
* Priority
* Status
* Due date (especially for follow-ups)
* Optional links to external systems (for example, Jira issue URL)
* Custom fields — pre-filled from the incident where fields are shared
Click **Save** to create the item.
The task or follow-up will appear in the list on the tab and be associated with the incident timeline for future reference and retrospectives.
Depending on your workspace configuration, you may see slightly different fields (for example, required teams, custom fields, or external ticket links). Your admin controls these under **Configuration**.
***
## Using Markdown in Action Item Descriptions
Action item descriptions support [Markdown](https://www.markdownguide.org/ "Markdown") so you can structure notes and instructions clearly.
You can use Markdown to:
* Add **bold** or *italic* emphasis
* Create bullet lists or numbered steps
* Insert links to dashboards, runbooks, or logs
* Highlight command snippets
Markdown makes it easier for assignees to understand exactly what needs to be done—especially for complex or multi-step work.
***
## Exporting Action Items Automatically (Smart Defaults)
With **Smart Defaults**, you can configure Rootly to automatically export tasks to external tools for tracking—so responders don’t need to create tickets manually.
These settings live under integration pages such as Jira, Asana, Motion, or Linear.
Examples:
* Automatically create a Jira issue whenever a new follow-up is created
* Push all high-priority follow-ups to Linear as issues
* Create Asana tasks for follow-ups tied to specific services
Use Smart Defaults when you want **every** action item (or a filtered subset) to end up in your external tracker without manual effort.
***
## Exporting Action Items Manually from an Incident
If you prefer more control, you can export action items manually from the **Tasks** and **Follow-ups** tabs.
Open the incident in the web app.
Go to the **Tasks** or **Follow-ups** tab.
Click the **Export to ticketing** button to send selected items to your configured tool (Jira, Linear, Asana, Trello, Zendesk, etc.).
During export, you may need to select:
* Which integration to use
* Project, board, team, or workspace
* Issue type or workflow state
* Whether to create a **subtask/sub-issue** when an incident already has a linked parent ticket
Manual export is perfect when only some action items should be tracked externally.
The **Export to ticketing** modal does not support [Liquid variables](/liquid/liquid). Anything you type into the description field is sent as literal text — `{{ incident.url }}` will not be interpolated. To enrich exported tickets with incident context (URL, severity, services, etc.), use the workflow pattern in the next section.
***
## Linking Exported Tasks Back to the Incident
When you export an action item via **Export to ticketing**, the resulting Jira (or Linear, Asana, ClickUp, etc.) ticket lands in your tracker without any incident context — no Rootly link, no severity, no service. That's a frequent gap: the assignee sees the ticket later, can't tell which incident it came from, and has to dig.
You can close the gap with a small **[Action Item Workflow](/workflows/action-item-workflows)** that enriches the ticket automatically the moment it's created. Pressing **Export to ticketing** stores the external ticket reference on the action item, which fires the `Action Item Updated` trigger — so a workflow can react in real time and write incident fields into the just-created ticket.
In Jira, add a **custom URL or text field** on the issue type used for exports — name it something like *"Source Incident"*. The custom-field path is what the Update Jira Issue action's field mapping targets and is also JQL-searchable later.
Adding entries to the Jira issue's **Links** panel (Jira "remote links" / web links) is a separate REST endpoint that the Update Jira Issue field mapping doesn't drive. If you specifically want a Links-panel entry rather than a custom field value, that's outside this walkthrough — keep the link in a custom field, or open the Jira issue manually and add a remote link.
In Rootly, go to **Workflows → Create Workflow** and pick **Action Item** as the type.
Configure:
* **Trigger:** `Action Item Updated`. This fires when **Export to ticketing** writes the external ticket reference back to the action item. It also fires on every other action-item update — see the safety guard in the Action step below.
* **Action:** add the **Update Jira Issue** action (see the [Jira Workflows](/integrations/jira/jira#workflows) reference). Use `{{ action_item.jira_issue_id }}` in the **Jira Issue to Update** field. The action requires a valid Jira issue ID — if the action item doesn't have one yet (the export hasn't happened, or another kind of update fired the trigger), the action fails cleanly rather than running against the wrong issue. Enable **Skip on Failure** on the action so unrelated updates silently no-op instead of halting the workflow.
Open the **Advanced** tab on the Update Jira Issue action. Add a [custom field mapping](/integrations/jira/jira#field-type-mappings) that sets the custom field you created in Step 1 to a [Liquid expression](/liquid/incident-variables) like `{{ incident.url }}`.
Common payloads:
| Goal | Liquid value |
| -------------------- | --------------------------------------------------------------------- |
| Just the Rootly link | `{{ incident.url }}` |
| Title plus link | `{{ incident.title }} — {{ incident.url }}` |
| Severity-aware label | `[{{ incident.severity }}] {{ incident.title }} ({{ incident.url }})` |
Save the workflow. Future Export to Ticketing presses on action items will write the incident link into the custom Jira field automatically, in addition to whatever the export modal recorded.
The same shape of pattern is available for other ticketing tools that have action-item-workflow Update actions — **Linear**, **Asana**, **ClickUp**, **Shortcut**, **Zendesk**, **GitHub**, **GitLab**, and **Trello** all expose an "Update \[Tool] Issue/Task" action that can be invoked from an Action Item Workflow. The exact field-mapping mechanism and supported field types differ per tool — open the [integration page](/integrations/overview) for the tool you use and check its workflows or functionalities reference to see the action's available fields and how custom-field mapping works for that tool, then mirror the pattern above.
***
## Best Practices
* **Create tasks early** — capture investigation steps while context is fresh.
* **Use follow-ups for long-term improvements** — reliability work, runbook updates, etc.
* **Assign owners immediately** — unassigned items go stale.
* **Set due dates** — especially for follow-ups tied to retrospectives.
* **Use Markdown for clarity** — links and structured notes help assignees move faster.
* **Export to ticketing systems when appropriate** — keep work aligned with your team’s backlog.
* **Review open follow-ups regularly** — ensures continuous improvement.
***
## Troubleshooting
Your workspace or role may have restricted access, or you may not have permission to manage action items for this incident.
Check with your Rootly admin.
Some organizations disable new action items after certain incident lifecycle stages (for example, after resolution or close).
If the creation buttons are missing, your configuration may enforce these rules.
Exporting requires at least one ticketing integration (Jira, Linear, Asana, etc.) to be configured.
Check **Configuration** → **Integrations**.
The external tool may have missing required fields or permission restrictions.
Verify:
* Project/workspace is valid
* Issue type and fields are allowed
* The integration user has permission to create tickets
# SLA Policies for Follow-Ups
Source: https://docs.rootly.com/incidents/action-items/sla-policies
Use SLA policies to set assignment and completion deadlines on follow-up action items, get notified before deadlines pass, and track violations.
## Overview
SLA policies let you define time-based expectations for follow-up action items. When a matching follow-up is created, Rootly automatically calculates its assignment and completion deadlines, sends notifications as those deadlines approach, and records a violation if the deadline is missed.
SLA policies apply exclusively to **follow-ups** — not to tasks. They are configured per team and evaluated against every follow-up that team creates.
SLA policies are managed under **Configuration → SLA Policies** in the web app.
***
## Create an SLA Policy
Go to **Configuration → SLA Policies** and click **+ New SLA Policy**.
Give the policy a clear, descriptive name. Names must be unique within your team.
Optionally add a description to explain when this policy applies or what it enforces.
The manager is the person responsible for ensuring follow-ups covered by this policy are completed on time. Choose one of:
The policy is managed by whoever holds a specific role on the incident (for example, the Incident Commander or the assigned engineer). This is the recommended option for most teams since it adapts dynamically to each incident.
A named user is always the manager, regardless of who holds any particular role on the incident.
You must set either a manager role or a specific user — not both.
Configure the two deadlines Rootly tracks for each follow-up:
How many days after a given incident status the follow-up must be assigned to someone.
How many days after a given incident status the follow-up must be completed. When a policy applies, Rootly writes this computed date into the follow-up's **Due date** field — the same field you see when creating a follow-up manually. If a policy is applied, the Due date reflects the SLA deadline rather than a manually entered value.
For each deadline, choose:
The incident status that starts the deadline clock. Options: `In Triage`, `Started`, `Mitigated`, `Resolved`, `Closed`, `Cancelled`.
1, 2, 3, 4, 5, 6, 7, 14, 21, or 30 days.
If your team uses custom lifecycle sub-statuses, you can anchor deadlines to a specific sub-status instead of a top-level status.
By default, a policy applies to every follow-up the team creates. Add conditions to scope it to a subset.
Conditions can be built on:
* **Built-in incident fields** — severity, environment, service, functionality, incident type, team, cause, status, incident role, visibility, and timestamps
* **Custom fields** — any select or multi-select custom field configured for your team
Most conditions support the operators **is one of**, **is not one of**, **is set**, and **is not set**. Timestamp fields (such as `started_at` or `resolved_at`) only support **is set** and **is not set**, since specific datetime values cannot be selected from a list.
Use the **Match** toggle to control whether the policy triggers when **Any** condition matches or when **All** conditions match.
A policy can have up to 20 conditions.
Add up to 5 notification rules that control when the policy's manager is notified about upcoming or overdue deadlines. Notifications are sent to the manager only — either the user in the configured incident role or the specific user assigned to the policy.
Each rule fires independently for **both** the assignment deadline and the completion deadline. For example, a "1 day before due" rule will send one notification before the assignment deadline and another before the completion deadline.
Send a notification X days before the deadline. Requires a minimum deadline of at least 2 days.
Send a notification on the day the deadline falls.
Send a notification X days after the deadline has passed (1–99 days). Use this to escalate violations that have not been resolved.
Click **Save**. The policy will immediately start applying to new follow-ups that match its conditions. Existing follow-ups are not retroactively affected.
***
## How Deadlines Are Calculated
When a follow-up is created, Rootly scans all active SLA policies for the team and applies the first matching policy. The deadline clock starts when the incident reaches the configured trigger status.
For example, if a policy sets a **7-day completion deadline from Resolved** and the incident resolves on Tuesday the 1st, the follow-up completion deadline is Tuesday the 8th.
Deadlines are calculated once when the trigger status is reached. If the incident moves back through statuses (for example, from Resolved back to Started), the deadline is not recalculated.
***
## Violations
A **violation** is recorded when a deadline passes without the required action being taken. Rootly tracks two violation types:
* **Assignment overdue** — the follow-up had no assignee when the assignment deadline passed
* **Completion overdue** — the follow-up was not marked done when the completion deadline passed
Violations remain open until the follow-up is assigned or completed. Once resolved, the violation is marked as resolved with a timestamp.
You can view open violations and historical SLA data on the SLA Policies page under **Configuration**.
***
## Best Practices
* **Set completion deadlines relative to Resolved** for most follow-ups — this aligns accountability with the natural end of the incident lifecycle.
* **Use assignment deadlines** to catch follow-ups that get created but never picked up, especially across team handoffs.
* **Use conditions to differentiate by severity** — a P1 incident may warrant a 2-day completion SLA while a P3 can tolerate 14 days.
* **Add a before-due notification** so managers have time to act, not just receive a violation notice after the fact.
* **Keep policies simple** — one or two policies per team covering the most common cases is easier to maintain than a complex matrix.
***
## Frequently Asked Questions
Only follow-ups. Tasks are intended for work done during an incident and do not have SLA enforcement.
The first matching policy (in the order they appear in the SLA Policies list) is applied. Only one policy is applied per follow-up.
No. SLA policies are evaluated at follow-up creation time. Existing follow-ups are not affected when a new policy is created or an existing one is updated.
Notifications are sent only to the policy's configured manager — either the user currently holding the specified incident role on the incident, or the specific user assigned to the policy. No other users are notified.
Yes. Create separate SLA policies with conditions scoped to each severity level, each with different deadline values.
In Triage, Started, Mitigated, Resolved, Closed, and Cancelled. If your team uses custom sub-statuses, you can also anchor to a specific sub-status.
***
## Related Pages
The parent concept — SLA policies apply to follow-ups.
Automate reminders, ticket creation, and reassignment when SLA milestones are hit.
Where follow-ups typically get planned and tracked over time.
# Converting Existing Slack Channels to Incidents
Source: https://docs.rootly.com/incidents/creating-incidents/converting-existing-slack-channels-to-incidents
A step-by-step guide to converting an existing Slack channel into a Rootly incident channel without losing message history, members, or context.
## Overview
If your team begins investigating an issue in Slack before formally declaring an incident, you can convert that existing conversation into a Rootly incident channel.\
This ensures:
* No message history is lost
* All responders stay in the same channel
* Automated timelines, workflows, and notifications still run
* The incident is created with full context from the existing discussion
The `/incident convert` command transforms any standard Slack channel into a full Rootly incident channel.
***
## Convert an Existing Slack Channel
In the Slack channel you want to convert, type:
```text theme={null}
/incident convert
```
Then press **Enter**.
This opens the **Convert to Incident** modal.
You must run the command inside the channel you want to convert — it cannot be used from other channels or DMs.
The modal includes the same configurable fields you see when creating a new incident:
* **Title**
* **Summary**
* **Severity**
* **Incident Type**
* **Private Incident (optional)**
* Any custom fields your workspace has configured
***
## What Happens After Conversion
Once submitted, Rootly will:
* Create a new incident in the Rootly platform
* Link the Slack channel to the incident
* Preserve **all** prior messages in the channel
* Generate initial timeline entries
* Trigger any incident-creation workflows
* Assign default roles or responders (if configured)
* Enable Slack commands such as `/rootly status`, `/rootly resolve`, etc.
From here, the channel behaves like any other incident channel created through Slack or the Web UI.
Conversion never deletes or archives the channel — all previous activity remains intact.
***
## When to Use Conversion
Use `/incident convert` when:
* Responders start troubleshooting informally in Slack
* An issue escalates from a conversation into a true incident
* You want to preserve all investigative context without creating a new channel
* You want workflows, timelines, and notifications to begin after discussion has already started
***
## Troubleshooting
Ensure:
* You ran `/incident convert` **inside the Slack channel** to be converted
* The Rootly Slack app has permission to access that channel
* You are a user with permission to create incidents
Your workspace may enforce creation requirements.\
Open **Configuration → Forms** to confirm what fields must be included.
Confirm Slack channel conversions are enabled in your Rootly Slack Integration settings.
***
## Best Practices
* Convert as soon as a conversation becomes operational or time-sensitive
* Provide a clear incident title and summary to help responders ramp quickly
* Use severity to trigger correct workflows and escalation
* Avoid converting channels that contain unrelated historical content
* Use private incidents when the discussion involves sensitive data
# Creating Incidents via API
Source: https://docs.rootly.com/incidents/creating-incidents/creating-incidents-via-api
Create incidents programmatically using the Rootly API with supported fields, custom fields, sub-incidents, severity levels, and error handling.
## Overview
The Rootly API allows you to create incidents automatically from monitoring tools, CI/CD pipelines, internal services, or any external automation system. This is the preferred method when you need:
* Deterministic and repeatable incident creation
* Automated declarations from alerting or detection systems
* Consistent metadata applied across incidents
* The ability to create sub-incidents within orchestrated workflows
* Fully headless incident creation with no human intervention
API-based creation ensures incidents follow the same lifecycle rules, validations, and workflows as incidents created through Slack or the Web UI.
More details are available in the [API documentation](/api-reference/overview).
***
## Before You Begin
Before creating incidents via API, ensure you have:
* **A Rootly API token** with permissions to create incidents
* Knowledge of any **required fields** (severity, type, environments, etc.)
* IDs for any contextual fields you intend to populate:
* Services
* Functionalities
* Environments
* Groups
* Incident types
* Custom form fields
* The **Create Incident** endpoint reference:
`POST /api/v1/incidents`
To avoid validation failures, review which fields are required under **Configuration → Forms** and **Configuration → Required Fields.**
***
## Creating an Incident via API
Requests must include:
```http theme={null}
POST /api/v1/incidents
Authorization: Bearer
Content-Type: application/json
```
Any HTTP client or automation system (Python, curl, Terraform, GitHub Actions, etc.) will work.
Below are the commonly used fields.
**Core fields**
* `title`
* `summary`
* `severity_id`
* `incident_type_ids`
* `private` (boolean)
* `notify_emails` (array — used by workflows, not auto-emailed by default)
**Contextual fields**
* `service_ids`
* `functionality_ids`
* `environment_ids`
* `group_ids`
**Custom form fields**
Use `form_field_selections` to populate custom data.
Supports all field types: text, dropdowns, multi-select, relations, user selectors, catalog entities, etc.
**Optional advanced fields**
* `parent_incident_id` — creates a **sub-incident**
* `create_test_incident` — only works if the **Test Incidents** feature is enabled
* `mitigation_message`, `resolution_message`, `cancellation_message`
* Lifecycle timestamps (advanced):
* `in_triage_at`, `started_at`, `mitigated_at`, `resolved_at`, `closed_at`
To create sub-incidents programmatically, provide `parent_incident_id`. Rootly automatically links the child to the parent.
A successful response includes:
* The incident ID
* Lifecycle status
* Timestamps
* A URL to open the incident in the web app
* Slack channel details (if Slack is integrated + auto-create enabled)
You can use these details to perform follow-up actions like:
* Posting timeline entries
* Updating lifecycle status
* Attaching alerts
* Triggering or monitoring workflows
***
## Example Request Payloads
### Basic Example
```json theme={null}
{
"title": "API-declared service outage",
"summary": "Automated alert from internal monitoring.",
"severity_id": 1,
"incident_type_ids": [3],
"private": false
}
```
### With Custom Fields
```json theme={null}
{
"title": "Database latency above threshold",
"summary": "DB p95 latency exceeded SLO for 10 minutes.",
"severity_id": 0,
"service_ids": [12],
"environment_ids": [4],
"form_field_selections": [
{
"form_field_id": 45,
"value": "us-east-1"
},
{
"form_field_id": 46,
"selected_option_ids": [102]
}
]
}
```
### Creating a Sub-Incident
```json theme={null}
{
"title": "Sub-incident: Cache layer investigation",
"summary": "Investigating cache cluster behavior.",
"severity_id": 2,
"parent_incident_id": 1234,
"service_ids": [18]
}
```
***
## Validation & Error Handling
Rootly returns standard error responses for debugging and automation safety.
### 401 Unauthorized
```json theme={null}
{
"error": "unauthorized",
"message": "Invalid or missing API token."
}
```
### 403 Forbidden
```json theme={null}
{
"error": "forbidden",
"message": "You do not have permission to create incidents."
}
```
### 422 Validation Errors
```json theme={null}
{
"error": "unprocessable_entity",
"message": "Validation failed.",
"details": {
"severity_id": ["can't be blank"],
"title": ["can't be blank"]
}
}
```
### Idempotency (Recommended)
To prevent duplicate incidents during retries:
```text theme={null}
Idempotency-Key:
```
***
## Troubleshooting
Ensure required fields in **Forms** or **Required Fields** are included.
Check that workflow conditions (severity, type, service, etc.) match the payload.
Verify:
* Slack is connected
* Auto-create channels is enabled
* Incident is not private (depending on settings)
Make sure `parent_incident_id` is passed correctly.
***
## Best Practices
* Pre-fill key metadata to streamline response
* Use structured fields (services, environments, types) for better analytics
* Use private incidents for security-sensitive or customer-specific events
* Follow consistent naming conventions across automated incidents
* Use idempotency keys to prevent duplication
* Automate creation of sub-incidents for multi-team or multi-domain issues
* Avoid manually setting lifecycle timestamps unless necessary
# Creating Incidents via PagerDuty Integration
Source: https://docs.rootly.com/incidents/creating-incidents/creating-incidents-via-pagerduty
Create Rootly incidents from PagerDuty alerts with automatic service mapping, resolution sync, severity translation, and troubleshooting tips.
## Overview
Rootly can ingest alerts from PagerDuty to power a complete, end-to-end incident lifecycle. PagerDuty remains responsible for **alerting and escalation**, while Rootly handles **incident coordination, communication, workflows, timelines, and retrospectives**.
Use this integration when:
* Your alerts originate in PagerDuty
* You want Rootly to manage the lifecycle, collaboration, and post-incident processes
* You need Slack channels, workflows, automations, and retrospectives built off PD alerts
Rootly supports:
* Ingesting alerts directly from PagerDuty
* Creating Rootly incidents from PagerDuty alerts
* Linking Rootly incidents to PagerDuty incidents
* Syncing resolution back to PagerDuty when the Rootly incident is resolved
Resolving an incident in Rootly automatically resolves the linked PagerDuty incident and all associated PagerDuty alerts.
Resolving directly in PagerDuty does *not* resolve the corresponding Rootly incident.
***
## Before You Begin
Before creating incidents from PagerDuty, ensure:
* You have installed and authorized the Rootly ↔ PagerDuty integration
* Your PagerDuty services are mapped to Rootly services
* On-call coverage exists for the PagerDuty service (PagerDuty won’t trigger incidents without coverage)
* Your Rootly team is ready to ingest alerts under **Configuration → Alerts**
Correct service mapping (via `pagerduty_id`) ensures alerts land in the right Rootly service. If mapping is missing or incorrect, incidents may not route as expected.
***
## Creating an Incident from PagerDuty
You can use any method you normally use in PagerDuty:
**Option 1 — Create an incident manually**
1. Open PagerDuty and navigate to the New Incident flow by selecting the **New Incident** button from the top navigation.
2. In the Create New Incident dialog, select the **Impacted Service**, which should be one of the services you integrated earlier with Rootly. Add a descriptive Title, and fill in any other fields as needed.
3. Click *Create Incident*. PagerDuty will create the incident and redirect you to its detail page, where you can view the incident’s status, responders, and associated alerts.
After creating the incident in PagerDuty, log in to Rootly and navigate to:
**Configuration → Alerts**
Here, you’ll see:
* All incoming alerts ingested from PagerDuty
* Alerts routed to the Rootly services you previously mapped
* A clear option to create a Rootly incident from any alert
This view is your starting point for turning PagerDuty alerts into fully managed Rootly incidents.
Locate the PagerDuty alert you want to escalate and click:
**Create Incident**
This opens Rootly’s standard incident creation workflow, where you can:
* Set severity
* Provide an incident summary
* Choose the incident type
* Mark the incident as private (if needed)
* Trigger any relevant workflows
When you submit the form, Rootly will:
* Create the new incident
* Generate initial timeline entries
* Create and link a Slack incident channel (if configured)
* Run any incident-creation workflows you have enabled
* Attach and link the Rootly incident to the originating PagerDuty alert
Once created, the Rootly incident becomes the **source of truth** for lifecycle status, workflows, communication, timelines, and retrospectives.
***
## How Resolution Works
Resolution behavior between Rootly and PagerDuty is intentionally **one-directional**. This ensures that Rootly remains the authoritative system for lifecycle status, workflows, timelines, and retrospectives.
### Rootly → PagerDuty (Supported)
Resolving the incident in Rootly will:
* Mark the linked PagerDuty incident as **Resolved**
* Resolve all associated PagerDuty alerts linked to that incident
### PagerDuty → Rootly (Not Supported)
Resolving the incident directly in PagerDuty will **not** update or resolve the corresponding incident in Rootly.
This directional behavior ensures:
* Rootly timelines remain accurate and complete
* Required fields and lifecycle rules are enforced
* Retrospective and follow-up processes function properly
Always resolve incidents in Rootly to maintain consistent lifecycle data, ensure workflows run correctly, and preserve accurate analytics.
***
## Additional Details & Behaviors
### Service Mapping
PagerDuty alerts are routed into Rootly based on the `pagerduty_id` configured on each Rootly Service (and sometimes Teams).
Correct mapping ensures:
* Alerts appear under the correct Rootly service
* Workflows trigger for the right teams
* Rootly knows which PagerDuty incidents to update upon resolution
If you recently migrated or reorganized services, re-run the Rootly PagerDuty import to refresh all mappings.
### On-Call Requirements (PagerDuty Behavior)
PagerDuty only triggers incidents if **someone is on call** for the escalation policy tied to that service.
If a PagerDuty alert appears in Rootly but PD did not create an incident, verify that the correct on-call schedule was in place.
### Temporary Migration Flags (Advanced)
For complex migrations, Rootly can temporarily allow overlapping PagerDuty IDs using:
* `disable_service_pagerduty_id_unique_validation`
* `disable_group_pagerduty_id_unique_validation`
These are advanced, temporary options—duplicate IDs can cause ambiguous routing.
***
## Troubleshooting
Rootly does not auto-create incidents from PD alerts unless you configure an Alert Workflow.\
To proceed:
* Click **Create Incident** manually, or
* Enable an Alert Workflow to auto-create incidents for selected conditions
Check that the Rootly incident is linked to a mapped PD service.\
Resolution syncing only works when a valid mapping exists.
Verify and correct the `pagerduty_id` mapping under:
**Services → Edit Service**
Your workspace may have temporarily disabled unique ID validation.\
Re-enable uniqueness once the transition is complete.
***
## Best Practices
* Treat Rootly as the **source of truth** for lifecycle, communication, timelines, and analytics
* Use PagerDuty for **alerting and escalation only**
* Keep service mapping clean and up to date
* Automate incident creation via Alert Workflows for critical services
* Always resolve incidents in Rootly
* Avoid resolving directly from PagerDuty unless the alert is non-critical or PD-local
# Creating Incidents via Slack Interface
Source: https://docs.rootly.com/incidents/creating-incidents/creating-incidents-via-slack
Create incidents from Slack using slash commands or message actions with customizable fields, validation, severity, and channel auto-creation.
## Overview
Slack is one of the fastest and most natural places to declare an incident. Whether a responder notices an issue in conversation, spots a customer report, or sees a monitoring message posted into a channel, Rootly’s Slack integration lets you create an incident instantly — directly from where your team already works.
Use Slack when you need **speed**, **context**, and **collaboration without switching tools**.
Slack-based creation supports:
* Customizable incident fields
* Required-field validation
* Private incident creation
* Automated Slack channel creation
* Full integration with workflows and lifecycle updates
Need help installing the Rootly Slack app? See the **Slack Integration Guide**.
***
## Create a New Incident in Slack
**Method 1 — Use a Slash Command**
1. Type:
```text theme={null}
/rootly new
```
in any Slack channel.
2. Press **Enter** to open the New Incident form.
This is the fastest way to start a new incident manually.
**Method 2 — Create an Incident From a Slack Message**
Use this when the trigger is a message, alert, screenshot, or customer report already posted in Slack.
1. Hover over the message
2. Click **More actions** (three dots)
3. Select **Create an incident**
The New Incident form will open **pre-filled with a link to the original message**, giving responders immediate context.
Message-based creation provides the clearest starting point for responders and is ideal for customer complaints, noisy alerts, or discussions that evolve into incidents.
The New Incident form appears as a Slack modal and includes the essential fields needed to start coordinated response.
Most fields are customizable in **Configuration → Forms**.
**Default Fields**
| Field | Description |
| :------------------ | :------------------------------------------------------------------- |
| **Title** | Title of the incident; also used to name the Slack incident channel. |
| **Summary** | A concise description of the issue. |
| **Severity** | Default levels SEV3 → SEV0. |
| **Type** | Default categories: Cloud, Security, Customer-Facing, Default. |
| **Mark as Private** | Restricts visibility to permitted users. |
**Additional Notes**
* Required fields are marked with a **\***
* Leaving **Title** blank triggers the **Automatic Incident Title Generator**
* Only privileged users can create or access **Private** incidents
* Private mode is ideal for sensitive or security-related issues
If your team uses **Mark as In Triage**, selecting it will start the incident in **Triage** instead of **Started**. See *Incident Lifecycle* for details.
Click **Create**.
Rootly will immediately:
* Create a **dedicated Slack incident channel**
* Post the initial system message
* Log the creation event in the Timeline
* Trigger any configured workflows
* Role assignment
* Stakeholder notifications
* Ticket creation
* Checklists
* Channel topic updates
Most teams automate channel setup, role assignments, and initial communication, so responders can focus on investigation — not coordination.
***
## After the Incident Is Created
The Slack incident channel becomes your command center. From here you can:
* Update lifecycle status with `/rootly status`
* Resolve or cancel with `/rootly resolve` or `/rootly cancel`
* Add timeline events
* Modify fields using `/rootly edit`
* Run workflows using `/rootly workflow`
* Generate an AI summary using `/rootly summary`
* Invite responders and collaborate in real time
All changes sync automatically with the Rootly Web UI and appear in the Timeline.
***
## Customizing the Slack Incident Form
Your Slack form can be fully tailored to match your Web UI form.
**To customize:**
1. Go to **Configuration → Forms**
2. Under **Default Forms**, click **Configure** on *New Incident*
3. Select the **Slack** tab
4. (Optional) Click **Copy fields from Web form**
The editor shows:
* Left side → the form structure
* Right side → real-time preview
**You can customize:**
* Field order
* Field visibility
* Required fields
* Custom field types (dropdowns, multi-selects, relations, etc.)
**Controls:**
* Drag handle → reorder
* Pencil icon → edit
* Minus icon → remove
* **Add Fields** → add new fields
Changes save automatically.
Rootly recommends keeping Slack and Web forms aligned. This ensures responders have a consistent experience no matter where incidents originate.
***
## Troubleshooting
Make sure you’re inside a **Rootly incident channel**, not a normal channel.
You need the correct permissions (owner/admin/private-incident access).
Your workspace likely uses **sub-statuses**, which disable the mitigate command.\
Use `/rootly status` instead.
Your workspace may enforce:
* Required fields
* Conditional fields
* Required lifecycle metadata
Check for missing fields marked with **\***.
Check:
* Slack integration is connected
* Auto-create channels is enabled
* Private incident behavior matches workspace rules
***
## Best Practices
* Prefer **message-based creation** for rich context
* Keep fields minimal but meaningful
* Use Private mode for sensitive incidents
* Train responders to use `/rootly status` for lifecycle updates
* Align Slack + Web forms for consistency
* Automate repetitive tasks (channel setup, assignments, notifications)
High-quality incident creation through Slack accelerates response, reduces confusion, and keeps everyone aligned from the very first minute.
# Creating Incidents via Web Interface
Source: https://docs.rootly.com/incidents/creating-incidents/creating-incidents-via-web-ui
Create incidents through the Rootly web interface with customizable form fields, severity selection, validation rules, and post-creation automation triggers.
## Overview
The Rootly web interface provides the most complete and structured way to create an incident. It supports rich field configuration, required-field validation, access controls, and the full power of automations and workflows.
Use the web interface when you need clarity, accuracy, and full control over the incident creation experience.
The Web UI is the most reliable way to create high-quality incidents. It enforces all required fields, validations, and permissions set by your workspace.
***
## Create a New Incident in the Web App
You can initiate a new incident from several locations:
* **Dashboard → Create Incident** (top-right)
* **Incidents → Create Incident** (top-right)
* **Global Action Menu → Create Incident** (bottom-left)
This opens the full New Incident form.
The New Incident form captures all core information needed to begin coordinated response and trigger automation.
Most fields are customizable under **Configuration → Forms**.
**Default fields include:**
| Field | Description |
| :------------------ | :------------------------------------------------------------------ |
| **Title** | Name of the incident; also used to generate the Slack channel name. |
| **Summary** | Short description of what’s happening. |
| **Severity** | Defaults from SEV3 → SEV0. |
| **Type** | Defaults: Cloud, Security, Customer-Facing, Default. |
| **Mark as Private** | Restricts visibility to permitted users. |
**Additional Notes**
* Required fields are marked with a **\***
* Leaving **Title** blank activates the **Automatic Incident Title Generator**
* Only owners, admins, or privileged users can create/view private incidents
* Private incidents are recommended for security-, privacy-, or customer-sensitive issues
If your team uses **Mark as In Triage**, selecting this checkbox starts the incident in **Triage** instead of **Started**. See the *Incident Lifecycle* page for details on how these statuses differ.
Your workspace may enforce:
* Required fields on incident **creation**
* Required fields for **specific lifecycle transitions**
* Required fields based on **severity**, **incident type**, or **team**
If you miss a required field, the Web UI will block submission and highlight the missing values.
Completing required metadata during creation prevents blockers later when moving the incident from Started → Mitigated → Resolved.
Depending on how your team configures the form, you may see optional sections such as:
* Services
* Functionalities
* Environments
* Groups
* Incident Types
* Labels
* Notify Emails
* Custom form fields
* Test Incident checkbox (if enabled)
Adding contextual metadata improves:
* Automated routing
* Workflow execution
* Analytics and dashboards
* Retrospective quality
Click **Create Incident**.
Upon creation, Rootly will automatically:
* Create the incident record
* Capture lifecycle timestamps (for example, started\_at)
* Trigger your incident-creation workflows
* Create a Slack incident channel (if enabled)
* Assign default responders or roles
* Add initial timeline entries
* Redirect you to the newly created incident page
Most teams automate channel creation, role assignment, and stakeholder notifications to reduce manual overhead and speed up initial response.
***
## After the Incident Is Created
Once the incident is open, you can:
* Update lifecycle status (Triage → Started → Mitigated → Resolved → Closed)
* Assign roles and add responders
* Add timeline entries
* Attach or review alerts
* Trigger or monitor workflows
* Publish stakeholder updates
* Track action items and tasks
* Join the Slack channel associated with the incident
All changes are tracked automatically and appear in the Timeline for retrospective analysis.
***
## Customizing the New Incident Form
Navigate to:
**Configuration → Forms → New Incident → Configure**
Then select the **Web** tab.
You can optionally copy the structure from the Slack form using:
**Copy fields from Slack form**
* Left panel: current form structure
* Right panel: real-time preview
You can customize:
* Field order
* Field visibility
* Required fields
* Custom field types (dropdowns, multi-selects, relations, etc.)
Use:
* **Drag handle (six dots)** → reorder fields
* **Pencil icon** → edit a field
* **Minus icon** → remove a field
* **Add Fields** → add new fields
Changes save automatically.
Rootly recommends keeping Slack and Web forms aligned so responders have a consistent experience regardless of where incidents are created.
***
## Troubleshooting
Check for:
* Missing required fields
* Missing permissions
* Private incident restrictions
Confirm that workflow conditions match:
* Severity
* Type
* Services
* Environments
* Groups
Required-fields enforcement or conditional visibility rules may be preventing submission.
Verify:
* Slack integration is enabled
* Auto-channel creation is turned on
* The incident wasn’t created as private (depending on workspace rules)
***
## Best Practices
* Use structured fields (Severity, Services, Environments) for clarity & analytics
* Keep required fields minimal but meaningful
* Use Private mode for security or privacy-sensitive incidents
* Align Slack and Web forms for consistency
* Automate repetitive creation steps with workflows
* Provide descriptive titles and actionable summaries
High-quality incident creation dramatically accelerates response and improves clarity for everyone involved.
# Incident Title Generator
Source: https://docs.rootly.com/incidents/creating-incidents/incident-title-generator
Learn how Rootly automatically generates unique incident titles using random adjective–noun combinations while allowing full customization and manual editing.
## How the Incident Title Generator Works
Rootly can automatically generate a unique title for an incident when you leave the **Title** field blank. The generator creates a memorable two-word phrase by combining:
* An adjective
* A noun
Both words come from your organization’s **configurable word banks**.
This ensures that every incident—manual or automated—has a distinct title, even if responders forget to provide one. Users may edit the title at any time during the incident lifecycle.
If a user does not enter a title, Rootly automatically assigns one using the team’s configured adjective and noun lists.
***
## Title Generation Logic
When Rootly generates a title:
1. It collects adjectives and nouns used in incident titles **within the last year**.
2. These recently used words are added to an exclusion list to reduce repeats.
3. Rootly selects a random adjective and noun from your team’s configured word banks.
4. The result is **titleized** (for example, `"sleepy server"` → `"Sleepy Server"`).
5. The incident is marked with `title_autogenerated = true`.
This logic applies to:
* Incidents created in the Web UI
* Incidents created via Slack
* Incidents created via the API
API-created incidents also auto-generate titles if the payload omits the `title`.\
The API response includes `title_autogenerated` so automation can detect system-generated titles.
***
## Configuring the Word Banks
Admins may customize the adjective and noun lists used for generation.
You can update these from:
**Organization Settings → Show Advanced Settings → Incident Title Generator**
Configuration options include:
List of allowed adjectives.
List of allowed nouns.
Exclusion logic is automatic (based on 1 year of past incidents).
Customizing your word banks allows incident names to better reflect your organization’s culture, domains, and terminology.
***
## Optional: AI-Generated Titles
With [Rootly AI](/ai/ai-settings) opted in, responders can replace a generated title with an AI-written one: run `/rootly update` in the incident channel and click **Generate with AI**. Rootly AI reads the incident's summary, alerts, and early timeline to produce the title. See [AI Summaries](/ai/ai-summaries#generated-titles).
***
## Titles in External Integrations
When exporting incidents to tools like PagerDuty or Opsgenie:
* If the title was auto-generated, Rootly may prefer using the **summary** as the outbound title.
* Rootly prepends the **severity** to outbound titles when appropriate.
Example:
\[SEV2] Database Latency Degradation
This ensures external systems receive clear, actionable titles.
***
## Best Practices
* **Let Rootly auto-generate titles** when responders are busy—clean-up can happen later.
* **Customize your adjective/noun lists** to improve clarity and team culture.
* **Use AI generation** for complex or ambiguous incidents.
* **Edit titles manually** once the incident scope is understood.
* **Avoid relying solely on the title** for operational details—pair it with a strong summary.
***
## Frequently Asked Questions
Yes. Titles can be edited at any point during the incident lifecycle.
Rootly excludes adjectives and nouns used in the past year to reduce duplication.
Yes. If `title` is omitted, Rootly generates one automatically and marks it as auto-generated (`title_autogenerated: true`).
Not currently. Titles always follow the adjective + noun format unless manually edited or overwritten by AI.
External integrations may use the summary instead when the title is autogenerated. Severity may also be prefixed automatically.
***
## Related Pages
Where auto-generated titles fit in the incident creation flow.
The umbrella page covering how incidents work end-to-end.
Regenerate or override titles later in the incident lifecycle via workflow actions.
# Incident Lifecycle
Source: https://docs.rootly.com/incidents/incident-lifecycle
How Rootly models an incident from triage through closure — every status, the timestamps each one records, and how transitions actually happen.
Every incident in Rootly moves through a sequence of **statuses** that mirror how teams actually respond: contain uncertainty, coordinate a response, contain impact, fix the underlying issue, and wrap up the follow-up work. Each transition records a timestamp, which powers MTTx analytics, retrospectives, and workflow automation.
## Overview
Rootly's incident status model has six primary statuses and two optional timestamps. A status change is made from the web UI, from Slack (`/rootly mitigate`, `/rootly resolve`, `/rootly cancel`), or via workflow automation — and Rootly records the corresponding timestamp automatically.
| Status | Data Value | Timestamp | Notes |
| :-------- | :---------- | :------------- | :--------------------------------------------------- |
| Triage | `in_triage` | `in_triage_at` | Only recorded if the incident actually enters Triage |
| Started | `started` | `started_at` | Set when coordinated response begins |
| Mitigated | `mitigated` | `mitigated_at` | Impact contained; work continues |
| Resolved | `resolved` | `resolved_at` | Underlying issue fixed |
| Closed | `closed` | `closed_at` | All follow-up work complete |
| Cancelled | `cancelled` | `cancelled_at` | False positive or duplicate; Triage-only |
Two additional timestamps — `detected_at` and `acknowledged_at` — are separate fields, not statuses. They power MTTD and MTTA metrics without changing the incident's primary status.
***
## Triage
Incidents often begin with ambiguous signals. **Triage** is designed for the early moment when something *might* be wrong, but responders aren't yet certain. Notifications are limited so teams can investigate without alarming broader stakeholders.
**Enter Triage by:**
* Selecting **Mark as In Triage** when creating the incident
* Updating the status from the incident page or `/rootly status` in Slack
Triage contains scope of impact. Use it when the signal is real but unconfirmed — you can always promote to Started once you're sure.
***
## Started
Once responders confirm the issue is real, the incident moves to **Started**. This is the point of coordinated response: roles get assigned, communication channels open, and early hypotheses form.
**Enter Started by:**
* Leaving **Mark as In Triage** *unchecked* at creation — Rootly sets Started directly
* Moving from Triage → Started from the incident page or Slack
Skipping Triage during creation is common for confirmed incidents. Rootly sets the incident straight to Started with no intermediate Triage timestamp.
***
## Mitigated
**Mitigated** means the immediate impact has been contained. Users may still be affected, but the incident is no longer actively getting worse. This is common when a failover, temporary fix, or emergency control has been applied while the underlying issue is still being investigated.
**Enter Mitigated by:**
* Clicking **Mitigate** on the incident page
* Running `/rootly mitigate` in Slack
If an incident moves straight to Resolved without passing through Mitigated, Rootly sets `mitigated_at` equal to `resolved_at` so time-to-mitigate analytics stay accurate.
***
## Resolved
An incident is **Resolved** when the underlying issue has been fixed and service impact is no longer present. This is the moment that typically triggers stakeholder updates and kicks off the retrospective process.
**Enter Resolved by:**
* Clicking **Resolve** on the incident page
* Running `/rootly resolve` in Slack
Many teams configure a workflow to automatically generate a retrospective when an incident reaches Resolved. See [Configuring Templates](/retrospectives/configuring-templates).
***
## Closed
**Resolved** means the system is fixed. **Closed** means all follow-up work is complete — retrospectives published, action items verified, and communications wrapped up.
Closed is optional but recommended: it separates technical completion from process completion, so dashboards can distinguish "fixed" from "fully done".
Closed status is controlled per-team via **Configuration → Teams → Enable Closed Status**. When disabled, incidents transition directly from Resolved to their final state without a separate Closed step.
***
## Cancelled
A **Cancelled** incident is a false positive or a duplicate. Cancelling prevents wasted responder effort and keeps analytics clean by excluding non-actionable events from your incident metrics.
**Enter Cancelled by:**
* Clicking **Cancel Incident** on the incident page
* Running `/rootly cancel` in Slack
Cancel is only available while the incident is in Triage. Once an incident is Started, it must go through the normal Resolved path — even if it turns out to be non-impactful.
***
## Optional Timestamps
Two timestamps sit alongside the primary statuses to support detection and acknowledgement metrics:
When the issue was first *noticed* — often earlier than when response formally began. Powers MTTD (Mean Time To Detect).
When a specific responder took ownership of the incident. Pauses paging escalations and clarifies responsibility. Powers MTTA (Mean Time To Acknowledge).
Neither field changes the incident's primary status. Both can be set from the incident page, updated via API, or backfilled with **Update Timestamps** — see [Updating Incident Timestamps](/incidents/managing-incidents/updating-incident-timestamps).
***
## Planned Maintenance
Rootly models scheduled operational work with its own lifecycle values, distinct from unplanned incidents:
| Status | Data Value | What It Means |
| :---------- | :------------ | :------------------------------------------------------------------ |
| Planning | `planning` | Scope and impact being defined |
| Scheduled | `scheduled` | Approved for a specific window (`scheduled_for`, `scheduled_until`) |
| In Progress | `in_progress` | Work is underway |
| Completed | `completed` | Work is finished |
| Verifying | `verifying` | Final checks in progress |
Planned maintenance uses the same automation, timeline, and retrospective machinery as normal incidents. See [Scheduling a Maintenance Incident](/incidents/incident-operations/scheduling-a-maintenance-incident).
***
## Incident Timeline
Every incident has a **Timeline** that captures status changes, role assignments, workflow actions, Slack updates, alert events, and manual entries in one chronological view. It's the source of truth for retrospectives and stakeholder recaps.
Timeline entries can be added from Slack, the web UI, email-to-incident, or automations. See [Incident Timeline](/incidents/incident-timeline/incident-timeline).
***
## Troubleshooting
Cancel is only available while the incident is in Triage. If the incident has already moved to Started, resolve it as normal — cancellation isn't possible from later stages.
If the incident went straight from Started to Resolved without a Mitigate action, Rootly sets `mitigated_at` equal to `resolved_at`. To backfill a true mitigation timestamp, use **Update Timestamps** on the incident page.
Closed is controlled per-team. Ask an admin to check **Configuration → Teams → Enable Closed Status**. When disabled, incidents finalize at Resolved.
Common causes:
* The incident is already Resolved, Closed, or Cancelled — check the channel header before running the command.
* Your team has **Sub-Statuses** enabled, which disables `/rootly mitigate` by design. Use `/rootly status` and pick the appropriate sub-status instead. See [Managing Incident Status via Slack](/incidents/managing-incidents/managing-incident-status-via-slack) for the full sub-status flow.
***
## Frequently Asked Questions
Use **Triage**. It limits notifications and keeps early investigation to a small responder group. Promote to **Started** once you're confident the issue is real.
Yes. Leave **Mark as In Triage** unchecked at creation and Rootly sets the incident directly to Started. No `in_triage_at` timestamp is recorded.
No. Mitigated is optional but recommended. If you go straight to Resolved, Rootly sets `mitigated_at = resolved_at` automatically so MTTM analytics still work.
**Resolved** means the technical issue is fixed and impact is gone. **Closed** means all follow-up work — retrospective, action items, comms — is complete. Many teams resolve within hours but close days later.
They're timestamp fields, not statuses. `detected_at` and `acknowledged_at` power MTTD and MTTA metrics but the incident's primary status keeps moving through the main lifecycle (Triage → Started → Mitigated → Resolved).
You can add **sub-statuses** underneath the primary statuses to model your team's more granular process (for example, "Investigating" or "Awaiting Vendor" beneath Started). See [Incident Sub-Statuses](/configuration/incident-status).
In [Action Items](/incidents/action-items/action-items). Once every action item is closed and the retrospective is published, move the incident to Closed.
***
## Related Pages
The umbrella page covering how incidents work end-to-end.
Transition rules, timestamp validation, and sub-statuses beneath the primary lifecycle stages.
Where lifecycle-relevant properties like severity and status are configured.
# Creating Sub-Incidents
Source: https://docs.rootly.com/incidents/incident-operations/creating-sub-incident
Learn how to split large incidents into sub-incidents for better organization across multiple teams, with workflow automation support.
## Overview
For larger or cross-functional incidents, you may want to break work into **sub-incidents**.\
A sub-incident allows a team to investigate, coordinate, and track their scope independently—while maintaining shared context with the parent incident.
Each parent incident can have **multiple sub-incidents**.
***
## What Is a Sub-Incident?
A sub-incident is a normal incident that is linked to a parent using `parent_incident_id`.\
Rootly automatically assigns the sub-incident a kind based on its parent:
* `normal_sub`
* `test_sub`
* `scheduled_sub`
Sub-incidents are **not** the same as duplicate incidents.\
Duplicates link via `duplicate_incident_id` and do *not* form a hierarchy.
***
## Restrictions
* Sub-incidents **cannot be split further** (no nested sub-incidents).
* A sub-incident **must have** a parent incident.
* You cannot create a sub-incident **from an existing sub-incident**.
* Some UI options (like “Attach to Parent Incident”) only appear when:
* The incident is not already a sub-incident
* It has no existing sub-incidents
* You have permission to create incidents
***
## Creating Sub-Incidents
Rootly supports creating sub-incidents through two interfaces:
1. **Slack** – Use commands such as `/rootly sub`, `/rootly split`, `/rootly fork`, or `/rootly swimlane`\
→ [**See the Slack guide →**](/incidents/incident-operations/slack-creating-a-sub-incident)
2. **Web** – Use **Create Sub-Incident** or **Attach to Parent Incident** from the incident menu\
→ [**See the Web guide →**](/incidents/incident-operations/web-creating-a-sub-incident)
***
Use any of the following commands in the **parent incident’s Slack channel**:
```text theme={null}
/rootly split
/rootly sub
/rootly fork
/rootly swimlane
```
This opens the **Create Sub-Incident** modal, already linked to the parent.
Slack enforces:
* You must be in an incident channel
* The parent cannot itself be a sub-incident
* You must have permission to create incidents
Slack-created sub-incidents use the same logic as Web-created sub-incidents, including workflow triggers and automatic Slack-channel creation (when enabled).
From the parent incident:
* Click **…** → **Create Sub-Incident**, or
* Use **Attach to Parent Incident** to convert an existing incident into a sub-incident
When attaching an existing incident, Rootly updates its kind and sets its parent relationship.
***
## What Gets Inherited?
Depending on your configuration, sub-incidents may inherit:
* Severity
* Status
* Privacy settings
* Incident types
* Attached services, functionalities, environments
* Teams / groups
* Jira epic or Google Drive folder links
* Slack channel creation settings
***
## Configuring Workflows for Sub-Incidents
Sub-incidents are fully compatible with Rootly Workflows.
To target sub-incidents, set a workflow condition such as:
```text theme={null}
Kind → is one of → normal_sub, test_sub, scheduled_sub
```
Use cases include:
* Creating role assignments for sub-incident teams
* Syncing updates to the parent incident
* Auto-generating investigative tasks
* Auto-creating a Slack channel for each sub-incident
***
## Best Practices
* **Use sub-incidents to delegate ownership** to teams like SRE, Security, or Networking.
* **Keep the parent incident customer-facing**, using sub-incidents to track internal workstreams.
* **Use workflows to create structure**, such as templated tasks, roles, or Slack-channel creation.
* Use the `Create a sub incident` Workflow Action to automatically create a sub-incident for specific scenarios, like being able to coordinate with stakeholders outside of your engineering response teams. [See this in action here](https://www.loom.com/share/e6f038a78d8e4dec8a51c06e557e4298).
* **Avoid unnecessary splitting**—small tasks can often stay in the parent incident.
* **Name sub-incidents cleanly and consistently**, reflecting the scope of work.
***
## Troubleshooting
This occurs when:
* The incident is **already a sub-incident**
* It has its **own sub-incidents**
* You do not have **permission to create incidents**
Slack prevents splitting when:
* You are not in an incident channel
* The incident is a **sub-incident**
* You lack required permissions
Inheritance depends on:
* Workflows that override defaults
* Creation method (Slack vs Web)
* Privacy restrictions
This happens when:
* The incident is already a sub-incident
* It has existing sub-incidents
* It is a scheduled maintenance incident
* Permissions prevent linking
Sub-incidents group parallel workstreams of one active event, and
[marking as duplicate](/incidents/incident-operations/marking-as-duplicate)
links two records of the same event. For a failure that keeps coming back
across separate incidents, tag the incidents instead:
1. Pick a marker: an incident **Type**, a **Cause**, or a
[custom field](/configuration/custom-fields), or a combination.
2. Set it on each incident during the response or in the retrospective.
3. Filter the incidents list by that marker to see the full set of
matching incidents in one view.
4. To analyze the set — recurrence, severity, time to resolve — add a
[custom dashboard panel](/metrics/customized-dashboards) with a
panel-level filter on the same marker. Dashboard-level filters cover
date range, period, team, and service; Type, Cause, and custom fields
are configured per panel.
You can also pull the tagged set through the API to analyze recurring
themes externally.
***
## Related Pages
The adjacent operation — consolidate related incidents instead of splitting into sub-incidents.
The umbrella page covering how incidents work end-to-end.
The status and timestamp model sub-incidents move through, same as parent incidents.
# Marking Incidents as Duplicate
Source: https://docs.rootly.com/incidents/incident-operations/marking-as-duplicate
Mark incidents as duplicates in Rootly to consolidate response efforts via the web UI, Slack, or API, with auto-cancellation support and parent linking.
## How Duplicate Incidents Work
During fast-moving operational issues, teams may accidentally create multiple incidents describing the same underlying problem. Rootly allows you to **mark one incident as the duplicate of another**, ensuring responders align around a single source of truth.
When an incident is marked as a duplicate:
* The *duplicate* incident is linked to a *canonical* (primary) incident
* The duplicate’s timeline records the change
* Workflows, alerts, and Slack channels can consolidate under the primary incident
* Optionally, the duplicate incident can be automatically **cancelled**
This helps reduce fragmentation, avoid duplicate work, and maintain accurate historical records.
Duplicate incidents use a dedicated field (`duplicate_incident_id`) and are **not** the same as sub-incidents, which use `parent_incident_id`.
***
## Why Mark Incidents as Duplicate
Teams benefit from merging duplicates because it:
* Ensures responders focus on the correct incident
* Reduces conflicting updates or duplicated communication
* Clarifies ownership and priority
* Simplifies retrospectives and reporting
* Maintains a clean incident list without losing context
Typical scenarios include:
* Multiple teams declare the same outage simultaneously
* Monitoring tools trigger multiple detection paths
* Slack responders create overlapping incidents during triage
***
## What Happens When You Mark an Incident as Duplicate
When you mark Incident A as a duplicate of Incident B:
* Incident A becomes linked to Incident B
* A timeline entry is added to Incident A
* Slack responders receive a confirmation message
* (Optional) Incident A is automatically **cancelled** and any attached alerts are resolved
* The “Duplicate of …” banner appears in the duplicate incident UI
This ensures full transparency on how and why incidents were consolidated.
Auto-cancellation is enabled by default when marking a duplicate but can be turned off during the action.
***
## Where You Can Manage Duplicates
### **In the Web Interface**
From an incident, open the action menu and select **Mark as Duplicate**.\
You can then:
* Search for the canonical incident
* Choose whether to auto-cancel the duplicate
* Add a cancellation reason for context
A redirect takes you to the canonical incident after completion.
[Learn how to mark duplicates via Web →](/incidents/incident-operations/web-marking-as-duplicate)
***
### **In Slack**
Use one of the supported commands:
* **`/rootly dup`**
* **`/rootly duplicate`**
This opens a modal where you can:
* Select the canonical incident
* Provide a cancellation reason
* Enable/disable auto-cancel
Slack posts a confirmation message to the duplicate’s channel when completed.
Duplicate marking is not available for scheduled maintenance incidents.
[Learn how to mark duplicates via Slack →](/incidents/incident-operations/slack-marking-as-duplicate)
***
## API Support
You can also mark incidents as duplicates programmatically using:
```http theme={null}
POST /api/v1/incidents/:id/duplicate
```
Supported attributes:
The canonical incident this incident is a duplicate of.
When true, the duplicate is automatically cancelled after linking. Enabled by default — matches the Web and Slack flows.
Free-text context recorded on the cancellation — helpful for retrospectives and audit trails.
Rootly updates the relationship and adds a timeline entry automatically.
API duplicate linking does not automatically resolve attached alerts—this behavior is only available via Slack or Web.
***
## Best Practices
* **Always consolidate early**\
Merge duplicate incidents as soon as duplication is detected to reduce confusion.
* **Use auto-cancel thoughtfully**\
Cancelling duplicates keeps your incident list clean, but you may leave them open temporarily during complex triage.
* **Write clear cancellation reasons**\
Adds helpful context for retrospectives and audit history.
* **Educate responders on Slack commands**\
Many duplicates are resolved faster when responders use `/rootly dup`.
* **Review duplicate patterns**\
Repeated duplicates may highlight monitoring or workflow tuning opportunities.
***
## Frequently Asked Questions
Duplicate incidents refer to the **same problem**, while sub-incidents represent **related but distinct workstreams**.
Yes. Edit the incident to remove the duplicate relationship and update the status.
Yes, but only if you have permission to view the target incident.
Any responder with **update** permission on the incident (including private-incident permissions when relevant).
No. Timelines remain separate, but all future response activity should occur in the canonical incident.
***
## Related Pages
The adjacent operation — split into sub-incidents instead of consolidating.
The umbrella page covering how incidents work end-to-end.
What happens to lifecycle state when an incident is marked as a duplicate.
# Scheduling Maintenance Incidents
Source: https://docs.rootly.com/incidents/incident-operations/scheduling-a-maintenance-incident
Learn how to schedule and manage maintenance incidents for planned service interruptions, including Slack channel creation and status page integration.
Maintenance incidents allow your teams to plan, coordinate, and communicate progress of your planned downtime and maintenance windows.
Create a Maintenance Incident in the Rootly web app under **Incidents** > **Maintenance**.
Rootly does not automatically generate a Slack channel for Maintenance Incidents. Create one by selecting the Slack icon under the incident title in the web app.
After the maintenance incident has been created, share it on your [Status Pages](/configuration/status-pages).
## Schedule a Maintenance Incident from the web app
Go to **Incidents > Maintenance** and click **Schedule Maintenance** in the top-right corner.
Fill in the *Maintenance Incident* form. If you want to gather more details, the form can be completely customized in the **Configuration** > **Forms** section of the web application.
The default *Maintenance Incident* form includes:
| Field | Content |
| ------------------------------------- | -------------------------------------------------------------------------------------------- |
| Title | Title of the incident. This will be used to create the channel name along with today's date. |
| Summary | A summary of the incident. |
| [Severity](/configuration/severities) | Defaults: Severity level from SEV3 to SEV0. |
| [Type](/configuration/incident-types) | The type of incident. Defaults: Cloud, Security, Customer facing, Default. |
| [Services](/configuration/services) | The service or services impacted. |
Click **Create Incident** to save.
## Schedule a Maintenance Incident from Slack
Enter the Slack command **/rootly maintenance**. Press *enter* or click *the paper plane icon* to run the command and open the *maintenance incident* form.
Fill in the *maintenance incident* form. *Scheduled for* and *Scheduled until* dates and times are required.
Most of the fields in the *maintenance incident* form can be customized and new fields can be added. If you want to gather more details, the form can be completely customized in the **Configuration** > **Forms** section of the web application.
The default *maintenance incident* form includes:
| Field | Content |
| ------------------------------------- | -------------------------------------------------------------------------------------------- |
| Title | Title of the incident. This will be used to create the channel name along with today's date. |
| Summary | A summary of the incident. |
| [Severity](/configuration/severities) | Defaults: Severity level from SEV3 to SEV0. |
| [Type](/configuration/incident-types) | The type of incident. Defaults: Cloud, Security, Customer facing, Default. |
| [Services](/configuration/services) | The service or services impacted. |
Click **Schedule** to save.
The maintenance incident is now available in the Rootly web app. To manage the incident in Slack, select *View in Rootly,* then click the Slack icon under the incident title.
## Update a maintenance incident
Once a maintenance incident is scheduled, you can change its status, edit its details, assign roles, and open a Slack channel for it from the incident view.
### Change the status
Maintenance incidents can have the following statuses:
* Planning
* Scheduled
* In Progress
* Verifying
* Completed
* Cancelled
Change the status by clicking **Incident Status** in the top-right corner, or in Slack using the `/rootly status` command.
### Update Details
Click **Edit** in the top-right corner to update the incident.
Default fields include:
| Field | Content |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Scheduled start and end time | The planned time for the maintenance to take place. |
| Title | The title of the maintenance incident. This will only be visible in the Rootly web app or the incident Slack channel (if applicable). |
| [Severity](/configuration/severities) | Defaults: Severity level from SEV3 to SEV0. |
| [Type](/configuration/incident-types) | The type of incident. Defaults: Cloud, Security, Customer facing, Default. |
| [Services](/configuration/services) | The service or services impacted. |
| [Environments](/configuration/environments) | The environment the incident will impact. For example, Dev or Production. |
| [Functionalities](/configuration/functionalities) | Specific functionalities impacted. For example, Checkout or Search. |
| [Teams](/configuration/teams) | The relevant teams involved in this maintenance incident. |
The form can be edited from **Configuration** > **Forms & Fields** > **Update Maintenance Incident.**
### Assign Roles
Pre-assign roles to this maintenance incident by selecting "Assign Roles" under the incident title.
### Create a Slack channel
Select the Slack icon under the incident title to create a Slack channel for this maintenance incident.
## Publish Your Maintenance Incident to a Status Page
Communicate your upcoming and active maintenance windows to your stakeholders through the Rootly Status Page.
Navigate to your maintenance window, select the **Status Page** tab, then **Publish Incident**.
Select the status page you'd like to publish an update to and fill in the subsequent information to include in the update.
Rootly will automatically surface any Maintenance Windows at the top of the status page.
Further, any services attached to your Maintenance Window will automatically be shown as **In Maintenance** if the update published to the status page is either **In Progress** or **Verifying.**
To give you full control over how maintenance windows are communicated to your stakeholder, Rootly will not automatically update your status page based on the maintenance incident's current status: updates must be manually published to the status page.
## Building Workflows for Maintenance Incidents
You can build automations for your Maintenance Incidents using [Rootly's Workflow builder](/workflows/incident-workflows). Follow the instructions to create a workflow in the linked documentation.
To create a workflow specific to Maintenance Windows, ensure your workflow has a **Kind** condition set to **Scheduled Maintenance** so that the workflow will only fire on your maintenance incidents.
## Converting a maintenance incident
Sometimes, unexpected complexity might occur during your maintenance incident, and it requires a regular incident to be declared.
Rootly lets you convert an existing maintenance incident into a regular incident directly in Rootly Web, or via Slack.
## Converting to a regular incident on web
While viewing your Maintenance Incident on web, select (...), then **Convert to incident**.
Clicking on this button will trigger your Rootly **Create Incident** form, as well as a 'Reason for conversion' field for your commanders to fill out to give additional context for why the incident is being converted. The information provided in this field will be added to the incident's timeline.
## Converting to a regular incident on Slack
To convert your maintenance incident on Slack, in your maintenance incident's Slack channel use the `/rootly convert maintenance` command.
This will trigger your Rootly **Create Incident** form, as well as a 'Reason for conversion' field for your commanders to fill out to give additional context for why the incident is being converted. The information provided in this field will be added to the incident's timeline.
Once your maintenance incident is converted to a regular incident, all of your related automations and workflows will trigger much like they do when a new incident is created.
***
## Related Pages
The umbrella page covering how incidents work end-to-end.
Where maintenance windows get communicated to customers.
How maintenance-incident updates land on the status page.
# Creating Sub-Incidents via Slack
Source: https://docs.rootly.com/incidents/incident-operations/slack-creating-a-sub-incident
Create sub-incidents directly from Slack incident channels using the /rootly sub command and interactive dialog to track related issues separately.
## Overview
Create sub-incidents directly from an incident’s Slack channel using Rootly slash commands.\
Sub-incidents help teams split large or cross-functional incidents into focused workstreams while keeping everything tied back to the parent incident.
***
## Restrictions
Sub-incident creation is only available when:
* You run the command **inside an incident channel**
* The incident is **not already a sub-incident**
* You have **permission to create incidents**
* The incident has no restrictions (for example, cannot split a sub-incident)
If these conditions are not met, Slack will show an appropriate error.
***
## How to Create a Sub-Incident in Slack
### 1. Run the sub-incident command
In the parent incident channel, type **any** of the following:
```text theme={null}
/rootly sub
/rootly split
/rootly fork
/rootly swimlane
```
These commands all trigger the **Create Sub-Incident** dialog.
***
### 2. Complete the creation dialog
Fill in the incident fields as you normally would.\
Rootly automatically links the new incident as a **sub-incident** of the channel you ran the command from.
After submitting, Slack will confirm that the sub-incident has been created:
You’ll then see a reference to the new sub-incident in the parent incident’s summary, Slack channel, and web interface.
***
## What Happens Behind the Scenes
Rootly automatically:
* Sets the new incident’s **parent\_incident\_id**
* Assigns a sub-incident kind (for example, `normal_sub`, `scheduled_sub`)
* Attributes the creation to **Slack**
* Optionally creates a **Slack channel** for the sub-incident (team settings apply)
* Triggers any workflows conditioned on\
`Kind → is one of → normal_sub / scheduled_sub / test_sub`
Sub-incidents created via Slack behave exactly the same as those created in the Web UI. They inherit parent properties according to your workspace configuration and any workflows you've defined on sub-incident creation.
***
## Demo
***
## Best Practices
* **Use sub-incidents to divide ownership** across SRE, Security, Networking, or other teams.
* **Keep the parent incident customer-facing** while sub-incidents track internal or deep-dive workstreams.
* **Use workflows to automate structure**, such as creating roles or tasks for each new sub-incident.
* **Name sub-incidents clearly** to reflect their specific investigative track.
* Avoid splitting unless the scope is meaningfully distinct—small tasks are usually better captured as action items.
***
## Troubleshooting
Slack restricts `/rootly sub` to **incident channels only**.\
Run the command inside the relevant incident channel.
Sub-incidents cannot be split further.\
Create sub-incidents **from parent incidents only**.
Your role does not have permission to create incidents.\
Contact your Rootly admin to update your permissions.
This may occur if:
* Required fields were left blank
* Your Slack integration is temporarily disconnected
* A workflow with a blocking condition prevented sub-incident creation
Ensure that:
* The originating channel was the correct **parent incident channel**
* The parent incident is not archived or cancelled
* The sub-incident was created successfully (Slack will show a confirmation)
# Marking Incidents as Duplicate via Slack
Source: https://docs.rootly.com/incidents/incident-operations/slack-marking-as-duplicate
Mark incidents as duplicates from Slack incident channels using the /rootly dup command to consolidate response efforts and avoid scattered chats.
You can mark an incident as a duplicate directly from Slack using a simple slash command. This helps consolidate related incidents quickly and keep responders aligned in a single source of truth.
This operation links the current incident to a **canonical incident** via `duplicate_incident_id`.\
This is separate from **sub-incidents**, which use `parent_incident_id`.
***
## Mark a Duplicate in Slack
In any **incident Slack channel**, type:
```text theme={null}
/rootly dup
```
or
```text theme={null}
/rootly duplicate
```
A modal opens allowing you to select the original incident and configure cancellation options.
***
## Modal Fields
The Slack modal includes:
Search for the canonical incident.
Optional toggle (on by default).
Optional free text, added to the timeline.
Slack enforces the same permissions as the web interface.\
You must be able to **update** the incident to mark it as a duplicate.
***
## What Happens After Submission
When you confirm the duplicate:
* The current incident is linked to the selected original incident
* A non-editable **timeline entry** is created
* Slack posts a confirmation message in the duplicate’s channel (if applicable)
* If **Auto Cancel** is enabled:
* The duplicate is cancelled
* Alerts attached to the duplicate are resolved automatically
* Slack posts a “Duplicate incident detected” message
Rootly also updates Slack summaries and workflows that rely on incident lifecycle changes.
***
## Best Practices
* **Run the command from the incident channel**\
Slack automatically associates the action with the incident the channel is tied to.
* **Use the canonical incident with the most context**\
Choose the incident that contains the most accurate investigation details or customer-facing messaging.
* **Provide a clear cancellation summary**\
This helps responders understand why context moved and assists retrospectives.
* **Auto-cancel when appropriate**\
This prevents duplicate incidents from remaining open and triggering unnecessary automations.
* **Avoid marking scheduled maintenance as duplicates**\
Slack prevents this automatically, since maintenance incidents follow different lifecycle rules.
***
## Troubleshooting
You must run `/rootly dup` inside a **Rootly incident Slack channel**.\
The command will not work in normal or private Slack channels.
Possible reasons:
* You do not have **update** permissions on the incident
* The incident is a **scheduled maintenance incident** (duplicates are disallowed)
* The incident is **already marked as a duplicate**
Slack only shows incidents you have permission to view.\
Private or restricted incidents may not appear unless you have the required access.
Common causes:
* Auto-cancel was toggled **off**
* The incident was already cancelled
* Slack permissions prevented cancellation
* Workflow or feature flags restricting cancellation were active
This can occur when:
* Slack is not integrated or connected for your team
* The duplicate incident has **no Slack channel**
* Notifications are suppressed by workspace settings
# Creating Sub-Incidents via Web Interface
Source: https://docs.rootly.com/incidents/incident-operations/web-creating-a-sub-incident
Create sub-incidents through the Rootly web interface using the incident menu and creation form to track related child issues under a parent incident.
## How It Works
You can create a sub-incident directly from an existing incident in the Rootly web interface.\
This is useful when multiple teams need to investigate different parts of a larger incident while keeping everything linked and coordinated.
***
## Create the Sub-Incident
In any parent incident, click the **⋯ (More)** menu next to the incident title or status. You will see **Create Sub-Incident** when:
* The incident is **not already a sub-incident**
* The incident is **not a scheduled maintenance incident**
* You have **permission to create incidents**
Selecting **Create Sub-Incident** opens the standard **New Incident** form. Rootly automatically injects a hidden `parent_incident_id`, ensuring the new incident is created as a sub-incident.
You can customize:
* Summary
* Severity
* Impacted services & functionalities
* Roles, assignees, and metadata
* Any fields defined in **Configuration → Forms & Fields**
Click **Create Incident** to finish.
***
## What Happens After Creation
Once saved:
* The new incident becomes a **sub-incident** of the parent
* Its **kind** is automatically derived (for example, `normal_sub`, `scheduled_sub`)
* The parent incident displays a **Sub-Incidents** panel linking to all sub-incidents
Sub-incidents cannot themselves create further sub-incidents.\
They represent the lowest level in an incident hierarchy.
***
## Optional: Attach an Existing Incident as a Sub-Incident
If you already have an incident you want to convert into a sub-incident:
Open the child incident you want to attach.
Go to **⋯ → Attach to Parent Incident**.
Choose a parent incident from the autocomplete search.
Save to attach the child to the parent.
This option appears only when:
* The incident is **not already a sub-incident**
* It has **no sub-incidents of its own**
* You have permission to create incidents
***
## Best Practices
* **Use sub-incidents when multiple teams or domains are involved**\
Helps isolate workstreams while maintaining a unified parent incident.
* **Keep naming clear and scoped**\
Example: “Database Failover Sub-Incident (SRE)” or “Authentication Latency (Identity Team)”.
* **Enable workflows**\
Many teams auto-assign roles, create tasks, or spin up Slack channels for sub-incidents.
* **Avoid unnecessary sub-incidents**\
If the effort is small or tightly scoped, keep work in the main incident.
* **Review sub-incidents together during retrospectives**\
They provide excellent insight into how different teams contributed to resolution.
***
## Troubleshooting
This usually occurs when:
* The incident is **already a sub-incident**
* The incident is a **scheduled maintenance incident**
* You lack **create incident** permissions
* Your team has feature restrictions
This happens if:
* The incident **already has a parent**
* It has its **own sub-incidents** (nested sub-incidents are not allowed)
* The incident was created as **scheduled maintenance**
* You don’t have adequate permissions
Inheritance varies depending on:
* Workflow automation
* Feature flags (for example, parent/sub synchronization)
* Privacy rules
* Origin of creation (Slack vs Web)
Timeline sync requires:
* `enable_parent_and_sub_incident_sync` feature flag
* `parent_to_sub_incident_sync` enabled on the incident\
Only **non-internal** timeline events sync across related incidents.
# Marking Incidents as Duplicate via Web Interface
Source: https://docs.rootly.com/incidents/incident-operations/web-marking-as-duplicate
Learn how to mark incidents as duplicates in the Rootly web interface, including selecting the primary incident and optional auto-cancellation.
Marking an incident as a duplicate helps consolidate response efforts when multiple responders report the same issue. The Web UI provides a simple modal to link the current incident to its canonical incident and optionally auto-cancel it.
Duplicate incidents use a dedicated **duplicate\_incident\_id** relationship and are separate from sub-incidents, which use **parent\_incident\_id**.
***
## Mark a Duplicate via the Web UI
In the top-right corner of the incident page, click the **⋯** menu and select **Mark as Duplicate**.
This option appears only when the incident is not already a duplicate and you have permission to update the incident.
In the modal, search for and select the **original (canonical)** incident.\
This is the incident the current one will be linked to.
You can also:
* **Auto-cancel** the duplicate (enabled by default)
* Provide a **reason for cancellation**, which appears in the timeline
Click **Confirm** to save your changes.
Rootly will:
* Link the incident as a duplicate
* Add a timeline entry
* Post a notification to the duplicate’s Slack channel (if Slack is connected)
* Cancel the duplicate (if enabled)
* Redirect you to the original incident
***
## What Happens After Marking a Duplicate
* The duplicate incident displays **“Duplicate of …”** at the top of the page
* A non-editable timeline entry records who performed the action and why
* Auto-cancel will:
* Move the incident to **Cancelled**
* Resolve all attached alerts automatically
* Slack responders are notified if the Slack integration is active
Auto-cancel is recommended to reduce noise in reports and Slack channels, but you may disable it when the duplicate incident still contains useful investigation context.
***
## Best Practices
* **Use “Mark as Duplicate” early**\
Consolidating incidents right away helps reduce confusion across teams and channels.
* **Always designate a canonical incident**\
The canonical incident should contain the most accurate timeline and central communication thread.
* **Provide a clear cancellation reason**\
This helps responders understand why context moved and ensures retrospectives remain accurate.
* **Auto-cancel duplicate incidents when appropriate**\
This prevents “ghost incidents” from appearing unresolved in dashboards or workflow triggers.
* **Avoid marking scheduled maintenance incidents as duplicates**\
Maintenance windows follow different lifecycle logic and should remain separate.
* **Review duplicate frequency**\
Frequent duplicates may indicate alerting issues, unclear runbooks, or multiple teams raising incidents for the same symptom.
***
## Troubleshooting
* You may not have **update permission** for the incident.
* The incident may already be marked as a duplicate.
* Scheduled maintenance incidents cannot be marked as duplicates.
* The incident you're looking for may be private and you may not have permission to view it.
* The selector excludes the current incident automatically.
* Try searching by title or ID.
* The auto-cancel toggle may have been turned off.
* The incident may have already been cancelled.
* Workflow restrictions or permissions may prevent auto-cancel in rare cases.
* Slack may not be integrated for your team.
* The duplicate incident may not have a Slack channel.
* Notification settings may restrict posting confirmations.
Auto-cancel removes the duplicate from most active incident metrics.\
If auto-cancel was disabled, manually cancel or close the duplicate to prevent clutter.
# Incident Roles Overview
Source: https://docs.rootly.com/incidents/incident-roles/incident-roles
Understand how incident roles provide structure, clarity, and accountability during incidents, and how they are managed in the Rootly web interface and Slack.
## How Incident Roles Work
Incident roles give teams a clear operating structure during an incident. By defining **who is responsible for what**, roles reduce confusion, accelerate response, and help responders coordinate effectively across tools.
Roles are visible throughout Rootly—in the incident sidebar, Slack summaries, workflows, and retrospectives—providing consistent clarity for everyone involved in the response.
This page introduces how roles work, why they matter, and where they fit across the incident lifecycle.
***
## Why Roles Matter
Most teams benefit from having predictable responsibilities during an incident. Roles help by:
* Establishing clear ownership for critical responsibilities
* Reducing duplication, conflicting work, or unclaimed tasks
* Helping new responders understand the command structure instantly
* Powering workflow automation (for example, “notify the Communications Lead”)
* Improving retrospective clarity and accountability
Common examples include:
* **Incident Commander** – Leads the response, drives decisions
* **Technical Lead** – Owns investigation and mitigation
* **Communications Lead** – Handles internal/external updates
* **Scribe** – Captures decisions and incident notes
* **Customer Support Liaison** – Bridges engineering and support
Rootly role definitions are fully customizable. You can match them to your organization’s processes, staffing patterns, and terminology.
***
## Where Roles Live in Rootly
### **On the Incident Detail Page (Web UI)**
The **Roles** section shows the full list of defined roles and current assignees. Responders can:
* Assign or reassign role owners
* Remove owners
* Review historical ownership via the timeline
* Update responsibilities as the incident evolves
### **In Slack**
If Slack is integrated, responders can manage roles directly inside the incident channel using:
* Slash commands
* Contextual role dialogs
* Buttons in the pinned incident overview
* Workflow-triggered assignment prompts
This keeps role management close to where real-time communication happens.
### **In Workflows**
Roles can be automatically assigned using rules based on:
* Severity
* Impacted services
* Incident type
* On-call schedule
* Custom logic
Automation ensures important roles are filled immediately and consistently.
***
## How Roles Support the Response Process
Role assignments shape how Rootly orchestrates incident response:
* Timeline entries track all role changes
* Status updates, notifications, and communications reference current role owners
* Slack channel summaries update automatically when roles shift
* Retrospectives include full role history
* Permissions or visibility rules may depend on roles
* Workflow logic can target role owners with precision
Consistent role assignment increases the value of automation, improves communication clarity, and strengthens the command structure across incidents.
***
## Where to Go Next
These pages will help you use and manage roles more effectively:
* **Manage via Slack** – How to assign roles, reassign owners, and use role dialogs inside Slack
* **Manage via Web Interface** – How to manage roles on the incident detail page
* **Incident Access & Permissions** – How roles can influence who can update or view incident details
* **Workflows** – How to automate role assignment based on triggers or incident conditions
***
## Best Practices
* **Define roles clearly**\
A brief description ensures responders know exactly what each role owns.
* **Use single-owner roles for critical responsibilities**\
Avoid ambiguity by ensuring one clear decision-maker per key role.
* **Automate what’s predictable**\
Use workflows to assign roles like Incident Commander or Communications Lead based on severity or team on-call.
* **Reassign roles as conditions change**\
Ownership should shift naturally if workloads or expertise change.
* **Review role effectiveness after every incident**\
Use retrospectives to refine your role model and identify process improvements.
* **Make role management part of responder onboarding**\
Teams respond faster when everyone knows how to assign and update roles.
***
## Frequently Asked Questions
No. Most teams define more roles than they need in every incident. You can assign only the roles that make sense for the severity, scope, and complexity of the situation.
Yes, but it is recommended to keep **critical roles** (like Incident Commander) single-owned to avoid decision ambiguity. Supporting roles may have multiple contributors if needed.
Absolutely. Rootly allows you to add, rename, reorder, or remove roles entirely so they align with your organization’s terminology and response structure.
Roles can influence visibility and editing permissions, especially in organizations that use private incidents or restricted access groups. See **Incident Roles & Access** for details.
Yes. Workflows are one of the most powerful ways to keep role assignments consistent—triggered by severity, incident type, service, or custom logic.
All role changes appear in the **incident timeline**, including assignments, reassignments, and removals. This history is preserved for retrospectives.
Yes. Responders can use Slack commands or modal dialogs inside the incident channel to assign or update roles without switching to the UI.
The incident can still proceed normally, but Rootly’s automation, ownership clarity, and structured workflows work best when key roles—such as Incident Commander—are filled.
***
## Related Pages
Set up the role definitions this page shows how to assign during incidents.
Roles can carry predefined tasks that become action items on every incident.
The umbrella page covering how incidents work end-to-end.
# Managing Incident Roles Through Slack
Source: https://docs.rootly.com/incidents/incident-roles/managing-incident-roles-through-slack
Assign, update, and manage incident roles like Incident Commander and Comms Lead directly from Slack using slash commands and dialogs.
## Overview
Slack is often where incident response actually happens, so Rootly lets you assign and manage incident roles **directly inside the incident channel**, without switching back to the web interface.
This includes:
* Assigning yourself to a role
* Assigning or removing other responders
* Editing all incident roles in one modal
* Adding roles that aren't yet part of this incident
* Managing multi-user and single-user roles
* Enforcing permission checks for private incidents
To use these Slack capabilities, make sure the [Slack integration is installed](/integrations/slack/slack).
Role management in Slack only works inside an **incident channel** and requires permission to assign incident roles.\
For private incidents, users must also have update permission for private incidents.
***
## Manage Roles via Slack
Navigate to the Slack channel for the incident.\
Slack commands and buttons rely on the channel’s mapping to an active incident.
You can open the Assign Roles modal in two ways:
**Option A: Use the Assign Roles button**
When an incident is created, the pinned incident summary includes an **:firefighter: Assign Roles** button.
**Option B: Use the slash command**
Run the command inside the incident channel:
```text theme={null}
/rootly assign
```
You may also use the aliases:
* `/rootly role`
* `/rootly roles`
The modal displays every role available for this incident.\
Each role has an associated menu or selector depending on how it was configured.
Common actions include:
* **Assign Myself**\
Quickly take ownership of a role.
* **Edit Assigned Users**\
Add or remove specific responders.
* **Remove Myself**\
Step out of a role you previously held.
If the role supports multiple assignees, you’ll see a **multi-select**.\
If the role only allows one assignee, you’ll see a **single-select** dropdown.
Some roles may display a notice like:\
**“Only users with an Incident Response seat can be assigned.”**\
This appears when your organization enforces seat restrictions.
If your team has defined incident roles that are **not yet added to this specific incident**, you’ll see an **Add Roles** banner.
These roles must be added before responders can be assigned to them.
Click **Update** to apply all role assignments.\
Rootly updates the incident immediately and posts relevant timeline entries.
***
## Best Practices
* **Assign roles early in the incident**\
Clear ownership improves coordination and communication.
* **Use multi-assignee roles intentionally**\
For example, an “On-call Engineer” role may allow multiple users, while “Incident Commander” should be single-assignee.
* **Review roles during major status transitions**\
As the incident escalates, mitigation begins, or communications ramp up, ensure the right responders are assigned.
* **Use role automation where appropriate**\
Workflows can auto-assign on-call responders, service owners, or leadership roles when an incident begins or severity increases.
* **Keep roles aligned with your process**\
Customize roles in the web UI to match how your incident response team operates.
***
## Troubleshooting
Make sure you’re running it **inside an incident channel**.\
Running the command in DMs or non-incident channels will fail.
You may not have permission to assign incident roles.\
Check your incident role or RBAC configuration.
Roles are configured by your team.\
If a role only allows one user, Slack will display a single-select field.
Your organization enforces seat restrictions for role holders.\
Only users with an available seat can be assigned.
The role may not be added to this incident yet.\
Use the “Add Roles” option if available.
# Managing Incident Roles Through the Web Interface
Source: https://docs.rootly.com/incidents/incident-roles/managing-incident-roles-through-the-web
Configure, assign, and manage incident response roles like Incident Commander and Comms Lead using the Rootly web interface for clear ownership.
## Overview
The Rootly web interface provides a full-featured way to configure and manage incident roles.\
From the **Incident Roles** settings page, you can create new roles, edit existing ones, define responsibilities, and control which users can perform specific actions during an incident.
These role definitions become available across your organization and determine which roles appear in Slack and in the incident detail page.
Role configuration is a workspace-level setting. Any changes you make here apply to all incidents going forward.
***
## Manage Roles in the Web Interface
Navigate to:
**Configuration → Incident Roles**
This page lists all existing roles in your workspace.
Click:
* **New Incident Role** to create a new role, or
* The **edit (pencil)** icon next to an existing role to modify it.
You’ll be taken to the role editor, where you can configure the role’s name, summary, responsibilities, and permissions.
Within the role editor, you can set:
* **Name** – The title of the role (for example, “Incident Commander”).
* **Summary** – A short description shown in lists.
* **Responsibilities** – A longer description outlining expectations for this role.
* **Optional Role** – Specify whether this role must be assigned for every incident.
* **Allow Multiple Assignees** – Enable if more than one user can hold this role at the same time.
* **Permission Set** – Determine what actions assignees are allowed to perform on an incident (for example, update status, manage roles, modify properties).
These configuration options shape how the role behaves in both the web interface and Slack.
Click **Save** to apply your updates.
Your new or updated role will now appear across all incident workflows and Slack role assignment modals.
***
## Best Practices
* **Use clear, action-oriented role names**\
Roles like *Incident Commander*, *Communications Lead*, or *Ops Owner* help responders quickly understand responsibilities.
* **Limit multi-assignee roles**\
Multi-user roles can be useful, but restricting some roles to a single owner helps maintain accountability.
* **Document responsibilities thoroughly**\
Clear written expectations improve consistency across incidents and make onboarding easier.
* **Review role definitions periodically**\
As your response process matures, update roles to reflect clearer responsibilities or new workflows.
* **Keep roles aligned with permissions**\
Ensure each role’s permission set reflects what responders actually need to do during an incident.
***
## Troubleshooting
You may not have access to configuration settings.\
Only workspace admins or users with the appropriate configuration permissions can view this page.
Roles that are referenced by workflows or required by the workspace cannot be deleted until dependencies are removed.
The role must have **Allow Multiple Assignees** enabled in the role configuration.
Slack surfaces the latest role definitions, but cached pinned blocks may refresh only after certain lifecycle actions.\
Running `/rootly assign` will always fetch updated roles.
# Adding Events to Timeline via Email
Source: https://docs.rootly.com/incidents/incident-timeline/adding-events-to-timeline-via-email
Add events to incident timelines by responding to incident emails through the Rootly Email integration, capturing context from external stakeholders.
## Overview
Using the [Email integration](/integrations/email), you can add timeline events simply by **replying to an incident email**.\
This makes it easy for stakeholders—especially those who don’t live in Slack or the web interface—to contribute updates directly to the incident record.
When you reply to an incident email, Rootly automatically logs that message as a timeline entry, preserving its content, sender information, and relevant metadata.
***
## How It Works
### **Replying to an Existing Incident**
When you reply to an incident’s email thread:
* A new **Email** timeline event is automatically created
* The event includes:
* The parsed message body
* Sender information (matched to a Rootly user if possible)
* The To/From header values
* A permalink-style reference to the inbound message
* The event is timestamped using the time the email was received
* The event is **non-editable**, ensuring integrity
Rootly determines which incident the message belongs to by scanning the email’s **References** header, which preserves threading.
### **Starting a New Incident by Email**
If an email is not part of an existing thread, Rootly can create a **new incident** using:
* The subject → incident title
* The body → summary
* Best-effort parsing to extract:
* Severity
* Services
* Functionalities
* Environments
* Incident types
Metadata parsing works best when your teams follow consistent subject/body formatting conventions.
***
## Setup Requirements
To ensure reliable processing of inbound email:
* Confirm the Email integration is **enabled**
* Ensure all expected sender domains are listed under **Allowed Domains**
* If provenance enforcement is enabled, only allowlisted domains may send emails
* Provide the incident thread’s email address to anyone who needs to contribute via email
Emails from unapproved domains may be rejected when provenance checks are enabled.
***
## Behavior & Limitations
* Email-created timeline events are **not editable**
* Forwarded emails or replies that strip the **References** header cannot be attached to the existing incident
* If a sender’s email does not match any Rootly user, Rootly assigns attribution to the **Rootly bot**
* Email events default to **internal visibility**
* Attachments are not ingested as timeline files (only the text body is added)
***
## Troubleshooting
The reply may have lost the critical **References** header, which Rootly uses to link messages to incidents.\
Other causes include:
* Sender domain not allowlisted
* Email integration disabled
* Message rejected due to provenance enforcement
This occurs when Rootly cannot match the sender’s email address to a user in your workspace.\
In those cases, the system defaults to the Rootly bot.
No. Email-created timeline events are immutable and always internal.
Yes. When an inbound message does not belong to an existing thread, Rootly creates a new incident using its subject, body, and any auto-parsed metadata.
# Adding Events to Timeline via Slack
Source: https://docs.rootly.com/incidents/incident-timeline/adding-events-to-timeline-via-slack
Add timeline events from Slack using the /rootly timeline command, message actions, or emoji reactions to capture key moments during incident response.
## Overview
Slack is one of the fastest ways to record timeline events during an incident.\
Rootly supports multiple Slack-based methods so responders can capture actions, observations, and decisions without leaving the incident channel.
You can add events using:
* The `/rootly timeline` slash command
* Message actions (the Slack **hamburger menu**)
* Configurable **pin or emoji reactions**
All Slack-created events appear instantly in the incident timeline.
***
## Methods for Adding Timeline Events
In the incident Slack channel, type:
**`/rootly timeline `**
This opens the Add Event modal pre-filled with your text, allowing you to set visibility and optional details before submitting.
You can capture any message directly into the timeline:
1. Hover over a message
2. Click the **hamburger icon**
3. Select **Add event**
The modal will auto-fill the message content and attach a permalink back to Slack.
Rootly can automatically create timeline entries whenever specific reactions are added to a message.
* **Pin reactions** (📌)
* **Any custom emoji** your team configures for timeline ingestion
You can configure which emoji should create events in **Slack Integration Settings**.
***
## How Slack-Captured Events Behave
* Events created from a command or message action open a modal so you can review details
* Events created from pin/emoji reactions are added automatically — *no modal*
* Reaction-based events use the **original Slack message timestamp** as the event’s `occurred_at` value
* All entries include a Slack permalink and optional user-attribution
* Deduplication prevents duplicate events from repeat reactions
Emoji triggers, follow-up creation, and task creation each use separate emoji lists and **cannot overlap**. Configure them in *Integrations → Slack*.
***
## Troubleshooting
Make sure you ran the command **inside the incident channel**.\
Running it anywhere else will result in a non-incident error.
Verify that:
* Emoji ingestion is enabled
* The emoji is included in the **Add to Timeline** emoji list
* You are in a recognized incident channel
For emoji/pin reactions, occurred\_at is taken from the **Slack message timestamp**, not the moment you reacted.
You may not have permission to update the incident timeline, especially for private incidents.
If you're on Slack Enterprise Grid and pinning messages to the incident timeline isn't working, this is a sign that your Slack integration was installed as a **non-Grid** (single-workspace) installation rather than at the organization level. \
\
**Solutions:**
* Disconnect the Slack integration from Rootly
* Reconnect it, making sure to select **Slack Enterprise Grid** during installation and authorize at the **organization level** (not a single workspace)
# Adding Events to Timeline via Web Interface
Source: https://docs.rootly.com/incidents/incident-timeline/adding-events-to-timelines-in-the-web-ui
Add timeline events directly from the Rootly web interface with markdown support for event descriptions, custom timestamps, and visibility controls.
## Overview
The Web interface provides the most structured and controlled way to add timeline events to an incident. It supports rich text formatting, attachments, timestamps, and granular visibility settings—making it ideal for adding clear, polished, retrospective-ready updates.
Events added through the Web UI are treated the same as those created via Slack, email, or API, and appear immediately in the incident’s chronological timeline.
***
## Adding a Timeline Event in the Web UI
Navigate to the incident you want to update and scroll to the **Timeline** section.
Click the **Add event** button at the top of the timeline to open the event creation modal.
Enter the text you want recorded as a timeline event.
Your description supports **Markdown formatting**, allowing you to add emphasis, structure, and links.\
This is especially helpful when summarizing findings, outlining hypotheses, or highlighting important decisions.
[Markdown](https://www.markdownguide.org/) syntax is supported in your event description.
You can optionally customize:
Set an exact timestamp or backfill earlier events.
Upload logs, screenshots, or supporting documents.
These fields help maintain an accurate and high-quality incident timeline.
Click **Create event** to publish your entry to the timeline.\
It will appear in chronological order based on the timestamp you provided.
***
## Tips for Creating Useful Timeline Entries
* Use Markdown to structure your updates for readability
* Write concise, factual observations and decisions
* Attach files instead of pasting long logs
* Record the *why* behind actions when possible
* Use accurate timestamps when reconstructing events
Well-written timeline entries significantly accelerate retrospective creation and help future responders understand what happened.
***
## Troubleshooting
Check the **Occurred At** field.\
If left blank, Rootly uses the time you created the event.
Make sure visibility is set to **External**, not Internal.
You may not have permissions to update incidents or timeline entries.
Ensure the file type and size comply with your workspace’s attachment rules.
***
## Best Practices
* Keep entries focused and easy to scan
* Include decisions, not just actions
* Backdate events thoughtfully to maintain timeline accuracy
* Use Markdown headings, lists, and code formatting where helpful
* Add context such as impacted services or related systems
# Adding Events to Timeline via API
Source: https://docs.rootly.com/incidents/incident-timeline/adding-events-via-api
Add timeline events to incidents programmatically via the Rootly API with visibility controls, custom event fields, timestamps, and bulk import support.
## Overview
The Rootly API allows you to automatically add timeline events from monitoring tools, CI/CD pipelines, automation systems, or any service that needs to record activity during an incident. This is ideal when you want to:
* Ensure key system activity is captured automatically
* Add highly structured or machine-generated data
* Record actions taken outside Slack or the Web UI
* Maintain a complete and auditable incident history
* Integrate internal tools directly into your incident process
API-created timeline events behave exactly the same as those added through Slack, email, or the Web UI. They appear chronologically, support visibility controls, and participate in analytics, retrospective preparation, and exports.
More details are available in the [API documentation](/api-reference/overview).
***
## Before You Begin
Before adding events through the API, ensure you have:
* A **Rootly API token** with permission to update incidents
* The **incident ID** for the timeline you want to write to
* Any IDs for context you plan to add later (services, functionalities, etc.)
* Awareness of your team’s required fields for timeline events (if applicable)
* The **Incident Events** API endpoint reference:
`/api/v1/teams/:team_id/incidents/:incident_id/events`
If you are unsure which fields your team requires, check **Configuration → Required Fields** or the incident’s form configuration.
***
## Adding a Timeline Event via API
You must know the incident ID, which you can obtain from:
* The Web UI URL
* The list-incidents API
* A previously created incident response
* A workflow-driven or system-triggered context
All events you create will attach directly to this incident’s timeline.
The API supports several top-level fields for constructing timeline entries:
**Core fields**
* Event text (the message shown in the timeline)
* Visibility (internal-only or external/public)
* Occurred time (when the event actually happened)
* Starring (optional highlighting)
**Impact fields (set after creation)**\
These can be added after the event exists:
* Affected services
* Affected functionalities
If you do not provide an occurred time, Rootly uses the creation timestamp automatically, ensuring correct chronological ordering.
Any workflow engine, monitoring tool, or automation system can make the call using standard HTTP—CI/CD pipelines, serverless functions, alert processors, or internal services.
The API will return the full event record, including IDs you can use for follow-up actions.
After the event is created, you may optionally attach:
* Impacted services
* Impacted functionalities
These attributes enrich the incident story and make root-cause and impact analysis clearer.
Once created, the event appears immediately:
* In the incident’s timeline UI
* In Slack (if the incident channel displays timeline messages)
* In exports and retrospectives
* In API queries and analytics
You can edit, star, or delete the event later if needed.
***
## What You Can Include in an API Timeline Event
You can capture a wide range of structured information through API events:
* Deployment summaries
* Automated rollback notices
* Monitoring alerts or anomaly detections
* CI/CD pipeline results
* Runbook or playbook execution steps
* Health check transitions
* Logs or metrics snapshots
* Notifications from internal tooling
API events support both internal-only and externally visible visibility settings, making them suitable for both responder-facing and customer-facing communications.
***
## Validation & Error Behavior
Rootly uses consistent validation rules across Slack, email, the Web UI, and the API. When submitting an event programmatically, you may encounter:
### Unauthorized Access
Occurs when the API token is missing or invalid.
### Forbidden Actions
Triggered when the token does not have permission to modify the incident.
### Validation Errors
May occur if required fields are missing, formats are invalid, or the incident cannot accept changes in its current lifecycle state.
### Incorrect Incident ID
If the incident does not exist or cannot be accessed by your integration.
Most validation failures can be resolved by verifying that the target incident exists, your API token has the correct permissions, and event text and visibility values match expected formats.
***
## Troubleshooting
Ensure the incident ID is correct and the API token has permission to update the incident.
Provide an explicit occurred time when backfilling or submitting historical events.
These are added after initial creation. First create the event, then attach services or functionalities using their respective endpoints.
Verify that the visibility is set to external. Internal events are not displayed publicly.
Confirm that your token has update/delete permissions and that the event is editable (some system events are intentionally locked).
***
## Best Practices
* **Keep event messages concise**\
The timeline should tell a clear, readable story.
* **Attach context after creation**\
Tagging services and functionalities improves investigative clarity.
* **Automate high-frequency or system-driven updates**\
Let your monitoring and tooling contribute directly to the timeline.
* **Avoid sending overly verbose machine logs**\
Link to deeper logs instead of pasting large blocks of text.
* **Use explicit timestamps for backfilled entries**\
This helps maintain an accurate historical sequence.
* **Maintain consistent formatting**\
Standard phrasing (for example, “Deployment started…”, “Alert triggered…”) improves readability in retrospectives.
* **Integrate with workflow-based automations**\
API-created events can trigger or complement workflows for notifications, assignments, or analytics.
# Incident Timeline
Source: https://docs.rootly.com/incidents/incident-timeline/incident-timeline
Understand how Rootly incident timelines capture key events, decisions, status changes, and system signals throughout the incident lifecycle for retrospectives.
## How Timelines Work
The incident timeline is the **authoritative record of what happened during an incident**. It brings together updates from people, systems, automations, and communication channels into one clear, chronological narrative.
Timelines help responders stay aligned during active incidents and make retrospectives far more accurate by capturing everything in one place.
This page introduces how timelines work, why they matter, and how they fit across the incident lifecycle.
***
## Why Timelines Matter
A well-maintained timeline supports every phase of the incident lifecycle. Timelines help teams:
* Build a shared understanding of what is happening
* Avoid losing critical context in Slack threads or meetings
* Track decisions and actions across engineering, support, and comms
* Maintain a consistent audit trail for compliance and reporting
* Strengthen retrospectives with accurate, timestamped history
* Align stakeholders with clear, trustworthy incident narratives
Rootly automatically logs many events, and responders can contribute additional context from wherever they work—Slack, email, the web UI, or automation.
Timelines ensure the full story of an incident is captured, even when many responders contribute different pieces of information.
***
## What Appears in the Timeline
Timelines combine both **human-generated** and **system-generated** events.
Examples include:
* Status transitions (Triage → Mitigated → Resolved)
* Role assignments or reassignments
* Slack messages captured as timeline events
* Email replies
* Attachments or uploaded files
* Alert updates or linked monitoring signals
* Workflow-triggered actions
* Decisions, notes, and investigative steps
* System events such as channel membership changes
Each event includes:
* Event text or description
* Who performed the action (person or system)
* Timestamp of occurrence
* Source (Slack, Web, Email, API, etc.)
* Optional attachments
* Optional affected services/functionality
* Optional visibility (internal vs. external)
***
## Where Timelines Appear in Rootly
### **On the Incident Detail Page (Web UI)**
The timeline appears as a chronological feed where responders can read, filter, star, export, and contribute events.
Responders can:
* Add structured events
* Upload attachments
* Adjust timestamps
* Star critical entries
* Filter system vs. responder events
* Export the timeline for reporting or retrospectives
### **In Slack**
If Slack is integrated, responders can:
* Add events using modals
* Convert Slack messages into timeline events
* React to workflow prompts to supply investigation notes
* View system updates reflected in the timeline
This makes it easy to contribute during real-time response, when most work happens in chat.
### **Via Email**
Replies to an incident email thread automatically appear in the timeline.\
This allows cross-functional teams (customer support, success, leadership) to contribute context from their preferred communication channel.
### **Via API**
Engineering and SRE teams can integrate CI/CD systems, automated diagnostics, monitoring tools, or runbooks to create timeline entries programmatically.
***
## How Timelines Support the Response Process
Timelines are deeply connected to how Rootly orchestrates incident response:
* Retrospectives pull directly from timeline events
* Status changes, assignments, and communications are logged automatically
* Workflows rely on structured events for decision logic
* External timelines (if enabled) use timeline visibility settings
* Investigation notes help later teams onboard quickly
* Incident analytics use timeline data for MTTx measurements
High-quality timeline entries improve clarity during response and dramatically increase the usefulness of retrospectives afterward.
***
## Where to Go Next
These pages explain how to add events through each method:
* [**Add Events via Slack**](/incidents/incident-timeline/adding-events-to-timeline-via-slack) – Capture notes, message actions, attachments, and updates
* [**Add Events via Web Interface**](/incidents/incident-timeline/adding-events-to-timelines-in-the-web-ui) – Use structured fields to record detailed events
* [**Add Events via Email**](/incidents/incident-timeline/adding-events-to-timeline-via-email) – Ensure email replies are logged in the timeline
* [**Add Events via API**](/incidents/incident-timeline/adding-events-via-api) – Automate system-generated timeline entries
***
## Best Practices
* **Capture important decisions explicitly**\
Don’t rely on Slack threads—add events that explain key choices or pivots.
* **Add investigation updates as they happen**\
Even brief notes improve clarity for downstream responders and retrospectives.
* **Use visibility settings intentionally**\
Internal vs. external timeline events should align with your communication guidelines.
* **Star key milestones**\
Highlight major actions like mitigations, rollbacks, or customer updates.
* **Automate system signals**\
Use the API or workflows to consistently record deployments, alerts, or diagnostics.
* **Review the timeline during retrospectives**\
The timeline often surfaces root causes, delayed decisions, or communication gaps.
***
## Frequently Asked Questions
No. Rootly logs many events automatically—status changes, alerts, workflow actions, role updates, and Slack channel events.\
Responders simply add additional context as needed.
Timeline ordering is based on the **occurred\_at** timestamp.\
If you adjust timestamps or add events retroactively, the position may shift.
Only when captured intentionally—either using the event modal, message actions, or configured workflows.\
Regular Slack messages are not automatically converted.
Yes. Timeline events can be marked **internal** or **external**.\
Only external events appear on public or customer-facing timelines.
Yes. You can toggle system events on/off in the timeline view to reduce noise.
The Web UI includes an **Export Timeline** option, allowing you to download timeline data for retrospectives, compliance, or reporting.
Yes. Using the Rootly API, workflows, or integrations, systems can add structured timeline events programmatically.
***
## Related Pages
The umbrella page covering how incidents work end-to-end.
Adjust lifecycle timestamps that surface on the timeline as events.
Where the completed timeline gets referenced during post-incident review.
# Incident management lifecycle in Rootly
Source: https://docs.rootly.com/incidents/incidents
Understand how Rootly streamlines incident response through automated detection, paging, triage, and response workflows across your entire incident lifecycle.
## How Rootly Works
Rootly provides an end-to-end incident management platform that helps your teams detect issues quickly, coordinate a response, and learn from every incident. This page walks through the main phases of the incident lifecycle in Rootly and points you to where each phase lives in the product and documentation.
### Incident Lifecycle at a Glance
Most teams move through a common flow:
1. Detect a potential issue from alerts.
2. Create an incident (manually or automatically).
3. Triage and understand impact.
4. Coordinate a response across teams.
5. Resolve the incident.
6. Run a retrospective and track follow-ups.
7. Use analytics to improve over time.
Each of these phases maps to specific areas in Rootly, described below.
### Detection & Alerting
Rootly starts working as soon as your monitoring or observability tools notice something is wrong. You can connect sources like Datadog, Grafana, Sentry, cloud provider alerts, or any system capable of sending webhooks.
Once connected, alerts flow into Rootly and can:
* Create incidents automatically based on your rules.
* Attach to existing incidents to provide additional context.
* Drive paging via your escalation policies.
To learn more about setting up detection, look for the [**Alert Sources**](/alerts/alerts) and [**Integrations**](/integrations/overview) documentation.
Use **Alert Sources** to connect monitoring tools and define which alerts should create or update incidents.
### Creating Incidents
Incidents are the core record of “something is wrong” in Rootly. You can create them:
* Manually from the UI (for example when someone reports an issue in Slack or via support).
* Automatically from alerts when certain conditions are met.
* Via automations or external systems (Slack commands, CI/CD pipelines, etc.).
When a new incident is opened, Rootly prompts you for key **incident properties** such as severity, impacted service, type, and any custom fields your team has defined. These properties drive workflows, routing, and reporting later.
For more detail, see the [**Creating Incidents**](/incidents/creating-incidents/creating-incidents-via-web-ui) documentation.
### Triage & Assess
Once an incident exists, the first step is understanding how bad it is and who needs to be involved. On the incident detail page, responders can:
* Update **status** (for example: Open, In Triage, Mitigated, Resolved).
* Adjust **severity** and affected **services** to reflect impact.
* Attach related alerts and signals.
* Assign an **incident commander** and other roles.
* Capture notes, hypotheses, and decisions in one place.
This is also where you will see the evolving **incident timeline**, including changes, assignments, notifications, and actions taken.
Look for the [**Incident Lifecycle**](/incidents/incident-lifecycle) and **Triage Incidents** docs for a deeper dive into statuses, roles, and best practices.
Most lifecycle actions—status changes, severity updates, assignments, and alert attachments—live on the **Incident Detail** page.
### Respond & Coordinate
During an active incident, Rootly helps keep everyone aligned and reduces manual coordination work.
Typical activities include:
* Synchronizing updates to Slack or other chat tools.
* Notifying stakeholders and leadership on a predictable cadence.
* Posting updates to status pages.
* Creating and tracking action items or tasks.
* Running automation (for example, calling runbooks or external tools).
This behavior is usually powered by **Workflows** that react to incident events (like “status changed to Mitigated” or “severity is SEV0”) and perform actions for you.
To see what’s possible, explore the [**Workflows**](/workflows/workflows) and [**Communication & Notifications**](/notifications/getting-started) documentation.
Workflows are a powerful way to standardize how your organization responds to incidents, without responders having to remember every step manually.
### Resolve the Incident
When the underlying issue has been mitigated or fully fixed, the incident is moved to a **Resolved** state.
At this point, Rootly can:
* Run “on-resolve” workflows (for example, notify stakeholders, close tickets, or clean up temporary channels).
* Enforce required fields, such as root cause, impact summary, or customer communication notes.
* Trigger the creation of a retrospective automatically based on your rules.
If you want to control what must be filled out before resolution, see the **Incident Properties** or **Required Fields** documentation.
Many teams configure a workflow that automatically creates a retrospective when an incident’s status changes to **Resolved**.
### Retrospectives
After resolution, the focus shifts to learning. Rootly’s **Retrospectives** provide a structured way to:
* Document what happened and when.
* Capture contributing factors and underlying causes.
* Record customer impact and communication.
* Create and assign follow-up actions.
* Share outcomes with stakeholders.
Retrospectives are linked directly to the incident and use the same properties (like service and severity) so they can be analyzed alongside other incidents.
To learn more about templates, workflows, and best practices, see the [**Retrospectives**](/retrospectives/retrospectives) documentation.
Rootly uses the term **Retrospective** instead of “postmortem,” but you can mirror whatever language your team prefers in templates and forms.
### Analytics & Insights
Rootly automatically records every incident, alert, and lifecycle change so you can answer questions like:
* How quickly do we detect and resolve incidents (MTTD, MTTR)?
* Which services or teams are seeing the most incidents?
* Are certain severities increasing over time?
* Are retrospectives being completed and action items followed up?
The **Incident Analytics** documentation explains the available dashboards, filters, and metrics, and how to slice your data by properties such as service, severity, or type.
### Incident Properties
Incident properties are the fields that describe an incident and drive automation. They can be:
* **Built-in fields** like title, severity, status, and impacted services.
* **Custom fields** defined by your organization (for example, customer segment, region, product area, or incident type).
These properties are used to:
* Categorize and filter incidents during triage.
* Power workflow conditions (for example, “page leadership when severity is SEV0”).
* Enforce required information at different lifecycle stages.
* Break down analytics by whichever dimensions matter to you.
You can manage and customize these fields in the **Incident Properties / Form Fields** settings, and you can read more in the dedicated [**Incident Properties**](/configuration/configuration) documentation.
A common pattern is to start with a simple set of properties (severity, service, type) and expand over time as analytics needs become clearer.
### Where to Go Next
If you’re just getting started, here are good follow-up pages to link from here:
* [**Incidents**](/incidents/creating-incidents/creating-incidents-via-web-ui) – how to create, view, and manage incidents.
* [**Alert Sources**](/integrations/datadog/datadog) – how to connect monitoring tools and route alerts.
* [**Workflows**](/workflows/workflows) – how to automate response and communications.
* [**Retrospectives**](/retrospectives/retrospectives) – how to document and learn from incidents.
* [**Incident Analytics**](/metrics/default-metrics) – how to measure and improve your reliability.
* [**Incident Properties**](/configuration/configuration) – how to define the fields that structure your incidents.
## Frequently Asked Questions
Incidents can be created manually from the UI, automatically from alerts, through workflows, or from external tools like Slack or CI/CD pipelines. See **Incidents** or [**Alert Sources**](/alerts/alerts) to learn more.
Use workflows to automate repetitive tasks—paging responders, posting Slack updates, syncing status pages, creating tickets, assigning roles, or creating retrospectives.
Yes. Severity, type, impacted service, and other fields are all customizable through **Incident Properties** and can be used to drive workflows or analytics.
Alerts are incoming signals from monitoring tools. Incidents are the structured record Rootly creates to track and manage an issue. Multiple alerts can attach to the same incident.
***
## Related Pages
The status flow every incident moves through, from triage to closed.
Tasks and follow-ups captured against every incident.
The permanent record of what happened — events, roles, and status transitions.
# Adding Incident Feedback
Source: https://docs.rootly.com/incidents/managing-incidents/adding-incident-feedback
Learn how to submit and manage incident feedback through both the Rootly web interface and Slack. Each user may submit feedback once per incident.
## Overview
Incident feedback helps teams capture what went smoothly during response and where improvements can be made.\
Rootly allows each user to submit **one feedback entry per incident**, either through Slack or the web interface, once the incident reaches **Mitigated** or **Resolved**.
Feedback becomes part of the incident record and is used in retrospectives, follow-up planning, and reliability improvements.
You can only submit feedback once per incident. If you need to update it, you may edit your existing entry through the web interface.
***
## When Feedback Can Be Submitted
Feedback is available only after an incident has reached:
* **Mitigated** — customer impact has stopped
* **Resolved** — the root cause has been fixed
If you attempt to submit feedback before the incident is Mitigated or Resolved, Rootly will block the submission and prompt you to try again later.
***
## Add Feedback Through the Web Interface
Navigate to the incident where you want to leave feedback.
Scroll to the **Feedback** section on the incident page.\
If no feedback exists yet, you will see an option to **Leave Feedback**.\
If you have already submitted feedback, you can select **Edit**.
Provide the following:
Your overall rating of the incident response.
Free-text feedback — what went well, what needs improvement, or context for the rating.
When enabled, your identity is hidden from other responders and stakeholders. Your feedback is still linked to your user for edit access.
Click **Submit** to finalize your feedback.
***
## Add Feedback Through Slack
Responders can also submit feedback directly in the incident’s Slack channel.
In the incident channel, type:
`/incident feedback`
or
`/rootly feedback`
Rootly will open a feedback submission modal.
Fill in the same fields as the Web flow:
Your overall rating of the incident response.
Free-text feedback — what went well, what needs improvement, or context for the rating.
When enabled, your identity is hidden from other responders and stakeholders. Your feedback is still linked to your user for edit access.
Once submitted, your feedback is saved and can be viewed from the web interface.
Slack feedback commands must be run **inside the incident channel**, as Rootly identifies the incident using the channel ID.
***
## What Happens After Feedback Is Submitted
After your feedback is recorded:
* It is linked to your user and the incident
* You cannot submit a second feedback entry
* You *can* edit your existing feedback through the web interface
* Anonymous feedback hides your identity from other responders and stakeholders
* Feedback becomes available for retrospectives and process improvement reviews
***
## Troubleshooting
The incident may still be active.\
Feedback is only available after **Mitigated** or **Resolved**.
Ensure you ran the command **inside the incident channel**.\
Commands executed elsewhere cannot be mapped to an incident.
You can edit feedback at any time from the **web interface**.\
Slack does not support editing after submission.
Verify whether the **anonymous** checkbox was selected during submission.\
You can change this setting by editing the feedback on the web.
Confirm:
* The incident is Mitigated or Resolved
* You have permission to submit feedback
* The Rootly Slack app has access to the channel
* You are running the command in the correct incident channel
***
## Best Practices
* **Submit feedback as close to resolution as possible**\
Context fades quickly; timely feedback is more accurate.
* **Be specific and actionable**\
Comments such as “unclear ownership during triage” or “alert was noisy” help teams make targeted improvements.
* **Use anonymity when necessary**\
Anonymous submissions can encourage more candid insights.
* **Incorporate feedback into retrospectives**\
Reviewing user feedback alongside incident timelines provides richer context.
* **Automate reminders to leave feedback**\
Many teams configure workflows that prompt responders to submit feedback immediately after the incident transitions to Resolved.
* **Encourage all responders to participate**\
Broader participation leads to more comprehensive insights across teams and roles.
***
## Related Pages
Where feedback fits in the post-mitigation flow.
Where feedback often surfaces as an input for the post-incident review.
The umbrella page covering how incidents work end-to-end.
# Managing Incident Status via Slack
Source: https://docs.rootly.com/incidents/managing-incidents/managing-incident-status-via-slack
Step-by-step guide to updating incident lifecycle status directly from an incident's Slack channel using Rootly slash commands and interactive status modals.
## Overview
Slack lets responders update incident status in real time—without switching to the web interface.\
Using `/rootly status` (and related quick actions), you can move an incident through its lifecycle, capture required context, and keep all Timeline entries accurate and audit-ready.
Use Slack status updates when your team needs fast, in-channel lifecycle changes during active response.
***
## Prerequisites
Before updating an incident via Slack:
* You **must run commands inside the incident’s Slack channel**\
(Commands do not work from random channels or DMs.)
* You must have **permission to update incidents** based on your workspace’s roles and access settings.
* The Slack integration must be installed and Rootly must have access to the channel.
If a command “does nothing,” you are likely not in an incident channel. Try again inside the correct channel.
***
## Updating Status with `/rootly status`
In the incident’s Slack channel, type:
```text theme={null}
/rootly status
```
This opens a modal showing the available incident lifecycle statuses your team has enabled (Triage, Started, Mitigated, Resolved, Cancelled, etc.).
Choose the appropriate status for the incident, then click **Submit**.
Rootly will:
* Update the Incident Status
* Record the change in the Timeline
* Trigger any associated workflows (notifications, role assignment, stakeholder updates, etc.)
* Sync the new status back to the web interface
***
## Supported Quick Actions
Slack also supports shortcut commands for common lifecycle operations:
| Command | Description | Where It Works |
| :----------------------------------- | :-------------------------------------- | :------------------------------------- |
| `/rootly resolve` | Resolve the incident | Must be inside incident channel |
| `/rootly cancel` | Cancel the incident | Must be inside incident channel |
| `/rootly mitigate` | Mark mitigated | May be blocked if sub-statuses enabled |
| `/rootly status` | Open modal to choose any allowed status | Must be inside incident channel |
| `/rootly new` / `create` / `declare` | Create a new incident | Works in any channel |
If your workspace uses **Sub-Statuses**, `/rootly mitigate` will be blocked. Rootly will prompt you to use your sub-status flow instead.
***
## Important Behavior & Guardrails
### Required Fields Enforcement
If your workspace enforces required fields for lifecycle transitions, you may see an error when attempting to update status through Slack.
For example:
* Moving from Started → Resolved may require a Severity or Impact Summary
* Moving out of Triage may require Service or Environment
The Slack modal will clearly indicate what is missing.
### Sub-Statuses and Mitigation
If your organization has Sub-Statuses enabled, Rootly disables `/rootly mitigate` to prevent conflicts.\
You’ll see a message indicating mitigation must be performed through the sub-status workflow.
### Scheduled Incidents
Slack lifecycle commands (mitigate/resolve/cancel) are **not supported for scheduled incidents**.\
You must use the Web UI to update scheduled maintenance lifecycle states.
***
## Troubleshooting
* You are likely not inside an incident channel.
* Use `/rootly status` **inside the incident’s Slack channel**.
Check your incident role or team permissions:
* Only authorized users may update incident status.
Your workspace is enforcing **required fields** for the next lifecycle status.\
Fill the missing fields in the Slack modal or in the Web UI.
Your workspace uses **Sub-Statuses**, so mitigation must be done via the sub-status flow.
***
## Best Practices
* Use `/rootly status` during response to maintain clean, accurate lifecycle transitions.
* Add short notes when submitting the modal—these appear in the Timeline and help with retrospective analysis.
* Use `/rootly resolve` when service is restored; complete post-incident tasks later in the Web UI.
* Keep lifecycle updates in Slack concise and consistent so responders always understand the current state.
# Resolving Incidents via Slack
Source: https://docs.rootly.com/incidents/managing-incidents/resolving-incidents-via-slack
Resolve incidents directly from Slack using Rootly's /rootly resolve command and status update modal to capture resolution context and trigger retrospectives.
## Overview
Slack allows responders to resolve incidents directly from the incident channel—no need to switch to the web interface.\
Using **`/rootly resolve`**, you can mark an incident as fully resolved, provide a short summary of the fix, and trigger any workflows your team has configured for this stage.
All actions performed in Slack are captured in the Timeline, synchronized to the web UI, and used for analytics and retrospectives.
***
## Prerequisites
Before resolving an incident through Slack:
* You must run commands **inside the incident’s Slack channel**.\
Rootly identifies the incident by the channel ID; commands run in other channels or DMs won’t work.
* You must have permission to update incidents.\
Organizations may restrict who can transition lifecycle states.
* Slack lifecycle commands are **not supported for scheduled incidents**.\
Scheduled maintenance must be updated in the web interface.
If `/rootly resolve` appears unresponsive, you are likely not inside an active incident channel.
***
## Resolving an Incident with `/rootly resolve`
In the incident’s Slack channel, type:
**`/rootly resolve`**
Rootly will display a confirmation dialog prompting you to provide a resolution summary and finalize the update.
Enter a concise explanation of the final fix or corrective action.
This summary becomes part of the permanent Timeline and is often used in:
* Retrospectives
* Stakeholder communications
* Status page updates (if configured)
* Internal reporting
Clear and direct resolution notes help responders and stakeholders understand what restored service.
Click **Submit** to finalize.
Once submitted, Rootly will:
* Update the incident status to **Resolved**
* Add a Timeline entry with your resolution note
* Trigger any configured “on-resolve” workflows
* Update analytics timestamps
* Automatically set a mitigation timestamp if one was never recorded
* Sync the new status back to the web interface and API
***
## Other Ways to Resolve via Slack
If you prefer a modal-based workflow—or need to review available lifecycle states—you can also resolve an incident using the full status picker.
**Using the Status Modal**
Run:
**`/rootly status`**
This opens the incident lifecycle dialog.\
Select **Resolved**, add any optional notes, and submit.
Both methods—`/rootly resolve` and selecting **Resolved** inside `/rootly status`—perform the same lifecycle transition.
***
## Troubleshooting
* You are likely not inside the incident’s Slack channel.
* Run the command again **inside the correct channel**, where Rootly can match the channel ID to an incident.
You may not have sufficient role or team permissions to modify incident status.\
Check with your Rootly administrator to confirm your permissions.
Your workspace may enforce **required fields** before moving to Resolved.\
The Slack modal clearly lists any fields that must be completed.
Slack lifecycle commands do **not** support scheduled maintenance incidents.\
Use the web interface to update scheduled incident lifecycle states.
Rootly resolves linked PagerDuty incidents only if:
* The incident is linked to a PagerDuty incident
* The PagerDuty integration has **auto-resolve** enabled
Resolving an incident directly in PagerDuty does **not** update or resolve the incident in Rootly.
***
## Best Practices
* **Add informative resolution notes.**\
These appear in timelines, retrospectives, stakeholder notifications, and status pages.
* **Use Slack to move quickly during active response.**\
Fast, in-channel updates help keep everyone aligned.
* **Resolve incidents through Rootly—not PagerDuty.**\
Rootly syncs to PagerDuty, but PagerDuty does not sync back.
* **Automate repetitive actions.**\
Use workflows to send final updates, publish status page events, initiate retrospectives, or archive Slack channels.
* **Check required fields early.**\
Completing required information during the incident avoids blockers at resolution time.
# Resolving Incidents via Web Interface
Source: https://docs.rootly.com/incidents/managing-incidents/resolving-incidents-via-web-ui
Move incidents through the Mitigated and Resolved stages using the Rootly web interface to capture timestamps, mitigation notes, and resolution details.
## Overview
The Rootly web interface provides a guided, reliable way to move an incident toward closure. Whether you are stabilizing an issue or fully resolving it, the web UI ensures each lifecycle transition is documented, timestamped, and tied to the workflows and notifications your team depends on.
Status updates made through the interface become part of the incident’s permanent timeline, reinforcing transparency, improving retrospective accuracy, and standardizing how your organization reports and closes incidents.
***
## Marking an Incident as Mitigated
Mitigation communicates that the **immediate impact has been contained**, even if longer-term remediation is still underway.
Teams often use this step when a temporary fix, rollback, or workaround restores functionality while engineers continue to diagnose or implement a permanent solution.
Navigate to the incident’s detail page in the Rootly web interface.\
The status action buttons are displayed prominently in the incident toolbar.
Select **Mark as Mitigated** when customer impact has ended or stabilized.
Use Mitigated as soon as impact stops—even if engineering work continues behind the scenes.\
This helps stakeholders understand that conditions have improved.
A dialog will appear prompting you to describe what actions were taken to stabilize the situation.
These notes will appear in:
* Incident timelines
* Retrospectives
* Status updates
* Stakeholder notifications (if configured)
Clear mitigation notes help downstream teams—support, customer success, leadership—understand when and how conditions improved.
Click **Mark as Mitigated** again to finalize the update.
Rootly will:
* Record the mitigation timestamp
* Add a timeline entry
* Trigger any mitigation workflows, such as Slack announcements or status page updates
* Sync the change back to Slack and API clients
Mitigating an incident is optional. If your workflow does not require this intermediate state, you may proceed directly to resolution.
***
## Marking an Incident as Resolved
Resolution indicates that the **underlying cause has been fully addressed** and no further customer impact is expected.\
This is the final lifecycle stage for most incidents before retrospective work begins.
When the fix or corrective action is complete, click **Mark as Resolved** in the toolbar.
It’s best to resolve only when the team is confident the issue will not recur under the current conditions.
A dialog will prompt you to summarize the final fix or corrective action.\
This explanation becomes a key part of the incident’s historical record.
Resolution notes should briefly describe *what was done*, *why it worked*, and *any remaining follow-up*.
Click **Mark as Resolved** again to close the incident.
Rootly will:
* Record the resolution timestamp
* Log a timeline entry
* Trigger “on-resolve” workflows such as stakeholder announcements, ticket closures, or retrospective creation
* Update any connected systems such as Slack or Status Pages
If an incident is resolved without being mitigated first, Rootly automatically assigns a mitigation time equal to the resolution time.\
This keeps analytics—especially MTTR and phase durations—accurate and consistent.
***
## Troubleshooting
This typically means:
* Required fields have not been completed
* You do not have permission to update lifecycle status
The interface will highlight any missing fields.
Your workspace may enforce structured lifecycle transitions.\
You may need to advance through statuses in order or return to a previously visited state.
Resolution syncing requires:
* A linked PagerDuty incident
* Auto-resolve enabled in the integration settings
When configured, Rootly resolves both the PD incident and its alerts.
If you resolve without mitigating, Rootly automatically sets the mitigation time to match the resolution time.\
This ensures consistent and meaningful analytics.
***
## Best Practices
* **Write clear, concise mitigation and resolution notes**\
These notes appear in timelines, retrospectives, Slack updates, and status pages. They help responders and stakeholders quickly understand what changed and why.
* **Use mitigation to separate “impact ended” from “work completed”**\
This distinction improves customer communication, stakeholder clarity, and metrics.
* **Always resolve incidents through Rootly**\
If PagerDuty auto-resolve is enabled, Rootly will update the PD incident automatically.\
Resolving directly in PagerDuty does **not** update Rootly.
* **Automate repetitive closure activities**\
Many teams use workflows to:
* Send final Slack updates
* Publish status page messages
* Create retrospectives
* Archive Slack channels
* Notify leadership or customers
* **Complete required fields early**\
Some organizations require specific information (for example, customer impact, affected services, root cause category) before resolution.\
Filling these fields earlier avoids blockers late in the incident.
* **Review the timeline after resolving**\
Ensuring all key actions, decisions, and updates are recorded helps support strong retrospectives.
# Updating Incident Integration Links
Source: https://docs.rootly.com/incidents/managing-incidents/updating-incident-integration-links
View, edit, and update external integration links for incidents through both the Rootly web interface and Slack to keep Jira, ticketing, and docs in sync.
## Overview
Many incidents rely on external systems—ticketing tools, documentation platforms, notebooks, meeting links, and on-call providers.\
Rootly centralizes these external references by allowing teams to store and update integration links directly on the incident.
These links may be:
* Automatically created by integrations
* Generated through workflows
* Manually added or corrected by responders
You can update integration links through both the Rootly web interface and the Rootly Slack bot.
The list of editable links depends on which integrations your workspace has enabled. Only integrations your team has configured will appear in the editor.
***
## Editing Integration Links via the Web UI
Navigate to the incident whose integration links you want to modify.
In the **Integrations** section of the incident page, click **Edit Integrations**.
This opens a modal listing all editable integration link fields—for example, Jira, Asana, PagerDuty, Google Drive, Zoom, Confluence, and others.
Each field represents an external system link. You may:
* Replace an existing URL
* Add a missing link
* Leave the field blank to remove it
All links require a valid URL format.
Click **Update** to apply your changes.
Your updated links will immediately appear in the Integrations section of the incident.
Use the web interface when updating multiple links at once or when cleaning up links after workflows or automations.
***
## Editing Integration Links via Slack
You can also update integration links without leaving Slack.\
This is useful during active response when responders are working primarily in the incident channel.
There are two ways to open the integration editor in Slack.
***
### Option 1: Use the Pinned Incident Overview
When viewing an incident channel, the pinned incident summary includes an **Integrations** section with an **Edit** button.
Clicking **Edit** opens the same integration editor modal used in the web interface.
***
### Option 2: Use the Slash Command
You can also open the integration editor by typing:
/incident integration
inside the incident channel.
Rootly will open a modal where you can update any of the available integration links.
Slack commands must be run inside the **incident channel**.\
Rootly identifies the incident based on the channel ID.
***
## Which Integrations Can Be Edited?
The integrations editor displays only the links that apply to the integrations your team has enabled.\
Common examples include:
* Jira
* Asana
* PagerDuty
* ServiceNow
* Zendesk
* GitHub
* Linear
* Confluence
* Google Drive / Google Docs / Google Meet / Google Calendar
* Zoom / Webex / GoToMeeting
* Trello
* Notion
* Shortcut
* Coda
* Airtable
* Datadog Notebook
If an integration is installed but a link was not automatically created, you can manually add it here.
***
## Troubleshooting
Your workspace may not have any integrations enabled for this incident type.\
Only integrations your team has configured will appear.
Make sure you are running the command **inside the incident channel**.\
Commands sent from other channels or DMs cannot be mapped to an incident.
Integration links must be valid URLs.\
Invalid or improperly formatted URLs will cause a validation error.
You may not have permission to update incidents.\
Check your incident role or workspace access settings.
Only integrations with active workspace configuration appear.\
Ensure the integration is fully set up under **Configuration → Integrations**.
***
## Best Practices
* **Use workflows to automatically generate links**\
For example, create Jira issues or PagerDuty incidents automatically and populate the link fields.
* **Maintain consistency across incident types**\
Standardizing where each system’s link is stored makes retrospectives and auditing much easier.
* **Remove outdated or incorrect links**\
Leaving fields blank clears stale or incorrect values to avoid confusion later.
* **Encourage responders to update links early**\
Accurate integration links ensure the right systems stay connected throughout the lifecycle.
* **Use Slack for quick updates, Web UI for bulk editing**\
Slack is ideal during active response; the web interface is better for comprehensive cleanup.
***
## Related Pages
The scribe targets whichever meeting URL is attached — updating the link changes what it joins.
Where integration link updates surface on the timeline.
The umbrella page covering how incidents work end-to-end.
# Updating Incident Timestamps
Source: https://docs.rootly.com/incidents/managing-incidents/updating-incident-timestamps
Update incident timestamps in Rootly for accurate event documentation, compliance tracking, retrospective analysis, and SLA reporting after the fact.
## Overview
Incident timestamps are crucial for accurately documenting events, enabling precise tracking and analysis of occurrences. Not only are incident timestamps essential for legal and compliance purposes, they are also the foundation to tracking the quality and efficiency of your incident response process.
***
## Available Timestamps
Each Rootly incident comes by default with the following timestamps:
| Name | Required? | Description | Liquid Variable |
| ------------ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
| In Triage | No | Before an incident starts, it can go through a triage state. This timestamp is automatically logged when the incident enters the `in_triage` state. | `{{ incident.in_triage_at }}` |
| Started | Yes | This marks the official start of an incident. This timestamp is automatically logged when the incident enters the `started` state. | `{{ incident.started_at }}` |
| Detected | No | This marks the time when the response team is informed. For many teams, the time in which the incident starts is also the time in which their responder team is informed. There is no "detected" state, so this timestamp is NOT automatically logged out of the box. Teams can manually set it OR automatically set it through workflows. | `{{ incident.detected_at }}` |
| Acknowledged | No | This marks the time when the response team acknowledges that they are looking into the incident. For many teams, this timestamp is often tied to when the first responder acknowledges the page through an on-call solution (for example, Rootly On-Call, PagerDuty, Opsgenie, etc.). There is no "acknowledged" state, so this timestamp is NOT automatically logged out of the box. Teams can manually set it OR automatically set it through workflows. | `{{ incident.acknowledged_at }}` |
| Mitigated | Yes | This marks the time in which the impact of the incident is halted. This does NOT signify the end of an incident. This timestamp is automatically logged when the incident enters the `mitigated` state. | `{{ incident.mitigated_at }}` |
| Resolved | Yes | This marks the time in which the incident is resolved and all systems are running as normal. This timestamp is automatically logged when the incident enters the `resolved` state. | `{{ incident.resolved_at }}` |
| Cancelled | No | This marks the time in which the incident is cancelled. This timestamp is automatically logged when the incident enters the `cancelled` state. | `{{ incident.cancelled_at }}` |
***
## Updating Timestamps
### Manually Via Slack
Timestamps can be updated through the Rootly Slack bot by using the /incident timestamps Slack command.
### Manually Via Web UI
Timestamps can also be updated through the Rootly web UI from the Incident Details page.
Click on any timestamp at the top right hand corner of a specific incident.
A modal will pop up to allow you to edit each timestamp.
***
### Automatically Via Workflow
By default, Rootly will automatically log the *In Triage*, *Started*, *Mitigated*, and *Resolved* timestamps when the incident cycle enters those corresponding states. For the timestamps that Rootly does not automatically log out of the box (*Detected* and *Acknowledged*), you can use a workflow to automate the logging. This method will work with all timestamps.
To automate via workflow, you'll want to trigger a workflow following a specific event that updates the timestamp using the **Update Incident** workflow action.
Then, use the following syntax in the Custom Field Mapping input textarea to systematically update the acknowledged timestamp.
```txt Custom Field Mapping theme={null}
{ "acknowledged_at": "" }
```
**ISO 8601 Format:** YYYY-MM-DD HH:MM:ss +/-0X00
Example:
* 2024-07-26 16:07:46 -0400 means July 26, 2024 at 4:07 PM in a timezone that is 4 hours behind UTC
Liquid syntax is supported in this input text area so you can dynamically set the time by referencing a Liquid variable.
***
## Metrics Calculations
Each timestamp plays an important role in calculating the metrics of an incident across the overall organization. The following is the math behind each calculated value:
| Value | Format | Formula |
| ---------------------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| Time to Mitigation `{{ incident.time_to_mitigation }}` | Integer in hours | `{{ incident.mitigated_at }}` - `{{ incident.started_at }}` |
| Mitigation Duration `{{ incident.mitigation_duration }}` | Integer in seconds | `{{ incident.mitigated_at }}` - `{{ incident.started_at }}` |
| Time to Detection `{{ incident.time_to_detection }}` | Integer in hours | `{{ incident.detected_at }}` - `{{ incident.started_at }}` |
| Detection Duration `{{ incident.detection_duration }}` | Integer in seconds | `{{ incident.detected_at }}` - `{{ incident.started_at }}` |
| Time to Acknowledge `{{ incident.time_to_acknowledge }}` | Integer in hours | `{{ incident.acknowledged_at }}` - `{{ incident.started_at }}` |
| Acknowledge Duration `{{ incident.acknowledge_duration }}` | Integer in seconds | `{{ incident.acknowledged_at }}` - `{{ incident.started_at }}` |
| Time to Resolution `{{ incident.time_to_resolution }}` | Integer in hours | `{{ incident.resolved_at }}` - `{{ incident.started_at }}` |
| Incident Duration `{{ incident.duration }}` | Integer in seconds | If resolved, `{{ incident.resolved_at }}` - `{{ incident.started_at }}`
If not resolved, `now - {{ incident.started_at }}` |
## Troubleshooting
The timestamp may conflict with another field. For example, a mitigation time cannot occur before the incident starts. Update related timestamps to maintain chronological order.
You may not have run the command inside the incident’s Slack channel. Slack commands outside the incident channel cannot be mapped to an incident.
Certain timestamps only appear when the incident is in the corresponding lifecycle state. For example, Mitigated and Resolved timestamps appear only after those transitions occur.
The incident is a scheduled maintenance event. Scheduled incidents use Scheduled From and Scheduled Until instead of lifecycle fields.
Refresh the page and verify that all timestamps follow chronological order. Incorrect ordering may cause metrics to appear inconsistent.
***
## Best Practices
* **Align on timestamp definitions** to avoid interpretation differences across teams.
* **Use automation whenever possible** to promote consistent and reliable data.
* **Review timestamps during retrospectives** to ensure accuracy before finalizing the incident.
* **Maintain chronological order** so that insights and dashboards remain accurate.
* **Prefer the Web UI for bulk adjustments**, especially when updating several timestamps.
* **Update timestamps promptly** to avoid confusion around when key actions occurred.
***
## Related Pages
Where lifecycle timestamps appear as timeline events.
Which timestamps exist per lifecycle stage and what updating them affects.
The umbrella page covering how incidents work end-to-end.
# Managing Private Incident Access via Slack
Source: https://docs.rootly.com/incidents/private-incidents/manage-via-slack
Learn how to manage and control access to private incident channels directly through Slack using Rootly’s access management commands and modal.
## Overview
Private incidents allow teams to restrict who can see sensitive discussions, customer details, or internal system information.\
Using Rootly’s Slack integration, you can add or remove authorized responders directly from the incident’s Slack channel—without switching to the web interface.
The Slack access modal mirrors the same controls available in the Rootly UI and ensures only approved users can view or participate in private incident channels.
These actions only work inside a **private incident channel**, and require appropriate permissions to manage access.
***
## Manage Access via Slack
Navigate to the private incident channel in Slack.\
Access controls only work from within the correct incident channel.
You can open the access modal in two ways:
**Option A: Slash command**
Type one of the following commands and press Enter:
* `/rootly manage`
* `/rootly access`
* `/rootly users`
**Option B: Button in the pinned incident summary**
Click **Manage Access** in the pinned Rootly block at the top of the channel.
The access modal displays:
* A **multi-select list** showing all users who currently have access
* A **search box** to add additional users
* A **checkbox** titled **Remove Unauthenticated Users**
**To add users:**\
Start typing a name and select any user to grant them access immediately.
**To remove users:**\
Click the **×** next to their name in the selected users list.
The checkbox **“Remove Unauthenticated Users”** does **not** remove all users you didn’t select.\
Instead, it automatically removes *anyone who does not have permission to view private incidents* based on RBAC.
Click **Update** to apply the changes.\
Rootly will add or remove Slack channel members accordingly.
***
## What Happens After Updating Access
When you save changes:
* Users added gain access to the private incident immediately
* Users removed are removed from the Slack channel
* Removed users *may* receive a Slack notification depending on workspace settings
* Rootly updates the list of authorized incident subscribers
* Any user who lacks private-incident read permission can be automatically removed if the checkbox was selected
Slack may prevent automatic removal if your workspace restricts channel membership management.\
In those cases, Rootly attempts removal but Slack may reject the action.
***
## Best Practices
* **Use the checkbox when cleaning up access**\
It ensures only users with the correct private incident permissions remain in the channel.
* **Be intentional about adding observers**\
Private incidents often involve sensitive operational or customer data.\
Grant access sparingly.
* **Review access during major incident transitions**\
For example, as roles shift or when incident severity changes.
* **Use workflows for structured access management**\
Workflows can automatically add on-call engineers, service owners, or leadership groups.
* **Keep private incidents small and focused**\
The fewer people involved, the faster and more aligned your response tends to be.
***
## Troubleshooting
Make sure you ran the command **inside the private incident channel**.\
Rootly identifies the incident by the Slack channel ID.
You may not have permission to manage private incident access.\
Only users with the required RBAC permissions will see the button.
The **Remove Unauthenticated Users** checkbox removes *anyone* who lacks private-incident read permission—even if you had selected them previously.
Some Slack workspaces restrict who can remove members from channels.\
Rootly attempts removal, but Slack may reject it based on workspace policies.
The user must be a Slack workspace member and must have Rootly access in your organization.
# Managing Private Incident Access via Web Interface
Source: https://docs.rootly.com/incidents/private-incidents/manage-via-web
Manage and control access to private incidents in Rootly directly through the web interface, including viewer lists, RBAC overrides, and audit history.
## Overview
Private incidents restrict visibility to only the responders who need to see sensitive operational details, customer information, or internal system context.\
Using the Rootly web interface, you can add or remove authorized users from a private incident—without requiring Slack or modifying RBAC roles.
The **Manage Access** dialog provides full control over incident-level access, matching the functionality available in Slack.
Managing access requires the appropriate permissions.\
Users with *private-incident read* permissions automatically have access; all others must be explicitly added as incident subscribers.
***
## Manage Access via the Web Interface
Navigate to the private incident you want to manage in the Rootly web application.
Click **Manage access**, located directly beneath the incident title.
The access modal includes:
* A **multi-select list** showing all users who currently have access
* A **search field** to add new users
* A **checkbox** titled **Remove users**
**To add users:**\
Begin typing a user’s name. Select a user to immediately grant them access.
**To remove users:**\
Click the **×** beside a user’s name to remove their access.
The checkbox **“Remove users”** does **not** simply remove everyone you didn’t select.\
It removes *any subscriber who does not have private-incident read permission* according to RBAC.
Click **Update users** to apply the changes.\
Rootly will immediately grant or revoke incident-level access based on your selections.
***
## What Happens After Updating Access
After saving your changes:
* Newly added users gain access to the private incident immediately
* Removed users lose access to the incident in Rootly
* If Slack is connected, Rootly attempts to update channel membership accordingly
* Users lacking private-incident read permission may be automatically removed if the checkbox was used
* Access updates apply consistently across Rootly and any connected systems
If Slack workspace permissions prevent Rootly from removing a user from the channel, Rootly still revokes their access within the platform.
***
## Best Practices
* **Use the Remove Users checkbox to clean up access**\
This keeps private incidents restricted to only those with the correct RBAC permissions.
* **Limit access to essential responders**\
Private incidents often contain sensitive or high-impact information; keep the participant list tight.
* **Review access as roles shift**\
During long-running or high-severity incidents, revisit access when responsibilities change.
* **Automate access via workflows**\
Workflows can automatically add on-call responders, service owners, or leadership when private incidents are created.
* **Ensure users have Rootly access first**\
Only Rootly-enabled users can be added as private incident subscribers.
***
## Troubleshooting
You may not have permission to manage private-incident access.\
Only users with the required RBAC permissions or incident roles will see the button.
If the **Remove users** checkbox was selected, Rootly removes all subscribers who lack private-incident read permission—even if they previously had access.
They must be a member of your Rootly organization.\
If they were recently added to Slack or your IdP, they may need to log into Rootly first.
Some Slack workspaces restrict channel member removal.\
Rootly will try to remove them, but Slack may block the action.
Yes—if your workspace has parent→child sync enabled.\
Access changes propagate automatically when this feature is turned on.
# Private Incidents
Source: https://docs.rootly.com/incidents/private-incidents/private-incidents
Learn how private incidents in Rootly restrict access beyond RBAC with incident-level permissions managed through the web UI and Slack for sensitive cases.
## What Are Private Incidents?
Private incidents allow sensitive operational, customer, or security-related information to be restricted to a limited group of responders.\
Unlike standard incidents—where visibility is governed solely by workspace-wide RBAC—**private incidents add a second layer of access control**.
In Rootly, users may gain access to a private incident in two ways:
1. **RBAC permissions**\
A user whose role grants *private incident read access* can view all private incidents.
2. **Incident-level invitation (subscriber-level access)**\
Even if a user does *not* have role-based permission, they can still be added as a responder through the **Manage Access** dialog (Web or Slack).\
This provides **incident-specific access on top of RBAC**.
Private incident access is additive.\
A user either needs (A) role-based private-incident permissions **or** (B) to be explicitly added as a subscriber to the incident.
Rootly exposes simple controls for managing access through both the Web interface and Slack. These tools allow incident commanders to invite additional responders quickly while maintaining strict visibility boundaries.
***
## When to Use Private Incidents
Private incidents are commonly used for:
* Security or privacy-related investigations
* Customer-impacting issues involving sensitive data
* Vendor or partner escalations
* Production outages requiring access to confidential systems or dashboards
* Internal-only discussions during high-severity events
Because access is tightly controlled, private incidents ensure the right responders are looped in without exposing sensitive information to the entire organization.
***
## How to Manage Access
Rootly provides dedicated access-management flows in **both the Web UI** and **Slack**, ensuring responders can add or remove users without breaking focus.
Use the Web interface to add or remove subscribers, bulk-edit access, and review current authorized users.
Update access directly from the incident channel using `/rootly manage`, `/rootly access`, or the Manage Access button.
***
## How Access Updates Work Behind the Scenes
Rootly performs several automated steps when you update access:
### Adding a User
* They are added as an **authorized subscriber** to the private incident.
* If Slack is integrated, Rootly automatically attempts to **invite them to the incident channel**.
* They immediately gain permission to view private incident details in the Web UI and API.
### Removing a User
* They are removed from the incident’s subscriber list.
* If Slack permissions allow it, they are **removed from the incident’s Slack channel**.
* They lose access to incident details, timeline, roles, and integrations.
Slack workspace restrictions may prevent Rootly from removing users from channels.\
In those cases, Rootly removes incident access but Slack may reject channel removal.
### “Remove Unauthenticated Users”
If selected in Slack or the Web UI, Rootly will:
* Remove anyone who **does not have private-incident read permissions**,\
*even if they were manually added previously*.
This is typically used to quickly sanitize membership during sensitive investigations.
***
## Best Practices for Private Incidents
* **Limit access to essential responders only**\
Fewer participants reduce noise and risk when working with sensitive information.
* **Grant subscriber access proactively**\
When involving teams like Legal, Security, or Support, add them early via the Manage Access dialog.
* **Use Slack for quick changes, Web UI for structured updates**\
Slack is ideal for rapid response.\
The Web UI is better for reviewing and bulk-editing access.
* **Regularly audit access during long-running incidents**\
Make sure only the necessary responders continue to have access.
* **Use workflows for automatic access control**\
Add on-call engineers, service owners, or leadership automatically for critical severities.
***
## Frequently Asked Questions
No. Private incidents **add** incident-level permissions on top of RBAC.\
Users with the correct role can see all private incidents. Others must be explicitly added.
No. The [default announcement channel](/integrations/slack/slack) only announces **public** incidents — private incidents are excluded from that channel.
When a Slack channel is created for a private incident (if channel creation is enabled), the channel itself is created as a **private Slack channel**, and Rootly restricts membership to responders who have access to the incident.
Other Slack notification paths configured through Smart Defaults (for example, **High Severity Notifications**) or through your own workflows are not covered by this behavior — audit each notification workflow's run conditions to confirm it excludes private incidents where you need it to.
Yes—if they are added as a subscriber through the Manage Access dialog (Web or Slack).
Slack may send a notification, but this depends on workspace settings.\
Rootly attempts removal, but Slack may reject the action if workspace policies prevent it.
The modal shows all current subscribers and allows searching for any workspace user.\
Users may disappear automatically if “Remove Unauthenticated Users” was selected.
Rootly removes their incident access, but Slack may block channel removal based on workspace permissions.
If your workspace enables parent–child syncing, access changes (invites and removals) may propagate to linked sub-incidents.
***
## Related Pages
The umbrella page covering how incidents work end-to-end.
Assigning roles inside a private incident — access controls apply.
How Rootly's classic AI features handle private incident data — the visibility scope carries through.
# Google Chat Integration
Source: https://docs.rootly.com/integrating-with-google-chat
Connect Google Chat to Rootly to create incident spaces, send notifications, run slash commands, and manage on-call alerts directly from chat.
Rootly's Google Chat integration automates incident communication, on-call management, and alerting. When an incident starts, Rootly creates a dedicated Google Chat space, invites responders, and posts real-time incident overview cards.
For detailed installation instructions, screenshots, and troubleshooting, see the [Google Chat Installation Guide](/integrations/google-chat/overview).
## Before You Get Started
There are two ways to connect Google Chat to Rootly. The recommended path is through the **Google Workspace Marketplace**, which requires no GCP project setup. For organizations that need **domain-wide delegation**, a service account can be configured as an advanced option.
| Method | Best For | Limitations |
| ------------------------------ | ---------------------------------------------- | -------------------------------------------------------- |
| **Marketplace** (recommended) | Most organizations | None for standard use |
| **Service Account** (advanced) | Organizations requiring domain-wide delegation | Requires Google Cloud project and Workspace admin access |
## Quick Installation Steps
**Requirements:**
* **Rootly account:** Admin or Owner
* **Google account:** Workspace Admin (for Marketplace install or service account setup)
### Marketplace (Recommended)
1. Install Rootly from the [Google Workspace Marketplace](https://workspace.google.com/marketplace/app/rootly/1046293539231)
2. Add the Rootly bot to a Google Chat space
3. Type `/rootly` in the space and select your team to complete setup
### Service Account (Advanced)
1. Create a service account in your Google Cloud project (**IAM & Admin > Service Accounts**)
2. Download the JSON key file
3. Configure domain-wide delegation in [admin.google.com](https://admin.google.com) with the service account's Client ID and required Chat scopes
4. In Rootly, go to **Configuration > Integrations** and search for **Google Chat**
5. Click **Setup**, upload the JSON key, and enter the delegated user email
6. Click **Connect**
For step-by-step instructions with full details, see the [Google Chat Installation Guide](/integrations/google-chat/overview).
## After Connecting
Once connected, Rootly automatically creates default workflows:
* **Auto Create Incident Google Chat Space** — Creates a dedicated space when an incident starts
* **Default Announcement Space** — Posts to a shared announcement space (disabled until configured)
Go to **Configuration > Integrations > Google Chat > Settings** to configure incident spaces, emoji shortcuts, and interaction preferences.
## Frequently Asked Questions
Use the **Marketplace** install for the fastest setup with no GCP project required. Use the **service account** path only if your organization requires domain-wide delegation for advanced use cases.
The Marketplace install handles permissions automatically. If using a service account, it requires six Google Chat scopes for creating spaces, managing members, and sending messages. See the full scope list in the [Installation Guide](/integrations/google-chat/overview).
Yes. Rootly supports multiple chat integrations simultaneously. You can configure workflows to route incidents to specific platforms based on conditions.
No. The Marketplace install provides full functionality without a service account. A service account is only needed if your organization requires domain-wide delegation for specific use cases.
Verify the Rootly bot has been added to the target space. If you installed via the Marketplace, the bot should be available automatically once added to a space.
# Microsoft Teams Integration
Source: https://docs.rootly.com/integrating-with-microsoft-teams
Connect Microsoft Teams to Rootly to create incident channels, post real-time updates, and start Teams meetings directly from an incident.
Rootly's Microsoft Teams integration automates incident communication. When an incident starts, Rootly can create a dedicated Teams channel, invite responders, and post real-time updates as the incident progresses.
For detailed installation instructions, screenshots, and troubleshooting, see the [Microsoft Teams integration guide](/integrations/microsoft-teams).
## Before You Get Started
Microsoft Teams connects in two parts, and they are independent — the main integration handles channels and notifications, while meetings are a separate OAuth connection with their own permissions.
| Part | What it does | Required for |
| ----------------------------- | -------------------------------------------------------- | ------------------------------- |
| **Teams integration** | Incident channels, notifications, workflow actions | Everyday incident communication |
| **Teams Meeting integration** | The **Create a Microsoft meeting** button on an incident | Live video collaboration |
**Requirements:**
* **Rootly account:** Admin
* **Microsoft 365 account:** permission to authorize apps for your tenant
## Quick Installation Steps
1. In Rootly, go to **Configuration → Integrations** and select **Microsoft Teams**
2. Sign in with your Microsoft 365 work account and approve the requested permissions
3. Install the Rootly bot into the Teams team you want incident channels created in
4. Confirm the integration shows as **Connected**
To create meetings from incidents, connect **Microsoft Teams Meeting** separately from the same integrations page. It uses a different permission set and must be authorized on its own, even if the main integration is already connected.
Rootly recommends connecting with a service account rather than a personal one, so the integration keeps working when someone leaves your organization.
## What You Get
* A dedicated Teams channel per incident, with responders invited automatically
* Real-time incident updates posted to the channel as status and severity change
* Workflow actions for posting messages and managing channels — see [Microsoft Teams workflows](/integrations/microsoft-teams#workflows)
* A **Create a Microsoft meeting** button on every incident, once the meeting integration is connected
## Related Resources
* [Microsoft Teams integration guide](/integrations/microsoft-teams)
* [Slack integration](/integrating-with-slack)
* [Google Chat integration](/integrating-with-google-chat)
# Manage incidents in Slack with the Rootly integration
Source: https://docs.rootly.com/integrating-with-slack
Connect Slack to Rootly to run incidents from Slack with channels, slash commands, message actions, notifications, and Workflow Builder connector controls.
Rootly’s Slack integration brings incident management directly into Slack, so responders can create incidents, coordinate updates, manage channels, and run workflows without leaving the conversation.
For detailed installation instructions, screenshots, and video walkthroughs, see the [Slack Installation Guide](/integrations/slack/slack#installation).
## Before You Get Started
Before connecting Slack, confirm which Slack plan your organization uses. If you are unsure, click your organization name in the top-left corner of Slack. Your current plan appears below the organization name.
Supported Slack plans:
* **Slack Free, Pro, or Business+** — Install Rootly at the workspace level
* **Slack Enterprise Grid** — Install Rootly at the organization level across multiple workspaces using [Multi-Workspace Channels](https://slack.com/help/articles/115001399587-Add-a-channel-to-multiple-workspaces-in-your-Enterprise-Grid-organization)
Rootly requests different Slack scopes depending on your Slack plan and enabled features, such as AI. The list below reflects the full set of permissions you may be asked to approve.
### Bot Scopes
**Core permissions**\
**bookmarks:write:** Add bookmarks to incident channels for quick access to important resources.\
**channels:manage:** Create public Slack channels for incidents.\
**channels:read:** View basic information about public channels in a workspace.\
**chat:write + chat:write.public:** Post messages in incident channels and respond to Slack actions.\
**commands:** Enable `/rootly` and `/incident` slash commands.\
**files:read:** Save files associated with pinned or reacted messages to the incident timeline.\
**files:write:** Upload files, such as workflow output, directly into Slack. Rootly does not delete files in your Slack workspace.\
**groups:read:** View basic information about private channels that Rootly has been added to.\
**groups:write:** Create private Slack channels for sensitive incidents.\
**pins:read:** Add pinned Slack messages to the incident timeline.\
**pins:write:** Pin important messages in incident channels.\
**reactions:read:** Add Slack messages to the incident timeline through reactions you configure.\
**reactions:write:** React to messages after they are added to the incident timeline.\
**usergroups:read:** View Slack user groups, such as `@security`.\
**usergroups:write:** Manage on-call user groups for scheduling and rotation.\
**users:read + users:read.email:** View workspace members and email addresses for one-click invitations. Rootly does not invite users automatically.\
**users.profile:read:** Display full names instead of Slack usernames.
**AI and assistant features**\
**app\_mentions:read:** View messages that mention `@rootly`.\
**channels:history:** Read message history in public channels for AI-powered features.\
**groups:history:** Read message history in private channels for AI-powered features.\
**assistant:write:** Enable Rootly AI agent capabilities.\
**im:history:** Read direct message history for AI agent interactions.
### User Scopes
**usergroups:write:** Required for on-call user group management using user permissions.
### Additional Scopes for Slack Enterprise Grid
**conversations.connect:write:** Connect channels across multiple workspaces in Enterprise Grid organizations.\
**admin.conversations:write:** Manage conversations at the organization admin level for Enterprise Grid.
### Additional User Scopes When Bot Channel Creation Is Restricted
Some Slack workspaces allow only admins or owners to create channels. In those environments, Rootly may request additional user scopes from an admin or owner so it can create channels on their behalf.
**channels:write:** Create and manage public channels on behalf of an admin or owner.\
**groups:write:** Create and manage private channels on behalf of an admin or owner.
## Quick Installation Steps
**Requirements:**
* **Rootly account:** Admin or Owner
* **Slack account:** Workspace Admin or Owner, or Organization Admin or Owner for Enterprise Grid
### For Slack Free, Pro, or Business+
1. Go to **Configuration → Integrations**
2. Select **Setup** under the Slack integration
3. Choose **Other Slack Plans**
4. Select your Slack workspace and review permissions
5. Click **Allow** to authorize Rootly
### For Slack Enterprise Grid
1. Go to **Configuration → Integrations**
2. Select **Setup** under the Slack integration
3. Choose **Slack Enterprise Grid**
4. Authorize Rootly at the organization level
5. Add Rootly to the appropriate workspaces through **Organization settings → Integrations → Installed apps**
For step-by-step instructions with screenshots and videos, see the [Slack Installation Guide](/integrations/slack/slack#installation).
## Workspace Setup
After connecting Slack, go to **Configuration → Slack** to configure defaults and workspace behavior.
You can configure:
* **Default announcement channel** for new incidents
* **Default alerts channel** for notifications
* **Team notifications** for high-severity incidents or specific groups
* **Smart Reminders** to prompt responders to add roles, update the status page, and keep tasks moving
* **Incident updates** to keep stakeholders informed throughout the lifecycle
* **Incident Slack channel settings** such as naming conventions, bookmarks, and incident TPOC updates
* **Interactions** using emoji to pin messages, create follow-up work, or add tasks
* **Channel archiving** for incident channels after resolution
* **Member settings** to require Slack connection or track incident access
## Channel Creation Restrictions
In some Slack workspaces, only admins or owners are allowed to create channels. When that restriction is enabled, Rootly may ask an admin or owner to grant additional permissions so it can create channels on their behalf.
In Rootly, this is managed through **Configuration → Slack**, where you may see options such as **Bypass Slack permissions** or **Elevate privileges**.
## Rootly AI Permissions
If you want to use Rootly AI features in Slack, your integration may need additional Slack scopes. In some cases, you may be asked to update or reinstall the Slack integration to grant the required permissions.
See the [Slack Installation Guide](/integrations/slack/slack#installation) or use the in-app **Upgrade permissions** option if it appears.
## Frequently Asked Questions
Rootly supports Slack Free, Pro, Business+, and Slack Enterprise Grid. Standard workspaces install at the workspace level, while Enterprise Grid installs at the organization level.
Rootly uses Slack permissions to create and manage incident channels, send messages, power workflows, manage on-call user groups, and support AI features. The exact permissions requested depend on your Slack plan and enabled features.
Some Slack workspaces restrict channel creation to admins or owners. In those cases, Rootly may request additional user scopes from an admin or owner so it can create channels on their behalf.
After installation, go to **Configuration → Slack** to manage default channels, notifications, reminders, incident channel settings, archiving, and member behavior.
Sometimes. If your current Slack integration is missing the scopes required for AI features, Rootly may prompt you to upgrade permissions or reinstall the integration.
Slack includes a native, Slack-built Rootly connector in Workflow Builder. This is separate from the Rootly Slack app and is managed at the workspace level by Slack admins.
To disable or restrict this connector:
1. From your desktop, click **Admin** in the sidebar
2. Select **Apps and workflows** from the menu to open the Slack Marketplace
3. Click **Workflow steps, triggers, & integrations**
4. Next to the Rootly connector, click the **three dots** icon
5. Select **Deny** to block the connector entirely, or select **Change to approval required** to allow members to request it when needed
These steps reflect Slack's current admin UI. Labels and menu paths may vary by Slack plan or as Slack updates its interface. See Slack's Help Center article on [managing access to Slack Workflow Builder connectors](https://slack.com/help/articles/27832980498067-Manage-access-to-Slack-Workflow-Builder-connectors) for the latest instructions.
# Agent Plugins
Source: https://docs.rootly.com/integrations/agent-plugins
Bring Rootly incident response, on-call context, and retrospectives into Claude Code and Cursor with curated slash commands and automatic hooks.
## Introduction
Rootly agent plugins bring incident response, on-call context, and retrospective generation directly into the AI coding agents where engineers already work. Each plugin ships with curated slash commands and automatic hooks, all backed by [Rootly's hosted MCP service](/integrations/mcp-server).
## Why Use an Agent Plugin
Incident response has always required switching contexts: from your editor to Slack, to your incident tool, back to your terminal. By the time you've caught up on what's happening, you've already lost the thread of what you were building. Rootly's agent plugins close that gap — incident context, on-call state, and retrospective generation are available from the same environment where you write and ship code.
## Common Workflows
Across all agent plugins, you can:
* **Investigate incidents** — pull full incident context and find similar past incidents
* **Check on-call** — see current on-call state, upcoming handoffs, and health risk indicators
* **Draft status updates** — generate stakeholder-ready incident summaries
* **Run handoffs** — produce structured handoff documents for incident commander transitions
* **Generate retrospectives** — turn incident data into structured retrospectives
* **Run deploy checks** — analyze git diffs against past incidents to catch risky changes
## Claude Code
The Rootly Claude Code plugin brings incident response workflows directly into [Claude Code](https://claude.com/claude-code).
### Slash Commands
The plugin ships with nine slash commands:
| Command | Description |
| ------------------------ | ------------------------------------------------------------------------------------------------ |
| `/rootly:deploy-check` | Analyzes your git diff against past incidents and warns if similar changes caused outages before |
| `/rootly:respond [id]` | Pulls full incident context, finds similar past incidents, and shows who's on-call |
| `/rootly:oncall` | On-call dashboard with shift metrics, upcoming handoffs, and health risk indicators |
| `/rootly:retro [id]` | Generates a structured retrospective from incident data |
| `/rootly:status` | All services with active incidents grouped by severity |
| `/rootly:ask [question]` | Natural language queries over your incident history |
| `/rootly:brief [id]` | Executive-ready incident summary for stakeholder updates |
| `/rootly:handoff` | Structured handoff document for incident commander transitions |
| `/rootly:setup` | First-run configuration and API token validation |
### Automatic Hooks
The plugin includes two automatic hooks:
* **Session-start token check** — verifies your Rootly API token is valid when Claude Code starts
* **Pre-commit / pre-push warning** — alerts you if there's an active critical incident in progress before you ship code
### Installation
Install the plugin through Rootly's custom plugin marketplace:
```bash theme={null}
/plugin marketplace add Rootly-AI-Labs/rootly-claude-plugin
/plugin install rootly@rootly-plugins
/reload-plugins
```
Then run the setup command — Claude handles OAuth2 login automatically:
```bash theme={null}
/rootly:setup
```
A browser window opens for you to authenticate with Rootly. No API token needed for MCP commands.
## Cursor
The Rootly Cursor plugin brings the same Rootly workflows into [Cursor](https://cursor.com), so incident investigation, on-call context, status drafting, handoffs, retrospectives, and deploy checks are available directly in the editor.
### Installation
Install the Rootly plugin from the public GitHub plugin source in the [`rootly-cursor-plugin`](https://github.com/Rootly-AI-Labs/rootly-cursor-plugin) repository.
### Configuration
Run the setup command in Cursor — OAuth2 login is handled automatically:
```bash theme={null}
/rootly-setup
```
**Fallback (environments without browser access):**
1. Generate an API token in **Account** > **Manage API keys** > **Generate New API Key**
2. Set it in the environment **before** launching Cursor:
```bash theme={null}
export ROOTLY_API_TOKEN=""
```
3. Restart Cursor so it inherits the variable
4. Run `/rootly-setup` to verify connectivity
## Authentication
Both plugins use **OAuth2** by default — your MCP client handles the login flow automatically when it connects to the Rootly MCP server. No API token needed.
For environments without browser access, use a Rootly API token as a fallback. Generate one in **Account** > **Manage API keys** > **Generate New API Key**.
Hook scripts (active-incident warnings on commit/push) also use API tokens since they run outside the MCP context.
All agent plugins are backed by Rootly's hosted MCP service. For direct MCP configuration with other clients (Windsurf, Gemini CLI, Claude Desktop, etc.), see the [MCP Server documentation](/integrations/mcp-server).
## Related
* [MCP Server](/integrations/mcp-server) — direct MCP configuration for any compatible client
* [Rootly CLI](/integrations/cli) — terminal-based access to Rootly resources
# Airtable
Source: https://docs.rootly.com/integrations/airtable
Automatically create and update Airtable records from Rootly incidents using workflow actions to track incidents, follow-ups, and metrics in your bases.
## Overview
Rootly's Airtable integration lets you push incident data directly into Airtable tables using workflow actions. When an incident is declared — or updated — Rootly can create or update a record in any base and table you choose, with full control over field mapping via Liquid variables.
Automatically create a new Airtable record when an incident is declared, capturing key fields like title, summary, severity, and more.
Update an existing Airtable record as the incident progresses — reflect status changes, resolution notes, or any custom field.
Map any Rootly incident field to any Airtable column using JSON and [Liquid variables](/liquid/incident-variables).
Target any base and table in your Airtable workspace — not limited to a single sheet.
## Before You Begin
* You must be a Rootly admin to set up the integration
* You need an Airtable account with permission to create OAuth applications
* The Airtable base and table you want to write to must already exist
## Installation
Setting up the Airtable integration requires creating an OAuth application in Airtable and connecting it to Rootly.
In Rootly, go to **Configuration → Integrations** and find **Airtable**. Click **Connect**.
In a new tab, go to [airtable.com/create/oauth](https://airtable.com/create/oauth) and create a new OAuth application.
Set the **Redirect URL** (callback URL) to:
```text theme={null}
https://rootly.com/auth/airtable/callback
```
In the OAuth app settings, enable the required scopes:
Copy the **Client ID** and **Client Secret** from your Airtable OAuth app into Rootly and save.
Click **Authorize** in Rootly. You'll be redirected to Airtable to grant access. Once approved, you'll return to Rootly with the integration connected.
When you connect Airtable, Rootly automatically creates a default **Create Airtable Record** workflow to get you started quickly.
## Workflow Actions
### Create Airtable Record
Creates a new record in the specified Airtable base and table when the workflow triggers.
The Airtable base to write the record to. Select from the dropdown populated from your connected account.
The table within the selected base. Populated dynamically based on the selected base.
A JSON object mapping Airtable column names to values. Supports [Liquid variables](/liquid/incident-variables).
```json theme={null}
{
"Name": "{{ incident.title }}",
"Notes": "{{ incident.summary }}",
"Started At": "{{ incident.started_at | date: '%FT%T%:z' }}",
"Severity": "{{ incident.severity }}",
"Link": "{{ incident.url }}"
}
```
### Update Airtable Record
Updates an existing record in Airtable. Use this after a record has been created to reflect incident updates.
The Airtable base ID (for example, `appXXXXXXXXXXXXXX`). Supports Liquid variables.
The name of the table containing the record to update. Supports Liquid variables.
The ID of the Airtable record to update (for example, `recXXXXXXXXXXXXXX`). Supports Liquid variables.
A JSON object of fields to update. Same syntax as the Create action.
## Uninstall
To remove the Airtable integration:
1. Go to **Configuration → Integrations** and find **Airtable**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
## Frequently Asked Questions
The **Base Key** is visible in the URL when you open a base in Airtable: `airtable.com/appXXXXXXXXXXXXXX/...`. The **Record ID** (format: `recXXXXXXXXXXXXXX`) can be retrieved via the Airtable API or by expanding a record and copying the ID from the URL.
Yes. Use the `incident.custom_fields` Liquid variable to access custom field values. For example: `{{ incident.custom_fields | find: 'custom_field.slug', 'your-slug' | get: 'selected_options' | map: 'value' }}`.
Airtable will return an error and the workflow action will fail. Make sure all column names in the mapping exactly match your Airtable table's field names (case-sensitive).
Yes. Add multiple **Create Airtable Record** actions to the same workflow, each targeting a different base or table.
# Prometheus Alertmanager
Source: https://docs.rootly.com/integrations/alertmanager
Connect Prometheus Alertmanager to Rootly to ingest firing alerts, automatically resolve them when restored, and page on-call escalation targets.
## Introduction
The Prometheus Alertmanager integration connects Rootly with your existing Prometheus alerting pipeline so teams can receive alerts in Rootly and trigger on-call paging directly from Alertmanager.
This integration is a strong fit for teams already using Prometheus and Alertmanager for infrastructure monitoring who want Rootly to handle incident coordination and on-call response.
With the Prometheus Alertmanager integration, you can:
* Ingest Alertmanager firing alerts into Rootly as alerts
* Automatically resolve Rootly alerts when Alertmanager sends a resolved notification
* Page Rootly on-call targets directly from Alertmanager using webhook URLs or Prometheus rule annotations
* Use alert workflows to create incidents and automate follow-up actions
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with permission to manage integrations and alert sources
* Access to your Alertmanager configuration file (`alertmanager.yml`)
* The webhook URL and bearer token secret from the Rootly Alertmanager integration page
You can find your webhook URL and bearer token secret by navigating to **Integrations** > **Prometheus Alertmanager** > **Configure** in Rootly.
## Installation
Navigate to the integrations page in Rootly and select **Prometheus Alertmanager**. Copy the webhook URL and bearer token secret shown in the configuration modal.
Add a Rootly receiver to your `alertmanager.yml` configuration file. Set the `url` to the Rootly webhook URL and the `credentials` to your bearer token secret.
```yaml theme={null}
route:
receiver: default
group_by:
- job
routes:
- receiver: rootly
match:
alertname: Rootly
repeat_interval: 1m
receivers:
- name: rootly
webhook_configs:
- url: 'https://webhooks.rootly.com/webhooks/incoming/alertmanager_webhooks'
send_resolved: true
http_config:
authorization:
type: Bearer
credentials:
```
Setting `send_resolved: true` is required for Rootly to automatically resolve alerts when Alertmanager sends a resolved notification.
## Page Rootly On-Call
Alertmanager can page Rootly on-call targets directly. There are two ways to configure this.
### Via Receiver URL
Append a notification target to the webhook URL in your `alertmanager.yml`. This routes the alert to the specified Rootly resource for paging.
```yaml theme={null}
receivers:
- name: rootly
webhook_configs:
- url: 'https://webhooks.rootly.com/webhooks/incoming/alertmanager_webhooks/notify//'
send_resolved: true
http_config:
authorization:
type: Bearer
credentials:
```
Replace `` and `` with one of the following:
| Resource Type | Description |
| ------------------ | -------------------------- |
| `User` | A specific Rootly user |
| `Group` | A Rootly team |
| `EscalationPolicy` | A Rootly escalation policy |
| `Service` | A Rootly service |
The resource ID can be found by editing the resource in Rootly.
### Via Prometheus Rule Annotations
If you use Prometheus alerting rules, you can set the notification target through annotations in your `prometheus.rules.yml` file. This lets you define the paging target per rule rather than per receiver.
```yaml theme={null}
groups:
- name: ./rules.conf
rules:
- alert: HighCPUUsage
expr: cpu_usage > 90
labels:
severity: critical
annotations:
summary: "High CPU usage detected"
rootly: '{"notification_target":{"type":"User","id":""}}'
```
To page multiple targets from a single rule, use `alerting_targets` (an array) instead of `notification_target`:
```yaml theme={null}
rootly: '{"alerting_targets":[{"type":"User","id":""},{"type":"EscalationPolicy","id":""}]}'
```
The `type` and `id` values follow the same options as the receiver URL approach above.
## How Alerts Are Mapped
Rootly extracts the following fields from each Alertmanager alert:
* **Summary** — taken from the alert's `alertname` label, falling back to `commonLabels.alertname`, then `commonLabels.description`
* **Labels** — all key-value pairs from `commonLabels` are attached as Rootly alert labels, making them available for routing, filtering, and display. Individual labels like `instance`, `dc`, `job`, and `status` are also extracted.
* **External ID** — the `alertname` label, used to deduplicate and match resolve events
* **External URL** — the `generatorURL` from the alert, or the `externalURL` from the webhook envelope
## How Auto-Resolution Works
When `send_resolved: true` is set in your Alertmanager configuration, Alertmanager sends a resolved notification to Rootly when a firing alert returns to a normal state. Rootly uses the `endsAt` timestamp in the resolved payload to mark the corresponding alert as resolved.
Alerts are matched by their external identifier — if an alert fires and resolves multiple times, Rootly updates the existing alert rather than creating duplicates.
You can also explicitly set the alert status by including `rootly_alert_status` in the webhook payload. Valid values are `open`, `triggered`, and `resolved`.
## Troubleshooting
Verify that the webhook URL in your `alertmanager.yml` matches the one shown in your Rootly integration settings. Confirm that the bearer token secret is correctly set under `credentials` and that the Alertmanager receiver is being triggered by your routing rules.
Confirm that `send_resolved: true` is set in your webhook configuration. Without this, Alertmanager will not send resolved notifications to Rootly and alerts will remain open until manually resolved.
Check that the `resource_type` and `resource_id` in the notification target URL are correct. The resource ID can be found by editing the target resource in Rootly. Ensure the resource type is one of `User`, `Group`, `EscalationPolicy`, or `Service`.
Confirm the `rootly` annotation is valid JSON and that the `type` and `id` values match an existing Rootly resource. Invalid JSON or a missing resource will cause the notification target to be ignored.
## Uninstall
To remove the Alertmanager integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related resources
* [Checkly](/integrations/checkly)
* [Chronosphere](/integrations/chronosphere)
* [Dynatrace](/integrations/dynatrace)
* [Google Cloud Monitoring](/integrations/google-cloud-monitoring)
# Anthropic
Source: https://docs.rootly.com/integrations/anthropic
Connect your Anthropic account to Rootly to power AI-assisted incident workflows using Claude with your organization's own API key and data agreements.
## Introduction
The Anthropic integration lets you connect Rootly to your organization's Anthropic account, using your own API key to power AI-assisted incident workflows with Claude. This gives your team control over the model, data handling, and API usage under your organization's specific agreements with Anthropic. Usage is billed directly to your Anthropic account — not through Rootly — making this a good fit for organizations with data residency requirements or custom API agreements.
With the Anthropic integration, you can:
* Generate AI-powered summaries, analyses, and responses within incident workflows
* Send custom prompts to Claude with full Liquid template support for dynamic, incident-aware content
* Use a system prompt to define Claude's role, tone, or constraints for each workflow action
* Choose which Claude model to use based on your account's available models
## Before You Begin
Before setting up the Anthropic integration, make sure you have:
* A Rootly account with permission to manage integrations
* An [Anthropic API key](https://console.anthropic.com/settings/keys) with access to the models you want to use
Rootly recommends creating a dedicated API key for Rootly rather than using a personal key — this makes it easier to rotate or revoke access independently. Your key is validated on save and encrypted at rest in Rootly.
API keys are validated against the Anthropic API when you save the integration. If the key is inactive, expired, or over its usage limit, the integration will not save.
## Installation
Navigate to the integrations page in your Rootly workspace and select **Anthropic**.
Paste your Anthropic API key into the **API Key** field. You can generate or manage keys in the [Anthropic Console](https://console.anthropic.com/settings/keys).
Choose the Claude model you want to use for workflow actions. The available models are fetched dynamically from your Anthropic account. Common options include:
* `claude-opus-4-5` — most capable, best for complex analysis
* `claude-sonnet-4-5` — balanced performance and speed
* `claude-haiku-4-5` — fastest, best for high-volume workflows
Your Anthropic integration is active. The **Create Anthropic Chat Completion** workflow action is now available in your incident and action item workflows.
## Workflow Actions
### Create Anthropic Chat Completion
Sends a prompt to Claude and captures the response as a workflow output. The response can be used in subsequent workflow steps, posted to Slack, or written to incident fields. Rootly uses a maximum output of **4,000 tokens** per request — for longer responses, consider breaking your workflow into multiple steps with more focused prompts.
| Field | Description | Required |
| ------------- | ----------------------------------------------------------------------- | -------- |
| Model | The Claude model to use — fetched from your Anthropic account | Yes |
| Prompt | The user message sent to Claude — supports Liquid templating | Yes |
| System Prompt | Instructions for Claude's role or behavior — supports Liquid templating | No |
The **System Prompt** field is useful for setting Claude's persona or output format. For example: *"You are an incident response assistant. Respond in bullet points. Be concise."*
Use Liquid variables in your prompts to include live incident context — for example `{{ incident.title }}`, `{{ incident.severity }}`, and `{{ incident.description }}`. See the [Liquid variables reference](/liquid/incident-variables) for all available fields.
## Troubleshooting
Rootly validates your API key by making a test request to the Anthropic API. If the key is rejected, confirm it is active and has not been revoked in the [Anthropic Console](https://console.anthropic.com/settings/keys). Also check that the key has not exceeded its usage limits.
If the integration was working and then stopped, the API key may have been rotated or revoked. Go to the integration settings in Rootly and update the API key — Rootly will re-validate on save.
Anthropic enforces rate limits based on your plan tier. If you are running many concurrent workflows, you may hit requests-per-minute or tokens-per-minute limits. Consider staggering workflows or upgrading your Anthropic plan. Rootly does not retry rate-limited requests automatically.
The model list is fetched dynamically from your Anthropic account. If a model is not appearing, confirm that your API key has access to that model. Some models require a specific Anthropic tier or may not yet be available on your account.
Check your Liquid syntax — unclosed tags or undefined variables can cause rendering failures or unexpected output. Use the [Liquid variables reference](/liquid/incident-variables) to confirm correct variable names and test your template in a low-stakes workflow first.
## Related Pages
Build workflows that use Claude to analyze, summarize, or respond to incidents automatically.
Reference for all incident variables available in Liquid-templated prompts.
Learn about Rootly's built-in AI features for incident management.
# Asana
Source: https://docs.rootly.com/integrations/asana
Connect Asana to Rootly to automatically create and update tasks from incidents and action items in your Asana workspace.
The Asana integration connects Rootly with your Asana workspace so teams can automatically create and update tasks through Genius workflows. Tasks can be assigned, linked to projects, given due dates, and populated with custom fields — all driven by incident data.
With the Asana integration, you can:
* Automatically create Asana tasks when incidents are declared or reach a certain state
* Create subtasks under an existing Asana task to track action items
* Update task title, completion status, assignee, and custom fields as incidents evolve
* Set task dependencies to model blocking relationships between tasks
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* An Asana account with access to the workspace you want to use
Rootly recommends installing with a dedicated Asana service account so the integration does not break if an individual user leaves your organization.
## Installation
Navigate to the integrations page in Rootly and select **Asana**.
You will be redirected to Asana to sign in and grant Rootly permission to access your workspace. Once authorized, the installation is complete.
After authorization, the **Create an Asana Task**, **Create an Asana Subtask**, and **Update an Asana Task** workflow actions are available in your Genius workflows.
## Workflow Actions
The Asana integration provides three workflow actions for managing tasks directly from Rootly incidents. If you are unfamiliar with how Genius workflows work, visit the [Workflows](/workflows/workflows) documentation first.
### Create an Asana Task
This action creates a new task in a specified Asana project.
| Field | Description | Required |
| ------------------------- | --------------------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Workspace** | Asana workspace where the task will be created | Yes |
| **Team** | Asana team used to filter available projects | |
| **Projects** | One or more Asana projects to associate the task with | Yes |
| **Title** | Task title. Defaults to `{{ incident.title }}`. Supports Liquid | Yes |
| **Notes** | Task description. Supports Liquid | |
| **Assign User Email** | Email of the Asana user to assign the task to. Supports Liquid | |
| **Completion** | Task completion status. **Auto** mirrors the incident or action item status | Yes |
| **Due Date** | Task due date. Supports Liquid | |
| **Custom Fields Mapping** | JSON mapping Asana custom field IDs to values. Supports Liquid | |
| **Dependency Direction** | Whether this task is **blocking** or **blocked by** the dependent tasks | |
| **Dependent Task IDs** | Asana task IDs that this task has a dependency relationship with | |
Use the [Incident Variable Explorer](https://rootly.com/account/help/liquid-explorer) to preview what Liquid variables return for your incidents.
### Create an Asana Subtask
This action creates a subtask under an existing Asana task.
When a **Create an Asana Task** action runs, Rootly stores the resulting task ID on the incident record. Reference it in subsequent subtask actions using Liquid variables.
| Field | Description | Required |
| ------------------------- | -------------------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Parent Task ID** | Asana task ID of the parent task. Supports Liquid | Yes |
| **Title** | Subtask title. Supports Liquid | Yes |
| **Notes** | Subtask description. Supports Liquid | |
| **Assign User Email** | Email of the Asana user to assign the subtask to. Supports Liquid | |
| **Completion** | Subtask completion status | Yes |
| **Due Date** | Subtask due date. Supports Liquid | |
| **Custom Fields Mapping** | JSON mapping Asana custom field IDs to values. Supports Liquid | |
| **Dependency Direction** | Whether this subtask is **blocking** or **blocked by** the dependent tasks | |
| **Dependent Task IDs** | Asana task IDs this subtask depends on | |
### Update an Asana Task
This action updates an existing Asana task with new values.
| Field | Description | Required |
| ------------------------- | ----------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Task ID** | Asana task ID to update. Supports Liquid | Yes |
| **Title** | Updated task title. Supports Liquid. Leave blank to keep existing | |
| **Assign User Email** | Updated assignee email. Supports Liquid | |
| **Completion** | Updated completion status | Yes |
| **Due Date** | Updated due date. Supports Liquid | |
| **Custom Fields Mapping** | Updated custom field values as JSON. Supports Liquid | |
| **Dependency Direction** | Updated dependency direction: **blocking** or **blocked by** | |
| **Dependent Task IDs** | Updated list of dependent Asana task IDs | |
## Custom Fields
Use the **Custom Fields Mapping** field to set Asana custom field values using a JSON object. The key is the Asana custom field ID and the value depends on the field type.
**Text fields**
```json theme={null}
{
"4578152156": "Not Started",
"5678904321": "On Hold"
}
```
**Liquid syntax in text fields**
```json theme={null}
{
"4578152156": "{{ incident.severity }}",
"5678904321": "{{ incident.status }}"
}
```
**Single-select enum fields** — use the Asana enum option ID as the value:
```json theme={null}
{
"5678904322": "1004598149"
}
```
**Multi-select enum fields** — use an array of enum option IDs:
```json theme={null}
{
"5678904322": ["459021796", "1004598149"]
}
```
**Conditional enum mapping with Liquid**
```json theme={null}
{
"4578152156": "{{ incident.severity }}",
{% if incident.severity == "sev0" %}
"5678904322": "1004598149"
{% elsif incident.severity == "sev1" %}
"5678904322": "2005678230"
{% endif %}
}
```
To find custom field IDs and enum option IDs, use the Asana API or inspect the URL when editing a custom field in Asana.
## Uninstall
To remove the Asana integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related Resources
* [Workflows](/workflows/workflows)
* [Liquid templating](/liquid/liquid)
* [Integrations overview](/integrations/overview)
# Route AWS CloudWatch alarms into Rootly via SNS
Source: https://docs.rootly.com/integrations/aws-cloudwatch
Receive alerts from AWS CloudWatch in Rootly to trigger incidents, route notifications to on-call teams, and automatically resolve alerts when alarms recover.
## Overview
The AWS CloudWatch integration allows Rootly to treat CloudWatch alarms as a native alert source. The integration uses Amazon Simple Notification Service (SNS) to deliver CloudWatch alarm state change events to Rootly via HTTPS webhooks.
When a CloudWatch alarm transitions into the `ALARM` state, Rootly creates a new alert or updates an existing unresolved alert. When the same alarm transitions back into the `OK` state, Rootly automatically resolves the corresponding alert. This behavior enables CloudWatch alarms to participate fully in Rootly’s alert routing, on-call, and incident management workflows.
Alerts created from CloudWatch can be routed to services, escalation policies, or teams, and customized using alert templates that parse fields from the SNS payload.
CloudWatch alerts are stateful. Rootly creates alerts when alarms enter the ALARM state and resolves them automatically when the same alarms return to OK.
## How the Integration Works
CloudWatch alarms publish state change notifications to an SNS topic. Rootly subscribes to this SNS topic using an HTTPS webhook endpoint generated when you create a CloudWatch alert source in Rootly.
Each SNS notification contains information about the alarm, including its name, ARN, state, reason for the state change, and timestamp. Rootly uses the alarm ARN as the external identifier for the alert, ensuring that repeated alarm triggers update the same alert and that alerts are resolved when the alarm returns to an OK state.
## Prerequisites
Before configuring the integration, ensure that you have access to an AWS account with permissions to manage CloudWatch alarms and SNS topics. You must also have a Rootly account with access to Alert Sources.
## Setup Instructions
Begin by creating a CloudWatch alert source in Rootly. Navigate to **Settings** → **Alert Sources** and click **Add Alert Source**. Select **CloudWatch** and provide a descriptive name, such as “Production CloudWatch Alarms.”
You may optionally configure default alert urgency, assign owner groups, or define an alert template. Once the alert source is saved, copy the webhook URL provided by Rootly.
```txt theme={null}
https://webhooks.rootly.com/webhooks/incoming/cloud_watch_webhooks?secret=YOUR_SECRET_KEY
```
The webhook secret authenticates incoming requests from Amazon SNS. Treat this value as sensitive and rotate it if it is exposed.
Create an Amazon SNS topic to receive CloudWatch alarm notifications. In the AWS SNS Console, create a new topic using the **Standard** topic type and give it a clear, descriptive name such as `rootly-cloudwatch-alerts`.
This SNS topic acts as the delivery mechanism between CloudWatch and Rootly.
Open the SNS topic and navigate to the **Subscriptions** tab. Create a new subscription using the **HTTPS** protocol and paste the Rootly webhook URL into the endpoint field.
AWS sends a subscription confirmation request to the webhook endpoint. Rootly automatically attempts to confirm this request, and the subscription typically transitions to **Confirmed** within a few seconds.
If the subscription remains in a pending state, verify that the webhook endpoint is reachable and that no network restrictions are blocking AWS SNS traffic.
In the CloudWatch Console, navigate to **All alarms** and create a new alarm. Select the metric to monitor and define the alarm conditions, including thresholds and evaluation periods.
Configure the alarm to send notifications to the SNS topic for both the **In alarm** and **OK** states. This ensures alerts are created and resolved automatically in Rootly.
Trigger the CloudWatch alarm or allow it to trigger naturally. Verify that a new alert appears in Rootly with the source set to CloudWatch.
When the alarm returns to the `OK` state, confirm that the alert is automatically resolved.
## Alert Mapping and Behavior
Rootly extracts key fields from CloudWatch alarm notifications and maps them to alert attributes. The alarm ARN is used as the external identifier, which allows Rootly to deduplicate alerts and correctly match resolve events. The alarm name, metric name, and state change reason are included in the alert summary.
The alert summary is generated automatically and typically follows the format shown below.
```txt theme={null}
{MetricName} - {NewStateReason}
```
For example:
```txt theme={null}
CPUUtilization - Threshold Crossed: 1 datapoint [85.5] was greater than the threshold (80.0).
```
**CloudWatch alarm tags are not included in the SNS payload.** Amazon's CloudWatch → SNS notification pipeline does not propagate the tags you set on the alarm resource, so Rootly cannot read them and cannot turn them into alert labels. If you need tag-like metadata on a Rootly alert for routing, use the patterns in [Passing Metadata for Routing](#passing-metadata-for-routing) below.
## Passing Metadata for Routing
CloudWatch alarm tags are not delivered to Rootly through SNS — this is an AWS-side limitation, not a Rootly limitation. There are three supported patterns for getting routing metadata (team, environment, severity, service) onto Rootly alerts that originate from CloudWatch.
### Pattern 1: Structured AlarmName Conventions
The `AlarmName` field is included in every SNS notification and is the simplest place to encode metadata. Adopt a positional convention like `---` — for example `platform-prod-api-latency-p1` — then use the alert template on your CloudWatch Alert Source to extract each segment into an Alert Field (or set them as labels) using Liquid:
```liquid theme={null}
Team: {{ alert.data.Message.AlarmName | split: "-" | first }}
Severity: {{ alert.data.Message.AlarmName | split: "-" | last }}
```
Once those values exist on the alert as fields, build an [Alert Route](/alerts/alert-routing) that matches on the field value to target the right service, escalation policy, or team. Routing rules evaluate Alert Fields or JSONPath into the raw payload — they don't evaluate Liquid templates directly, so this two-step (extract into a field with Liquid, then route on the field) is the pattern.
This is the lowest-effort approach and needs no new infrastructure. The trade-off is that AlarmName length and format are constrained, and you lose flexibility once you have more than 3–4 dimensions to encode.
### Pattern 2: AlarmDescription Key-Value Metadata
The `AlarmDescription` field is also delivered through SNS and accepts free-form text up to AWS's character limit. Put key-value pairs in the description (one per line, `key: value` format works well):
```text theme={null}
team: platform
env: prod
severity: high
runbook: https://wiki/runbooks/api-latency
```
In the Rootly alert template, parse the description with Liquid to extract each value into an Alert Field (or label) on the resulting alert, then [route](/alerts/alert-routing) on those fields. If you'd rather skip the alert-template step entirely, an Alert Route can also match against a JSONPath expression directly against the raw payload (for example `$.Message.AlarmDescription`) using contains/regex matchers — useful when you only need to match on the description content for routing without persisting structured fields on the alert.
This pattern scales better than AlarmName encoding and keeps the alarm name human-readable.
### Pattern 3: Lambda Enrichment (Most Flexible)
If you need access to the actual CloudWatch alarm **tags** — not metadata you've embedded in the name or description — insert a Lambda function between SNS and Rootly. The Lambda receives the SNS notification, calls `cloudwatch:ListTagsForResource` against the alarm ARN, enriches the payload with the tag values, and posts the enriched payload to a [Generic Webhook Alert Source](/integrations/generic-webhook-alert-source/generic-webhook-alert-source) in Rootly.
Flow:
```text theme={null}
CloudWatch alarm → SNS topic → Lambda function → Rootly Generic Webhook
```
The Lambda needs IAM permissions for `cloudwatch:ListTagsForResource` (or `cloudwatch:DescribeAlarms` if you also need other alarm attributes). This pattern is the only way to access real CloudWatch tags from Rootly, and it's the right choice when you already standardize on tags across many AWS resources and want a single source of truth.
**Preserve dedup and auto-resolve semantics when you move off the native CloudWatch source.** The native CloudWatch Alert Source automatically uses the alarm ARN as the external identifier (for deduplication) and maps `ALARM` → triggered / `OK` → resolved (for auto-resolution). When you switch to a Generic Webhook Alert Source, those mappings are no longer automatic — your Lambda needs to set them explicitly in the payload it posts to Rootly:
* **External identifier:** include `AlarmArn` (or a stable equivalent) as the dedup key so repeated alarm triggers update the same Rootly alert instead of creating duplicates.
* **State mapping:** translate the CloudWatch `NewStateValue` field (`ALARM`, `OK`, `INSUFFICIENT_DATA`) into the alert state field your Generic Webhook source expects — typically `triggered` for `ALARM` and `resolved` for `OK`.
See the [Generic Webhook Alert Source](/integrations/generic-webhook-alert-source/generic-webhook-alert-source) reference for the expected payload shape and the auto-resolution conditions you can configure on the source.
## Advanced Configuration
### Alert Templates
Alert templates allow you to control how CloudWatch alerts appear in Rootly. Templates are configured from the Alert Source settings and support Liquid templating, which makes it possible to dynamically generate alert content from the CloudWatch alarm payload.
Commonly used template variables include the alarm name, alarm ARN, metric name, state change reason, and timestamp. These variables can be combined to produce descriptive alert titles, detailed descriptions, and direct links back to the AWS Console.
### Alert Routing
CloudWatch alerts can be routed automatically using Rootly alert routes. Routing rules may be defined using alarm names, metric names, regions, namespaces, AlarmDescription content, or any other field actually included in the SNS payload. Routes can target services, escalation policies, or teams, ensuring that alerts are delivered to the appropriate responders without manual intervention.
If you need to route by team, environment, severity, or other tag-style metadata, see [Passing Metadata for Routing](#passing-metadata-for-routing) above — CloudWatch alarm tags themselves are not in the SNS payload, so routing rules cannot reference them directly.
### Deduplication and Resolution
Rootly deduplicates CloudWatch alerts using the alarm ARN as the external identifier. If an alarm triggers multiple times while an alert remains unresolved, Rootly updates the existing alert instead of creating duplicates. When the alarm transitions back to the `OK` state, Rootly automatically resolves the corresponding alert.
### Notification Targets
In addition to default routing rules, CloudWatch alarms can be sent directly to specific notification targets using a specialized webhook endpoint.
```txt theme={null}
https://webhooks.rootly.com/webhooks/incoming/cloud_watch_webhooks/notify/{notification_target_type}/{notification_target_id}?secret=YOUR_SECRET_KEY
```
The notification target type must be one of `Service`, `EscalationPolicy`, or `Group`. The notification target ID must be replaced with the UUID of the corresponding resource.
### Webhook Payload Structure
CloudWatch delivers alarm notifications to Amazon SNS, which then forwards them to Rootly. The SNS payload includes metadata about the message and a `Message` field containing a JSON-encoded representation of the CloudWatch alarm state change. Rootly automatically parses this message and extracts the relevant alarm data for alert creation and resolution.
### Security Considerations
Rootly webhook endpoints require HTTPS and use a secret key to authenticate incoming requests. SNS message signatures are verified to ensure authenticity. If IP allowlisting is enabled for your Rootly instance, ensure that AWS SNS IP ranges are permitted.
## Troubleshooting
Verify that the SNS subscription is confirmed and that the webhook URL configured in SNS exactly matches the one provided by Rootly. Ensure that the CloudWatch alarm is actively entering the `ALARM` state and review the alert source status in Rootly to confirm whether recent events have been received.
Ensure that the CloudWatch alarm is configured to send `OK` notifications to the same SNS topic used for alarm notifications. Rootly relies on the alarm ARN to match resolve events, so confirm that the alarm ARN has not changed since the alert was created.
Confirm that the webhook endpoint is reachable over HTTPS and that no firewall rules or IP allowlisting restrictions are blocking AWS SNS traffic. Also verify that the webhook URL is correctly formatted and includes the required secret parameter.
Expected behavior — CloudWatch alarm tags are not included in the SNS notification payload, so they never reach Rootly. This is an AWS-side limitation. To get tag-like metadata onto Rootly alerts, use one of the patterns in [Passing Metadata for Routing](#passing-metadata-for-routing): encode the values in AlarmName, put key-value pairs in AlarmDescription, or run a Lambda between SNS and Rootly that looks up the alarm's tags via `cloudwatch:ListTagsForResource` and enriches the payload before posting to a Generic Webhook Alert Source.
## Best Practices
* Use clear and descriptive alarm names. The AlarmName is the most-visible field on the resulting Rootly alert and the easiest place to encode routing metadata using a structured naming convention. Extract each segment into an Alert Field via the alert template, then route on those fields.
* Put key-value metadata in the AlarmDescription field when you need more than 3–4 dimensions to route on. It carries through the SNS payload and can be parsed with Liquid into Alert Fields, or matched directly via JSONPath in an Alert Route.
* If your existing observability practice relies on consistent CloudWatch tags across teams, use [Lambda enrichment](#pattern-3-lambda-enrichment-most-flexible) to bring those tag values onto Rootly alerts.
* Configure alert routing rules to ensure alerts reach the appropriate teams.
* Periodically test alarms to validate that the integration continues to function as expected.
For additional assistance, consult the Rootly documentation or contact Rootly Support. You may also refer to AWS CloudWatch and Amazon SNS documentation for more information about alarm and notification configuration.
# AWS Elastic Beanstalk
Source: https://docs.rootly.com/integrations/aws-elastic-beanstalk
Connect AWS Elastic Beanstalk to Rootly to log deployment pulses automatically during every application deploy using the Rootly CLI and .ebextensions hooks.
## Introduction
The AWS Elastic Beanstalk integration lets you record deployment activity as Rootly pulses every time your Elastic Beanstalk application deploys. It works by embedding the Rootly CLI into your `.ebextensions` deploy hooks — no separate service or OAuth connection required.
With this integration, you can:
* Automatically log a deployment pulse to Rootly every time a new version is deployed to an Elastic Beanstalk environment
* Tag pulses with the environment, service, and custom labels that matter to your team
* Surface deployment context on the incident timeline when an outage coincides with a recent deploy
* Use Rootly's API key and the CLI to fit naturally into your existing `.ebextensions` configuration
This integration is **CLI-based** and does not require an OAuth connection in Rootly. You configure it entirely through your application's `.ebextensions` directory, using your Rootly API key to authenticate the CLI.
## Before You Begin
Before setting up the Elastic Beanstalk integration, make sure you have:
* A Rootly account and a **Rootly API key** (found under your account settings)
* An AWS Elastic Beanstalk application with access to modify `.ebextensions` configuration files
* The ability to set **environment configuration variables** in Elastic Beanstalk for your API key and environment name
Store your **Rootly API key** as an Elastic Beanstalk environment variable rather than hardcoding it in your `.ebextensions` config file. This keeps secrets out of your repository.
## Installation
In the AWS Console (or via the EB CLI), add the following environment configuration variables to your Elastic Beanstalk environment:
| Variable | Value |
| ---------------- | ----------------------------------------------------------- |
| `rootly_api_key` | Your Rootly API key |
| `environment` | The environment name (for example, `production`, `staging`) |
| `service` | The service name as it appears in Rootly |
These values will be read by the deploy hook script at runtime using `get-config container`.
In your application repository, create a file at `.ebextensions/rootly.config` (the filename does not have to be `rootly`).
Add the following content to the file, adapting the `labels` value for your use case:
```shell theme={null}
files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/01rootly.sh":
mode: "000775"
owner: root
group: users
content: |
#!/bin/bash
rootly_api_key="$(/opt/elasticbeanstalk/bin/get-config container -k rootly_api_key)";
environment="$(/opt/elasticbeanstalk/bin/get-config container -k environment)";
service="$(/opt/elasticbeanstalk/bin/get-config container -k service)";
labels="key=value,key2=value2"
# install rootly cli
curl -fsSL https://raw.githubusercontent.com/rootly-io/cli/main/install.sh | sh
# log a pulse
rootly pulse --api-key "${rootly_api_key}" --quiet --environments "${environment}" --services "${service}" --labels "${labels}" Deploy in progress...
```
The script is placed in `appdeploy/pre/` so it runs **before** the new application version is deployed. This means the pulse fires at the start of each deployment. You can duplicate the hook into `appdeploy/post/` to also log a pulse when the deployment completes.
Update the `labels` variable in the script to include any metadata your team finds useful. Labels are comma-separated key-value pairs:
```bash theme={null}
labels="team=platform,region=us-east-1,app=api"
```
Labels appear on the pulse in Rootly and make it easier to filter deployment activity across services and environments.
Commit the `.ebextensions/rootly.config` file and deploy your application. On the next deployment, the hook script will run, install the Rootly CLI, and log a pulse to your Rootly workspace.
Verify the integration is working by navigating to **Pulses** in Rootly after your next deployment. You should see a pulse with the summary "Deploy in progress..." tagged with the environment and service you configured.
## How Pulses Work
Each time the deploy hook runs, the Rootly CLI sends a pulse to your workspace with:
* **Summary:** The message passed to the `rootly pulse` command (for example, "Deploy in progress...")
* **Environment:** The environment name from the `environment` variable
* **Service:** The service name from the `service` variable
* **Labels:** Any key-value labels you configured
Pulses are visible on the Rootly pulse feed and will appear on the timeline of any incident linked to the affected service or environment during the deployment window.
If an incident is declared around the same time as a deployment, the deployment pulse will surface automatically on the incident timeline — giving responders immediate context about whether a recent deploy may have contributed to the issue.
## Customizing the Hook
### Log a pulse on deployment completion
To also record when a deployment finishes, create a second hook file at `appdeploy/post/`:
```shell theme={null}
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/01rootly.sh":
mode: "000775"
owner: root
group: users
content: |
#!/bin/bash
rootly_api_key="$(/opt/elasticbeanstalk/bin/get-config container -k rootly_api_key)";
environment="$(/opt/elasticbeanstalk/bin/get-config container -k environment)";
service="$(/opt/elasticbeanstalk/bin/get-config container -k service)";
curl -fsSL https://raw.githubusercontent.com/rootly-io/cli/main/install.sh | sh
rootly pulse --api-key "${rootly_api_key}" --quiet --environments "${environment}" --services "${service}" Deploy complete
```
### Use the Rootly CLI for more than pulses
The Rootly CLI supports additional commands beyond `pulse`. You can also use it to declare incidents, update incident status, or trigger workflows from your deploy hooks. See the [Rootly CLI documentation](/integrations/cli) for the full command reference.
## Troubleshooting
Check the Elastic Beanstalk environment logs for the deploy hook output. Look for errors from the `curl` install command or the `rootly pulse` command. Common causes include network access restrictions that prevent the EC2 instance from reaching `raw.githubusercontent.com` or the Rootly API endpoint.
Confirm that the environment configuration variable `rootly_api_key` is set in your Elastic Beanstalk environment settings. Variables must be set in the environment itself (not just in the `.ebextensions` config) to be accessible via `get-config container`. Redeploy after adding variables.
The install script requires `curl` and internet access from the EC2 instance. If your Elastic Beanstalk environment runs in a private subnet without internet access, the CLI install will fail. In this case, pre-install the Rootly CLI in a custom AMI or bundle it directly in your application artifact rather than downloading it at deploy time.
The `--services` and `--environments` flags in the CLI command must match the exact names of the service and environment as they appear in Rootly. Names are case-sensitive. Check your Rootly services and environments configuration and update the `service` and `environment` variables in your Elastic Beanstalk environment settings accordingly.
## Related Pages
Full reference for the Rootly CLI, including all available commands and flags.
Learn how deployment pulses appear in Rootly and how they surface during incidents.
Configure services in Rootly to link deployment pulses to the right team and context.
# AWS EventBridge
Source: https://docs.rootly.com/integrations/aws-eventbridge
Stream incident and alert lifecycle events from Rootly to AWS EventBridge for real-time event-driven integrations with Lambda and Step Functions.
## Overview
The AWS EventBridge integration allows Rootly to publish incident and alert lifecycle events directly to your AWS account through the [EventBridge partner event source](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-saas.html) model. Events are delivered in near real-time as incidents and alerts progress through their lifecycle, enabling you to build event-driven automations entirely within AWS.
Once configured, Rootly creates a partner event source in your AWS account. You associate this event source with an event bus in the EventBridge console, then create rules to route events to any EventBridge target — Lambda functions, Step Functions, SQS queues, SNS topics, API Gateway endpoints, and more.
This integration uses the AWS EventBridge partner event source model. Rootly pushes events to your account — no polling or webhook configuration is required on your side.
Looking to send AWS events **into** Rootly to trigger alerts? Route EventBridge events to an SNS topic subscribed to Rootly's [AWS SNS](/integrations/aws-sns) alert source. Use an EventBridge [input transformer](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-transform-target-input.html) to format events into the [required payload schema](/integrations/aws-sns#supported-payload-schema). For CloudWatch alarms specifically, use the dedicated [AWS CloudWatch](/integrations/aws-cloudwatch) alert source instead.
## Supported Event Types
You can subscribe to any combination of the following event types per integration:
**Alert Events:**
| Event Type | Description |
| -------------------- | ---------------------------------------- |
| `alert.created` | A new alert was created |
| `alert.updated` | Alert properties were changed |
| `alert.acknowledged` | An alert was acknowledged by a responder |
| `alert.resolved` | An alert was resolved |
**Incident Events:**
| Event Type | Description |
| -------------------- | -------------------------------- |
| `incident.created` | A new incident was started |
| `incident.updated` | Incident properties were changed |
| `incident.mitigated` | An incident was mitigated |
| `incident.resolved` | An incident was resolved |
If no event subscriptions are selected, all event types are published. This is useful when you want to receive everything and filter using EventBridge rules instead.
## Prerequisites
Before configuring the integration, ensure that you have:
* A Rootly account with admin or owner permissions
* An AWS account ID (12-digit number)
* Access to the AWS EventBridge console in your target region
## Setup Instructions
Navigate to **Settings** → **Integrations** → **AWS EventBridge** and click **Add Integration**.
Fill in the following fields:
* **Integration Name**: A friendly name (for example, "Production Events")
* **AWS Account ID**: Your 12-digit AWS account ID
* **AWS Region**: The region where your event bus will be created
* **Event Source Name**: A unique identifier (for example, "production", "staging")
* **Event Subscriptions**: Select which event types to stream (leave empty for all)
Click **Create Integration**. Rootly creates a partner event source in your AWS account.
Your new integration will appear on the index page with a **Pending** status until you complete the AWS setup.
The AWS Account ID, Region, and Event Source Name cannot be changed after creation. A new integration must be created if these values need to change.
Open the [AWS EventBridge console](https://console.aws.amazon.com/events/) in the region you selected.
1. Go to **Partner event sources** in the left navigation
2. Find your event source — it will be named `aws.partner/rootly.com//`
3. Select the event source and click **Associate with event bus**
4. Confirm the association
This creates a partner event bus in your account that receives events from Rootly.
Return to Rootly and edit your EventBridge integration. Check **Mark as Active** and save.
You can also configure **Event Subscriptions** to select which event types to stream.
The integration must be activated after associating the event source in AWS. Events are only published to active integrations.
In the AWS EventBridge console, navigate to **Rules** and select your partner event bus.
Create rules to route events to your targets. Use event patterns to filter by event type:
```json theme={null}
{
"detail-type": ["incident.created", "incident.resolved"]
}
```
Or match all Rootly events:
```json theme={null}
{
"source": [{
"prefix": "aws.partner/rootly.com"
}]
}
```
Create a test incident in Rootly and verify that events appear in your EventBridge targets. Check the EventBridge monitoring tab for delivery metrics.
## Event Payload Structure
Events are published using the [EventBridge event format](https://docs.aws.amazon.com/eventbridge/latest/userguide/aws-events.html). Each event contains:
| Field | Description |
| ------------- | -------------------------------------------------- |
| `source` | The full partner event source name |
| `detail-type` | The event type (for example, `incident.created`) |
| `detail` | JSON object containing the entity data |
| `time` | ISO 8601 timestamp of when the event was published |
| `resources` | Array containing the resource ARN |
### Incident Event Detail
```json theme={null}
{
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"sequential_id": 42,
"title": "Database outage in us-east-1",
"slug": "database-outage-in-us-east-1",
"summary": "Production database is experiencing connection timeouts",
"status": "started",
"kind": "normal",
"private": false,
"detected_at": "2026-01-15T10:30:00Z",
"acknowledged_at": null,
"started_at": "2026-01-15T10:30:00Z",
"mitigated_at": null,
"resolved_at": null,
"cancelled_at": null,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-01-15T10:30:00Z",
"services": [
{ "id": "abc-123", "name": "API Service", "slug": "api-service" }
],
"environments": [
{ "id": "def-456", "name": "Production", "slug": "production" }
],
"functionalities": [
{ "id": "ghi-789", "name": "Authentication", "slug": "authentication" }
],
"severity": {
"id": "jkl-012", "name": "Critical", "slug": "critical", "color": "#FF0000"
}
}
```
### Alert Event Detail
```json theme={null}
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"source": "pagerduty",
"summary": "High CPU usage on web-server-01",
"status": "triggered",
"labels": { "env": "production", "service": "web" },
"started_at": "2026-01-15T10:30:00Z",
"ended_at": null,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-01-15T10:30:00Z",
"services": [
{ "id": "abc-123", "name": "Web Service", "slug": "web-service" }
],
"environments": [
{ "id": "def-456", "name": "Production", "slug": "production" }
]
}
```
## Multiple Integrations
You can create multiple EventBridge integrations for the same team. This is useful for:
* **Multi-region delivery**: Stream events to different AWS regions
* **Multi-account delivery**: Send events to separate AWS accounts (for example, production vs. staging)
* **Selective subscriptions**: Send only alert events to one bus and only incident events to another
Each integration operates independently with its own event source, subscriptions, and active status.
## Managing Integrations
### Editing
You can update the integration name, event subscriptions, and active status at any time. AWS Account ID, Region, and Event Source Name are locked after creation.
### Deleting
Deleting an integration in Rootly stops event delivery. The partner event source remains in your AWS account and can be cleaned up from the EventBridge console.
## Troubleshooting
1. Verify the integration is marked as **Active** in Rootly
2. Confirm the partner event source is **Associated** in the AWS EventBridge console
3. Check that the event type is included in the integration's subscriptions (or that subscriptions are empty for all events)
4. Verify your EventBridge rules are targeting the correct partner event bus
Ensure you are looking in the correct AWS region. The event source is created in the region selected when configuring the integration. Also verify the AWS Account ID is correct.
Check the **Event Subscriptions** setting on your integration. If specific events are selected, only those events will be published. Clear all subscriptions to receive all event types.
Events are published asynchronously via background jobs. Under normal conditions, events are delivered within a few seconds. If you observe persistent delays, contact Rootly Support.
## Best Practices
* **Use event subscriptions** to limit events to only what you need, reducing noise and cost
* **Create separate integrations** for different environments or AWS accounts
* **Use EventBridge rules** for fine-grained filtering beyond what subscriptions provide
* **Monitor delivery** using EventBridge metrics in CloudWatch
* **Test in staging first** by creating a separate integration pointed at a non-production AWS account
# AWS SNS
Source: https://docs.rootly.com/integrations/aws-sns
Receive alerts from Amazon SNS topics in Rootly using a versioned payload schema to create, route, deduplicate, and automatically resolve alerts.
## Overview
The AWS SNS integration allows Rootly to treat Amazon Simple Notification Service (SNS) messages as a native alert source. Rootly subscribes to an SNS topic using an HTTPS webhook endpoint and processes SNS `Notification` messages that contain a supported Rootly alert payload.
Unlike AWS CloudWatch, Amazon SNS is a transport layer rather than a fixed alert producer. To keep alert creation and resolution predictable, Rootly expects a versioned JSON schema inside the SNS `Message` field. This schema defines the alert status, summary, external identifier, and any optional metadata used for routing, urgency, labels, and enrichment.
When Rootly receives an SNS payload with `status: "triggered"`, it creates a new alert. When Rootly receives a payload with `status: "resolved"` and the same `external_id`, it resolves the corresponding alert.
Alerts created from SNS can be routed to services, escalation policies, or teams, enriched with labels and metadata, customized with alert fields, and sent directly to specific notification targets using Rootly's specialized webhook endpoint format.
AWS SNS does not define a native alert schema. Rootly requires a versioned payload contract inside the SNS Message body so alerts can be created and resolved consistently.
AWS SNS alert-source support is currently in beta. Rootly recommends validating your payloads, routing rules, urgency configuration, and resolve behavior in a non-production environment before rolling the integration out broadly.
## How the Integration Works
Amazon SNS publishes messages to a Rootly-managed HTTPS webhook endpoint generated when you create an AWS SNS alert source in Rootly.
When Amazon SNS sends a `SubscriptionConfirmation` request, Rootly automatically attempts to confirm the subscription. After the subscription is confirmed, SNS delivers `Notification` messages to the Rootly webhook endpoint.
For each incoming notification, Rootly reads the SNS envelope and parses the JSON content stored in the `Message` field. Rootly validates that message against the supported versioned schema and then uses the following fields to determine behavior:
* `version` identifies which Rootly payload contract is being used.
* `status` determines whether the alert should be triggered or resolved.
* `summary` becomes the alert title unless overridden by alert fields.
* `external_id` is used to match trigger and resolve events for the same alert.
## Prerequisites
Before configuring the integration, ensure that you have access to an AWS account with permissions to manage SNS topics and subscriptions. You must also have a Rootly account with access to Alert Sources.
## Setup Instructions
Begin by creating an AWS SNS alert source in Rootly. Navigate to **Settings** → **Alert Sources** and click **Add Alert Source**. Select **AWS SNS** and provide a descriptive name, such as “Production SNS Alerts.”
You may optionally configure default alert urgency, owner groups, alert fields, or deduplication settings. Once the alert source is saved, copy the webhook URL provided by Rootly.
```txt theme={null}
https://webhooks.rootly.com/webhooks/incoming/aws_sns_webhooks?secret=YOUR_SECRET_KEY
```
The webhook secret authenticates incoming requests from Amazon SNS. Treat this value as sensitive and rotate it if it is exposed.
In the AWS SNS Console, create a new topic using the **Standard** topic type and give it a clear, descriptive name such as `rootly-aws-sns-alerts`.
This SNS topic acts as the delivery mechanism between your alert publisher and Rootly.
Open the SNS topic and navigate to the **Subscriptions** tab. Create a new subscription using the **HTTPS** protocol and paste the Rootly webhook URL into the endpoint field.
AWS sends a subscription confirmation request to the webhook endpoint. Rootly automatically attempts to confirm this request, and the subscription typically transitions to **Confirmed** within a few seconds.
If the subscription remains in a pending state, verify that the webhook endpoint is reachable and that no network restrictions are blocking AWS SNS traffic.
In the AWS SNS Console, open the topic and click **Publish message**. Paste a valid Rootly SNS schema payload into the message body.
For a minimal trigger test, publish the following JSON as the SNS message body:
```json theme={null}
{
"version": 1,
"status": "triggered",
"summary": "SNS staging validation trigger",
"description": "trigger test",
"external_id": "sns-staging-validation-1"
}
```
Rootly receives this JSON inside the SNS `Message` field and validates it before creating the alert.
To resolve the alert, publish another SNS message with the same `external_id` and `status: "resolved"`.
```json theme={null}
{
"version": 1,
"status": "resolved",
"summary": "SNS staging validation trigger",
"description": "resolve test",
"external_id": "sns-staging-validation-1"
}
```
After the message is received, Rootly resolves the matching unresolved alert.
## Supported Payload Schema
Rootly currently supports **version 1** of the AWS SNS alert payload schema.
If an SNS notification does not follow the supported schema, Rootly responds with an HTTP 200 status and ignores the payload. This prevents Amazon SNS from repeatedly retrying malformed messages under a retry policy. Rootly still records a validation error for debugging, so you can correct the payload and republish it.
### Required Fields
* `version`
* `status`
* `summary`
* `external_id`
### Supported Status Values
* `triggered`
* `resolved`
### Optional Fields
* `noise`
* `description`
* `service_ids`
* `group_ids`
* `environment_ids`
* `external_url`
* `alert_urgency_id`
* `labels`
* `data`
* `started_at`
* `ended_at`
### Version 1 Example
```json theme={null}
{
"version": 1,
"noise": null,
"status": "triggered",
"summary": "High CPU usage on web-server-01",
"description": "CPU usage exceeded 95% for 5 minutes",
"service_ids": ["550e8400-..."],
"group_ids": ["660e8400-..."],
"environment_ids": [],
"external_id": "alert-12345",
"external_url": "https://acme.com/alerts/1",
"alert_urgency_id": "880e8400-...",
"labels": [
{ "key": "region", "value": "us-east-1" }
],
"data": { "metric": "cpu.usage" },
"started_at": "2026-03-11T10:00:00Z",
"ended_at": null
}
```
Use the same external\_id for the triggered and resolved messages that represent the same alert. Rootly uses this value to match resolve events to the correct alert.
## Alert Mapping and Behavior
Rootly maps SNS schema fields to alert attributes as follows:
* `summary` becomes the alert title.
* `description` becomes the alert description.
* `external_id` is used to correlate trigger and resolve events.
* `external_url` becomes the source link.
* `labels` are attached to the alert as Rootly labels.
* `data` is stored as alert payload metadata and can be used in alert fields, urgency rules, and routing conditions.
* `service_ids`, `group_ids`, and `environment_ids` can associate the alert with existing Rootly resources.
If you configure alert fields for the source, those fields can override the title, description, and source link shown in Rootly.
## Advanced Configuration
### Alert Fields
Alert fields allow you to transform the incoming SNS payload into alert fields using Liquid templates. These fields can be used to customize the alert title, description, and source link, as well as create additional custom fields for routing, urgency, filtering, and reporting.
Because SNS messages are stored as alert payload data in Rootly, you can inspect a sample alert from the source and use the alert payload viewer to copy Liquid variables and JSONPath selectors for field configuration.
### Alert Urgency
AWS SNS alerts can be assigned urgency dynamically using Rootly alert urgency rules. Rules may be based on raw payload JSONPath values or on alert field values generated from the SNS message.
If no rule matches, Rootly applies the source's fallback alert urgency.
### Deduplication and Resolution
Rootly uses `external_id` to match trigger and resolve events for the same SNS alert. If you want to suppress repeated notifications that represent the same incoming event, you can also configure a unique identifier in the **Events** tab and enable duplicate alert suppression.
This deduplication setting is separate from the required `external_id` field:
* `external_id` matches triggered and resolved events for the same alert.
* the **Events** tab unique identifier can suppress repeated create events before additional alerts are created.
### Notification Targets
In addition to default routing rules, SNS alerts can be sent directly to specific notification targets using a specialized webhook endpoint.
```txt theme={null}
https://webhooks.rootly.com/webhooks/incoming/aws_sns_webhooks/notify/{notification_target_type}/{notification_target_id}?secret=YOUR_SECRET_KEY
```
The notification target type must be one of `Service`, `EscalationPolicy`, or `Group`. The notification target ID must be replaced with the UUID of the corresponding resource.
### Webhook Payload Structure
Amazon SNS delivers a standard SNS envelope to Rootly. The Rootly alert payload is expected inside the `Message` field as JSON.
At delivery time, the full payload sent by SNS resembles the following structure:
```json theme={null}
{
"Type": "Notification",
"MessageId": "11111111-1111-1111-1111-111111111111",
"Message": "{\"version\":1,\"status\":\"triggered\",\"summary\":\"SNS staging validation trigger\",\"description\":\"trigger test\",\"external_id\":\"sns-staging-validation-1\"}"
}
```
When publishing from the SNS Console, you normally provide only the inner JSON object. Amazon SNS wraps it in the outer envelope automatically.
### Security Considerations
Rootly webhook endpoints require HTTPS and use a secret key to authenticate incoming requests. SNS subscription confirmation requests are automatically handled by Rootly. If IP allowlisting is enabled for your Rootly instance, ensure that AWS SNS traffic is permitted.
## Troubleshooting
Verify that the SNS subscription is confirmed and that the webhook URL configured in SNS exactly matches the one provided by Rootly. Confirm that the published SNS message contains valid JSON in the Message field and includes the required Rootly schema fields: version, status, summary, and external\_id.
Ensure that the resolved SNS message uses status: "resolved" and the same external\_id used when the alert was first triggered. If the external\_id differs, Rootly will treat the resolution as unrelated to the original alert.
Confirm that the webhook endpoint is reachable over HTTPS and that no firewall rules or IP allowlisting restrictions are blocking AWS SNS traffic. Also verify that the webhook URL is correctly formatted and includes the required secret parameter.
Rootly validates SNS messages against the supported versioned payload schema. Messages that do not conform to the schema are ignored to prevent repeated SNS retries. Start with the minimal valid payload and then add optional fields incrementally.
## Best Practices
* Start with the minimal required schema and add optional fields gradually as you validate your integration.
* Use a stable and descriptive `external_id` for every alert lifecycle so Rootly can reliably match trigger and resolve events.
* Store additional contextual metadata under `data` so it can be reused in alert fields, urgency rules, and routing conditions.
* Use alert fields and the payload viewer in Rootly to validate Liquid variables and JSONPath selectors before depending on them for routing or urgency.
* Periodically publish a trigger and resolve test pair to validate that the integration continues to function as expected.
For additional assistance, consult the Rootly documentation or contact Rootly Support. You may also refer to AWS SNS documentation for more information about topic, subscription, and delivery behavior.
## Related resources
* [Prometheus Alertmanager](/integrations/alertmanager)
* [Checkly](/integrations/checkly)
* [Chronosphere](/integrations/chronosphere)
* [Dynatrace](/integrations/dynatrace)
# Azure OpenAI
Source: https://docs.rootly.com/integrations/azure-openai
Connect Rootly to Azure-hosted OpenAI deployments for AI-assisted incident workflows under your own compliance and data residency rules.
## Introduction
The Azure OpenAI integration lets you connect Rootly to AI models running inside your organization's Azure subscription. Rather than using Rootly's default OpenAI account, requests are routed through your own Azure OpenAI resource — giving you control over data residency, compliance posture, content filtering policies, and the specific model deployment your team has provisioned.
With the Azure OpenAI integration, you can:
* Generate AI-powered summaries, analyses, and responses within incident workflows
* Send custom prompts to your Azure-deployed GPT models with full Liquid template support
* Use a system prompt to define the model's role, tone, or output constraints
* Satisfy data residency and enterprise compliance requirements by keeping requests within Azure infrastructure
## Before You Begin
Before setting up the Azure OpenAI integration, make sure you have:
* A Rootly account with permission to manage integrations
* An active [Azure OpenAI resource](https://portal.azure.com) with at least one model deployed
* Your Azure OpenAI **API key**, **resource name**, and **deployment name** (details below)
Azure OpenAI resources are not automatically created with your Azure subscription. You must request access and deploy a model in the Azure Portal before connecting to Rootly.
### Finding Your Credentials
**API Key**
1. Go to the [Azure Portal](https://portal.azure.com) and open your Azure OpenAI resource.
2. Select **Keys and Endpoint** from the left menu.
3. Copy either **KEY 1** or **KEY 2**.
**Resource Name**
Your resource name is the subdomain portion of your Azure OpenAI endpoint URL. For example, if your endpoint is:
```text theme={null}
https://my-company-openai.openai.azure.com/
```
Your resource name is `my-company-openai`.
**Deployment Name**
1. In the Azure Portal, open your Azure OpenAI resource.
2. Select **Model deployments** or **Deployments** from the left menu.
3. Copy the name of the deployment you want Rootly to use (for example, `gpt-4o` or `gpt-35-turbo`).
## Installation
Navigate to the integrations page in your Rootly workspace and select **Azure OpenAI**.
Enter your **API Key**, **Resource Name**, and **Deployment Name** into the respective fields. Rootly constructs your Azure OpenAI endpoint as:
```text theme={null}
https://{resource_name}.openai.azure.com/openai/deployments/{deployment_name}
```
Your API key is encrypted at rest in Rootly.
Your Azure OpenAI integration is active. The **Create OpenAI Chat Completion** workflow action is now available in your incident and action item workflows, routing requests through your Azure deployment.
## Workflow Actions
### Create OpenAI Chat Completion
Sends a prompt to your Azure-deployed model and captures the response as a workflow output. This is the same action used by the standard OpenAI integration — when Azure OpenAI is connected, Rootly routes requests through your Azure resource automatically.
| Field | Description | Required |
| ------------- | -------------------------------------------------------------------------- | -------- |
| Model | Your configured Azure deployment — set by the deployment name you provided | Yes |
| Prompt | The user message — supports Liquid templating | Yes |
| System Prompt | Instructions for the model's role or behavior — supports Liquid templating | No |
| Temperature | Sampling temperature between `0.0` and `2.0` — controls randomness | No |
| Max Tokens | Maximum number of tokens in the response | No |
| Top P | Nucleus sampling probability between `0.0` and `1.0` | No |
Use Liquid variables in your prompts to include live incident context — for example `{{ incident.title }}`, `{{ incident.severity }}`, and `{{ incident.description }}`. See the [Liquid variables reference](/liquid/incident-variables) for all available fields.
The **System Prompt** field sets the model's persona or output format — for example: *"You are an incident response assistant. Respond in bullet points. Be concise."*
## Troubleshooting
Confirm that the API key is active and has not been revoked. In the Azure Portal, go to **Keys and Endpoint** and verify the key is still valid. Also confirm that the resource name matches the Azure OpenAI resource the key belongs to — using a key from a different resource will cause authentication to fail.
If the integration was working and then stopped, the API key may have been rotated in Azure. Update the key in the integration settings. Also check that the deployment name has not been renamed or deleted in the Azure Portal.
Azure OpenAI enforces rate limits based on your provisioned capacity (tokens per minute and requests per minute). Running many concurrent Rootly workflows may exceed these limits. Consider staggering workflows, reducing token usage with more focused prompts, or increasing your Azure OpenAI quota in the Azure Portal.
The model behavior is determined by the deployment you configured — Rootly uses your deployment name directly and does not select a model. If you need a different model, create a new deployment in the Azure Portal and update the deployment name in Rootly.
Check your Liquid syntax — unclosed tags or undefined variables can cause rendering failures. Use the [Liquid variables reference](/liquid/incident-variables) to confirm variable names and test your template in a low-stakes workflow first.
## Related Pages
Use Rootly's standard OpenAI integration if you don't need Azure-specific data residency or compliance controls.
Build workflows that use Azure OpenAI models to analyze, summarize, or respond to incidents.
Reference for all incident variables available in Liquid-templated prompts.
# Backstage
Source: https://docs.rootly.com/integrations/backstage/installation
Integrate Rootly with Spotify's Backstage developer portal to enhance service catalog management, ownership tracking, and incident response visibility.
There are two ways to connect Backstage and Rootly, and they work differently:
* The **Rootly plugin for Backstage** runs inside your Backstage instance and pushes data to Rootly. It supports a rich set of `rootly.com/...` annotations for mapping entities to Rootly services, functionalities, teams, and catalog entities.
* The **built-in Backstage integration** runs on Rootly's side and pulls entities from your Backstage catalog API on a schedule. It is configured in Rootly, with one optional annotation on your Backstage entities for owner mapping.
Pick one based on where you want the configuration to live. The annotations each mode supports are different, so check the section for the mode you use. If you want to reconcile Backstage data alongside other sources like GitHub or internal APIs, the standalone [Catalog Sync CLI](/catalog-sync) is a third option.
## Rootly plugin for Backstage
The plugin is installed in your Backstage app and pushes entities to Rootly. Installation steps and the full list of supported annotations (including `rootly.com/service-id`, `rootly.com/team-slug`, auto-import, and attribute pass-through annotations) are documented in the plugin README:
[https://github.com/rootlyhq/backstage-plugin](https://github.com/rootlyhq/backstage-plugin)
## Built-in Backstage integration
The built-in integration pulls entities from your Backstage catalog API and syncs them into Rootly. To set it up:
1. In Rootly, go to **Catalogs** and click **Sync from Backstage**.
2. Enter your **Backstage API URL**, for example `https://backstage.myserver.com`.
3. Enter a **Backstage static authentication token** — a service-to-service [static token](https://backstage.io/docs/auth/service-to-service-auth/#static-tokens) from your Backstage instance.
4. Under **Kinds to import**, choose which Backstage kinds to pull, for example `Component`, `Group`, `System`, `API`. Leave it blank to import all kinds.
5. Optionally set **Filter entities to import** — a Backstage catalog API [query string](https://backstage.io/docs/features/software-catalog/software-catalog-api/#filtering) to scope the import.
6. Click **Sync from Backstage**.
### What the sync creates
Imported entities are grouped into Rootly [Catalogs](/catalogs) by their Backstage kind and type. For example, `Component` entities with `spec.type: service` land in a catalog named "Service", and `Group` entities land in a "Group" catalog.
Backstage relations such as Owner, System, `dependsOn`, and `providesApis` are stored as references between catalog entities. A reference only resolves if the entity it points to is also imported. If your components' owners show up blank, add `Group` to the entity kinds you import.
`Component` entities with `spec.type: service` can also sync into Rootly's built-in [Services](/configuration/services) catalog, so they can be used directly in escalation paths and workflows. Services are matched by name, so existing Rootly services are linked rather than duplicated.
Syncing into the built-in Services catalog is enabled per organization. If your components only appear in a custom catalog and not under Services, contact support to turn it on.
### What syncs onto a service
For each Backstage component synced as a service, the integration maps:
* **Name** and **description** from the entity's metadata.
* **Owning team**, resolved in this order:
1. A `rootly.com/team-slug` annotation on the component, matched against a Rootly team's slug.
2. The entity's `spec.owner` reference, matched against a Rootly team that has the corresponding Backstage ID set.
Owner syncing is additive: the sync adds the Backstage owner if it isn't already linked, and never removes teams you set in Rootly.
Other service fields, such as environments, escalation policy, and notification settings, are not synced from Backstage. Set them in the Rootly UI or via the [API](/api-reference/overview). They persist across re-syncs. For example, to set environments on a service:
```bash theme={null}
curl --request PUT \
--url https://api.rootly.com/v1/services/{service_id} \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/vnd.api+json' \
--data '{
"data": {
"type": "services",
"attributes": {
"environment_ids": ["your-environment-uuid"]
}
}
}'
```
**Deleting an entity in Backstage deletes the matching synced service in Rootly** on the next sync. If you remove a component from Backstage but want to keep the service, recreate it in Rootly without a Backstage link.
### Map owners with the team-slug annotation
The built-in integration reads one annotation from your Backstage entities: `rootly.com/team-slug`. Add it to a component to link the synced service to a Rootly team:
```yaml theme={null}
metadata:
annotations:
rootly.com/team-slug: infrastructure-platform
```
The value must match the team's slug in Rootly exactly. Owner matching does not fall back to name matching.
The other `rootly.com/...` annotations documented in the plugin README, including the `service-attr-...` attribute pass-through annotations, apply only to the Rootly plugin for Backstage. The built-in integration ignores them.
### Scope the import with filters
The entity filter uses Backstage's catalog API filter syntax: conditions inside one `filter` parameter are combined with AND, and separate `filter` parameters are combined with OR. For example, to import production service components and all groups:
```text theme={null}
filter=kind=component,spec.type=service,spec.lifecycle=production&filter=kind=group
```
## Troubleshooting
The referenced entity was not imported, so the reference has nothing to resolve to. Add the referenced kind (usually `Group` or `System`) to the entity kinds you import, and make sure your filter doesn't exclude it, then re-sync.
The built-in integration only reads `rootly.com/team-slug`. The other annotations in the plugin README, including `service-attr-...`, only work with the Rootly plugin for Backstage. Set those fields in the Rootly UI or via the API instead.
Syncing components into the built-in Services catalog is enabled per organization. Contact support to enable it, then re-sync. Existing services are matched by name, so nothing gets duplicated.
The catalog entity's Owner reference and the service's owning team are set separately. The owning team on a service requires the `rootly.com/team-slug` annotation or a `spec.owner` reference that matches a Rootly team's Backstage ID.
## Related
* [Catalogs](/catalogs)
* [Services](/configuration/services)
* [Catalog Sync CLI](/catalog-sync)
# BambooHR
Source: https://docs.rootly.com/integrations/bamboohr
Connect BambooHR to Rootly via iCal to overlay employee time off and company holidays on on-call schedules, surfacing coverage gaps early.
## Overview
BambooHR exposes your team's time-off and holiday calendar as an iCal feed. Point Rootly at that feed and vacations, PTO, and company holidays appear directly on top of your on-call schedule timeline. Shifts that overlap with someone's leave are highlighted, making it easy to create an override before the next page fires.
This is a read-only overlay. BambooHR stays the source of truth for time off; Rootly polls the feed in the background and keeps the schedule view current.
***
## Exporting the Calendar Feed from BambooHR
BambooHR maintains its own walkthrough for generating a time-off calendar URL, including which permissions are required and where the feed link is surfaced in the UI.
Follow [BambooHR's help article](https://help.bamboohr.com/s/article/587318) to copy the iCal URL for your time-off calendar, then bring it back to Rootly for the next step.
***
## Adding the Feed to Rootly
Once you have the BambooHR iCal URL, the rest of the setup happens inside Rootly's schedules view.
In the Rootly dashboard, go to **On-Call → Schedules**. In the calendar preview area, open the **Holiday calendars** dropdown.
Select **Add your team's holiday calendar**, then choose **Add a holiday calendar**.
Paste the iCal URL you copied from BambooHR into the URL field.
Give the calendar a descriptive name (for example, `BambooHR — Engineering PTO`) so teammates know what it represents. Select the appropriate timezone, or leave it blank to let Rootly infer it from the feed.
Click **Add**. Rootly fetches the calendar and begins syncing automatically. Back in the schedule view, select the new feed from the **Holiday calendars** dropdown to overlay BambooHR time off on the on-call timeline.
For the full behavior of holiday calendars in Rootly — conflict highlighting, recurring events, multi-region setups — see [Adding a Holiday Calendar](/on-call/holiday-calendar).
***
## Troubleshooting
The feed has to be toggled on per schedule preview. Open the **Holiday calendars** dropdown above the schedule and confirm the BambooHR feed is selected.
The calendar timezone determines how all-day events align with on-call shifts. Remove the calendar and re-add it with the correct timezone, or leave the timezone field blank to let Rootly infer it from the feed.
Rootly resyncs feeds periodically in the background, so a change made seconds ago may take a few minutes to appear.
***
## Frequently Asked Questions
No. Holiday calendars are read-only previews — they surface conflicts so you can decide whether to override, but they never reassign shifts.
Yes. If your team uses separate BambooHR calendars per department or region, add each as its own feed and toggle them on per schedule.
On the Rootly side, anyone with the **On-Call Admin** or **On-Call User** role can add a holiday calendar feed — see [Schedule Permissions](/on-call/schedules#permissions-access). The BambooHR side depends on your BambooHR account configuration; refer to the BambooHR help article for the specifics.
# Integrations Catalog
Source: https://docs.rootly.com/integrations/catalog
Browse every Rootly integration. Find the tools you need for alerting, communication, deployment tracking, monitoring, and ticketing.
## Featured
Connect Rootly to AWS CloudWatch to turn alarms, metrics, and infrastructure signals into faster incident detection, alerting, and response.
Connect Rootly to AWS EventBridge to stream incident and alert events into AWS and route them to Lambda, SNS, SQS, Step Functions, and other event-driven workflows.
Connect Claude to Rootly to power AI-assisted incident workflows, automate response tasks, and enhance incident management with intelligent support.
Connect Cortex to Rootly to sync service ownership and engineering context so responders can act faster with the right systems and teams in view.
Connect Datadog to Rootly to turn monitoring, logs, and alerting signals into faster incident detection, response, and coordination.
Connect GitHub to Rootly to tie code changes, deployments, and engineering workflows directly into incident response and follow-up.
Connect Linear to Rootly to turn incident follow-up work into issues and keep engineering teams aligned from response through resolution.
Connect Rootly to Notion to automatically create and update incident documentation so teams stay aligned during response, retrospectives, and follow-up.
Connect PagerDuty to Rootly to page responders, sync alert activity, and coordinate incident response across both platforms.
Connect Sentry to Rootly to turn application errors into actionable alerts and speed up incident detection and response.
Connect Slack to Rootly to declare, manage, and coordinate incidents directly from chat while keeping responders aligned in real time.
Connect Zoom to Rootly to launch incident meetings quickly and keep responders aligned in a shared collaboration space.
## Alerting
Connect Rootly to any monitoring or observability tool that can send webhooks, then route alerts, trigger escalations, and automate response from a single alert pipeline.
Connect Google Cloud to Rootly to turn cloud alerts, events, and infrastructure signals into faster incident detection, response, and coordination.
Migrate from Opsgenie to Rootly On-Call to modernize alerting, paging, and incident response in a single platform.
Connect PagerDuty to Rootly to page responders, sync alert activity, and coordinate incident response across both platforms.
Connect PagerTree to Rootly to sync alert activity, page responders, and automate incident escalation across both platforms.
Connect Prometheus Alertmanager to Rootly to turn alerting signals into actionable incidents and speed up detection, response, and coordination.
Connect VictorOps to Rootly to escalate incidents, sync alert activity, and keep responders aligned across both platforms.
## Automation
Connect Rootly to AWS EventBridge to stream incident and alert events into AWS and route them to Lambda, SNS, SQS, Step Functions, and other event-driven workflows.
Connect Claude to Rootly to power AI-assisted incident workflows, automate response tasks, and enhance incident management with intelligent support.
Connect Email to Rootly to send incident notifications, updates, and communications through email during response and recovery.
Connect Fivetran to Rootly to sync incident data into your warehouse and make reliability insights easier to analyze across your business.
Sync Rootly incident data with Glean to make incident context easier to search, discover, and use across your organization.
Connect Google Gemini to Rootly to power AI-driven workflows, automate incident tasks, and bring Gemini's multimodal intelligence into your incident response process.
Connect Mistral AI to Rootly to power AI-assisted workflows, automate incident tasks, and bring large language model capabilities into your incident response process.
Connect OpenAI to Rootly to power AI-assisted workflows, automate incident tasks, and bring intelligent support into every stage of incident response.
Connect SMTP to Rootly to send incident notifications and email-based communications through your own mail infrastructure.
Connect SendGrid to Rootly to send incident notifications and email-based communications reliably during response and recovery.
Connect ServiceNow to Rootly to turn incident follow-up work into trackable records and keep response, operations, and support teams aligned.
Connect Zapier to Rootly to automate incident workflows and connect Rootly with thousands of apps without writing custom code.
## Catalog
Connect Backstage to Rootly to bring service ownership and developer portal context into incident response so teams can act faster with the right information.
Connect Cortex to Rootly to sync service ownership and engineering context so responders can act faster with the right systems and teams in view.
## Communication
Connect Rootly to AWS SNS to publish incident notifications and operational updates so teams and systems can subscribe and respond automatically.
Connect Rootly to Google Meet to launch incident meetings quickly and keep responders aligned in a shared collaboration space.
Connect Mattermost to Rootly to declare, manage, and coordinate incidents directly from chat while keeping responders aligned in real time.
Connect Microsoft Teams to Rootly to declare, manage, and coordinate incidents directly from chat while keeping responders aligned in real time.
Connect Slack to Rootly to declare, manage, and coordinate incidents directly from chat while keeping responders aligned in real time.
Connect Rootly to Webex to launch incident meetings quickly and keep responders aligned in a shared collaboration space.
Connect X to Rootly to share incident updates publicly and keep external communications aligned during outages and recovery.
Connect Zoom to Rootly to launch incident meetings quickly and keep responders aligned in a shared collaboration space.
Connect Statuspage.io to Rootly to publish updates externally and keep customers informed with consistent status communications.
## Deployment
Connect AWS Elastic Beanstalk to Rootly to turn deployment and environment events into faster incident detection, alerting, and response.
Connect GitHub to Rootly to tie code changes, deployments, and engineering workflows directly into incident response and follow-up.
Connect GitLab to Rootly to tie deployments, code changes, and engineering workflows directly into incident response and follow-up.
Connect Heroku to Rootly to turn app and deployment events into faster incident detection, response, and coordination.
Connect Kubernetes to Rootly to turn cluster events and infrastructure issues into faster incident detection, response, and coordination.
Connect Pulumi to Rootly to automate infrastructure-aware incident workflows and keep incident response aligned with infrastructure changes.
Connect Terraform to Rootly to automate infrastructure-aware incident workflows and keep incident response aligned with infrastructure changes.
## Monitoring
Connect Rootly to AWS CloudWatch to turn alarms, metrics, and infrastructure signals into faster incident detection, alerting, and response.
Connect Datadog to Rootly to turn monitoring, logs, and alerting signals into faster incident detection, response, and coordination.
Connect Grafana to Rootly to turn metrics, dashboards, and alerting signals into faster incident detection and response.
Connect Honeycomb to Rootly to turn observability signals into actionable alerts and help teams investigate incidents with richer production context.
Connect New Relic to Rootly to turn observability signals into actionable alerts and speed up incident detection and response.
Connect Rollbar to Rootly to turn application errors into actionable alerts and speed up incident detection and response.
Connect Sentry to Rootly to turn application errors into actionable alerts and speed up incident detection and response.
Connect Splunk to Rootly to turn logs, events, and observability signals into actionable alerts and speed up incident response.
## Retrospectives
Connect Airtable to Rootly to sync incident data into flexible tables and workflows so teams can track, organize, and act on response information.
Connect Coda to Rootly to automatically create and update incident documents in shared Coda pages and keep responders aligned with live incident context.
Connect Confluence Cloud to Rootly to automatically create and update incident documentation so teams stay aligned during response, retrospectives, and follow-up.
Connect Dropbox Paper to Rootly to automatically create and update shared incident documents so teams stay aligned during response and follow-up.
Connect Rootly to Google Docs to automatically create and update incident documentation so teams stay aligned during response, retrospectives, and follow-up.
Connect Rootly to Notion to automatically create and update incident documentation so teams stay aligned during response, retrospectives, and follow-up.
Connect Rootly to Outlook to send incident notifications, coordinate communications, and keep responders aligned through email and calendar workflows.
Connect Quip to Rootly to automatically create and update shared incident documents so teams stay aligned with live response context.
Connect Rootly to SharePoint to automatically create and update incident documentation so teams stay aligned during response, retrospectives, and follow-up.
## Ticketing
Connect Asana to Rootly to turn incident follow-up work into trackable tasks and keep teams aligned after the incident.
Connect ClickUp to Rootly to turn incident follow-up work into trackable tasks and keep response actions moving across teams.
Connect Freshservice to Rootly to turn customer support issues into coordinated incident response and keep teams aligned during escalations.
Connect Jira Cloud to Rootly to turn incident follow-up work into trackable issues and keep teams aligned from response through resolution.
Connect Linear to Rootly to turn incident follow-up work into trackable issues and keep engineering teams aligned from response through resolution.
Connect Shortcut to Rootly to turn incident follow-up work into trackable tasks and keep engineering teams aligned after an incident.
Connect Trello to Rootly to turn incident follow-up work into organized boards and track response tasks across teams.
Connect Zendesk to Rootly to turn customer support issues into coordinated incident response and keep teams aligned during escalations.
## Everything Else
Connect GoToMeeting to Rootly to launch incident meetings quickly and keep responders aligned in a shared collaboration space.
Connect Rootly to Google Calendar to schedule incident meetings, coordinate responders, and keep response workflows aligned with calendar events.
Connect HashiCorp Vault to Rootly to securely retrieve secrets, rotate sensitive credentials, and support safer incident automation.
Connect Looker to Rootly to share incident data in analytics workflows and give teams better visibility into reliability trends and operational performance.
Set up SSO and SCIM with Rootly to streamline authentication, automate user provisioning, and keep access aligned with your identity provider.
Connect Workday to Rootly to sync employee and organizational data so the right users, teams, and escalation paths stay up to date.
# CharlieHR
Source: https://docs.rootly.com/integrations/charliehr
Connect CharlieHR to Rootly to overlay employee time off and vacations on on-call schedule timelines, surfacing coverage gaps before pages fire.
## Overview
CharlieHR exposes your team's time-off calendar as a subscribe-able URL. Point Rootly at that URL and vacations and PTO appear directly on top of your on-call schedule timeline. Shifts that overlap with someone's leave are highlighted, making it easy to create an override before the next page fires.
This is a read-only overlay. CharlieHR stays the source of truth for time off; Rootly polls the feed in the background and keeps the schedule view current.
***
## Exporting the Calendar Feed from CharlieHR
CharlieHR's own walkthrough covers both the user-level and admin-level flows for generating a time-off calendar URL.
Follow [CharlieHR's help article](https://help.charliehr.com/en/articles/839648-importing-your-time-off-calendar-to-google-calendar) to copy the calendar URL. The article is framed around Google Calendar, but the URL it produces is a standard subscribe-able feed that Rootly accepts directly — there's no need to route through Google Calendar first.
CharlieHR's feed covers a rolling 6-month window (past 6 months plus upcoming 6 months), and updates can take up to 48 hours to propagate.
***
## Adding the Feed to Rootly
Once you have the CharlieHR feed URL, the rest of the setup happens inside Rootly's schedules view.
In the Rootly dashboard, go to **On-Call → Schedules**. In the calendar preview area, open the **Holiday calendars** dropdown.
Select **Add your team's holiday calendar**, then choose **Add a holiday calendar**.
Paste the URL you copied from CharlieHR into the URL field.
Give the calendar a descriptive name (for example, `CharlieHR — Team PTO`) so teammates know what it represents. Select the appropriate timezone, or leave it blank to let Rootly infer it from the feed.
Click **Add**. Rootly fetches the calendar and begins syncing automatically. Back in the schedule view, select the new feed from the **Holiday calendars** dropdown to overlay CharlieHR time off on the on-call timeline.
For the full behavior of holiday calendars in Rootly — conflict highlighting, recurring events, multi-region setups — see [Adding a Holiday Calendar](/on-call/holiday-calendar).
***
## Troubleshooting
The feed has to be toggled on per schedule preview. Open the **Holiday calendars** dropdown above the schedule and confirm the CharlieHR feed is selected.
The calendar timezone determines how all-day events align with on-call shifts. Remove the calendar and re-add it with the correct timezone, or leave the timezone field blank to let Rootly infer it from the feed.
CharlieHR feeds can take up to 48 hours to update on their side, and Rootly resyncs periodically on top of that. Give the change time to propagate before troubleshooting further.
***
## Frequently Asked Questions
No. Holiday calendars are read-only previews — they surface conflicts so you can decide whether to override, but they never reassign shifts.
Yes. If different teams or regions maintain separate CharlieHR feeds, add each as its own calendar and toggle them on per schedule.
No — regular CharlieHR users can generate their own time-off feed URL from the Time view. Admins have an additional org-wide feed available under Integrations.
# Checkly
Source: https://docs.rootly.com/integrations/checkly
Connect Checkly to Rootly to turn synthetic check failures and API monitoring alerts into routed, actionable incidents and on-call pages.
## Overview
Checkly's synthetic checks and API monitors fire webhook alerts the moment something fails. Wire those webhooks at Rootly and every failure becomes a normalized alert that can page on-call, route to the right service, or auto-create an incident through alert workflows. Recovery events from Checkly close the same alert automatically, so your timeline stays clean.
Checkly has first-class support as a dedicated alert source in Rootly — you don't need the Generic Webhook source. The integration ships with vendor-specific payload parsing, pre-mapped fields, a `secret`-header authentication path, and a guided setup wizard in the Rootly dashboard.
Trigger escalation policies the moment a Checkly check fails, paging the right responder in seconds.
Turn a degraded check into a full Rootly incident with custom fields, workflows, and Slack channels.
Map Checkly's recovery event to `rootly_alert_status` and the alert closes itself when the check comes back.
Send API checks to one team, browser checks to another, all from a single Checkly alert channel.
***
## Before You Begin
**You'll need access to both sides of the connection.**
* **In Rootly** — the **On-Call Admin** or **On-Call User** role so you can create alert sources. See [Schedule Permissions](/on-call/schedules#permissions-access).
* **In Checkly** — permission to add and configure alert channels under **Alert Settings**.
A clear routing plan helps too: decide whether every alert from this source should land on the same service or team, or whether routing varies per check.
***
## Add the Alert Source in Rootly
The Rootly side hands you a webhook URL and a `secret` value — paste those into Checkly in the next section.
In the Rootly dashboard, navigate to **Alerts → Sources** and click **New alert source**.
Select **Checkly** from the list of available sources and give the source a descriptive name — for example, `Checkly — Production Synthetics`.
If every alert from this source should always route to the same service, team, or escalation policy, set the target on the source configuration page. Leave it blank if you want routing to come from each check's payload instead — covered under [Routing Alerts](#routing-alerts).
Rootly generates a unique webhook URL and a per-source `secret`. Copy both — they go into Checkly next.
Without a default routing target:
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/checkly_webhooks
```
With a default routing target baked into the URL:
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/checkly_webhooks/notify//
```
***
## Configure the Webhook in Checkly
Create a webhook alert channel in Checkly, point it at the Rootly URL, and use the payload template Rootly expects.
In Checkly, navigate to **Alert Settings → Alert Channels** and click **Add channel**. Choose **Webhook**. For the latest Checkly UI specifics, refer to [Checkly's webhook alert channel documentation](https://www.checklyhq.com/docs/alerting-and-retries/webhooks/).
Configure the request:
`POST`
The webhook URL you copied from Rootly.
Key: `secret` — Value: the secret you copied from Rootly.
Rootly's Checkly source authenticates the request using the custom `secret` header, not Bearer Token or HMAC. Without it, Rootly returns `401 Unauthorized` and the alert is dropped.
Use the JSON template below. Checkly substitutes the `{{ }}` Handlebars variables with values from the failing check at send time.
Standard template — alert lands in Rootly and routes based on the source's default target.
```json theme={null}
{
"alert_type": "{{ALERT_TYPE}}",
"check_id": "{{CHECK_ID}}",
"check_result_id": "{{CHECK_RESULT_ID}}",
"check_name": "{{CHECK_NAME}}",
"alert_title": "{{ALERT_TITLE}}",
"started_at": "{{STARTED_AT}}",
"link": "{{RESULT_LINK}}"
}
```
Add a `rootly` object to route this specific check to a different service, team, or escalation policy.
```json theme={null}
{
"alert_type": "{{ALERT_TYPE}}",
"check_id": "{{CHECK_ID}}",
"check_name": "{{CHECK_NAME}}",
"alert_title": "{{ALERT_TITLE}}",
"started_at": "{{STARTED_AT}}",
"link": "{{RESULT_LINK}}",
"rootly": {
"notification_target": {
"type": "Service",
"id": "8c4a5e91-1b2d-4c3e-9f6a-7d8b2c5e9a01"
}
}
}
```
Valid `type` values are the Rootly resource class names: `Service`, `Group`, or `EscalationPolicy`.
Use this template on a second Checkly alert channel scoped to recovery events. The `rootly_alert_status` field closes the matching alert in Rootly.
```json theme={null}
{
"check_id": "{{CHECK_ID}}",
"check_name": "{{CHECK_NAME}}",
"alert_title": "{{ALERT_TITLE}}",
"started_at": "{{STARTED_AT}}",
"rootly_alert_status": "resolved"
}
```
Save the alert channel, then attach it to the checks (or check groups) you want forwarded to Rootly. New failures on those checks POST to the Rootly webhook URL within seconds.
***
## Payload Reference
Rootly's Checkly source parses these fields from each incoming webhook. The full raw payload is also preserved on the alert record, so any extra fields Checkly sends remain accessible to alert routes, workflows, and field mappings.
The name of the Checkly check that fired. Joined with `alert_title` using `" - "` to form the Rootly alert's summary.
The descriptive title Checkly attached to the alert. Combined with `check_name` for the alert summary.
Stable identifier for the check. Rootly uses this as the **External Identifier** to match recovery events back to the original alert for auto-resolution.
When the check first failed. Populates the alert's started-at timestamp.
Direct link back to the failing check in the Checkly dashboard. Preserved on the alert record for responders to jump straight to the source.
Optional. Sets the routing target for this specific alert. Used only when the alert source does **not** have a default URL-based target — if a URL target is configured on the source, it takes precedence and the payload target is ignored. Expects `type` (`Service`, `Group`, or `EscalationPolicy`) and `id` (the Rootly resource's internal ID).
Optional. Sets the alert state directly. Use `resolved` on recovery channels so Checkly's "check is back" event closes the original Rootly alert.
***
## Routing Alerts
Two ways to point a Checkly alert at the right responder. URL-based routing takes precedence when both are set on the same request.
Set a default routing target when you create the alert source. Rootly bakes it into the webhook URL:
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/checkly_webhooks/notify/Service/
```
Every alert from this Checkly channel routes to that target — no payload-level routing needed.
**Best when**: a single Checkly account corresponds to one Rootly team or service.
Leave the default target empty on the Rootly source. In each Checkly alert channel's payload template, add a `rootly` object naming the target:
```json theme={null}
"rootly": {
"notification_target": {
"type": "Service",
"id": "8c4a5e91-1b2d-4c3e-9f6a-7d8b2c5e9a01"
}
}
```
Valid `type` values are the Rootly resource class names: `Service`, `Group`, or `EscalationPolicy`. The `id` is the Rootly resource's internal ID — open the resource in Rootly and copy it from the edit page. Names and slugs aren't accepted.
**Best when**: different checks need to page different teams. You can hardcode targets per channel, or use Checkly's per-check variables to switch them dynamically.
***
## Auto-Resolution
Checkly fires a recovery event whenever a failing check comes back to passing. Rootly closes the original alert automatically when the recovery payload includes `"rootly_alert_status": "resolved"`.
The cleanest pattern is **two separate Checkly alert channels** scoped to different alert events:
* **Failure channel** — uses the **Basic Alert** payload from the [Configure step](#configure-the-webhook-in-checkly) above, unchanged. No `rootly_alert_status` field needed; Rootly defaults to a triggered state when one isn't present.
* **Recovery channel** — uses the **Recovery (Auto-Resolve)** template, which hardcodes `"rootly_alert_status": "resolved"`.
Rootly matches the two events using the **External Identifier** (`check_id`) and transitions the same alert from triggered to resolved.
See [Alert Statuses](/alerts/alert-statuses) for the full lifecycle.
***
## Test the Integration
After saving the alert channel in Checkly, run a test to confirm the connection works end-to-end.
Open the alert channel you created and click **Send test webhook**. Checkly POSTs a sample payload to the Rootly URL.
Open the Checkly alert source in Rootly. The test alert should appear in the source's recent activity within a few seconds. Click into it to verify the title, started-at timestamp, and link populated correctly.
For full end-to-end verification, deliberately fail a check (point an API check at a 500-returning endpoint, for example) and confirm the alert reaches Rootly with the correct routing target and triggers the workflow you expect.
A successful test alert in Rootly means the webhook URL, the `secret` header, and the payload template are all wired correctly. You're ready to attach the channel to production checks.
***
## Troubleshooting
The `secret` header is missing or doesn't match the value shown on the Rootly source configuration. Re-copy the secret from Rootly, paste it as a custom header in the Checkly alert channel (header key: `secret`, value: the secret string), and re-send a test.
Rootly processes webhooks asynchronously, so check again after a few seconds. If the alert still doesn't appear:
* Confirm the routing target referenced in the URL or payload exists and isn't archived
* Inspect the source's recent activity in Rootly to verify the payload was received
* Verify `check_name` and `alert_title` aren't empty in the payload template
Either the recovery payload has a different `check_id` than the failure event, or the `rootly_alert_status` field isn't set to `resolved` (case-sensitive). Confirm both events come from the same Checkly check and that the recovery channel's template hardcodes `"rootly_alert_status": "resolved"`.
URL-based routing takes precedence over payload-based routing. If the webhook URL ends with `/notify//`, that target wins regardless of the JSON body. Either remove the URL target and rely on payload routing, or update the URL target to the correct destination.
Checkly retries up to five times with 20-second backoff on any HTTP response above 399. If Rootly returned `401`, check the `secret` header. If Rootly returned `500`, contact Rootly support with the timestamps so they can correlate against server logs.
***
## Frequently Asked Questions
No. Rootly ships a dedicated Checkly alert source with vendor-specific payload parsing, pre-mapped fields, and the `secret`-header authentication shown above. Use it instead of the Generic Webhook source for a cleaner setup and built-in field mappings.
Yes. Create a separate Checkly alert channel for each Rootly source you want to feed — each with its own webhook URL and secret — and attach each channel to the relevant checks. Useful when different check groups need to route to different Rootly teams.
Rootly's Checkly source authenticates via the `secret` custom header, not HMAC. Checkly's optional `x-checkly-signature` SHA-256 signature isn't required and isn't validated.
Set the source's default routing target (or the payload's `rootly.notification_target`) to an **Escalation Policy**. Rootly triggers the escalation as soon as the alert is created, paging the on-call responder per the policy's steps.
Adjust the payload template in Checkly's alert channel. The `check_name` and `alert_title` Handlebars variables can be combined with static text — for example, `"alert_title": "[{{SEVERITY}}] {{CHECK_NAME}} failing"`. Rootly stores whatever string you produce as the alert summary.
***
## Next Steps
Configure routes that send alerts from this source to the right responders based on severity, region, or any custom field.
Auto-create incidents, post Slack notifications, run runbooks, and chain follow-up actions from Checkly alerts.
Extract custom fields from the Checkly payload (severity, region, deployment) for richer routing and reporting.
Confirm which Rootly roles can create and edit this alert source.
# Chronosphere
Source: https://docs.rootly.com/integrations/chronosphere
Connect Chronosphere to Rootly to turn observability alerts into actionable incidents, paging on-call responders directly from monitor notifications.
## Overview
Chronosphere's notification policies fan monitor alerts out to wherever they need to go. Point one of those webhooks at Rootly and every triggering monitor becomes a normalized alert that can page on-call, route to a service, or auto-create a full incident through alert workflows. Alertmanager-style batches arrive as a single Rootly alert, fingerprint-keyed so duplicates don't pile up.
Chronosphere has first-class support as a dedicated alert source in Rootly — you don't need the Generic Webhook source. The integration ships with vendor-specific Alertmanager payload parsing, fingerprint-based deduplication via UUID v5, and a guided setup wizard in the Rootly dashboard.
Fire escalation policies the moment a Chronosphere monitor triggers, paging the right responder in seconds.
Turn a monitor alert into a full Rootly incident with custom fields, workflows, and Slack channels.
Chronosphere's Alertmanager-style batches collapse into a single Rootly alert, keyed on the sorted fingerprint set.
Send infrastructure alerts to one team and application alerts to another, all from a single Chronosphere notification policy.
***
## Before You Begin
**You'll need access to both sides of the connection.**
* **In Rootly** — the **On-Call Admin** or **On-Call User** role so you can create alert sources. See [Schedule Permissions](/on-call/schedules#permissions-access).
* **In Chronosphere** — permission to create notifiers and notification policies (typically Admin or a custom role with notifier write access).
A clear routing plan helps too: decide whether every alert from this Chronosphere notifier should land on the same service or team, or whether routing varies per monitor.
***
## Add the Alert Source in Rootly
The Rootly side hands you a webhook URL with the authentication `secret` baked into the query string. Paste that URL into Chronosphere in the next section.
In the Rootly dashboard, navigate to **Alerts → Sources** and click **New alert source**.
Select **Chronosphere** from the list of available sources and give the source a descriptive name — for example, `Chronosphere — Production Monitors`.
If every alert from this source should always route to the same service, team, or escalation policy, set the target on the source configuration page. Leave it blank if you want routing to vary per Chronosphere notification policy — covered under [Routing Alerts](#routing-alerts).
Rootly generates a unique webhook URL with the per-source `secret` embedded as a query parameter. Copy the full URL — that's what goes into Chronosphere.
Without a default routing target:
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/chronosphere_webhooks?secret=
```
With a default routing target baked into the URL:
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/chronosphere_webhooks/notify//?secret=
```
***
## Configure the Webhook in Chronosphere
Create a webhook notifier in Chronosphere, point it at the Rootly URL, then attach it to a notification policy.
In Chronosphere, navigate to **Alerts → Notifiers** and click **Create notifier**. Choose **Webhook** as the type. For the latest Chronosphere UI specifics, refer to [Chronosphere's webhook notifier documentation](https://docs.chronosphere.io/investigate/alerts/notifications/notifiers/webhook).
Paste the full webhook URL you copied from Rootly into the **URL** field, including the `?secret=...` query string. The method is `POST`.
Rootly's Chronosphere source authenticates the request using the `secret` query parameter — not Bearer Token or HMAC. The secret has to remain on the URL, so treat the full webhook URL as a credential.
Chronosphere's webhook notifier has a **Notify when resolved** toggle. Leaving it **off** is recommended for the Rootly source — resolved events are not used to close alerts in Rootly (covered in [Handling Resolved Events](#handling-resolved-events) below).
Save the notifier, then open or create a **Notification Policy** in Chronosphere. Add a rule that routes the monitors you care about to the new Rootly notifier. New triggers on those monitors POST to the Rootly webhook URL within seconds.
Chronosphere optionally signs webhooks with HMAC-SHA256 via the `Chronosphere-Webhook-Timestamp` header. Rootly's Chronosphere source doesn't verify that signature — authentication relies on the `secret` query parameter instead. You can leave Chronosphere's signing toggle off without affecting the integration.
***
## Payload Reference
Rootly's Chronosphere source parses the Alertmanager-style payload Chronosphere sends. The full raw payload is preserved on the alert record, so any field Chronosphere sends remains accessible to alert routes, workflows, and field mappings.
The monitor's alert name from Chronosphere's common labels. Populates the Rootly alert's summary. Defaults to `"Alert from Chronosphere"` if absent.
Array of one or more alert objects. Each contains at minimum a `fingerprint` and a `startsAt` timestamp.
Chronosphere's stable identifier for each individual alert. Rootly combines all fingerprints from a single webhook (sorted, comma-joined, UUID v5 hashed) into the **External Identifier** for deduplication.
When the first alert in the batch began firing. Populates the Rootly alert's started-at timestamp.
Direct link back to the Chronosphere alert view. Preserved on the alert record for responders to jump straight to the source.
Either `firing` or `resolved`. See [Handling Resolved Events](#handling-resolved-events) for behavior differences.
Optional. Sets the routing target for this specific webhook. Used only when the alert source does **not** have a default URL-based target — if a URL target is configured on the source, it takes precedence. Expects `type` (`Service`, `Group`, or `EscalationPolicy`) and `id` (the Rootly resource's internal ID).
***
## Routing Alerts
Two ways to point a Chronosphere alert at the right responder. URL-based routing takes precedence when both are configured.
Set a default routing target when you create the alert source. Rootly bakes it into the webhook URL:
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/chronosphere_webhooks/notify/Service/?secret=
```
Every alert from this Chronosphere notifier routes to that target — no payload-level routing needed.
**Best when**: a single Chronosphere notifier corresponds to one Rootly team or service.
Leave the default target empty on the Rootly source. In Chronosphere's notifier payload template (or your notification policy variables), inject a `rootly` object naming the target. Most teams use a separate Chronosphere notifier per Rootly target rather than templating per alert, but both work.
```json theme={null}
{
"rootly": {
"notification_target": {
"type": "Service",
"id": "8c4a5e91-1b2d-4c3e-9f6a-7d8b2c5e9a01"
}
}
}
```
Valid `type` values are the Rootly resource class names: `Service`, `Group`, or `EscalationPolicy`. The `id` is the Rootly resource's internal ID — open the resource in Rootly and copy it from the edit page. Names and slugs aren't accepted.
**Best when**: different notifiers (or different notification policies) need to page different teams.
***
## Handling Resolved Events
**Resolved events from Chronosphere are silently dropped — they do not close the matching Rootly alert.** This is intentional: Chronosphere's resolved notifications are noisy in environments with high monitor churn, and Rootly treats alert lifecycle as a workflow concern rather than a webhook concern.
What this means in practice:
* A Chronosphere webhook with `"status": "firing"` creates or updates a Rootly alert
* A follow-up webhook with `"status": "resolved"` is ingested but produces no alert mutation — Rootly returns 200 and discards the event
* Alerts created from Chronosphere stay in their triggered state until a responder resolves them in Rootly, or until an alert workflow closes them based on its own logic
If you want resolution behavior driven by Chronosphere, build an alert workflow that closes alerts based on time-since-creation, on a downstream signal, or on a manual responder action. Don't rely on Chronosphere's resolved notifications to clean up the Rootly side.
You can leave Chronosphere's **Notify when resolved** toggle off to avoid sending noise that gets discarded anyway.
***
## Multi-Alert Payloads
Chronosphere's Alertmanager-style webhook can include multiple alerts in a single POST under the `alerts` array — typical when a notification policy groups related monitors together. Rootly collapses the entire batch into a **single** Rootly alert:
* The **External Identifier** is computed as `uuid_v5(DNS namespace, fingerprints.sort.join(","))` — every fingerprint in the batch contributes, so the same batch produces the same identifier on retry, and a different batch produces a different identifier
* The **summary** comes from `commonLabels.alertname` (a single field on the batch, not per-alert)
* The **started\_at** timestamp comes from the first alert in the array (`alerts[0].startsAt`)
* The entire payload is preserved on the alert record, so per-alert details remain accessible to alert workflows and field mappings
If you want each Chronosphere alert to be its own Rootly alert, configure Chronosphere's notification policy to send one alert per webhook (no grouping). Rootly's parsing matches whatever shape Chronosphere sends.
***
## Troubleshooting
The `secret` query parameter is missing from the webhook URL or doesn't match the value Rootly generated for this source. Re-copy the full webhook URL from the alert source configuration in Rootly (it includes `?secret=...`) and paste it into the Chronosphere notifier's URL field, replacing the existing one.
A few common causes:
* The webhook payload had `"status": "resolved"` — Rootly drops resolved events on purpose (see [Handling Resolved Events](#handling-resolved-events))
* Rootly processes webhooks asynchronously; check again after a few seconds
* Confirm the routing target referenced in the URL or payload exists and isn't archived
* Inspect the source's recent activity in Rootly to verify the payload was received
Each unique fingerprint set produces a separate Rootly alert. If Chronosphere is grouping alerts differently between webhooks (different fingerprints in the batch), Rootly sees them as new alerts. Check the notification policy's grouping rules in Chronosphere to ensure consistent batching.
URL-based routing takes precedence over payload-based routing. If the webhook URL ends with `/notify//`, that target wins regardless of the JSON body. Either remove the URL target and rely on payload routing, or update the URL target to the correct destination.
Open the Chronosphere notifier's delivery history. Rootly returns `401` if the `secret` query parameter is missing or wrong, and `500` for server-side issues. For 500 responses, contact Rootly support with the timestamps so they can correlate against server logs.
***
## Frequently Asked Questions
No. Rootly ships a dedicated Chronosphere alert source with Alertmanager-style payload parsing, fingerprint-based deduplication, and pre-mapped fields. Use it instead of the Generic Webhook source — you'll get cleaner setup and built-in batch handling.
Chronosphere's resolved notifications fire frequently in environments with monitor churn, which would create unwanted lifecycle churn on the Rootly side. Rootly treats alert resolution as a workflow concern — drive it from alert workflows, responder action, or downstream signals rather than vendor recovery webhooks. See [Handling Resolved Events](#handling-resolved-events) for the rationale.
Yes — configure Chronosphere's notification policy to send a separate webhook per alert (no grouping). Rootly parses each POST independently, so single-alert batches produce single Rootly alerts.
No. Rootly's Chronosphere source authenticates via the `secret` query parameter only. Chronosphere's optional `Chronosphere-Webhook-Timestamp` + HMAC-SHA256 signature isn't required or validated. You can leave signing off in Chronosphere without affecting the integration.
Set the source's default routing target (or the payload's `rootly.notification_target`) to an **Escalation Policy**. Rootly triggers the escalation as soon as the alert is created, paging the on-call responder per the policy's steps.
***
## Next Steps
Configure routes that send Chronosphere alerts to the right responders based on severity, region, or any custom field.
Auto-create incidents, post Slack notifications, run runbooks, and chain follow-up actions from Chronosphere alerts.
Extract custom fields from Chronosphere's Alertmanager labels (severity, region, service) for richer routing and reporting.
Confirm which Rootly roles can create and edit this alert source.
# CLI
Source: https://docs.rootly.com/integrations/cli
Manage Rootly incidents, alerts, services, teams, on-call schedules, and workflows from your terminal with the official Rootly command-line interface.
The Rootly CLI is a command-line interface for managing Rootly resources directly from your terminal. Built for engineers who prefer working in the terminal, it provides fast access to incidents, alerts, services, teams, and on-call schedules.
## Features
* **Incidents**: Full CRUD operations with filtering by status, severity, and more
* **Alerts**: Create, acknowledge, and resolve alerts with source tracking
* **Services & Teams**: Manage your service catalog and team structure
* **On-Call**: Query schedules, view shifts, and see who is on-call right now
* **Pulses**: Track events and wrap command execution with automatic pulse recording
* **Multiple Output Formats**: Table, JSON, YAML, and Markdown
* **TTY-Aware Output**: Table format in terminal, JSON when piped
* **Shell Completions**: Bash, Zsh, Fish, and PowerShell
* **Pagination & Filtering**: Server-side filtering with paginated results
## Installation
### Using Homebrew (macOS/Linux)
```bash theme={null}
brew install rootlyhq/tap/rootly-cli
```
### Using Go
```bash theme={null}
go install github.com/rootlyhq/rootly-cli/cmd/rootly@latest
```
### Download Binary
Download the latest release from [GitHub Releases](https://github.com/rootlyhq/rootly-cli/releases).
Available for Linux (amd64/arm64), macOS (Intel/Apple Silicon), and Windows (amd64).
## Quick Start
1. **Set your API key**:
```bash theme={null}
export ROOTLY_API_TOKEN="your-api-key"
```
2. **List your incidents**:
```bash theme={null}
rootly incidents list
```
3. **Get incident details**:
```bash theme={null}
rootly incidents get INC-123
```
## Configuration
Set your API token via environment variable or config file:
```bash theme={null}
# Environment variable (recommended for CI/scripts)
export ROOTLY_API_TOKEN="your-api-key"
```
Or create a config file at `~/.rootly-cli/config.yaml`:
```yaml theme={null}
api_token: "your-api-key"
endpoint: "api.rootly.com" # Optional, defaults to api.rootly.com
```
### Getting an API Key
1. Log in to your Rootly account
2. Navigate to **Settings** > **API Keys**
3. Create a new API key with appropriate permissions
## Commands
### Incidents
```bash theme={null}
# List incidents
rootly incidents list
# List with filters
rootly incidents list --status=started --severity=critical
# Get incident details
rootly incidents get INC-123
# Create a new incident
rootly incidents create --title="Database outage" --severity=critical
# Update an incident
rootly incidents update INC-123 --status=mitigated
# Delete an incident
rootly incidents delete INC-123
```
### Alerts
```bash theme={null}
# List alerts
rootly alerts list
# Get alert details
rootly alerts get ALR-123
# Create a new alert
rootly alerts create --summary="High CPU usage" --source=datadog
# Acknowledge an alert
rootly alerts ack ALR-123
# Resolve an alert
rootly alerts resolve ALR-123 --message="Issue fixed"
```
### Services
```bash theme={null}
# List services
rootly services list
# Get service details
rootly services get api-gateway
# Create a service
rootly services create --name="api-gateway"
# Update a service
rootly services update api-gateway --description="Main API gateway"
# Delete a service
rootly services delete api-gateway
```
### Teams
```bash theme={null}
# List teams
rootly teams list
# Get team details
rootly teams get engineering
# Create a team
rootly teams create --name="Platform"
# Update a team
rootly teams update engineering --color="#FF5733"
# Delete a team
rootly teams delete engineering
```
### On-Call
```bash theme={null}
# List on-call schedules
rootly oncall list
# View upcoming shifts (next 7 days)
rootly oncall shifts
# View shifts for next 14 days
rootly oncall shifts --days=14
# See who is on-call right now
rootly oncall who
# Filter shifts by schedule
rootly oncall shifts --schedule="Primary On-Call"
```
### Pulses
```bash theme={null}
# Send a pulse event
rootly pulse create "Deploy v1.2.3"
# With labels and services
rootly pulse create "Deploy v1.2.3" --labels="version=1.2.3,team=backend" --services=api-gateway
# Wrap a command and automatically record timing and exit code
rootly pulse run -- make deploy
# Wrap with summary and metadata
rootly pulse run --summary="Deploy to prod" --services=api-gateway --labels="env=prod" -- make deploy
```
The `pulse run` variant automatically captures the wrapped command's exit code as a label (`exit_status`).
| Flag | Short | Env Variable | Description |
| ---------------- | ----- | --------------------- | -------------------------------------------- |
| `--labels` | `-l` | `ROOTLY_LABELS` | Key=value pairs, comma-separated |
| `--services` | `-s` | `ROOTLY_SERVICES` | Service slugs or IDs, comma-separated |
| `--environments` | `-e` | `ROOTLY_ENVIRONMENTS` | Environment slugs or IDs, comma-separated |
| `--source` | | `ROOTLY_SOURCE` | Source identifier (default: `cli`) |
| `--refs` | `-r` | `ROOTLY_REFS` | Reference key=value pairs, comma-separated |
| `--summary` | | `ROOTLY_SUMMARY` | Summary (alternative to positional argument) |
## Output Formats
The CLI supports multiple output formats via the `--format` flag:
| Format | Description |
| ---------- | ------------------------------------------ |
| `table` | Human-readable table (default in terminal) |
| `json` | JSON output (default when piped) |
| `yaml` | YAML output |
| `markdown` | Markdown table |
```bash theme={null}
# Table (default in terminal)
rootly incidents list
# JSON (default when piped, or explicit)
rootly incidents list --format=json
# Pipe JSON to jq for processing
rootly incidents list --format=json | jq '.[].title'
# YAML
rootly incidents get INC-123 --format=yaml
# Markdown
rootly incidents list --format=markdown
```
## Pagination & Filtering
```bash theme={null}
# Pagination
rootly incidents list --limit=50 --page=2
# Filtering
rootly incidents list --status=started --severity=critical
rootly alerts list --source=datadog
rootly services list --name=api
# Sorting
rootly incidents list --sort=created_at --order=desc
```
## Global Flags
| Flag | Description |
| ------------- | --------------------------------------------------------------------- |
| `--api-token` | Rootly API token (env: `ROOTLY_API_TOKEN`) |
| `--endpoint` | Rootly API endpoint (default: `api.rootly.com`) |
| `--format` | Output format: `table`, `json`, `yaml`, `markdown` (default: `table`) |
| `--no-color` | Disable colored output |
| `--help` | Show help for any command |
## Shell Completions
Generate shell completion scripts for tab-completion support:
```bash theme={null}
# Bash
rootly completion bash > /etc/bash_completion.d/rootly
# Zsh
rootly completion zsh > "${fpath[1]}/_rootly"
# Fish
rootly completion fish > ~/.config/fish/completions/rootly.fish
# PowerShell
rootly completion powershell > rootly.ps1
```
## Feedback & Support
* **Issues**: [GitHub Issues](https://github.com/rootlyhq/rootly-cli/issues)
* **Source Code**: [GitHub Repository](https://github.com/rootlyhq/rootly-cli)
## Related resources
* [Terminal UI (TUI)](/integrations/tui)
* [Setup Wizard](/integrations/rootly-wizard)
* [Open Source at Rootly](/open-source/overview)
# ClickUp
Source: https://docs.rootly.com/integrations/clickup
Connect ClickUp to Rootly to create tasks from incidents and receive ClickUp task events as alerts in your incident response process.
The ClickUp integration connects Rootly with your ClickUp workspace so teams can automatically create and update tasks through Genius workflows. Rootly also receives task events from ClickUp as alerts, enabling bidirectional workflows between the two systems.
With the ClickUp integration, you can:
* Automatically create ClickUp tasks when incidents are declared or reach a certain state
* Create tasks as subtasks of an existing ClickUp task using a parent task ID
* Update task title, description, priority, and custom fields as incidents evolve
* Receive ClickUp task events (created, updated, deleted) as Rootly alerts
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A ClickUp account with access to the workspace you want to use
* A ClickUp Personal API Token (PAT)
This integration requires a **Personal API Token (PAT)**, not an OAuth app token. You can generate one from your ClickUp account settings under **Apps > API Token > Generate**.
Rootly recommends installing with a dedicated ClickUp service account so the integration does not break if an individual user leaves your organization.
## Installation
Navigate to the integrations page in Rootly and select **ClickUp**.
Paste your ClickUp Personal API Token into the **API Key** field and select **Connect**.
Rootly validates the token and registers a webhook with ClickUp to receive task events. Once connected, the installation is complete.
After installation, the **Create a ClickUp Task** and **Update a ClickUp Task** workflow actions are available in your Genius workflows. ClickUp task events will also appear as alerts in Rootly.
## Workflow Actions
ClickUp organizes content in a hierarchy: **Workspaces (Teams) → Spaces → Folders → Lists**. When configuring workflow actions, select each level to narrow down the target list.
### Outbound Actions (Rootly → ClickUp)
The actions in this section are used in **Incident Workflows**. They execute on changes to the Rootly incident or action item.
#### Create a ClickUp Task for Incident
Creates a new task in a ClickUp list, linked to the Rootly incident.
| Field | Description | Required |
| ------------------------- | ------------------------------------------------------------------------------- | -------- |
| **Team** | ClickUp workspace (Team) to use | Yes |
| **Space** | ClickUp space within the selected team | Yes |
| **Folder** | Folder within the selected space. Leave blank if the list is at the space level | |
| **List** | ClickUp list where the task will be created | Yes |
| **Title** | Task title. Defaults to `{{ incident.title }}`. Supports Liquid | Yes |
| **Description** | Task description. Supports Liquid | |
| **Priority** | Task priority. **Auto** mirrors the incident severity | |
| **Due Date** | Task due date. Supports Liquid | |
| **Tags** | Comma-separated tags to apply to the task | |
| **Custom Fields Mapping** | JSON mapping ClickUp custom field IDs to values. Supports Liquid | |
| **Task Payload** | Advanced JSON merged into the task creation request. Supports Liquid | |
**Priority mapping (Auto)**
| Rootly Severity | ClickUp Priority |
| --------------- | ---------------- |
| Critical | Urgent (1) |
| High | High (2) |
| Medium | Normal (3) |
| Low | Low (4) |
#### Create a ClickUp Subtask for Action Item
Creates a new task as a subtask of an existing ClickUp task, linked to a Rootly action item.
When a **Create a ClickUp Task for Incident** action runs, Rootly stores the resulting task ID on the incident record. Reference it in the **Parent Task ID** field using Liquid to nest this subtask under the incident task.
| Field | Description | Required |
| ------------------------- | ------------------------------------------------------------------ | -------- |
| **Team** | ClickUp workspace (Team) to use | Yes |
| **Space** | ClickUp space within the selected team | Yes |
| **Folder** | Folder within the selected space | |
| **List** | ClickUp list where the subtask will be created | Yes |
| **Parent Task ID** | ID of the ClickUp task to nest this subtask under. Supports Liquid | Yes |
| **Title** | Subtask title. Supports Liquid | Yes |
| **Description** | Subtask description. Supports Liquid | |
| **Completion** | Subtask completion. **Auto** mirrors the action item status | Yes |
| **Due Date** | Subtask due date. Supports Liquid | |
| **Tags** | Comma-separated tags to apply | |
| **Custom Fields Mapping** | JSON mapping ClickUp custom field IDs to values. Supports Liquid | |
#### Update a ClickUp Task
Updates an existing ClickUp task linked to a Rootly incident.
| Field | Description | Required |
| ------------------------- | ------------------------------------------------------------------ | -------- |
| **Task ID** | ClickUp task ID to update. Supports Liquid | Yes |
| **Title** | Updated task title. Supports Liquid. Leave blank to keep existing | |
| **Description** | Updated task description. Supports Liquid | |
| **Priority** | Updated priority | |
| **Due Date** | Updated due date. Supports Liquid | |
| **Tags** | Updated tags | |
| **Custom Fields Mapping** | Updated custom field values as JSON. Supports Liquid | |
| **Task Payload** | Advanced JSON merged into the task update request. Supports Liquid | |
#### Update a ClickUp Subtask
Updates an existing ClickUp subtask linked to a Rootly action item.
| Field | Description | Required |
| ------------------------- | ------------------------------------------------------------------ | -------- |
| **Task ID** | ClickUp subtask ID to update. Supports Liquid | Yes |
| **Title** | Updated subtask title. Supports Liquid | |
| **Description** | Updated subtask description. Supports Liquid | |
| **Completion** | Updated completion status. **Auto** mirrors the action item status | Yes |
| **Due Date** | Updated due date. Supports Liquid | |
| **Tags** | Updated tags | |
| **Custom Fields Mapping** | Updated custom field values as JSON. Supports Liquid | |
#### Update a ClickUp Action Item
Updates a ClickUp task that represents a Rootly action item.
| Field | Description | Required |
| ------------------------- | ------------------------------------------------------------------ | -------- |
| **Task ID** | ClickUp task ID to update. Supports Liquid | Yes |
| **Title** | Updated title. Supports Liquid | |
| **Description** | Updated description. Supports Liquid | |
| **Completion** | Updated completion status. **Auto** mirrors the action item status | Yes |
| **Due Date** | Updated due date. Supports Liquid | |
| **Custom Fields Mapping** | Updated custom field values as JSON. Supports Liquid | |
### Inbound Events (ClickUp → Rootly)
The actions in this section are used in **Alert Workflows**. They execute on update events sent from ClickUp via webhook.
When the integration is installed, Rootly registers a webhook with ClickUp to receive task events. The following events create alerts in Rootly:
| ClickUp Event | Description |
| ------------- | ------------------------ |
| `taskCreated` | A new task was created |
| `taskUpdated` | A task field was changed |
| `taskDeleted` | A task was deleted |
Each event creates a Rootly alert with the following labels:
| Label | Source |
| ---------- | -------------------------------------------------------- |
| `task_id` | ClickUp task ID |
| `event` | Event type (`taskCreated`, `taskUpdated`, `taskDeleted`) |
| `field` | The field that changed (for `taskUpdated` events) |
| `username` | The user who made the change |
| `id` | The history item ID (for `taskUpdated` events) |
#### Update Action Item
Use an **Alert Workflow** with the **Update Action Item** action to sync ClickUp task changes back to Rootly action items.
#### Data Mapping Syntax
Use the following Liquid template in the **Data Mapping** field to map ClickUp task update fields to Rootly action item fields:
```json theme={null}
{
{% if alert.data.history_items[0].field == 'name' %}
"title": "{{ alert.data.history_items[0].after }}"
{% endif %}
{% if alert.data.history_items[0].field == 'status' %}
{% if alert.data.history_items[0].after.status == 'complete' %}
"status": "done"
{% else %}
"status": "open"
{% endif %}
{% endif %}
{% if alert.data.history_items[0].field == 'priority' %}
{% if alert.data.history_items[0].after == null %}
"priority": "medium"
{% elsif alert.data.history_items[0].after.priority == 'urgent' %}
"priority": "high"
{% elsif alert.data.history_items[0].after.priority == 'high' %}
"priority": "high"
{% elsif alert.data.history_items[0].after.priority == 'normal' %}
"priority": "medium"
{% else %}
"priority": "low"
{% endif %}
{% endif %}
{% if alert.data.history_items[0].field == 'due_date' %}
{% if alert.data.history_items[0].after != null %}
{% assign date = alert.data.history_items[0].after %}
{% assign dateInSeconds = date | divided_by: 1000 %}
"due_date": "{{ dateInSeconds | date: "%Y-%m-%d" }}"
{% endif %}
{% endif %}
}
```
ClickUp sends due dates as Unix timestamps in milliseconds. Divide by 1000 and apply the `date` filter to convert to a readable format.
## Uninstall
To remove the ClickUp integration, open the integrations panel in Rootly and select **Configure > Delete**. Rootly will also remove the registered ClickUp webhook on deletion.
## Related Resources
* [Workflows](/workflows/workflows)
* [Alert workflows](/workflows/alert-workflows)
* [Integrations overview](/integrations/overview)
# Coda
Source: https://docs.rootly.com/integrations/coda/coda
Connect Coda to Rootly to automate incident retrospectives with pre-built templates, Liquid variables, and automatic timeline and action item generation.
Rootly's Coda integration streamlines the process of completing incident retrospectives. Using pre-built templates and workflows, teams automate retrospective creation and save hours of manual work per incident.
With the Coda integration, you can:
* **Use customizable templates** — define the retrospective body in Rootly for a semi-custom retrospective that follows industry best practices, or build a fully custom template in Coda and have Rootly generate the retrospective accordingly
* **Reference Liquid variables** in templates created in either Rootly or Coda
* **Generate incident timelines** automatically for templates created in Rootly, or with [custom Liquid syntax](/liquid/incident-variables) for templates created in Coda
* **Track action items** — follow-ups are recorded automatically when Rootly-hosted templates are used, and [custom Liquid syntax](/liquid/incident-variables) lists them in Coda-hosted templates
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account, logged in as an **Admin** user
* A Coda account and an API key
Rootly recommends installing with a **service account** so the integration does not break if the installing user leaves your organization.
## Installation
Locate **Coda** on the [integrations catalog](https://rootly.com/account/integrations) and select **Setup**.
You will be prompted to enter your Coda API key.
After installation, the **Create a Coda Page** and **Update a Coda Page** workflow actions are available in your Genius workflows.
## Workflow Actions
The Coda integration uses workflows to generate retrospective pages in Coda automatically. If you are unfamiliar with how workflows function, visit the [Workflows](/workflows/workflows) documentation first.
Use the [Incident Variable Explorer](https://rootly.com/account/help/liquid-explorer) to preview what Liquid variables return for your incidents.
### Create a Coda Page
Creates an incident retrospective in a Coda doc.
| Field | Description |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Page ID** | Coda page ID under which the retrospective is created. Found in the URL when viewing a page in your Coda doc |
| **Title** | Title of the Coda page. Use `{{ incident.title }}` to match the incident. Supports Liquid |
| **Subtitle** | Subtitle of the Coda page. Supports Liquid |
| **Custom Retrospective Template** | Body content of the Coda page. Use `{{ incident.summary }}` to match the incident summary. Supports Liquid |
| **Retrospective Template** | A predefined Rootly template used for the body. Managed on the [Retrospective Templates page](https://rootly.com/account/retrospective-steps?tab=documents) |
| **Coda Template** | A predefined template from your Coda doc |
| **Mark Post Mortem as Published** | Sets the retrospective status to `published` rather than `draft`. Use this when notification workflows trigger only on published retrospectives |
These three template fields override one another. **Coda Template** takes precedence over **Retrospective Template**, which takes precedence over **Custom Retrospective Template**.
### Update a Coda Page
Updates an existing incident retrospective in a Coda doc.
| Field | Description |
| --------------------------------- | ----------------------------------------------------------------------------- |
| **Doc ID** | Coda doc containing the page to update |
| **Page ID** | Coda page ID to update. Found in the URL when viewing a page in your Coda doc |
| **Title** | Updated title of the Coda page. Supports Liquid |
| **Subtitle** | Updated subtitle of the Coda page. Supports Liquid |
| **Custom Retrospective Template** | Updated body content. Supports Liquid |
| **Retrospective Template** | A predefined Rootly template used for the body |
| **Coda Template** | A predefined template from your Coda doc |
| **Mark Post Mortem as Published** | Sets the retrospective status to `published` rather than `draft` |
The same precedence applies on update: **Coda Template** overrides **Retrospective Template**, which overrides **Custom Retrospective Template**.
## Uninstall
To remove the Coda integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related Resources
* [Workflows](/workflows/workflows)
* [Retrospectives](/retrospectives/retrospectives)
* [Incident variables](/liquid/incident-variables)
# Confluence
Source: https://docs.rootly.com/integrations/confluence/confluence
Automate Confluence retrospective pages from Rootly incidents using templates and Liquid variables, on Confluence Cloud OAuth or Server personal tokens.
Rootly's Confluence integration automates the creation of retrospective pages after incidents. When an incident resolves or a retrospective is started, Rootly creates a new Confluence page in your specified space and populates it with incident data — including the timeline, affected services, teams involved, and follow-up action items.
Both **Confluence Cloud** (OAuth) and **Confluence Server / Data Center** (Basic auth or Personal Access Token) are supported.
## Features
Create Confluence pages automatically when incidents resolve or retrospectives begin.
Update existing Confluence pages with new incident data as the incident progresses.
Populate pages with incident data using Liquid variables — timeline, services, teams, and action items.
Use Rootly's built-in retrospective templates or your own templates built directly in Confluence.
## Template Options
You have two approaches for retrospective content:
* **Rootly templates** — Use pre-built retrospective templates defined in Rootly. These automatically include timeline visualization and follow-up action item tracking with no additional setup.
* **Confluence templates** — Build fully custom templates directly in Confluence using Liquid variables for dynamic content. Rootly fetches templates from your Confluence space via the API and applies them when creating pages.
If a Confluence template is selected in the workflow action, it overrides both the Custom Retrospective Template and the Rootly Retrospective Template fields.
## Before You Begin
Rootly recommends performing the installation with a **service account** to ensure the integration does not break if the installing user leaves the company. Ensure you are logged in as an **Admin** in Rootly.
Rootly supports two Confluence deployment types:
| Type | Authentication |
| ----------------------------------- | ----------------------------------------- |
| **Confluence Cloud** | OAuth 2.0 (recommended) |
| **Confluence Server / Data Center** | Basic auth or Personal Access Token (PAT) |
## Installation
Choose the path that matches your deployment.
### Confluence Cloud
Navigate to **Configuration → Integrations** in your Rootly dashboard.
Search for **Confluence** and click **Setup**.
You will be redirected to Confluence to grant Rootly permission. Rootly requests the following OAuth scopes:
* `read:user:confluence` — Read your user profile
* `read:content-details:confluence` — Read page content
* `write:content:confluence` — Create and update pages
* `read:template:confluence` — Read Confluence templates
* `read:space:confluence` — Read spaces
* `write:page:confluence` — Create pages
Click **Accept** to authorize Rootly.
You will be redirected back to Rootly with a confirmation message. The integration status will show **Connected**.
### Confluence Server / Data Center
For on-premise deployments, Rootly supports authentication via **Basic auth** or a **Personal Access Token (PAT)**.
1. Navigate to **Configuration → Integrations** and search for **Confluence Server**.
2. Click **Setup** and enter your Confluence Server URL (for example, `https://confluence.yourcompany.com`).
3. Enter your credentials:
* **Basic auth**: Username and password
* **PAT**: Generate a token in Confluence under **Profile → Personal Access Tokens** and paste it into the Token field
4. Click **Save** and **Test Connection** to verify.
Personal Access Tokens expire after 90 days by default. Rootly will notify you when a token is approaching expiry. Rotate the token in Confluence and update it in Rootly to avoid workflow failures.
### On-Premise Notes
If you run Atlassian Confluence Data Center (on-premise) rather than Confluence Cloud, the setup is the same as [Confluence Cloud](#confluence-cloud), with one difference: you authenticate using **URL + username + password** instead of the Cloud OAuth flow.
If your Confluence server sits in a private network, allowlist Rootly's IP addresses so Rootly can reach your instance:
* 34.232.217.139
* 18.213.181.255
## Creating Pages from Workflows
Workflows let you automate Confluence page creation and control exactly what information Rootly publishes during an incident. You can trigger a page creation when an incident resolves, when a retrospective begins, or on any other workflow event — and use Liquid variables to populate pages with live incident data.
If you do not need advanced trigger or condition logic, skip to [Step 4](#step-4-add-the-create-confluence-page-action) to add the action directly.
### Step 1: Create a Workflow
Navigate to **Workflows** in the Rootly sidebar and click **Create Workflow**.
Select the workflow type that matches your use case:
* **Incident** — trigger actions during active incidents
* **Retrospective** — trigger actions when a retrospective begins or changes status
* **Pulse** — trigger actions on a schedule
### Step 2: Configure Triggers
Triggers define when the workflow runs.
| Trigger | When it fires |
| -------------------------------- | ------------------------------------------------------------------ |
| **Incident Created** | A new incident is opened |
| **Incident Updated** | A field like severity or status changes |
| **Incident Status Changed** | The incident moves into a specific status |
| **Retrospective Status Changed** | The retrospective status changes (for example, Started, Published) |
| **Manual Trigger** | An operator runs the workflow manually from the UI |
For retrospective pages, use **Retrospective Status Changed** with a condition of **Status equals Started** so pages are created when a retrospective kicks off.
### Step 3: Add Conditions
Conditions let you refine when the workflow executes after a trigger fires.
Common condition patterns:
* **Severity filter** — only create a page for SEV-1 or SEV-2 incidents
* **Team or service filter** — scope page creation to incidents affecting specific teams or services
* **Incident type** — ensure the workflow only runs when Kind is set to **Incident**
* **Environment** — only generate pages for production or customer-impacting issues
### Step 4: Add the Create Confluence Page Action
Click **Add Action** and search for **Confluence**.
Choose **Create Confluence Page** from the results.
Fill in the fields using the table below.
Click **Add**, enter a workflow name, and click **Create Workflow**.
#### Action Fields
| Field | Required | Description |
| ----------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Space Key** | Yes | The Confluence space where the page will be created. Find this under **Space Settings → Space Details** in Confluence. |
| **Title** | Yes | The page title. Supports Liquid syntax (for example, `{{ incident.title }}`). |
| **Ancestor** | No | Page ID of a parent page. If blank, the page is created at the root of the space. |
| **Confluence Template** | No | A template fetched from your Confluence space. Overrides both retrospective template fields. |
| **Custom Retrospective Template** | No | Define page content directly using Liquid variables. Overrides the Retrospective Template field. |
| **Retrospective Template** | No | A pre-built template from [Retrospective Templates](https://rootly.com/account/retrospective-steps?tab=documents). |
| **Mark Retrospective as Published** | No | Publish the page immediately rather than leaving it as a draft. |
If a **Confluence Template** is selected, it overrides both the **Custom Retrospective Template** and **Retrospective Template** fields.
### Update an Existing Confluence Page
In addition to creating pages, Rootly can update pages that already exist. Add an **Update Confluence Page** action and configure the following fields:
| Field | Required | Description |
| ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| **Page ID** | Yes | The ID of the Confluence page to update. Supports Liquid syntax to reference a page created in a prior step. |
| **Title** | No | Updated page title. Leave blank to keep the existing title. |
| **Content** | No | Updated page content using Liquid variables. |
| **Confluence Template** | No | Re-apply a Confluence template when updating the page. |
## Creating a Confluence Template
Rootly fetches page templates directly from your Confluence space via the API. Templates you create in Confluence appear automatically in the **Confluence Template** dropdown within the workflow action.
Navigate to the space where you want to create the template and open **Space Settings**.
Under **Look and Feel**, select **Templates**.
Click **Create New Template** and add your content. Liquid syntax is fully supported — use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test variables.
Click **Save**. The template will appear in the **Confluence Template** dropdown the next time you configure a Create Confluence Page action.
## Template Examples
Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test variables before deploying templates in production.
```markdown theme={null}
# Retrospective: {{ incident.title }}
**Date:** {{ incident.started_at | date: "%Y-%m-%d" }}
**Severity:** {{ incident.severity }}
**Status:** {{ incident.status }}
## Summary
{{ incident.summary }}
## Timeline
{{ incident.timeline_table_markdown }}
## Services Affected
{% for service in incident.services %}
- {{ service }}
{% endfor %}
## Teams Involved
{% for group in incident.groups %}
- {{ group.name }}
{% endfor %}
## Follow-Up Items
{% for action_item in incident.action_items %}
- {{ action_item.summary }} ({{ action_item.status }})
{% endfor %}
## Lessons Learned
[To be completed by the team]
```
```markdown theme={null}
# Executive Summary: {{ incident.title }}
**Date:** {{ incident.started_at | date: "%B %d, %Y" }}
**Severity:** {{ incident.severity }}
**Duration:** {{ incident.duration }} minutes
## What Happened
{{ incident.summary }}
## Resolution
{{ incident.resolution_message }}
## Key Metrics
- Services Affected: {{ incident.services | size }}
- Time to Resolution: {{ incident.duration }} minutes
## Next Steps
{% for action_item in incident.action_items %}
- {{ action_item.summary }}
{% endfor %}
```
```markdown theme={null}
# Root Cause Analysis: {{ incident.title }}
**Started:** {{ incident.started_at | date: "%Y-%m-%d %H:%M %Z" }}
**Resolved:** {{ incident.resolved_at | date: "%Y-%m-%d %H:%M %Z" }}
**Duration:** {{ incident.duration }} minutes
## Affected Services
{% for service in incident.services %}
- {{ service }}
{% endfor %}
## Detailed Timeline
{{ incident.timeline_table_markdown }}
## Root Cause
[To be completed by engineering team]
## Resolution Steps
{{ incident.resolution_message }}
## Preventive Measures
{% for action_item in incident.action_items %}
- {{ action_item.summary }} ({{ action_item.status }})
{% endfor %}
```
## Troubleshooting
Ensure you have **Create** or **Edit** permissions in the Confluence spaces you want Rootly to use. Ask an admin to check **Space Settings → Permissions**. If the issue persists, disconnect and reconnect the integration to refresh permissions.
Check if your organization restricts external apps under **Atlassian Admin → Security → App Access**. Confirm the installing user is not limited to read-only access. Retry the installation in an incognito window to avoid stale credentials.
Verify the Confluence Server URL is reachable from Rootly's servers — check any firewall or allowlist rules. Confirm SSL certificates are valid. For PAT authentication, ensure the token has not expired and has the required permissions.
## Frequently Asked Questions
Rootly fetches templates from your Confluence space via the API. Ensure the template was saved in the correct space and that your Rootly integration has access to that space. Try disconnecting and reconnecting the integration to refresh the template list.
Check the workflow run log in Rootly for error details. Common causes include an invalid Space Key, a missing or incorrect Ancestor page ID, or a Liquid variable that returned an empty value for the Title field (Title is required). Verify the Space Key matches exactly what appears in **Space Settings → Space Details** in Confluence.
Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to verify that the variable returns a value for your incident. Some variables like `incident.resolved_at` will be empty if the incident has not yet resolved. Add a fallback using Liquid filters (for example, `{{ incident.resolved_at | default: "TBD" }}`).
Add multiple **Create Confluence Page** actions to the same workflow, each configured with a different Space Key. Each action runs sequentially and creates an independent page.
Use the **Update Confluence Page** action after a **Create Confluence Page** action. Reference the created page ID via Liquid using the output of the prior step.
## Uninstall
To remove the Confluence integration:
1. Go to **Configuration → Integrations** and find **Confluence**
2. Click the **Connected** button to reveal the disconnect option
3. Click **Delete**
Disconnecting the integration does not delete existing Confluence pages created by Rootly. Those pages remain in your Confluence space.
## Related Resources
* [Workflows](/workflows/workflows)
* [Retrospectives](/retrospectives/retrospectives)
* [Integrations overview](/integrations/overview)
# Cortex
Source: https://docs.rootly.com/integrations/cortex/overview
Connect Cortex to Rootly to sync catalog entities into Rootly services and surface Rootly incident data inside Cortex.
## What is Cortex?
Cortex is the Engineering Operations Platform that enables organizations to continuously improve their operational maturity and reduce developer friction. With centralized visibility, clear ownership, automated Scorecards, and golden paths, Cortex helps engineering organizations operate as one.
## Integration Overview
The Rootly + Cortex integration is **bidirectional**, meaning data flows in both directions to create a seamless experience:
Sync your Cortex Catalogs into Rootly
Display Rootly incident data within Cortex portal
## How It Works
### Cortex → Rootly (Catalog Sync)
Rootly imports your Cortex catalogs, making Cortex the **source of truth** for your Catalog data in Rootly.
**What gets synced:**
* Cortex entities become Rootly entities, including all properties
* Changes made in Cortex are synced in Rootly
[Set up Cortex → Rootly integration →](#sync-entities-from-cortex-to-rootly)
***
### Rootly → Cortex (Incident Display)
Cortex pulls incident data from Rootly and displays it within your Internal Developer Portal.
**What you can do:**
* View active incidents on service pages in Cortex
* Create Rootly incidents directly from Cortex
* Build scorecards based on Rootly incident metrics
* Track service reliability using incident data
[Learn about Rootly → Cortex integration →](#display-rootly-incidents-in-cortex)
## Key Benefits
### Unified Catalog
Use Cortex as your single source of truth for your Rootly Catalog. When you update an entity in Cortex, the changes automatically flow to Rootly, ensuring consistency across your incident management workflow.
### Reduced Context Switching
Developers and on-call engineers can stay in Cortex while accessing incident information. Create incidents, check incident history, and view operational metrics without switching tools.
### Automated Service Ownership
Use Cortex's ownership data to automatically route incidents to the right teams. For example, when an incident affects a service, Rootly knows exactly who owns it based on Cortex's catalog.
### Data-Driven Reliability
Build Cortex scorecards using Rootly incident data to measure and improve service reliability. Track MTTR, incident frequency, and operational maturity across all your entities.
## Which Integration Do I Need?
**Both!** The integrations work together to provide the complete experience:
| If you want to... | You need... |
| --------------------------------- | ---------------------------------------------------------------------------- |
| Keep entities in sync | [Cortex → Rootly](#sync-entities-from-cortex-to-rootly) |
| View incidents in Cortex portal | [Rootly → Cortex](https://docs.cortex.io/docs/reference/integrations/rootly) |
| Link incidents to Cortex services | [Cortex → Rootly](#sync-entities-from-cortex-to-rootly) |
| Create incidents from Cortex | [Rootly → Cortex](https://docs.cortex.io/docs/reference/integrations/rootly) |
| Build reliability scorecards | [Rootly → Cortex](https://docs.cortex.io/docs/reference/integrations/rootly) |
The **Cortex → Rootly** integration is configured in Rootly. The **Rootly → Cortex** integration is configured in Cortex and maintained by the Cortex team.
## Using Both Directions Together
With entity sync and incident display both configured:
* Entities in Rootly stay in sync with Cortex
* Incidents in Rootly appear on entity pages in Cortex
* Teams can work from either tool
## Before You Begin
* **Cortex account** with API access
* **Rootly admin or owner** permissions
* **Cortex API key** (you'll generate this below)
## Sync Entities from Cortex to Rootly
### Step 1: Generate a Cortex Access Token
1. Log into your **Cortex** account
2. Navigate to **Settings** > **My access tokens**
3. Click **Create new token**
4. Give it a descriptive name like "Rootly Integration"
5. Copy the generated API key
Rootly recommends using a service account token to ensure uninterrupted access if team members change roles.
Make sure to copy the API key immediately - Cortex will only show it once for security purposes.
### Step 2: Connect Cortex to Rootly
1. Log into your **Rootly** account as an Admin
2. Navigate to **Configurations** > **Integrations** > **Cortex**
3. Click **Setup** to open the configuration modal
4. Enter your Access Token from Step 1 into the Access Token field
5. Click **Connect**
If successful, you'll see a confirmation message and the Cortex integration card will show as **Connected**.
### Step 3: Enable Catalog Sync (Optional)
By default, the integration connects to Cortex but doesn't automatically sync your Cortex Catalogs with Rootly's Catalog.
To enable automatic synchronization:
1. Navigate to your Cortex integration settings in Rootly.
2. Toggle **Sync Cortex Catalogs** on.
3. Select the Cortex Catalogs you want to pull into Rootly in the **Cortex types** field.
4. Add any **Catalog Groups** filters. This is optional: if the field is left blank, all entities in the defined Catalogs will be pulled into Rootly. Filter in specific Groups with this field.
5. Click **Save.**
Rootly automatically syncs with Cortex every 24 hours to keep your data accurate and up-to-date. You can manually run a sync at any time.
### What Gets Synced
When Cortex sync is enabled in step 3, Rootly will:
* Map Cortex Types to Rootly Catalogs by name. If you've already defined a Catalog in Rootly called "Domain", Rootly will map your Cortex "Domain" to the Rootly "Domain" Catalog.
* Create new Catalogs in Rootly for any Cortex Types that don't have existing matching Rootly Catalogs.
* Add new properties to Rootly Catalogs to store all entity data in Rootly for your teams to use.
* Create new entities in Rootly in the corresponding Catalogs. Rootly will ingest all property data from Cortex.
* Update any existing entities in Rootly that were previously synced with Cortex with new data.
* Archive existing entities that have been removed from Cortex.
### Using Synced Entities
Once entities are synced from Cortex:
* They appear in your Rootly catalogs with a Cortex badge
* You can track the impact of incidents against your entities with incident fields
* Build workflows to automate your incident response process around your business entities
## Display Rootly Incidents in Cortex
This integration is configured entirely within Cortex. Visit the [Cortex integration setup guide](https://docs.cortex.io/docs/reference/integrations/rootly) for detailed installation instructions.
**You'll need:**
* Cortex admin permissions
* Rootly admin or owner permissions
* A Rootly API key (generated during Cortex setup)
### Features
#### Trigger Incidents from Cortex
Create Rootly incidents directly from service pages in Cortex without switching tools.
**How it works:**
From any service page in Cortex, click the Rootly action to create a new incident. The incident is created in Rootly with the service context already attached.
#### View Incident Data in Cortex
See real-time incident information directly on service entity pages in your Cortex catalog.
**What you can see:**
* Active incidents affecting the service
* Recent incident history
* Incident severity and status
* Links to detailed incident pages in Rootly
#### Build Scorecards with Incident Data
Create custom scorecards and write CQL queries using Rootly incident data to measure service reliability.
**Example use cases:**
* Track MTTR (Mean Time to Resolution) per service
* Measure incident frequency and severity trends
* Score services based on operational maturity
* Set goals for reducing critical incidents
#### Incident Catalog View
Rootly is the only incident management platform that appears in Cortex's catalog list view, giving you a unified perspective of both services and active incidents.
### Use Cases
#### Platform Engineering Teams
Your platform team maintains dozens of internal services. When checking service health in Cortex, you want to immediately see if there are any active incidents.
**Solution**: Incident status appears directly on service pages. If an issue arises, you can create a Rootly incident without leaving Cortex.
#### SRE Teams
You're conducting a service reliability review and need to understand incident patterns across services.
**Solution**: Use Cortex scorecards powered by Rootly data to visualize MTTR, incident frequency, and severity trends. Create CQL queries to track improvement over time.
#### On-Call Engineers
You're paged about a service issue and need to quickly understand service dependencies and recent incident history.
**Solution**: Open the service in Cortex to see ownership, dependencies, and recent Rootly incidents all in one place. Create follow-up incidents directly from the context you're already in.
## Best Practices
### Keep Service Mappings Accurate
Ensure services in Cortex are properly mapped to services in Rootly for accurate incident association. Consistent naming helps maintain the connection.
### Use Scorecards
Create scorecards that track operational metrics like:
* Incidents per service per week
* Mean time to resolution
* Percentage of incidents with retrospectives
* Critical incident frequency
### Use Incident Context
When creating incidents from Cortex, include relevant service context in the incident description to help responders quickly understand the situation.
### Review Historical Trends
Regularly review incident data in Cortex to identify services that may need architectural improvements or additional monitoring.
## Uninstall
To disconnect the Cortex integration:
1. Navigate to **Configurations** > **Integrations** > **Cortex**
2. Click **Delete**
3. Confirm the removal
Removing the integration will stop service synchronization. Existing entities imported from Cortex will remain in Rootly but will no longer update automatically.
## Support
### For Entity Sync (Cortex → Rootly)
This integration is built and maintained by Rootly.
* Contact Rootly support through your account
* Visit [Rootly documentation](https://docs.rootly.com)
### For Incident Display (Rootly → Cortex)
This integration is built and maintained by Cortex.
* Email: [help@cortex.io](mailto:help@cortex.io)
* Visit [Cortex integration docs](https://docs.cortex.io/docs/reference/integrations/rootly)
## Related Resources
* [Service catalog](/integrations/catalog)
* [Integrations overview](/integrations/overview)
# Datadog
Source: https://docs.rootly.com/integrations/datadog/datadog
Connect Datadog to Rootly to ingest monitor alerts and capture notebooks, graphs and dashboards during incidents.
## Overview
Rootly's Datadog integration connects your monitoring stack to your incident response process. When a Datadog monitor fires, Rootly can receive the alert, route it to the right team, and automatically kick off an incident — all without manual intervention. During incidents, Rootly workflows can also pull Datadog notebooks, graph snapshots, and dashboards directly into the incident record.
## Features
Receive Datadog monitor alerts in Rootly via webhooks and route them to on-call or incident workflows.
Page a specific user, team, escalation policy, or service directly from a Datadog alert payload.
Create Datadog notebooks automatically from Rootly workflow actions during incidents.
Pull Datadog graph snapshots and dashboards into incident records via workflow actions.
## Before You Begin
Rootly recommends performing the installation with a **service account** to ensure the integration does not break if the installing user leaves the company. Ensure you are logged in as an **Admin** in Rootly.
You will need three pieces of information from Datadog:
* **Host** — your Datadog account's API hostname
* **API Key** — authenticates Rootly with your Datadog organization
* **Application Key** — grants Rootly permission to read dashboards
### Plan Requirements
* Datadog account with Admin access
* Rootly account with Owner or Admin role
## Installation
Navigate to **Configuration → Integrations** in Rootly, search for **Datadog**, and click **Setup**.
In Datadog, navigate to **Organization Settings → API Keys** and click **+ New Key**.
Name the key (for example, `Rootly Integration`) and click **Create Key**. Copy the key immediately.
The API key value is only shown once at creation. Copy it before closing the dialog — not the Key ID.
In Datadog, navigate to **Personal Settings → Security → Application Keys** and click **+ New Key**.
Name the key (for example, `Rootly Integration`), then edit its scope to include **Read** permission for **Dashboards**.
Copy the application key.
Rootly only requires `dashboard_read` scope. You can add more permissions if needed for other integrations, but this is the minimum required.
Back in the Rootly setup form, enter:
* **Host** — your Datadog API hostname. Common values:
| Region | Host |
| ------------- | ----------------------- |
| US1 (default) | `api.datadoghq.com` |
| US3 | `api.us3.datadoghq.com` |
| US5 | `api.us5.datadoghq.com` |
| EU | `api.eu.datadoghq.com` |
| Gov | `api.ddog-gov.com` |
* **API Key** — paste the API key you created
* **Application Key** — paste the application key you created
Click **Connect**.
Datadog will appear as **Connected** in your integrations list.
## Ingest Datadog Alerts
Once Datadog is connected, forward monitor alerts to Rootly via a webhook. Alerts received in Rootly can be routed to a Slack channel, used to page on-call responders, or trigger incident workflows automatically.
### Step 1: Set Up the Webhook in Datadog
In Datadog, navigate to **Integrations**, search for **Webhooks**, and click **Install**.
Switch to the **Configuration** tab and click **+ New** to add a webhook.
Fill in the following fields:
**Name** — give the webhook a descriptive name (for example, `Rootly_Alerts`)
**URL** — enter:
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/datadog_webhooks
```
**Payload** — choose based on your use case:
Use this payload for standard alerts that appear in Rootly's Alerts page without paging anyone.
```json theme={null}
{
"id": "$ID",
"body": "$EVENT_MSG",
"last_updated": "$LAST_UPDATED",
"event_type": "$EVENT_TYPE",
"title": "$EVENT_TITLE",
"alert_id": "$ALERT_ID",
"alert_metric": "$ALERT_METRIC",
"alert_priority": "$ALERT_PRIORITY",
"alert_query": "$ALERT_QUERY",
"alert_scope": "$ALERT_SCOPE",
"alert_status": "$ALERT_STATUS",
"alert_title": "$ALERT_TITLE",
"alert_transition": "$ALERT_TRANSITION",
"alert_type": "$ALERT_TYPE",
"date": "$DATE",
"org": {"id": "$ORG_ID", "name": "$ORG_NAME"}
}
```
Use this payload to page a specific user, team, escalation policy, or service when the alert fires. Replace `` and `` with your target resource.
```json theme={null}
{
"id": "$ID",
"body": "$EVENT_MSG",
"last_updated": "$LAST_UPDATED",
"event_type": "composite_monitor",
"title": "Datadog webhook alert",
"alert_id": "$ALERT_ID",
"alert_metric": "$ALERT_METRIC",
"alert_priority": "$ALERT_PRIORITY",
"alert_query": "$ALERT_QUERY",
"alert_scope": "$ALERT_SCOPE",
"alert_status": "$ALERT_STATUS",
"alert_title": "$ALERT_TITLE",
"alert_transition": "$ALERT_TRANSITION",
"alert_type": "$ALERT_TYPE",
"date": "$DATE",
"org": {"id": "$ORG_ID", "name": "$ORG_NAME"},
"rootly": {
"notification_target": {
"type": "",
"id": ""
}
}
}
```
| Field | Values |
| ------ | --------------------------------------------------------- |
| `type` | `User`, `Group`, `EscalationPolicy`, or `Service` |
| `id` | The resource ID — found by editing the resource in Rootly |
The only difference between these payloads is the `notification_target` object. Including it tells Rootly who to page when the alert is received.
Check the **Custom Headers** box and add the following, replacing the value with your Rootly webhook secret:
```json theme={null}
{
"secret": ""
}
```
To find your secret:
1. In Rootly, go to **Alerts → Sources → Datadog** and click **Configure**
2. Find the **Connection Instructions** panel on the right
3. Copy the **secret** value from the Custom Headers section
Click **Save**.
### Step 2: Attach the Webhook to a Monitor
In Datadog, navigate to **Monitors → New Monitor** and choose a monitor type, or open an existing monitor to edit it.
In the **Configure notifications and automations** section, reference your webhook using `@webhook-` syntax (for example, `@webhook-Rootly_Alerts`).
Click **Test Notifications** to confirm the alert reaches Rootly, then save the monitor.
Verify the alert appeared on the [Alerts page](https://rootly.com/account/alerts) in Rootly.
### Step 3: Build Alert Workflows in Rootly
With alerts flowing into Rootly, create a workflow that reacts to them. Alert workflows let you check alert fields, apply conditions, and trigger automated actions like creating an incident or notifying responders.
Navigate to **Workflows** in Rootly and click **Create Workflow**.

Select **Alert** as the workflow type. This workflow triggers whenever Rootly receives an alert from Datadog.

Select **Alert Created** to fire on new alerts, or **Alert Status Updated** to react when an existing alert changes.
Available triggers: **Alert Created** fires when a new alert is received. **Alert Status Updated** fires when an existing alert changes state.
Filter which alerts should trigger this workflow. Common patterns:
Add a condition where **Source is Datadog** to scope the workflow to Datadog alerts only.
Use payload field conditions to filter further — for example:
* `alert_priority` equals `P1`
* `alert_title` contains `CRITICAL`
* `alert_transition` equals `Triggered`
Use Datadog payload fields like `alert_priority`, `alert_status`, `alert_type`, and `alert_title` to build precise conditions.
Add one or more actions to execute when the workflow fires:
| Action | Use case |
| ----------------------- | ---------------------------------------------- |
| **Create Incident** | Auto-create an incident from the alert |
| **Page Rootly On-Call** | Page the responsible team or escalation policy |
| **Send Slack Message** | Notify a channel about the alert |
| **Send SMS or Email** | Alert responders directly |
You can chain multiple actions for a complete response process — for example, create an incident and then send a Slack message in the same workflow.
Name the workflow (for example, `Create Incident from Datadog P1 Alert`) and click **Create Workflow**.

### Verify the Workflow
After saving the workflow:
1. Return to Datadog and trigger a test alert from your monitor by clicking **Test Notifications**
2. Confirm the workflow activates in Rootly and performs the expected actions
3. View the run log under **Workflows → History** in Rootly
You have successfully built a Datadog alert workflow in Rootly!
## Workflow Actions
| Action | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------- |
| **Create Datadog Notebook** | Creates a new notebook in your Datadog account, optionally pre-populated with incident data |
| **Get Datadog Graph Snapshot** | Retrieves a point-in-time snapshot of a Datadog metric graph and attaches it to the incident |
| **Get Datadog Dashboard** | Fetches a Datadog dashboard URL and surfaces it in the incident timeline |
### Create Datadog Notebook
Use this action to automatically create a Datadog notebook when an incident starts or reaches a specific status. Notebooks are useful for capturing investigation notes, timelines, and graphs in a single Datadog-native view.
Navigate to **Workflows** in Rootly and click **Create Workflow**, or open an existing workflow to edit it.
Click **Add Action**, search for **Datadog**, and select **Create Datadog Notebook**.
| Field | Required | Description |
| ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | No | A label for this action step. Does not affect behavior. |
| **Notebook Name** | Yes | The title of the notebook. Supports Liquid syntax — use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to build dynamic names. |
Click **Add**, name the workflow, and click **Create Workflow**.
### Get Datadog Graph Snapshot
Use this action to capture a point-in-time graph from Datadog and attach it to the incident. This is useful for preserving the state of a metric at the time an incident was declared or escalated.
In your workflow, click **Add Action**, search for **Datadog**, and select **Get Datadog Graph Snapshot**.
| Field | Required | Description |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| **Metric Query** | Yes | The Datadog metric query to snapshot — for example `avg:system.cpu.user` with an optional scope filter. |
| **Start** | No | Snapshot start time in Unix epoch seconds. Supports Liquid syntax. |
| **End** | No | Snapshot end time in Unix epoch seconds. Defaults to the current time if blank. |
### Get Datadog Dashboard
Use this action to retrieve a Datadog dashboard and surface its URL in the incident timeline. This gives responders quick access to the relevant monitoring view without leaving Rootly.
In your workflow, click **Add Action**, search for **Datadog**, and select **Get Datadog Dashboard**.
| Field | Required | Description |
| ---------------- | -------- | -------------------------------------------------------------------------------------------------- |
| **Dashboard ID** | Yes | The ID of the Datadog dashboard to fetch. Found in the dashboard URL (for example, `abc-123-xyz`). |
### Alert Workflow Patterns
In addition to incident workflow actions, you can build **Alert workflows** in Rootly that trigger automatically when a Datadog alert arrives. These are separate from incident workflows and configured under **Workflows → Alert**.
Common patterns:
* **Auto-create an incident** when a SEV-1 Datadog alert fires
* **Page on-call** for alerts with `alert_priority` of `P1` or `P2`
* **Send a Slack message** to a channel when a monitor transitions to `ALERT`
* **Resolve the alert** automatically when Datadog sends a `RECOVERY` transition
To scope workflows to Datadog only, add a condition where **Source is Datadog**, or filter on payload fields like `alert_priority`, `alert_title`, or `alert_transition`.
## Uninstall
To remove the Datadog integration:
1. Go to **Configuration → Integrations** and find **Datadog**
2. Click the **Connected** button to reveal the disconnect option
3. Click **Delete**
## Frequently Asked Questions
Verify the webhook URL is exactly `https://webhooks.rootly.com/webhooks/incoming/datadog_webhooks`. Confirm the Custom Headers `secret` value matches what is shown in **Alerts → Sources → Datadog → Configure** in Rootly. Check that the Datadog integration is still connected under **Configuration → Integrations**.
Open the resource (User, Team, Escalation Policy, or Service) in Rootly and click **Edit**. The resource ID appears in the URL or in the edit form. Copy it and paste it into the `id` field of the paging payload.
Yes. Create one webhook and attach it to as many monitors as needed by adding `@webhook-` to each monitor's notification body. Each alert will appear separately in Rootly's Alerts page.
Alert workflows in Rootly support **Alert Created** (fires on new alerts) and **Alert Status Updated** (fires when an existing alert changes). Use conditions to filter by source (Datadog), payload fields like `alert_priority` or `alert_title`, or alert status.
By default, Rootly only pages for CRITICAL alerts from Datadog. WARNING vs. CRITICAL is the monitor's `alert_status` field in the webhook payload — not `alert_priority` (which is your monitor's P1–P5 importance and is independent of state). To extend paging to WARNING alerts, either configure your monitor to fire on the threshold you want treated as paging-eligible, or build an alert workflow that matches `alert_status` equals `Warn` (or `Warning`, depending on the value Datadog sends) and routes to the same target as CRITICAL.
### Workflow Questions
Check the workflow run log in Rootly for error details. Confirm the Datadog Application Key has sufficient permissions and that the integration is still connected under **Configuration → Integrations**.
Yes. Datadog actions can be combined with any other Rootly workflow actions in the same workflow — for example, create a Datadog notebook and then send a Slack message with the notebook link.
Any incident Liquid variable is supported. Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to browse available variables and preview their values.
## Related Resources
* [Alert workflows](/workflows/alert-workflows)
* [Alert routing](/alerts/alert-routing)
* [Integrations overview](/integrations/overview)
# Dropbox Paper
Source: https://docs.rootly.com/integrations/dropbox-paper
Connect Dropbox Paper to Rootly to automatically create and update retrospective documents from incidents using Liquid templates.
The Dropbox Paper integration connects Rootly with your Dropbox account so teams can automatically create and update retrospective documents during and after incidents through Genius workflows.
With the Dropbox Paper integration, you can:
* Automatically create retrospective documents in Dropbox Paper from incident workflows
* Populate documents using Rootly retrospective templates or custom Liquid templates
* Update existing Paper documents as an incident progresses
* Attach created documents directly to the incident record
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A Dropbox or Dropbox Business account
Rootly recommends installing the integration with a **service account** so it does not break if the installing user leaves your organization.
Access level depends on your Dropbox account type:
* **Dropbox Paper** (personal) — non-admin access is sufficient, but you will only have access to your personal folders
* **Dropbox Paper Business** — admin-level access is required to access team folders and namespaces
## Installation
Navigate to the integrations page in Rootly and select **Dropbox Paper**.
You will be prompted to sign in to Dropbox and grant Rootly permission to access your account.
Once confirmed, the installation is complete and Dropbox Paper workflow actions become available.
After authorization, the **Create a Dropbox Paper** and **Update a Dropbox Paper** workflow actions are immediately available in your Genius workflows.
## Workflow Actions
The Dropbox Paper integration provides two workflow actions for creating and updating Paper documents from incidents. If you are unfamiliar with how workflows function, see the [Workflows](/workflows/workflows) documentation first.
### Create a Dropbox Paper Document
This action creates a new Paper document in a specified Dropbox folder.
**Name**
The display name for this workflow action. Rename it to describe what the action does — the value does not affect behavior.
**Namespace**
Only available when integrated with **Dropbox Paper Business**. Selects the team namespace from which the parent folder list is populated.
If you integrated with personal Dropbox Paper, the Namespace field is not shown and folders are limited to your personal folders.
**Parent Folder**
The folder in which the Paper document will be created.
* **Dropbox Paper** (personal) — shows your personal folders
* **Dropbox Paper Business** — shows folders within the selected Namespace
**Title**
The title of the Paper document. Defaults to `{{ incident.title }}`. Supports Liquid syntax.
Use the [Incident Variable Explorer](https://rootly.com/account/help/liquid-explorer) to preview what Liquid variables return for your incidents.
**Retrospective Template**
Select a predefined retrospective template to populate the document body. Templates are managed on the [Retrospective Templates page](https://rootly.com/account/retrospective-steps?tab=documents).
If a Retrospective Template is selected, it overrides any content defined in the Custom Retrospective Template field.
**Custom Retrospective Template**
Define the body content of the Paper document manually. Supports Liquid syntax. Used only when no Retrospective Template is selected.
**Mark Post Mortem as Published**
When enabled, marks the retrospective status as `published` after the document is created. Use this when you have follow-up notification workflows that trigger on published retrospectives.
### Update a Dropbox Paper Document
This action updates an existing Paper document with new content.
**Name**
The display name for this workflow action.
**File ID**
The Dropbox file ID of the Paper document to update. Supports Liquid syntax. Use `{{ incident.retrospective_url }}` or a stored file ID variable to reference the document created earlier in the workflow.
When a **Create a Dropbox Paper** action runs, Rootly stores the resulting document URL and file ID on the incident record. You can reference the file ID in subsequent update actions using Liquid variables.
**Title**
The updated title for the document. Supports Liquid syntax. Leave blank to keep the existing title.
**Content**
Additional HTML content to append to the document. Supports Liquid syntax.
**Retrospective Template**
Select a predefined retrospective template to re-render the document body.
## Uninstall
To remove the Dropbox Paper integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related Resources
* [Workflows](/workflows/workflows)
* [Retrospectives](/retrospectives/retrospectives)
* [Integrations overview](/integrations/overview)
# Dynatrace
Source: https://docs.rootly.com/integrations/dynatrace
Set up Dynatrace as an alert source in Rootly to route problem notifications, configure urgency rules, page on-call teams, and auto-resolve alerts on recovery.
## Setup instructions
Begin by creating a Dynatrace alert source in Rootly. Navigate to **Settings** → **Alert Sources** and click **Add Alert Source**. Select **Dynatrace**.
You may optionally configure default alert urgency, owner groups, alert fields, or deduplication settings. Once the alert source is saved, copy the webhook URL provided by Rootly.
```txt theme={null}
https://webhooks.rootly.com/webhooks/incoming/dynatrace_webhooks?secret=YOUR_SECRET_KEY
```
The webhook secret authenticates incoming requests from Dynatrace. Treat this value as sensitive and rotate it if it is exposed.
This step is for **Dynatrace Generation 3**.
If using **Dynatrace Generation 2**, follow Dynatrace's [instructions](https://docs.dynatrace.com/docs/analyze-explore-automate/notifications-and-alerting/problem-notifications/webhook-integration) to send notifications via webhook, using the webhook URL provided by Rootly.
Create a new workflow in your Dynatrace environment.
Select a **Problem** trigger. Choose "active or closed" for the "Event state" field. Configure any additional categories or tags.
Add an **HTTP Request** task. Choose "POST" method, use the webhook URL provided in the Rootly alert source connection instructions. Copy and paste the following request payload:
```text theme={null}
{
"PID": "{{ event()['event.id'] }}",
"Problem URL": "{{ environment()['url'] }}/ui/apps/dynatrace.davis.problems/problem/{{ event()['event.id'] }}",
"ProblemTitle": {{ event()['event.name'] | to_json }},
"ProblemDetailsHTML": {{ event()['event.description'] | to_json }},
"State": "{{ event()['event.status'] }}"
}
```
Save the workflow.
Run the workflow using an active problem event. You should see the alert in Rootly. When the problem is closed, the alert should auto-resolve in Rootly.
## Advanced Configuration
### Alert Fields
Alert fields allow you to transform the incoming Dynatrace request into alert fields using Liquid templates. These fields can be used to customize the alert title, description, and source link, as well as create additional custom fields for routing, urgency, filtering, and reporting.
Because the raw Dynatrace request is stored in alert data in Rootly, you can inspect a sample alert from the source and use the alert payload viewer to copy Liquid variables and JSONPath selectors for field configuration.
### Alert Urgency
Dynatrace alerts can be assigned urgency dynamically using Rootly alert urgency rules. Rules may be based on raw payload JSONPath values or on alert field values generated from the request.
If no rule matches, Rootly applies the source's fallback alert urgency.
### Deduplication and Resolution
Rootly uses `external_id` to match trigger and resolve events for the same Dynatrace problem. If you want to suppress repeated notifications that represent the same incoming event, you can also configure a unique identifier in the **Events** tab and enable duplicate alert suppression.
This deduplication setting is separate from the required `external_id` field:
* `external_id` matches triggered and resolved events for the same alert.
* the **Events** tab unique identifier can suppress repeated create events before additional alerts are created.
### Notification Targets
In addition to default routing rules, Dynatrace alerts can be sent directly to specific notification targets using a specialized webhook endpoint.
```txt theme={null}
https://webhooks.rootly.com/webhooks/incoming/dynatrace_webhooks/notify/{notification_target_type}/{notification_target_id}?secret=YOUR_SECRET_KEY
```
The notification target type must be one of `Service`, `EscalationPolicy`, or `Group`. The notification target ID must be replaced with the UUID of the corresponding resource.
## Related resources
* [Prometheus Alertmanager](/integrations/alertmanager)
* [Checkly](/integrations/checkly)
* [Chronosphere](/integrations/chronosphere)
* [Google Cloud Monitoring](/integrations/google-cloud-monitoring)
# Email
Source: https://docs.rootly.com/integrations/email
Create incidents by sending emails to your team's Rootly inbound alias, and send templated email notifications from workflows with Liquid and CC support.
## Overview
Rootly's Email integration works in both directions. Inbound emails to your team's generated alias automatically open new incidents, while the **Send an email** workflow action lets you notify stakeholders at any point during an incident.
Send an email to your Rootly alias to instantly create an incident — no login required.
Rootly automatically maps severity from the email subject line using tags like `[SEV0]` or `sev1`.
Reply to an incident notification email and Rootly adds your reply to the incident timeline.
Send fully templated emails to any address from a workflow, with Liquid variables, CC, BCC, and custom branding.
## Installation
The Email integration provisions automatically — there are no API keys or OAuth flows to complete.
Go to **Configuration → Integrations**, find **Email**, and click **Setup**.
Rootly immediately generates a unique email alias for your team.
After connecting, click **Settings** to view your team's alias. It looks like:
```text theme={null}
incidents-{secret}@email.rootly.io
```
Copy this address — you'll send incident-creating emails to it and can share it with monitoring tools or on-call rotation scripts.
## Creating Incidents via Email
To open an incident, send an email to your alias. The email subject becomes the incident title and the body becomes the initial description.
### Automatic Severity Detection
Rootly parses the subject line for severity tags and maps them to your configured severities. Supported formats:
| Subject format | Mapped severity |
| ------------------------------------------------------ | --------------------- |
| `[SEV0] Shopping cart is showing empty items` | SEV0 |
| `Shopping cart is showing empty items [SEV1]` | SEV1 |
| `Shopping cart is showing empty items, this is a sev1` | SEV1 |
| `Shopping cart is showing empty items` | *(none — not mapped)* |
Severity tags are only matched if the corresponding severity exists in your Rootly configuration. If no match is found, the incident is created without a severity.
## Replying to Incidents via Email
When Rootly sends an email notification for an incident, you can reply to it directly. Rootly detects the reply and appends it to the incident timeline.
## Workflow Action
### Send an Email
Sends a fully templated email from a workflow. All text fields support [Liquid variables](/liquid/incident-variables).
The sender address displayed to recipients. Defaults to `Rootly `. You can override this with a custom address.
One or more recipient email addresses. Supports Liquid — for example, `{{ incident.commander.email }}` to notify the incident commander.
Email addresses to copy on the message.
Email addresses to blind-copy. Maximum 10 BCC recipients on trial plans.
The email subject line. Defaults to `{{ incident.title }} is on fire`. Supports Liquid.
The email body. Supports Markdown formatting and Liquid variables.
Short preview text that appears in the recipient's inbox next to the subject line. Supports Liquid.
A URL pointing to an image to use as the email header logo. Overrides the default Rootly logo.
Whether to include the email header section. Defaults to `true`.
Whether to include the email footer section. Defaults to `true`.
Set the **To** field to `{{ incident.commander.email }}` or `{{ incident.subscribers | map: 'email' | join: ',' }}` to dynamically address emails based on who is assigned to the incident.
## Uninstall
To remove the Email integration:
1. Go to **Configuration → Integrations** and find **Email**
2. Click **Settings**
3. Click **Delete**
Deleting the integration permanently removes your alias. Any monitoring tools or scripts sending emails to the old alias will stop creating incidents. You will receive a new alias if you reconnect.
## Frequently Asked Questions
No. The inbound alias is always on Rootly's domain (`email.rootly.io`). If you need to route from your own domain, set up email forwarding from your mail provider to the Rootly alias.
Yes. Any email sent to your alias creates an incident, regardless of the sender. You can configure as many tools as needed to send alerts to the same address.
The workflow action is skipped and a log entry is recorded. No email is sent. This can happen if a Liquid expression resolves to an empty value — double-check your template variables if emails aren't being delivered.
On trial plans, BCC is capped at 10 recipients and total recipients (To + CC + BCC) at 50. Paid plans do not have these restrictions.
# Fivetran
Source: https://docs.rootly.com/integrations/fivetran
Sync Rootly incident, alert, and metrics data to your data warehouse via Fivetran for custom analytics, BI dashboards, and long-term reliability reporting.
## Overview
Fivetran is a no-code data movement platform that syncs your Rootly incident data directly into your data warehouse. Once connected, you can query incident data alongside the rest of your business metrics in any BI tool.
Pull Rootly incidents, workflows, roles, and more into Snowflake, BigQuery, Redshift, or any Fivetran-supported destination.
Build tailored visualizations and executive reports in your BI tool of choice — beyond what Rootly's built-in analytics provide.
Join Rootly incident data with other business metrics for deeper trend analysis and forecasting.
Fivetran handles scheduling and incremental syncs — historical data is captured on first run, then kept up to date automatically.
## Synced Data
Fivetran syncs the following tables from Rootly into your destination:
| Table | Contents |
| --------------- | ----------------------------------------------------------- |
| **Incidents** | Core incident records — title, severity, status, timestamps |
| **Cause** | Root cause data attached to incidents |
| **Roles** | User role assignments per incident |
| **Form Fields** | Custom form field values |
| **Workflows** | Workflow definitions and run history |
| **Audit** | Audit log entries |
## Before You Begin
* You need a Fivetran account with a configured destination (Snowflake, BigQuery, Redshift, etc.)
* You need Rootly admin or owner access to generate an API key
## Installation
Setup is handled entirely in Fivetran. Rootly only needs to provide an API key.
In Rootly, go to **Organization Settings → API Keys** and create a new API key. Copy it — you'll paste it into Fivetran.
In Fivetran, navigate to **Connectors** and add a new connector. Search for **Rootly** and select it.
Enter your destination schema name and paste in your Rootly API key, then click **Save & Test**.
For detailed field-by-field setup instructions, see [Fivetran's Rootly setup guide](https://fivetran.com/docs/connectors/applications/rootly/setup-guide).
Fivetran performs a full historical sync on first run, then syncs incrementally on a schedule based on your Fivetran plan.
## Frequently Asked Questions
Sync frequency is determined by your Fivetran plan and connector settings. Fivetran manages the schedule — there are no sync controls in Rootly.
Yes. The initial sync captures all historical data available via the Rootly API. Subsequent syncs are incremental.
Fivetran maintains the full entity-relationship diagram at the [Rootly connector ERD](https://fivetran.com/connector-erd/rootly).
No. The integration is managed entirely from Fivetran. As long as your Rootly API key remains valid, syncs will continue automatically.
## Related resources
* [Airtable](/integrations/airtable)
* [AWS EventBridge](/integrations/aws-eventbridge)
* [Looker](/integrations/looker)
# Freshservice
Source: https://docs.rootly.com/integrations/freshservice
Connect Freshservice to Rootly to automatically create and update tickets and tasks from incidents in your IT service management workspace.
The Freshservice integration connects Rootly with your Freshservice instance so teams can automatically create and update tickets and tasks through Genius workflows. Tickets are created using Freshservice's ticket API with full support for priority, status, tags, CC recipients, and custom fields.
With the Freshservice integration, you can:
* Automatically create Freshservice tickets when incidents are declared or reach a certain state
* Create tasks within a Freshservice ticket to track action items
* Update ticket and task fields as incidents evolve
* Map incident severity and status to Freshservice priority and ticket status automatically
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A Freshservice account with admin access
* Your Freshservice subdomain (the part before `.freshservice.com`)
* A Freshservice API key
To find your Freshservice API key, log in to Freshservice and go to **Profile Settings > API Key**. The key is shown at the bottom of the page.
Rootly recommends installing with a dedicated Freshservice service account so the integration does not break if an individual user leaves your organization.
## Installation
Navigate to the integrations page in Rootly and select **Freshservice**.
Provide the following:
* **Domain Name** — your Freshservice subdomain (for example, `yourcompany` for `yourcompany.freshservice.com`)
* **API Key** — the API key from your Freshservice profile settings
Select **Connect** to validate the credentials and complete installation.
After installation, the **Create a Freshservice Ticket**, **Update a Freshservice Ticket**, **Create a Freshservice Task**, and **Update a Freshservice Task** workflow actions are available in your Genius workflows.
## Workflow Actions
The Freshservice integration provides four workflow actions for managing tickets and tasks. If you are unfamiliar with how Genius workflows work, visit the [Workflows](/workflows/workflows) documentation first.
### Create a Freshservice Ticket
This action creates a new ticket in Freshservice.
| Field | Description | Required |
| ------------------------- | ----------------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Request User Email** | Email of the requester. Must exist in Freshservice. Supports Liquid | Yes |
| **Subject** | Ticket subject line. Supports Liquid | Yes |
| **Description** | Ticket body. Supports Liquid | |
| **Tags** | Comma-separated tags to apply to the ticket. Supports Liquid | |
| **CC Emails** | Additional email addresses to CC on the ticket | |
| **Priority** | Ticket priority. **Auto** mirrors the incident severity | |
| **Status** | Ticket status. **Auto** mirrors the incident status | |
| **Custom Fields Mapping** | JSON mapping Freshservice custom field names to values. Supports Liquid | |
**Priority mapping (Auto)**
| Rootly Severity | Freshservice Priority |
| --------------- | --------------------- |
| Critical | Urgent (4) |
| High | High (3) |
| Medium | Medium (2) |
| Low | Low (1) |
**Status mapping (Auto)**
| Rootly Status | Freshservice Status |
| ------------- | ------------------- |
| Started | Open (2) |
| Mitigated | Open (2) |
| Resolved | Resolved (4) |
### Update a Freshservice Ticket
This action updates an existing Freshservice ticket.
When a **Create a Freshservice Ticket** action runs, Rootly stores the resulting ticket ID on the incident record. Reference it in subsequent update actions using Liquid variables.
| Field | Description | Required |
| ------------------------- | ---------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Ticket ID** | Freshservice ticket ID to update. Supports Liquid | Yes |
| **Subject** | Updated ticket subject. Supports Liquid | Yes |
| **Description** | Updated ticket description. Supports Liquid | |
| **Tags** | Updated tags. Supports Liquid | |
| **Priority** | Updated priority | |
| **Status** | Updated ticket status | |
| **Custom Fields Mapping** | Updated custom field values as JSON. Supports Liquid | |
### Create a Freshservice Task
This action creates a task within an existing Freshservice ticket.
| Field | Description | Required |
| -------------------- | ---------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Parent Ticket ID** | Freshservice ticket ID to create the task under. Supports Liquid | Yes |
| **Title** | Task title. Supports Liquid | Yes |
| **Description** | Task description. Supports Liquid | |
| **Status** | Task status. **Auto** mirrors the incident or action item status | Yes |
**Task status mapping (Auto)**
| Rootly Status | Freshservice Task Status |
| ---------------- | ------------------------ |
| Open | Open (1) |
| In Progress | In Progress (2) |
| Done / Cancelled | Completed (3) |
### Update a Freshservice Task
This action updates an existing task within a Freshservice ticket.
| Field | Description | Required |
| -------------------- | ----------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Parent Ticket ID** | Freshservice ticket ID containing the task. Supports Liquid | Yes |
| **Task ID** | Freshservice task ID to update. Supports Liquid | Yes |
| **Title** | Updated task title. Supports Liquid | |
| **Description** | Updated task description. Supports Liquid | |
| **Status** | Updated task status | Yes |
## Troubleshooting
The email provided in the **Request User Email** field must correspond to an existing Freshservice contact or agent. Verify the email address exists in your Freshservice account before creating tickets.
Custom field names in the **Custom Fields Mapping** JSON must match the field names as they appear in the Freshservice API (typically snake\_case). Check your Freshservice admin settings under **Admin > Custom Fields** to confirm the correct field names.
## Uninstall
To remove the Freshservice integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related Resources
* [Workflows](/workflows/workflows)
* [Liquid templating](/liquid/liquid)
* [Integrations overview](/integrations/overview)
# Generic Webhook Alert Source
Source: https://docs.rootly.com/integrations/generic-webhook-alert-source/generic-webhook-alert-source
Ingest alerts from any monitoring, observability, or security tool into Rootly via webhook — works with any system that can POST JSON to a URL.
The **Generic Webhook Alert Source** lets Rootly ingest alerts from any tool that can fire HTTP webhooks. If your monitoring, observability, security, or data-quality platform can send a POST with a JSON body, Rootly can turn that event into an alert, route it to the right responder, and trigger downstream automation.
Use it when your alerting tool doesn't have a dedicated Rootly integration, when you're ingesting alerts from custom or internal services, or when you want a single, unified pattern for handling webhook-based signals across multiple sources.
***
## Compatible Alerting Tools
If a tool can send an HTTP POST with a JSON body, it works with Rootly. The Generic Webhook Alert Source is the standard way to wire up alerts from:
* **Application performance & error tracking** — BugSnag, AppOptics, Coralogix
* **Infrastructure & log monitoring** — Sumo Logic, Elastic, Chronosphere, Nagios, PRTG
* **Uptime & synthetic monitoring** — Pingdom, StatusCake, uptime.com, Checkly, Cronitor, Runscope
* **Security & threat detection** — CrowdStrike, Expel, Cloudflare
* **Data quality & observability** — Monte Carlo
It also works for internal services, custom monitoring jobs, scheduled scripts, and any system you build in-house that needs to page an on-call responder.
If your tool has a [dedicated Rootly integration](/integrations/overview), prefer that — native sources reduce setup time and ship with vendor-specific field mappings. The Generic Webhook Alert Source is the right choice when no native integration exists.
***
## How It Works
The Generic Webhook Alert Source gives you a webhook endpoint URL that your external system POSTs alert events to. When a request arrives, Rootly:
1. **Authenticates the request** using the Bearer Token configured for the source.
2. **Parses the JSON body** and extracts the fields you mapped — title, description, identifier, state, routing target.
3. **Creates or updates an alert** based on the External Identifier. If Rootly already has an alert with the same identifier, follow-up events update it; otherwise a new alert is created.
4. **Routes the alert** to the target you specified, either from the URL or from the payload itself.
5. **Triggers alert workflows**, which can create incidents, page on-call, post to Slack, or run any other downstream action you've configured.
Webhook events are processed asynchronously. The POST returns quickly; the alert appears in Rootly shortly after.
***
## Before You Begin
Before creating a Generic Webhook Alert Source, make sure you have:
* Access to create alert sources in Rootly
* A tool that can send `POST` requests with a JSON body
* A plan for how alerts should be routed after ingestion
* The fields you want Rootly to extract, such as:
* Alert title
* Description
* External identifier
* Alert state
* Routing target
For best results, send requests with `Content-Type: application/json`.
In production, the Generic Webhook Alert Source uses these endpoint patterns:
* Base endpoint: `POST https://webhooks.rootly.com/webhooks/incoming/generic_webhooks`
* Fixed target endpoint: `POST https://webhooks.rootly.com/webhooks/incoming/generic_webhooks/notify//`
Use the **base endpoint** when routing will be determined from the incoming payload. Use the **notify** endpoint only when both the target type and target ID are included in the URL.
## Installation
Go to the [new alert source page](https://rootly.com/account/integrations) and locate **Generic Webhook Alert Source**.
You will be prompted to name the source.
Rootly verifies inbound generic webhook requests using a **Bearer Token** — a static secret you provide in either of these forms:
* `Authorization: Bearer `
* `secret` as a query string or request parameter
If the secret is missing or invalid, Rootly rejects the request with a `401 Unauthorized` response. Prefer the header form when your sending tool supports it — query parameters tend to be captured in proxy and load-balancer access logs.
**Example request** (header form, recommended):
```bash theme={null}
curl -X POST \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"title": "High CPU on web-01",
"description": "CPU > 90% for 5 minutes",
"external_id": "monitor-12345",
"state": "triggered"
}' \
https://webhooks.rootly.com/webhooks/incoming/generic_webhooks
```
**Example request** (query-parameter form):
```bash theme={null}
curl -X POST \
-H "Content-Type: application/json" \
-d '{ "title": "High CPU on web-01", "external_id": "monitor-12345", "state": "triggered" }' \
"https://webhooks.rootly.com/webhooks/incoming/generic_webhooks?secret="
```
Generic webhook sources do not require a strict vendor-specific payload shape. Instead, you configure how Rootly should interpret the incoming JSON by mapping fields from the webhook payload.
At a minimum, you should map a field for the alert title so alerts are easy to identify in Rootly.
Depending on your use case, you may also want to map:
* Alert description
* External URL
* External identifier
* Alert state
* Notification target type
* Notification target ID
Follow the instructions shown on the Generic Webhook creation page to configure these mappings.
**Notification target ID must be Rootly's internal resource ID** — not a team name, service slug, or any human-readable identifier. Open the service, team, or escalation policy in Rootly and copy the ID from its edit page. Using a name or slug is a common cause of alerts that ingest successfully but never route. See [Routing Alerts](#routing-alerts) for the full mapping guidance.
## Authentication
Rootly authenticates inbound webhook requests with a **Bearer Token** — a static secret sent in the `Authorization` header, or as a `secret` query string parameter on the webhook URL. Prefer the header form when your sending tool supports it — query parameters tend to be captured in proxy and load-balancer access logs, so they're more exposure-prone than a header. Either form is simple to set up: paste the secret into your sending tool and you're done.
Code samples for Bearer Token authentication live in [Installation](#installation).
***
## Mapping Payload Fields
Rootly doesn't require a specific JSON shape. You map fields from your sending tool's payload to Rootly's alert fields during source creation.
A typical payload from a monitoring tool:
```json theme={null}
{
"alert_title": "High CPU on web-01",
"alert_description": "CPU > 90% for 5 minutes",
"external_id": "monitor-12345",
"state": "triggered",
"service": "web-api"
}
```
Map those fields to Rootly's alert fields in the source configuration:
| Rootly Field | Mapped From | Purpose |
| ------------------- | ------------------- | ---------------------------------------------------------------------- |
| Title | `alert_title` | Headline shown on the alert |
| Description | `alert_description` | Body text on the alert |
| External Identifier | `external_id` | Stable key Rootly uses to match follow-up events to the same alert |
| State | `state` | Lifecycle state — drives auto-resolution when a recovery event arrives |
| Routing Target | `service` | Which service, team, or escalation policy receives the alert |
The **External Identifier** is what Rootly uses to match recovery events back to the original alert when auto-resolution is configured. Map it to whatever field your sending tool uses as the alert's persistent ID (`monitor_id`, `incident_id`, `alert_uuid`, etc.) so that a follow-up "resolved" event can close the original alert instead of being ignored.
See the Installation guide for the field-mapping UI walkthrough.
***
## Routing Alerts
There are two ways to tell Rootly where an alert should go. You can mix both across sources, but a single source typically uses one or the other.
Include the target type and ID directly in the webhook URL Rootly generates:
```http theme={null}
POST https://webhooks.rootly.com/webhooks/incoming/generic_webhooks/notify//
```
Use this when every alert from this source should always route to the same target — one service, one team, or one escalation policy. Cleanest setup, and you do not need to map the target type and target ID in the payload mapping step.
Send the target type and ID in the JSON body and let Rootly extract them via field mappings:
```json theme={null}
{
"alert_title": "Database slow query",
"notification_target_type": "service",
"notification_target_id": "8c4a5e91-1b2d-4c3e-9f6a-7d8b2c5e9a01"
}
```
The `notification_target_id` is the Rootly resource's internal ID — open the service, team, or escalation policy in Rootly and copy the ID from its edit page. Names and slugs aren't accepted in this field.
Use this when a single source needs to route alerts to different targets depending on the event — useful when your monitoring tool already tags events by service or team, or when you want the routing decision to come from the event payload itself. Advanced payloads can also include a Rootly notification target object directly in the JSON body.
Common target types: `service`, `group` (or `team`), `escalationPolicy`.
## Automatically Added Labels
Every alert ingested from a Generic Webhook Alert Source is automatically tagged with a **`source_name`** label whose value is your alert source's name parameterized — lowercased, with spaces and other non-alphanumeric characters replaced by hyphens. For example, an alert source named `Harbor Image Scan (c1)` adds `source_name:harbor-image-scan-c1` to every alert it produces.
This label is the canonical way to differentiate alert sources of the same type in Alert Workflows. The source condition in a workflow matches by source **type** (for example, `generic_webhook`), so if you have multiple Generic Webhook sources, the workflow can't tell them apart from the source condition alone — pair it with a `source_name` label condition (using **contains any of**) to scope each workflow to a specific source instance. See [Scoping to a specific source instance](/workflows/alert-workflows#scoping-to-a-specific-source-instance) for the workflow-side setup.
## Test the Source
After setup, send a test alert from your observability provider and confirm that Rootly receives and processes it as expected.
A successful test should confirm that:
* The webhook request reaches Rootly
* The payload is parsed correctly
* The alert title and other mapped fields are populated as expected
* The alert routes to the correct target
* The alert appears in Rootly
Rootly processes webhook events asynchronously, so the alert may appear shortly after a successful request.
If the request is authenticated correctly but the payload is missing expected fields, Rootly may still ingest the event, but the alert may not contain the data you intended.
## Auto-Resolution
Auto-resolution lets Rootly close alerts when your external system sends a recovery or resolved-style webhook event. This is useful when your monitoring platform sends one event when an issue starts and another when it clears — by configuring the correct identifier and state fields, Rootly recognises the related alert and applies the resolution logic you defined.
Auto-resolution depends on the resolution configuration stored on the source.
For the Generic Webhook Alert Source, that configuration is based on:
* The field that identifies the alert
* The field that represents its state
* The value that should be treated as resolved
These settings allow Rootly to handle follow-up webhook events consistently when your source sends a recovery or cleared event.
### Configure Auto-Resolution
Configure a field mapping for the external identifier in your webhook payload.
This value should stay consistent across events for the same alert so Rootly can associate follow-up webhook events with the correct alert.
Configure a field mapping for the alert state in your webhook payload.
This field should represent whether the alert is active, cleared, resolved, or in another lifecycle state used by your source system.
Set the state value that Rootly should treat as resolved.
In most cases, this is an exact match against the value you configure, such as `resolved`, `recovered`, or `ok`.
Turn on auto-resolution for the Generic Webhook Alert Source after your identifier and state mappings are configured.
Once enabled, Rootly uses those mappings and the resolved-state value as part of the source’s resolution configuration.
### Important Notes
* Auto-resolution depends on the field mappings configured for the source
* The identifier field and state field should be stable and predictable in your incoming webhook payload
* If your payload does not include the expected values, Rootly may still ingest the alert event, but it may not resolve the alert the way you intend
* Some teams may also use payload-driven alert status fields separately from auto-resolution mapping
* Teams using newer alert field or resolution-rule configuration may manage this behavior through that newer configuration path instead of the legacy generic webhook mapping flow
## From Alert to Incident
Alerts created through this source behave like any other Rootly alert — they're regular signals you can drive any of Rootly's alert-driven automation off of:
* **Create incidents** automatically based on alert content, severity, or service
* **Page on-call responders** through escalation policies
* **Post notifications** to Slack, Microsoft Teams, or email
* **Trigger downstream workflows** that update runbooks, status pages, ticketing systems, or run custom scripts
The webhook source ingests the alert; [alert workflows](/workflows/alert-workflows) decide what the alert *means* and what should happen next.
***
## Troubleshooting
The most common cause is a missing or mismatched Bearer token. Confirm:
* The `Authorization: Bearer ` header is present on the request (or the `secret` query string parameter is set)
* The secret matches the one shown in the source configuration in Rootly
Webhooks process asynchronously, so check again after a few seconds. If the alert still doesn't appear:
* Verify the Title field mapping points at a non-empty field in the payload
* Check the source's recent activity in Rootly to confirm the payload was received
* Confirm the routing target referenced in the URL or payload exists and isn't archived
The field mapping is pointing at JSON paths that don't exist in the incoming payload. Capture a real payload using a request inspector (RequestBin, webhook.site, or a local server), compare it against your mapping, and update the JSON paths to match the actual structure.
The External Identifier isn't mapped to a stable, unique value, so the resolved event can't be matched back to the original alert. Map it to whatever field your sending tool uses as the persistent ID (`monitor_id`, `incident_id`, `alert_uuid`, etc.) so trigger and recovery events share the same identifier.
Either the recovery payload has a different External Identifier than the original alert, or the State field isn't mapping to the exact resolved value you configured. See [Auto-Resolution](#auto-resolution) for the matching rules.
Switch from URL-based routing to payload-based routing. Map the target type and target ID fields from the incoming JSON so the routing decision lives in the event itself.
***
## Frequently Asked Questions
No. If your tool can send an HTTP POST with a JSON body, the Generic Webhook Alert Source can ingest its alerts. Native integrations are nicer when they exist because they ship with vendor-specific field mappings and reduce setup time, but they're not required.
Alerts are signals — discrete events from your monitoring stack. Incidents are coordinated response — the incident channel, the timeline, the retrospective. One incident may be informed by many alerts. The webhook source creates alerts; [alert workflows](/workflows/alert-workflows) decide when an alert should escalate to an incident.
You can, but it's cleaner to create one source per sending tool. Separate sources make it easier to route alerts differently per tool, attribute issues during troubleshooting, and manage authentication independently.
Route the alert to a single target with the webhook, then use an alert workflow to fan out the response — page on-call, post to Slack, create an incident, update a status page. The webhook ingests the alert; the workflow decides what should happen next.
Both work. Rootly accepts the Bearer secret either as the `Authorization: Bearer ` header or as a `secret` query string parameter on the webhook URL.
The webhook source maps from existing payload fields, and alert workflows fire after an alert is created and routed — not before. To compose a richer title (combining service name, severity, and a summary, for example), construct the title in your sending system before the webhook is sent and map the prepared field as the Title.
Any valid JSON. Rootly doesn't require a specific schema — instead you map your tool's existing fields to Rootly's alert fields during source setup. Most monitoring tools work out of the box; you just point them at the webhook URL and configure the mapping.
***
## Related Resources
* [Alert workflows](/workflows/alert-workflows)
* [Alert routing](/alerts/alert-routing)
* [Integrations overview](/integrations/overview)
# GitHub
Source: https://docs.rootly.com/integrations/github/github
Track deployments, create and update issues, fetch commits, and enrich PR links with automatic status tracking for incident management.
Connect GitHub to Rootly to automate issue tracking, surface commit context during incidents, and capture deployment signals as they happen.
**This integration allows you to:**
* Create and update GitHub issues from incident workflows
* Fetch recent commits across repositories during an incident
* Receive push, pull request, and issue events as Rootly pulses
* Automatically enrich GitHub PR links shared in Slack with live status updates
## Before You Begin
You must be an **Owner** of your GitHub organization and an **Admin** of your Rootly account to complete this installation.
Rootly recommends using a **service account** so the integration continues to work if a user leaves your organization.
This integration uses a two-step process:
1. Install the **rootlyhq** GitHub App from the GitHub Marketplace
2. Connect GitHub to Rootly via OAuth
## Permissions
The following GitHub App permissions are required:
| Permission | Access Level |
| ------------- | ------------ |
| Checks | Read |
| Code | Read |
| Deployments | Read |
| Metadata | Read |
| Pull Requests | Read |
| Issues | Read + Write |
## Installation
### Step 1: Install the GitHub Marketplace App
Navigate to the GitHub Apps page for your organization. Replace `` with your organization's name:
```text theme={null}
https://github.com/organizations//settings/installations
```
Click **GitHub Marketplace**.
Search for **rootly** and click on the Rootly app.
Click **Add** to begin the installation.
If you belong to multiple GitHub organizations, select the correct one and click **Install it for free**.
Confirm the correct organization is selected. Check **Allow my billing information to be linked with this organization** and click **Save**.
Click **Complete order and begin installation**.
Select the desired **scope of access** (all repositories or specific repositories) and click **Install**.
Log out of your GitHub account before proceeding. This is required so Rootly can re-establish the connection under the correct account.
### Step 2: Connect GitHub to Rootly
Navigate to the [Integrations](https://rootly.com/account/integrations) page in Rootly and search for **github**.
You'll be prompted to sign in to GitHub to authorize the connection to your organization.
Click **Save** to complete the setup.
GitHub is now connected. You can use the **Create Issue**, **Update Issue**, and **Get Commits** workflow actions, and GitHub events will begin flowing in as pulses.
## Workflow Actions
These actions are available in **Incident Workflows** and **Alert Workflows**.
### Create a GitHub Issue
Creates a new issue in the specified GitHub repository and links it to the Rootly incident or action item.
| Field | Description | Required |
| ----------------------- | ------------------------------------------------------------------------------- | -------- |
| **Repository** | The GitHub repository where the issue will be created (for example, `org/repo`) | Yes |
| **Title** | Issue title. Supports Liquid templating (for example, `{{ incident.title }}`) | Yes |
| **Body** | Issue body/description. Supports Liquid templating | No |
| **Labels** | Comma-separated list of label names to apply to the issue | No |
| **Issue Type** | The type of issue to create (for example, `Bug`, `Feature`, `Task`) | No |
| **Parent Issue Number** | Issue number of the parent issue. Use this to create a sub-issue | No |
### Update a GitHub Issue
Updates an existing GitHub issue linked to the incident or action item.
| Field | Description | Required |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| **Issue ID** | The ID of the GitHub issue to update. Use the stored ID from a prior Create Issue action | Yes |
| **Title** | New title for the issue. Supports Liquid templating | No |
| **Body** | New body/description. Supports Liquid templating | No |
| **Labels** | Comma-separated list of label names to apply | No |
| **Issue Type** | Updated issue type | No |
| **Completion** | Set to **Auto** to mirror the incident or action item status. Closes the issue when the incident resolves or the action item is marked done | No |
When **Completion** is set to **Auto**, Rootly will automatically close the GitHub issue when the linked incident is resolved or the linked action item is completed.
### Get Commits
Fetches recent commits from one or more GitHub repositories and optionally posts them to the incident timeline or a Slack channel.
| Field | Description | Required |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| **Services Impacted by Incident** | When enabled (default), automatically queries the GitHub repositories linked to the services impacted by the incident. Disable this to specify repositories manually | No |
| **Service IDs** | Rootly service IDs whose linked GitHub repositories will be queried. Required when **Services Impacted by Incident** is disabled and **Repository Names** is not set | Conditional |
| **Repository Names** | Explicit list of GitHub repository names to query (for example, `org/repo`). Required when **Services Impacted by Incident** is disabled and **Service IDs** is not set | Conditional |
| **Branch** | The branch to fetch commits from. Defaults to `master` | No |
| **Past Duration** | How far back to look for commits (for example, `1h`, `30m`) | No |
| **Post to Incident Timeline** | When enabled, appends fetched commits as an event in the incident timeline | No |
| **Post to Slack Channels** | Slack channel names to post the commit list to | No |
When **Services Impacted by Incident** is disabled, either **Service IDs** or **Repository Names** must be provided. Each service used must have a GitHub repository configured in its settings.
## PR Link Enrichment
When an engineer pastes a GitHub PR URL into the incident's Slack channel, Rootly automatically:
1. Detects the PR link and attaches it to the incident
2. Tracks the PR status (open, approved, merged) in real time
3. Posts status updates in Slack as the PR progresses
4. Adds each status change as an event in the incident timeline
## Inbound Events (Pulses)
Rootly receives GitHub webhook events and stores them as **pulses** — timestamped signals you can correlate with incidents.
### Supported Events
| Event | Trigger |
| -------------------------- | ------------------------------------------- |
| **Push** | Any push to any repository branch |
| **Pull Request: Opened** | A new pull request is opened |
| **Pull Request: Closed** | A pull request is closed without merging |
| **Pull Request: Merged** | A pull request is merged |
| **Pull Request: Approved** | A pull request review approval is submitted |
| **Issues** | A GitHub issue is opened, closed, or edited |
### Pulse Labels
Each pulse includes the following labels for filtering and routing:
| Label | Description | Events |
| ------------ | -------------------------------------------------- | --------------------- |
| `action` | Event action (for example, `push`, `pr_merged`) | All |
| `repository` | Repository name where the event originated | All |
| `ref` | Branch or tag ref (for example, `refs/heads/main`) | Push, Pull Request |
| `base` | Target branch of the pull request | Pull Request (merged) |
| `merged_by` | GitHub login of the user who merged the PR | Pull Request (merged) |
## Secret Scanning
GitHub scans public repositories for known secret patterns, including Rootly API tokens.
Rootly has partnered with GitHub's secret scanning program. When a Rootly token is detected in a public repository, GitHub notifies Rootly, which then alerts workspace owners and allows them to revoke the token within seconds.
GitHub Advanced Security customers can additionally enable [push protection](https://github.blog/changelog/2022-04-04-secret-scanning-prevents-secret-leaks-with-protection-on-push/) to block Rootly tokens from entering repositories at push time.
* [Learn more about secret scanning](https://docs.github.com/en/github/administering-a-repository/about-secret-scanning)
* [Partner with GitHub on secret scanning](https://docs.github.com/en/developers/overview/secret-scanning/)
## Troubleshooting
* Confirm the repository name is in `org/repo` format
* Verify the connected GitHub account has write access to the target repository
* Check that the **rootlyhq** GitHub App is still installed and has access to the repository
* Confirm the branch name is correct and exists in the repository
* Check that the **Past Duration** window is wide enough to include recent commits
* When using Service IDs, verify each service has a GitHub repository configured in its settings
* The incident must have an active Slack channel
* The PR URL must be pasted directly in the incident Slack channel (not a thread)
* Confirm the GitHub App has **Read** access to pull requests
* Navigate to the Rootly integrations page and verify the GitHub connection is active
* Re-authenticate if the OAuth token has expired
* Confirm the **rootlyhq** GitHub App is installed and the webhook is active in your GitHub organization settings
## Uninstall
Uninstalling requires two steps — removing the integration from Rootly and uninstalling the GitHub App.
Delete the GitHub integration from Rootly via the **Integrations** page.
Uninstall the **rootlyhq** app from your organization's GitHub Apps page.
# GitLab Integration
Source: https://docs.rootly.com/integrations/gitlab
Connect GitLab to Rootly to track deployments and merge requests as pulses, create issues from incidents, and enrich GitLab links in Slack.
## Introduction
The GitLab integration connects Rootly with GitLab through OAuth so your team can surface engineering context during incidents and automate issue tracking across both platforms.
With the GitLab integration, you can:
* Fetch recent commits from GitLab repositories through incident workflows
* Automatically track push events, merged merge requests, and deployment events as Rootly pulses
* Create and update GitLab issues directly from incident and action item workflows
* Enrich GitLab merge request links pasted into incident Slack channels with live status cards
* Connect to self-hosted GitLab instances in addition to gitlab.com
GitLab issues can be created from both incident workflows and action item workflows, making it easy to turn follow-up work into trackable GitLab tasks automatically.
## Before You Begin
Before setting up the GitLab integration, make sure you have:
* A Rootly account with permission to manage integrations
* A GitLab account with **admin access** to create OAuth applications
* The GitLab instance URL if you are using a self-hosted GitLab instance (must use HTTPS)
This integration uses OAuth 2.0. You will need to create an OAuth application in GitLab and paste the credentials into Rootly. Keep your application secret secure — it is encrypted at rest in Rootly.
## Installation
Navigate to the integrations page in your Rootly workspace and select **GitLab**.
In GitLab, go to **User Settings → Applications** (or **Admin Area → Applications** for instance-wide access) and create a new OAuth application.
Enter the following values:
| Field | Value |
| ------------ | ----------------------------------------- |
| Redirect URI | `https://rootly.com/auth/gitlab/callback` |
| Scopes | `api` or `read_api` |
Use the `api` scope to let Rootly automatically create webhooks on your repositories. If you prefer to manage webhooks yourself, use `read_api` instead.
After saving your GitLab application, copy the **Application ID** and **Secret** and paste them into Rootly.
If you are using a self-hosted GitLab instance, enter your instance URL (must start with `https://`). The default is `https://gitlab.com`.
Optionally, specify the repository names you want Rootly to track for pulse events. If you leave this blank, Rootly will track all repositories accessible to the connected account.
Limiting tracked repositories reduces noise. Only pushes, merge requests, and deployments from listed repositories will appear as Rootly pulses.
Your GitLab integration is live. Rootly will begin tracking events from your repositories and the workflow actions below will be available in your incident and action item workflows.
## Pulse Events
Rootly automatically ingests the following GitLab webhook events and records them as pulses on the incident timeline and service activity feed.
### Push Events
When a commit is pushed to any tracked repository, Rootly creates a pulse with:
* **Summary:** `[GitLab][Push] Commit: {commit message}`
* **Labels:** repository name, action (push)
* **Refs:** commit SHA, short SHA, branch ref
### Merge Request Events
When a merge request is merged, Rootly creates a pulse and posts an enriched card to any linked incident Slack channel with merge request details and status.
* **Summary:** `[GitLab][MR] Merged: {source branch}`
* **Labels:** repository name, action (pr\_merged)
* **Refs:** merge commit SHA, base branch
Even if an MR is not merged during an active incident, Rootly will enrich any GitLab merge request URL pasted into an incident Slack channel with a live status card showing the MR title, author, and current state.
### Deployment Events
When a deployment event is received, Rootly creates a pulse tied to the associated environment.
* **Summary:** `[GitLab][Deploy] Commit: {title} | {status}`
* **Labels:** repository name, action (deploy)
* **Refs:** short commit SHA
### Issue Events
GitLab issue events are also ingested and converted to Rootly alerts with severity, state, and a link back to the GitLab issue.
## Workflow Actions
GitLab workflow actions are available in both incident workflows and action item workflows.
### Create a GitLab Issue
Creates a new issue in a specified GitLab repository. Available in incident and action item workflows.
| Field | Description | Required |
| ----------- | ------------------------------------------------------------------------------ | -------- |
| Repository | The GitLab repository to create the issue in | Yes |
| Issue Type | Type of issue: `issue`, `incident`, `test_case`, or `task` | No |
| Title | Issue title — supports Liquid templating (for example, `{{ incident.title }}`) | Yes |
| Description | Issue body — supports Liquid templating | No |
| Labels | Comma-separated labels to apply | No |
| Due Date | Due date — supports Liquid templating | No |
Use Liquid variables like `{{ incident.title }}`, `{{ incident.severity }}`, and `{{ incident.url }}` in the title and description to automatically populate issues with live incident context.
### Update a GitLab Issue
Updates an existing GitLab issue. Commonly used to close or reopen issues when an incident changes state.
| Field | Description | Required |
| ----------- | ---------------------------------------------------------------------------------- | -------- |
| Issue ID | ID of the GitLab issue to update — supports Liquid templating | Yes |
| Issue Type | Type of issue to update | No |
| Title | Updated title | No |
| Description | Updated body | No |
| Labels | Updated labels | No |
| Due Date | Updated due date | No |
| Completion | Whether to close or reopen the issue — can be set to auto-map from incident status | Yes |
Set **Completion** to auto-map from incident status so GitLab issues close automatically when the linked Rootly incident is resolved, and reopen if the incident is reopened.
### Get GitLab Commits
Fetches recent commits from one or more repositories and posts them to a Slack channel. Useful for surfacing recent code changes during incident investigation.
| Field | Description | Required |
| ---------------------- | -------------------------------------------------------------------- | -------- |
| Services | Services to fetch commits for (uses the service's linked repository) | No\* |
| Repository Names | Specific GitLab repository names to query | No\* |
| Branch | Branch to fetch commits from | Yes |
| Past Duration | How far back to look (for example, `2 hours`, `1 day`) | Yes |
| Post to Slack Channels | Slack channels to post results to | No |
\* At least one of **Services** or **Repository Names** is required.
## Default Workflows
When GitLab is connected, Rootly can create the following default workflows to get you started:
* **Create a GitLab issue when an incident is declared** — automatically opens a GitLab issue tied to the incident
* **Update the GitLab issue when the incident is resolved** — closes the linked issue when the incident closes
* **Create a GitLab issue for each action item** — turns follow-up tasks into GitLab issues automatically
* **Update the GitLab issue when an action item is completed** — keeps GitLab in sync as action items are closed
Review and customize these workflows after installation to match your team's process.
## Troubleshooting
Rootly automatically creates webhooks when you add repository names to the integration settings. If webhooks are not appearing in GitLab, confirm that the OAuth application was created with the `api` scope. The `read_api` scope does not allow Rootly to create webhooks on your behalf — you will need to create them manually if you use `read_api`.
Check that the repository name is listed in the integration's **Repository Names** field. Only events from listed repositories are tracked. Also verify that the GitLab webhook is active by checking **Repository → Settings → Webhooks** in GitLab and confirming the Rootly webhook URL appears there with recent delivery history.
Link enrichment applies to merge request URLs pasted into incident Slack channels. Confirm that the GitLab integration is connected and that the URL format matches a GitLab merge request (the path should contain `/merge_requests/`). Personal or group access tokens are not supported — the integration must be connected via OAuth.
The OAuth token must have access to the repository you are targeting. If the repository is in a group or namespace the connected user cannot access, the action will fail. Re-authenticate with a user or service account that has the appropriate permissions.
GitLab OAuth tokens are tied to the user who authorized the application. If that user is removed from your GitLab instance, the token becomes invalid. Reconnect the integration using a GitLab service account or bot user to avoid this in the future.
Make sure your instance URL starts with `https://` and does not have a trailing slash. Rootly does not support HTTP-only GitLab instances. Also confirm that your GitLab instance is reachable from the public internet, as Rootly needs to send webhook deliveries to it.
## Uninstall
To remove the GitLab integration, go to the integrations page in Rootly, find the GitLab account, and select **Configure → Delete**. This will disconnect the account and remove all Rootly-managed webhooks from your repositories.
## Related Pages
Automate GitLab issue creation and updates using incident workflow triggers.
Automatically create and close GitLab issues as action items move through their lifecycle.
Learn how deployment and commit events appear as pulses in Rootly.
# Glean
Source: https://docs.rootly.com/integrations/glean
Sync Rootly incident data to Glean so your team can search incidents, schedules, alerts, and retrospectives alongside the rest of your company knowledge.
## Introduction
The Rootly–Glean connector is an open-source Python project that syncs Rootly data into Glean's unified search index. Once running, your team can search for incidents, on-call schedules, alerts, escalation policies, and retrospectives directly in Glean alongside all other company knowledge.
The connector syncs the following Rootly data types:
| Data Type | What's included |
| ----------------------- | ---------------------------------------------------------------------- |
| **Incidents** | Active and resolved incidents with severity, status, and timeline data |
| **Alerts** | Alert configurations and monitoring rules |
| **Schedules** | On-call schedules with rotations, shifts, and user assignments |
| **Escalation Policies** | Escalation rules and notification chains |
| **Retrospectives** | Post-incident analysis links |
This is a connector-based integration — data flows from Rootly into Glean for search purposes. It runs as a standalone Python service, separate from the Rootly web UI. There is no account setup required within Rootly.
## Before You Begin
Before setting up the connector, make sure you have:
* **Python 3.13 or higher** — install via Homebrew on macOS: `brew install python@3.13`
* A **Rootly API token** — generate one in **Account** > **Manage API keys** > **Generate New API Key**
* A **Glean API token** — obtain from your Glean admin
* Your **Glean API host** — the hostname of your Glean instance (for example, `your-company-be.glean.com`)
## Installation
```bash theme={null}
git clone https://github.com/rootlyhq/rootly-glean-connector.git
cd rootly-glean-connector
```
```bash theme={null}
python -m venv venv
source venv/bin/activate
```
```bash theme={null}
pip install -r requirements.txt
```
Create a `secrets.env` file in the project root with your API tokens:
```bash theme={null}
GLEAN_API_TOKEN=your_glean_api_token_here
ROOTLY_API_TOKEN=your_rootly_api_token_here
```
This file is not committed to version control.
Edit `config.json` to match your environment. At minimum, update the `glean.api_host` value to your Glean instance hostname:
```json theme={null}
{
"glean": {
"api_host": "support-lab-be.glean.com"
}
}
```
See [Configuration](#configuration) below for all available options.
```bash theme={null}
python app.py
```
The connector is running and syncing Rootly data to Glean. Your team can now search for incidents, schedules, and more directly in Glean.
## Configuration
All configuration lives in two files:
* **`config.json`** — non-sensitive settings (data types, limits, sync behavior)
* **`secrets.env`** — API tokens (keep this out of version control)
Key `config.json` options:
| Setting | Description |
| -------------------------- | --------------------------------------------------------------------------------------------------- |
| `glean.api_host` | Your Glean instance hostname (default: `support-lab-be.glean.com`) |
| Data type toggles | Enable or disable syncing for incidents, alerts, schedules, escalation policies, and retrospectives |
| Item limits | Maximum items to sync per data type |
| Enhanced incident features | Include timeline events and action items in incident documents |
| Logging level | Set verbosity for debugging |
| Sync interval | How frequently the connector polls Rootly for updates |
## Searching Rootly Data in Glean
Once the connector has synced, your team can search for Rootly data in Glean using natural language:
**Incidents**
* *"Find incidents with timeline events"*
* *"Show high severity resolved incidents"*
**Schedules & On-Call**
* *"Show the latest on-call schedule in Rootly"*
**Alerts**
* *"Show the latest alerts in Rootly"*
## Architecture
The connector is organized into four modules:
| Module | Purpose |
| ------------------- | -------------------------------------------------------------- |
| `data_fetchers/` | API clients that pull each Rootly data type via the Rootly API |
| `document_mappers/` | Converts Rootly data into the Glean document format |
| `processors/` | Coordinates sync orchestration across data types |
| `glean_schema/` | Glean document schema definitions |
This structure makes it straightforward to extend the connector — for example, to add a new Rootly data type, add a fetcher and a mapper for it.
## Troubleshooting
Confirm Python 3.13+ is installed (`python --version`) and the virtual environment is activated (`source venv/bin/activate`). Make sure dependencies are installed with `pip install -r requirements.txt`.
Confirm that `secrets.env` exists in the project root and contains valid values for both `GLEAN_API_TOKEN` and `ROOTLY_API_TOKEN`. Check that neither token has been revoked.
Allow a few minutes for Glean to index synced documents. If data still doesn't appear, check the connector logs for errors. Confirm `glean.api_host` in `config.json` matches your Glean instance hostname exactly.
Each data type (incidents, alerts, schedules, etc.) can be individually enabled or disabled in `config.json`. Confirm the relevant data type is enabled and that your Rootly API token has access to it.
## Related Pages
The connector uses the Rootly API to fetch data. See the API reference for available endpoints and token setup.
Source code, issues, and release notes for the Rootly–Glean connector.
Learn about Rootly's built-in AI features for incident management.
# GoToMeeting
Source: https://docs.rootly.com/integrations/go-to-meeting
Automatically create GoToMeeting sessions for Rootly incidents and share meeting links in Slack channels for quick responder collaboration during outages.
## Overview
Rootly's GoToMeeting integration automatically creates a meeting bridge for each incident via a workflow action. Meeting links are shared directly to Slack channels so responders can join immediately.
Spin up a GoToMeeting session the moment an incident is declared — no manual setup required.
Choose from PSTN, free conference call, hybrid, or VoIP audio depending on your team's setup.
Meeting links are automatically posted to incident Slack channels so responders can join without leaving Slack.
Attach the meeting link to the incident timeline to keep a record of collaboration during the response.
## Before You Begin
* You must be a Rootly admin to set up the integration
* You need a GoTo developer account to create an OAuth application at [developer.goto.com](https://developer.goto.com/)
* Use a **service account** rather than a personal account to prevent the integration from breaking if a user leaves
## Installation
Setting up GoToMeeting requires creating an OAuth application at GoTo's developer portal and connecting it to Rootly.
Go to [developer.goto.com](https://developer.goto.com/) and create a new OAuth application.
Set the **Redirect URI** to:
```text theme={null}
https://rootly.com/auth/go_to_meeting/callback
```
In the OAuth app settings, enable at least one of the following product scopes:
* **GoToMeeting**
* **GoToWebinar**
* **GoToTraining**
In Rootly, go to **Configuration → Integrations** and find **GoToMeeting**. Click **Connect**, then enter your **Client ID** and **Client Secret** from the GoTo developer portal and authorize.
After connecting, Rootly automatically creates a default workflow that triggers on incident creation (status: **Started**, priority: **High**) and creates a GoToMeeting session linked to the incident.
## Joining a Meeting
Once a GoToMeeting session is created for an incident, the meeting link appears in the **Integrations** section of the Rootly Slack bot message in the incident channel. Responders can click it to join without leaving Slack.
## Workflow Action
### Create GoToMeeting
Creates a GoToMeeting session for the incident and optionally shares the link to Slack or the incident timeline.
The meeting title. Supports [Liquid variables](/liquid/incident-variables) — for example, `{{ incident.title }}`. Maximum 200 characters.
The audio conferencing mode for the meeting:
* `ptsn` — PSTN dial-in number
* `free` — Free conference call number
* `hybrid` — Both PSTN and VoIP
* `voip` — VoIP only
When enabled, GoToMeeting will require a password to join the session.
Attaches the meeting link to the incident timeline as a logged event.
One or more Slack channels to share the meeting link to. Use `{{ incident.slack_channel_id }}` to target the incident's dedicated channel.
## Uninstall
To remove the GoToMeeting integration:
1. Go to **Configuration → Integrations** and find **GoToMeeting**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
## Frequently Asked Questions
No. Rootly stores one GoToMeeting session per incident — once a meeting has been created for an incident, subsequent **Create GoToMeeting** workflow actions will be skipped. If you need a new session, disconnect and reconnect the integration or create the meeting manually.
Choose **hybrid** if your team has a mix of office and remote participants — it provides both dial-in and VoIP options. Use **voip** for fully remote teams to avoid dial-in costs.
Rootly automatically refreshes the OAuth token in the background. If refresh fails (for example, the connected account is deactivated), the integration will stop working. Use a service account to minimize this risk.
Any of the three GoTo product scopes (GoToMeeting, GoToWebinar, GoToTraining) are supported. The workflow action creates a standard GoToMeeting session regardless of which scope is enabled.
# Google Calendar
Source: https://docs.rootly.com/integrations/google-calendar
Connect Google Calendar to Rootly to schedule incident meetings from workflows, and import a calendar as a holiday feed for on-call schedules.
The Google Calendar integration connects Rootly with your Google Workspace so incident workflows can schedule calendar events, attach video meetings, and invite responders automatically. A Google Calendar can also be imported as a holiday feed to overlay company holidays on your on-call schedules.
With the Google Calendar integration, you can:
* Create Google Calendar events from incident workflows, with a video meeting attached
* Invite responders drawn from the incident's roles and teams
* Update an existing event's time, attendees, or duration as an incident evolves
* Import a calendar's iCal feed to overlay holidays on Rootly on-call schedules
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A Google Workspace account, or a Google Cloud project if you are using a service account
Rootly recommends installing with a **service account** so the integration does not break if the installing user leaves your organization.
## Installation
Locate **Google Calendar** on the [integrations catalog](https://rootly.com/account/integrations) and click **Setup**.
You will be prompted to choose a connection method: OAuth credentials, or JSON file credentials.
Use this method for non-GCP service accounts. It is the simplest approach.
To install as a shared identity rather than a personal one:
1. Create a Google account with a generic email (for example, `acme_rootly@company.com`).
2. Log into that Google account in your browser.
3. Add `acme_rootly@company.com` as a member of your Rootly organization.
4. Follow the steps below while signed in as that account.
Click **Setup** to begin. You will be prompted to select a Google account.
After selecting an account, grant Rootly permission to integrate with it.
Select **Allow**. You are redirected back to Rootly and the installation is complete.
Use this method for GCP service accounts. See the [Google service account overview](https://cloud.google.com/iam/docs/service-account-overview) for background.
In the [Google Cloud console](https://console.cloud.google.com/), open **IAM & Admin**.
Navigate to **Service Accounts** and click **Create Service Account**.
Fill in the service account details — the Service Account ID is generated automatically. Click **Done**.
Open the **Keys** tab and click **Add a Key**.
Create a key and download it in JSON format.
Return to the Rootly integration page and upload the JSON file.
In [admin.google.com](https://admin.google.com/), go to **Security > API Controls > Domain Wide Delegation**. Select your service account and add these scopes:
```text theme={null}
https://www.googleapis.com/auth/calendar.readonly
https://www.googleapis.com/auth/calendar.events
```
In [admin.google.com](https://admin.google.com/), go to **Google Workspace > Core Google Workspace** and select **Google Calendar**.
Configure external sharing options for the primary calendar:
Configure internal sharing options for the primary calendar:
Open your own calendar's settings and share it with the service account email, granting **Make changes to events** permission.
In the Rootly integration, enter the email of the user you want to schedule meetings as, then click **Save**.
## Workflow Actions
The Google Calendar integration uses workflows to schedule calendar events automatically. If you are unfamiliar with how workflows function, visit the [Workflows](/workflows/workflows) documentation first.
Use the [Incident Variable Explorer](https://rootly.com/account/help/liquid-explorer) to preview what Liquid variables return for your incidents.
### Create a Google Calendar Event
Schedules a new calendar event, optionally with a video meeting attached.
| Field | Description | Required |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Summary** | Event title. Defaults to `{{ incident.title }}`. Supports Liquid | Yes |
| **Description** | Event description. Supports Liquid | |
| **Attendees** | Attendee email addresses, entered directly or drawn from the incident | |
| **Conference Type** | Video meeting to attach to the event. Select **Hangout** to attach a Google Meet | |
| **Time Zone** | Time zone used to schedule the event | |
| **Days Until Meeting** | Number of days from now until the event | |
| **Meeting Duration** | Length of the event. Supports Liquid | |
| **Time of Meeting** | Start time, interpreted in the selected **Time Zone** | |
| **Slack Channels** | Slack channels to post the result to. Use `{{ incident.slack_channel_id }}` or `{{ parent_incident.slack_channel_id }}` | |
### Update a Google Calendar Event
Updates an existing calendar event. Only the fields you specify are changed; unspecified fields keep their existing values.
| Field | Description | Required |
| -------------------- | --------------------------------------------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Event** | Calendar event ID to update. Defaults to `{{ incident.google_calendar_event_id }}`. Supports Liquid | Yes |
| **Summary** | Updated event title. Supports Liquid | |
| **Description** | Updated event description. Supports Liquid | |
| **Conference Type** | Video meeting to attach to the event | |
| **Attendees** | Updated attendees. Overwrites the existing list only when **Replace attendees** is checked | |
| **Adjustment** | Type of date-and-time adjustment to apply, if any | |
| **Adjustment Days** | Number of days by which to adjust the event, if any | |
| **Meeting Duration** | Updated event length. Supports Liquid | |
| **Time of Meeting** | Updated start time, interpreted in the selected **Time Zone** | |
| **Slack Channels** | Slack channels to post the result to | |
## Importing a Google Calendar as a PTO Feed
The OAuth integration above is for event-based workflow actions. If your goal is instead to **overlay** holidays on your Rootly on-call schedules — for example, a shared team calendar tracking company holidays — no OAuth is required. Rootly accepts a Google Calendar's iCal URL as a holiday calendar feed.
Use the calendar's **Secret address in iCal format** for any calendar containing HR or PTO data. The secret address works without making the calendar publicly readable on the internet. Reserve the **Public address** for calendars that are already meant to be shareable, such as a company-wide holidays calendar.
In Google Calendar, hover over the calendar in the left sidebar, click the overflow menu, and choose **Settings and sharing**.
Scroll to the **Integrate calendar** section and copy the URL that fits your use case:
* For private or sensitive calendars, copy the URL under **Secret address in iCal format**. Treat this URL as a credential — anyone with it can subscribe to the calendar.
* For calendars already intended to be public (like company holidays), copy the URL under **Public address in iCal format**. This option requires the calendar to be set as public under **Access permissions**.
Do not use the **Embed code** or the **Public URL to this calendar**. Those are for embedding the calendar on a webpage and will not work as a feed. Only the iCal URLs end in `.ics`.
In the Rootly dashboard, go to **On-Call → Schedules**, open the **Holiday calendars** dropdown, and select **Add a holiday calendar**. Paste the iCal URL, give the calendar a descriptive name, and save.
For the full behavior of holiday calendars in Rootly — conflict highlighting, recurring events, multi-region setups — see [Adding a Holiday Calendar](/on-call/holiday-calendar).
## Uninstall
To remove the Google Calendar integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related Resources
* [Workflows](/workflows/workflows)
* [Adding a Holiday Calendar](/on-call/holiday-calendar)
* [Integrations overview](/integrations/overview)
# Google Chat
Source: https://docs.rootly.com/integrations/google-chat/overview
Connect Google Chat to Rootly to create incident spaces, run slash commands, and drive incident workflows from chat.
**Closed Beta** — The Google Chat integration is currently in closed beta. Contact [support@rootly.com](mailto:support@rootly.com) to request access.
Rootly's Google Chat integration automates incident communication, on-call management, and alerting. When an incident starts, Rootly creates a dedicated Google Chat space, invites responders, and posts real-time incident overview cards. Responders can manage incidents, respond to alerts, and check on-call schedules without leaving Google Chat.
Automatically create dedicated Google Chat spaces for each incident with responders invited
Page responders via Google Chat, respond to alerts with action buttons, and check on-call schedules
Declare incidents, create alerts, check on-call, and manage shifts with `/rootly` commands
React to messages to add timeline events, follow-ups, or tasks to the incident
Get notified of role assignments, action items, shift changes, and meeting recordings
Control which events trigger Google Chat notifications using workflow conditions
***
## How It Works
Create a service account, configure domain-wide delegation, and upload the key to Rootly (recommended). Or connect via OAuth for a quick evaluation.
Set up workflows to automatically create spaces, send messages, or post cards when incidents occur.
Add Google Chat spaces as escalation policy targets to page responders directly in chat.
***
## Installation
There are two ways to connect Google Chat to Rootly. The recommended path is the **Google Workspace Marketplace**, which handles all configuration automatically. For organizations that need **domain-wide delegation**, a service account can be configured as an advanced option.
## Google Workspace Marketplace
This is the recommended setup. Installing from the Marketplace requires no Google Cloud project, no service account, and no manual scope configuration.
### Prerequisites
**Before you start:**
* Rootly account with Admin permissions
* Google Workspace admin access to install Marketplace apps
***
### Step 1: Install from the Marketplace
Go to the [Rootly Google Workspace Marketplace listing](https://workspace.google.com/marketplace/app/rootly/1046293539231) and click **Install**.
Review the requested permissions and click **Allow** to complete the installation for your Google Workspace domain.
***
### Step 2: Add Rootly to a Space
Navigate to the Google Chat space where you want to use Rootly, or create a new one.
Add the Rootly bot to the space. You can do this by typing `@Rootly` or adding it from the space's member list.
***
### Step 3: Connect to Your Team
In the space, type `/rootly` and press Enter.
A dialog will appear. Select the Rootly team you want to connect this space to and confirm.
Google Chat is now connected to Rootly via the Marketplace. No additional configuration is needed.
## Service Account + Domain-Wide Delegation
This is an advanced setup for organizations that require domain-wide delegation. A Google Cloud service account with domain-wide delegation gives Rootly access to Google Chat capabilities through a delegated user identity.
Most organizations do not need this setup. The [Marketplace install](#google-workspace-marketplace) provides full functionality without a service account.
### Prerequisites
**Before you start:**
* Rootly account with Admin permissions
* A Google Cloud project where you can create a service account
* Google Workspace admin access to configure domain-wide delegation
* A delegated user email in your workspace (for example, `rootly-bot@company.com`) for the service account to impersonate
***
### Step 1: Create a Service Account
In your Google Cloud project, go to **IAM & Admin > Service Accounts** and click **Create Service Account**.
Give it a descriptive name (for example, `rootly-chat-bot`) and click **Create and Continue**.
Click on the newly created service account, go to the **Keys** tab, and click **Add Key > Create new key**. Select **JSON** and download the key file.
Store this key file securely. You'll upload it to Rootly in the next step and should not commit it to version control.
***
### Step 2: Configure Domain-Wide Delegation
Domain-wide delegation allows the service account to impersonate a user in your workspace, which is required for creating spaces and managing members.
In your service account details, find the **Unique ID** (also called OAuth 2 Client ID). You'll need this for the admin console.
Go to [admin.google.com](https://admin.google.com) and navigate to **Security > Access and data control > API Controls > Domain-wide delegation**.
Click **Add new** and enter:
* **Client ID**: The service account's OAuth 2 Client ID
* **OAuth Scopes** (comma-separated):
```text theme={null}
https://www.googleapis.com/auth/chat.spaces.create,https://www.googleapis.com/auth/chat.spaces,https://www.googleapis.com/auth/chat.memberships,https://www.googleapis.com/auth/chat.memberships.app,https://www.googleapis.com/auth/chat.messages.create,https://www.googleapis.com/auth/chat.messages
```
The delegated user email should be a dedicated workspace user (for example, `rootly-bot@company.com`), not a personal account. This ensures the integration stays active if team members leave.
***
### Step 3: Connect in Rootly
In Rootly, go to **Configuration > Integrations** and search for **Google Chat**.
Click **Setup** on the Google Chat integration. Upload the JSON key file you downloaded earlier.
Enter the email of the workspace user the service account will impersonate (for example, `rootly-bot@company.com`).
Click **Connect**. Rootly will verify the credentials and establish the connection.
Google Chat is now connected to Rootly with domain-wide delegation.
### Required Scopes
| Scope | Purpose |
| ---------------------- | -------------------------------- |
| `chat.spaces.create` | Create dedicated incident spaces |
| `chat.spaces` | Read and manage space settings |
| `chat.memberships` | Manage space members |
| `chat.memberships.app` | Add the bot to spaces |
| `chat.messages.create` | Send messages to spaces |
| `chat.messages` | Read and manage messages |
***
## After Connecting
Once connected (via either method), Rootly automatically creates default workflows:
* **Auto Create Incident Google Chat Space** — Creates a dedicated space when an incident starts (enabled by default)
* **Default Announcement Space** — Posts to a shared announcement space (disabled until you configure a target space)
You can customize these workflows or create new ones from **Workflows** in the Rootly dashboard.
### Configure Settings
Go to **Configuration > Integrations > Google Chat > Settings** to configure:
* **Incident space** — Toggle auto-creation of incident spaces and announcements
* **Emoji shortcuts** — Customize which emoji reactions trigger timeline events, follow-ups, or tasks
* **Interactions** — Enable or disable slash command responses and link previews
### Remove Service Account Credentials
If you previously configured a service account and no longer need it (for example, after switching to the Marketplace install), you can remove the service account credentials from **Configuration > Integrations > Google Chat > Edit**.
***
## Authentication Model
Google Chat uses a hybrid authentication model where different operations require different identities:
| Operation | Auth Method | Notes |
| -------------------- | -------------------------------------- | ------------------------------------------- |
| Create/delete spaces | Marketplace app or Delegated user (SA) | Marketplace handles this automatically |
| Add bot to space | Marketplace app or Delegated user (SA) | Uses `chat.memberships.app` scope with SA |
| Send Cards v2 | Bot identity | Google requires bot identity for rich cards |
| Send text messages | Marketplace app or Delegated user (SA) | Both methods work |
| Manage members | Marketplace app or Delegated user (SA) | SA requires delegation scopes |
| Webhook responses | Bot identity | Synchronous responses to Google |
***
## Workflows
Auto-create Google Chat spaces at incident start using built-in settings
Build workflows with triggers, conditions, and multiple Google Chat actions
***
### Available Actions
| Action | What It Does |
| ---------------------------------------- | ------------------------------------------------------------------------------------ |
| **Create Google Chat Space** | Creates a dedicated space for the incident, adds the bot, and posts an overview card |
| **Send Google Chat Message** | Sends a text message to one or more spaces (with optional threading) |
| **Send Google Chat Attachments** | Sends Cards v2 to spaces (requires service account) |
| **Invite to Google Chat Space** | Invites users to an incident space by email |
| **Rename Google Chat Space** | Changes the display name of a space |
| **Update Google Chat Space Description** | Updates the description of a space |
| **Change Google Chat Space Privacy** | Switches a space between private and discoverable |
| **Archive Google Chat Spaces** | Deletes incident spaces when they're no longer needed |
***
### Create a Workflow
Go to **Rootly > Workflows > Create Workflow**.
Select the workflow type that matches your use case (for example, Incident, Retrospective, or Pulse).
Triggers define when this workflow runs.
| Trigger | When It Fires |
| ------------------------------- | ----------------------------------------- |
| **Incident Created** | New incident opens |
| **Incident Updated** | Severity, status, or fields change |
| **Incident Status Changed** | Incident moves to a specific status |
| **Incident Commander Assigned** | Someone takes ownership |
| **Incident Resolved** | Incident is resolved |
| **Google Chat Space Created** | The incident's Google Chat space is ready |
| **Manual Trigger** | Run on demand from the UI |
Conditions filter when the workflow should run after it's been triggered — keeping notifications focused on the incidents that matter.
Examples:
* Only for SEV-1 or SEV-2 incidents
* Only for specific teams or services
* Only for production environments
Click **Add Action** and search for **Google Chat** to see all available actions.
***
### Action Reference
Creates a dedicated Google Chat space for the incident. The bot is automatically added to the space and posts an incident overview card showing title, status, severity, start time, summary, and a "See in Rootly" button.
This is typically the first action in an incident workflow — it gives responders a central place to coordinate.
The space name. Supports Liquid syntax (for example, `{{ incident.title }}`). Automatically formatted to meet Google Chat's display name requirements.
An optional description for the space. Supports Liquid syntax.
Controls space discoverability:
* **Empty** (default) — Space is private, only invited members can see it
* **`audiences/default`** — Space is discoverable by everyone in your Google Workspace organization
Discoverable spaces cannot be created for private incidents.
If the incident already has a Google Chat space, this action skips creation to avoid duplicates.
The overview card requires the **service account** connection. It is sent using bot identity automatically after space creation.
Sends a text message to one or more Google Chat spaces. Use Liquid variables to include dynamic incident details.
The space(s) to post to. Supports Liquid syntax.
The message content. Supports Liquid variables.
```liquid theme={null}
*Incident Update*
*Title:* {{ incident.title }}
*Severity:* {{ incident.severity }}
*Status:* {{ incident.status }}
*Commander:* {{ incident.commander.name | default: "Unassigned" }}
{{ incident.summary }}
```
An optional thread key to group messages into a thread within the space. Messages with the same thread key appear as replies in the same thread. Supports Liquid syntax.
If the message text is empty, the action will be skipped.
**Common triggers:** Incident Created, Incident Updated, Status Changed
Sends Cards v2 to one or more Google Chat spaces. Use this to send richly formatted, interactive content such as structured incident summaries with action buttons.
The space(s) to send the cards to. Supports Liquid syntax.
A JSON payload defining the Cards v2 content. Supports Liquid syntax. Follows the [Google Chat Cards v2 schema](https://developers.google.com/workspace/chat/api/reference/rest/v1/cards).
Cards v2 require the **service account** connection. OAuth connections cannot send cards — Google restricts card messages to bot identity.
Invites users to the incident's Google Chat space by email. Use this to automatically add on-call responders when they're assigned a role.
The space to invite users to. Supports Liquid syntax.
Comma-separated list of email addresses to invite. Supports Liquid syntax.
**Common triggers:** Incident Created, Incident Commander Assigned
Renames an existing Google Chat space. Use this to reflect status changes — for example, prefixing resolved incidents with `[RESOLVED]`.
The space to rename. Supports Liquid syntax.
The new display name. Supports Liquid syntax.
```liquid theme={null}
[RESOLVED] {{ incident.title }}
```
**Common trigger:** Incident Resolved
Updates the description of a Google Chat space. Use this to keep the space description in sync with the incident summary as it evolves.
The space to update. Supports Liquid syntax.
The new description. Supports Liquid syntax.
**Common trigger:** Incident Updated
Switches a space between private and discoverable. Use this to open up a space to the broader organization during a major incident, or lock it down afterward.
The space to update. Supports Liquid syntax.
* **Empty** — Makes the space private (invited members only)
* **`audiences/default`** — Makes the space discoverable organization-wide
Setting a space to discoverable will also update the incident's private flag. You cannot make a private incident's space discoverable — change the incident visibility first.
Deletes the incident's Google Chat space when it's no longer needed. Keeps your workspace clean after incidents are resolved.
The space(s) to delete. Supports Liquid syntax.
Google Chat does not support archiving spaces — this action permanently deletes the space. Ensure your retention requirements are met before using this action.
**Common trigger:** Incident Status Changed to "Closed"
***
## Slash Commands
When the Rootly bot is added to a Google Chat space, team members can use slash commands to manage incidents, alerts, and on-call directly from chat.
### Incident Commands
| Command | Description |
| ------------------------- | -------------------------------------------- |
| `/rootly declare` | Declare a new incident (opens a form dialog) |
| `/rootly update` | Update incident details |
| `/rootly status` | View current incident status |
| `/rootly resolve` | Resolve the incident |
| `/rootly mitigate` | Mark incident as mitigated |
| `/rootly cancel` | Cancel the incident |
| `/rootly ack` | Acknowledge the incident |
| `/rootly note ` | Add a timeline event |
| `/rootly summary ` | Update incident summary |
| `/rootly severity ` | Set incident severity |
| `/rootly list` | List active incidents |
### On-Call & Alerting Commands
| Command | Description |
| ------------------ | ------------------------------------------------------------ |
| `/rootly alert` | Create a new alert and page responders (opens a form dialog) |
| `/rootly oncall` | Show who's currently on-call across your schedules |
| `/rootly escalate` | Escalate — create an alert and page the escalation policy |
| `/rootly override` | Create a shift override (opens a form dialog) |
### Utility Commands
| Command | Description |
| -------------- | --------------------------- |
| `/rootly help` | Show all available commands |
Slash commands work with both `/rootly` and `/incident` prefixes.
The `declare`, `update`, `alert`, `escalate`, and `override` commands open dynamic form dialogs with the same configurable fields available in Slack and the web UI, including custom fields.
***
## Emoji Reactions
Rootly can convert emoji reactions on messages in incident spaces into timeline events, follow-ups, or tasks. This lets responders quickly capture important information without leaving the conversation.
| Default Emoji | Action |
| ----------------- | ------------------------------------ |
| Pin or star emoji | Adds the message as a timeline event |
| Clipboard emoji | Creates a follow-up action item |
| Checkmark emoji | Creates a task action item |
Rootly responds with a confirmation emoji (for example, ✅) when it processes a reaction.
Customize which emojis trigger each action in **Configuration > Integrations > Google Chat > Settings**.
***
## On-Call & Alerting
Google Chat spaces can be used as escalation policy targets, making Google Chat a first-class on-call surface alongside Slack.
### Escalation Policy Targets
Add Google Chat spaces as notification targets on escalation policy levels. When an alert fires, Rootly posts an alert card to the configured space with action buttons.
To configure:
1. Go to **On-Call > Escalation Policies**
2. Edit or create a policy level
3. Select a Google Chat space as a notification target
### Alert Cards
When an alert is sent to a Google Chat space, Rootly posts an interactive card with action buttons that change based on alert status:
| Button | Action |
| ----------------- | --------------------------------- |
| **Acknowledge** | Acknowledge the alert |
| **Resolve** | Resolve the alert |
| **Escalate** | Escalate to the next policy level |
| **Mark as Noise** | Mark the alert as noise |
| **Snooze** | Snooze the alert temporarily |
Cards update automatically as the alert status changes — buttons reflect the current available actions.
### Shift Notifications
When configured, Rootly sends notifications to Google Chat spaces for on-call events:
* **Shift start** — Notifies when an on-call shift begins
* **Shift override** — Notifies when someone takes over or creates an override
* **Coverage request** — Posts a card with a "Take the Shift" button when someone requests coverage
Enable shift notifications in **On-Call > Schedules > Edit > Notifications**.
### Additional Alert Spaces
Configure extra Google Chat spaces to receive alert broadcasts in **Configuration > Integrations > Google Chat > Settings**. This lets you send alerts to shared spaces in addition to the escalation policy targets.
***
## Lifecycle Notifications
When connected via service account, Rootly automatically posts notifications to incident spaces for key events:
* **Role assigned** — When a responder is assigned a role on the incident
* **Action item added** — When a follow-up or task is created
* **Meeting recording** — When a recording session starts or completes (includes duration and transcript link)
* **Retrospective published** — When the post-incident review is published
Each notification includes a "View in Rootly" button for quick access.
***
## Liquid Variables
Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test variables with real incident data.
### Incident Variables
| Variable | Description |
| -------------------------------- | ------------------------------------ |
| `{{ incident.title }}` | Incident title |
| `{{ incident.summary }}` | Incident summary |
| `{{ incident.severity }}` | Severity level (for example, "SEV1") |
| `{{ incident.status }}` | Current status |
| `{{ incident.started_at }}` | When the incident started |
| `{{ incident.commander.name }}` | Incident commander name |
| `{{ incident.commander.email }}` | Incident commander email |
| `{{ incident.url }}` | Link to the incident in Rootly |
### Google Chat Variables
| Variable | Description |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `{{ incident.google_chat_space_id }}` | ID of the incident's Google Chat space |
| `{{ incident.google_chat_space_name }}` | Full resource name of the space (for example, `spaces/AAAA...`) |
| `{{ incident.google_chat_space_url }}` | URL to the Google Chat space |
| `{{ incident.google_chat_space_short_url }}` | Shortened URL to the space |
| `{{ incident.google_chat_space_archived }}` | Whether the space has been deleted (Google Chat does not support archiving — this flag indicates the space was removed via the Archive action) |
| `{{ incident.google_chat_space_domain_id }}` | Google Workspace domain ID of the space |
## Troubleshooting
Workflows run successfully but no Google Chat spaces appear.
**Solutions:**
* Confirm the Rootly bot has been added to the space
* If using a service account, verify domain-wide delegation is configured with the correct Client ID and all required scopes
* If using a service account, confirm the delegated user email exists as an active user in your Google Workspace
* Check workflow run logs for errors: **Workflows > Your Workflow > ... > View Runs**
Messages appear as plain text instead of rich Cards v2.
**Solutions:**
* Confirm the Rootly bot has been added to the target space
* Check workflow run logs for specific error messages
After installing from the Marketplace, the Rootly bot is not available in Google Chat.
**Solutions:**
* Verify the Marketplace app was approved by a Google Workspace admin
* It may take a few minutes for the app to propagate across your workspace
* Try refreshing Google Chat or signing out and back in
* Check your Google Workspace admin console under **Apps > Google Workspace Marketplace apps** to confirm the installation
Typing `/rootly` or `/incident` in Google Chat does nothing.
**Solutions:**
* Confirm the Rootly bot has been added to the space where you're running commands
* Verify the integration is active in **Configuration > Integrations > Google Chat**
* If using a service account, check that domain-wide delegation is correctly configured
Service account operations fail with permission errors.
**Solutions:**
* Double-check the Client ID in the admin console matches the service account's OAuth 2 Client ID (not the service account email)
* Ensure all six scopes are entered exactly as shown, comma-separated with no spaces
* Domain-wide delegation changes can take up to 24 hours to propagate — wait and retry
* Verify the delegated user email is a valid, active user in the same Google Workspace domain
## Uninstall
To remove the Google Chat integration from Rootly:
1. Go to **Configuration > Integrations** and find **Google Chat**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
If you used the service account setup, disconnecting from Rootly does not remove the service account or domain-wide delegation from your Google Cloud project. To fully uninstall, revoke the domain-wide delegation in the Google Workspace admin console and delete the service account if no longer needed.
***
# Google Cloud Monitoring
Source: https://docs.rootly.com/integrations/google-cloud-monitoring
Forward alerts from Google Cloud Monitoring to Rootly for escalation, Slack routing, on-call paging, and automated incident response across GCP workloads.
## Overview
Google Cloud Monitoring can be configured as an alert source that sends webhook notifications to Rootly whenever an alert fires in your GCP environment. Once alerts arrive in Rootly, they can trigger incident workflows, page on-call responders, or route notifications to Slack.
## Before You Begin
Rootly recommends performing the installation with a **service account** to ensure the integration does not break if the installing user leaves the company. You will need a GCP account with access to Google Cloud Monitoring and a Rootly account with Admin permissions.
## Setting Up the Integration
To integrate Google Cloud Monitoring with Rootly, you will create a webhook notification channel in GCP that forwards alert notifications to Rootly. These alerts can then be used in Rootly for automation and incident response.
Follow these steps to set up the integration:
## Step 1: Choose Your Webhook Endpoint
You will first retrieve the appropriate Rootly webhook endpoint URL where GCP will send its alerts. Rootly provides two types of webhook endpoints: **Non-paging** and **Paging**. Depending on how you want to handle alerts from GCP, you can choose either type. Below is a summary of both options:
| Endpoint Type | Behavior | URL |
| -------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **Non-paging** | Alert appears in Rootly for visibility and automation without paging anyone | `https://webhooks.rootly.com/webhooks/incoming/google_cloud_webhooks` |
| **Paging** | Alert is received in Rootly **and** pages a specific resource you specify | `https://webhooks.rootly.com/webhooks/incoming/google_cloud_webhooks/notify//` |
For paging URLs, replace `` and `` with the resource you want to page:
| Parameter | Allowed values | Example |
| --------- | ----------------------------------------------------------------------- | ----------- |
| `TYPE` | `User`, `Group`, `EscalationPolicy`, `Service` | `Service` |
| `ID` | The unique ID of the resource in Rootly — found by editing the resource | `svc_12345` |
Copy the URL you need — you will use it in [Step 3](#step-3-create-the-webhook-notification-channel-in-gcp).
## Step 2: Retrieve Your Auth Password
Google Cloud Monitoring authenticates to Rootly using HTTP Basic Auth. The username is always `rootly` — the password is an organization-specific secret you retrieve from Rootly.
Go to **Alerts → Sources** in Rootly and click **Add Source**, then select **Google Cloud Platform**.

Provide an **Alert Source Name** (for example, `GCP – Production Alerts`) and select an **Owning Team**, then click **Add Source**.

On the **Google Cloud Setup** page, find **Step 5** and copy the **Auth Password**.

This password authenticates GCP to Rootly. Keep it secure and do not share it publicly.
## Step 3: Create the Webhook Notification Channel in GCP
Now that you have:
* The **Rootly Webhook URL** from [Step 1](#step-1-choose-your-webhook-endpoint)
* The **Auth Password** from [Step 2](#step-2-retrieve-your-auth-password)
You can now use these values to create a Webhook Notification Channel in Google Cloud Monitoring.
In the Google Cloud Console, go to **Monitoring → Alerting**.

Click **Edit Notification Channels** at the top of the Alerting page.

Scroll to the **Webhooks** section and click **Add New**.

Fill in the form using the values gathered in the previous steps:
| Field | Value |
| ----------------------- | -------------------------------------------------------------------------- |
| **Endpoint URL** | The Rootly webhook URL from [Step 1](#step-1-choose-your-webhook-endpoint) |
| **Display Name** | A descriptive name, for example, `Rootly – Production Alerts` |
| **Use HTTP Basic Auth** | Enabled |
| **Username** | `rootly` |
| **Password** | The Auth Password from [Step 2](#step-2-retrieve-your-auth-password) |
Click **Test Connection** to verify GCP can reach Rootly.

* If successful: click **Save** to create the notification channel.
* If unsuccessful:
* Verify the URL is correct
* Confirm you used `rootly` as the username
* Re-copy the Auth Password from Rootly
Your integration is now active. Alerts from Google Cloud Monitoring will be delivered to Rootly and routed based on your paging or automation configuration.
## Step 4: Verify the Test Alert in Rootly
After running **Test Connection**, a test notification is sent from GCP to Rootly. Confirm it arrived on the [Alerts page](https://rootly.com/account/alerts) in Rootly.

The GCP test payload differs from real alert payloads. Test with actual alerts in your environment to verify end-to-end functionality before relying on this in production.
```json theme={null}
{
"ID": "d7cdb19e-381e-4b72-8066-8691ac011529",
"rootly": {
"title": "Test Incident",
"description": null,
"alert_source_url": "http://www.example.com"
},
"version": "test",
"incident": {
"url": "http://www.example.com",
"state": "OPEN",
"metric": {
"type": "test.googleapis.com/metric",
"labels": { "example": "label" },
"displayName": "Test Metric"
},
"summary": "Test Incident",
"ended_at": 0,
"metadata": {
"user_labels": { "example": "label" },
"system_labels": { "example": "label" }
},
"resource": {
"type": "example_resource",
"labels": { "example": "label" }
},
"condition": {
"name": "projects/12345/alertPolicies/12345/conditions/12345",
"displayName": "Example condition",
"conditionThreshold": {
"filter": "metric.type=\"test.googleapis.com/metric\" resource.type=\"example_resource\"",
"trigger": { "count": 1 },
"duration": "0s",
"comparison": "COMPARISON_GT",
"thresholdValue": 0.5
}
},
"started_at": 0,
"incident_id": "12345",
"policy_name": "projects/12345/alertPolicies/12345",
"condition_name": "Example condition",
"observed_value": "1.0",
"threshold_value": "0.5",
"documentation": {
"content": "TEST ALERT",
"subject": "ALERT - No severity",
"mime_type": "text/markdown"
}
},
"rootly_alert_status": "open"
}
```
## Frequently Asked Questions
Verify the Endpoint URL is correct and matches your intended alert type (paging or non-paging). Confirm the username is exactly `rootly` (lowercase). Re-copy the Auth Password from **Alerts → Sources → Google Cloud Platform → Configure** in Rootly — passwords can change if the source is recreated.
Confirm the webhook notification channel is attached to an active alerting policy in GCP. Check that the alert policy has fired by reviewing **Monitoring → Alerting → Incidents** in GCP. Verify the webhook URL and credentials in the notification channel settings.
Open the resource (User, Team, Escalation Policy, or Service) in Rootly and click **Edit**. The resource ID appears in the URL or in the edit form. Use this ID in the paging URL path.
## Related resources
* [Prometheus Alertmanager](/integrations/alertmanager)
* [Checkly](/integrations/checkly)
* [Chronosphere](/integrations/chronosphere)
* [Dynatrace](/integrations/dynatrace)
# Google Directory Sync
Source: https://docs.rootly.com/integrations/google-directory-sync
Automatically sync users and groups from Google Workspace to Rootly using the Google Admin Directory API to keep team membership and roles up to date.
## Introduction
Google Directory Sync provides automatic user and group provisioning from Google Workspace into Rootly. Unlike [SCIM](/integrations/scim) (which relies on push events from an identity provider), Google Directory Sync periodically polls the Google Admin Directory API — approximately every 30 minutes — to keep your Rootly organization in sync with your Google Workspace directory.
Google Directory Sync and SCIM are **mutually exclusive**. You cannot enable both on the same organization. If SCIM provisioning is currently active on your team, you must disable it before enabling Google Directory Sync.
With Google Directory Sync, Rootly automatically:
* **Provisions users** — New Google Workspace users are added as Rootly members with first name, last name, email, phone numbers, profile photo, and timezone
* **Updates users** — Name and contact changes in Google Workspace are reflected in Rootly
* **Deprovisions users** — Users suspended or deleted in Google Workspace are soft-deleted in Rootly
* **Syncs groups** — Google Groups are mapped to Rootly Groups, with membership kept up to date
* **Assigns roles** — Rootly roles and on-call roles are assigned based on Google Group membership and Google role (Owner, Manager, Member)
* **Protects against mass deletion** — A configurable safeguard (default: 20%) prevents accidental bulk deprovisioning if the API returns partial results
## Before You Begin
Before setting up Google Directory Sync, make sure you have:
* A Google Workspace account with **super admin** access
* One of the following authentication methods:
* **OAuth** — Recommended for smaller organizations. Uses a familiar Google sign-in flow.
* **Service account with domain-wide delegation** — Recommended for enterprises with strict admin policies.
## Installation
Navigate to **Integrations** in your Rootly dashboard, find **Google Directory Sync**, and click **Setup**.
### Option A: OAuth Authentication
Click **Sign in with Google** and authenticate with a Google Workspace **super admin** account. Grant the following permissions when prompted:
* `admin.directory.user.readonly`
* `admin.directory.group.readonly`
* `admin.directory.group.member.readonly`
You'll be redirected back to Rootly with the integration active. The first sync will run within 30 minutes, or you can click **Sync Now** to trigger it immediately.
### Option B: Service Account Authentication
Use this method if your organization requires service accounts or restricts OAuth consent flows.
In [Google Cloud Console](https://console.cloud.google.com/), go to **IAM & Admin > Service Accounts**. Click **Create Service Account**, name it (for example, `rootly-directory-sync`), and click **Done**. Then open the service account, go to **Keys > Add Key > Create new key > JSON**, and download the key file.
In the service account details page, expand **Advanced Settings** and copy the **Client ID**. In [Google Admin Console](https://admin.google.com/), navigate to **Security > Access and data control > API controls > Domain-wide delegation**, click **Add new**, and enter the Client ID with the following scopes:
```text theme={null}
https://www.googleapis.com/auth/admin.directory.user.readonly
https://www.googleapis.com/auth/admin.directory.group.readonly
https://www.googleapis.com/auth/admin.directory.group.member.readonly
```
Click **Authorize**.
In Rootly, select **Service Account** as the authentication method, upload the JSON key file, and enter the **impersonation email** — the email address of a Google Workspace super admin.
The impersonation email must belong to an **active super admin**. The service account technically impersonates this user when calling the Google Directory API. If this user is suspended or deleted, syncing will fail. Use a dedicated service account admin that won't be deactivated.
You must also provide the **domain** — your Google Workspace primary domain (for example, `yourcompany.com`). Click **Save** to validate the connection.
## What Gets Synced
### User Field Mappings
When Rootly provisions or updates a user, it maps the following fields from the Google Directory:
| Google Field | Rootly Field | Notes |
| --------------------- | ----------------- | ------------------------------------------------------------------ |
| `primary_email` | `user.email` | Used for matching — case-insensitive |
| `name.given_name` | `user.first_name` | |
| `name.family_name` | `user.last_name` | |
| `phones[*].value` | Phone numbers | Normalized with US as default country code; all marked as verified |
| `thumbnail_photo_url` | Profile photo | Downloaded and attached; skipped if user already has an avatar |
| N/A | Timezone | Set from the team's timezone for newly created users |
| N/A | Membership role | Set to the team's default SSO role on first provision |
| N/A | On-call role | Set to the team's default SSO on-call role on first provision |
New users provisioned by Google Directory Sync receive the organization's configured **default SSO role** and **default SSO on-call role**. You can adjust these under your team's SSO settings.
### User Deprovisioning
When a Google Workspace user is suspended, archived, or deleted, their Rootly membership is soft-deleted. If the user has no other Rootly team memberships, the user record itself is also soft-deleted. This is reversible — if the user is reactivated in Google Workspace, they will be re-provisioned on the next sync cycle.
## Configuring Group Sync
Navigate to **Integrations > Google Directory Sync** and click the **Groups** tab.
Select one of two modes:
* **Sync all groups** — All Google Groups in your directory are automatically mapped to Rootly Groups. Mappings are kept up to date as groups are added or removed in Google Workspace.
* **Sync selected groups** — Only the groups you explicitly select are synced. Use the search box to find groups by name.
For each synced group, you can configure how Google Group roles map to Rootly group admin status:
* **Map Owners as admins** (default: on) — Google group OWNER role → Rootly group admin
* **Map Managers as admins** (default: on) — Google group MANAGER role → Rootly group admin
* Google group MEMBER role always maps to a regular group member
You can also assign a **Rootly Role** and **On-Call Role** to be applied to all members of a specific group.
When using "sync all" mode, Rootly automatically creates group mappings for every Google Group in your directory and removes mappings for groups that no longer exist. When a Google Group is renamed, the linked Rootly Group name is updated to match.
Group members are resolved with nested group flattening — members of sub-groups are included. If a user appears via multiple paths with different roles, the highest role takes precedence (Owner > Manager > Member).
## Sync Status & Monitoring
The **Sync** tab shows the current status for both user and group sync, including last sync time, counts of users created/updated/deprovisioned, and any per-user or per-group errors.
Click **Sync Now** to trigger an immediate sync without waiting for the next scheduled run. Rootly prevents concurrent sync executions — if a sync is already running, a new one will not start.
Each sync produces a log entry with:
* Start and completion timestamps
* Counts: users created, updated, deprovisioned; group members added, updated, removed
* Per-item error details for any failures (individual failures do not abort the overall sync)
## Mass Deletion Safeguard
Rootly includes a configurable safeguard to prevent accidental bulk deprovisioning. By default, if a single sync cycle would deprovision more than **20%** of your current Rootly members, or remove more than 20% of a group's members, the deletions are skipped and logged as errors rather than executed.
All sync operations are logged and visible under the sync history section. Each log entry includes:
* Timestamp
* Operation type (user created, user removed, group updated, etc.)
* Affected user or group
* Success or error status
The threshold is always bypassed if the number of deletions is **5 or fewer**, regardless of percentage.
| Issue | Cause | Resolution |
| ---------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| "403 Forbidden" during setup | Impersonation email doesn't have admin privileges | Ensure the impersonation email belongs to a Google Workspace admin |
| Users from secondary domains not syncing | Integration is using `domain` filter instead of `customer` parameter | Contact Rootly support to verify configuration |
| Sync shows 0 users | Service account scopes not properly delegated | Re-check domain-wide delegation settings in Google Admin Console |
| "Mass deletion safeguard triggered" | Google API returned partial results that would remove a large number of users | This is a safety feature. Check Google Workspace status and retry. Contact support if persistent. |
| Phone numbers not syncing | Phone fields not populated in Google Workspace | Ensure users have phone numbers set in their Google Workspace profile |
## Troubleshooting
For service account auth, the impersonation email must belong to an active super admin with Google Directory access. For OAuth, confirm you authenticated with a super admin account. Also verify that domain-wide delegation is configured with all three required scopes in Google Admin Console.
The service account scopes may not be properly delegated. Re-check the domain-wide delegation settings in Google Admin Console and confirm all three required scopes are authorized for the service account's Client ID. Also ensure the `domain` field in Rootly matches your primary Google Workspace domain exactly.
By default the integration queries by primary domain. If your organization has multiple domains, contact Rootly support — the integration may need to be configured to query by `customer` parameter instead of domain.
A single sync cycle attempted to remove more than 20% of your members or group membership, which exceeded the safety threshold. Check Google Workspace API status and verify the sync results are complete. If the removals are intentional (for example, after a large offboarding), contact Rootly support to bypass the threshold for your organization.
Confirm that users have phone numbers set in their Google Workspace profiles. Rootly reads from the `phones` array in the Google Directory response — if this field is empty, no phone number will be synced. Phone numbers are normalized with US as the default country code; numbers in other formats may need to include a country code prefix.
The group list is fetched via the Google Directory API. Confirm the connected account (OAuth user or service account impersonation target) has permission to view groups in your directory. Groups are paginated at 200 per request — all pages are fetched automatically.
For service account auth, syncing stops if the impersonation email belongs to a user who is suspended, deleted, or had their admin role removed. Update the impersonation email in the integration settings to a current active super admin.
If you encounter any issues not covered above, contact Rootly support at [support@rootly.com](mailto:support@rootly.com).
## Related Pages
Push-based provisioning from Okta, Entra, and other SCIM-compatible identity providers.
Configure SAML 2.0 single sign-on — required before enabling SCIM provisioning.
Manage on-call schedules once users and groups are synced from Google Workspace.
# Google Docs
Source: https://docs.rootly.com/integrations/google-docs/overview
Connect Google Docs to Rootly to automatically create incident retrospective documents from templates using Liquid variables.
Rootly's Google Docs integration automates the creation of incident documentation. When an incident resolves or a retrospective begins, Rootly generates a Google Doc from your template and populates it with incident data, timeline events, affected services, and follow-up items — eliminating manual copy-paste work and ensuring consistent documentation across every incident.
You create a template document once with Liquid variables as placeholders. Rootly copies that template for each incident and replaces the variables with actual data. The generated document is saved to your specified Google Drive folder and can be automatically shared with the right people.
## Document Types
Post-incident analysis with timeline, root cause, and follow-up action items
High-level incident overviews for stakeholder communication
Step-by-step response procedures generated on incident creation
Stakeholder communication templates auto-populated with incident data
## Before You Begin
You must be an **Admin or Owner** in Rootly to install integrations.
* **OAuth:** Requires a Google account with access to Google Drive
* **Service Account:** Requires Google Workspace admin access and a Google Cloud project
Choose your setup method based on your environment:
**Best for:** Testing, evaluation, or personal use
Connects your personal Google account. If that account loses access or the person leaves, the integration breaks.
**Best for:** Teams and production environments
Uses a dedicated service account that isn't tied to any individual. More resilient and easier to manage at scale.
## Installation
Setup takes about 2 minutes via OAuth, or about 10 minutes via a service account.
### Quick Setup (OAuth)
OAuth connects your personal Google account in about 2 minutes.
Use the search bar to find **Google Docs** among the available integrations.
Select the OAuth connection method, then choose which Google account to connect.
Google will ask Rootly to access Google Drive and Docs on your behalf. Approve to complete the connection.
You'll be redirected back to Rootly once the authorization completes.
Google Docs is now connected. Next, [create a template and wire it up in a workflow](#creating-documents-from-templates).
### Production Setup (Service Account)
A service account keeps the integration running independent of any individual's Google account. This setup involves creating the account in Google Cloud, uploading its credentials to Rootly, and granting it domain-wide delegation.
If you don't have a project yet, create one first. You'll create the service account inside an existing project.
Click **Create Service Account**, fill in a name and description, then click **Done**.
After creating the account, click on its email address to open its details.
Go to the **Keys** tab → **Add Key** → **Create new key**. Select **JSON** as the key type and click **Create**.
A `.json` file will download automatically — keep it safe, you'll need it in the next step.
In Rootly, go to **Configuration → Integrations → Google Docs → Setup**. Choose the **Service Account** connection method and upload the JSON file you just downloaded.
You should see a success message confirming the integration is active.
The service account needs domain-wide delegation to create documents on behalf of users in your Google Workspace.
In [Google Admin Console](https://admin.google.com), go to **Security → API Controls → Domain-wide Delegation** and click **Add new**. Enter your service account's Client ID (found in GCP Console under the service account details), then add these OAuth scopes:
```text theme={null}
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/drive.appdata
https://www.googleapis.com/auth/documents
```
Click **Authorize**.
Without domain-wide delegation, the service account can't create documents on behalf of users. If you skip this step, document creation will fail silently in workflows.
## Verify the Connection
Once connected, confirm the integration is working before building templates and workflows.
1. The integration should show **Connected** status with your Google account email
2. Try creating a test document in Google Drive to confirm access is working
1. The integration should show **Connected** status with the service account email
2. Confirm domain-wide delegation is active — changes can take up to 15 minutes to propagate
3. Run a test workflow (see [Creating Documents from Templates](#creating-documents-from-templates)) to validate end-to-end
## Creating Documents from Templates
Rootly generates Google Docs from your templates when incidents are created, updated, or resolved. The steps below cover creating a template, sharing it with Rootly, and wiring it up in a workflow.
### Step 1: Create Your Template Document
You create **one template document** with Liquid variable placeholders. Each time the workflow fires, Rootly copies that template and replaces the variables with real incident data — so you never manually copy-paste incident details again.
#### Create the Document
Go to **New → Google Docs**. Give it a clear, descriptive name so it's easy to find later — for example:
* "Rootly Retrospective Template"
* "Executive Summary Template"
* "Incident Runbook Template"
Design your document the way you'd want every generated doc to look. Use Liquid variables anywhere you want incident data to appear. See the template examples below for a starting point.
#### Template Examples
```liquid theme={null}
# Retrospective: {{ incident.title }}
**Date:** {{ incident.started_at | date: "%B %d, %Y" }}
**Severity:** {{ incident.severity }}
**Status:** {{ incident.status }}
## What Happened
{{ incident.summary }}
## Timeline
- Started: {{ incident.started_at | date: "%I:%M %p" }}
- Mitigated: {{ incident.mitigated_at | date: "%I:%M %p" | default: "In progress" }}
- Resolved: {{ incident.resolved_at | date: "%I:%M %p" | default: "In progress" }}
- Total Duration: {{ incident.duration | divided_by: 60 }} minutes
## Services Affected
{{ incident.services | join: ", " }}
## Team
- Created By: {{ incident.creator.name }}
## Communication
Slack Channel: #{{ incident.slack_channel_name }}
```
```liquid theme={null}
# Retrospective: {{ incident.title }}
## Incident Overview
- **ID:** #{{ incident.id }}
- **Date:** {{ incident.started_at | date: "%B %d, %Y" }}
- **Duration:** {{ incident.duration | divided_by: 3600 }} hours {{ incident.duration | modulo: 3600 | divided_by: 60 }} minutes
- **Severity:** {{ incident.severity }}
## Summary
{{ incident.summary }}
## Impact
- **Services:** {{ incident.services | join: ", " }}
- **Groups:** {% for group in incident.groups %}{{ group.name }}{% unless forloop.last %}, {% endunless %}{% endfor %}
- **Environments:** {{ incident.environments | join: ", " }}
## Timeline of Events
{{ incident.timeline_table_markdown }}
## Root Cause Analysis
[To be completed during review]
## What Went Well
- [Add items]
## What Could Be Improved
- [Add items]
## Action Items
[To be added during review]
## Participants
{% for role in incident.roles %}
{%- if role.user -%}
- {{ role.incident_role.name }}: {{ role.user.full_name }}
{%- else -%}
- {{ role.incident_role.name }}: Unassigned
{%- endif -%}
{% endfor %}
```
```liquid theme={null}
# Executive Brief: {{ incident.title }}
**Incident Duration:** {{ incident.duration | divided_by: 60 }} minutes
**Customer Impact:** [To be assessed]
## What Happened
{{ incident.summary }}
## Current Status
{{ incident.status }} as of {{ "now" | date: "%I:%M %p" }}
## Services Affected
{{ incident.services | join: ", " }}
## Next Steps
1. [Add next steps]
2. [Add next steps]
**Created By:** {{ incident.creator.name }}
**Full Report:** {{ incident.url }}
```
#### Common Liquid Variables
For the full variable reference, see [Rootly's Liquid documentation](/liquid/incident-variables). Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test variables against real incident data before committing them to your template.
```liquid theme={null}
# Basic Info
{{ incident.id }} # Incident ID
{{ incident.title }} # Title
{{ incident.summary }} # Description
{{ incident.severity }} # SEV1, SEV2, etc.
{{ incident.status }} # Current status
# Timestamps
{{ incident.started_at }} # Start time
{{ incident.mitigated_at }} # Mitigation time
{{ incident.resolved_at }} # Resolution time
{{ incident.duration }} # Duration in seconds
# People
{{ incident.creator.name }} # Creator name
{{ incident.creator.email }} # Creator email
# Services & Groups
{{ incident.services }} # Array of services
{{ incident.groups }} # Array of groups (teams)
{{ incident.environments }} # Array of environments
# Communication
{{ incident.slack_channel_name }} # Slack channel
{{ incident.url }} # Rootly incident URL
```
### Step 2: Share Your Template with Rootly
Before Rootly can use your template, it needs read access to the document.
Nothing to do here — the Google account you connected in the installation step already has access to documents you own.
You need to explicitly share the template with the service account email.
The email follows the pattern `name@project.iam.gserviceaccount.com`. You can find it in Google Cloud Console under **IAM & Admin → Service Accounts**.
Open your template document, click **Share**, add the service account email, and set the permission to **Editor**.
The permission must be **Editor**, not Viewer or Commenter. Rootly needs write access to copy and populate the template — anything less will cause workflow failures.
### Step 3: Create a Workflow
With the template ready and shared, create a workflow that triggers document generation automatically.
Go to **Rootly → Workflows → Create Workflow**.
Choose the event that should kick off document creation:
* **Incident** — triggers on incident events like creation or resolution
* **Retrospective** — triggers when retrospective status changes
* **Action Item** — for follow-up documentation
Click **Add Action → Google Docs → Create Doc**.
Choose the template document you created in Step 1 from the dropdown.
Set any additional options — a descriptive name, conditions to filter which incidents trigger the workflow, and a destination folder in Google Drive.
Save and toggle the workflow to active. It will fire on the next matching event.
### Configuration Reference
| Setting | Description | Example |
| --------------- | ------------------------------------------------ | -------------------------------------- |
| **Template** | The Google Doc to use as the source template | Select from dropdown |
| **Trigger** | When to generate a document | Incident Created, Incident Resolved |
| **Conditions** | Optional filters to narrow which incidents apply | `Severity = SEV1`, `Duration > 30 min` |
| **Folder** | Where to save the generated doc in Drive | `/Incidents/2024` |
| **Permissions** | Who can access the generated doc | Domain, Team, Private |
| **Delay** | Wait before generating | 24 hours (useful for retrospectives) |
## Best Practices
* **Test with a real incident** before relying on the workflow in production
* **One template per document type** — keep retrospective, runbook, and executive summary templates separate
* **Use `| default:` for optional fields** so missing data doesn't leave blank placeholders in your docs
* **Version your templates** by keeping a dated copy before making significant changes
## Troubleshooting
**OAuth:** Try signing in again using a different browser or an incognito window.
**Service Account:** Verify the JSON key file is valid and hasn't been corrupted or truncated.
This is almost always a domain-wide delegation issue. Check that:
* The Client ID in Google Admin matches your service account exactly
* All three OAuth scopes are entered as shown (no extra spaces or typos)
* You've waited at least 15 minutes for Google to propagate the changes
**OAuth:** Re-authenticate to refresh your access token.
**Service Account:** Confirm the service account has **Editor** access to the target folder in Google Drive.
***
### Template and Workflow Issues
* Is the workflow toggled to active?
* Does the incident meet all the workflow conditions?
* Is your template shared with Rootly? (Service Account only)
* Check the workflow execution log for errors
* Double-check variable spelling — Liquid is case-sensitive
* Test the variable in the [Liquid Explorer](https://rootly.com/account/help/liquid-explorer)
* Make sure the field has data on the incident (for example, `mitigated_at` won't exist on an unmitigated incident)
* Use `| default: "N/A"` to handle missing values gracefully
* OAuth: Re-authenticate if your access token has expired
* Service Account: Confirm the template is shared with the service account as **Editor**
* Confirm domain-wide delegation is still active in Google Admin
* Folder paths use forward slashes — confirm the path is correct
* Parent folders must already exist in Drive; Rootly won't create them
* Test any Liquid expressions in the folder path separately
## Uninstall
To remove the Google Docs integration, go to **Configuration → Integrations**, find **Google Docs**, and click the **Connected** button to reveal the disconnect option.
Disconnecting stops Rootly from creating new documents. Documents already generated by Rootly are not affected.
***
# Google Gemini
Source: https://docs.rootly.com/integrations/google-gemini
Connect Rootly to Google Gemini to send prompts to Gemini models from incident and action item workflows for AI-assisted summaries and triage.
## Introduction
The Google Gemini integration lets you connect Rootly to your organization's Google Gemini API account. Once connected, a new **Gemini Chat Completion** workflow action becomes available, allowing you to send prompts to Gemini models and capture their responses — directly within your incident and action item workflows.
With the Google Gemini integration, you can:
* Generate AI-powered incident summaries, analyses, and recommendations
* Send custom prompts to Gemini models with full Liquid template support
* Use a system prompt to define the model's role, tone, or output constraints
* Choose from any Gemini model available on your API account
## Before You Begin
Before setting up the Google Gemini integration, make sure you have:
* A Rootly account with permission to manage integrations
* A [Google AI Studio API key](https://aistudio.google.com/app/apikey) with access to Gemini models
Your API key is validated against the Gemini API when you save the integration. If validation fails, confirm the key is active and has access to at least one Gemini model.
## Installation
Navigate to the integrations page in your Rootly workspace and select **Google Gemini**.
Paste your Google AI Studio API key into the **API Key** field. Rootly validates the key by fetching your available Gemini models before saving. Your key is encrypted at rest in Rootly.
Your Google Gemini integration is active. The **Gemini Chat Completion** workflow action is now available in your incident and action item workflows.
## Workflow Actions
### Gemini Chat Completion
Sends a prompt to a Gemini model and captures the response as a workflow output. The model list is fetched dynamically from your API account.
| Field | Description | Required |
| ------------- | -------------------------------------------------------------------------- | -------- |
| Model | The Gemini model to use — fetched from your account | Yes |
| Prompt | The user message — supports Liquid templating | Yes |
| System Prompt | Instructions for the model's role or behavior — supports Liquid templating | No |
Use Liquid variables in your prompts to include live incident context — for example `{{ incident.title }}`, `{{ incident.severity }}`, and `{{ incident.description }}`. See the [Liquid variables reference](/liquid/incident-variables) for all available fields.
The **System Prompt** field sets the model's persona or output format — for example: *"You are an incident response assistant. Respond in bullet points. Be concise."*
## Troubleshooting
Rootly validates your API key by fetching the list of available Gemini models when you save. If validation fails, confirm the key is active in [Google AI Studio](https://aistudio.google.com/app/apikey) and has not been revoked or restricted.
If the integration was working and then stopped, the API key may have been revoked or rotated. Update the key in the integration settings — Rootly re-validates on save.
Google Gemini enforces rate limits based on your API tier. Running many concurrent workflows may exceed requests-per-minute limits. Consider staggering workflows or upgrading your Google AI Studio plan for higher quota.
The model list is fetched dynamically from your API account and is filtered to Gemini models. If a model you expect is missing, confirm your API key has access to it — some models may require specific API tiers or allowlisting.
Check your Liquid syntax — unclosed tags or undefined variables can cause rendering failures. Use the [Liquid variables reference](/liquid/incident-variables) to confirm variable names and test your template in a low-stakes workflow first.
## Related Pages
Build workflows that use Gemini models to analyze, summarize, or respond to incidents.
Reference for all incident variables available in Liquid-templated prompts.
Learn about Rootly's built-in AI features for incident management.
# Google Meet
Source: https://docs.rootly.com/integrations/google-meet/google-meet
Connect Google Meet to Rootly to create an incident meeting automatically and capture transcripts and summaries with Meeting Scribe.
Rootly's Google Meet integration eliminates the friction of setting up incident calls. When an incident is declared, Rootly automatically creates a Google Meet room, sends calendar invites to the right people, and posts the link to your Slack channel.
The integration supports both personal OAuth connections for quick setup and Google Cloud Service Accounts for production environments where you need domain-wide access and stability.
## Features
Instantly create a Google Meet room when an incident is declared, no manual setup required.
The Meet link is automatically posted to your incident Slack channel so responders can join immediately.
Send calendar invites to incident responders so everyone has the meeting on their schedule.
Enable automatic recording, transcription, and AI-generated summaries of incident calls.
## How It Works
When an incident is created, your configured workflows run automatically based on severity, type, or team ownership.
A meeting is generated with the incident details added to the title and description.
Everyone who needs to join gets a calendar invite automatically.
The Meet link is posted to your Slack channel, status pages, and other configured tools.
## Meeting Scribe on Google Meet
The Google Meet integration powers **[Rootly AI Meeting Scribe](/ai/meeting-scribe)** on your Google Meet incident bridges — automatic recording, live transcription, PII-redacted transcripts, and Rootly AI meeting summaries fed straight into the incident.
To enable:
1. Go to **Integrations → Google Meet** in Rootly.
2. Toggle on **Meeting transcript and summary**.
3. Connect via a **Google Cloud Service Account** (recommended for production). Personal-OAuth connections work for testing but tie the scribe to one user — when that user leaves or their token expires, the scribe stops joining meetings.
4. Verify your Google Workspace **Meet safety** admin settings. Restrictive host-management policies can silently block the scribe from being admitted. See troubleshooting below.
Google Meet without a service account is the number-one reason customers report "the scribe won't join our calls." Set up the service account before rolling it out broadly.
Running into issues? See **Google Meet Meeting Scribe Troubleshooting** for admission failures, service-account setup, and admin-console settings.
***
## Before You Begin
**Before you start, you'll need:**
* A Rootly account with Admin permissions to manage integrations
* **For OAuth:** A Google account with Google Meet enabled
* **For Service Account:** Access to Google Cloud Console and Google Admin Console
Rootly recommends integrating with a **service account** rather than a personal account. This ensures the integration continues to work even if a user leaves your organization.
## Installation
You can use OAuth for quick setup with a personal account, or a Google Cloud Service Account for production environments that need domain-wide access. After completing these steps, you can configure workflows to automatically create Google Meet rooms when incidents are declared.
### OAuth Setup
Best for quick testing or evaluating Rootly before a full organizational rollout.
Navigate to **Configuration → Integrations** in the Rootly sidebar.
Search for **Google Meet** and click **Setup**.
Select **OAuth** as your connection method, then choose the Google account you want to connect.
Approve the requested permissions. You'll be redirected back to Rootly once the connection is established.
Your Google Meet account is now connected. Head to the Workflows page to configure automated meeting creation.
### Service Account Setup
Use a [Google Cloud Service Account](https://cloud.google.com/iam/docs/service-account-overview) if you're connecting on behalf of your entire organization. This method ensures the integration keeps running even if a user leaves the company.
In Google Cloud Console, navigate to **IAM & Admin → Service Accounts** and click **Create Service Account**.
Enter the service account name and ID. Click **Done** to create the account, then click on the new account's email to open its details.
Navigate to the **Keys** tab and click **Add Key → Create New Key**. Select **JSON** as the key type and click **Create**. A `.json` file will be downloaded — keep this safe.
Return to Rootly's Google Meet setup screen and upload the `.json` file you just downloaded.
In **Acts as user**, enter the email address of a real, active user in the Google Workspace domain your domain-wide delegation scopes cover. The service account impersonates this user when it creates Meet calls. This field is required for service account connections, and is not used by OAuth connections.
Use a dedicated, non-personal workspace account here (for example `rootly-meet@yourcompany.com`) rather than an individual's account, and exclude it from offboarding so it isn't deactivated when someone leaves.
Once uploaded, you'll see a confirmation that your Google Meet account has been connected.
Domain-wide delegation of authority has not yet been configured. Without granting the necessary domain-wide access, API requests will fail with a **403 Forbidden** error.
In [Google Admin Console](https://admin.google.com), go to **Security → API Controls → Domain-wide Delegation**. Select your service account and add a new API client.
Enter your service account's **Client ID** (found in GCP Console under the service account's details) and add the following OAuth scopes:
```text theme={null}
https://www.googleapis.com/auth/meetings.space.created
https://www.googleapis.com/auth/calendar.events
https://www.googleapis.com/auth/calendar
```
The calendar scopes are required for creating calendar events with Meet links attached.
Click **Authorize** to save the configuration. Changes may take 10–15 minutes to propagate through Google's systems.
Your Google Meet integration is now fully configured. Head to the Workflows page to set up automated meeting creation.
### Why Production Should Use a Service Account
The single biggest lever for reliable Google Meet scribe behavior is connecting via a **Google Cloud Service Account** rather than personal OAuth.
| Connection type | Reliability | When to use |
| ------------------- | -------------------------------------------------- | ---------------------------- |
| **Service account** | High — domain-wide, stable across staff changes | Production incident response |
| **Personal OAuth** | Fragile — tied to one user's token and permissions | Quick testing only |
The **Acts as user** account still has to stay active. A service account survives staff turnover because the credentials, the delegation grant and the scopes all stay valid, but if the impersonated user is deactivated or deleted, meeting creation fails until you point **Acts as user** at another active user. That's a one-field change in Rootly, with no key re-upload and no new delegation grant in the Google Admin Console.
**Fix if you're on personal OAuth:** Reconnect the integration via a service account. See Google Meet → Installation for the setup flow.
***
## Creating the Incident Meeting
You can automate Google Meet room creation in two ways:
Automatically create a Google Meet room at incident start using built-in settings — no workflow required.
Use workflows for conditional or advanced meeting automation with full control over triggers and actions.
### Option 1: Auto-Create Incident Call
The Auto-Create Incident Call panel lets you automatically generate a Google Meet room whenever an incident begins, without building a workflow from scratch.
It includes a full set of configuration options so you can control how the room is created, where it's shared, and what Google Meet features are enabled.
These settings let you control exactly how Google Meet calls behave during incidents.
Automatically spin up a meeting the moment an incident opens.
Add the meeting link as a bookmark in the incident's Slack channel.
Announce new incident calls in specific Slack channels.
Enable AI-powered recording, transcription, and summary generation.
Use Auto-Create when you want instant, zero-configuration Google Meet automation. Build a custom workflow when you need conditions, multiple actions, or advanced routing logic.
### Option 2: Creating a Custom Workflow
For teams that need conditional logic — such as only creating calls for SEV-1 incidents or specific teams — a custom workflow gives you full control.
Go to **Rootly → Workflows → Create Workflow**.
Select your workflow type — typically **Incident** for meeting automation.
Triggers define when this workflow should run. Choose the event that should kick off your Google Meet room creation.
| Trigger | What It Does |
| --------------------------- | -------------------------------------------------------------- |
| Incident Created | Creates a Google Meet room as soon as a new incident is opened |
| Incident Updated | Fires when fields like severity or status change |
| Incident Status Changed | Starts a call when the incident moves into a specific status |
| Incident Commander Assigned | Creates a meeting once someone takes ownership |
| Manual Trigger | Run the workflow manually from the incident UI |
Conditions control when the workflow should or shouldn't run after being triggered. Use conditions to narrow the scope of your automation.
Examples:
* **Severity-based** — Only create calls for SEV-1 or SEV-2 incidents
* **Team or service filters** — Only for incidents impacting specific teams
* **Incident type filtering** — Only when the incident kind is set to Incident (not Maintenance)
Click **Add Action → Google Meet → Create Room**. Configure the action settings that appear.
Enable **AI Meeting Capture** to have Rootly AI automatically capture and summarize the meeting.
Click **Add**, give your workflow a descriptive name, and click **Create Workflow**.
### Variable Reference
Use these variables in workflow notifications, Slack messages, and calendar event templates.
#### Google Meet Variables
| Variable | Description | Available |
| ----------------------------- | ------------------------------------- | ------------------------ |
| incident.google\_meeting\_url | The link to join the Google Meet room | After meeting is created |
| incident.google\_meeting\_id | The unique ID of the Google Meet | After meeting is created |
#### Incident Variables
| Variable | Description |
| ----------------------------- | ------------------------------------------- |
| incident.title | Incident title |
| incident.summary | Incident summary or description |
| incident.severity | Severity level (for example, SEV1) |
| incident.status | Current incident status |
| incident.started\_at | Timestamp when the incident started |
| incident.creator.name | Name of the person who created the incident |
| incident.creator.email | Email of the incident creator |
| incident.slack\_channel\_name | Name of the incident's Slack channel |
| incident.url | Link to the incident in Rootly |
Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test variables with real incident data before using them in production.
### Example Templates
Include the Google Meet link in a Slack message automatically when an incident is created:
```liquid theme={null}
Incident {{ incident.title }} started
Join Google Meet: {{ incident.google_meeting_url }}
Severity: {{ incident.severity }}
Please confirm when you've joined.
```
Use Google Meet variables to automatically populate calendar event details for your team:
```liquid theme={null}
Title: Incident {{ incident.title }}
Started: {{ incident.started_at | date: "%Y-%m-%d %H:%M" }}
Join Google Meet: {{ incident.google_meeting_url }}
Description: {{ incident.summary }}
Please join the meeting on time.
```
## Troubleshooting
**Error:** "Failed to authenticate with Google"
* Verify you're using the correct Google account
* Check that your account has Google Meet enabled
* For OAuth: Try incognito mode to avoid account conflicts
* For Service Account: Verify the JSON key file is valid and not expired
**Error:** "API requests fail with 403 error"
1. Verify domain-wide delegation is enabled in Google Admin Console
2. Confirm all three OAuth scopes are added exactly as shown
3. Check the Client ID matches your service account
4. Ensure the subject email belongs to your domain
5. Wait 10–15 minutes for Google to propagate changes
**Error:** "Invalid JSON key file"
* Ensure you downloaded the JSON (not P12) format
* Check the file hasn't been modified or corrupted
* Verify the service account still exists in GCP Console
* Generate a new key if the current one is older than 90 days
**Error:** "Where to find Client ID for domain delegation"
1. Go to Google Cloud Console
2. Select your project
3. Navigate to **IAM & Admin → Service Accounts**
4. Click on your service account
5. Find **Unique ID** or **Client ID** in the details section
**Error:** "Setup complete but workflows fail"
* For Service Account: check **Acts as user** first. An empty field surfaces as `Invalid request` while the integration continues to display as connected.
* For Service Account: if **Acts as user** points at a user who has been deactivated or deleted, meeting creation also fails until you point it at another active user.
* For Service Account: domain delegation may also be missing or incomplete
* For OAuth: Re-authenticate and ensure all permissions were granted
* Check that Google Meet is enabled in your Google Workspace
* Verify the integration shows **Active** status in Rootly
### Meeting Scribe Will Not Join
Nearly every "the scribe didn't join our call" report traces back to one of a small set of causes. Work through them in this order.
#### The Scribe Won't Join Google Meet Meetings
Walk through this list in order.
#### The integration is on personal OAuth (not a service account)
Personal-OAuth connections work but are tied to one user. If that user's token expired or they lost calendar permissions, the scribe stops being able to admit itself to calls.
**Fix:** Reconnect via a service account (see above).
#### The meeting URL wasn't created by Rootly
The scribe is scoped to the Google Meet room Rootly created for the incident. Ad-hoc `meet.google.com` links or personal meeting rooms won't be picked up.
**Fix:** Use the meeting link Rootly pinned at the top of the incident's Slack channel.
#### Google Workspace Meet safety settings block admission
This is the most common cause of "the scribe says it joined but nobody can let it in."
Unless the scribe was pre-invited to the calendar event as an attendee (in which case Google typically skips the waiting room), it joins as an external participant and lands in the waiting room. When **Host management** is on in your Google Workspace Meet safety settings, only the meeting host and any pre-assigned co-hosts can see and admit people from the waiting room. Every other responder on the call — even responders in your own organization — sees nothing to admit. The scribe waits, nobody with permission notices, and it leaves at the 10-minute timeout.
**Check who the host actually is.** Google treats the calendar event's organizer as the host, and Rootly-created events are organized by the account Rootly used to create the meeting, not by whoever declared the incident. That account depends on how you connected the integration: for service-account connections, it's the delegated **Acts as user** (per [Service Account Setup](#service-account-setup)); for OAuth connections, it's the connected OAuth user. Only that organizer account or a pre-assigned co-host can admit the scribe — so if neither the organizer nor a co-host is on the bridge, no one else can let it in. On OAuth connections the organizer may happen to also be a responder; on service-account connections it typically isn't. Either way, that's the account to check if you're chasing this from the Google side.
**Fix — pre-assign a co-host.** The organizer can designate co-hosts on the calendar event so more than one person can admit from the waiting room. This is only available in the Google Calendar UI, so it's a manual step per meeting rather than something you can automate.
**Fix — turn Host management off.** In the Google Admin console, go to **Menu → Apps → Google Workspace → Google Meet → Meet safety settings** and turn **Host management** off for the organizational unit **containing the organizer account** — the service account's **Acts as user**, or the OAuth-connected user, per the warning above. Applying it to responders' OU instead of the organizer's OU has no effect. Any participant can then admit from the waiting room.
Turning Host management off does more than open up admission. It also removes the host's exclusive control over who can present, who can send chat messages, participant audio and video, muting all participants, ending the meeting for everyone, and assigning co-hosts. Weigh that against your meeting-security posture before changing it org-wide.
***
#### Waiting-room timeout (10 minutes)
If the scribe is stuck waiting for admission and no one lets it in, it leaves after **10 minutes**.
**Fix:** Reinvite from the **Scribe** tab and admit it promptly. Prevention: pre-assign a co-host or turn Host management off — see [Google Workspace Meet safety settings block admission](#google-workspace-meet-safety-settings-block-admission) above.
#### Nobody-joined timeout (5 minutes)
If the scribe enters the meeting but no responders join within **5 minutes**, it leaves.
**Fix:** Start the meeting on your side first, then reinvite the scribe — or wait until responders are on the call before inviting it.
***
#### The Scribe Joined but Transcript Is Missing
#### Post-meeting processing is still running
Transcripts and Rootly AI meeting summaries generate after the call ends. Give it 5–10 minutes.
#### Recording started but the call ended abruptly
If the meeting host ended the call while the scribe was still in an unstable state, some of the recording may not have made it to processing. Reinvite for future sessions of the same incident if the meeting resumes.
#### The scribe recorded a "waiting room" clip and nothing else
The scribe was never admitted to the meeting — the recording is only its own waiting-room view. See the "won't join" section above for the underlying cause.
***
## Uninstall
To remove the Google Meet integration:
1. Go to **Configuration → Integrations** and find **Google Meet**
2. Click the **Connected** button to reveal the disconnect option
3. Click **Disconnect**
Disconnecting will prevent Rootly from creating new Google Meet rooms. Existing meetings and calendar events are not affected.
## Frequently Asked Questions
Each incident is associated with one Google Meet room by default. If you need additional rooms, you can create sub-incidents and configure workflows to create separate rooms for each sub-incident.
Rootly does not automatically end or delete the Google Meet room when an incident is resolved. The room remains accessible through the meeting link until it expires naturally per Google Meet's settings.
Yes. The workflow actions work the same regardless of which connection method you used during installation. The integration handles authentication transparently.
Ensure the **Slack Channels** field is configured in your workflow action and that the channel reference is correct. You can use `{{ incident.slack_channel_id }}` to target the incident's dedicated channel automatically.
### Meeting Scribe Questions
Service accounts represent your Google Workspace organization rather than a specific user. They don't need a personal OAuth grant to keep working, they don't lose access when someone leaves the team, and they behave consistently regardless of who declared the incident. Personal OAuth ties the scribe to whoever connected it — one departure and reliability drops.
Only one Google Meet connection is active at a time. Switch by reconnecting.
The scribe joins meetings hosted on your Google Workspace domain. Meetings hosted by an external organization (a vendor, a partner) can't grant your scribe entry unless their admin admits it, which is unusual.
No. Meeting Scribe is scoped to your Google Workspace domain. Meetings created by a personal `@gmail.com` account aren't covered.
***
## Related Resources
* [Rootly AI Meeting Scribe](/ai/meeting-scribe)
* [Workflows](/workflows/workflows)
* [Integrations overview](/integrations/overview)
# Grafana
Source: https://docs.rootly.com/integrations/grafana/grafana
Connect Grafana to Rootly to ingest alert events and capture dashboard and panel snapshots during incidents through Genius workflows.
The Grafana integration connects Rootly with your Grafana instance in two directions. Grafana alert rules send events into Rootly as alerts, and incident workflows capture dashboard and panel snapshots so responders keep point-in-time visibility into your metrics without leaving the incident.
With the Grafana integration, you can:
* Receive Grafana alert events as Rootly alerts, routed to services, teams, or escalation policies
* Page Rootly on-call targets directly from Grafana alert rules
* Capture Grafana dashboard and panel snapshots from Genius workflows during incidents
* Attach snapshot links to incident timelines for post-incident review
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with permission to manage integrations
* A Grafana instance accessible over HTTPS
* Permission to create service accounts in Grafana
* Permission to configure contact points and alert rules in Grafana, if you plan to ingest alerts
Rootly requires a Grafana service account with an **Admin** role to create dashboard snapshots. Rootly recommends a dedicated service account so the integration does not break if an individual user leaves your organization.
## Installation
Navigate to the integrations page in Rootly and select **Grafana**.
In your Grafana instance, navigate to **Administration > Service Accounts**.
Select **Add service account** and create it with an **Admin** role.
Grafana service accounts with roles lower than Admin cannot create snapshots. The integration will fail silently if the role is insufficient.
Open the service account and select **Add Service Account token**. Enter a display name, set the token expiration, and generate the token.
Copy the token immediately — Grafana will not show it again after you leave this page.
Enter your Grafana **instance URL** and the **service account token** into the Rootly integration settings and save.
The instance URL must use HTTPS. HTTP URLs are not accepted.
## Ingest Grafana Alerts
Grafana sends alert events into Rootly through a webhook contact point. Once alerts are flowing, alert workflows can create incidents, notify Slack channels, or page on-call targets.
Install the integration before configuring the contact point. The webhook secret is generated during installation and is required for authentication.
### Configure a Webhook Contact Point
Log into your Grafana instance and navigate to **Alerting > Contact points**.
Select **+ Add contact point**.
Fill in the contact point details:
* **Name** — give the contact point a descriptive name
* **Integration** — select **Webhook**
* **HTTP Method** — select **POST**
The URL format depends on whether you want a general alert or want to page an on-call target.
**For a general alert** (appears in Rootly Alerts, does not page anyone):
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/grafana_webhooks/?secret=
```
**To page a Rootly on-call target**, append a notification target to the URL:
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/grafana_webhooks/notify//?secret=
```
Supported resource types are `User`, `Group` (team), `EscalationPolicy`, and `Service`. The resource ID can be found by editing the resource in Rootly.
Your webhook URL and secret are available in Rootly under **Integrations > Grafana > Configure**.
Select **Test** to send a test alert to Rootly. A test alert should appear on your [Rootly Alerts page](https://rootly.com/account/alerts).
Once the test succeeds, select **Save contact point**.
### Attach the Contact Point to Alert Rules
A contact point only receives alerts when it is attached to an active alert rule.
Navigate to **Alerting > Alert rules** and select **+ New alert rule**, or edit an existing rule. In the rule configuration, set the **Contact point** to the one you just created.
You can attach the same Rootly contact point to multiple alert rules. Use different contact point URLs (with different notification targets) to route different rules to different on-call targets.
### How Alerts Are Mapped
Rootly extracts the following fields from each Grafana webhook payload:
* **Summary** — the `title` field from the Grafana alert payload
* **External ID** — the `ruleId`, used to deduplicate alerts from the same rule
* **External URL** — the `ruleUrl`, linking back to the Grafana alert rule
* **Labels** — all key-value pairs from `commonLabels` are attached as Rootly alert labels, making them available for routing and filtering
Grafana `commonLabels` map directly to Rootly alert labels. You can use these labels in alert routing rules and workflow conditions to control how different Grafana alerts are handled.
## Workflow Actions
Once the integration is connected, two new tasks are available in your Genius workflows:
* **Capture Grafana Dashboard Snapshot** — captures a snapshot of a full dashboard
* **Capture Grafana Panel Snapshot** — captures a snapshot of a specific panel
Snapshots are point-in-time captures. The snapshot link is attached to the incident timeline so you can reference exactly what your dashboards looked like when the incident occurred.
## Troubleshooting
Confirm the contact point is correctly attached to the alert rule that fired. Verify the webhook URL is correct and the secret matches what is shown in your Rootly Grafana integration settings. Use the **Test** button in the contact point configuration to confirm delivery.
Check that the alert rule is in a firing state and that the contact point is set as the notification destination for that rule. Grafana alert rules that use notification policies rather than direct contact point assignment may route differently than expected.
Verify that the `resource_type` and `resource_id` in the notification target URL are correct and that the resource exists in Rootly. Ensure the resource type is one of `User`, `Group`, `EscalationPolicy`, or `Service`.
Confirm the Grafana service account has the **Admin** role — lower roles cannot create snapshots and the workflow task fails silently. Check that the instance URL uses HTTPS and that the service account token has not expired.
## Uninstall
To remove the Grafana integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related Resources
* [Alert workflows](/workflows/alert-workflows)
* [Alert routing](/alerts/alert-routing)
* [Integrations overview](/integrations/overview)
# HashiCorp Vault
Source: https://docs.rootly.com/integrations/hashicorp-vault
Securely read secrets from HashiCorp Vault and inject them into Rootly workflow actions using Liquid templates with KV v1, KV v2, and namespace support.
## Introduction
The HashiCorp Vault integration lets Rootly securely read secrets from your Vault cluster and make them available in workflow actions via Liquid templating. Instead of hardcoding sensitive values — API keys, tokens, passwords — in your workflow configurations, you define named secret references that are resolved at runtime from Vault.
Rootly only supports the **KV Secrets Engine version 2**. KV v1 and other secret engines (AWS, PKI, Transit, etc.) are not currently supported.
## Before You Begin
Before setting up the HashiCorp Vault integration, make sure you have:
* A Rootly account with owner or admin permissions
* A running HashiCorp Vault cluster accessible over HTTPS (or HTTP for internal deployments)
* An **AppRole** configured in Vault with a `role_id` and `secret_id` — Rootly authenticates exclusively via the AppRole auth method
* The **namespace** your AppRole is configured in (enterprise Vault deployments)
* The **mount path** and **path** of the KV v2 secrets you want to expose to Rootly
Only the AppRole auth method is supported. If you need another auth method (token, Kubernetes, AWS IAM, etc.), contact [support@rootly.com](mailto:support@rootly.com).
## Installation
Navigate to the integrations page in your Rootly workspace and select **HashiCorp Vault**.
Fill in the following fields:
| Field | Description |
| ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| **Instance URL** | Your Vault server URL — for example, `https://vault.yourcompany.com`. Trailing slashes are stripped automatically. |
| **Namespace** | Your Vault namespace. For Vault Enterprise, this is typically `admin` or a child namespace. Required. |
| **Role ID** | The `role_id` from your AppRole configuration in Vault. Encrypted at rest in Rootly. |
| **Secret ID** | The `secret_id` from your AppRole configuration in Vault. Encrypted at rest in Rootly. |
Rootly validates the credentials by attempting an AppRole login against your Vault instance before saving. If the login fails, you'll see: *"cannot access Vault service. Please check your credentials."*
Your HashiCorp Vault integration is active. You can now define named secrets under **Account > Secrets** and reference them in any workflow action.
## Defining Secrets
Once the Vault integration is connected, you create named **secret references** in Rootly that point to specific paths in your Vault KV store. These references are what you use in Liquid templates — Rootly fetches the actual secret value from Vault at workflow runtime.
By default, only Rootly **owners and admins** can create and manage secret definitions. You can adjust this via Rootly's RBAC settings.
Navigate to **Account > Secrets** and define a new HashiCorp Vault secret:
| Field | Description |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | A unique name for this secret reference in Rootly (for example, `pagerduty_key`). This is the name you use in Liquid templates. |
| **Mount** | The KV v2 mount path in Vault (default: `secret`). |
| **Path** | The path to the secret within the mount (for example, `integrations/pagerduty`). |
| **Version** | The KV v2 version number to read. Set to `0` to always read the latest version. |
## Using Secrets in Workflows
Once a secret is defined, you can reference it in any workflow action that supports Liquid templating using the following syntax:
```liquid theme={null}
{{ secrets.SECRET_NAME.KEY_NAME }}
```
Where `SECRET_NAME` is the name you gave the secret in Rootly, and `KEY_NAME` is the key within the Vault secret JSON.
For example, given a Vault secret at `integrations/pagerduty` containing:
```json theme={null}
{
"api_key": "pd_key_abc123",
"webhook_token": {
"value": "wh_secret_xyz789"
}
}
```
You can reference it in a workflow action as:
```liquid theme={null}
{{ secrets.pagerduty_key.api_key }}
{{ secrets.pagerduty_key.webhook_token.value }}
```
Nested secret keys are supported — use dot notation to traverse the JSON structure.
## Troubleshooting
Rootly validates credentials by attempting an AppRole login at `{instance_url}/v1/auth/AppRole/login`. Confirm that:
* The instance URL is reachable from Rootly's servers (check any firewall or allowlist rules)
* The namespace is correct — for HCP Vault, this is typically `admin`
* The `role_id` and `secret_id` are both valid and haven't expired or been rotated
* The AppRole auth method is enabled at the path `auth/AppRole` in Vault
Check that:
* The **mount** and **path** in the Rootly secret definition match the actual path in Vault
* The **version** is set to `0` (latest) or a specific version that exists
* The AppRole has a policy granting `read` access to the secret path in KV v2 format: `secret/data/your/path`
* The KV engine is version 2 — KV v1 paths have a different structure and are not supported
Rootly uses dot notation to traverse JSON secret values. Ensure the key path in your Liquid template matches the JSON structure exactly, including case. For example, `{{ secrets.my_secret.nested.foo }}` requires a JSON structure of `{"nested": {"foo": "value"}}`.
The AppRole's attached Vault policy must explicitly grant `read` capability on the KV v2 data path. KV v2 paths follow the pattern `secret/data/` (not `secret/`). A minimal policy granting read access looks like:
```hcl theme={null}
path "secret/data/integrations/*" {
capabilities = ["read"]
}
```
Secret definitions are restricted to Rootly owners and admins by default. If you have a lower permission level, ask an admin to create the secret reference for you, or ask an admin to adjust the RBAC settings to allow your role to manage secrets.
## Uninstall
To disconnect the integration, navigate to the integrations panel, open the Vault integration, and click **Configure > Delete**.
## Related Pages
Use Vault secrets in workflow actions to authenticate with external systems during incidents.
Reference for all Liquid variables available in workflow actions alongside secrets.
Manage Rootly resources as infrastructure as code with the Rootly Terraform provider.
# Heroku Integration
Source: https://docs.rootly.com/integrations/heroku
Track Heroku builds and releases as pulses in Rootly, and run commands on dynos directly from incident workflows for deployment context and rollback.
## Overview
The Heroku integration connects Rootly to your Heroku apps via OAuth. Build and release events are automatically tracked as pulses so your team can correlate deployments with incidents — and the **Run Command on Heroku** workflow action lets you execute rollbacks or diagnostic scripts on a live dyno without leaving the incident response flow.
Build starts, completions, and release events are automatically tracked as Rootly pulses and linked to matching services.
Execute one-off commands on a Heroku dyno from a workflow — output is streamed and posted to Slack.
Pulses are automatically associated with Rootly services that have a matching Heroku app name configured.
Choose which Heroku apps to monitor — Rootly only creates webhooks on the apps you explicitly list.
## Before You Begin
* You must be a Rootly admin to set up the integration
* You need a Heroku account with access to the apps you want to monitor
Connect using a **Heroku service account** rather than a personal user account. If the connecting user leaves your organization, the OAuth token becomes invalid and the integration will stop working.
## Installation
Go to **Configuration → Integrations**, find **Heroku**, and click **Setup**.
Click **Connect Heroku Account**. You'll be redirected to Heroku to authorize Rootly's OAuth application. After approving, you'll be returned to Rootly with the integration connected.
In the integration settings, add the names of the Heroku apps you want to track. Rootly creates webhooks on each listed app to receive build and release events.
If you leave the app list empty, no webhooks are created and no pulses will be tracked. Add app names to enable pulse tracking.
## Pulse Events
Rootly ingests Heroku webhook events and records them as pulses on the incident timeline and service activity feed. Pulses are automatically linked to Rootly services with a matching **Heroku App Name** field.
### Build Events
| Event | Pulse Summary |
| --------------- | -------------------------------------- |
| Build started | `[Heroku][Build] {app_name} pending` |
| Build succeeded | `[Heroku][Build] {app_name} succeeded` |
| Build failed | `[Heroku][Build] {app_name} failed` |
Each pulse includes the build ID, commit SHA, and the email of the user who triggered the build.
### Release Events
| Event | Pulse Summary |
| ---------------- | ----------------------------------------- |
| Release deployed | `[Heroku][Release] {release description}` |
Each pulse includes the release version, status, commit SHA, and app name. Rootly filters out non-current release updates to avoid duplicate pulses from Heroku's release phase behavior.
Rootly tracks `api:build` and `api:release` webhook events. Dyno events (`api:dyno`) are received but not currently converted into pulses.
## Workflow Action
### Run Command on Heroku
Executes a one-off command on a Heroku dyno and streams the output to Slack. Useful for running rollbacks, querying database state, or executing diagnostic scripts mid-incident.
The command to run on the dyno. Supports [Liquid variables](/liquid/incident-variables) — for example, use `{{ incident.title }}` to reference the active incident.
The name of the Heroku app to run the command against.
The size of the one-off dyno to spin up:
* `standard-1X`
* `standard-2X`
Defaults to `standard-1X`.
Maximum run time for the command in seconds. Capped at **1800 seconds (30 minutes)** regardless of the value set. Defaults to `1800`.
When enabled, records the command run as an event on the incident timeline.
One or more Slack channels to receive the command output as a file attachment once execution completes.
Rootly connects to the dyno over TLS using the Rendezvous protocol, streams all output lines, and posts the collected output to Slack once the command completes or the dyno exits.
## Uninstall
To remove the Heroku integration:
1. Go to **Configuration → Integrations** and find **Heroku**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
Disconnecting removes the integration and deletes all Rootly-managed webhooks from your Heroku apps.
## Frequently Asked Questions
Confirm the app names are listed in the integration settings. Rootly only creates webhooks on explicitly listed apps. Also check that the connected Heroku account still has access to those apps — if permissions have changed, webhooks may have been removed.
Rootly links Heroku pulses to services by matching the **Heroku App Name** field on each service. Go to the affected service and confirm the field exactly matches the Heroku app name (case-sensitive).
Confirm the app name is correct and the connected OAuth account has permission to create dynos on that app. If the command exits immediately, check that it's compatible with the app's runtime environment, buildpack, and Procfile.
Heroku OAuth tokens can expire or be revoked if the authorizing user's account access changes. Reconnect using a service account to prevent future disruption. After reconnecting, verify webhooks have been re-created on your monitored apps.
Heroku sends multiple webhook events during the release phase. Rootly filters out non-current updates, but each pipeline promotion generates its own release event — so deploys through multiple pipeline stages will produce multiple pulses by design.
# HiBob
Source: https://docs.rootly.com/integrations/hibob
Sync HiBob time off into Rootly via calendar feed to overlay vacations and PTO on on-call schedules and spot coverage gaps before pages fire.
## Overview
HiBob exposes your team's time-off data as a subscribe-able calendar feed. Point Rootly at that feed and vacations and PTO appear directly on top of your on-call schedule timeline. Shifts that overlap with someone's leave are highlighted, making it easy to create an override before the next page fires.
This is a read-only overlay. HiBob stays the source of truth for time off; Rootly polls the feed in the background and keeps the schedule view current.
***
## Exporting the Calendar Feed from HiBob
HiBob's calendar export is generated from a filtered view of the People's Time-Off page, so you can scope the feed to a specific team, department, or set of people before sharing it with Rootly.
From the HiBob sidebar, navigate to the **People's Time Off** view.
In the top right, click **Filters** and choose which parts of the organization or which people you want the feed to cover.
If you want a feed of every person's time off, add the **"None"** filter. Without it, HiBob generates a feed of company events only and strips out individual names.
In the top right, click **Sync with external calendar**, then pick **Filtered view** and copy the URL HiBob generates.
Keep the URL handy — you'll paste it into Rootly next.
***
## Adding the Feed to Rootly
Once you have the HiBob feed URL, the rest of the setup happens inside Rootly's schedules view.
In the Rootly dashboard, go to **On-Call → Schedules**. In the calendar preview area, open the **Holiday calendars** dropdown.
Select **Add your team's holiday calendar**, then choose **Add a holiday calendar**.
Paste the URL you copied from HiBob into the URL field.
Give the calendar a descriptive name (for example, `HiBob — Engineering PTO`) so teammates know what it represents. Select the appropriate timezone, or leave it blank to let Rootly infer it from the feed.
Click **Add**. Rootly fetches the calendar and begins syncing automatically. Back in the schedule view, select the new feed from the **Holiday calendars** dropdown to overlay HiBob time off on the on-call timeline.
For the full behavior of holiday calendars in Rootly — conflict highlighting, recurring events, multi-region setups — see [Adding a Holiday Calendar](/on-call/holiday-calendar).
***
## Troubleshooting
HiBob strips names from the feed unless the filtered view includes a **"None"** filter. Re-generate the URL after adding **"None"** to the filter set.
The feed has to be toggled on per schedule preview. Open the **Holiday calendars** dropdown above the schedule and confirm the HiBob feed is selected.
The calendar timezone determines how all-day events align with on-call shifts. Remove the calendar and re-add it with the correct timezone, or leave the timezone field blank to let Rootly infer it from the feed.
***
## Frequently Asked Questions
No. Holiday calendars are read-only previews — they surface conflicts so you can decide whether to override, but they never reassign shifts.
Yes. Generate a separate filtered view per team or region in HiBob, copy each URL, and add them to Rootly as independent feeds.
The feed mirrors whatever your filtered view includes in HiBob. Use the HiBob filters to control whether the feed contains PTO, sick days, public holidays, or all of the above.
# Honeycomb Integration
Source: https://docs.rootly.com/integrations/honeycomb
Receive Honeycomb alerts in Rootly to trigger incidents, notify Slack, page your on-call team, and automatically resolve alerts when triggers clear.
## Overview
Rootly receives alerts from Honeycomb via webhooks. When Honeycomb detects anomalies like latency spikes, error rate increases, or threshold breaches, it sends an alert to Rootly. From there, Rootly can create an incident, notify Slack, or page your on-call team automatically.
## Before You Begin
You will need a Honeycomb account with admin access to create API keys and alert policies, and a Rootly account with Admin permissions to create integrations.
## Step 1: Get Your API Key from Honeycomb
You will first create a Configuration API key in Honeycomb. Rootly uses this key to authenticate your environment and generate the webhook URL and secret needed in the next steps.
Log into Honeycomb and select the environment you want to integrate with Rootly.
Go to **Settings → API Keys** and click **Create a Configuration API Key**.
Honeycomb has two types of API keys: **Configuration** and **Management**. Rootly requires a **Configuration** (environment-level) key.
Name the key, set any permissions, and click **Create Key**. Copy the key immediately — you will need it in the next step.
The API key is used only to authenticate Rootly to your Honeycomb environment and generate a webhook URL and secret. Rootly does not make direct calls to Honeycomb to read or write data.
## Step 2: Connect Honeycomb in Rootly
Now that you have your Honeycomb API key, connect the integration in Rootly to generate the webhook URL and secret you will configure in Honeycomb.
In Rootly, navigate to **Configuration → Integrations** and search for **Honeycomb**.
Click **Setup**, paste your Honeycomb API key, and click **Connect**.
After connecting, Rootly displays a **Webhook URL** and **Secret**. Copy both — you will need them in Step 3.
## Step 3: Create a Webhook in Honeycomb
Now that you have the Webhook URL and Secret from Rootly, go back to Honeycomb and create a webhook integration that forwards alerts to Rootly. The webhook URL format depends on whether you want to page someone or just surface alerts.
In Honeycomb, navigate to **Account → Team Settings → Integrations**.
Click **Add Integration**, select **Webhook** as the provider, and give it a descriptive name (for example, `Rootly Alerts` or `Page On-Call`).
Choose the alert type and enter the appropriate URL:
Alerts appear in Rootly's Alerts page without paging anyone. Use this for low-priority or informational notifications.
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/honeycomb_webhooks?secret=YOUR_SECRET
```
Replace `YOUR_SECRET` with the secret from Rootly.
Alerts trigger an on-call notification for a specific Rootly resource. Replace `RESOURCE_TYPE` and `RESOURCE_ID` with your target.
```text theme={null}
https://webhooks.rootly.com/webhooks/incoming/honeycomb_webhooks/notify/RESOURCE_TYPE/RESOURCE_ID?secret=YOUR_SECRET
```
| Parameter | Allowed values |
| --------------- | ---------------------------------------------- |
| `RESOURCE_TYPE` | `User`, `Group`, `EscalationPolicy`, `Service` |
| `RESOURCE_ID` | Found by editing the resource in Rootly |
The secret must appear in both the Webhook URL query string **and** the Shared Secret field. They must match exactly.
Click **Add** to create the webhook integration.
Your webhook is now active. Any Honeycomb alert policy using this integration will send alerts to Rootly.
## Verify Installation
1. Go to the [Alerts page](https://rootly.com/account/alerts) in Rootly
2. Trigger a test alert in Honeycomb
3. Confirm the alert appears in Rootly within a few seconds
## Uninstall
To remove the Honeycomb integration:
1. Go to **Configuration → Integrations** and find **Honeycomb**
2. Click the **Connected** button to reveal the disconnect option
3. Click **Delete**
Disconnecting in Rootly does not stop Honeycomb from sending alerts. Delete the webhook in Honeycomb under **Team Settings → Integrations** to stop alert delivery.
## Frequently Asked Questions
Verify the webhook URL includes the secret as a query parameter (`?secret=...`). Confirm the Shared Secret field in Honeycomb matches the URL secret exactly. Check that the alert policy in Honeycomb is using this webhook integration.
The secret in the URL must match the Shared Secret field exactly — regenerate the secret in Rootly and update both places in Honeycomb if needed. Also verify you are using a **Configuration** API key, not a Management key.
Verify you are using the `/notify/RESOURCE_TYPE/RESOURCE_ID` URL format. Confirm the resource type is one of `User`, `Group`, `EscalationPolicy`, or `Service`, and that the resource ID exists in Rootly.
## Related resources
* [Prometheus Alertmanager](/integrations/alertmanager)
* [Checkly](/integrations/checkly)
* [Chronosphere](/integrations/chronosphere)
* [Dynatrace](/integrations/dynatrace)
# IP Allowlist
Source: https://docs.rootly.com/integrations/ip-whitelist
Allowlist the IP addresses and hostnames needed for traffic between Rootly and your network, in both directions, through firewalls and proxies.
## Overview
When connecting Rootly to your internal systems or third-party services, you may need to allow traffic from Rootly’s outbound IP addresses.
Rootly uses a fixed set of outbound IP addresses for:
* Integration traffic
* Outbound webhook delivery
If your infrastructure restricts inbound traffic by source IP, add the addresses below to your firewall, security group, or allowlist configuration.
This page covers two directions. Use the fixed IP addresses below to allow traffic **from Rootly to your systems** (webhooks and integrations). To allow your own network to reach **Rootly's web app and API**, see [Connecting to Rootly from a restricted network](#connecting-to-rootly-from-a-restricted-network).
## Security Considerations
IP whitelisting adds an extra layer of network security by helping you:
* Restrict access to trusted IP addresses
* Prevent unauthorized connections from unknown sources
* Meet internal security or compliance requirements
* Protect systems that receive data from Rootly
## Rootly Outbound IP Addresses
Add the following IPv4 addresses to your allowlist:
### Production IP Addresses
```text theme={null}
34.232.217.139/32
18.213.181.255/32
```
These addresses are used for both integration traffic and outbound webhook delivery.
**IP Address Stability:** These production IP addresses are permanent and will not change. You can safely use them in long-term firewall rules and security policies.
## Common Use Cases
### Webhook Endpoints
If Rootly sends webhooks to your systems:
* Allowlist both IP addresses on the receiving endpoint
* Ensure your endpoint accepts HTTPS traffic
* Verify your SSL certificates are valid
### API Access
If Rootly makes API calls to your services:
* Update firewall or load balancer rules to allow these IPs
* Confirm your API gateway accepts traffic from both addresses
* Test connectivity after making changes
## Connecting to Rootly from a restricted network
If your network restricts **outbound** traffic, you may need to allow your users and servers to reach Rootly — for example, to open the web app or call the REST API from inside a locked-down environment.
Rootly's web app and APIs sit behind Cloudflare, so there is no fixed set of destination IP addresses to allowlist. Cloudflare's addresses are shared ranges that rotate. Allow outbound HTTPS (port 443) to Rootly's hostnames instead:
| Hostname | Purpose |
| ----------------------- | --------------------------------------------- |
| `rootly.com` | Web app and login |
| `api.rootly.com` | REST API |
| `mobile-api.rootly.com` | Rootly mobile app (only if your team uses it) |
| `rec.rootly.com` | Edge Connector (only if you deploy it) |
Allow only the hostnames your team uses. `mobile-api.rootly.com` is needed only for the mobile app, and `rec.rootly.com` only if you run the [Edge Connector](/edge-connectors-installation).
If your firewall can only allowlist IP ranges rather than hostnames, allow Cloudflare's published IP ranges, available at [cloudflare.com/ips](https://www.cloudflare.com/ips/). These front all traffic to Rootly.
Do not use the fixed IP addresses listed above to reach Rootly. Those are the source addresses of traffic Rootly sends to you — they are not the destinations your network connects to.
## Testing Your Configuration
After updating your allowlist:
1. Verify integration connectivity in Rootly
2. Check integration or delivery logs for connection errors
3. Test webhook delivery if applicable
4. Review firewall or security logs to confirm traffic is allowed
If these IP addresses are not properly allowlisted, integrations may fail, webhooks may not be delivered, and data synchronization may be incomplete.
## Getting IP Ranges via API
You can also retrieve the current IP ranges programmatically using Rootly’s IP ranges API.
The API returns:
* `integrations_ipv4`
* `integrations_ipv6`
* `webhooks_ipv4`
* `webhooks_ipv6`
This is useful if you want to automate allowlist updates or verify the current published ranges from code instead of hardcoding them.
## IPv6
Rootly also exposes IPv6 fields in the IP ranges API. If IPv6 ranges are added in the future, they will be reflected there alongside the IPv4 ranges.
## Need Help?
If you run into issues with IP allowlisting, contact [support@rootly.com](mailto:support@rootly.com) and include your integration details and network configuration.
# Jira (On-Premise)
Source: https://docs.rootly.com/integrations/jira-on-premise
Connect Rootly with your Jira Data Center or on-premise instance using URL, username/password, or Personal Access Token authentication.
## Introduction
The Jira On-Premise integration connects Rootly with your self-hosted Jira Data Center instance. It supports the same workflow actions as [Jira Cloud](/integrations/jira/jira) — creating issues, subtasks, and syncing status — but authenticates directly against your instance URL rather than through OAuth.
You can connect with **username + password** (Basic Auth) or a **Personal Access Token (PAT)**. Multiple instances are supported, allowing you to connect more than one Jira Data Center environment to a single Rootly organization.
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* Your Jira Data Center instance URL (publicly accessible or network-reachable from Rootly)
* A Jira account with the following permissions: Create Issues, Edit Issues, Assign Issues, Transition Issues, Close Issues, Link Issues
* Username + password **or** a Personal Access Token
Rootly recommends installing with a dedicated Jira service account so the integration does not break if an individual user leaves your organization.
If your Jira instance is in a private network, you must allowlist Rootly's IP addresses before installation. See [IP Allowlist](#ip-allowlist) below.
## Installation
Navigate to the integrations page in Rootly and select **Jira (On-Premise)**.
Provide the following:
**Instance URL**
The base URL of your Jira Data Center instance (for example, `https://jira.yourcompany.com`).
**Internal URL** *(optional)*
An internal network URL for Rootly to use when calling your instance. If set, Rootly uses this URL for API calls while displaying the public Instance URL in the UI.
**SSL Verify Mode** *(optional)*
Controls how Rootly verifies your instance's SSL certificate. Leave blank to use the default (`VERIFY_PEER`). Options:
| Mode | Behavior |
| ----------------------------- | ----------------------------------------- |
| `VERIFY_PEER` | Default — verifies the server certificate |
| `VERIFY_CLIENT_ONCE` | Verifies the client certificate only once |
| `VERIFY_FAIL_IF_NO_PEER_CERT` | Fails if no peer certificate is provided |
| `VERIFY_NONE` | Disables certificate verification |
Only use `VERIFY_NONE` if your instance uses a self-signed certificate in a trusted internal network. Disabling verification exposes you to man-in-the-middle attacks.
Provide either a **username + password** or a **Personal Access Token** — not both.
* **Username + Password** — use your Jira Data Center account credentials
* **Personal Access Token** — generate a PAT from your Jira profile under **Profile > Personal Access Tokens**
Rootly automatically refreshes Personal Access Tokens when they are within 5 days of expiry. Tokens are assumed to have a 30-day lifetime.
Select **Connect** to validate the connection and complete installation.
After installation, the same workflow actions available for Jira Cloud are available for your on-premise instance: **Create a Jira Issue**, **Create a Jira Subtask**, and **Update a Jira Issue**.
## IP Allowlist
If your Jira instance is hosted in a private network or behind a firewall, allowlist the following Rootly IP addresses so Rootly's servers can reach your instance:
* `34.232.217.139`
* `18.213.181.255`
## Workflow Actions
The Jira On-Premise integration shares the same workflow actions as Jira Cloud. Refer to the [Jira Cloud documentation](/integrations/jira/jira) for the full reference on:
* Create a Jira Issue
* Create a Jira Subtask
* Update a Jira Issue
When configuring workflow actions, select your on-premise instance from the **Account** dropdown.
## Troubleshooting
Verify that your instance URL is publicly accessible or that Rootly's IP addresses (`34.232.217.139` and `18.213.181.255`) are allowlisted in your firewall. Confirm the URL includes the correct port if your instance does not run on the default HTTPS port.
If your instance uses a self-signed or internal CA certificate, try setting the **SSL Verify Mode** to `VERIFY_NONE` as a temporary test. For production use, configure your instance with a certificate that Rootly can verify, or use `VERIFY_PEER` with a certificate from a trusted CA.
Confirm the token has not expired and that it was generated by a user with the required Jira permissions. If the token was recently rotated, update the integration credentials in Rootly under **Configure**.
## Uninstall
To remove the Jira On-Premise integration, open the integrations panel in Rootly and select **Configure > Delete**. Removing the integration disables any internal workflows associated with this instance.
# Jira
Source: https://docs.rootly.com/integrations/jira/jira
Sync Rootly incidents with Jira issues: auto-create them on declare with Smart Defaults or custom workflows, and flow Jira status changes back into Rootly.
Rootly's Jira integration keeps incidents and Jira issues in sync. When an incident is declared, a Jira issue is automatically created. Updates flow both ways: incident changes update Jira, and Jira changes can update incidents.
Auto-create Jira issues at incident start without building workflows
Advanced automation with triggers, conditions, and multiple actions
Map incident data to Jira native and custom fields
Follow-up tasks become Jira subtasks linked to the parent issue
***
## How It Works
Authenticate via OAuth and configure webhooks for bidirectional sync.
Use Smart Defaults for instant setup, or build custom workflows for conditional logic.
When an incident is created, Rootly automatically creates a Jira issue.
Changes to incidents update Jira. Jira events can trigger incident updates.
***
## Before You Begin
**Before you start, you'll need:**
* A Rootly account with **Admin** or **Owner** permissions
* A **Jira Cloud** account with admin rights to your instance
### Required Jira Permissions
The Jira account you use to install must have these permissions:
| Permission | Description |
| --------------------- | --------------------------------------------- |
| **Assign issues** | Ability to assign issues to users |
| **Close issues** | Ability to close issues |
| **Create issues** | Ability to create new issues |
| **Delete issues** | Ability to delete issues |
| **Edit issues** | Ability to edit existing issues |
| **Link issues** | Ability to link issues to one another |
| **Transition issues** | Ability to transition issues between statuses |
Learn more about Jira permissions in [Atlassian's documentation](https://confluence.atlassian.com/adminjiraserver073/managing-project-permissions-861253293.html).
### Required OAuth Scopes
Rootly requests these OAuth scopes during installation:
**Read permissions:**
* `read:application-role:jira`
* `read:avatar:jira`
* `read:field-configuration:jira`
* `read:group:jira`
* `read:issue:jira`
* `read:issue-status:jira`
* `read:issue-meta:jira`
* `read:issue-security-level:jira`
* `read:issue-type:jira`
* `read:issue-type-hierarchy:jira`
* `read:issue.changelog:jira`
* `read:issue.transition:jira`
* `read:issue.vote:jira`
* `read:priority:jira`
* `read:project:jira`
* `read:project-category:jira`
* `read:project-version:jira`
* `read:project.component:jira`
* `read:project.property:jira`
* `read:status:jira`
* `read:user:jira`
* `read:user.property:jira`
**Write permissions:**
* `write:attachment:jira`
* `write:comment:jira`
* `write:comment.property:jira`
* `write:issue:jira`
* `write:issue.property:jira`
## Installation
Setting up the Jira integration involves two parts: connecting your Jira account via OAuth and configuring a webhook so Jira can send events back to Rootly. Both are required for full bidirectional sync.
The OAuth flow connects your Jira Cloud instance to Rootly. You'll be redirected to Jira to authorize the connection, then returned to Rootly automatically.
In the Rootly sidebar, click **Configuration → Integrations**.
Search for **Jira Cloud** and click **Setup**.
You'll be redirected to Jira. Verify you're installing on the correct instance, then click **Accept**.
You'll be redirected back to Rootly with a success message confirming the connection.
Your Jira Cloud instance is now connected to Rootly.
### Installing Additional Instances
If your organization uses multiple Jira Cloud instances, you can connect them separately.
A Jira Cloud **instance** is not the same as a Jira **project**. An instance is a separate domain (for example, `company.atlassian.net`). You can have multiple projects within one instance — most organizations have a single instance with multiple projects.
To add another instance:
1. Go to **Integrations** and search for **Jira Cloud**
2. Click **Set up another instance**
3. Follow the same authorization flow
Make sure you're logged into the correct Jira instance in your browser before starting the authorization flow.
### Setting Up the Jira Webhook
To enable **Jira → Rootly sync**, you must configure a webhook in Jira. This allows Rootly to receive events when Jira issues are created or updated. Without this step, changes in Jira won't reflect back in Rootly.
In Jira, navigate to **Settings → System → WebHooks**.
Click **Create a WebHook**.
Give it a descriptive name (for example, "Rootly Webhook Listener") and ensure the status is set to **Enabled**.
In Rootly, go to **Integrations → Jira → Configure** and copy the webhook URL. Paste it into the **URL** field in Jira.
To limit which projects send events to Rootly, add a JQL filter under **Issue related events**. Leave this blank to receive events from all projects.
Choose the Jira events you want Rootly to receive — at minimum, select **issue created** and **issue updated**.
Ensure **Exclude body** is **not** checked. Jira may enable this by default, but Rootly requires the full event payload to process events correctly.
Click **Create** to save your webhook configuration.
Your Jira webhook is now configured for bidirectional sync.
## Verify Installation
Once connected, confirm the integration is working end-to-end:
1. **Check integration status** — The Jira tile in Rootly should show **Connected**.
2. **Test Rootly → Jira** — Create a test incident and verify that a Jira issue is created in the expected project.
3. **Test Jira → Rootly** — Create or update a Jira issue, then check the [Alerts page](https://rootly.com/account/alerts) in Rootly to confirm the event arrived.
If events appear on the Alerts page, your webhook is configured correctly.
## Workflows
**Setup fast and effortless**
Automatically create and manage Jira issues at incident start using pre-configured settings
Use workflows for conditional or advanced Jira issue automation
***
### Smart Defaults
Smart Defaults let you automatically generate a Jira issue whenever an incident begins — without building a workflow. New Rootly accounts have Smart Defaults enabled automatically. Existing accounts have it off by default to avoid conflicting with existing workflows.
To configure Smart Defaults, go to **Integrations → Jira → Configure**.
Configure webhooks in your Jira Admin using this endpoint to allow updates made in Jira to reflect back in Rootly.
See [Setting Up Jira Webhook](/integrations/jira/jira#setting-up-the-jira-webhook) for detailed steps.
This section controls how Jira tickets are created from Rootly incidents.
Automatically create a Jira ticket in the specified project as soon as an incident is declared in Rootly.
The Jira project where tickets will be created. If you need to route tickets to different projects based on conditions, disable this and use custom workflows instead.
The type of Jira issue to create. Options are pulled from the project specified in Project Key.
The initial status of the new ticket. Options are pulled from the selected project and issue type.
The Summary field of the Jira ticket. Defaults to `{{ incident.title }}`. Supports Liquid syntax.
The Description field of the Jira ticket. Defaults to `{{ incident.summary }}`. Supports Liquid syntax.
Assign the Jira ticket to a user by email address. If blank, the ticket is assigned to the incident creator. Supports Liquid syntax.
Automatically create a bookmark to the Jira ticket in the incident's Slack channel for quick access.
Automatically update the matching Jira ticket whenever the incident is updated. This is one-way: changes flow from Rootly to Jira only.
This section controls how Jira subtasks are created from Rootly action items.
Automatically create a Jira subtask under the parent Jira ticket every time a new action item is created in Rootly.
Leave this field **blank**. Jira subtasks can only be one type. This field will be expanded in a future release.
The initial status of the new subtask. Options are pulled from the project specified in Project Key.
Automatically update the matching Jira subtask whenever an action item is updated. This is one-way: changes flow from Rootly to Jira only.
Automatically set the Jira subtask priority to match the action item priority in Rootly.
Use Smart Defaults when you want instant, built-in Jira issue automation without touching workflows. Build a workflow when you need conditions, custom triggers, multiple actions, or more advanced issue routing.
***
### Custom Workflows
Custom workflows give you full control over when and how Jira issues are created or updated. You can filter by severity, service, environment, and more — or chain multiple Jira actions together in a single workflow.
Open **Rootly → Workflows → Create Workflow** and choose the workflow type that matches your use case.
Triggers define when the workflow runs. Choose the event that should create or update a Jira issue.
| Trigger | What it does |
| ------------------------------- | -------------------------------------------------------- |
| **Incident Created** | Creates a Jira issue as soon as a new incident is opened |
| **Incident Updated** | Fires when fields like severity or status change |
| **Incident Status Changed** | Triggers when the incident moves to a specific status |
| **Incident Commander Assigned** | Fires once someone takes ownership |
| **Manual Trigger** | Run manually from the UI when needed |
Choose the trigger that fires only when you actually need a Jira issue. Avoid creating issues earlier than necessary.
Conditions let you control when the workflow should run after it's been triggered. This keeps your Jira project clean by limiting automation to the incidents that matter.
Common condition setups:
* **Severity-based** — Only create Jira issues for SEV-1 or SEV-2 incidents
* **Team or service filters** — Only fire for incidents impacting specific teams or services
* **Incident type** — Ensure the workflow only runs when the Kind is set to Incident
* **Environment** — Trigger only for customer-facing or production-impacting incidents
Use conditions to avoid unnecessary Jira issues and keep the workflow focused.
Actions are the steps that run when the workflow fires. Click **Add Action**, then search for **Jira** to see the available actions.
#### Create Jira Issue
Creates a new Jira issue for an incident or retrospective.
Optional label for this action. Does not affect behavior.
The Jira project where the issue will be created.
The type of Jira issue to create (for example, Bug, Task, Story). Options are pulled from the selected project.
Title of the Jira issue. Supports Liquid syntax (for example, `{{ incident.title }}`).
Detailed description. Supports Liquid syntax (for example, `{{ incident.summary }}`).
Priority of the Jira issue (for example, High, Medium, Low).
Initial status of the issue. Options are pulled from the selected project and issue type.
Jira labels to categorize the issue. Supports multiple values.
Optional due date. Supports Liquid syntax or fixed dates.
The reporter for the Jira issue. Defaults to the incident creator. Supports Liquid syntax.
The assignee for the Jira issue. Supports Liquid syntax.
Prevents the workflow from stopping if this action fails.
Toggle this action on or off, useful when testing.
Use Rootly's [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test variables before using them in your workflow.
#### Update Jira Issue
Updates an existing Jira issue. You must reference the issue using `{{ incident.jira_issue_id }}` in the **Jira Issue to Update** field.
This action only works if a Jira issue has already been created and linked to the incident.
The Update Jira Issue action also works inside [Action Item Workflows](/workflows/action-item-workflows). When paired with the `Action Item Updated` trigger, it's the canonical way to enrich Jira tickets created via **Export to ticketing** with incident context (Rootly URL, severity, services, etc.) — see [Linking Exported Tasks Back to the Incident](/incidents/action-items/adding-action-items-via-web-ui#linking-exported-tasks-back-to-the-incident). In an action item workflow, use `{{ action_item.jira_issue_id }}` instead of the incident-side variable.
#### Create Jira Subtask
Creates a subtask under an existing Jira issue. Reference the parent issue using `{{ incident.jira_issue_id }}` in the **Parent Jira Issue** field. The **Project Key** must match the one used to create the parent issue.
This action is intended for action items or sub-incidents.
Give your workflow a descriptive name (for example, "Create Jira Issue on SEV-1 Incident"), then click **Create Workflow**.
***
### Action Reference
Creates a new ticket in a Jira project. You must select the **Project Key** and **Issue Type** for the ticket to be created correctly.
This action can be used for both incidents and action items. For action items, using **Create Jira Subtask** is recommended if your team uses subtasks — but if not, this action works as well.
The Jira project where the issue will be created.
The type of Jira issue to create. Options are pulled from the selected project.
The title of the Jira issue. Supports Liquid syntax (for example, `{{ incident.title }}`).
The description of the Jira issue. Supports Liquid syntax (for example, `{{ incident.summary }}`).
Assign the Jira issue to a user by email. Supports Liquid syntax.
Updates an existing ticket in Jira. You must reference the issue in the **Jira Issue to Update** field using `{{ incident.jira_issue_id }}`.
This action only works if a Jira issue has already been created and linked to the incident.
Reference to the existing Jira issue. Use `{{ incident.jira_issue_id }}` to dynamically target the issue linked to the current incident.
Updated title of the Jira issue. Supports Liquid syntax.
Updated description. Supports Liquid syntax.
Transition the issue to a new status. Options are pulled from the selected project and issue type.
Reassign the Jira issue to a different user. Supports Liquid syntax.
Creates a subtask under an existing Jira issue. Intended for **action items** or **sub-incidents**. The **Project Key** must match the one used when creating the parent issue.
Reference to the parent Jira issue. Use `{{ incident.jira_issue_id }}` to link the subtask to the current incident's issue.
Must match the project used to create the parent issue.
Title of the subtask. Supports Liquid syntax.
Description of the subtask. Supports Liquid syntax.
Assign the subtask to a user by email. Supports Liquid syntax.
***
### Jira Native Field Mapping
Some Jira fields behave differently than standard custom fields. This section explains how to correctly map Rootly fields to Jira's **native** fields.
These mappings go in the **Custom Fields Mapping** section of the Jira action, not the API Payload section.
Jira's native Labels field uses a different syntax than custom label-type fields.
**Map Rootly services to Jira Labels:**
```json theme={null}
"customfield_12345": {{ incident.service_slugs | join: ","}}
```
**Map a Rootly custom multi-select to Jira Labels:**
```json theme={null}
"customfield_10033": {{ incident.custom_fields | find: 'custom_field.slug', 'your_custom_field_slug' | get: 'selected_options' | map: 'value' | join: "," }}
```
Replace `customfield_12345` with your actual Jira field ID. Find field IDs in **Jira Settings → Issues → Custom Fields**.
Jira's native Team field is stored as a custom field but only allows a single team selection.
**Map a static Jira Team ID:**
```json theme={null}
"customfield_10001": ""
```
**Map Rootly's first team dynamically:**
```json theme={null}
"customfield_10001": "{{ incident.raw_groups[0] | get: 'description' }}"
```
This example assumes you store the corresponding Jira Team ID in the Rootly team's description field. Adjust based on how your teams are configured.
***
### Custom Fields Mapping
The **Custom Fields Mapping** section lets you map Rootly incident data to Jira custom fields dynamically.
#### What You Need
| Item | Where to Find It |
| ------------------- | --------------------------------------------------------------------------------------------------- |
| **Jira Field ID** | Jira Settings → Issues → Custom Fields → Click field → ID in URL (for example, `customfield_12345`) |
| **Field Type** | Same location, check the field type (text, select, multi-select, etc.) |
| **Rootly Property** | Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) |
For detailed instructions on finding Jira field IDs, see [Atlassian's documentation](https://confluence.atlassian.com/jirakb/how-to-find-id-for-custom-field-s-744522503.html).
#### Field Type Mappings
```json theme={null}
// Rootly native field → Jira text
"customfield_12345": "{{ incident.functionalities }}"
// Rootly custom field → Jira text
"customfield_12345": "{{ incident.custom_fields | find: 'custom_field.slug', 'your-slug' | get: 'selected_options' | map: 'value' }}"
```
Note the `{ "value": ... }` wrapper required by Jira:
```json theme={null}
// Rootly team name → Jira single select
"customfield_12345": { "value": "{{ incident.raw_groups | first | get: 'name' }}" }
// Rootly custom field → Jira single select
"customfield_12345": { "value": "{{ incident.custom_fields | find: 'custom_field.slug', 'your_slug' | get: 'selected_options' | map: 'value' }}" }
```
**Simple approach (Rootly custom multi-select):**
```json theme={null}
"customfield_12345": {{ incident.custom_fields | find: 'custom_field.slug', 'your_slug' | get: 'selected_options' | to_values }}
```
**Manual array building (Rootly native fields):**
```liquid theme={null}
{% assign functions = incident.functionalities %}
{% assign array = "" %}
{% for function in functions %}
{% assign item = '{"value":"' | append: function | append: '"}' %}
{% assign array = array | append: item | append: "," %}
{% endfor %}
{% capture final_array %}[{{ array | remove_last: ',' }}]{% endcapture %}
"customfield_12345": {{ final_array }}
```
For Jira custom fields of type "Labels" (different from the native Labels field):
```json theme={null}
// Rootly services → Jira custom labels
"customfield_12345": {{ incident.service_slugs | to_json }}
// Rootly custom multi-select → Jira custom labels
"customfield_10033": {{ incident.custom_fields | find: 'custom_field.slug', 'your_slug' | get: 'selected_options' | map: 'value' | to_json }}
```
```json theme={null}
"customfield_26117": {{ incident.custom_fields | find: 'custom_field.slug', 'your_slug' | get: 'selected_options.value' }}
```
Must use ISO 8601 format:
```json theme={null}
// Rootly incident start time → Jira datetime
"customfield_10030": "{{ incident.started_at | date: '%FT%T%:z' }}"
// Rootly custom datetime → Jira datetime
"customfield_26218": "{{ incident.custom_fields | find: 'custom_field.slug', 'your_slug' | get: 'selected_options.value' | date: '%Y-%m-%dT%H:%M:%S.%d%z' }}"
```
**Single user:**
```json theme={null}
{% assign jira_email = incident.roles | find: 'incident_role.slug', 'incident-commander' | get: 'user.email' %}
"customfield_20825": { "id": "{{ team.jira_users | where: 'email', jira_email | first | get: 'account_id' }}" }
```
**Multiple users:**
```json theme={null}
{% assign jira_email = incident.roles | find: 'incident_role.slug', 'incident-commander' | get: 'user.email' %}
"customfield_20825": [{ "id": "{{ team.jira_users | where: 'email', jira_email | first | get: 'account_id' }}" }]
```
#### How to Test Your Mapping
1. Create a test incident in Rootly
2. Run your workflow manually
3. Check the Jira issue to verify fields are populated correctly
4. If errors occur, go to **Workflows → Your Workflow → ... → View Runs** to see the error details
***
### API Payload
The **API Payload** section provides direct access to Jira's REST API for advanced field updates not available through Custom Fields Mapping.
API Payload uses Jira's [update issue REST API](https://developer.atlassian.com/server/jira/platform/updating-an-issue-via-the-jira-rest-apis-6848604/). Fields use verb-based operations: `set`, `add`, and `remove`.
#### When to Use API Payload
| Use Case | Use API Payload |
| ------------------------ | ----------------------------------- |
| Set priority dynamically | Yes |
| Add comments | Yes (Update Jira Issue action only) |
| Link issues together | Yes |
| Set native Labels field | Yes |
| Set Components field | Yes |
| Map custom fields | No, use Custom Fields Mapping |
#### API Payload Examples
```liquid theme={null}
{% if incident.severity_slug == 'sev0' %}
{ "priority": [ { "set": { "name" : "High" } } ] }
{% elsif incident.severity_slug == 'sev1' %}
{ "priority": [ { "set": { "name" : "Medium" } } ] }
{% elsif incident.severity_slug == 'sev2' %}
{ "priority": [ { "set": { "name" : "Low" } } ] }
{% endif %}
```
Add a comment to an existing Jira issue. Only works with the **Update Jira Issue** action.
```json theme={null}
{
"comment": [
{
"add": {
"body": "Incident {{ incident.title }} has been updated. Current status: {{ incident.status }}"
}
}
]
}
```
Comments can only be added to existing issues. Use this with the Update Jira Issue action, not Create.
**"Relates to" link:**
```json theme={null}
{
"issuelinks": [
{
"add": {
"type": { "name": "Relates", "outward": "relates to" },
"outwardIssue": { "id": "{{ incident.jira_issue_id }}" }
}
}
]
}
```
**Custom "Action item for" link:**
```json theme={null}
{
"issuelinks": [
{
"add": {
"type": { "name": "Action", "outward": "action item for" },
"outwardIssue": { "id": "{{ incident.jira_issue_id }}" }
}
}
]
}
```
```json theme={null}
{
"labels": [{ "set": ["incident", "production", "{{ incident.severity }}"] }]
}
```
```liquid theme={null}
{% assign components = incident.services %}
{
"components": [
{
"set": [
{% for component in components %}
{ "name": "{{ component }}" }{% unless forloop.last %},{% endunless %}
{% endfor %}
]
}
]
}
```
Component names must match exactly between Rootly and Jira. If a component doesn't exist in Jira, the update will fail.
#### API Payload Verbs
| Verb | Description | Example |
| -------- | ------------------------- | ------------------------------------------------ |
| `set` | Replace the current value | `{ "labels": [{ "set": ["label1"] }] }` |
| `add` | Add to current values | `{ "comment": [{ "add": { "body": "text" } }] }` |
| `remove` | Remove specific values | `{ "labels": [{ "remove": "old-label" }] }` |
***
### Best Practices
* **Name workflows clearly.** Use names like `Create Bug on High-Priority Incident` or `Update Jira Issue on Resolution` so the intent is obvious.
* **Keep logic simple.** Avoid overly complex conditions or chained automations — simpler workflows are easier to debug.
* **Test in a sandbox project.** Before applying to production, trigger test incidents to verify issues are created and updated as expected.
## Syncing Jira Changes Back to Rootly
1. Jira sends events to Rootly via webhook
2. Events appear as alerts on Rootly's **[Alerts page](https://rootly.com/account/alerts)**
3. Alert workflows process these events and create or update incidents
***
### Create an Alert Workflow
Go to **Workflows → Create Workflow** and select **Alert** as the workflow type.
Select **Alert Created** as the trigger. This fires whenever a new alert arrives in Rootly — including events from Jira.
Filter to only process Jira alerts so the workflow doesn't fire on unrelated alert sources. You can filter by source and by label:
* Set **Source** equals `Jira`
* Use label filters to narrow by event type or project:
* `event:jira:issue_created` — responds to new Jira issues
* `event:jira:issue_updated` — responds to Jira issue updates
* `project_key:YOUR_PROJECT` — (optional) limits to a specific Jira project
For more targeted filtering, use the **Payload** condition with JSON path syntax (for example, `$.issue.fields.issuetype.name`). You can preview your syntax using the [JSON Path Explorer](https://rootly.com/account/help/json-path-explorer).
Only a single payload field can be filtered at a time. Use label conditions as much as possible before falling back to payload filtering.
Choose **Create Incident** or **Update Incident** from the action picker depending on whether you want to open a new incident or update an existing one.
***
### Sync Actions
Creates a new Rootly incident from a Jira alert.
Use `{{ alert.data.* }}` to reference Jira fields when populating incident properties:
| Incident Field | Jira Source |
| -------------- | ------------------------------------------- |
| Title | `{{ alert.data.issue.fields.summary }}` |
| Summary | `{{ alert.data.issue.fields.description }}` |
**Link back to Jira** — Add this to Custom Field Mapping so Rootly knows which Jira issue this incident came from. This mapping is required if you later want to update the incident when the Jira issue changes.
```json theme={null}
{
"jira_issue_id": "{{ alert.data.issue.id }}",
"jira_issue_url": "https://your-instance.atlassian.net/browse/{{ alert.data.issue.key }}"
}
```
Updates an existing Rootly incident based on a Jira update. Rootly needs to know which incident corresponds to the incoming Jira event — configure these fields to match them:
| Field | Value |
| ------------------ | --------------------------- |
| Attribute to Match | `jira_issue_id` |
| Attribute Value | `{{ alert.data.issue.id }}` |
***
### Field Mapping Examples
Use Custom Field Mapping to dynamically set incident properties from Jira data.
Maps Jira priority levels to Rootly severity IDs. Adjust the priority names to match your Jira configuration.
```json theme={null}
{
{% if alert.data.issue.fields.priority.name == 'Highest' %}
"severity_id": "SEV0"
{% elsif alert.data.issue.fields.priority.name == 'High' %}
"severity_id": "SEV1"
{% elsif alert.data.issue.fields.priority.name == 'Medium' %}
"severity_id": "SEV2"
{% else %}
"severity_id": "SEV3"
{% endif %}
}
```
Maps Jira workflow statuses to Rootly incident statuses. Replace the Jira status names with your actual values.
```json theme={null}
{
{% if alert.data.issue.fields.status.name == 'To Do' %}
"status": "in_triage"
{% elsif alert.data.issue.fields.status.name == 'In Progress' %}
"status": "active"
{% elsif alert.data.issue.fields.status.name == 'Done' %}
"status": "resolved"
{% else %}
"status": "cancelled"
{% endif %}
}
```
Valid Rootly statuses: `in_triage`, `active`, `resolved`, `closed`, `cancelled`
Sets a Rootly custom field to a fixed value. Replace `form_field_id` with your actual field ID.
```json theme={null}
{
"form_field_selections_attributes": [{
"form_field_id": "YOUR_FIELD_ID",
"value": "Production"
}]
}
```
Pulls a value from a Jira custom field and sets it on the Rootly incident. Inspect the alert payload to find the correct field path.
```json theme={null}
{
"form_field_selections_attributes": [{
"form_field_id": "YOUR_FIELD_ID",
"value": "{{ alert.data.issue.fields.customfield_10001 }}"
}]
}
```
Find the correct JSON path by inspecting alert payloads on the **Alerts** page in Rootly.
For single or multi-select Rootly custom fields, use `selected_option_ids` instead of `value`.
```json theme={null}
{
"form_field_selections_attributes": [{
"form_field_id": "YOUR_FIELD_ID",
"selected_option_ids": ["option_id_1", "option_id_2"]
}]
}
```
***
## Troubleshooting
**Issue:** After completing OAuth, Jira doesn't show under Connected Apps.
**Solutions:**
* Ensure you completed the full OAuth consent flow without navigating away
* Confirm your Jira user has **admin** or **manage apps** permissions
* Log out of other Jira accounts and retry authorization
* Revoke the app in Jira (**Settings → Apps → Manage Apps**) and reconnect
**Issue:** Jira connects but no projects appear in Rootly.
**Solutions:**
* Verify your Jira account has **Browse Projects** permission
* Check project-level permissions for **Create Issues**, **Edit Issues**, and **Add Comments**
* Re-authenticate to refresh your permission scopes
**Issue:** Integration connects but Rootly can't create issues in Jira.
**Solutions:**
* Verify your Jira user has: Create Issues, Edit Issues, Assign Issues, Add Comments
* Check for required custom fields in Jira that aren't being populated by Rootly
* Confirm the issue type exists in the selected project
* Review Jira workflow validators that may block external issue creation
**Issue:** Jira events don't show on Rootly's Alerts page.
**Solutions:**
* Verify the webhook URL in Jira matches the one from Rootly
* Ensure **Exclude body** is NOT checked in the Jira webhook settings
* Confirm the webhook status is **Enabled**
* Check that your JQL filter (if used) includes the project you're testing with
### Debugging Workflows
To view error details, locate the workflow in Rootly, then select **... → View Runs → View**.
| Error | Cause | Fix |
| -------------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------- |
| `issue_id cannot be null.` | The Jira issue you're trying to update doesn't exist yet | Ensure the Create action runs before the Update action |
| `"customfield_12345": "Custom Field is required."` | A required Jira custom field isn't being populated | Add a mapping for the field, or make it optional in Jira |
| `unexpected token at '{ "customfield_10032": }'` | Custom mapping syntax is invalid | Fix your JSON syntax |
| `Specify a valid project ID or key` | The selected Project Key isn't available in the Jira instance | Reselect the Jira instance, then reselect the Project Key |
| `The issue type selected is invalid.` | The selected issue type doesn't exist in the project | Reselect the Project Key, then reselect the Issue Type |
***
### Debugging Sync
| Error | Cause | Fix |
| -------------------------------- | ---------------------------------- | ------------------------------------------------ |
| `unknown attribute for Incident` | Invalid field name or wrong syntax | Verify the field is enabled for workflow updates |
| `unexpected token` | Invalid JSON in custom mapping | Check your JSON syntax |
View error details: **Workflows → Your Workflow → ... → View Runs → View**
## Uninstall
To remove the Jira integration:
1. Go to **Configuration → Integrations** and find **Jira**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
Disconnecting Rootly does **not** remove the webhook from Jira. To stop Jira from sending events, you must also delete the webhook in Jira under **Settings → System → WebHooks**.
# Kubernetes Integration
Source: https://docs.rootly.com/integrations/kubernetes
Connect Kubernetes to Rootly to monitor cluster events across pods, deployments, and services, and surface them as pulses during incidents.
## Introduction
The Kubernetes integration connects Rootly with your Kubernetes clusters using an inbound webhook. Cluster events are captured via [kubewatch](https://github.com/robusta-dev/kubewatch) and forwarded to Rootly, where they appear as pulses on your incident timelines and service activity feeds.
With the Kubernetes integration, you can:
* Automatically track events from across your cluster as Rootly pulses in real time
* Correlate Kubernetes events with active incidents to surface infrastructure context fast
* Monitor a wide range of resource types including pods, deployments, services, nodes, and more
* Associate cluster events with Rootly services by matching the Kubernetes deployment name
This integration uses a **static webhook secret** rather than OAuth. Rootly generates a unique webhook URL and signing secret for your workspace — kubewatch sends events to this URL and Rootly verifies the signature on each request.
## Before You Begin
Before setting up the Kubernetes integration, make sure you have:
* A Rootly account with permission to manage integrations
* Access to your Kubernetes cluster to deploy or configure kubewatch
* `kubectl` or Helm available to apply configuration to your cluster
The Kubernetes integration relies on **kubewatch** to watch cluster events and forward them to Rootly. You will need to deploy and configure kubewatch in your cluster as part of the setup process.
## Installation
Navigate to the integrations page in your Rootly workspace and select **Kubernetes**.
Rootly will generate a unique **webhook URL** and **signing secret** for your workspace. Copy both — you will need them when configuring kubewatch.
Kubewatch is an open-source Kubernetes watcher maintained by Robusta. It watches for cluster events and forwards them to webhook endpoints.
An example ConfigMap is available at:
[kubewatch webhook config example](https://github.com/robusta-dev/kubewatch/blob/master/examples/conf/kubewatch.conf.webhook.yaml)
You only need to configure the **webhook handler** portion of kubewatch to integrate with Rootly. Other notification handlers (Slack, Teams, etc.) can be disabled.
In your kubewatch configuration, set the webhook URL to the one displayed in Rootly after creating the integration.
```yaml theme={null}
handler:
webhook:
url: "https://rootly.com/webhooks/kubernetes/YOUR_WEBHOOK_URL"
```
The webhook URL is unique to your Rootly workspace and contains your signing secret. Copy it directly from the Rootly integrations page after connecting — do not use a placeholder URL.
In your kubewatch configuration, enable the Kubernetes resource types you want to track. Rootly supports events from all of the following:
| Resource Type | Description |
| ----------------------- | ----------------------------------------- |
| `deployment` | Deployment creates, updates, and deletes |
| `replicationcontroller` | Replication controller events |
| `replicaset` | Replica set scaling and status events |
| `daemonset` | DaemonSet updates across nodes |
| `services` | Service creation and changes |
| `pod` | Pod scheduling, crashes, and terminations |
| `job` | Batch job completions and failures |
| `node` | Node readiness and condition changes |
| `clusterrole` | RBAC cluster role changes |
| `serviceaccount` | Service account events |
| `persistentvolume` | PersistentVolume binding and release |
| `namespace` | Namespace creation and deletion |
| `secret` | Secret creation and updates |
| `configmap` | ConfigMap changes |
| `ingress` | Ingress rule updates |
Once kubewatch is running and pointing at your Rootly webhook URL, cluster events will begin appearing as pulses in Rootly. You can verify delivery by checking the pulse feed or the incident timeline for any linked services.
## How Pulses Work
When kubewatch forwards a Kubernetes event to Rootly, it is recorded as a pulse with the following structure:
* **Source:** `k8s`
* **Summary:** `[k8s][{resource kind}] {event text}`
* **Labels:** resource kind, reason, action (update)
* **Refs:** resource name, namespace
Pulses are automatically associated with Rootly services where the service's **Kubernetes Deployment Name** field matches the event's resource name. Rootly uses a partial match, so a service named `api-server` will match events from deployments containing `api-server` in the name.
To link Kubernetes pulses to a service, set the **Kubernetes Deployment Name** field on the service in Rootly. This enables automatic correlation between cluster events and the services they affect.
## Troubleshooting
First, verify that kubewatch is running and healthy in your cluster (`kubectl get pods -n kubewatch`). Then check that the webhook URL in your kubewatch config matches exactly what is shown in Rootly — including the path and any query parameters. You can test delivery by checking kubewatch logs for outbound HTTP requests and any error responses.
Rootly matches events to services using the **Kubernetes Deployment Name** field. Navigate to the service in Rootly and confirm this field is populated with the deployment name you expect. The match is a partial text search, so the deployment name does not need to be an exact match, but it must be a substring of the resource name in the event.
A 401 response means the webhook secret does not match. The signing secret is embedded in the webhook URL — make sure you are using the full URL copied from the Rootly integrations page without modification. If you regenerate the integration, the URL will change and you will need to update kubewatch.
If pulse volume is too high, narrow down the resource types you have enabled in kubewatch. For example, disabling `secret` and `configmap` events will significantly reduce low-signal noise. You can also use kubewatch namespace filters to restrict monitoring to specific namespaces.
Kubewatch watches Kubernetes events — not container logs or crash states directly. Pod crash loops may or may not generate Kubernetes events depending on the crash behavior and your cluster version. For deeper crash detection, consider pairing this integration with a monitoring tool like Datadog or Prometheus Alertmanager.
## Uninstall
To remove the Kubernetes integration, navigate to the integrations page in Rootly, find the Kubernetes account, and select **Configure → Delete**. After removing the integration in Rootly, update or remove the kubewatch webhook configuration in your cluster to stop sending events to the now-inactive URL.
## Related Pages
Learn how Kubernetes cluster events appear as pulses in Rootly.
Set the Kubernetes Deployment Name on a service to link cluster events automatically.
Pair Kubernetes monitoring with Alertmanager for alert-driven incident response.
# Linear Integration
Source: https://docs.rootly.com/integrations/linear/linear
Sync Rootly incidents to Linear issues for seamless issue tracking, follow-up management, and engineering context from incident response to delivery.
Rootly's Linear integration connects your incident workflow to Linear. When an incident is declared, a Linear issue is automatically created. As the incident progresses, the issue stays in sync. When resolved, the Linear issue moves to Done.
Follow-up action items become Linear sub-issues under the parent incident issue, keeping post-incident work organized in one place.
## What You Can Do
Automatically create a Linear issue when an incident is declared, with title, description, severity, and assignee populated from incident data
Every follow-up action item created during an incident becomes a Linear sub-issue under the parent incident issue
When an incident resolves in Rootly, the linked Linear issue automatically moves to Done
Connect Rootly on-call schedules to Linear's Triage Responsibility so new issues auto-assign to whoever is on call
## How It Works
An incident is created in Rootly, either manually or via an alert from PagerDuty, Datadog, or another source.
Your configured workflow fires and creates a Linear issue in the specified team and project, with fields populated from incident data.
The Linear issue URL is automatically attached to the incident in Rootly. Teams can navigate between both systems.
As the incident progresses, action items become sub-issues. When the incident resolves, the Linear issue status updates automatically.
Connecting Linear to Rootly is a one-time OAuth setup that takes a few minutes. Once complete, Rootly can create and update Linear issues on your behalf as incidents move through their lifecycle — no manual copy-pasting between tools.
## Before You Begin
This setup involves authorizing Rootly inside your Linear workspace. Make sure you have the right access in both systems before starting — the OAuth flow will fail silently if your Linear account doesn't have the correct permissions.
You need:
* **Rootly:** Admin or Owner role to create and manage integrations
* **Linear:** Membership in at least one team with write permissions — read-only roles cannot create issues
## Installation
The connection is established through Linear's OAuth flow — Rootly redirects you to Linear, you approve access, and you're brought back to Rootly with the integration active. You won't need to handle any API keys or tokens manually.
Navigate to **Configuration → Integrations** in your Rootly dashboard. This is where all third-party integrations are managed.
Search for **Linear** in the integrations catalog and click **Setup** to begin the OAuth authorization flow.
You'll be redirected to Linear's authorization page. Review the requested permissions — Rootly needs write access to create and update issues on your behalf. Click **Allow Access** to proceed.
If you belong to multiple Linear workspaces, choose the one you want to connect to Rootly and click **Authorize**. You can only connect one workspace per Rootly account.
You'll be redirected back to Rootly and see a confirmation: *"Great! We've added that Linear account to your Rootly account!"* The integration is now active.
Linear is now connected. The [workflow actions](#workflow-actions) below configure automated issue creation for your incidents.
## Verify the Connection
Once connected, it's worth confirming the integration is active on both sides before building workflows.
**In Rootly:** The integration should show **Connected** status on the Integrations page.
**In Linear:** Open your workspace menu, go to **Settings → Integrations**, and confirm Rootly appears in your connected apps list. If it's missing, the OAuth flow may not have completed successfully — try reconnecting.
Once Linear is connected, you configure workflows that automatically create and update Linear issues as incidents move through their lifecycle. This page covers the three main workflow actions — creating issues, updating them, and creating sub-issues for action items — as well as setting up Triage Responsibility to keep your Linear queue synced with whoever is on call.
## Workflow Actions
### Create a Linear Issue
This is the core workflow: whenever an incident is declared in Rootly, a corresponding Linear issue is created automatically with incident data populated into the fields you configure.
Go to **Rootly → Workflows → Create Workflow**.
Select the event type that should trigger this workflow — for example, **Incident**, **Retrospective**, or **Pulse**.
Triggers define when this workflow fires. Choose the event that should kick off Linear issue creation.
| Trigger | When It Fires |
| ------------------------------- | ---------------------------------------- |
| **Incident Created** | A new incident opens |
| **Incident Updated** | Severity, status, or other fields change |
| **Incident Commander Assigned** | Someone takes ownership of the incident |
| **Manual Trigger** | Run on demand from the Rootly UI |
Conditions let you filter which incidents trigger the workflow — for example, only SEV-1 incidents, only specific teams, or only production environments.
Click **Add Action**, search for **Linear**, and select **Create Linear Issue**.
Fill in the fields to control how the Linear issue is created:
The Linear team where the issue will be created.
The initial workflow state for the issue — for example, **Todo** or **In Progress**.
Optional. Associate the issue with a specific Linear project.
Add labels to the issue for filtering and triage.
The issue title. Supports Liquid — use `{{ incident.title }}` to default to the incident title.
The issue body. Supports Liquid — use `{{ incident.summary }}` to populate with the incident summary.
The issue priority. Select **Auto** to automatically map incident severity to a corresponding Linear priority, or choose **Urgent**, **High**, **Medium**, or **Low** manually.
Email address of the Linear user to assign the issue to.
Optional. Map Linear custom fields using JSON. Values support Liquid, so you can populate Linear fields from Rootly context — in an [action item workflow](/workflows/action-item-workflows), reference the follow-up's [custom field values](/incidents/action-items/action-item-custom-fields):
```json theme={null}
{"customFieldKey": "{{ action_item.custom_fields_by_slug.your-field-slug }}"}
```
Click **Add**, give your workflow a name, and click **Create Workflow**.
### Update a Linear Issue
Use the **Update Linear Issue** action to keep the Linear issue in sync as the incident progresses — for example, moving it to Done when the incident resolves, or updating priority when severity changes.
Create a **separate workflow** for updates. Do not add the Update action to your Create workflow — they need to trigger on different events.
Configure the action with:
Use `{{ incident.linear_issue_id }}` to reference the issue that was created when the incident was declared.
Optional. JSON mapping of Linear custom fields, with Liquid support — same format as on the Create Linear Issue action.
Common use cases:
* Move to **Done** when the incident is resolved
* Update **priority** when severity escalates
* Change **assignee** as ownership transfers
* Sync a follow-up's [custom field values](/incidents/action-items/action-item-custom-fields) into Linear custom fields (in action item workflows, via `{{ action_item.custom_fields_by_slug.your-field-slug }}`)
### Create Linear Sub-Issues
To track action items as Linear sub-issues, create a separate workflow triggered by **Action Item Created** and use the **Create Linear Sub-Issue** action.
Use `{{ incident.linear_issue_id }}` to nest the sub-issue under the parent incident issue.
Use `{{ action_item.summary }}` to populate the sub-issue title from the action item.
The Create Linear Sub-Issue action also supports the **Custom fields mapping** input described above, so sub-issues can carry the action item's [custom field values](/incidents/action-items/action-item-custom-fields) into Linear.
This keeps all follow-up work organized under the parent incident issue in Linear.
***
### Triage Responsibility
Connect Linear's [Triage Responsibility](https://linear.app/docs/triage#triage-responsibility) feature to your Rootly on-call schedules so new Linear issues are automatically assigned to whoever is currently on call. This keeps your triage queue aligned with your incident response rotation.
Go to **Schedules** and click **Create Schedule**.
In the **Integrations** tab, toggle on **Sync with Linear**.
Give the schedule a name, add members, and click **Save**.
In Linear, navigate to **Settings → Teams** and select the team you want to configure.
Under **Workflow → Triage**, find **Triage responsibility** and select **Use schedule**. Choose the Rootly schedule you just created.
New Linear issues in triage will now be automatically assigned to whoever is on call in Rootly — no manual triage queue management needed.
## Troubleshooting
Confirm you completed the OAuth flow and granted Rootly access to your workspace. In Linear, go to **Settings → Integrations** and verify Rootly is listed and enabled. If it's missing or showing an error, disconnect the integration in Rootly and reconnect from scratch — the OAuth token may have expired or been revoked.
You must be a member of at least one Linear team with write permissions — read-only roles won't allow issue creation. If your workspace uses restricted teams, a Linear admin needs to add you before you can proceed. After your permissions are updated, restart the authorization flow so Linear returns the correct team list.
***
## Uninstall
To remove the Linear integration, go to **Configuration → Integrations**, find **Linear**, and click the **Connected** button to reveal the disconnect option.
Disconnecting stops all Linear-related workflows from running. Existing Linear issues created by Rootly are not affected.
# Looker
Source: https://docs.rootly.com/integrations/looker
Capture and share Looker dashboard snapshots directly in Rootly incident workflows and Slack channels to give responders fast access to business context.
## Overview
Rootly's Looker integration lets you capture snapshots of Looker dashboards during an incident and share them directly to the incident timeline or Slack channels. This keeps your team grounded in data during the response without leaving their incident workflow.
Capture a point-in-time snapshot of any Looker dashboard and attach it to the incident.
Automatically share dashboard snapshots to incident Slack channels so responders have the data they need instantly.
Post snapshots directly to the incident timeline to create a visual record of system state during the incident.
Trigger snapshot capture automatically via workflows — on incident creation, severity change, or any other event.
## Before You Begin
* You must be a Rootly admin to set up the integration
* You need a Looker instance URL and API credentials (Client ID and Client Secret)
* Use a **service account** in Looker rather than a personal account to prevent the integration from breaking if a user leaves
## Installation
In Rootly, go to **Configuration → Integrations** and find **Looker**. Click **Connect**.
In your Looker instance, navigate to **Admin → Users** and select the user (or service account) you want to use for the integration.
Scroll down to **API Keys** and click **New API Key** to generate a Client ID and Client Secret.
Rootly recommends using a **service account** rather than a personal user account to ensure the integration stays active if someone leaves your team.
Back in Rootly, enter your **Instance URL**, **Client ID**, and **Client Secret**, then click **Connect**.
Rootly will validate the credentials against your Looker instance before saving.
## Workflow Action
### Snapshot Looker Dashboard
Captures a snapshot of one or more Looker dashboards and optionally posts them to Slack or the incident timeline.
Select one or more Looker dashboards to snapshot. Populated from your connected Looker instance.
When enabled, attaches the snapshot to the incident timeline for a visual record of system state at the time of the snapshot.
Select one or more Slack channels to share the snapshot to. Use `{{ incident.slack_channel_id }}` to target the incident's dedicated channel.
## Uninstall
To remove the Looker integration:
1. Go to **Configuration → Integrations** and find **Looker**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
## Frequently Asked Questions
Your instance URL is the base URL you use to access Looker, for example `https://yourcompany.looker.com`. Remove any trailing slashes before entering it in Rootly.
The API user needs at minimum **see\_looks\_and\_dashboards** and **access\_data** permissions to allow Rootly to list and snapshot dashboards. For user-defined dashboards, **see\_user\_dashboards** is also required.
Yes. The **Dashboards** field supports selecting multiple dashboards. Each selected dashboard will be snapshotted and shared.
The dropdown is populated from your Looker instance at the time the workflow is configured. If a dashboard was recently created, try reconnecting the integration or refreshing the page. Also confirm the API user has access to view the dashboard.
## Related resources
* [Airtable](/integrations/airtable)
* [AWS EventBridge](/integrations/aws-eventbridge)
* [Fivetran](/integrations/fivetran)
# Mattermost
Source: https://docs.rootly.com/integrations/mattermost
Connect Mattermost to Rootly so responders can declare, manage, and coordinate incidents directly from Mattermost with channels and slash commands.
## Introduction
The Mattermost integration connects Rootly with your Mattermost workspace so responders can work from chat while Rootly keeps the incident record up to date.
This integration is best for teams that use Mattermost as a primary collaboration tool and want to manage incidents without constantly switching between Mattermost and the Rootly web app.
With the Mattermost integration, you can:
* Declare incidents directly from Mattermost with slash commands
* Automatically create a dedicated Mattermost channel for each incident
* Mitigate and resolve incidents from the incident channel
* Guide responders through a consistent incident workflow from chat
* Keep Rootly and Mattermost in sync during the incident lifecycle
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with permission to manage integrations
* Access to your Mattermost workspace
* Permission to create and configure an OAuth 2.0 application in Mattermost
You will need to register **both** of the following redirect URLs in Mattermost:
* `https://rootly.com/auth/mattermost/callback`\
Used when an admin installs the Mattermost integration in Rootly
* `https://rootly.com/auth/sign_in_mattermost/callback`\
Used when individual users connect their Mattermost account with `/incident connect`
## Installation
In Mattermost, navigate to **Menu > Integrations**, then open **OAuth 2.0** and create a new OAuth application.
In the Mattermost OAuth application, add both of the following redirect URLs:
`https://rootly.com/auth/mattermost/callback`
`https://rootly.com/auth/sign_in_mattermost/callback`
The first URL is used when an admin installs the Mattermost integration in Rootly. The second is used when individual users connect their Mattermost account with `/incident connect`.
After saving the OAuth application in Mattermost, copy the **client\_id** and **client\_secret** into the Mattermost integration settings in Rootly.
## Configuration
In Rootly, navigate to **Configuration** > **Integrations** > **Mattermost** > **Configure**.
In the configuration panel, you can define how Rootly works with Mattermost during incident creation and response.
Available options include:
* **Channel title** for incident channels
* Whether to **automatically create a Mattermost channel** when an incident is declared
* Whether incident channels should always be **private**
* Which fields appear in the **incident creation wizard**
* Which incident events should be posted into the Mattermost channel, including:
* Incident created
* Incident mitigated
* Incident resolved
* Incident cancelled
You can also control what data responders are asked to provide during incident creation so the Mattermost experience matches your team’s incident process.
## Connect Your Mattermost Account
Each user who wants to manage incidents from Mattermost must complete this step.
After the integration is installed, run `/incident connect` in Mattermost to start linking your Mattermost account to Rootly.
Rootly will respond with a bot message that includes a **Connect now** action.
Click **Connect now**, then click **Allow** to authorize access and finish linking your Mattermost account.
Once connected, you are ready to manage incidents in Rootly through Mattermost.
## Managing Incidents from Mattermost
Once your Mattermost account is connected, you can use slash commands to declare incidents, update incident status, and move through the incident workflow directly from Mattermost.
### Declare an Incident
To declare a new incident from Mattermost, use one of the following commands:
* `/incident new`
* `/incident create`
* `/incident declare`
You can run these commands in any Mattermost channel.
Mattermost prompts you to enter the incident details.
When the incident is created:
* A new incident is created in Rootly
* A dedicated Mattermost channel can be created automatically, depending on your configuration
### Mitigate an Incident
To mark an incident as mitigated, run either of the following commands in the incident-specific Mattermost channel:
* `/incident mitigate`
* `/incident mitigated`
These commands must be run from the Mattermost channel created for that incident.
### Resolve an Incident
To resolve an incident, run either of the following commands in the incident-specific Mattermost channel:
* `/incident resolve`
* `/incident resolved`
These commands must be run from the Mattermost channel created for that incident.
### View Available Commands
If you need a reminder of the available Mattermost commands, run:
* `/incident help`
This shows the current list of supported commands.
## Uninstall
To remove the Mattermost integration, go to the integrations panel and select **Configure** > **Delete**.
# Rootly MCP Server for AI assistants and IDEs
Source: https://docs.rootly.com/integrations/mcp-server
Connect AI assistants and IDEs to Rootly using the Model Context Protocol, with Code Mode, OAuth2, hosted, and self-hosted deployment options.
## Introduction
The Rootly MCP Server implements the [Model Context Protocol](https://modelcontextprotocol.io) to expose Rootly incident data and actions as tools that any MCP-compatible client can use. This means you can query incidents, check on-call schedules, find similar past incidents, and take action — all from within Cursor, Windsurf, Claude Code, Gemini CLI, or any other MCP-compatible environment.
The server dynamically generates tools from Rootly's OpenAPI specification, so it always reflects the current API surface. It also includes a set of intelligent tools built on top of that foundation:
**Two Rootly MCP surfaces.** This page covers the **Product MCP Server** at `https://mcp.rootly.com` — the one that exposes Rootly's API as tools your AI client can call. Rootly also publishes a **Docs MCP Server** at `https://docs.rootly.com/mcp` that exposes the documentation content for search and retrieval. The two are complementary: connect both and your AI client can answer "how do I configure X?" (docs MCP) and "now configure X for me" (product MCP) in the same session. Setup for the Docs MCP is at the bottom of this page — see [Rootly Docs MCP Server](#rootly-docs-mcp-server).
* **`find_related_incidents`** — uses TF-IDF similarity analysis to surface historically similar incidents
* **`suggest_solutions`** — mines past incident resolutions to recommend actionable next steps
* **`get_oncall_shift_metrics`** — shift counts, hours, and days on-call grouped by user, team, or schedule
* **`get_oncall_handoff_summary`** — current and next on-call plus incidents during shifts, with optional regional filtering
* **`get_shift_incidents`** — incidents during a time window, filterable by severity, status, and tags
## Authentication
The hosted MCP server supports two authentication methods:
### OAuth2 (Recommended)
MCP clients that support OAuth2 (Claude Desktop, Claude Code, Cursor) authenticate automatically — a browser window opens for you to log in to Rootly and grant access. No API token needed. Permissions are scoped through Rootly's granular OAuth2 consent screen.
OAuth2 is supported on all hosted transport endpoints: Streamable HTTP (`/mcp`), SSE (`/sse`), and Code Mode (`/mcp-codemode`).
### API Token
For clients that don't support OAuth2, or for local/self-hosted installations, use a Rootly API token. Generate one in **Account** > **Manage API keys** > **Generate New API Key**.
| Token Type | Access Level |
| -------------------------------- | ------------------------------------------------------ |
| **Global API Key** (recommended) | Full access across all teams, schedules, and incidents |
| **Team API Key** | Full read/write access scoped to a single team |
| **Personal API Key** | Inherits the permissions of the user who created it |
Tools like `get_oncall_handoff_summary` and `get_oncall_shift_metrics` require organization-wide visibility. A Global API Key is recommended for full functionality.
For local installation, you also need:
* Python 3.12 or higher
* The `uv` package manager
## Installation
Choose the deployment option that fits your team. The hosted option is the fastest way to get started and requires no local setup.
### Hosted (recommended)
Connect to Rootly's managed MCP server — always up to date, zero maintenance.
The standard hosted URL exposes the full tool surface by default. If you want a smaller remote profile, add `?tool_profile=slim` to the URL or send `X-Rootly-Tool-Profile: slim`.
**Transport Options:**
* **Code Mode (recommended):** `https://mcp.rootly.com/mcp-codemode`
* **Streamable HTTP:** `https://mcp.rootly.com/mcp`
* **SSE:** `https://mcp.rootly.com/sse`
**Use Code Mode.** Instead of registering \~200 individual tools — whose schemas are re-sent on every model turn — Code Mode exposes a compact set of meta-tools (`list_tools`, `tool_search`, `get_schema`, `tags`, `execute`). The model discovers the tools it needs and writes a short async Python block in `execute` that chains multiple `call_tool(...)` calls server-side, returning only the final result. This means dramatically lower token usage and fewer round-trips for multi-step work. It supports OAuth2 and API tokens identically to the other endpoints.
Connect Code Mode *instead of* the classic endpoints, not alongside them. If both surfaces are available to the same client, the model tends to call the classic tools directly and skip `execute` — so the full tool surface still loads and you lose the savings.
**With OAuth2 (recommended):**
```json theme={null}
{
"mcpServers": {
"rootly": {
"url": "https://mcp.rootly.com/mcp-codemode"
}
}
}
```
Your MCP client handles OAuth2 login automatically. No token configuration needed.
**With API Token:**
```json theme={null}
{
"mcpServers": {
"rootly": {
"url": "https://mcp.rootly.com/mcp-codemode",
"headers": {
"Authorization": "Bearer "
}
}
}
}
```
**Slim Profile (Hosted):**
```json theme={null}
{
"mcpServers": {
"rootly": {
"url": "https://mcp.rootly.com/mcp?tool_profile=slim",
"headers": {
"Authorization": "Bearer "
}
}
}
}
```
**Header Alternative:**
```json theme={null}
{
"mcpServers": {
"rootly": {
"url": "https://mcp.rootly.com/mcp",
"headers": {
"Authorization": "Bearer ",
"X-Rootly-Tool-Profile": "slim"
}
}
}
}
```
**SSE Alternative:**
```json theme={null}
{
"mcpServers": {
"rootly": {
"url": "https://mcp.rootly.com/sse",
"headers": {
"Authorization": "Bearer "
}
}
}
}
```
### Client-Specific Setup
#### Claude Code
**With OAuth2 (recommended):**
```bash theme={null}
claude mcp add --transport http rootly https://mcp.rootly.com/mcp-codemode
```
**With API Token:**
```bash theme={null}
claude mcp add --transport http rootly https://mcp.rootly.com/mcp-codemode \
--header "Authorization: Bearer YOUR_ROOTLY_API_TOKEN"
```
**Manual Configuration** - Create `.mcp.json` in your project root:
```json theme={null}
{
"mcpServers": {
"rootly": {
"type": "http",
"url": "https://mcp.rootly.com/mcp"
}
}
}
```
#### Cursor
Add to `.cursor/mcp.json` or `~/.cursor/mcp.json`:
**With OAuth2 (recommended):**
```json theme={null}
{
"mcpServers": {
"rootly": {
"url": "https://mcp.rootly.com/mcp"
}
}
}
```
**With API Token:**
```json theme={null}
{
"mcpServers": {
"rootly": {
"url": "https://mcp.rootly.com/mcp",
"headers": {
"Authorization": "Bearer "
}
}
}
}
```
#### Windsurf
Add to `~/.codeium/windsurf/mcp_config.json`:
```json theme={null}
{
"mcpServers": {
"rootly": {
"serverUrl": "https://mcp.rootly.com/mcp",
"headers": {
"Authorization": "Bearer "
}
}
}
}
```
#### Codex
Add to `~/.codex/config.toml`:
```toml theme={null}
[mcp_servers.rootly]
url = "https://mcp.rootly.com/mcp"
bearer_token_env_var = "ROOTLY_API_TOKEN"
```
#### Claude Desktop
Add to `claude_desktop_config.json`:
**With OAuth2 (recommended):**
```json theme={null}
{
"mcpServers": {
"rootly": {
"url": "https://mcp.rootly.com/mcp"
}
}
}
```
Claude Desktop handles OAuth2 login automatically — a browser window opens for you to authenticate with Rootly.
**With API Token (via mcp-remote):**
```json theme={null}
{
"mcpServers": {
"rootly": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://mcp.rootly.com/mcp",
"--transport",
"http",
"--header",
"Authorization: Bearer "
]
}
}
}
```
#### Gemini CLI
Install as an extension:
```bash theme={null}
gemini extensions install https://github.com/Rootly-AI-Labs/Rootly-MCP-server
```
Or configure manually in `~/.gemini/settings.json`:
```json theme={null}
{
"mcpServers": {
"rootly": {
"command": "uvx",
"args": ["--from", "rootly-mcp-server", "rootly-mcp-server"],
"env": {
"ROOTLY_API_TOKEN": ""
}
}
}
}
```
#### Slack (Slackbot)
Connect the Rootly MCP server to [Slack's Slackbot MCP client](https://docs.slack.dev/ai/slackbot-mcp-client/) so your team can query Rootly from a Slackbot DM. No changes to the MCP server are required — you point Slackbot at the hosted endpoint and authenticate with a Rootly OAuth application.
**Prerequisite:** Slack AI features must be enabled for your workspace and app. The **MCP Servers** configuration and the Slackbot **Apps** connection flow only appear when Slack's AI / agent features are turned on.
Use the **Code Mode** endpoint (`https://mcp.rootly.com/mcp-codemode`) for Slack — it exposes a compact tool surface and keeps token usage low.
**1. Register a Rootly OAuth application**
In Rootly, open your **OAuth Applications** settings and create a new application:
* **Grant Type:** Authorization Code (user login via browser redirect — *not* Client Credentials)
* **Redirect URI:** `https://oauth2.slack.com/external/auth/callback`
* **Scopes:** the minimum your use case needs, for example `openid` and `ir.incidents:read`. Keep this list small.
* **Use PKCE:** enabled
* **Use HTTP Basic Authentication:** enabled
Save the application and note its **Client ID** and **Client Secret**.
**2. Configure the Slack app**
In your Slack app ([api.slack.com/apps](https://api.slack.com/apps) → **Features → MCP Servers**), add the Rootly server using manual OAuth:
```yaml theme={null}
mcp_servers:
- name: rootly
url: https://mcp.rootly.com/mcp-codemode
auth_type: manual_auth
external_auth_providers:
- client_id:
client_secret: # store as a Slack secret / env var
authorization_url: https://rootly.com/oauth/authorize
token_url: https://rootly.com/oauth/token
scope: openid ir.incidents:read # must match the Rootly app's scopes
use_pkce: true
token_url_config:
use_basic_auth_scheme: true # must match "Use HTTP Basic Authentication" on the Rootly app
identity_config:
url: https://api.rootly.com/v1/users/me
account_identifier: $.data.id
```
Add the `mcp:connect` bot scope under **OAuth & Permissions**, then install (or reinstall) the app to your workspace.
**3. Connect and use**
Open a direct message with Slackbot, click **Apps**, and connect the Rootly server. You'll be redirected to log in to Rootly and grant access. Once connected, ask Slackbot in natural language, for example *"list recent Rootly incidents."*
The Slack `scope` and the Rootly application's granted scopes must match, and PKCE and HTTP Basic Authentication must be enabled on both sides. Start with a minimal scope set — requesting a large number of scopes at once can cause the authorization step to fail.
### Local Installation
The package is downloaded automatically when you first open your editor. Local installation provides additional security controls not available in the hosted version.
**With `uv`:**
```json theme={null}
{
"mcpServers": {
"rootly": {
"command": "uv",
"args": ["tool", "run", "--from", "rootly-mcp-server", "rootly-mcp-server"],
"env": {
"ROOTLY_API_TOKEN": "",
"ROOTLY_MCP_ENABLE_WRITE_TOOLS": "true"
}
}
}
}
```
**With `uvx`:**
```json theme={null}
{
"mcpServers": {
"rootly": {
"command": "uvx",
"args": ["--from", "rootly-mcp-server", "rootly-mcp-server"],
"env": {
"ROOTLY_API_TOKEN": ""
}
}
}
}
```
#### Security Controls (Local Only)
Local installations support granular permission controls through environment variables:
**Default Mode (All Tools):**
```json theme={null}
{
"env": {
"ROOTLY_API_TOKEN": ""
// All tools available by default, matching hosted behavior
}
}
```
**Read-Only Mode (Restricted):**
```json theme={null}
{
"env": {
"ROOTLY_API_TOKEN": "",
"ROOTLY_MCP_ENABLE_WRITE_TOOLS": "false"
}
}
```
**Restrict to Specific Tools:**
```json theme={null}
{
"env": {
"ROOTLY_API_TOKEN": "",
"ROOTLY_MCP_ENABLE_WRITE_TOOLS": "true",
"ROOTLY_MCP_ENABLED_TOOLS": "createIncident,getIncident,listTeams,getCurrentUser"
}
}
```
**Full Access by Default** — Local installations match hosted behavior with all tools available. Use `ROOTLY_MCP_ENABLE_WRITE_TOOLS=false` to restrict to read-only mode.
**Environment Variables:**
| Variable | Description | Default |
| ------------------------------- | ------------------------------------------- | ------------------- |
| `ROOTLY_API_TOKEN` | Your Rootly API authentication token | Required |
| `ROOTLY_MCP_ENABLE_WRITE_TOOLS` | Enable write operations (create, update) | `true` |
| `ROOTLY_MCP_ENABLED_TOOLS` | Comma-separated allowlist of specific tools | All available tools |
**Example: Minimal Write Access for Automation:**
```json theme={null}
{
"env": {
"ROOTLY_API_TOKEN": "",
"ROOTLY_MCP_ENABLE_WRITE_TOOLS": "true",
"ROOTLY_MCP_ENABLED_TOOLS": "createIncidentActionItem,updateIncidentFormFieldSelection,listIncidents,getIncident"
}
}
```
This configuration allows only creating action items and updating form fields — perfect for automation that needs to add findings without modifying incident status or severity.
**Discovering Available Tools:**
To see all available tool names for your configuration:
```bash theme={null}
ROOTLY_API_TOKEN= \
uvx --from rootly-mcp-server rootly-mcp-server --list-tools
```
With write tools enabled:
```bash theme={null}
ROOTLY_API_TOKEN= \
ROOTLY_MCP_ENABLE_WRITE_TOOLS=true \
uvx --from rootly-mcp-server rootly-mcp-server --list-tools
```
### Self-Hosted
For organizations that need full control over infrastructure or data flow:
```bash theme={null}
git clone https://github.com/Rootly-AI-Labs/Rootly-MCP-server
cd Rootly-MCP-server
uv pip install .
```
Both hosted and self-hosted deployments expose the same curated tool surface by default, including write-enabled tools. To restrict to read-only tools, start the server with `--no-enable-write-tools` or set `ROOTLY_MCP_ENABLE_WRITE_TOOLS=false`.
To expose only a specific subset of MCP tools, set `ROOTLY_MCP_ENABLED_TOOLS` (or pass `--enabled-tools`) with a comma-separated allowlist of exact tool names.
**Discover available tool names:**
```bash theme={null}
ROOTLY_API_TOKEN= \
uv run python -m rootly_mcp_server --list-tools
```
**Smoke-test a self-hosted allowlist:**
```bash theme={null}
ROOTLY_API_TOKEN= \
ROOTLY_MCP_ENABLED_TOOLS=list_incidents,getIncident,get_server_version \
uv run python -m rootly_mcp_server --transport streamable-http --log-level ERROR
```
Then connect an MCP client to `http://127.0.0.1:8000/mcp` and verify `tools/list` returns only the specified tools.
**Run with Docker (Streamable HTTP):**
```bash theme={null}
docker run -p 8000:8000 \
-e ROOTLY_TRANSPORT=streamable-http \
-e ROOTLY_API_TOKEN= \
-e ROOTLY_MCP_ENABLE_WRITE_TOOLS=true \
rootly-mcp-server
```
**Run with Docker (SSE):**
```bash theme={null}
docker run -p 8000:8000 \
-e ROOTLY_TRANSPORT=sse \
-e ROOTLY_API_TOKEN= \
rootly-mcp-server
```
**Run with Docker (Dual Transport + Code Mode):**
```bash theme={null}
docker run -p 8000:8000 \
-e ROOTLY_TRANSPORT=both \
-e ROOTLY_API_TOKEN= \
rootly-mcp-server
```
The MCP server is now connected. Your MCP client can call Rootly tools to list incidents, check on-call schedules, find related incidents, and more.
**Alternative: Rootly CLI** — For terminal-based workflows, check out the [Rootly CLI](/integrations/cli) which provides direct command-line access to incidents, alerts, and on-call operations.
## Available Tools
The MCP server exposes **200+ tools** dynamically generated from Rootly's OpenAPI specification, plus custom agentic tools for intelligent incident analysis.
* **Hosted default:** full tool surface
* **Hosted slim profile:** about 70 high-usage tools via `?tool_profile=slim`
* **Local and self-hosted default:** full tool surface
* **Exact custom subset:** use `ROOTLY_MCP_ENABLED_TOOLS` to expose only a specific allowlist
### Custom Agentic Tools
* **`check_oncall_health_risk`** — detects workload health risk in scheduled responders
* **`check_responder_availability`** — checks responder availability
* **`collect_incidents`** — collects incident data with filtering
* **`createIncident`** — create incidents with scoped fields for agent workflows
* **`create_override_recommendation`** — suggests on-call override recommendations
* **`find_related_incidents`** — uses TF-IDF similarity to find historically similar incidents
* **`getIncident`** — retrieve single incidents with PIR-related fields
* **`get_alert_by_short_id`** — get alerts using short IDs
* **`get_oncall_handoff_summary`** — complete handoff information
* **`get_oncall_schedule_summary`** — schedule overview
* **`get_oncall_shift_metrics`** — comprehensive shift analytics
* **`get_server_version`** — server version information
* **`get_shift_incidents`** — incidents during specific time periods
* **`list_endpoints`** — available API endpoints
* **`list_incidents`** — incident listing with filters
* **`list_shifts`** — on-call shift information
* **`search_incidents`** — advanced incident search
* **`suggest_solutions`** — mines past resolutions for actionable recommendations
* **`updateIncident`** — scoped incident updates for summary and retrospective progress
### OpenAPI-Generated Tools
The server also includes all standard Rootly API operations — covering alerts, escalation policies, schedules, services, teams, workflows, dashboards, playbooks, post-incident reviews, and more. Security-sensitive operations (API key management, user creation/deletion, role management, webhook configuration) and delete operations are excluded from the default tool surface.
To see the exact tools available under your configuration:
```bash theme={null}
ROOTLY_API_TOKEN= \
uvx --from rootly-mcp-server rootly-mcp-server --list-tools
```
For the complete tool inventory and pre-built workflow subsets (Incident Response, On-Call Management, Monitoring & Alerting, Post-Incident Analysis, Analytics & Reporting), see the [README on GitHub](https://github.com/Rootly-AI-Labs/Rootly-MCP-server#supported-tools).
## Workflow-Focused Tool Subsets
With 200+ tools available by default, you can either use the hosted slim profile or configure focused subsets for optimal AI agent performance using `ROOTLY_MCP_ENABLED_TOOLS`.
For hosted clients that want the smaller remote profile without maintaining a custom allowlist, use `https://mcp.rootly.com/mcp?tool_profile=slim` or send `X-Rootly-Tool-Profile: slim`.
Pre-built subsets are available for:
| Subset | Tools | Use Case |
| -------------------------- | ----- | ------------------------------------------------- |
| **Incident Response** | 25 | Emergency responders and incident commanders |
| **On-Call Management** | 35 | Schedule coordinators and on-call managers |
| **Monitoring & Alerting** | 41 | Platform teams setting up observability |
| **Post-Incident Analysis** | 30 | SREs doing retrospectives and process improvement |
| **Analytics & Reporting** | 15 | Leadership and metrics teams (read-only) |
Copy-paste ready tool lists for each subset are maintained in the [GitHub README](https://github.com/Rootly-AI-Labs/Rootly-MCP-server#workflow-focused-tool-subsets).
You can also run multiple MCP instances with different tool subsets for different teams:
```json theme={null}
{
"mcpServers": {
"rootly-incident-response": {
"command": "uvx",
"args": ["--from", "rootly-mcp-server", "rootly-mcp-server"],
"env": {
"ROOTLY_API_TOKEN": "",
"ROOTLY_MCP_ENABLED_TOOLS": ""
}
}
}
}
```
## MCP Resources
AI agents can access these resources for situational awareness:
| Resource | Description |
| -------------------------- | ---------------------------------------------------- |
| `incident://{incident_id}` | Detailed incident information for specific incidents |
| `team://{team_id}` | Team details including name, color, and metadata |
| `rootly://incidents` | List of recent incidents for quick reference |
| `rootly://oncall-status` | Current on-call status across all schedules |
| `rootly://workflow-guide` | Step-by-step workflow guidance for common operations |
Example usage: *"Check the current on-call status"* → AI reads `rootly://oncall-status` resource.
## Example Skills
### Rootly Incident Responder
The MCP server includes a pre-built [Rootly Incident Responder skill](https://github.com/Rootly-AI-Labs/rootly-mcp-server/blob/main/examples/skills/rootly-incident-responder.md) for Claude Code that demonstrates a complete incident response workflow:
* Analyzes production incidents with full context
* Finds similar historical incidents using ML-based similarity matching
* Suggests solutions based on past successful resolutions
* Coordinates with on-call teams across timezones
* Correlates incidents with recent code changes and deployments
* Creates action items and remediation plans
* Provides confidence scores and time estimates
**Quick Start:**
```bash theme={null}
# Copy the skill to your project
mkdir -p .claude/skills
curl -o .claude/skills/rootly-incident-responder.md \
https://raw.githubusercontent.com/Rootly-AI-Labs/rootly-mcp-server/main/examples/skills/rootly-incident-responder.md
# Then in Claude Code, invoke it:
# @rootly-incident-responder analyze incident #12345
```
## Example Tools
### On-Call Shift Metrics
Get shift counts, hours, and days on-call for any time period, grouped by user, team, or schedule:
```python theme={null}
get_oncall_shift_metrics(
start_date="2025-10-01",
end_date="2025-10-31",
group_by="user"
)
```
### On-Call Handoff Summary
Get current and next on-call responders plus incidents that occurred during their shifts. Supports optional regional filtering to show only responders on-call during business hours in a given timezone:
```python theme={null}
get_oncall_handoff_summary(
team_ids="team-1,team-2",
timezone="America/Los_Angeles"
)
# Show only APAC on-call during APAC business hours
get_oncall_handoff_summary(
timezone="Asia/Tokyo",
filter_by_region=True
)
```
### Shift Incidents
Incidents during a time window, filterable by severity, status, and tags. Returns an incident list plus a summary with counts and average resolution time:
```python theme={null}
get_shift_incidents(
start_time="2025-10-20T09:00:00Z",
end_time="2025-10-20T17:00:00Z",
severity="critical",
status="resolved",
tags="database,api"
)
```
## On-Call Health Integration
The MCP server integrates with [On-Call Health](https://oncallhealth.ai) to detect workload health risk in scheduled responders. Set the `ONCALLHEALTH_API_KEY` environment variable to enable it:
```json theme={null}
{
"mcpServers": {
"rootly": {
"command": "uvx",
"args": ["--from", "rootly-mcp-server", "rootly-mcp-server"],
"env": {
"ROOTLY_API_TOKEN": "your_rootly_token",
"ONCALLHEALTH_API_KEY": "och_live_your_key"
}
}
}
}
```
Then call:
```python theme={null}
check_oncall_health_risk(
start_date="2026-02-09",
end_date="2026-02-15"
)
```
Returns at-risk users who are scheduled on-call, recommended safe replacements, and action summaries.
## Troubleshooting
Some MCP clients require a restart after adding a new server configuration. Fully restart your editor or AI assistant after saving the configuration. Also confirm that the JSON configuration is valid — a missing comma or bracket will silently prevent the server from loading.
Confirm that the API token is active and has not been revoked. Go to **Account** > **Manage API keys** in Rootly and verify the key exists. Also check that the token is passed correctly — for hosted configurations it goes in the `Authorization` header as `Bearer `, and for local/self-hosted it goes in the `ROOTLY_API_TOKEN` environment variable.
Tools like `get_oncall_handoff_summary` and `get_oncall_shift_metrics` require visibility across all teams. If results are incomplete, your API token may be scoped to a single team. Switch to a Global API Key for full access.
Confirm that Python 3.12 or higher is installed (`python --version`) and that `uv` is available (`uv --version`). If using `uvx`, the package is downloaded on first run — ensure you have network access. For proxy environments, you may need to configure `uv` proxy settings.
The `check_oncall_health_risk` tool only appears when `ONCALLHEALTH_API_KEY` is set. Confirm the environment variable is present in your MCP server configuration and that the key is valid at oncallhealth.ai.
## Rootly Docs MCP Server
In addition to the Product MCP server documented above, Rootly publishes a **Docs MCP Server** that exposes the content of [docs.rootly.com](https://docs.rootly.com) for AI-driven search and retrieval. Connect it to your AI client and the model can ground its answers in current Rootly documentation — no copy-pasting docs into prompts, no stale training data.
### What It's For
| Question your AI client is being asked | Which MCP answers it |
| ------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| *"How do I configure Datadog alert routing in Rootly?"* | **Docs MCP** — searches the relevant pages and returns the answer |
| *"What's the difference between Alert Deduplication and Alert Grouping?"* | **Docs MCP** — surfaces the comparison page |
| *"What does the Slack Channel Created workflow trigger fire on?"* | **Docs MCP** |
| *"Page the on-call for the payments team."* | **Product MCP** — calls the Rootly API |
| *"Create a SEV1 incident with these details."* | **Product MCP** |
| *"Show me incidents from last week with Datadog as a source."* | **Product MCP** |
Connecting both gives the same AI session the ability to answer how-to questions from the docs *and* take action against your Rootly account.
### What The Docs MCP Exposes
Two tools and one auto-generated skill resource:
| Capability | Type | What it does |
| ------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `search_rootly` | Tool | Semantic search across the Rootly knowledge base. Returns titles, links, and excerpts of the most relevant pages for a natural-language query. Best for *"how do I…"* and conceptual questions. |
| `query_docs_filesystem_rootly` | Tool | Read-only shell-like access to a virtualized filesystem of every Rootly docs page. Supports `rg` (ripgrep), `grep`, `find`, `tree`, `ls`, `cat`, `head`, `tail`, `stat`, `wc`, `sort`, `uniq`, `cut`, `sed`, `awk`, `jq`. Best when your AI needs exact keyword matching, structural exploration of the docs tree, or the full content of a specific page. |
| `mintlify://skills/rootly` | Resource | Auto-generated *Rootly Skill Reference* — a Markdown document that tells your AI client when to reach for Rootly (incident management, on-call paging, alert routing, etc.), where the API and CLI live, and the canonical entry points for each task type. Your AI client reads this once at session start for grounding. |
### Installation
The Docs MCP is hosted by Mintlify at `https://docs.rootly.com/mcp` and uses Streamable HTTP transport with the standard MCP protocol (version `2024-11-05`). It's read-only and unauthenticated — no API key, no Rootly account required.
#### Claude Code
```bash theme={null}
claude mcp add --transport http rootly-docs https://docs.rootly.com/mcp
```
#### Cursor
Add to `.cursor/mcp.json` or `~/.cursor/mcp.json`:
```json theme={null}
{
"mcpServers": {
"rootly-docs": {
"url": "https://docs.rootly.com/mcp"
}
}
}
```
#### Claude Desktop
Add to `claude_desktop_config.json`:
```json theme={null}
{
"mcpServers": {
"rootly-docs": {
"url": "https://docs.rootly.com/mcp"
}
}
}
```
#### Windsurf
Add to `~/.codeium/windsurf/mcp_config.json`:
```json theme={null}
{
"mcpServers": {
"rootly-docs": {
"serverUrl": "https://docs.rootly.com/mcp"
}
}
}
```
### Running Both MCPs Together
If you already have the Product MCP configured, add the Docs MCP as a *second* entry under `mcpServers` — don't replace the existing `rootly` block. The two servers don't conflict, and your AI client routes queries to whichever surface is relevant.
**Preserve your existing Product MCP configuration.** If your current `rootly` entry uses `Authorization` headers, `?tool_profile=slim`, or any other query params, keep them exactly as they are. Only add the new `rootly-docs` stanza. Copy-pasting a stripped-down `rootly` block from any example — including the one below — will silently drop your auth and tool-profile settings.
Add this stanza alongside your existing `rootly` block:
```json theme={null}
{
"mcpServers": {
"rootly-docs": {
"url": "https://docs.rootly.com/mcp"
}
}
}
```
### Verifying the Connection
The most reliable check is **tool discovery in your client**. After connecting, confirm the Docs MCP is registered by looking for these tools in your client's MCP or tools list:
* `search_rootly`
* `query_docs_filesystem_rootly`
If both tools appear, the connection is working. If they don't, restart your client — most MCP clients only re-scan configuration at startup.
As a functional test, ask your AI client a question whose answer requires current Rootly docs — for example: *"Using the Rootly docs, what triggers are available on an incident workflow?"* A working Docs MCP surfaces the trigger list from [`/workflows/incident-workflows`](/workflows/incident-workflows). Note that some clients don't cite sources by default, so use tool discovery above as the primary check.
The client-specific commands above target current stable versions of Claude Code, Cursor, Claude Desktop, and Windsurf as of publication. If your client uses a different pattern for adding a Streamable HTTP MCP server, follow its documentation and set the URL to `https://docs.rootly.com/mcp` (transport: Streamable HTTP; auth: none).
***
## Related Pages
Browse the full Rootly API — all endpoints exposed by the MCP server come from here.
Learn about Rootly's built-in AI features for incident management.
Source code, issues, and release notes for the Rootly MCP Server.
# Microsoft Teams
Source: https://docs.rootly.com/integrations/microsoft-teams
Connect Microsoft Teams to Rootly to create incident channels, run workflow actions, and start Teams meetings from incidents.
Rootly's Microsoft Teams integration automates incident communication and collaboration. When an incident starts, Rootly can create a dedicated Teams channel, invite responders, and post real-time updates. You can also create Microsoft Teams meetings directly from incidents for live collaboration.
Automatically create dedicated Teams channels for each incident with responders invited
Post incident status changes, severity updates, and key events to Teams channels
Create Microsoft Teams meetings for live incident collaboration with one click
Control which events trigger Teams notifications using workflow conditions
***
## How It Works
Authorize Rootly to access your Teams workspace via OAuth.
Add the Rootly app to your Teams workspace to enable channel creation and messaging.
Set up workflows to automatically create channels, send messages, or start meetings when incidents occur.
***
## Before You Begin
**Before you start:**
* Rootly account with Admin permissions
* Microsoft Teams account with access to the workspace you want to connect
* Ability to install apps in your Teams workspace (or admin approval from your Microsoft 365 admin)
Rootly recommends connecting with a **service account** rather than a personal account. This ensures the integration stays active if team members leave your organization.
***
## Installation
Setting up the Microsoft Teams integration involves two steps that work together. First, you authorize Rootly via OAuth so it can call the Microsoft Teams API on your behalf. Then, you install the Rootly bot directly inside Teams so it can create channels and post messages. Both steps are required — OAuth alone isn't enough to create channels or send messages.
### Part 1: Connect via OAuth
The OAuth flow grants Rootly permission to interact with your Microsoft Teams workspace through the API. You'll be redirected to Microsoft to sign in and approve the required permissions, then returned to Rootly automatically.
In Rootly, go to **Configuration → Integrations** and search for **Microsoft Teams**.
Click **Setup** on the Microsoft Teams integration to begin the OAuth flow.
You'll be redirected to Microsoft. Select your Microsoft 365 work account — this should be the service account you intend to use for the integration.
Microsoft will show you the permissions Rootly is requesting. Review them and click **Accept** to grant access.
After approving, you'll be redirected back to Rootly. A success message confirms the integration is connected.
Microsoft Teams is now connected to Rootly.
#### Required OAuth Permissions
| Permission | Purpose |
| ------------------------------------------- | ----------------------------------------------------------- |
| `offline_access` | Keeps the Rootly → Teams connection active between sessions |
| `User.Read` | Identifies the account connecting to Rootly |
| `Team.ReadBasic.All` | Lets Rootly see your Teams and channels |
| `ChatMessage.Send` | Rootly can post messages in chats and channels |
| `Channel.Create` | Rootly can create incident channels |
| `Channel.ReadBasic.All` | Read channel names and descriptions |
| `ChannelMessage.Send` | Rootly can send channel messages |
| `ChannelMessage.ReadWrite` | Rootly can update messages it posts |
| `ChannelSettings.ReadWrite.All` | Allows Rootly to manage channel settings |
| `ChannelMember.ReadWrite.All` | Rootly can add and remove users in incident channels |
| `TeamsTab.ReadWriteSelfForChat` | Rootly can install tabs in chats |
| `TeamsTab.ReadWriteSelfForTeam` | Rootly can install tabs in teams |
| `TeamsAppInstallation.ReadWriteSelfForTeam` | Rootly can install itself in teams |
| `TeamsAppInstallation.ReadWriteSelfForChat` | Rootly can install itself in chats |
| `Chat.Create` | Rootly can create group and one-on-one chats |
| `Chat.ReadWrite` | Rootly can read and send messages in chats |
***
### Part 2: Install the Rootly Bot
OAuth gives Rootly API access, but channel creation and messaging also require the Rootly bot to be present inside Microsoft Teams. Without the bot installed, workflows that create channels or send messages will fail. You install it directly from the Teams app store.
In Microsoft Teams, click **Apps** in the left sidebar and search for **Rootly**.
Click **Add** on the Rootly app listing.
Select the team where you want to install Rootly. Rootly recommends starting with the General channel of your primary incident response team.
The Rootly bot is now installed in your team and ready to create channels and send messages.
You'll need to repeat the bot installation for each team where you want Rootly to create incident channels. The service account must be a member of each team.
***
## Verify Installation
Once both parts are complete, confirm everything is working before setting up workflows:
1. **Check Rootly** — The integration status shows **Connected** on the integrations page
2. **Check Teams** — The Rootly app appears in your team's installed apps
3. **Test end-to-end** — Create a test incident in Rootly and verify a Teams channel is created automatically
If channels aren't being created, check your workflow configuration first. The bot must be installed in the specific team referenced in the workflow action.
***
## Microsoft Teams Meeting
The **Microsoft Teams Meeting** integration is a separate OAuth connection that enables creating video meetings directly from Rootly incidents. It uses a different set of permissions than the main Teams integration and must be connected independently — even if you've already set up the main Teams integration.
Once connected, a **Create a Microsoft meeting** button appears in the incident header, letting anyone on the response team spin up a live video call with one click.
### Setup
1. Go to **Configuration → Integrations** and search for **Microsoft Teams Meeting**
2. Click **Setup** and sign in with your Microsoft 365 work account
3. Approve the requested permissions
4. Once connected, the **Create a Microsoft meeting** button will appear on every incident
Rootly recommends connecting with a **service account** so the meeting integration stays active if a user leaves your organization.
### Required OAuth Permissions
| Permission | Purpose |
| -------------------------- | -------------------------------------------------------------------------- |
| `offline_access` | Required for OAuth authentication |
| `User.Read` | Identifies the account connecting to Rootly |
| `OnlineMeetings.ReadWrite` | Allows Rootly to create online meetings on behalf of the connected account |
### Uninstall the Meeting Integration
1. Log into your **Microsoft Teams Meeting** account
2. Click **Manage → Installed Apps** or search for the **Rootly** app
3. Click the **Rootly** app and click **Uninstall**
***
## Workflows
Auto-create Teams channels at incident start using built-in settings
Build workflows with triggers, conditions, and multiple Teams actions
***
### Available Actions
| Action | What It Does |
| ------------------------------------------- | -------------------------------------------------------------- |
| **Create Microsoft Teams Channel** | Creates a new channel for the incident |
| **Create Microsoft Teams Chat** | Creates a group or one-on-one chat |
| **Add Microsoft Teams Tab** | Adds a tab to the incident channel |
| **Archive Microsoft Teams Channel** | Archives the incident channel |
| **Rename Microsoft Teams Channel** | Changes the channel name |
| **Invite Users to Microsoft Teams Channel** | Invites users to a private incident channel |
| **Send Microsoft Teams Message** | Posts a message to a Teams channel |
| **Send Microsoft Teams Attachments** | Sends attachments to a Teams channel |
| **Create Microsoft Teams Meeting** | Starts a video meeting (requires separate Meeting integration) |
***
### Create a Workflow
Go to **Rootly → Workflows → Create Workflow**.
Select the workflow type that matches your use case (for example, Incident, Retrospective, or Pulse).
Triggers define when this workflow runs.
| Trigger | When It Fires |
| ------------------------------- | ----------------------------------- |
| **Incident Created** | New incident opens |
| **Incident Updated** | Severity, status, or fields change |
| **Incident Status Changed** | Incident moves to a specific status |
| **Incident Commander Assigned** | Someone takes ownership |
| **Incident Resolved** | Incident is resolved |
| **Manual Trigger** | Run on demand from the UI |
Conditions filter when the workflow should run after it's been triggered — keeping Teams activity focused on the incidents that matter.
Examples:
* Only for SEV-1 or SEV-2 incidents
* Only for specific teams or services
* Only for production environments
Click **Add Action** and search for **Microsoft Teams** to see all available actions.
***
### Action Reference
Creates a dedicated Teams channel for the incident. Use this as your first action when an incident opens to give responders a central place to coordinate.
The Microsoft Teams workspace where the channel will be created.
The channel name. Supports Liquid syntax (for example, `{{ incident.title }}`).
Channel names are automatically lowercased, parameterized, and truncated to 50 characters.
An optional description for the channel. Supports Liquid syntax.
Controls channel visibility:
* **auto** — Private for private incidents, public for non-private incidents
* **true** — Always private
* **false** — Always public
If the incident already has a Teams channel, this action skips creation to avoid duplicates.
Creates a group or one-on-one chat for the incident. Once created, the chat ID and URL are stored on the incident for use in subsequent actions.
* **group** — Creates a group chat with multiple members and an optional topic
* **oneOnOne** — Creates a one-on-one chat between exactly two members
A topic for the chat. Only used for group chats. Supports Liquid syntax.
A JSON array of members to add. Each member requires an `email` field. Supports Liquid syntax.
```json theme={null}
[
{"email": "alice@company.com"},
{"email": "bob@company.com", "roles": ["guest"]}
]
```
Group chats require at least three members (including the service account). One-on-one chats require exactly two.
Adds a tab to the incident Teams channel. Use this to give responders quick access to dashboards, runbooks, or the Rootly incident page directly within the channel.
The team that contains the channel.
The channel to add the tab to. Use `{{ incident.microsoft_teams_channel_id }}` to target the incident's channel.
The display name shown on the tab. Supports Liquid syntax.
The URL the tab should point to. Supports Liquid syntax.
Optionally select a playbook to add as a dedicated playbook tab. When a playbook is selected, the tab renders only the playbook checklist — it is a distinct tab type and does not include the Rootly incident dashboard. Leave this empty to use the Title and Link fields to add a URL-based tab, such as a link to the incident page or an external runbook.
The Rootly app must be installed in the target team for this action to work.
Archives the incident channel when it's no longer needed. Keeps the workspace clean while preserving conversation history.
The team that contains the channel.
The channel(s) to archive. Use `{{ incident.microsoft_teams_channel_id }}` to target the incident's channel.
**Common trigger:** Incident Status Changed to "Closed"
Renames an existing Teams channel. Use this to reflect status changes — for example, prefixing resolved incidents with `[RESOLVED]`.
The team that contains the channel.
The channel to rename. Use `{{ incident.microsoft_teams_channel_id }}` to target the incident's channel.
The new channel name. Supports Liquid syntax.
```liquid theme={null}
[RESOLVED] {{ incident.title }}
```
**Common trigger:** Incident Resolved
Invites users to a private incident channel by email. Use this to automatically add on-call responders when they're assigned a role.
The team that contains the channel.
The private channel to invite users to. Supports Liquid syntax.
Comma-separated list of email addresses to invite. Supports Liquid syntax.
This action only works with **private** channels. Public channels are accessible to all team members by default.
**Common triggers:** Incident Created, Incident Commander Assigned
Posts a message to a Teams channel using the Rootly bot. Use Liquid variables to include dynamic incident details in the message.
The channel(s) to post to. Supports Liquid syntax.
The message content. Supports Liquid variables.
```liquid theme={null}
🚨 **Incident Update**
**Title:** {{ incident.title }}
**Severity:** {{ incident.severity }}
**Status:** {{ incident.status }}
**Commander:** {{ incident.commander.name | default: "Unassigned" }}
{{ incident.summary }}
```
If the message text is empty, the action will be skipped.
**Common triggers:** Incident Created, Incident Updated, Status Changed
Sends Adaptive Card attachments to one or more Teams channels. Use this to send richly formatted, interactive content such as structured incident summaries.
The channel(s) to send the attachments to. Supports Liquid syntax.
A JSON payload defining the Adaptive Card content. Supports Liquid syntax. Follows the [Microsoft Adaptive Card schema](https://adaptivecards.io/).
Creates a Microsoft Teams video meeting for live incident collaboration. The meeting link is automatically stored on the incident.
This action requires the **Microsoft Teams Meeting** integration to be installed separately.
The meeting title. Supports Liquid syntax (for example, `{{ incident.title }}`).
**Common trigger:** Incident Created (for high-severity incidents)
***
## Liquid Variables
Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test variables with real incident data.
### Incident Variables
| Variable | Description |
| -------------------------------- | ------------------------------------ |
| `{{ incident.title }}` | Incident title |
| `{{ incident.summary }}` | Incident summary |
| `{{ incident.severity }}` | Severity level (for example, "SEV1") |
| `{{ incident.status }}` | Current status |
| `{{ incident.started_at }}` | When the incident started |
| `{{ incident.commander.name }}` | Incident commander name |
| `{{ incident.commander.email }}` | Incident commander email |
| `{{ incident.url }}` | Link to the incident in Rootly |
### Microsoft Teams Variables
| Variable | Description |
| -------------------------------------------- | ------------------------------------- |
| `{{ incident.microsoft_teams_channel_id }}` | ID of the incident's Teams channel |
| `{{ incident.microsoft_teams_channel_url }}` | URL to the Teams channel |
| `{{ incident.microsoft_teams_chat_id }}` | ID of the incident's Teams chat |
| `{{ incident.microsoft_teams_meeting_url }}` | URL to the Teams meeting (if created) |
## Troubleshooting
After completing OAuth, Rootly doesn't appear as a connected app in Teams.
**Solutions:**
* Verify you completed OAuth using the same email as your Teams account
* Make sure Rootly was installed in a specific team, not just your personal app space
* Try uninstalling and reinstalling the Rootly app from the Teams store
* Check if your organization restricts third-party app installations — a Microsoft 365 admin may need to approve Rootly
Teams shows an error when trying to add Rootly to a team.
**Solutions:**
* Ensure you have owner or admin permissions in the team
* Ask a Team Owner or Microsoft 365 admin to approve the Rootly app
* Verify that third-party app installations are enabled in your Microsoft 365 admin center
Teams reports that the signed-in email isn't linked to a Rootly account.
**Solutions:**
* Verify the OAuth email matches exactly the email registered in Rootly
* Confirm this email exists as a user in Rootly
* Add the email under **Rootly → Organization Settings → Members** if needed
* Disconnect and reconnect the Microsoft Teams integration
Workflows run successfully but no Teams channels appear.
**Solutions:**
* Verify the Rootly bot is installed in the specific team referenced in the workflow action
* Check workflow run logs for errors: **Workflows → Your Workflow → ... → View Runs**
* Confirm the team name in the workflow action exactly matches the team in Teams
## Uninstall
To remove the main Microsoft Teams integration from Rootly:
1. Go to **Configuration → Integrations** and find **Microsoft Teams**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
Disconnecting from Rootly does not remove the Rootly bot from Teams. To fully uninstall, open **Microsoft Teams → Apps → Manage your apps**, find **Rootly**, and click **Uninstall**.
***
# Mistral AI
Source: https://docs.rootly.com/integrations/mistral
Connect Rootly to Mistral AI to send prompts to Mistral models from incident and action item workflows for AI-assisted summaries, drafts, and triage.
## Introduction
The Mistral AI integration lets you connect Rootly to your organization's Mistral AI API account. Once connected, a new **Mistral Chat Completion** workflow action becomes available, allowing you to send prompts to Mistral models and capture their responses — directly within your incident and action item workflows.
With the Mistral AI integration, you can:
* Generate AI-powered incident summaries, analyses, and recommendations
* Send custom prompts to Mistral and Codestral models with full Liquid template support
* Use a system prompt to define the model's role, tone, or output constraints
* Control response style with temperature, max tokens, and nucleus sampling parameters
## Before You Begin
Before setting up the Mistral AI integration, make sure you have:
* A Rootly account with permission to manage integrations
* A [Mistral AI API key](https://console.mistral.ai/) with access to at least one model
Your API key is validated against the Mistral API when you save the integration. If validation fails, confirm the key is active and has not been revoked in the Mistral console.
## Installation
Navigate to the integrations page in your Rootly workspace and select **Mistral AI**.
Paste your Mistral AI API key into the **API Key** field. Rootly validates the key by fetching your available models before saving. Your key is encrypted at rest in Rootly.
Your Mistral AI integration is active. The **Mistral Chat Completion** workflow action is now available in your incident and action item workflows.
## Workflow Actions
### Mistral Chat Completion
Sends a prompt to a Mistral model and captures the response as a workflow output. The model list is fetched dynamically from your API account and includes `mistral-`, `codestral-`, and `open-` model families.
| Field | Description | Required |
| ------------- | -------------------------------------------------------------------------- | -------- |
| Model | The Mistral model to use — fetched from your account | Yes |
| Prompt | The user message — supports Liquid templating | Yes |
| System Prompt | Instructions for the model's role or behavior — supports Liquid templating | No |
| Temperature | Sampling temperature between `0.0` and `1.5` — controls randomness | No |
| Max Tokens | Maximum number of tokens in the response | No |
| Top P | Nucleus sampling probability between `0.0` and `1.0` | No |
Use Liquid variables in your prompts to include live incident context — for example `{{ incident.title }}`, `{{ incident.severity }}`, and `{{ incident.description }}`. See the [Liquid variables reference](/liquid/incident-variables) for all available fields.
The **System Prompt** field sets the model's persona or output format — for example: *"You are an incident response assistant. Respond in bullet points. Be concise."*
## Troubleshooting
Rootly validates your API key by fetching the list of available models when you save. If validation fails, confirm the key is active in the [Mistral console](https://console.mistral.ai/) and has not been revoked or restricted.
If the integration was working and then stopped, the API key may have been rotated or revoked. Update the key in the integration settings — Rootly re-validates on save.
Mistral AI enforces rate limits based on your API tier. Running many concurrent workflows may exceed requests-per-minute limits. Consider staggering workflows, reducing token usage with more focused prompts, or upgrading your Mistral plan for higher quota.
The model list is fetched dynamically from your API account and is filtered to `mistral-`, `codestral-`, and `open-` model families. If a model you expect is missing, confirm your API key has access to it — some models may require specific Mistral tiers or allowlisting.
Check your Liquid syntax — unclosed tags or undefined variables can cause rendering failures. Use the [Liquid variables reference](/liquid/incident-variables) to confirm variable names and test your template in a low-stakes workflow first.
## Related Pages
Build workflows that use Mistral models to analyze, summarize, or respond to incidents.
Reference for all incident variables available in Liquid-templated prompts.
Learn about Rootly's built-in AI features for incident management.
# Motion integration for Rootly incidents
Source: https://docs.rootly.com/integrations/motion
Sync Rootly incidents and action items to Motion tasks with severity-to-priority mapping, bidirectional links, and Liquid title and description templates.
## Overview
Motion's AI-powered task and calendar app handles task prioritization, scheduling, and time-blocking for the people on your team who plan their day in it. Wire it into Rootly and incident follow-ups land in Motion automatically — pre-mapped severity to priority, pre-populated title and description from incident context, ready to be scheduled into a responder's day without anyone re-typing what happened.
The integration goes both directions: Rootly creates and updates Motion tasks as incidents and action items progress, and the Motion task URL is linked back on the Rootly side so responders can jump between the two with one click.
Every new incident and action item can spawn a corresponding Motion task with title, description, project, and labels populated from Rootly context.
Critical incidents map to Motion's ASAP priority, High to HIGH, Medium to MEDIUM, Low to LOW — so the on-call's Motion view sorts the right thing first.
The Motion task URL is stored on the incident or action item, and the Rootly link is on the Motion task — one click between systems either way.
Customize task titles and descriptions with Liquid expressions referencing incident fields, severity, environments, and custom fields.
***
## Before You Begin
**You'll need access to both sides of the connection.**
* **In Motion** — a user account with permission to generate API keys and at least one workspace and project available.
* **In Rootly** — an admin role so you can reach **Configuration → Integrations** and complete the Motion setup.
Motion's API access requires a paid plan. If you're evaluating Motion for the first time, [Motion's developer docs](https://docs.usemotion.com/) walk through the basics before you reach the API key step.
Rootly recommends generating the Motion API key from a **dedicated service account** rather than a personal user. The integration is keyed to one user's API key and only sees the workspaces and projects that user can access — using a personal account creates an avoidable outage if that user loses access or leaves the organization.
***
## Generate Your Motion API Key
The vendor-side setup is a single key. Refer to [Motion's API getting-started guide](https://docs.usemotion.com/cookbooks/getting-started/) for the latest UI specifics; the high-level flow is below.
Sign into Motion and navigate to **Settings → API**.
Click **Create API Key**, give it a descriptive name (`rootly-production` works), and click **Generate**.
Motion shows the API key value **once**. Copy it now and store it in your secrets manager — you cannot retrieve it later, only revoke and reissue.
Confirm the user that owns the API key has at least one workspace and one project visible. Rootly's setup uses those as the dropdown options for task destination — without them, the integration save will succeed but task creation will have nowhere to land.
***
## Connect Motion to Rootly
With the API key in hand, the Rootly-side setup is a single field and a save.
In Rootly, go to **Configuration → Integrations** and locate **Motion**. Click **Setup**.
Paste your Motion API key into the **API Key** field. Rootly validates the key against Motion's `v1/workspaces` endpoint immediately — a successful save means the key authenticates and at least one workspace is reachable.
Rootly creates four default workflows the moment the integration connects:
* **Create Motion Task** when an incident is created
* **Update Motion Task** when an incident updates
* **Create Motion Task** when an action item is created
* **Update Motion Task** when an action item updates
Open **Workflows** in Rootly to see them. They're disabled by default — enable the ones you want, and configure each with the target workspace, project, and status for your team.
***
## Auto-Created Workflows
The four workflows give you incident and action-item lifecycle coverage out of the box. Each can be customized — change the trigger conditions, modify the Liquid templates, or duplicate them for different teams or services.
Fires when an incident is created. Pushes a Motion task with the incident title, summary, severity-mapped priority, and a link back to Rootly.
Fires when an incident updates. Syncs the latest status, priority, and labels back to the linked Motion task.
Fires when a Rootly action item is created. Pushes the action item as a Motion task for the responder who owns the follow-up.
Fires when an action item changes — status, owner, due date. Keeps the linked Motion task in sync.
***
## Configuration Reference
Motion personal or workspace API key. Stored encrypted at rest. Rotate by revoking the key in Motion's Settings → API panel and pasting a new value here.
Motion workspace where Rootly creates tasks. Fetched live from Motion when you configure a workflow action. Each workflow can target a different workspace if your team uses several.
Motion project inside the chosen workspace. Cascading dropdown — the project list updates when the workspace selection changes.
Initial status the Motion task is created with. Pulled from the chosen project's status configuration. Defaults to the project's "todo"-equivalent if not set.
Initial priority of the Motion task. Defaults to a severity-based mapping (see [Field Mapping](#field-mapping) below), but you can hardcode a priority per workflow if you want every task at the same level.
Title shown on the Motion task. Default uses the incident or action item title. Override with Liquid expressions like `[{{ incident.severity }}] {{ incident.title }}` to bake severity into the title.
Description body on the Motion task. Default includes the incident summary plus a link back to Rootly. Customize with any incident field, custom field, or environment metadata.
Optional Motion labels to apply. Maps from Rootly environments by default — incidents tagged with the `production` environment become Motion tasks labeled `production`.
***
## Field Mapping
Rootly maps the most useful incident metadata to Motion's task fields out of the box. All of these can be overridden per workflow.
| Rootly Field | Motion Field | Default Behavior |
| ------------------------------------------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Incident title / action item summary | Task title | Direct copy, overrideable via Liquid template |
| Incident summary / action item description | Task description | Direct copy, overrideable via Liquid template |
| Incident severity | Task priority | `critical` → ASAP, `high` → HIGH, `medium` → MEDIUM, `low` → LOW |
| Incident environments | Task labels | Each environment name becomes a Motion label |
| Incident ID and URL | Stored on task body | Link back to Rootly is appended to the description |
| Motion task ID | Stored on Rootly record | `incident.motion_task_id` / `incident.motion_task_url` for incidents; `action_item.motion_task_id` / `action_item.motion_task_url` for action items |
***
## Test the Integration
After saving the API key and enabling at least one workflow, verify end-to-end task creation.
Trigger a test incident from Rootly's web UI, Slack, or API. Pick a severity that matches one of your workflow's trigger conditions.
Open your Motion workspace. A new task should appear in the configured project within a few seconds, with the incident title, severity-mapped priority, and a link back to Rootly in the description.
Back in Rootly, open the test incident. The Motion task URL should be visible in the **Integrations** section on the incident. Clicking it opens the task in Motion.
A Motion task created from a Rootly incident plus the reverse link visible on the Rootly side confirms both the create and the link-back paths are wired correctly. Now expand the workflow rollout to your real incident severities.
***
## Troubleshooting
The API key is invalid, expired, or copied with surrounding whitespace. Verify:
* The key value matches exactly what Motion displayed when you created it
* The key wasn't revoked or rotated in Motion's Settings → API panel
* The Motion account is on a plan that includes API access
Most common causes:
* The workspace or project configured on the workflow no longer exists in Motion — re-open the workflow and confirm both dropdowns still resolve
* The status configured on the workflow was deleted in Motion's project configuration
* The Motion API quota for your plan has been exhausted — Motion returns 429 errors that Rootly logs but doesn't surface visibly
The workflow has a hardcoded priority overriding the severity mapping. Open the workflow's Motion action and either remove the priority override (to fall back to severity mapping) or set the hardcoded priority you want.
The Update Motion Task workflow either isn't enabled or doesn't match the same trigger conditions as the Create workflow. Open both workflows and confirm the trigger conditions align — typically the Update workflow's trigger should be "Incident updates" with a condition matching the Create workflow's filters.
The link is stored in `incident.motion_task_url` when the Create workflow succeeds. If it's missing, either the workflow didn't run (check Workflow Runs) or the workflow encountered an error before completing the create step. Check the run history for the specific incident.
Revoke the existing key in Motion's Settings → API panel, create a new one with the same scope, and paste the new value into Rootly's Motion settings. The previous key continues working in Rootly until the new value is saved, then it's immediately replaced.
***
## Frequently Asked Questions
Yes. Duplicate the Create Motion Task workflow and set different trigger conditions plus different workspace/project targets on each copy. For example, production-environment incidents into a Production project, staging incidents into a Staging project.
Not currently. Rootly is the source of truth for incident and action-item lifecycle; Motion mirrors what Rootly sends. The Motion task URL stays accessible on the Rootly side, so responders can update Motion directly without affecting Rootly state.
Yes. Each ticketing integration runs its own workflows independently. Many teams push to Jira for engineering tracking and Motion for the responder's personal scheduling, in parallel.
Yes. Edit the auto-created Create workflow's trigger conditions to filter by severity, environment, custom field, or any other Rootly condition. Only matching incidents will spawn Motion tasks.
Workflow runs that hit a Motion API error are retried by Rootly's job queue. If Motion is unavailable for an extended outage, runs eventually fail and surface in the workflow run history — they can be re-run manually once Motion recovers.
***
## Next Steps
Customize the auto-created workflows, add filters, chain follow-up actions, or build new Motion automations from scratch.
Configure how Rootly tracks post-incident work that pushes to Motion as tasks.
Adjust the severity definitions Rootly uses for the severity-to-priority mapping.
Add custom fields whose values can flow into Motion task descriptions via Liquid templating.
# New Relic
Source: https://docs.rootly.com/integrations/new-relic
Connect New Relic to Rootly to ingest alert events and capture metric and chart snapshots during incidents through Genius workflows.
The New Relic integration connects Rootly with your New Relic account in two directions. New Relic alert policies send issue events into Rootly as alerts, and incident workflows capture chart snapshots so responders keep point-in-time visibility into your observability data without leaving the incident.
With the New Relic integration, you can:
* Receive New Relic issue events as Rootly alerts
* Filter and route alerts using workflow conditions on fields like `priority`, `state`, and `workflowName`
* Capture New Relic chart snapshots from Genius workflows during incidents
* Attach snapshot links to incident timelines for post-incident review
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with permission to manage integrations
* A New Relic account with permission to create API keys
* Your New Relic **Account ID**
* Access to configure notification channels in New Relic, if you plan to ingest alerts
Rootly recommends integrating with a dedicated service account so the integration does not break if an individual user leaves your organization.
## Installation
Navigate to the integrations page in Rootly and select **New Relic**.
In New Relic, navigate to your API keys settings.
Generate a new **User** key and copy it.
Copy the API key immediately after generating it — New Relic will not show the full key again.
Paste your **API key** and **Account ID** into the New Relic integration settings in Rootly and save.
## Ingest New Relic Alerts
New Relic sends alert events into Rootly through a webhook notification channel. Once alerts are flowing, alert workflows can create incidents, notify Slack channels, or page on-call targets.
Install the integration before setting up the webhook. The bearer token is generated during installation and is required for authentication.
### Configure a Webhook in New Relic
In New Relic, navigate to **Alerts > Notification channels** and create a new channel.
Select **Webhook** as the channel type and configure it with the following values:
* **Webhook URL**: `https://webhooks.rootly.com/webhooks/incoming/new_relic_webhooks`
* **Auth type**: Bearer token
* **Token**: the bearer token shown in your Rootly New Relic integration settings
Your bearer token is available in Rootly under **Integrations > New Relic > Configure**.
Click **Test Notification** in New Relic. A test alert should appear on your [Rootly Alerts page](https://rootly.com/account/alerts).
If the test alert appears in Rootly, the integration is working correctly. You can now attach this channel to New Relic alert policies.
### How Alerts Are Mapped
Rootly extracts the following fields from each New Relic alert payload:
* **Summary** — the `title` field from the New Relic issue
* **External ID** — the issue `id`, used to deduplicate alerts
* **External URL** — the `issueUrl`, linking back to the New Relic issue
* **Labels** — `state`, `trigger`, `priority`, and `workflowName` are attached as Rootly alert labels
New Relic `priority` and `state` values are available as alert labels in Rootly. You can use these in workflow run conditions to handle critical vs warning alerts differently.
## Workflow Actions
Once the integration is connected, a new task is available in your Genius workflows to capture New Relic chart snapshots during incidents.
Snapshots are point-in-time captures attached to the incident timeline, so you can reference exactly what your metrics looked like when the incident occurred.
## Troubleshooting
Verify that the webhook URL and bearer token are correct. Use the **Test Notification** button in New Relic to confirm delivery. Ensure the notification channel is attached to the alert policy that fired.
Rootly extracts fields from the standard New Relic issue payload. If your New Relic account uses a customized payload template for the webhook channel, ensure it still includes the standard fields: `title`, `id`, `issueUrl`, `state`, `priority`, and `createdAt`.
Confirm you are using the token from the Rootly New Relic integration settings, not your New Relic API key. These are different credentials — the bearer token is generated by Rootly for authenticating inbound webhooks.
## Uninstall
To remove the New Relic integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related Resources
* [Alert workflows](/workflows/alert-workflows)
* [Alert routing](/alerts/alert-routing)
* [Integrations overview](/integrations/overview)
# Nobl9
Source: https://docs.rootly.com/integrations/nobl9
Receive alerts in Rootly when SLO error budgets are breached in Nobl9, with routing to on-call teams, Slack channels, and incident creation workflows.
## Overview
Rootly's Nobl9 integration turns SLO alert policy violations into Rootly alerts. When Nobl9 detects that a service's error budget has been exhausted or an SLO objective has been breached, it fires a webhook to Rootly which creates an alert automatically.
Alerts created from Nobl9 include contextual labels pulled directly from the payload — service, project, severity, SLO name, alert policy, and organization — making it easy to route and filter alerts in Rootly.
Alerts fire automatically when error budgets are breached or SLO objectives are violated.
Each alert carries service, project, severity, SLO, alert policy, and organization labels from Nobl9.
Route Nobl9 alerts to services, escalation policies, or teams based on label values.
Escalate Nobl9 alerts into full incidents when SLO violations require immediate response.
## Before You Begin
* You must be a Rootly admin to set up the integration
* You must have access to Nobl9 with permissions to create **Alert Methods** and **Alert Policies**
## Installation
In Rootly, go to **Configuration → Integrations** and find **Nobl9**. Click **Connect**.
Rootly will generate a unique webhook URL tied to your team. Copy this URL — you'll need it in the next step.
In Nobl9, navigate to **Integrations → Alert Methods** and click **+ Add Alert Method**.
Click **Alert Methods** and create a new alert method.
Select **Webhook** as the alert method type.
Paste the webhook URL from Rootly into the URL field and save.
In Nobl9, open or create an **Alert Policy** and attach the Rootly alert method to it. Any SLO that uses this alert policy will now send alerts to Rootly when violated.
## Alert Labels
When Nobl9 fires an alert, Rootly automatically extracts the following labels from the payload:
| Label | Source |
| -------------- | ------------------ |
| `service` | Nobl9 service name |
| `project` | Nobl9 project name |
| `severity` | Alert severity |
| `slo` | SLO name |
| `alert_policy` | Alert policy name |
| `organization` | Nobl9 organization |
These labels can be used in Rootly to route alerts, set urgency, and filter in dashboards.
## Uninstall
To remove the Nobl9 integration:
1. Go to **Configuration → Integrations** and find **Nobl9**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
After disconnecting, update or remove any Nobl9 alert methods that reference the Rootly webhook URL. Nobl9 will continue attempting to deliver webhooks to a disconnected endpoint.
## Frequently Asked Questions
No. Nobl9 webhooks are fire-and-forget — they don't send a resolve signal when the SLO recovers. Alerts created from Nobl9 must be resolved manually in Rootly or via a separate automation.
Yes. Use Rootly's alert routing rules to match on labels like `service`, `project`, or `alert_policy` and route to the appropriate team or escalation policy.
Yes. The same webhook URL can be attached to multiple alert methods and policies in Nobl9. All alerts will flow into the same Rootly integration.
The alert summary is set from the `message` field in the Nobl9 payload, which typically describes the SLO violation (for example, "Error budget exhausted for checkout-latency SLO").
# Notion
Source: https://docs.rootly.com/integrations/notion/overview
Connect Notion to Rootly to automatically create and update incident retrospective pages in your Notion workspace.
Rootly's Notion integration automatically creates retrospective pages when incidents occur. Each page is populated with incident details, timeline, and action items — giving your team a single source of truth without manual documentation.
## Features
Retrospective pages are created automatically when incidents resolve or retrospectives begin.
Incident timeline and follow-up action items are included in every page.
Use your own retrospective templates with Liquid variables for dynamic content.
Re-generate pages with the latest incident data at any point via workflows.
## Before You Begin
Rootly recommends performing the installation with a **service account** to ensure the integration does not break if the installing user leaves the company. Ensure you are logged in as an **Admin** in Rootly. You will also need Editor or Owner access to the parent Notion page where Rootly will create pages.
## Installation
To connect Notion to Rootly, you will authorize via OAuth and select which Notion pages Rootly is allowed to access. Rootly can only create pages within the pages you explicitly grant access to during this step.
In Rootly, navigate to **Configuration → Integrations** and search for **Notion**.
Click **Setup**. You will be redirected to Notion. Click **Select pages** to choose which pages Rootly can access.
Choose the parent pages where you want Rootly to create incident retrospective pages, then click **Allow access**.
You will be redirected back to Rootly with a success message confirming the integration is connected.
Your Notion workspace is now connected. You can verify the connection in Notion under **Settings and Members → Connections** — Rootly should appear in the list.
## Verify the Connection
After connecting, confirm in Notion that Rootly has been granted access:
1. Open the parent page you selected during authorization
2. Click the **⋯** menu → **Connections**
3. Confirm Rootly appears in the list
## Workflow Actions
Workflows let you automate Notion page creation and updates for incident retrospectives. You can trigger page creation when an incident resolves or a retrospective begins, and populate the page with timeline data, action items, and custom template content using Liquid variables.
| Action | Description |
| ---------------------- | ------------------------------------------------------------------ |
| **Create Notion Page** | Creates a new retrospective page in a specified Notion parent page |
| **Update Notion Page** | Overwrites an existing Notion page with the latest incident data |
### Create a Workflow
Navigate to **Workflows** in Rootly and click **Create Workflow**.
Select the workflow type that matches your use case — **Incident**, **Retrospective**, or **Pulse**.
Triggers define when the workflow runs. Choose the event that should kick off page creation.
| Trigger | When it fires |
| --------------------------- | ---------------------------------------- |
| **Incident Created** | A new incident opens |
| **Incident Updated** | Severity, status, or other fields change |
| **Incident Status Changed** | The incident moves to a specific status |
| **Incident Resolved** | The incident is resolved |
| **Retrospective Started** | The retrospective process begins |
| **Manual Trigger** | Run on demand from the UI |
Use conditions to control when the workflow fires after the trigger. For example, only create a Notion page for SEV-1 or SEV-2 incidents, or only for specific teams or environments.
Click **Add Action** and search for **Notion**.
### Create Notion Page
Use this action to create a new retrospective page in Notion for an incident. The page is created under a parent page you select and is populated using the template and fields you configure.
| Field | Description |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Page** | The parent Notion page where the new page will be created. Must be a page Rootly was granted access to during installation. |
| **Title** | The page title. Supports Liquid syntax — use the incident title or any other variable. |
| **Post Mortem Template** | A pre-built retrospective template from [Retrospective Templates](https://rootly.com/account/retrospective-steps?tab=documents). |
| **Mark Post Mortem as Published** | Set the retrospective status to `published` immediately rather than leaving it as `draft`. |
| **Show Timeline as Table** | Include the incident timeline. Uncheck if you want images to appear inline — Notion does not support images in tables. |
| **Show Action Items as Table** | Include follow-up action items. Only `follow-up` type items are included — tasks are excluded as they are completed during the incident, before the retrospective. |
| **Skip on Failure** | Prevent the workflow from stopping if this action fails. |
| **Enabled** | Toggle this action on or off for testing. |
### Update Notion Page
Use this action to overwrite an existing Notion page with the latest incident data. This is useful for keeping the retrospective page current as the incident progresses.
This is an overwrite operation. Any manual changes made to the Notion page will be replaced when this action runs.
| Field | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------- |
| **File** | The Notion page to update. Use `incident.notion_page_id` via Liquid to reference the incident's existing page. |
| **Title** | Updated page title. Leave blank to keep the existing title. |
| **Post Mortem Template** | Template to apply when updating. Overwrites existing content. |
| **Show Timeline as Table** | Include the incident timeline. |
| **Show Action Items as Table** | Include follow-up action items. |
| **Skip on Failure** | Prevent the workflow from stopping if this action fails. |
| **Enabled** | Toggle this action on or off for testing. |
## Variable Reference
Use these variables in page titles and templates. Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test variables with real incident data.
### Incident Variables
| Variable | Description |
| ------------------------- | ---------------------------------- |
| `incident.title` | Incident title |
| `incident.summary` | Incident summary |
| `incident.severity` | Severity level (for example, SEV1) |
| `incident.status` | Current status |
| `incident.started_at` | When the incident started |
| `incident.resolved_at` | When the incident was resolved |
| `incident.commander.name` | Incident commander name |
| `incident.url` | Link to the incident in Rootly |
### Notion Variables
| Variable | Description |
| -------------------------- | ------------------------------------------------------------ |
| `incident.notion_page_id` | ID of the incident's Notion page — used in the Update action |
| `incident.notion_page_url` | URL to the Notion page |
## Uninstall
**In Rootly:**
1. Go to **Configuration → Integrations** and find **Notion**
2. Click the **Connected** button to reveal the disconnect option
3. Click **Delete**
**In Notion** (to fully revoke access):
1. Go to **Settings and Members → Connections**
2. Find **Rootly** and click **Disconnect**
Disconnecting from Rootly does not remove existing Notion pages created by Rootly. Those pages remain in your Notion workspace.
## Frequently Asked Questions
Ensure you granted access to the specific page during OAuth. Go to **Settings and Members → Connections** in Notion to confirm Rootly is listed. If missing, disconnect and reconnect the integration in Rootly. Also check that the page is not in a private or restricted workspace.
Notion only shows pages you have Editor or Owner access to. If the workspace has restricted pages, an admin must grant you access first. Try expanding parent pages in the selector to see nested pages, then restart the authorization flow.
Verify the parent page selected in the workflow action is one you granted access to during installation. Check workflow run logs under **Workflows → Your Workflow → View Runs** for error details. Re-authorize the integration if the connection has expired.
### Workflow Questions
Check the workflow run log under **Workflows → Your Workflow → View Runs** for error details. Confirm the parent page selected in the action is one Rootly was granted access to during installation. Re-authorize the integration if the connection has expired.
The Update Notion Page action is a full overwrite. If you need to preserve manual edits, disable any workflows that trigger an update on that page, or add conditions to prevent them from running after a certain point in the incident lifecycle.
Yes — define a custom retrospective template in [Retrospective Templates](https://rootly.com/account/retrospective-steps?tab=documents) and select it in the Post Mortem Template field. Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to build and test your template.
Notion does not support images inside tables. Uncheck **Show Timeline as Table** to render the timeline inline, which will allow images to display correctly.
## Related Resources
* [Workflows](/workflows/workflows)
* [Retrospectives](/retrospectives/retrospectives)
* [Integrations overview](/integrations/overview)
# OpenAI
Source: https://docs.rootly.com/integrations/openai
Connect your OpenAI account to Rootly to power AI-assisted incident workflows using your own API key, data agreements, and regional endpoint.
## Introduction
The OpenAI integration lets you connect Rootly to your organization's OpenAI account, using your own API key and Organization ID to power AI-assisted incident workflows. This gives your team control over model selection, data handling, and API usage under your organization's specific agreements with OpenAI — including data retention policies that may differ from Rootly's default OpenAI configuration.
With the OpenAI integration, you can:
* Generate AI-powered summaries, analyses, and responses within incident workflows
* Send custom prompts to GPT and reasoning models with full Liquid template support
* Use a system prompt to define the model's role, tone, or output constraints
* Route requests through a regional OpenAI endpoint to meet data residency requirements
* Access OpenAI's reasoning models (`o1`, `o3`) with configurable reasoning effort and summary output
## Before You Begin
Before setting up the OpenAI integration, make sure you have:
* A Rootly account with permission to manage integrations
* An [OpenAI API key](https://platform.openai.com/api-keys) with the following permissions:
* **Models** permission set to `Read`
* **Model Capabilities** permission set to `Write`
* Your [OpenAI Organization ID](https://platform.openai.com/settings/organization/general)
Rootly recommends creating a dedicated API key for Rootly rather than using a personal key. Your key is validated on save and encrypted at rest in Rootly.
## Installation
Navigate to the integrations page in your Rootly workspace and select **OpenAI**.
Paste your OpenAI API key and Organization ID into the respective fields. Rootly validates the credentials against the OpenAI API before saving.
Choose the OpenAI API host for your requests. The default is `api.openai.com`. If your organization requires data to stay within a specific region, select the appropriate regional endpoint:
| Host | Region |
| ------------------- | -------------- |
| `api.openai.com` | Default (US) |
| `us.api.openai.com` | United States |
| `eu.api.openai.com` | Europe |
| `gb.api.openai.com` | United Kingdom |
| `ae.api.openai.com` | UAE |
| `au.api.openai.com` | Australia |
| `ca.api.openai.com` | Canada |
| `jp.api.openai.com` | Japan |
| `in.api.openai.com` | India |
| `sg.api.openai.com` | Singapore |
| `kr.api.openai.com` | South Korea |
Your OpenAI integration is active. The **Create OpenAI Chat Completion** workflow action is now available in your incident and action item workflows.
## Workflow Actions
### Create OpenAI Chat Completion
Sends a prompt to an OpenAI model and captures the response as a workflow output. Supports both standard GPT models via the Chat Completions API and reasoning models (`o1`, `o3`) via the Responses API.
| Field | Description | Required |
| ----------------- | -------------------------------------------------------------------------- | -------- |
| Model | The OpenAI model to use — fetched from your account | Yes |
| Prompt | The user message — supports Liquid templating | Yes |
| System Prompt | Instructions for the model's role or behavior — supports Liquid templating | No |
| Temperature | Sampling temperature between `0.0` and `2.0` — controls randomness | No |
| Max Tokens | Maximum number of tokens in the response | No |
| Top P | Nucleus sampling probability between `0.0` and `1.0` | No |
| Reasoning Effort | For reasoning models: `minimal`, `low`, `medium`, or `high` | No |
| Reasoning Summary | For reasoning models: `auto`, `concise`, or `detailed` | No |
Use Liquid variables in your prompts to include live incident context — for example `{{ incident.title }}`, `{{ incident.severity }}`, and `{{ incident.description }}`. See the [Liquid variables reference](/liquid/incident-variables) for all available fields.
The **System Prompt** field sets the model's persona or output format — for example: *"You are an incident response assistant. Respond in bullet points. Be concise."*
**Reasoning models** (`o1-*`, `o3-*`) use the OpenAI Responses API instead of the Chat Completions API. When using these models, use **Reasoning Effort** to control how much compute the model uses before responding, and **Reasoning Summary** to control how much of that reasoning is surfaced in the output.
## Troubleshooting
Rootly validates your credentials by making a test request to OpenAI. Confirm that the API key is active, has not been revoked, and has the correct permissions: **Models** set to `Read` and **Model Capabilities** set to `Write`. Also verify that the Organization ID matches the organization the API key belongs to.
If the integration was working and then stopped, the API key may have been rotated or revoked. Update the key in the integration settings — Rootly re-validates on save. Also confirm the Organization ID has not changed.
OpenAI enforces rate limits based on your usage tier. Running many concurrent workflows may exceed requests-per-minute or tokens-per-minute limits. Consider staggering workflows, reducing token usage with more focused prompts, or upgrading your OpenAI tier.
The model list is fetched dynamically from your OpenAI account. Rootly filters for `gpt-*`, `o1-*`, and `o3-*` models. If a model you expect to see is missing, confirm your API key has access to it — some models require specific OpenAI tiers.
Reasoning effort and reasoning summary only apply to `o1-*` and `o3-*` models using the Responses API. If you select a standard GPT model, these fields are ignored and only the Chat Completions parameters (temperature, max tokens, top p) apply.
Check your Liquid syntax — unclosed tags or undefined variables can cause rendering failures. Use the [Liquid variables reference](/liquid/incident-variables) to confirm variable names and test your template in a low-stakes workflow first.
## Related Pages
Build workflows that use OpenAI models to analyze, summarize, or respond to incidents.
Reference for all incident variables available in Liquid-templated prompts.
Learn about Rootly's built-in AI features for incident management.
# Opsgenie
Source: https://docs.rootly.com/integrations/opsgenie
Connect Opsgenie to Rootly to import services, sync alerts and incidents, automate response workflows, and gradually migrate from Opsgenie to Rootly On-Call.
Atlassian has announced end of life for Opsgenie. If you're evaluating alternatives, see [how Rootly compares to Opsgenie](https://rootly.com/comparisons/opsgenie-vs-rootly-on-call).
## Introduction
The Opsgenie integration connects Rootly with your existing alerting and on-call workflows so teams can coordinate incidents across both platforms.
This integration is a strong fit for teams that already use Opsgenie for paging or alerting and want Rootly to act as the central system for incident coordination and response.
With the Opsgenie integration, you can:
* Import Opsgenie services into Rootly
* Create Rootly alerts from supported Opsgenie webhook events
* Create and update Opsgenie **alerts** from Rootly workflows, with automatic severity-to-priority mapping
* Create and update Opsgenie incidents from Rootly workflows and escalation actions
* Resolve linked Opsgenie incidents from Rootly
* Page Opsgenie teams from Slack when the Slack integration is enabled
## Before You Begin
Before installing the integration, make sure you have:
* A Rootly account with permission to manage integrations
* An Opsgenie account on a supported plan, such as Standard or Enterprise
* Access to create a **global** Opsgenie API integration key
* The correct Opsgenie API host for your workspace:
* `api.opsgenie.com`
* `api.eu.opsgenie.com`
Rootly recommends using a dedicated service account so the integration does not break if an individual user leaves your organization.
## Installation
You can install the integration from the Rootly integrations page as a logged-in admin user.
## Import or Link Services
You can import your current Opsgenie services into Rootly or link existing Rootly services to Opsgenie services from the **Services** page.
When a Rootly service is linked to Opsgenie, Rootly can use that relationship during incident escalation and sync workflows.
## Configure Opsgenie
To complete setup, create an API integration in Opsgenie and copy its credentials into Rootly.
In Opsgenie, navigate to **Settings > Integrations > New Integration**.
Select the **API** integration tile.
The API integration should include the access required for Rootly to read, create, and update incidents and related data.
The API key must be a **global** key and cannot be scoped only to a single team.
After saving the integration in Opsgenie, copy the API key into the Opsgenie integration settings in Rootly.
## Configure Webhooks
Rootly can receive supported Opsgenie webhook events and turn them into alerts or linked incident activity.
Supported webhook actions include:
* `Create`
* `Acknowledge`
* `AssignOwnership`
* `Close`
To configure webhook delivery in Opsgenie, add the Rootly webhook configuration shown during setup.
The webhook secret used for Rootly webhook delivery is separate from your Opsgenie API key. Make sure you copy the correct value into the webhook configuration.
## How Sync Works
The Opsgenie integration supports both inbound and outbound workflows.
### Opsgenie to Rootly
When Opsgenie sends supported webhook events to Rootly, Rootly can create alerts and update linked incident activity.
In most cases, the `Create` action creates a Rootly alert from the Opsgenie alert payload. The `Acknowledge`, `AssignOwnership`, and `Close` actions can also add incident activity when the Opsgenie event is linked to a Rootly incident.
If an incoming Opsgenie event is already tied to a synced Rootly incident, Rootly may skip creating a duplicate alert.
### Rootly to Opsgenie
Rootly can create or update both Opsgenie **alerts** and **incidents** through workflows and escalation actions.
**Alerts** — Rootly can create and update Opsgenie alerts directly, targeting specific teams, users, escalation policies, or schedules. Rootly incident severity is automatically mapped to Opsgenie priority:
| Rootly Severity | Opsgenie Priority |
| --------------- | ----------------- |
| Critical | P1 |
| High | P2 |
| Medium | P3 |
| Low | P4 |
| Informational | P5 |
**Incidents** — Rootly can also create or update Opsgenie incidents. This is commonly used when a Rootly incident needs to page an Opsgenie team or when a linked Opsgenie incident should be resolved after the Rootly incident is resolved.
## Default Workflows
When the integration is connected, Rootly can create default workflows to support common Opsgenie actions, such as:
* Adding Opsgenie on-call responders into the incident workflow
* Automatically resolving linked Opsgenie incidents when the Rootly incident is resolved
Review these workflows after installation so they match your team’s process.
## Auto Assign On-Calls to Incident Roles
If you want to automatically assign the on-call user from an Opsgenie schedule to an Incident Role, such as Commander, follow the setup guidance on the [PagerDuty integration page](/integrations/pagerduty/pagerduty).
## Re-Paging Existing Responders
By default, Rootly will not re-page responders who are already on an active Opsgenie alert or incident. If you want Rootly to re-page existing responders, enable **Re-page existing responders** in the Opsgenie integration settings.
## Paging Automatically via Workflows
You can use workflows to page different Opsgenie schedules and escalation policies based on incident conditions.
For example, you might page Infrastructure for SEV1 incidents and Security for incidents tagged with a security-related incident type.
Configure workflows to notify the correct Opsgenie targets based on incident severity, type, team, or other conditions.
## Paging from Slack
If the Slack integration is enabled, responders can page Opsgenie teams directly from Slack.
Use the Slack integration to trigger Opsgenie paging directly from the incident workflow in Slack.
## Notes
* Large imports and webhook volume may be affected by Opsgenie API rate limits.
* Incoming webhook-created alerts are also subject to your Rootly alert limits.
## Uninstall
To remove the Opsgenie integration, open the integrations panel in Rootly and select **Configure > Delete**.
# OpsLevel
Source: https://docs.rootly.com/integrations/opslevel
Connect OpsLevel with Rootly to sync your service catalog, so responders see current service ownership and metadata during incidents.
[OpsLevel](https://www.opslevel.com/) is a service catalog and internal developer
portal that tracks your services, their owners, and their operational maturity. Syncing
it into Rootly keeps service ownership and metadata consistent between the system your
engineers browse day to day and the system they respond to incidents in.
## Sync your OpsLevel catalog into Rootly
OpsLevel exposes a GraphQL API, so you can reconcile its catalog into Rootly using the
[`rootly-catalog-sync` CLI](/catalog-sync), which supports generic `graphql` and `http`
sources. Point a sync pipeline at your OpsLevel API and map the entities you care about —
services, teams, and their metadata — into Rootly [Catalogs](/catalogs). Services synced
by name link to existing Rootly [Services](/configuration/services) rather than
duplicating them.
## Related
* [Catalog Sync CLI](/catalog-sync)
* [Catalogs](/catalogs)
* [Services](/configuration/services)
# Outlook
Source: https://docs.rootly.com/integrations/outlook
Automatically schedule Microsoft Outlook calendar events from incident workflows — ideal for retrospectives, reviews, and follow-ups.
## Overview
Rootly's Outlook integration lets you schedule calendar events directly from incident workflows. The most common use case is automatically booking a retrospective meeting when an incident resolves, with attendees, description, and timing all populated from incident data.
Trigger calendar event creation at any workflow step — on incident creation, escalation, or resolution.
Populate event titles, descriptions, and attendees dynamically using incident variables.
Schedule events a set number of days out, with optional weekend exclusion, so meetings always land on business days.
Optionally attach a Microsoft Teams meeting link to the calendar event so attendees can join online.
## Before You Begin
* You must be a Rootly admin to set up the integration
* You do **not** need to be an admin of your company's Microsoft account
Use a **service account** rather than a personal Microsoft account. If the connected user leaves or loses access, the integration will stop creating calendar events.
## OAuth Permissions
When connecting, Rootly requests the following Microsoft permissions:
| Permission | Purpose |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `offline_access` | Keeps the integration connected without requiring re-authentication |
| `User.Read` | Reads the connected account's profile and organization info |
| `Calendars.ReadWrite.Shared` | Creates and manages events across calendars the account has access to, including shared and delegate calendars |
## Installation
Go to **Configuration → Integrations**, find **Outlook**, and click **Setup**.
You'll be redirected to Microsoft to sign in. Review the permissions Rootly is requesting and click **Accept**.
After authorizing, you'll be returned to Rootly and the integration will show as connected under the account's email address.
## Workflow Action
### Create an Outlook Event
Schedules a calendar event on the connected Outlook account. Commonly used to book a retrospective after incident resolution.
The Outlook calendar to create the event on. Rootly fetches the list of available calendars from your connected account.
The event title. Supports [Liquid variables](/liquid/incident-variables) — for example, `Retrospective for {{ incident.title }}`. Maximum 200 characters.
The event body. Supports Liquid and Markdown. Maximum 200 characters.
Email addresses to invite. Supports Liquid — for example, `{{ incident.incident_lead | get: "email" }}` or `{{ incident.subscribers | map: "email" | join: "," }}`.
The timezone for the event's start and end times. The **Time of Meeting** value will be interpreted in this timezone.
How many days from the workflow run to schedule the event. Range: 0–31. A value of `0` schedules the event for today.
The length of the event. Minimum 15 minutes. Accepts natural language — for example, `30min`, `1h`, `1h 30min`.
The start time in `HH:MM` format (24-hour). Interpreted in the timezone selected above. Defaults to `12:00`.
When enabled, weekend days are not counted when calculating the event date from **Days Until Meeting**. Defaults to `true`.
When enabled, attaches a Microsoft Teams meeting link to the calendar event.
Logs the created event to the incident timeline.
One or more Slack channels to share the event details to.
The most common setup is a workflow triggered on **incident resolved** that creates a retrospective event 3–5 business days out, with the incident lead and subscribers as attendees. Set **Exclude Weekends** to `true` so the meeting always lands on a weekday.
## Uninstall
To remove the Outlook integration:
1. Go to **Configuration → Integrations** and find **Outlook**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
## Frequently Asked Questions
Yes. The `Calendars.ReadWrite.Shared` permission gives Rootly access to any calendar the connected account can manage, including shared and delegate calendars. These will appear in the **Calendar** dropdown in the workflow action.
If **Exclude Weekends** is enabled, Rootly skips Saturday and Sunday when counting days, so the event will always land on a weekday. If disabled, the event will be scheduled on the weekend day.
Yes. There is no one-per-incident restriction. Each **Create an Outlook Event** workflow action creates a new calendar event independently.
Rootly automatically refreshes the token in the background using the stored refresh token. If refresh fails — for example, if the connected account's permissions were revoked — event creation will fail until you reconnect. This is why a service account is recommended.
# Rootly integrations with third-party tools
Source: https://docs.rootly.com/integrations/overview
Integrations connect Rootly with third-party services and internal tools to extend incident response, automation, and collaboration.
Integrations connect Rootly with the tools your teams already use, such as alerting platforms, collaboration tools, ticketing systems, and internal services.
By connecting these systems to Rootly, you can automate incident workflows, sync data across tools, reduce manual coordination, and keep responders working in the systems they already know.
## What Is an Integration?
An integration is a connection between Rootly and another system. That system might be a third-party product or custom software built by your organization.
Rootly supports a wide range of integrations across categories such as:
* Communication and collaboration
* Alerting and on-call
* Observability and monitoring
* Issue and project tracking
* Video conferencing
* Automation and AI
Popular examples include [PagerDuty](/integrations/pagerduty/pagerduty), [Jira](/integrations/jira/jira), [Zoom](/integrations/zoom/zoom), [Kubernetes](/integrations/kubernetes), and [GitHub](/integrations/github/github).
## How to Use This Section
Use the **Integrations** navigation on the left to browse available integrations by category.
Most integration sections include documentation for:
* Overview
* Installation or setup
* Workflow actions
* Alerting behavior, when supported
* Integration-specific configuration
If you are setting up a new integration, start with that integration’s main page and then follow any linked installation or workflow guides.
## Custom Integrations
If you want to connect Rootly to internal tooling or build your own integration, use the [API documentation](/api-reference/overview) to get started.
This is useful for organizations that want to extend Rootly with custom automation, internal systems, or proprietary workflows.
For alerting tools that don't have a dedicated Rootly integration, the [Generic Webhook Alert Source](/integrations/generic-webhook-alert-source/generic-webhook-alert-source) ingests alerts from any tool that can POST a JSON webhook.
## Security
* Integration keys are encrypted at rest using AES 256-bit encryption and protected by TLS in transit.
* Key management is in place for encryption keys used by production services.
For stricter network controls, see the documentation for Rootly outbound IP allowlisting if your organization restricts incoming traffic by source IP.
# PagerTree
Source: https://docs.rootly.com/integrations/pager-tree
Connect PagerTree to Rootly for inbound alert webhooks, outbound paging, linked incident workflows, and automatic alert synchronization.
## Introduction
The PagerTree integration connects Rootly with PagerTree so teams can receive alert activity in Rootly and page responders from Rootly when incidents need escalation.
This integration is a good fit for teams that already use PagerTree for alerting or paging and want Rootly to act as the central place for incident coordination and workflow automation.
With the PagerTree integration, you can:
* Receive PagerTree alert activity in Rootly through outgoing webhooks
* Create and update Rootly alerts from PagerTree events
* Page PagerTree teams and users from Rootly
* Create PagerTree alerts from incident workflows
* Automatically resolve linked PagerTree alerts when Rootly incidents are resolved
## Before You Begin
Before installing the integration, make sure you have:
* A Rootly account with permission to manage integrations
* A PagerTree account with permission to create API keys
* Access to create an **Outgoing Webhook** integration in PagerTree
* The teams or users in PagerTree that you want Rootly to page
Rootly uses two separate credentials for this integration:
* The **PagerTree API key** is used for Rootly-to-PagerTree API requests
* The **Rootly webhook secret** is used when PagerTree sends webhook events into Rootly
## Install the PagerTree Integration in Rootly
Open the integrations page in Rootly and choose **PagerTree**.
From there, enter your PagerTree API key and save the integration.
Rootly uses this API key to communicate with the PagerTree API for paging, alert creation, and alert updates.
After saving the integration, Rootly provides the webhook details you will need in PagerTree.
You will use these values when configuring the PagerTree outgoing webhook:
* The Rootly webhook URL
* The Rootly webhook secret
## Configure PagerTree Outgoing Webhooks
PagerTree sends alert events to Rootly using an outgoing webhook. Rootly expects the standard PagerTree webhook payload and the correct Rootly webhook secret.
In PagerTree, create a new **Outgoing Webhook** integration.
PagerTree’s outgoing webhook documentation is available here:
[PagerTree Outgoing Webhook Guide](https://pagertree.com/docs/integration-guides/outgoing-webhook)
Configure the outgoing webhook in PagerTree using the webhook URL provided by Rootly.
Rootly typically expects the webhook secret to be included with the request, often as a `?secret=` query parameter on the webhook URL, unless the Rootly UI shows a different format for your workspace.
If the secret does not match, Rootly rejects the request.
Rootly expects the standard PagerTree outgoing webhook structure:
```json theme={null}
{
"type": "alert.created",
"data": { ... }
}
```
If you customize the PagerTree webhook template, make sure it still includes the fields Rootly needs, especially:
* `type`
* `data`
* Alert identifiers such as `id` and `sid`
* Alert details such as `title`, `description`, `status`, and `urgency`
## Supported PagerTree Events
Rootly supports the following PagerTree webhook events:
* `alert.created`
* `alert.open`
* `alert.acknowledged`
* `alert.rejected`
* `alert.timeout`
* `alert.resolved`
* `alert.dropped`
* `alert.handoff`
These events can create or update Rootly alerts and, when linked to a Rootly incident, may also add incident activity in Rootly.
## How PagerTree Events Appear in Rootly
When PagerTree sends a supported webhook event to Rootly, Rootly stores and processes that event as PagerTree alert activity.
In most cases, Rootly uses the PagerTree alert data to create or update a Rootly alert with:
* The PagerTree alert ID as the external reference
* The alert title or description as the Rootly summary
* PagerTree status and urgency as labels
* A PagerTree alert URL for reference
If a PagerTree event is already associated with a synced Rootly incident, Rootly may skip creating a duplicate alert and instead add incident activity where appropriate.
## Severity and Urgency Mapping
When Rootly creates or updates PagerTree alerts via workflows, it maps Rootly incident severity to PagerTree severity levels:
| Rootly Severity | PagerTree Severity |
| --------------- | ------------------ |
| Critical | SEV-1 |
| High | SEV-2 |
| Medium | SEV-3 |
| Low | SEV-4 |
You can also set urgency explicitly when configuring a workflow action. Supported urgency values are `critical`, `high`, `medium`, `low`, and `auto` (lets PagerTree decide based on its own rules).
## Page PagerTree from Rootly
Rootly can also page PagerTree teams or users when incidents require escalation.
This is commonly used when:
* A Rootly incident needs to notify a PagerTree team
* A Slack-driven incident flow needs to escalate into PagerTree
* An incident workflow should automatically create a PagerTree alert
Rootly sends these requests to PagerTree using your configured API key.
## Default Workflows
When the PagerTree integration is connected, Rootly can create default workflows to support common PagerTree actions.
These workflows typically include:
* Creating a PagerTree alert when a Rootly incident is created
* Automatically resolving a linked PagerTree alert when the Rootly incident is resolved
After installation, review these workflows to make sure they match your team’s escalation process.
## Troubleshooting
This usually means Rootly is not accepting the webhook request. The most common cause is an incorrect or missing Rootly webhook secret. When the secret does not match, Rootly can return an error response such as HTTP 401.
Check the PagerTree outgoing webhook rules and confirm events are actually being sent to Rootly. Custom webhook rules or ignored events in PagerTree can prevent delivery.
If you customized the PagerTree outgoing webhook payload, make sure it still includes the standard fields Rootly expects, including the event type and alert data object.
PagerTree may retry failed webhook deliveries, and according to PagerTree’s webhook documentation those retries can happen multiple times. Rootly also uses PagerTree alert identifiers to determine how events should be created or updated, so retries and identifier reuse can affect how alerts appear.
If webhook delivery is succeeding but new alerts are no longer being created, check whether your Rootly workspace has reached its alert limits. Incoming PagerTree alerts are still subject to your Rootly plan limits.
## Related Pages
Automate incident creation, notifications, and follow-up actions for alerts.
Page and manage incidents from Slack when Slack is part of your incident workflow.
Learn how incidents are created, updated, and escalated in Rootly.
# PagerDuty
Source: https://docs.rootly.com/integrations/pagerduty/pagerduty
Connect PagerDuty to Rootly to page on-call responders, sync incidents in both directions, and import teams and schedules.
For a more seamless and deeper on-call experience, consider using Rootly On-Call. See [how Rootly On-Call compares to PagerDuty](https://rootly.com/comparisons/pagerduty-vs-rootly-on-call).
The PagerDuty integration connects Rootly with PagerDuty so teams can coordinate incidents, alerts, and on-call response across both platforms.
This integration is a strong fit for teams that already use PagerDuty for alerting or on-call management and want Rootly to act as the central place for incident coordination, workflows, and response automation.
With the PagerDuty integration, you can:
* Import, link, and sync services from PagerDuty into Rootly
* View on-call personnel directly from Slack
* Page PagerDuty services, escalation policies, and users from Rootly
* Invite on-call responders into incidents and assign incident roles automatically
* Keep key incident and alert activity aligned between Rootly and PagerDuty
* Ingest supported PagerDuty webhook events as Rootly alerts
## Before You Begin
Before setting up the PagerDuty integration, make sure you have:
* A Rootly account with permission to manage integrations
* A PagerDuty account with access to authorize integrations
* The services, escalation policies, or users you want Rootly to page
* Slack connected as well, if you want to use Slack-based on-call and paging flows
### PagerDuty Permissions
PagerDuty permissions in Rootly are tied to the PagerDuty user who completes the OAuth connection.
That means Rootly can only read from and write to the PagerDuty objects that the authenticated PagerDuty user has access to. Choose the PagerDuty account carefully, and use a service account when possible so the integration remains stable over time.
## Installation
Locate **PagerDuty** in the [Integrations catalog](https://rootly.com/account/integrations) and select **Setup**.
During setup, you will be prompted to sign in to PagerDuty or create a PagerDuty account if needed.
After signing in, grant Rootly permission to connect to your PagerDuty account.
Once authorization is complete, the PagerDuty integration is connected in Rootly.
### Set Up PagerDuty Webhooks
PagerDuty webhooks allow Rootly to receive supported PagerDuty webhook events for alerts and incident-related activity.
Rootly attempts to create the webhook for you automatically if the authenticated PagerDuty user has permission to create webhooks. If not, you can still create the webhook manually in PagerDuty.
#### Via the PagerDuty Web UI
In PagerDuty, navigate to **Integrations > Generic Webhooks**.
Select **+ New Webhook** to open the webhook creation form.
Use the following configuration in PagerDuty:
* **Webhook URL:** `https://webhooks.rootly.com/webhooks/incoming/pagerduty_webhooks`
* **Scope Type:** Choose one of:
* `Service` — only events for the selected service are sent to Rootly
* `Team` — only events for the selected team are sent to Rootly
* `Account` — events across the PagerDuty account are sent to Rootly
* **Description:** Optional
* **Custom Header Name:** `secret`
* **Custom Header Value:** ``
You can find the webhook URL and header secret in Rootly on the **Integrations > PagerDuty** setup screen.
The webhook URL is shared across Rootly accounts. The `secret` value is unique to your Rootly account.
Rootly supports the following PagerDuty webhook event types:
```text theme={null}
incident.acknowledged
incident.annotated
incident.delegated
incident.escalated
incident.priority_updated
incident.reassigned
incident.reopened
incident.resolved
incident.responder.added
incident.responder.replied
incident.triggered
incident.unacknowledged
pagey.ping
```
Rootly recommends selecting the supported incident events relevant to your Rootly workflows.
After completing the form, select **Add Webhook**.
PagerDuty may display a PagerDuty-generated webhook secret as part of its confirmation flow. You do not need that value for the Rootly integration.
#### Via the PagerDuty API
PagerDuty webhooks can also be created through the PagerDuty API.
Use the same Rootly endpoint and secret shown in the web UI setup:
* **URL:** `https://webhooks.rootly.com/webhooks/incoming/pagerduty_webhooks`
* **Header:** `secret: `
You can find the secret token on the Rootly **Integrations > PagerDuty** setup screen.
Use the same supported event list shown above when configuring subscriptions.
## Smart Defaults
Smart Defaults help teams get started with the PagerDuty integration faster by preconfiguring common behaviors that would otherwise require manual workflow setup.
This is useful for teams that want a simpler PagerDuty setup in Rootly without having to build every automation from scratch on day one.
Smart Defaults cover two directions of activity:
* **Rootly to PagerDuty** for paging, inviting responders, and resolving linked PagerDuty incidents
* **PagerDuty to Rootly** for alert ingestion, Slack notifications, incident creation, and sync-related behaviors
To review or update these settings, go to **Integrations > PagerDuty > Configure**.
### Rootly to PagerDuty
The first section of Smart Defaults controls actions that begin in Rootly and trigger behavior in PagerDuty.
In the PagerDuty configuration screen, locate the **Rootly to PagerDuty** section.
The **Auto-page on-call responder when an incident is created** setting allows Rootly to notify PagerDuty responders as soon as a Rootly incident is created.
Rootly determines who to page based on the selected PagerDuty service or escalation policy.
If both are configured, the selected escalation policy overrides the escalation policy linked to the selected service.
The services and escalation policies shown in these dropdowns are imported from your connected PagerDuty workspace.
The **Auto-invite on-call responder to new incident Slack channel** setting allows Rootly to invite PagerDuty on-call responders into the new incident Slack channel when the incident is created.
Rootly determines who to invite using the selected PagerDuty service or escalation policy. If both are configured, the escalation policy overrides the one linked to the selected service.
This setting requires Slack to be connected in Rootly.
The **Auto-resolve PagerDuty incident** setting allows Rootly to resolve the linked PagerDuty incident when the Rootly incident is resolved.
This is a one-way action from Rootly to PagerDuty. If you want PagerDuty activity to create or update alerts in Rootly, see [Alert Ingestion](#alert-ingestion) below.
### PagerDuty to Rootly
The second section of Smart Defaults controls actions that begin in PagerDuty and affect Rootly.
In the PagerDuty configuration screen, locate the **PagerDuty to Rootly** section.
The **Send PagerDuty alerts to Rootly** setting allows Rootly to ingest supported PagerDuty webhook events as alerts.
This depends on the PagerDuty webhook being configured correctly. To complete setup, follow the instructions on the Installation page.
This setting applies to supported PagerDuty webhook event types, not every possible PagerDuty event.
The **Notify Slack channel of new PagerDuty alerts** setting allows Rootly to send PagerDuty alert messages into a selected Slack channel.
Enable **Send PagerDuty alerts to Rootly** first, then choose the Slack channel you want Rootly to notify.
You can use **Send Test** to verify that the Slack channel is configured correctly.
Rootly rebuilds its Slack channel cache twice a day, at 09:00 and 21:00 UTC. If your channel does not appear in the dropdown, use **Refresh channels** to load the latest channels. See [Refresh and Reconnect](/integrations/slack/slack#refresh-channels).
If the selected channel is private, make sure the Rootly Slack bot has been added to that channel first.
The **Automatically create incidents in Rootly from PagerDuty alerts** setting allows Rootly to create incidents automatically from incoming PagerDuty alerts.
This setting is useful for teams that want PagerDuty events to drive incident creation in Rootly, but it should be enabled intentionally since not every alert should necessarily become a Rootly incident.
### Additional PagerDuty Settings
Depending on your configuration, the PagerDuty integration can also include additional settings for:
* Default PagerDuty incident title and description values
* Service and team sync or import behavior
* Other PagerDuty-to-Rootly coordination options
Use these alongside Smart Defaults when you want a broader PagerDuty configuration beyond the most common automation patterns.
### Smart Defaults Notes
* Smart Defaults simplify common PagerDuty use cases, but they do not replace every possible custom workflow
* Some Smart Default settings depend on Slack being connected in Rootly
* PagerDuty services and escalation policies used in these settings are imported from your PagerDuty workspace
* Automatically creating incidents from PagerDuty alerts should be reviewed carefully before enabling in production
## Import Teams
You can import PagerDuty teams into Rootly teams from the **Teams** page. This is useful when you want to align your Rootly team structure with your existing PagerDuty configuration.
Once imported, Rootly can use the team relationship during incident workflows, escalation actions, and on-call lookups.
## Workflow Actions
The following workflow actions are available for the PagerDuty integration.
### Page PagerDuty On-Call
Use this action to page an on-call responder through PagerDuty. In practice, this creates or updates a PagerDuty incident from the Rootly incident.
In PagerDuty, paging is tied to incident creation and responder assignment.
Each Rootly incident can only be linked to one PagerDuty incident.
The **Service** field specifies which PagerDuty service should be paged.
If you have imported PagerDuty services into Rootly, you may be able to reference them dynamically from the workflow configuration.
PagerDuty requires every incident to be associated with a service.
The **Escalation Policy** field lets you override the default escalation policy associated with the selected service.
The **Users** field lets you page specific PagerDuty users instead of relying on the default service routing.
Use these fields to control how the PagerDuty incident is created:
* **Title**
* **Urgency**
* **Message**
The **Message** field supports Liquid syntax.
Use the [Incident Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test Liquid values before adding them to your workflow action.
The **Always Create New PagerDuty Incident on Page** setting controls what happens if the Rootly incident is already linked to a PagerDuty incident.
If enabled, Rootly creates a new PagerDuty incident, but that new incident is not linked back to the Rootly incident.
If disabled, Rootly continues using the existing linked PagerDuty incident and may add responders to that incident instead.
Adding responders to an existing PagerDuty incident may depend on PagerDuty plan capabilities such as coordinated responding.
### AutoAssign Role from On-Call
Use this action to assign the current PagerDuty on-call responder to an Incident Role in Rootly.
The **Incident Role** field determines which Rootly incident role should be assigned.
To learn more about incident roles, see [Incident Roles](/managing-teams/incident-roles).
Use one of the following as the source of truth for the on-call lookup:
* A **Service**
* An **Escalation Policy**
* A **Schedule**
For the clearest results, choose one source rather than trying to combine multiple sources in the same action.
When assigning from an escalation policy, Rootly looks up the on-call responders at the lowest active escalation level and assigns the first matching user found in Rootly.
This action does not progress through the full escalation policy over time the way an actual page would.
### Invite On-Call to Slack Channel
Use this action to invite PagerDuty on-call responders into Slack channels.
Use one of the following as the source of truth for who should be invited:
* A **Service**
* An **Escalation Policy**
* A **Schedule**
For the clearest results, choose one source rather than trying to combine multiple sources in the same action.
Use the **Channels** field to select one or more Slack channels to invite PagerDuty responders into.
You can use:
* `{{ incident.slack_channel_id }}` for the current incident channel
* `{{ parent_incident.slack_channel_id }}` for the parent incident channel
When using a PagerDuty escalation policy, Rootly invites the on-call users at the lowest active escalation level rather than every user in the full policy.
This keeps the invite behavior aligned with how Rootly looks up active on-call responders.
### Update PagerDuty Incident
Use this action to update an existing PagerDuty incident linked to the Rootly incident.
Use **PagerDuty Incident ID** to specify which PagerDuty incident should be updated.
Set this field to `{{ incident.pagerduty_incident_id }}` to reference the PagerDuty incident linked to the Rootly incident.
You can update fields such as:
* **Title**
* **Status**
* **Urgency**
* **Priority**
* **Escalation Level**
The **Title** field supports Liquid syntax.
The **Status** field can also be set to `auto` if you want PagerDuty status behavior to follow Rootly status logic.
Use **Resolution Message** when resolving the PagerDuty incident.
This field is useful for adding final context or outcome details to the PagerDuty incident when Rootly closes it.
Liquid support for this field may vary, so test the output before relying on dynamic values in production.
### Create PagerDuty Status Update
Use this action to add a status update message to the linked PagerDuty incident.
Use **PagerDuty Incident ID** to specify which PagerDuty incident should receive the status update.
Set this field to `{{ incident.pagerduty_incident_id }}` to target the linked PagerDuty incident.
Use **Message** to define what should be posted into the PagerDuty incident notes or status updates.
This field supports Liquid syntax.
A common pattern is to post the latest Rootly incident event into PagerDuty.
### Workflow Notes
* Workflow actions can be combined to page, invite, assign, and synchronize activity across Rootly and PagerDuty
* Some PagerDuty actions depend on the PagerDuty plan and permissions of the connected account
* Rootly links only one PagerDuty incident to each Rootly incident
* Advanced teams can combine these actions with broader Rootly workflow conditions and branching logic
## Alert Ingestion
Rootly can ingest supported PagerDuty webhook events as alerts. These alerts can then be used to drive incident automation, alert workflows, and incident updates in Rootly. The steps below cover configuring ingestion and the automation it drives.
### Set Up the Workflow
PagerDuty events are ingested into Rootly as alerts, so the correct workflow type is **Alert**.
Create a new workflow and select **Alert** as the workflow type.
This tells Rootly that the workflow should run in response to alert activity rather than incident, action item, or retrospective activity.
Select **Alert Created** as the workflow trigger.
In this pattern, the workflow starts when Rootly creates a new alert from a supported PagerDuty webhook event.
Configure the workflow so it only runs for PagerDuty alerts you actually want to automate.
A typical setup starts with:
* **Alert source** is `Pagerduty`
* **Alert labels** contain the PagerDuty event type you want to react to
* Optional payload filtering if you need more precise matching
### Recommended Run Conditions
PagerDuty alerts in Rootly include label values that make it easier to target specific event types without relying only on payload filtering.
A common pattern is to match on the alert source first, then use `action:` labels to decide which PagerDuty event should trigger the workflow. You can also add `service_id:` if you only want the workflow to run for alerts from a particular PagerDuty service.
Common examples include:
* **New PagerDuty incident triggered**
* `action:incident.triggered`
* Optional: `service_id:PLVWMVW`
* **Existing PagerDuty incident acknowledged**
* `action:incident.acknowledged`
* Optional: `service_id:PLVWMVW`
* **Existing PagerDuty incident resolved**
* `action:incident.resolved`
* Optional: `service_id:PLVWMVW`
* **Responder added to an existing PagerDuty incident**
* `action:incident.responder.added`
Other `action:` label values may also be available depending on the specific supported PagerDuty event being ingested.
### Filter by Payload When Needed
If labels are not specific enough, you can add payload-based filtering.
Use JSONPath to select the field from the alert payload, then compare it to a value or regular expression. This is helpful when your team only wants to react to PagerDuty events that match a certain property in the webhook payload.
For example:
* JSONPath: `$.object.specific_field`
* Match value: `/specific_value/i`
Many workspaces start with a single payload condition plus labels. Some teams may have support for multiple payload conditions, depending on feature availability.
In most cases, it is better to filter by labels first and only use payload filters where labels are not enough.
Helpful tools:
* [JSON Path Explorer](https://rootly.com/account/help/json-path-explorer)
* [Rubular](https://rubular.com/) for Ruby regular expressions
### Create a Rootly Incident from a PagerDuty Alert
Use the **Create Incident** action when you want a PagerDuty alert to declare a new incident in Rootly.
Because this action is being driven by an alert, dynamic values use the `{{ alert. }}` format. If you want the new Rootly incident to stay linked to the PagerDuty incident, include a custom mapping that stores the PagerDuty identifiers on the incident.
Add a **Create Incident** action to your alert workflow.
This is the action that declares the Rootly incident when the PagerDuty alert arrives.
Add the following custom mapping so the new Rootly incident stays associated with the PagerDuty incident:
```json theme={null}
{
"pagerduty_incident_id": "{{ alert.data.data.id }}",
"pagerduty_incident_number": "{{ alert.data.data.number }}",
"pagerduty_incident_url": "{{ alert.external_url }}"
}
```
If alert grouping is enabled, Rootly skips incident creation for grouped alerts that are not the leader alert.
### Update an Existing Rootly Incident from a PagerDuty Alert
Use the **Update Incident** action when the PagerDuty alert should modify an incident that already exists in Rootly.
The most important part of this setup is telling Rootly how to find the correct incident. For PagerDuty-driven updates, the standard pattern is to match on `pagerduty_incident_id`.
Add an **Update Incident** action to the workflow for the PagerDuty event you want to handle.
Set the match fields as follows:
* **Attribute to Match:** `pagerduty_incident_id`
* **Attribute Value:** `{{ alert.data.data.id }}`
This tells Rootly which incident should be updated when the PagerDuty alert is processed.
### Use Custom Fields Mapping for Richer Automation
**Custom Fields Mapping** lets you set additional incident attributes dynamically. This field accepts JSON with embedded Liquid, which makes it useful for incident timestamps, role assignments, and custom form fields.
#### Log acknowledgement time
Use this when the workflow is responding to an acknowledged PagerDuty incident:
```json theme={null}
{
"acknowledged_at": "{{ alert.created_at }}"
}
```
Pair this with run conditions for `action:incident.acknowledged`.
#### Assign an incident role to the acknowledging user
You can map the PagerDuty acknowledging user back to a Rootly user by combining Liquid with custom JSON:
```liquid theme={null}
{% assign pd_user_email = team.pagerduty_users | find: 'id', alert.data.agent.id | get: 'email' %}
{% assign rootly_user_id = team.users | find: 'email', pd_user_email | get: 'id' %}
{
"incident_role_assignments_attributes": {
"0": {
"incident_role_id": "801dd6f8-f810-4819-9c3c-e77bc7038581",
"user_id": "{{ rootly_user_id }}"
}
}
}
```
Pair this with run conditions for `action:incident.acknowledged`.
#### Set a custom Rootly field
Example for a text field with a hard-coded value:
```json theme={null}
{
"form_field_selections_attributes": [
{
"form_field_id": "e041106e-cb9a-404b-8ae1-51a1d6213a68",
"value": "Nifty Gateway"
}
]
}
```
Example using data from the alert payload:
```json theme={null}
{
"form_field_selections_attributes": [
{
"form_field_id": "e041106e-cb9a-404b-8ae1-51a1d6213a68",
"value": "{{ alert.data.organization.name }}"
}
]
}
```
Replace that Liquid path with one that actually exists in your PagerDuty alert payload.
Example for a single-select or multi-select field:
```json theme={null}
{
"form_field_selections_attributes": [
{
"form_field_id": "e041106e-cb9a-404b-8ae1-51a1d6213a68",
"selected_option_ids": ["option_id"]
}
]
}
```
### Alert Notes
* Supported PagerDuty webhook events do not all behave the same way in Rootly
* Some accepted PagerDuty events may not create an alert at all, so there may be nothing for an alert workflow to trigger from
* `incident.triggered` alerts may be skipped if the PagerDuty incident is already linked to an existing Rootly incident
* PagerDuty webhook payload structure can differ by webhook version, so always verify your Liquid paths and payload fields before using them in production
### Debugging Alerts
If a workflow is not behaving as expected, open the workflow run details in Rootly by navigating to:
**... > View Runs > View**
Common errors include:
| Error Type | Comment |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `unknown attribute 'incident_property' for Incident.` | This usually means the incident property you are trying to set is not supported, is not enabled for workflows, or the syntax is incorrect. Verify the field name and confirm it can be set through workflows. |
| `unexpected token at '{ "incident_property": }'` | This means the custom mapping syntax is invalid. Make sure your JSON is complete, properly quoted, and does not contain invalid syntax. |
## Frequently Asked Questions
PagerDuty and Rootly overlap in some areas, but Rootly provides a broader incident management experience with stronger coordination workflows, automation, retrospectives, stakeholder communications, and integrated on-call capabilities.
With Rootly On-Call, Rootly can replace PagerDuty for many teams. If you are evaluating whether to consolidate tooling, see [how Rootly compares to PagerDuty](https://rootly.com/comparisons/pagerduty-vs-rootly-on-call).
Rootly will continue to support PagerDuty for teams that want to keep using it as part of their incident response stack.
Yes. Rootly does not require PagerDuty. Many teams use Rootly alongside an on-call provider, but Rootly can still support incident management workflows even if your team does not use PagerDuty.
This usually means the PagerDuty authorization did not complete successfully. Common causes include an inactive PagerDuty account, revoked authorization, or using the wrong PagerDuty account during setup.
Re-authorize the integration and confirm your PagerDuty account is active. If the issue continues, contact [support@rootly.com](mailto:support@rootly.com) or use **Help > Chat with Us** in Rootly.
# PeopleHR
Source: https://docs.rootly.com/integrations/peoplehr
Connect PeopleHR to Rootly via iCal to overlay employee time off and company holidays on on-call schedules, surfacing coverage gaps early.
## Overview
PeopleHR exposes your team's time-off and holiday calendar as an iCal feed. Point Rootly at that feed and vacations, PTO, and company holidays appear directly on top of your on-call schedule timeline. Shifts that overlap with someone's leave are highlighted, making it easy to create an override before the next page fires.
This is a read-only overlay. PeopleHR stays the source of truth for time off; Rootly polls the feed in the background and keeps the schedule view current.
***
## Exporting the Calendar Feed from PeopleHR
PeopleHR maintains its own walkthrough for generating an iCal calendar feed, including which permissions are required and where the feed link is surfaced in the UI.
Follow [PeopleHR's iCal calendar feed article](https://accessgroup.my.site.com/Support/s/article/PeopleHR-iCal-calendar-feed?language=en_US) to copy the iCal URL for your time-off calendar, then bring it back to Rootly for the next step.
***
## Adding the Feed to Rootly
Once you have the PeopleHR iCal URL, the rest of the setup happens inside Rootly's schedules view.
In the Rootly dashboard, go to **On-Call → Schedules**. In the calendar preview area, open the **Holiday calendars** dropdown.
Select **Add your team's holiday calendar**, then choose **Add a holiday calendar**.
Paste the iCal URL you copied from PeopleHR into the URL field.
Give the calendar a descriptive name (for example, `PeopleHR — Engineering PTO`) so teammates know what it represents. Select the appropriate timezone, or leave it blank to let Rootly infer it from the feed.
Click **Add**. Rootly fetches the calendar and begins syncing automatically. Back in the schedule view, select the new feed from the **Holiday calendars** dropdown to overlay PeopleHR time off on the on-call timeline.
For the full behavior of holiday calendars in Rootly — conflict highlighting, recurring events, multi-region setups — see [Adding a Holiday Calendar](/on-call/holiday-calendar).
***
## Troubleshooting
The feed has to be toggled on per schedule preview. Open the **Holiday calendars** dropdown above the schedule and confirm the PeopleHR feed is selected.
The calendar timezone determines how all-day events align with on-call shifts. Remove the calendar and re-add it with the correct timezone, or leave the timezone field blank to let Rootly infer it from the feed.
Rootly resyncs feeds periodically in the background, so a change made seconds ago may take a few minutes to appear.
***
## Frequently Asked Questions
No. Holiday calendars are read-only previews — they surface conflicts so you can decide whether to override, but they never reassign shifts.
Yes. If your team uses separate PeopleHR calendars per department or region, add each as its own feed and toggle them on per schedule.
On the Rootly side, anyone with the **On-Call Admin** or **On-Call User** role can add a holiday calendar feed — see [Schedule Permissions](/on-call/schedules#permissions-access). The PeopleHR side depends on your PeopleHR account configuration; refer to the PeopleHR help article for the specifics.
# Personio
Source: https://docs.rootly.com/integrations/personio
Connect Personio to Rootly via iCal feed to overlay employee time off and PTO on on-call schedule timelines, surfacing coverage gaps in advance.
## Overview
Personio exposes your team's time-off calendar as an iCal feed. Point Rootly at that feed and vacations and PTO appear directly on top of your on-call schedule timeline. Shifts that overlap with someone's leave are highlighted, making it easy to create an override before the next page fires.
This is a read-only overlay. Personio stays the source of truth for time off; Rootly polls the feed in the background and keeps the schedule view current.
***
## Exporting the Calendar Feed from Personio
Personio maintains its own walkthrough for generating an iCal link, including which user role can generate one and where the link is surfaced in Personio's settings.
Follow [Personio's help article](https://support.personio.de/hc/en-us/articles/360000286117-Add-a-Personio-Calendar-via-an-iCal-link) to copy the iCal URL, then bring it back to Rootly for the next step.
***
## Adding the Feed to Rootly
Once you have the Personio iCal URL, the rest of the setup happens inside Rootly's schedules view.
In the Rootly dashboard, go to **On-Call → Schedules**. In the calendar preview area, open the **Holiday calendars** dropdown.
Select **Add your team's holiday calendar**, then choose **Add a holiday calendar**.
Paste the iCal URL you copied from Personio into the URL field.
Give the calendar a descriptive name (for example, `Personio — EMEA PTO`) so teammates know what it represents. Select the appropriate timezone, or leave it blank to let Rootly infer it from the feed.
Click **Add**. Rootly fetches the calendar and begins syncing automatically. Back in the schedule view, select the new feed from the **Holiday calendars** dropdown to overlay Personio time off on the on-call timeline.
For the full behavior of holiday calendars in Rootly — conflict highlighting, recurring events, multi-region setups — see [Adding a Holiday Calendar](/on-call/holiday-calendar).
***
## Troubleshooting
The feed has to be toggled on per schedule preview. Open the **Holiday calendars** dropdown above the schedule and confirm the Personio feed is selected.
The calendar timezone determines how all-day events align with on-call shifts. Remove the calendar and re-add it with the correct timezone, or leave the timezone field blank to let Rootly infer it from the feed.
Rootly resyncs feeds periodically in the background, so a change made seconds ago may take a few minutes to appear.
***
## Frequently Asked Questions
No. Holiday calendars are read-only previews — they surface conflicts so you can decide whether to override, but they never reassign shifts.
Yes. If your team uses separate Personio calendars per department or region, add each as its own feed and toggle them on per schedule.
On the Rootly side, anyone with the **On-Call Admin** or **On-Call User** role can add a holiday calendar feed — see [Schedule Permissions](/on-call/schedules#permissions-access). The Personio side depends on your Personio account configuration; refer to the Personio help article for the specifics.
# Pulumi
Source: https://docs.rootly.com/integrations/pulumi
Manage Rootly resources as infrastructure as code using the official Pulumi provider for Node.js and TypeScript with full support for incident configurations.
## Introduction
The Rootly Pulumi provider lets you manage your Rootly configuration — severities, services, functionalities, on-call schedules, escalation policies, workflows, custom form fields, and more — as infrastructure as code using Pulumi. This allows you to version-control your Rootly configuration, apply changes through CI/CD pipelines, and keep your incident management setup consistent across environments.
The provider is built on top of the [Rootly Terraform provider](/integrations/terraform) and is available on the [Pulumi Registry](https://www.pulumi.com/registry/packages/rootly/installation-configuration/).
The Rootly Pulumi provider currently supports **JavaScript and TypeScript** only. Support for Python, Go, and .NET is not yet available.
## Before You Begin
Before setting up the Pulumi provider, make sure you have:
* [Pulumi CLI](https://www.pulumi.com/docs/install/) installed
* Node.js installed
* A Rootly API token — generate one in **Account** > **Manage API keys** > **Generate New API Key**
## Installation
Add the Rootly Pulumi package to your project:
```bash theme={null}
npm install @rootly/pulumi
```
Or with Yarn:
```bash theme={null}
yarn add @rootly/pulumi
```
Install the Pulumi provider binary:
```bash theme={null}
pulumi plugin install resource rootly v0.0.2 \
--server https://github.com/rootlyhq/pulumi-rootly/releases/download/v0.0.2
```
Set your Rootly API token. The recommended approach is to store it as an encrypted Pulumi secret:
```bash theme={null}
pulumi config set rootly:apiToken YOUR_API_TOKEN --secret
```
Alternatively, use an environment variable:
```bash theme={null}
export ROOTLY_API_TOKEN=YOUR_API_TOKEN
```
Always use `--secret` when setting the API token via `pulumi config` to ensure it is encrypted in your stack state. Never commit an unencrypted API token to version control.
## Creating Resources
Import the provider and declare resources in your Pulumi program. The following example creates a set of severities, services, functionalities, and a workflow:
```typescript theme={null}
import * as rootly from "@rootly/pulumi";
// Severities
const sev0 = new rootly.Severity("sev0", {
name: "SEV0",
color: "#FF0000",
});
const sev1 = new rootly.Severity("sev1", {
name: "SEV1",
color: "#FFA500",
});
// Services
const apiService = new rootly.Service("api_service", {
name: "production-api",
color: "#800080",
});
// Functionalities
const checkout = new rootly.Functionality("checkout", {
name: "Checkout",
color: "#FFFFFF",
});
```
### Supported Resources
The provider supports the full range of Rootly configuration resources, including:
| Category | Examples |
| ------------------------- | ---------------------------------------------------------------------- |
| Incident classification | `Severity`, `IncidentType`, `IncidentRole` |
| Services & infrastructure | `Service`, `Functionality`, `Environment`, `Team` |
| On-call | `Schedule`, `EscalationPolicy` |
| Workflows | `WorkflowIncident`, `WorkflowActionItem`, and 200+ workflow task types |
| Forms & fields | `FormField`, `FormFieldOption` |
| Status pages | `StatusPage`, `StatusPageTemplate` |
For the full resource reference, see the [Pulumi Registry documentation](https://www.pulumi.com/registry/packages/rootly/api-docs/).
## Deploying Changes
Preview changes before applying them:
```bash theme={null}
pulumi preview
```
Apply your changes:
```bash theme={null}
pulumi up
```
Pulumi will show a diff of resources to be created, updated, or deleted before prompting for confirmation.
## Troubleshooting
Confirm your API token is set correctly. If using `pulumi config`, run `pulumi config get rootly:apiToken` to verify the value is present. If using the environment variable, confirm `ROOTLY_API_TOKEN` is exported in your shell. Check that the token has not been revoked in Rootly under **Account > Manage API keys**.
Run the plugin install command again to ensure the binary is present:
```bash theme={null}
pulumi plugin install resource rootly v0.0.2 \
--server https://github.com/rootlyhq/pulumi-rootly/releases/download/v0.0.2
```
You can verify installed plugins with `pulumi plugin ls`.
Check the error message from the Pulumi output — it typically includes the Rootly API response. Common causes include missing required fields (for example, `name` or `color` on a Severity) or invalid field values. Cross-reference with the [Rootly API reference](/api-reference/overview) for valid field constraints.
Run `pulumi refresh` to reconcile Pulumi's state with the actual state in Rootly. If resources were modified outside of Pulumi (for example, via the Rootly UI), they may be out of sync with the Pulumi stack state.
## Related Pages
The Rootly Terraform provider — the Pulumi provider is built on top of it.
The Rootly API reference — all resources the provider manages are available here.
Full resource reference and API docs on the Pulumi Registry.
# Python SDK
Source: https://docs.rootly.com/integrations/python-sdk
Auto-generated Python client for the Rootly API with sync and async support, type-safe models, and full coverage of incident, alert, and on-call endpoints.
The Rootly Python SDK is an auto-generated client for the Rootly API, published on PyPI as [`rootly`](https://pypi.org/project/rootly/) and imported in Python as `rootly_sdk`. Every path and method becomes a typed Python module with both synchronous and asynchronous variants, powered by [httpx](https://www.python-httpx.org/).
## Features
* **Full API coverage** — every endpoint becomes a Python module with typed parameters and responses
* **Sync and async** — each endpoint has blocking (`sync`) and async (`asyncio`) variants
* **Type-safe models** — generated data models for all request and response types
* **Built on httpx** — modern HTTP client with connection pooling, HTTP/2, and event hooks
## Requirements
* Python 3.8+
## Installation
```bash theme={null}
pip install rootly
```
```bash theme={null}
poetry add rootly
```
## Quick Start
```python theme={null}
from rootly_sdk import AuthenticatedClient
client = AuthenticatedClient(
base_url="https://api.rootly.com",
token="YOUR_API_TOKEN",
)
```
### Getting an API Key
1. Log in to your Rootly account
2. Navigate to **Settings** > **API Keys**
3. Create a new API key with the permissions you need
## Usage
### Synchronous Requests
```python theme={null}
from rootly_sdk.api.incidents import list_incidents, get_incident
from rootly_sdk.types import Response
with client as c:
# List incidents
incidents = list_incidents.sync(client=c)
# Get full response details
response: Response = list_incidents.sync_detailed(client=c)
print(response.status_code)
```
### Async Requests
```python theme={null}
from rootly_sdk.api.incidents import list_incidents, get_incident
async with client as c:
# Async list
incidents = await list_incidents.asyncio(client=c)
# Async with full response
response = await list_incidents.asyncio_detailed(client=c)
```
### Endpoint Pattern
Every endpoint provides four functions:
| Function | Description |
| ------------------ | ---------------------------------------------------------- |
| `sync` | Blocking request, returns parsed data or `None` |
| `sync_detailed` | Blocking request, returns full `Response` with status code |
| `asyncio` | Async version of `sync` |
| `asyncio_detailed` | Async version of `sync_detailed` |
All path parameters, query parameters, and request bodies become function arguments.
### Using Models
```python theme={null}
from rootly_sdk.models import Incident, Service, Alert
```
## Configuration
### Custom Base URL
```python theme={null}
client = AuthenticatedClient(
base_url="https://custom.rootly.com",
token="your-token",
)
```
### Custom SSL Certificate
```python theme={null}
client = AuthenticatedClient(
base_url="https://internal_api.rootly.com",
token="your-token",
verify_ssl="/path/to/certificate_bundle.pem",
)
```
### Custom httpx Configuration
```python theme={null}
def log_request(request):
print(f"{request.method} {request.url}")
def log_response(response):
print(f"{response.status_code}")
client = AuthenticatedClient(
base_url="https://api.rootly.com",
token="your-token",
httpx_args={
"event_hooks": {
"request": [log_request],
"response": [log_response],
}
},
)
```
You can also access the underlying httpx client directly:
```python theme={null}
httpx_client = client.get_httpx_client()
async_client = client.get_async_httpx_client()
```
## Feedback & Support
* **Package**: [rootly on PyPI](https://pypi.org/project/rootly/)
* **Source Code**: [GitHub Repository](https://github.com/rootlyhq/rootly-python)
* **Issues**: [GitHub Issues](https://github.com/rootlyhq/rootly-python/issues)
## Related resources
* [TypeScript SDK](/integrations/typescript-sdk)
* [Rust SDK](/integrations/rust-sdk)
* [Swift SDK](/integrations/swift-sdk)
# Quip
Source: https://docs.rootly.com/integrations/quip
Connect Quip to Rootly to automatically create and update retrospective documents from incidents using Genius workflows with templates and folder routing.
## Introduction
The Quip integration connects Rootly with your Quip workspace so teams can automatically create and update documents during and after incidents through Genius workflows.
With the Quip integration, you can:
* Automatically create Quip documents from incident workflows using retrospective templates or custom content
* Start documents from an existing Quip template
* Update existing Quip documents as an incident progresses
* Attach created documents directly to the incident record
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A Quip account with permission to create API keys in the Quip admin portal
* Access to [admin.quip.com](https://admin.quip.com)
Rootly recommends installing with a dedicated service account so the integration does not break if an individual user leaves your organization.
## Installation
Go to [admin.quip.com](https://admin.quip.com) and navigate to **Settings > Integrations**.
Create a new API key with the following settings:
* **Permissions**: `USER_READ` and `USER_WRITE`
* **Redirect URI**: `https://rootly.com/auth/quip/callback`
Copy the Client ID and Client Secret after creating the key — you will need both to complete the setup in Rootly.
Navigate to the integrations page in Rootly and select **Quip**.
Paste the **Client ID** and **Client Secret** from Quip into the Rootly integration settings and save.
Once saved, the **Create a Quip Page** and **Update a Quip Page** workflow actions are available in your Genius workflows.
## Workflow Actions
### Create a Quip Page
This action creates a new Quip document in a specified folder.
**Parent Folder**
The Quip folder where the document will be created. Leave blank to create in your private folder.
**Title**
The title of the Quip document. Defaults to `{{ incident.title }}`. Supports Liquid syntax.
Use the [Incident Variable Explorer](https://rootly.com/account/help/liquid-explorer) to preview what Liquid variables return for your incidents.
**Quip Template**
Optionally select an existing Quip document to use as a starting template. The new document will be based on the content of the selected template.
**Retrospective Template**
Select a predefined Rootly retrospective template to populate the document body. Templates are managed on the [Retrospective Templates page](https://rootly.com/account/retrospective-steps?tab=documents).
If a Retrospective Template is selected, it overrides any content defined in the Custom Content field.
**Custom Content**
Define the document body manually. Supports Liquid syntax. Used when no Retrospective Template is selected.
**Mark Post Mortem as Published**
When enabled, marks the retrospective status as `published` after the document is created. Use this when follow-up notification workflows trigger on published retrospectives.
### Update a Quip Page
This action updates an existing Quip document with new content.
**File ID**
The Quip thread ID of the document to update. Supports Liquid syntax.
When a **Create a Quip Page** action runs, Rootly stores the resulting document ID and URL on the incident record. Reference the file ID in subsequent update actions using Liquid variables.
**Title**
The updated title for the document. Supports Liquid syntax. Leave blank to keep the existing title.
**Content**
Additional content to append to the document. Supports Liquid syntax.
**Quip Template / Retrospective Template**
Re-render the document body using a Quip template or Rootly retrospective template.
## Uninstall
To remove the Quip integration, open the integrations panel in Rootly and select **Configure > Delete**.
# Rippling
Source: https://docs.rootly.com/integrations/rippling
Sync Rippling time off into Rootly to overlay employee vacations and PTO on on-call schedule timelines, surfacing coverage gaps before pages fire.
## Overview
Rippling exposes your team's time-off calendar as a subscribe-able feed. Point Rootly at that feed and vacations and PTO appear directly on top of your on-call schedule timeline. Shifts that overlap with someone's leave are highlighted, making it easy to create an override before the next page fires.
This is a read-only overlay. Rippling stays the source of truth for time off; Rootly polls the feed in the background and keeps the schedule view current.
***
## Exporting the Calendar Feed from Rippling
Rippling exposes a subscribe-able time-off calendar URL. Their [short video tutorial](https://www.youtube.com/watch?v=XWZsfwbF0jg) walks through the exact UI path. If you can't access the video, open Rippling's Time Off module and look for the calendar-subscription or calendar-export option — that's the screen the video lands on. If the option is hidden by your role's permissions, ask a Rippling admin to generate the URL for you.
The URL Rippling generates starts with the `webcal://` protocol. Rootly's holiday calendar field expects an `https://` URL — replace the `webcal://` prefix with `https://` before pasting it into Rootly.
***
## Adding the Feed to Rootly
Once you have the Rippling feed URL (with the `webcal://` prefix replaced by `https://`), the rest of the setup happens inside Rootly's schedules view.
In the Rootly dashboard, go to **On-Call → Schedules**. In the calendar preview area, open the **Holiday calendars** dropdown.
Select **Add your team's holiday calendar**, then choose **Add a holiday calendar**.
Paste the rewritten `https://` URL from Rippling into the URL field.
Give the calendar a descriptive name (for example, `Rippling — Company PTO`) so teammates know what it represents. Select the appropriate timezone, or leave it blank to let Rootly infer it from the feed.
Click **Add**. Rootly fetches the calendar and begins syncing automatically. Back in the schedule view, select the new feed from the **Holiday calendars** dropdown to overlay Rippling time off on the on-call timeline.
For the full behavior of holiday calendars in Rootly — conflict highlighting, recurring events, multi-region setups — see [Adding a Holiday Calendar](/on-call/holiday-calendar).
***
## Troubleshooting
Rippling generates URLs with a `webcal://` prefix that Rootly does not accept. Replace `webcal://` with `https://` and re-paste the URL.
The feed has to be toggled on per schedule preview. Open the **Holiday calendars** dropdown above the schedule and confirm the Rippling feed is selected.
The calendar timezone determines how all-day events align with on-call shifts. Remove the calendar and re-add it with the correct timezone, or leave the timezone field blank to let Rootly infer it from the feed.
***
## Frequently Asked Questions
No. Holiday calendars are read-only previews — they surface conflicts so you can decide whether to override, but they never reassign shifts.
Yes. If different teams or regions maintain separate Rippling time-off views, add each generated feed as its own calendar in Rootly.
Holiday calendar feeds are fetched over standard HTTPS. The `webcal://` scheme is just a client-side handler hint — the underlying URL is identical when rewritten to `https://`.
# Rollbar
Source: https://docs.rootly.com/integrations/rollbar
Connect Rollbar to Rootly to ingest error monitoring events as alerts and automate incident creation from application errors, regressions, and exceptions.
## Introduction
The Rollbar integration connects Rootly with your Rollbar error monitoring so teams can receive error events as alerts in Rootly and automate incident response from application exceptions and regressions.
With the Rollbar integration, you can:
* Ingest Rollbar error events as Rootly alerts
* Automatically resolve Rootly alerts when Rollbar sends a `resolved_item` event
* Use alert workflows to create incidents when error thresholds are exceeded
* Filter and route alerts by environment, error level, and project
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with permission to manage integrations
* Admin access to your Rollbar project settings
* The webhook URL and secret from your Rootly Rollbar integration page
You can find your webhook URL and secret by navigating to **Integrations > Rollbar > Configure** in Rootly.
## Installation
Navigate to the integrations page in Rootly and select **Rollbar**. Copy the webhook URL and secret shown in the configuration modal.
In Rollbar, navigate to your project notification settings:
```text theme={null}
https://rollbar.com///settings/notifications/
```
Select **Webhook** from the list of notification channels.
Enter the webhook URL from your Rootly Rollbar integration settings.
Select which Rollbar event types should be sent to Rootly. See the **Supported Events** section below for the full list of supported events.
Rootly does not support **deploy** events. Enabling deploy notifications will result in those events being ignored.
## Supported Events
Rootly accepts the following Rollbar event types:
| Event | Description |
| ------------------ | ---------------------------------------- |
| `new_item` | A new error or issue is first seen |
| `occurrence` | An error occurrence is recorded |
| `reactivated_item` | A previously resolved issue reactivates |
| `reopened_item` | A resolved issue is manually reopened |
| `resolved_item` | An issue is resolved in Rollbar |
| `item_velocity` | An issue exceeds an occurrence threshold |
| `exp_repeat_item` | An issue repeats at an exponential rate |
| `test` | A test notification from Rollbar |
When Rootly receives a `resolved_item` event, the corresponding Rootly alert is automatically resolved. All other supported events create or update an alert in the open state.
## How Alerts Are Mapped
Rootly extracts the following fields from each Rollbar event:
* **Summary** — prefixed with `[New issue]` followed by the issue title
* **External ID** — the Rollbar item `id`, used to deduplicate and match resolve events
* **Labels** — `level`, `environment`, `type`, `status`, `total_occurrences`, and `project_id` are attached as Rootly alert labels
Rollbar `environment` and `level` values are available as alert labels in Rootly. Use them in workflow run conditions to route production critical errors differently from development warnings.
## Troubleshooting
Confirm the webhook URL in Rollbar matches the one shown in your Rootly integration settings. Verify that at least one notification rule is enabled and that the rule conditions are being met by your Rollbar events.
Ensure the `resolved_item` notification rule is enabled in Rollbar. Rootly only resolves alerts when it receives this specific event type. Manual resolutions in Rollbar that do not trigger the webhook will not resolve the corresponding Rootly alert.
Rootly does not process `deploy` events. If deploy notifications are enabled in Rollbar, those events will be received but ignored by Rootly. Disable the deploy notification rule in Rollbar to avoid unnecessary webhook traffic.
Rollbar `test` events are supported and should create a test alert in Rootly. If the test event is not appearing, verify the webhook URL and check that the integration is active in Rootly.
## Uninstall
To remove the Rollbar integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related resources
* [Prometheus Alertmanager](/integrations/alertmanager)
* [Checkly](/integrations/checkly)
* [Chronosphere](/integrations/chronosphere)
* [Dynatrace](/integrations/dynatrace)
# Setup Wizard
Source: https://docs.rootly.com/integrations/rootly-wizard
Go from empty workspace to incident-ready in minutes: the Rootly Setup Wizard configures teams, on-call, alerting, and a status page from your terminal.
The Rootly Setup Wizard is a guided command-line tool for getting a new Rootly workspace operational quickly. It walks you through creating a team, putting people on call, wiring up escalation and alerting, and creating a status page, then fires a real test alert (that pages whoever is on call) and opens a test incident, so you can see the whole flow end to end without clicking through every setup screen.
The Setup Wizard is for **initial onboarding and configuration**. For day-to-day incident and alert management from the terminal, see the [CLI](/integrations/cli) and [Terminal UI](/integrations/tui).
## Requirements
* **Node.js 18 or newer**
* A **Rootly account** (the wizard can hand you off to sign up if you don't have one)
* Sign-in via **browser (OAuth)** or a **Rootly API token**
## Quick Start
Run the wizard with `npx` (no install required):
```bash theme={null}
npx @rootly/wizard@latest
```
Sign in, then land on the main menu:
Authorize with your **browser (OAuth)** or paste a **Rootly API token**. Your session is stored securely in your operating system's keychain, so the next run takes you straight to the menu.
Pick **Recommended setup** to configure everything at once and see a live test alert and incident, or **General setup** to jump to any individual task.
The wizard reuses anything that already exists, so it's safe to re-run.
## Signing in
From the sign-in screen you can:
* **Browser sign-in**: authorize in your browser via OAuth.
* **API token**: paste a Rootly API token. Recommended for the full experience (an admin, organization-wide key can complete every step).
* **Create a Rootly account**: opens sign-up in your browser (account creation is web-only), then you return and sign in.
To create an API token:
1. Log in to Rootly.
2. Go to **Organization Settings → API Keys**.
3. Click **Generate New API Key**, name it, and copy the token.
Your token or session is stored in your operating system's keychain. You can also provide a token via the `ROOTLY_TOKEN` environment variable:
```bash theme={null}
ROOTLY_TOKEN=rootly_xxx npx @rootly/wizard@latest
```
On exit, the wizard asks whether to keep the saved sign-in or delete it from your keychain (it keeps it by default).
## Recommended setup (all-in-one)
The fastest path. In one flow it will:
1. Create a team (or reuse one you're already on)
2. Let you pick who joins the team and the on-call rotation
3. Create an on-call schedule
4. Create an escalation policy that pages the on-call schedule
5. Add an alert source
6. Create a public status page (and choose which components appear on it)
7. Fire a **test alert** that **pages the on-call person** (a real call or text)
8. Open a **test incident** (with a link to its Slack channel, if Slack is connected)
Before it runs, you can add and verify a **phone number** and connect **Slack** so the test alert actually reaches you. Anything that already exists is reused, so the flow is safe to re-run.
When the flow finishes, the wizard summarizes what it created, including your test alert and test incident, so you can verify everything in the Rootly web app.
## General setup
Jump to any individual task:
Create teams and add members from your directory.
Create on-call schedules and escalation policies.
Create a public status page and pick which components (services) appear on it.
Connect Slack and alert sources (Datadog, Grafana, Sentry, PagerDuty, Opsgenie).
Send a test alert (pages on-call) or create a test incident.
Review your current teams, schedules, and coverage.
Configure the Rootly MCP server for your editor or AI agent.
Talk to the Rootly team or book a demo.
## MCP / IDE setup
The wizard can write [Rootly MCP server](/integrations/agent-plugins) configuration for your editor or AI agent: preview the config or apply it directly. It points the client at the hosted Rootly MCP server (`https://mcp.rootly.com/mcp`) and reads your token from the `ROOTLY_TOKEN` environment variable rather than embedding it inline.
## Scripting (advanced)
Every setup step is also available non-interactively as a JSON-in / JSON-out action, handy for automation or AI agents. The interactive wizard requires a TTY; scripts and agents should use the `action` subcommand instead.
```bash theme={null}
rootly-wizard action list # list available actions
rootly-wizard action describe # input schema for one action
rootly-wizard action tools # actions as function-calling tool defs
rootly-wizard action '' # run a single action
```
Each action returns exactly one JSON object on stdout:
```json theme={null}
{ "ok": true, "summary": "...", "data": { } }
```
Set `ROOTLY_TOKEN` to an organization admin API key for actions that read or write your workspace. Add `"dryRun": true` to any mutating action to validate and echo the call without executing it:
```bash theme={null}
rootly-wizard action create-team '{"name":"Payments","dryRun":true}'
```
Actions that fire a **test alert** with paging enabled place a real call or text to whoever is on call, and creating a test incident opens a real incident in your workspace. Use a non-production workspace when experimenting.
## Feedback & Support
* **Issues**: [GitHub Issues](https://github.com/rootlyhq/rootly-wizard/issues)
* **Source Code**: [GitHub Repository](https://github.com/rootlyhq/rootly-wizard)
# Rust SDK
Source: https://docs.rootly.com/integrations/rust-sdk
Strongly-typed Rust client for the Rootly API, generated from the OpenAPI spec with full async/await support, builder patterns, and complete API coverage.
The Rootly Rust SDK (`rootly-rs`) is a strongly-typed client for the Rootly API. Types and methods are generated directly from the OpenAPI specification using [Progenitor](https://github.com/oxidecomputer/progenitor), giving you full type safety for every endpoint, parameter, and response.
## Features
* **Full coverage** — every API operation with builder pattern
* **Strongly typed** — every endpoint, parameter, and response is a Rust type
* **Async/await** — powered by [reqwest](https://github.com/seanmonstar/reqwest) and [tokio](https://tokio.rs)
* **JSON:API compliant** — handles `application/vnd.api+json` content negotiation
## Requirements
* Rust 1.85+
* tokio runtime
## Installation
Add to your `Cargo.toml`:
```toml theme={null}
[dependencies]
rootly = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```
## Quick Start
```rust theme={null}
use rootly::RootlyClient;
#[tokio::main]
async fn main() -> Result<(), Box> {
let client = RootlyClient::from_token(std::env::var("ROOTLY_API_TOKEN")?);
let response = client.client().list_incidents().page_size(10).send().await?;
for item in &response.data {
println!("{}: {}", item.id, item.attributes.title);
}
Ok(())
}
```
### Getting an API Key
1. Log in to your Rootly account
2. Navigate to **Settings** > **API Keys**
3. Create a new API key with the permissions you need
## Usage
### List Incidents
```rust theme={null}
let response = client
.client()
.list_incidents()
.filter_status("started".to_string())
.page_number(1)
.page_size(10)
.include("causes,services".to_string())
.send()
.await?;
for item in &response.data {
println!(
"[{}] {} ({})",
item.id,
item.attributes.title,
item.attributes.status.as_deref().unwrap_or("unknown"),
);
}
```
### Get an Incident
```rust theme={null}
let response = client
.client()
.get_incident()
.id("abc123")
.include("sub_statuses,causes,subscribers".to_string())
.send()
.await?;
let incident = &response.data.attributes;
println!("Title: {}", incident.title);
println!("Summary: {}", incident.summary.as_deref().unwrap_or(""));
```
### Create an Incident
```rust theme={null}
use rootly::types::{NewIncident, NewIncidentData, NewIncidentDataAttributes, NewIncidentDataType};
let body = NewIncident::builder()
.data(
NewIncidentData::builder()
.type_(NewIncidentDataType::Incidents)
.attributes(
NewIncidentDataAttributes::builder()
.title("Service degradation".to_string())
.summary("Users experiencing elevated latency".to_string())
.severity_id("sev-1".to_string()),
),
)
.build()
.unwrap();
let response = client.client().create_incident().body(body).send().await?;
```
### Update an Incident
```rust theme={null}
use rootly::types::{UpdateIncident, UpdateIncidentData, UpdateIncidentDataAttributes, UpdateIncidentDataType};
let body = UpdateIncident::builder()
.data(
UpdateIncidentData::builder()
.type_(UpdateIncidentDataType::Incidents)
.attributes(
UpdateIncidentDataAttributes::builder()
.summary("Root cause identified — deploying fix".to_string()),
),
)
.build()
.unwrap();
let response = client
.client()
.update_incident()
.id("abc123")
.body(body)
.send()
.await?;
```
### List Services
```rust theme={null}
let response = client.client().list_services().page_size(50).send().await?;
for svc in &response.data {
println!("{}: {}", svc.id, svc.attributes.name);
}
```
### Create an Alert
```rust theme={null}
use rootly::types::{NewAlert, NewAlertData, NewAlertDataAttributes, NewAlertDataType};
let body = NewAlert::builder()
.data(
NewAlertData::builder()
.type_(NewAlertDataType::Alerts)
.attributes(
NewAlertDataAttributes::builder()
.summary("High error rate on payments service".to_string())
.source("datadog".to_string()),
),
)
.build()
.unwrap();
let response = client
.client()
.create_alert()
.alerts_source_id("src-123")
.body(body)
.send()
.await?;
```
### Pagination
```rust theme={null}
let mut page = 1;
loop {
let response = client
.client()
.list_incidents()
.page_number(page)
.page_size(25)
.send()
.await?;
let data = response.into_inner();
if data.data.is_empty() {
break;
}
for item in &data.data {
println!("{}: {}", item.id, item.attributes.title);
}
page += 1;
}
```
### Error Handling
```rust theme={null}
use rootly::ClientError;
match client.client().get_incident().id("nonexistent").send().await {
Ok(response) => println!("Found: {}", response.data.attributes.title),
Err(ClientError::ErrorResponse(resp)) => {
eprintln!("API error {}: {}", resp.status(), resp.status());
}
Err(e) => eprintln!("Request failed: {e}"),
}
```
### Retry with Backoff
For handling rate limits (HTTP 429):
```rust theme={null}
use rootly::retry::{with_backoff, RateLimitConfig};
let config = RateLimitConfig {
max_retries: 5,
initial_backoff_ms: 500,
};
let response = with_backoff(config, || {
client.client().list_incidents().page_size(100).send()
}).await?;
```
## Using Types
All generated types are available under `rootly::types`:
```rust theme={null}
use rootly::types::{
Incident,
IncidentList,
NewIncident,
Service,
Alert,
Severity,
Team,
// ... and many more
};
```
## Configuration
### Custom Base URL
```rust theme={null}
use rootly::{RootlyClient, RootlyClientConfig};
let client = RootlyClient::new(RootlyClientConfig {
token: "your-token".into(),
base_url: "https://custom.rootly.com".into(),
});
```
### Quick Setup with Defaults
```rust theme={null}
let client = RootlyClient::from_token("your-token");
```
## API Coverage
Full coverage of the Rootly API v1:
| Resource | Operations |
| ------------------- | ---------------------------------------------------- |
| Incidents | list, get, create, update, delete |
| Services | list, get, create, update, delete |
| Alerts | list, get, create, update, resolve, snooze, escalate |
| Teams | list, get, create, update, delete |
| Severities | list, get, create, update, delete |
| Environments | list, get, create, update, delete |
| Workflows | list, get, create, update, delete |
| Playbooks | list, get, create, update, delete |
| Schedules | list, get, create, update, delete |
| Escalation Policies | list, get, create, update, delete |
| Dashboards | list, get, create, update, delete |
| Status Pages | list, get, create, update, delete |
| Custom Fields | list, get, create, update, delete |
| Catalogs | list, get, create, update, delete |
## Feedback & Support
* **Crate**: [rootly on crates.io](https://crates.io/crates/rootly)
* **Source Code**: [GitHub Repository](https://github.com/rootlyhq/rootly-rs)
* **Issues**: [GitHub Issues](https://github.com/rootlyhq/rootly-rs/issues)
## Related resources
* [TypeScript SDK](/integrations/typescript-sdk)
* [Python SDK](/integrations/python-sdk)
* [Swift SDK](/integrations/swift-sdk)
# SCIM user provisioning and deprovisioning for Rootly
Source: https://docs.rootly.com/integrations/scim
Automate Rootly user provisioning and deprovisioning with SCIM 2.0 from Okta, Microsoft Entra, Google Workspace, Keycloak, and other identity providers.
## Introduction
SCIM (System for Cross-domain Identity Management) lets your identity provider automatically manage Rootly users and groups. When users are assigned or unassigned in your IdP, they are provisioned or deprovisioned in Rootly without any manual steps.
SCIM requires [SSO](/integrations/sso) to be configured first — the SCIM endpoint will not resolve until SSO setup is complete. SCIM and [Google Directory Sync](/integrations/google-directory-sync) are also mutually exclusive and cannot both be active at the same time.
## Before You Begin
Before connecting your IdP:
1. Complete [SSO setup](/integrations/sso) for your organization
2. Navigate to **Integrations > SSO** in Rootly and copy your **SCIM Token** — this is the Bearer token your IdP uses to authenticate SCIM requests
3. Note your **SCIM tenant URL**: `https://rootly.com/scim`
Rootly supports the following SCIM 2.0 operations:
| Resource | Supported Operations |
| -------- | ----------------------------------------------------- |
| Users | Create, read, update (PUT/PATCH), deactivate, delete |
| Groups | Create, read, update (PUT/PATCH), delete, member sync |
## Identity Provider Setup
Expand the section for your identity provider:
In Okta, navigate to **Applications > Rootly > Provisioning tab**. Under **Settings > Integrations**, click **Configure API Integration**, enter your SCIM Token, and save.
Go to **Provisioning > To App**, click **Edit**, and enable:
* **Create Users** — provisions users when assigned to the Rootly app
* **Deactivate Users** — removes users from Rootly when unassigned
Ensure the **Default username** is set to **email**. If not, go to the **Sign on** tab, click **Edit**, and set **Application username** format to **email** under Credentials settings.
To sync Okta Groups to Rootly:
1. In Okta, navigate to **Directory > Groups** and create or select a group
2. Go to **Applications > Rootly > Push Groups** tab
3. Click **+Push Groups**, select the group, switch from **Create Group** to **Link Group**, and click **Save**
4. In Rootly, go to **Integrations > SSO > Role Assignment** and map the Okta Group to a Rootly Role
Every user added to that Okta Group will be provisioned in Rootly with the associated role.
Follow the official Microsoft tutorial for configuring SCIM provisioning with Rootly:
[Microsoft Entra SCIM provisioning tutorial →](https://learn.microsoft.com/en-us/entra/identity/saas-apps/rootly-provisioning-tutorial)
Google Workspace has limited native SCIM support. The following workaround uses Google's Adobe app as a proxy for SCIM provisioning.
In Google Admin Console, navigate to **Apps > Web and mobile apps** and click **Add app**.
Search for and select the **Adobe** app from the catalog.
When prompted for SAML fields, enter `https://dummy.com/saml` for all values. When you reach the auto-provisioning step:
* **SCIM Token**: your token from **Rootly > Integrations > SSO**
* **Endpoint URL**: `https://rootly.com/scim`
* Select a group of users to import, or leave empty to import all
Enable the application — sync will begin shortly.
Download the `keycloak-scim` JAR from the [releases page](https://github.com/mitodl/keycloak-scim/releases), place it in `/opt/keycloak/providers/`, and restart Keycloak.
Go to **Realm Settings > Events > Event Listeners** and add `scim` to the list. Save.
Navigate to **User Federation > Add provider > SCIM** and configure:
| Field | Value |
| --------------------- | --------------------------- |
| UI display name | `Rootly` |
| SCIM 2.0 endpoint | `https://rootly.com/scim` |
| Endpoint content type | `application/scim+json` |
| Auth mode | `BEARER` |
| Auth password/token | Your SCIM Token from Rootly |
Set the environment variable `SCIM_EMAIL_AS_USERNAME=true` — this ensures usernames are sent in email format, required for user matching in Rootly.
In the federation provider settings, enable:
* **Enable user propagation**: On
* **Enable group propagation**: On (optional)
* **Log SCIM requests and responses**: On (recommended for debugging)
* **Import action**: `CREATE_LOCAL`
Optionally enable **Periodic full sync** or **Periodic changed users sync** for regular synchronization.
Rippling supports SSO and SCIM provisioning for Rootly in a single step. Connect from the [Rippling app store](https://www.rippling.com/app-shop/app/rootly).
## Supported Attributes
### Users
| SCIM Attribute | Rootly Field | Notes |
| ----------------- | ----------------- | ------------------------------------------------------------------- |
| `userName` | Email | Required. Must be a valid email address. |
| `name.givenName` | First name | |
| `name.familyName` | Last name | |
| `displayName` | Preferred name | |
| `externalId` | External ID | Stored per SSO account, not globally |
| `active` | Membership status | `false` removes the user's team membership |
| `emails` | Email | Primary work email |
| `phoneNumbers` | Phone numbers | Auto-verified on import; normalized with US as default country code |
### Groups
| SCIM Attribute | Rootly Field | Notes |
| -------------- | ------------------- | ----------------------------------------- |
| `displayName` | Group name | |
| `externalId` | External identifier | |
| `members` | Group members | User and nested group types both accepted |
## Role Assignment via Groups
When **Assign roles to SCIM groups** is enabled, Rootly automatically assigns roles based on group membership. If a user belongs to multiple SCIM groups with different role configurations, the highest-weighted role is applied.
## Troubleshooting
The SCIM endpoint only becomes active after SSO is fully configured. Complete SSO setup in **Integrations > SSO** and save before connecting your IdP's SCIM provisioning. Confirm you are using `https://rootly.com/scim` with no trailing slash.
The IdP authenticates with your SCIM Token as a Bearer token. Retrieve the current token from **Integrations > SSO** in Rootly and confirm it matches what your IdP has configured. Also confirm that SCIM is enabled in your SSO settings.
Confirm that the user is assigned to the Rootly application in your IdP, the `userName` attribute is a valid email address, **Create Users** is enabled in your IdP's provisioning settings, and the default username format is set to **email**. Most IdPs record outbound SCIM requests with the full request body and Rootly's response — Okta's **System Log**, Microsoft Entra's **Provisioning logs**, and Google Workspace's **Admin reports** are the canonical first place to check. If the IdP shows successful sends but the user still isn't appearing in Rootly, contact [support@rootly.com](mailto:support@rootly.com).
When a user is deactivated (`active: false`), Rootly removes their team membership but preserves the user record. If the user still appears active in Rootly, check your IdP's outbound SCIM provisioning logs for the deactivation request — confirm it was sent with `active: false` and that Rootly returned a `2xx` response. If the IdP shows a successful send but the user is still active in Rootly, contact [support@rootly.com](mailto:support@rootly.com).
Confirm the source value in your IdP includes a country code prefix for non-US numbers. Rootly normalizes phone numbers using US as the default country code, so unprefixed international numbers fail to normalize and are not persisted.
## Related Pages
Configure SAML 2.0 single sign-on — required before enabling SCIM.
Poll-based alternative to SCIM for Google Workspace organizations.
Manage on-call schedules once users are provisioned via SCIM.
# SendGrid
Source: https://docs.rootly.com/integrations/sendgrid
Route Rootly workflow emails through your own SendGrid account to send from your company domain with full delivery visibility, tracking, and authentication.
## Overview
By default, Rootly sends workflow emails from `workflows@rootly.com`. Connecting SendGrid lets you route those emails through your own SendGrid account instead — so emails arrive from your company domain and you retain full delivery analytics in SendGrid.
Send workflow emails from your own domain instead of Rootly's default address.
Track opens, clicks, bounces, and delivery status directly in your SendGrid dashboard.
All **Send an Email** workflow actions automatically route through SendGrid once connected — no changes needed to existing workflows.
Rootly validates your API key against the SendGrid API on connect, so misconfigurations are caught immediately.
## Before You Begin
* You must be a Rootly admin to set up the integration
* You need a SendGrid account with permission to create API keys
## Installation
In SendGrid, go to **Settings → API Keys** and create a new key. Select **Restricted Access** and enable **Full Access** for **Mail Send** only — no other scopes are needed.
Copy the API key — you won't be able to view it again after leaving the page.
In Rootly, go to **Configuration → Integrations**, find **SendGrid**, and click **Setup**. Enter your API key and optionally set a **Default From** address.
Rootly validates the key against the SendGrid API before saving. If the `mail.send` scope is missing, the connection will be rejected.
## Configuration
Your SendGrid API key. Must have the `mail.send` scope. Stored encrypted at rest.
The sender email address used when no `From` is specified in a workflow action — for example, `incidents@yourcompany.com`. If left blank, the `From` field in each workflow action determines the sender.
Once SendGrid is connected, all **Send an Email** workflow actions are automatically routed through it. The **From** field in the workflow action still controls the sender address per-email — the **Default From** here serves as a fallback.
## Uninstall
To remove the SendGrid integration:
1. Go to **Configuration → Integrations** and find **SendGrid**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
After disconnecting, workflow emails will revert to Rootly's default delivery.
## Frequently Asked Questions
No. All **Send an Email** workflow actions automatically route through SendGrid once the integration is connected. No changes to existing workflows are required.
Only `mail.send` (Full Access) is required. Rootly validates this on connect — if the scope is missing, the key will be rejected.
No. If both a SendGrid and an SMTP integration are connected, Rootly prefers SMTP. To use SendGrid, disconnect the SMTP integration first.
No. Emails already delivered are unaffected. After disconnecting, new workflow emails will revert to Rootly's default delivery method.
## Related resources
* [Email](/integrations/email)
* [SMTP](/integrations/smtp)
* [Twitter / X](/integrations/twitter)
# Sentry
Source: https://docs.rootly.com/integrations/sentry/sentry
Connect Sentry to Rootly to ingest issue and metric alerts, and turn them into incidents or on-call pages with alert workflows.
This integration enables you to ingest alerts from Sentry and automatically trigger incident response workflows in Rootly.
When something breaks, Sentry sends the alert to Rootly, and Rootly starts your alert workflow: an incident is declared, context flows in, responders are notified, and you're ready to act.
***
## Why use this integration?
Pull Sentry issues directly into Rootly with zero manual steps.
Tailor Rootly workflows to fit your team's incident response processes.
Trigger incidents in Rootly automatically when your Sentry rules fire.
***
## At-a-Glance Workflow
```mermaid theme={null}
flowchart LR
A[Sentry Issue / Alert] --> B[Rootly Alert Source]
B --> C{Does threshold match?}
C -- Yes --> D[Create Incident in Rootly]
C -- No --> E[Attach to Existing Incident / Log as Alert]
```
***
## Before You Begin
This setup involves two systems — Sentry and Rootly — so make sure you have the right access in both before starting. The installation takes about 5 minutes and only needs to be done once per Sentry organization.
Before you start, make sure you have the following:
* **Sentry:** Admin or Owner role in your Sentry organization — required to install third-party integrations
* **Rootly:** Admin role — required to create and configure alert sources
* An existing Sentry organization with at least one project set up
## Installation
To start receiving Sentry alerts in Rootly, you install the Rootly app inside your Sentry organization. Once installed, Sentry can forward enriched alert payloads into Rootly, giving your workflows the real-time context they need to act.
Install the **Rootly integration** inside your Sentry organization. This allows Sentry to forward enriched alert payloads into Rootly, giving your Rootly workflows the real-time context they need.
Inside your Sentry organization, navigate to **Settings → Integrations** and search for **Rootly**.
Click **Accept & Install**. You'll be redirected to Rootly to complete the alert source setup.
Make sure you're logged into Rootly as an **Admin** before proceeding — the redirect will fail otherwise.
On the Sentry alert source page, enter a descriptive **Source Name** (for example, "Sentry Alerts") and click **Save**. You can leave optional settings like Owning Team at their defaults and adjust them later.
Switch back to Sentry and go to **Settings → Integrations**. Rootly should appear in your installed integrations list.
Rootly is now connected. Next, configure Sentry alert rules to forward alerts to Rootly and set up your incident response workflows.
## Alert Types
Rootly supports three Sentry alert types, each with different behavior.
### Issue Alerts
Issue alerts are tied to specific Sentry issues and support automatic resolution. When Sentry sends a resolved event, Rootly resolves the corresponding alert automatically.
You can configure the following directly in the Sentry alert rule action settings:
Routes the alert to a specific Rootly resource for on-call paging. Format: `type:id` — for example, `EscalationPolicy:abc-123`.
Supported types: `User`, `Group`, `EscalationPolicy`, `Service`. Set to `none` to disable paging entirely.
Sets the alert urgency in Rootly using the ID of a Rootly alert urgency. If not set or the ID is invalid, no urgency is assigned to the alert.
### Metric Alerts
Metric alerts are threshold-based and do not support automatic resolution. When a metric alert fires, Rootly creates an alert in the open state. You must resolve it manually or through a workflow.
Metric alerts do not auto-resolve. Rootly will not resolve a metric alert when the threshold returns to normal — you must resolve it manually or via a workflow action.
Metric alerts also support `rootly_notification_target` and `rootly_urgency` in the Sentry alert rule action settings.
### Issue (Legacy)
The `issue` resource type is a legacy format that's still supported but not recommended for new rules. New rules should use `event_alert` instead. Existing rules using the legacy type will continue to work without migration.
***
## Alert Workflows
Once Sentry is connected, you define alert rules in Sentry that determine when to forward alerts to Rootly, then build workflows in Rootly that react to those alerts — declaring incidents, paging responders, and kicking off your response process automatically.
### Step 1: Create Alert Rules in Sentry
You'll start in Sentry by defining the alert rules that determine when an event should be forwarded to Rootly. These rules let you specify conditions based on error frequency, type, tags, severity, or any combination — so only the alerts that matter reach Rootly. Every alert that passes these conditions will land in Rootly's alert feed with the full Sentry payload attached.
In Sentry, go to **Issues → Alerts**, then click **Create Alert**.
Select the type of alert you want to create — for example, an **Error Alert** — then click **Set Conditions**.
Set your conditions under the **When** and **If** fields. For example: trigger when an issue is seen more than 10 times in 1 hour, or when a specific tag like `environment:production` is present. The more precisely you scope these, the less noise your Rootly workflows will see.
Under the **Then** section, select **Rootly** as the action. This tells Sentry to forward the alert payload to Rootly whenever your conditions are met.
Use Sentry's **Send Test Notification** to fire a real test alert to Rootly. This sends a live payload so you can inspect exactly what fields are available before writing your workflow conditions.
The test alert will appear in **Rootly → Alerts**. Click on it to view the full payload — you'll use these fields when writing workflow conditions in the next step.
### Step 2: Build the Workflow in Rootly
With alerts now flowing into Rootly, you create a workflow that reacts to them. Rootly workflows let you inspect the incoming alert payload, apply conditions to filter which alerts should trigger a response, and chain together actions like creating an incident, paging on-call, or sending notifications. You only need one workflow per alert pattern — conditions handle the filtering.
In Rootly, go to **Workflows** and click **Create Workflow**.
Select the **Alert** workflow type. This workflow will trigger whenever Rootly receives an **alert** from any source — including Sentry. Conditions in a later step will narrow it down to Sentry alerts specifically.
Give your workflow a clear name like "Create Incident for Sentry Errors".
There are additional optional settings you can configure here, such as:
* **Workflow description** — helps your team understand what this workflow does
* **Repeat configuration** — controls whether the workflow can fire multiple times for the same alert
The trigger defines which alert event activates this workflow.
For **Alert** type workflows, two triggers are available:
1. **Alert Created** — fires when a new alert is received from Sentry
2. **Alert Status Updated** — fires when an existing alert changes state (for example, resolved or acknowledged)
Select **Alert Created** to run the workflow whenever a new Sentry alert arrives. Use **Alert Status Updated** if you want to automatically close an incident when Sentry marks the issue resolved.
Conditions filter which alerts trigger the workflow. Use one of the following to match alerts from Sentry:
Run this workflow if `any of` the following conditions are true:
* **Source** is `Sentry`
Run this workflow if `any of` the following conditions are true:
* **Payload**: `actor.name` is `Sentry`
The Sentry alert payload contains many fields you can use for more advanced conditions — environment, project, level, tags, and more. Open the test alert you sent earlier to browse all available fields.
Add one or more actions that should occur when the workflow is triggered. Common actions include:
* **Create Incident** — declares an incident with context pulled directly from the alert payload
* **Page Rootly On-Call** — immediately pages the on-call responder for the affected service
* **Send SMS or Email** — notifies stakeholders outside of Slack
You can chain multiple actions depending on your response process — for example: create the incident, then page on-call, then post a message to a Slack channel.
Click **Create Workflow**. The workflow is now active and will fire automatically on the next matching Sentry alert.
### Step 3: Verify
Return to Sentry and trigger the alert rule again — or send another test notification. Confirm that the workflow activates inside Rootly and that the expected incident or action is created. You can monitor workflow execution in **Rootly → Workflows → Activity**.
## How Alert Fields Are Mapped
Rootly extracts the following fields from each Sentry alert type and makes them available as conditions and variables inside your workflows:
Issue title, issue ID, issue URL, error type, level, and project name. Supports automatic resolution — when Sentry sends a resolved event, Rootly resolves the corresponding alert.
Alert title, alert ID, and web URL. Does not support automatic resolution — must be resolved manually or via a workflow action.
`level`, `type`, `project`, and `status` are extracted as labels on every alert where available. Use these as workflow conditions to filter by severity, environment, or state.
## Troubleshooting
Confirm the Rootly app is installed in your Sentry organization and that the alert rule has Rootly set as an action. Verify the rule conditions are being met by triggering a test event.
This is expected — metric alerts don't support automatic resolution. Resolve them manually or configure a workflow action to resolve them based on a follow-up Sentry event.
Check that the value follows `type:id` format exactly (for example, `EscalationPolicy:abc-123`) and that the resource exists in Rootly. Setting the value to `none` disables paging. An invalid or missing resource is silently ignored.
Confirm the value is a valid Rootly alert urgency ID belonging to your team. Invalid urgency IDs are silently ignored and no urgency will be assigned to the alert.
## Uninstall
To remove the Sentry integration from Rootly, go to **Configuration → Integrations**, find **Sentry**, click **Connected**, and select **Disconnect**.
Disconnecting from Rootly does not remove the Rootly app from Sentry. To fully revoke access, also go to **Sentry → Settings → Integrations** and uninstall the Rootly app there.
***
## Related Resources
* [Alert workflows](/workflows/alert-workflows)
* [Alert routing](/alerts/alert-routing)
* [Integrations overview](/integrations/overview)
# ServiceNow
Source: https://docs.rootly.com/integrations/service-now
Connect ServiceNow to Rootly for bidirectional incident sync — create and update ServiceNow incidents from workflows, and receive ServiceNow events as alerts.
The ServiceNow integration connects Rootly with your ServiceNow instance bidirectionally. Rootly can create and update ServiceNow incidents through workflow actions, and ServiceNow can send incident events to Rootly as alerts using Business Rules.
With the ServiceNow integration, you can:
* Automatically create ServiceNow incidents from Rootly incidents
* Update ServiceNow incident priority, state, and custom fields as incidents evolve
* Receive ServiceNow incident events as Rootly alerts to trigger on-call paging
* Sync ServiceNow CMDB business applications to Rootly services
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A ServiceNow instance with admin access
* Permission to create OAuth Application Registry entries in ServiceNow
Rootly recommends installing with a dedicated ServiceNow service account so the integration does not break if an individual user leaves your organization.
## Installation
Log into Rootly as an Admin and navigate to **Configurations > Integrations > ServiceNow**. Click **Setup**.
Log into your ServiceNow instance as an Admin and navigate to **System OAuth > Application Registry**.
Click **New**, then select **Create an OAuth API endpoint for external clients**.
Fill in the following fields and click **Submit**:
| ServiceNow Field | Value |
| ---------------- | ---------------------------------------------- |
| `Name` | `Rootly` |
| `Redirect URL` | `https://rootly.com/auth/service_now/callback` |
Open the application you just created in ServiceNow and copy the **Client ID** and **Client Secret**.
When copying the **Client Secret**, you may need to unmask it by clicking the lock icon. Masked values sometimes do not copy correctly in ServiceNow.
Paste the Client ID, Client Secret, and your ServiceNow instance URL into the Rootly setup modal and click **Connect**.
You will be redirected to ServiceNow to authorize the connection. Click **Allow**.
After authorization, the **Create a ServiceNow Incident** and **Update a ServiceNow Incident** workflow actions are available in your Genius workflows.
## Ingest ServiceNow Events
To receive ServiceNow incident events as Rootly alerts, configure a Business Rule in ServiceNow to send events to Rootly's webhook endpoint.
In Rootly, open the ServiceNow integration settings. Copy the **Webhook URL** and **Secret** values shown on the integration page.
In ServiceNow, navigate to **System Definition > Business Rules**.
There are multiple Business Rules pages in ServiceNow. Make sure you select the one under **System Definition**.
Click **New** and fill in:
| Field | Value |
| ---------- | ---------------------------------------------------- |
| `Name` | Any descriptive name (for example, `Send to Rootly`) |
| `Table` | `Incident [incident]` |
| `Advanced` | Check this |
| `When` | `After` |
| `Insert` | Check to receive events when incidents are created |
| `Update` | Check to receive events when incidents are updated |
| `Delete` | Check to receive events when incidents are deleted |
Navigate to the **Advanced** tab and replace the script with the following:
```js theme={null}
(function executeRule(current, previous /*null when async*/ ) {
try {
var r = new sn_ws.RESTMessageV2();
r.setEndpoint("");
r.setHttpMethod("post");
r.setRequestHeader("secret", "");
var usr = new GlideRecord('sys_user');
usr.get('sys_id', current.getValue("caller_id"));
var reported_by_email = usr.getValue('email');
var number = current.getValue("number");
var opened_at = current.getValue("opened_at");
var impact = current.getValue("impact");
var urgency = current.getValue("urgency");
var short_description = current.getValue("short_description");
var description = current.getValue("description");
var category = current.getValue("category");
var priority = current.getValue("priority");
var sys_id = current.getValue("sys_id");
var subcategory = current.getValue("subcategory");
var state = current.getValue("state");
var obj = {
"number": number,
"reported_by_email": reported_by_email,
"opened_at": opened_at,
"impact": impact,
"urgency": urgency,
"short_description": short_description,
"description": description,
"category": category,
"priority": priority,
"sys_id": sys_id,
"subcategory": subcategory,
"state": state
};
var body = JSON.stringify(obj);
r.setRequestBody(body);
var response = r.execute();
var httpStatus = response.getStatusCode();
} catch (ex) {
var message = ex.message;
gs.error("Error message: " + message);
}
gs.info("Webhook target HTTP status response: " + httpStatus);
})(current, previous);
```
Replace `` and `` with the values from the Rootly ServiceNow integration page.
Click **Submit**.
### How Alerts Are Mapped
Each ServiceNow event received creates a Rootly alert with the following fields:
| Rootly Alert Field | ServiceNow Source |
| ------------------ | ------------------------------------------------------ |
| Summary | `short_description`, then `description`, then `number` |
| External ID | `sys_id` |
| External URL | `url` (if provided in payload) |
Alert labels:
| Label | ServiceNow Field |
| ------------- | ---------------- |
| `id` | `sys_id` |
| `number` | `number` |
| `impact` | `impact` |
| `urgency` | `urgency` |
| `category` | `category` |
| `subcategory` | `subcategory` |
| `state` | `state` |
### Using ServiceNow as an Alert Source
If your org uses Rootly On-Call, ServiceNow alerts can be used to page on-call users. Once the Business Rule is configured, alerts from ServiceNow will appear in your Rootly alert feed and can trigger on-call notifications through alert workflows.
## Workflow Actions
The ServiceNow integration provides workflow actions for creating and updating ServiceNow incidents from Rootly. If you are unfamiliar with how Genius workflows work, visit the [Workflows](/workflows/workflows) documentation first.
### Create a ServiceNow Incident
This action creates a new record in the ServiceNow `Incident` table (for example, `INC0010001`) and links it to the Rootly incident.
| Field | Description | Required |
| ------------------------- | ------------------------------------------------------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Title** | Maps to `short_description` in ServiceNow. Supports Liquid | Yes |
| **Description** | Maps to `description` in ServiceNow. Supports Liquid | |
| **Priority** | Maps to `urgency`. **Auto** mirrors the incident severity | |
| **Status** | Maps to `state`. **Auto** mirrors the incident status | |
| **Acts As User** | Name or email of the ServiceNow user to set as caller when resolving. Only active when status is Resolved (6) | |
| **Custom Fields Mapping** | JSON of additional ServiceNow fields. Merged directly into the incident payload. Supports Liquid | |
**Priority mapping (Auto)**
| Rootly Severity | ServiceNow Urgency |
| --------------- | ------------------ |
| Critical | High (1) |
| High | High (1) |
| Medium | Medium (2) |
| Low | Low (3) |
**Status mapping (Auto)**
| Rootly Status | ServiceNow State |
| ------------- | ---------------- |
| Started | New (1) |
| Mitigated | In Progress (2) |
| Resolved | Resolved (6) |
Available states: New (1), In Progress (2), On Hold (3), Resolved (6), Closed (7), Canceled (8).
**Acts As User** triggers a ServiceNow user lookup by first name, last name, or email. When matched, Rootly sets `caller_id`, `close_code`, and `close_notes` automatically. It only applies when the state is set to Resolved (6).
### Update a ServiceNow Incident
This action updates an existing record in the ServiceNow `Incident` table.
When a **Create a ServiceNow Incident** action runs, Rootly stores the resulting `sys_id` and incident number on the incident record. Reference them in subsequent update actions using Liquid variables.
| Field | Description | Required |
| ------------------------- | -------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Incident ID** | ServiceNow `sys_id` of the incident to update. Supports Liquid | Yes |
| **Title** | Updated `short_description`. Supports Liquid | |
| **Description** | Updated `description`. Supports Liquid | |
| **Priority** | Updated urgency level | |
| **Status** | Updated incident state | |
| **Acts As User** | Name or email of the caller to set when resolving | |
| **Custom Fields Mapping** | Updated custom field values as JSON. Supports Liquid | |
### Common Custom Field Examples
**Work notes (internal)** — visible only to ServiceNow agents, not customers.
```json theme={null}
{
"work_notes": "{{ incident.events[0].event_raw }}"
}
```
**Comments (customer-visible)**
```json theme={null}
{
"comments": "{{ incident.events[0].event_raw }}"
}
```
**Major incident**
```json theme={null}
{
"assignment_group": "3De45d9ebc3b333200fe02c9bb34efc434",
"major_incident_state": "proposed"
}
```
Major incident state changes may require specific ACL permissions in ServiceNow. See the [ServiceNow community](https://community.servicenow.com/community?id=community_question\&sys_id=fae73aeb1b7370900b8a9979b04bcb1a) for details.
### Add Configuration Items (CIs) to an Incident
Adding configuration items to a ServiceNow incident requires multiple API calls (one per CI). Use Rootly's **HTTP Client** workflow action with the ServiceNow Batch API to consolidate them into a single request.
**Endpoint**
```http theme={null}
POST https://.com/api/now/v1/batch
```
**Headers**
```json theme={null}
{
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Basic {{ secrets.service_now_key_encoded }}"
}
```
Store your Base64-encoded `username:password` as a [Rootly Secret](https://rootly.com/account/secrets) to keep credentials out of plain-text workflow configurations.
**Body**
Each individual Table API call must have its `body` Base64-encoded. The following Liquid template dynamically generates one batch entry per service associated with the incident:
```json theme={null}
{
"batch_request_id": "1",
"rest_requests": [
{% for service in genius_workflow_run.newly_added_services %}
{% assign task_value = incident.service_now_incident_id %}
{% assign ci_item_value = service | get: 'service_now_ci_sys_id' %}
{% assign body_string = '{ "task": "' | append: task_value | append: '", "ci_item": "' | append: ci_item_value | append: '" }' %}
{
"id": "1{{ forloop.index }}",
"headers": [{ "name": "Content-Type", "value": "application/json" }],
"url": "/api/now/table/task_ci",
"method": "POST",
"body": "{{ body_string | base64_encode }}"
}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
}
```
To use this template, each ServiceNow CI's `sys_id` must be linked to the equivalent Rootly service using the `service_now_ci_sys_id` field.
**Succeed On Status** — set to `200`. The ServiceNow Batch API returns `200` (not `201`) on success.
## Uninstall
To remove the ServiceNow integration, navigate to **Configuration > Integrations > ServiceNow > Delete**.
## Related Resources
* [Workflows](/workflows/workflows)
* [Alert workflows](/workflows/alert-workflows)
* [Integrations overview](/integrations/overview)
# SharePoint
Source: https://docs.rootly.com/integrations/sharepoint
Connect Microsoft SharePoint to Rootly to automatically create and update Word documents in SharePoint sites during incidents for retrospectives and reports.
## Introduction
The SharePoint integration connects Rootly with your Microsoft SharePoint environment so teams can automatically create and update Word documents in SharePoint sites through Genius workflows. Documents are created as `.docx` files in the SharePoint site and drive of your choice.
With the SharePoint integration, you can:
* Automatically create Word documents in SharePoint from incident workflows
* Populate documents using Rootly retrospective templates or custom Liquid content
* Update existing SharePoint documents as an incident progresses
* Navigate your SharePoint hierarchy — Sites, Drives, and Folders — to place documents precisely where you need them
* Attach created documents directly to the incident record
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A Microsoft 365 account with access to SharePoint
* Permission to authorize applications in your Microsoft tenant
Rootly recommends installing with a dedicated service account so the integration does not break if an individual user leaves your organization.
## Installation
Navigate to the integrations page in Rootly and select **SharePoint**.
You will be redirected to Microsoft to sign in and grant Rootly the permissions required to access your SharePoint environment.
Rootly requests the following Microsoft Graph permissions:
| Permission | Purpose |
| --------------------- | --------------------------------------------------------- |
| `offline_access` | Maintain access without requiring re-authentication |
| `User.Read` | Read your profile and basic organizational information |
| `Sites.Read.All` | Read documents and list items across all site collections |
| `Files.ReadWrite.All` | Read, create, update, and delete files you have access to |
Rootly uses `Files.ReadWrite.All` to create and update incident documents. `Sites.Read.All` is used to discover available sites and drives when configuring workflow actions.
Once authorized, the installation is complete.
After authorization, the **Create a SharePoint Page** and **Update a SharePoint Page** workflow actions are available in your Genius workflows.
## Workflow Actions
### Create a SharePoint Document
This action creates a new Word document (`.docx`) in a specified SharePoint location.
**Name**
The display name for this workflow action. Rename it to describe what the action does.
**Site**
The SharePoint site where the document will be created. Rootly discovers available sites from your Microsoft tenant.
**Drive**
The document library (drive) within the selected site. Each SharePoint site can have multiple drives.
SharePoint organizes content as **Sites > Drives > Folders**. Select the Site first, then the Drive, and optionally a Folder within that Drive.
**Parent Folder**
The folder within the selected Drive where the document will be created. Leave blank to place the document in the root of the Drive.
**Title**
The title and filename of the Word document. Defaults to `{{ incident.title }}`. Supports Liquid syntax.
Use the [Incident Variable Explorer](https://rootly.com/account/help/liquid-explorer) to preview what Liquid variables return for your incidents.
**Retrospective Template**
Select a predefined Rootly retrospective template to populate the document body. Templates are managed on the [Retrospective Templates page](https://rootly.com/account/retrospective-steps?tab=documents).
If a Retrospective Template is selected, it overrides any content defined in the Custom Content field.
**Custom Content**
Define the document body manually using HTML content. Supports Liquid syntax. Used when no Retrospective Template is selected.
**Mark Post Mortem as Published**
When enabled, marks the retrospective status as `published` after the document is created. Use this when follow-up notification workflows trigger on published retrospectives.
### Update a SharePoint Document
This action updates an existing SharePoint Word document with new content.
**File ID**
The SharePoint item ID of the document to update. Supports Liquid syntax.
When a **Create a SharePoint Page** action runs, Rootly stores the resulting document ID and URL on the incident record. Reference the file ID in subsequent update actions using Liquid variables.
**Title**
The updated title for the document. Supports Liquid syntax. Leave blank to keep the existing title.
**Content**
Additional HTML content to append to the document. Supports Liquid syntax.
**Retrospective Template**
Re-render the document body using a Rootly retrospective template.
## Troubleshooting
Confirm the integration was authorized with an account that has access to the SharePoint sites you want to use. If your tenant has many sites, try searching by name in the site selector. Re-authenticating the integration may also refresh the available site list.
Verify that the authorized Microsoft account has write access to the target SharePoint drive and folder. The `Files.ReadWrite.All` permission grants access to files the authorizing user can access — it does not bypass SharePoint site permissions.
Check the workflow run log in Rootly for any errors returned from the SharePoint API. Confirm the selected Site, Drive, and Folder exist and are accessible to the authorized account.
## Uninstall
To remove the SharePoint integration, open the integrations panel in Rootly and select **Configure > Delete**.
# Shortcut
Source: https://docs.rootly.com/integrations/shortcut
Connect Rootly with Shortcut to automatically create and update stories and tasks from incidents, keeping engineering work and incident follow-up in sync.
## Introduction
The Shortcut integration connects Rootly with your Shortcut workspace so teams can automatically create and update stories through Genius workflows. Stories can be assigned to projects, epics, groups, owners, and workflow states — all driven by incident data.
With the Shortcut integration, you can:
* Automatically create Shortcut stories when incidents are declared or reach a certain state
* Create tasks within a Shortcut story to track action items
* Update story title, description, archivation status, and owner as incidents evolve
* Assign stories to epics, groups, and workflow states
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A Shortcut account with access to the workspace you want to use
* A Shortcut API token
To generate a Shortcut API token, go to your Shortcut profile settings at **Settings > API Tokens > Generate Token**.
Rootly recommends installing with a dedicated Shortcut service account so the integration does not break if an individual user leaves your organization.
## Installation
Navigate to the integrations page in Rootly and select **Shortcut**.
Paste your Shortcut API token into the **API Key** field and select **Connect**.
Rootly validates the token against the Shortcut API. Once connected, the installation is complete.
After installation, the **Create a Shortcut Story**, **Create a Shortcut Task**, **Update a Shortcut Story**, and **Update a Shortcut Task** workflow actions are available in your Genius workflows.
## Workflow Actions
### Create a Shortcut Story
This action creates a new story in Shortcut.
| Field | Description | Required |
| -------------------------- | --------------------------------------------------------------------------------- | ------------------- |
| **Name** | Display name for this workflow action | |
| **Workflow State** | The workflow state to place the story in (for example, Unstarted, In Progress) | Yes (if no Project) |
| **Project** *(deprecated)* | Shortcut project to associate with. Prefer Workflow State for new configurations | |
| **Group** | Shortcut team (group) to associate the story with | |
| **Epic** | Shortcut epic to associate the story with | |
| **Kind** | Story type: `bug`, `chore`, or `feature` | Yes |
| **Title** | Story title. Defaults to `{{ incident.title }}`. Supports Liquid | Yes |
| **Description** | Story description. Supports Liquid | |
| **Assigned Owner** | Shortcut member to assign as the story owner | |
| **Due Date** | Story due date. Supports Liquid | |
| **Archivation** | Whether to archive the story. **Auto** mirrors the incident or action item status | Yes |
***
### Create a Shortcut Task
This action creates a task within an existing Shortcut story.
When a **Create a Shortcut Story** action runs, Rootly stores the resulting story ID on the incident record. Reference it in subsequent task actions using Liquid variables.
| Field | Description | Required |
| ------------------- | --------------------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Parent Story ID** | Shortcut story ID to create the task under. Supports Liquid | Yes |
| **Description** | Task description. Supports Liquid | Yes |
| **Completion** | Task completion status. **Auto** mirrors the incident or action item status | Yes |
| **Assigned To** | Shortcut member to assign the task to | |
***
### Update a Shortcut Story
This action updates an existing Shortcut story.
| Field | Description | Required |
| ------------------ | ------------------------------------------------------------------ | -------- |
| **Name** | Display name for this workflow action | |
| **Story ID** | Shortcut story ID to update. Supports Liquid | Yes |
| **Title** | Updated story title. Supports Liquid. Leave blank to keep existing | |
| **Description** | Updated story description. Supports Liquid | |
| **Epic** | Updated epic association | |
| **Assigned Owner** | Updated story owner | |
| **Due Date** | Updated due date. Supports Liquid | |
| **Archivation** | Updated archivation status | Yes |
***
### Update a Shortcut Task
This action updates an existing task within a Shortcut story.
| Field | Description | Required |
| ------------------- | ------------------------------------------------------ | -------- |
| **Name** | Display name for this workflow action | |
| **Parent Story ID** | Shortcut story ID containing the task. Supports Liquid | Yes |
| **Task ID** | Shortcut task ID to update. Supports Liquid | Yes |
| **Description** | Updated task description. Supports Liquid | |
| **Completion** | Updated completion status | Yes |
| **Assigned To** | Updated assignee | |
***
## Troubleshooting
Confirm the API token is valid and belongs to a user with access to the target workspace. Re-entering the token in the integration settings will revalidate it. Also verify that either a Workflow State or Project is selected in the workflow action — one of these is required.
Shortcut loads available workflow states and projects from your authorized workspace. If your workspace has recently changed, try reconfiguring the workflow action to refresh the available options.
## Uninstall
To remove the Shortcut integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related resources
* [Jira (On-Premise)](/integrations/jira-on-premise)
* [Motion integration for Rootly incidents](/integrations/motion)
* [Zendesk](/integrations/zendesk)
# Slack
Source: https://docs.rootly.com/integrations/slack/slack
Connect Slack to Rootly to declare incidents from chat, run a dedicated incident channel, and drive response with commands and workflows.
Rootly's Slack integration automatically creates and manages incident channels the moment an incident starts. Channels stay in sync with incident details in real time, so teams stay aligned without manual coordination.
## What You Can Do
Auto-create dedicated channels for each incident with consistent naming, topics, and bookmarks. Channels can be public or private based on incident sensitivity.
Channel topics, names, and bookmarks update automatically as incident status, severity, or details change.
Announce new incidents to designated channels, notify user groups for high-severity events, and send reminders for stale incidents or unassigned roles.
Auto-invite on-call responders, service owners, or specific user groups to incident channels based on conditions.
Declare incidents, update status, assign roles, add action items, and trigger workflows directly from Slack with `/rootly` commands.
Send rich, interactive messages with buttons for common actions like updating summary, assigning roles, or escalating to PagerDuty.
***
## How It Works
Authorize Rootly to access your Slack workspace. For Enterprise Grid, install at the organization level and add to specific workspaces.
Use **Smart Defaults** for quick channel and notification setup, or build **Custom Workflows** for advanced conditional logic.
When incidents occur, Rootly creates channels, posts announcements, invites responders, sends reminders, and archives channels when resolved.
***
## Before You Begin
**You'll need:**
* Rootly account with admin permissions
* Slack workspace admin or owner access
* For Enterprise Grid: Org Owner or Org Admin role
***
### Required Permissions
Rootly requests the following Slack permissions during installation.
| Scope | Purpose |
| -------------------------------------- | ---------------------------------------- |
| `bookmarks:write` | Add bookmarks to incident channels |
| `channels:manage` | Create public incident channels |
| `channels:read` | View public channel information |
| `chat:write` | Send messages to incident channels |
| `chat:write.public` | Post to channels without joining |
| `commands` | Add `/rootly` and `/incident` commands |
| `files:read` | Save pinned/reacted files to timeline |
| `files:write` | Upload files via workflows |
| `groups:read` | View private channels Rootly is added to |
| `groups:write` | Create private incident channels |
| `pins:read` / `pins:write` | Pin messages to incident channels |
| `reactions:read` / `reactions:write` | Add timeline events via emoji reactions |
| `usergroups:read` / `usergroups:write` | Manage on-call user groups |
| `users:read` / `users:read.email` | View user info for invitations |
| `users.profile:read` | Display full names instead of usernames |
| Scope | Purpose |
| ------------------- | -------------------------------------------- |
| `app_mentions:read` | Respond to @rootly mentions |
| `channels:history` | Read public channel history for AI features |
| `groups:history` | Read private channel history for AI features |
| `assistant:write` | Enable Rootly AI agent |
| `im:history` | Read DMs for AI agent interactions |
| Scope | Purpose |
| ------------------ | ----------------------------- |
| `usergroups:write` | On-call user group management |
**When bot cannot create channels** (some workspaces restrict this):
| Scope | Purpose |
| ---------------- | ------------------------------------------- |
| `channels:write` | Create public channels on behalf of admins |
| `groups:write` | Create private channels on behalf of admins |
| Scope | Purpose |
| ----------------------------- | ---------------------------------- |
| `conversations.connect:write` | Connect channels across workspaces |
| `admin.conversations:write` | Manage conversations at org level |
For details on Slack scopes, see [Slack's permission documentation](https://docs.slack.dev/reference/scopes).
***
## Installation
Single workspace installation. Most common setup for teams on standard Slack plans.
Organization-level installation with multi-workspace support. Requires Org Owner/Admin.
***
### Slack Free, Pro, and Business+
In Rootly, go to **Configuration → Integrations** and search for **Slack**. Click **Setup**.
Choose **Other Slack Plans** (this covers Free, Pro, and Business+).
You'll be redirected to Slack. Verify you're installing to the correct workspace (check the dropdown in the top right), then click **Allow**.
You'll be redirected back to Rootly. The integration should show as **Connected**.
***
### Slack Enterprise Grid
You must be an **Org Owner** or **Org Admin** to complete Enterprise Grid setup. The install happens at the Slack organization level, so workspace-level roles (Workspace Owner, Workspace Admin) don't have the required permissions on their own.
With Enterprise Grid, you install Rootly at the organization level, then add it to specific workspaces. This lets you manage incidents across multiple workspaces from a single Rootly account.
In Rootly, go to **Configuration → Integrations** and search for **Slack**. Click **Setup**.
Choose **Slack Enterprise Grid**.
You'll be redirected to Slack. **Before clicking Allow**, verify you're installing at the **organization level** (not a single workspace).
Click **Allow** to approve Rootly as an organization-wide app.
After authorization, switch to your Slack Enterprise Grid admin portal:
1. Go to **Organization Settings → Integrations → Installed Apps**
2. Find **Rootly** in the list
3. Click the menu and select **Add to more workspaces**
4. Select which workspaces should have access to Rootly
5. Click **Next** and **Allow**
Rootly will now be available in those workspaces.
Return to Rootly and go to **Integrations → Slack → Configure**:
1. **Select incident workspace** — Choose which workspace will host your dedicated incident channels
2. **Set announcement channel** — Choose where new incidents are announced
3. **Set alerts channel** — Choose where alerts are posted
4. Click **Save Settings**
For cross-workspace visibility, create a shared incident channel:
1. In Slack, create or select a channel (for example, `#incidents`)
2. Click the channel name → **Settings** → **Workspaces with access**
3. Add all workspaces that should see incident announcements
This way, users in any workspace can see incidents declared from any other workspace.
***
### Switching From a Workspace Install to Enterprise Grid
If Rootly was originally installed at the **workspace** level (Slack Free / Pro / Business+) and you now want Enterprise Grid features — multi-workspace channel selection, Forms across workspaces, pin-to-timeline, shared cross-workspace incident channels — you need to **disconnect and reinstall** Rootly with the Enterprise Grid option selected.
The install-mode choice (workspace install vs Enterprise Grid install) is set **once during installation**. There is no setting in the Rootly UI to switch between the two modes after the fact. If you dismissed the install-mode prompt or originally picked workspace install, the only way to access Enterprise Grid features is to disconnect and reinstall.
**Slack-driven automation is unavailable during the disconnect-reinstall window.** Between the disconnect and the completed Enterprise Grid reinstall (including Add-to-Workspaces and channel reselection), the following stop working: `/incident` and other Slack slash commands, incident channel auto-creation, Slack notifications from workflows, `/rootly` alert commands, and any workflow action that posts to or invites into a Slack channel. Web-based incident creation and non-Slack integrations remain fully functional. **Plan the switch during a quiet operational window** — most teams schedule it outside of business hours or during a maintenance window so an active incident doesn't collide with the reinstall.
#### What's Preserved Across The Reinstall
Disconnecting and reinstalling the Slack integration only resets the **Slack integration's own settings** — the broader Rootly configuration around it stays intact. Specifically:
| Stays intact | Resets and needs to be re-set |
| ------------------------------------------------------------- | ----------------------------------------- |
| Incident workflows (triggers, conditions, actions) | Slack incident workspace selection |
| On-call schedules and escalation policies | Announcement channel |
| Other integrations (Jira, Datadog, PagerDuty, etc.) | Alerts channel |
| Channel and user references stored on existing Rootly records | Slack Smart Defaults |
| Historical incidents, timelines, retrospectives | App scopes (re-authorized during install) |
Existing workflow actions that reference specific Slack channels or users **do not need to be edited** after the reinstall — **as long as Rootly is re-added to every workspace that hosts those channels or users during the Enterprise Grid install**. Channel and user references are stored on the Rootly side and continue to resolve correctly once Rootly is present in the workspace again. You gain the *ability* to change which workspace a channel is selected from going forward, but you don't have to retroactively update anything. If Rootly is not added back to a workspace, actions that reference channels or users in that workspace will fail at execution time — this is the biggest reason to be deliberate about which workspaces you add Rootly to during Step 2.
#### Procedure
In Rootly, go to **Configuration → Integrations**, find **Slack**, click **Connected** to reveal the disconnect option, then click **Disconnect**.
See [Uninstall](#uninstall) for the full disconnect steps, including how to also remove Rootly from your Slack workspace (recommended before reinstalling to avoid lingering app state).
Restart the installation flow from **Configuration → Integrations → Slack → Setup**. When the install-mode prompt appears, choose **Slack Enterprise Grid** and follow the [Enterprise Grid install steps](#slack-enterprise-grid) above.
You must be an **Org Owner** or **Org Admin** to complete the Enterprise Grid setup — the install happens at the Slack organization level, so workspace-level roles aren't sufficient on their own. If your account doesn't have the required role, ask an Org Owner or Org Admin to complete this step.
After the Enterprise Grid install completes, set:
* The incident workspace (which workspace hosts dedicated incident channels)
* The announcement channel
* The alerts channel
* Smart Defaults as needed
These are the settings that were reset during the reinstall. Your workflows, schedules, and other integration configurations are unchanged.
Open a few of your most-used incident workflows and confirm their Slack actions still resolve to the expected channels. In almost every case they will — references are preserved across the reinstall — but spot-checking a couple of high-traffic workflows gives you a sanity check before the next incident.
If your organization isn't on a Slack Enterprise Grid plan, the Enterprise Grid option won't appear during the install flow. See the **Enterprise Grid option not showing** accordion in [Troubleshooting](#troubleshooting) below for the most common causes.
***
### Re-Claiming the /incident Command
During the transition to Rootly, you may experience issues where Rootly's bot claims the `/incident` Slack command from your existing bot. When multiple bots use the same command, [Slack will always invoke the one that was installed most recently](https://docs.slack.dev/interactivity/implementing-slash-commands/#naming_your_command). If this interrupts your transition, follow the steps below to reclaim the `/incident` command from Rootly.
#### Option 1 (Recommended)
This is the safest method — it does not result in a blackout period where your old bot is unusable.
1. Ensure Rootly is already installed on your Slack workspace.
2. Update your old bot's Slack command from `/incident` to a placeholder (for example, `/incident-1`).
3. Save the change.
4. Change the command of your old bot back to `/incident`.
Slack recognizes an update to the command as a new installation. This should make your old bot the "most recently installed bot" that uses the `/incident` command.
#### Option 2
If Option 1 does not work, try this option. There will be a brief blackout period where your old bot is unusable.
1. Ensure Rootly is already installed on your Slack workspace.
2. Uninstall your old bot.
3. Reinstall your old bot.
This is effectively the same as Option 1 — the reinstallation reclaims the `/incident` command from Rootly.
#### Enterprise Grid Consideration
If the issue persists after trying the above, check your installation scope. If **Rootly is installed at the Slack organization level** (Slack Enterprise Grid), you must also reinstall your old bot at the **Slack organization level**, not just at the workspace level.
***
## Refresh and Reconnect
Most Slack problems that look like a broken integration are a stale cache or a missing scope, and both have a dedicated refresh control. None of the three below disconnect the integration or touch your existing configuration.
Reinstalls the Slack app with its current scopes. Fixes missing permissions.
Rebuilds the cached channel list. Fixes channels missing from dropdowns.
Reloads visible Slack workspaces. Enterprise Grid.
Disconnecting is not a troubleshooting step. It clears your Slack workspace selection, announcement channel, alerts channel, and Smart Defaults, and Slack automation stops until the reinstall finishes. Use a refresh first. The only change that genuinely requires a disconnect is [switching a workspace install to Enterprise Grid](#switching-from-a-workspace-install-to-enterprise-grid).
***
### Refresh Connection
Go to **Configuration → Integrations → Slack**. **Refresh Connection** sits in the banner at the top of the page.
This re-runs the Slack installation so the app is reinstalled with its current scope list. It does not disconnect first, and your workspace selection, channels, Smart Defaults, and workflows all survive it. A Slack workspace admin approves the install on the Slack side, the same as the original setup.
Reach for it when:
* A Rootly feature needs a Slack scope your install predates. Turning on [Rootly AI in Slack](/ai/rootly-in-slack/getting-started) is the most common case, since the AI agent added scopes such as `assistant:write` and `channels:history`.
* The integration page shows a banner asking you to update permissions.
* Slack actions started failing with permission errors that no Slack-side setting explains.
When the integration page shows an **Upgrade permissions** banner for a specific feature, use the link in that banner. It requests exactly the scopes the feature needs.
***
### Refresh Channels
**Refresh Channels** sits next to **Refresh Connection** in the same banner. A **Refresh channels** link also appears beside every channel picker in Smart Defaults, so you can refresh without leaving the field you are configuring.
Rootly keeps a cached list of your Slack channels rather than querying Slack on every dropdown. The cache rebuilds automatically twice a day, at 09:00 and 21:00 UTC. Refreshing runs the same rebuild on demand as a background job, so allow a few minutes before the channel appears.
Reach for it when a channel that exists in Slack is missing from a Rootly dropdown, which usually means the channel was created since the last cache rebuild.
Refreshing does not grant access to private channels. Rootly can only see a private channel once the bot is a member. Post `@Rootly` in the channel to invite it, then refresh.
***
### Refresh Workspaces
Go to **Configuration → Integrations → Slack → Configure**. **Refresh Workspaces** sits under the workspace selector.
This reloads the list of Slack workspaces Rootly can see and applies immediately. It matters on Enterprise Grid, where the set of workspaces changes independently of the Rootly install.
Reach for it after adding Rootly to another workspace through **Organization Settings → Integrations → Installed Apps** in the Slack admin portal. The new workspace will not appear in Rootly's selector until the list is refreshed.
***
### Which One Do I Need
| What you are seeing | Control |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| A Slack scope or permission is missing | **Refresh Connection** |
| A feature banner asks you to update permissions | The link in that banner |
| A newly created channel is missing from a dropdown | **Refresh Channels** |
| A private channel is missing from a dropdown | Invite the bot with `@Rootly`, then **Refresh Channels** |
| A workspace you just added to the Grid is missing | **Refresh Workspaces** |
| You need Enterprise Grid features on a workspace install | [Disconnect and reinstall](#switching-from-a-workspace-install-to-enterprise-grid) |
***
## Smart Defaults
Smart Defaults let you configure automatic Slack behaviors without building custom workflows. Enable channel creation, set up announcements, configure reminders, and manage archiving from a single settings panel.
**New vs Existing Customers:**
* **New customers** have Smart Defaults enabled by default and can manage incidents immediately
* **Existing customers** have Smart Defaults disabled to avoid disrupting existing workflow configurations
***
1. Go to **Configuration → Integrations → Slack**
2. Click **Configure**
3. You'll see the Smart Defaults panel
***
### Workspace Setup
Select the Slack workspace where incident channels will be created.
Most users see one workspace. **Enterprise Grid** customers may see multiple workspaces.
The selected workspace determines which users, groups, and channels appear in Rootly dropdowns.
***
### Notifications
Configure what messages Rootly sends to Slack.
#### Team Notifications
Announces every new **public** incident in a specified channel. [Private incidents](/incidents/private-incidents/private-incidents) are excluded from this announcement.
Rootly rebuilds its channel cache twice a day, at 09:00 and 21:00 UTC. Click **Refresh channels** if a channel doesn't appear. See [Refresh and Reconnect](#refresh-channels).
For **private channels**, the Rootly bot must be added first. Send `@Rootly` in the channel to invite the bot.
Notify specific users, groups, or channels when high-severity incidents are declared.
See [Severities](/configuration/severities) to configure severity levels.
Announces new alerts in a specified channel. Messages auto-update as alerts are acknowledged, escalated, or resolved.
For conditional routing (for example, different channels per team), use a Custom Workflow.
#### Smart Reminders
| Reminder | What It Does |
| ---------------------- | ------------------------------------------------------------ |
| **Unassigned roles** | Notifies if no incident roles are assigned within a set time |
| **Triage timeout** | Notifies if incident stays in Triage state too long |
| **Inactive incident** | Notifies if no activity occurs within a set time |
| **Empty summary** | Notifies if incident summary remains blank |
| **Status page update** | Periodic reminder to update status pages |
| **Leave feedback** | Reminder to log feedback after resolution |
**What counts as "activity"?**
* Updating the incident summary ✓
* Using 📌 emoji to log timeline events ✓
* Regular messages in the channel ✗ (does not count)
#### Updates
| Setting | What It Does |
| ------------------------------------- | ---------------------------------------------- |
| **Status change notifications** | Post to channel when incident status changes |
| **Status page notifications** | Post when a status page is updated |
| **Draft communication notifications** | Post when a draft communication is created |
| **Timeline pin reaction** | Add ✅ emoji when events are pinned to timeline |
| **Pin timeline events** | Pin timeline updates to the Slack channel |
#### Advanced
| Setting | What It Does |
| ----------------------------- | -------------------------------------------------------------------------------------------- |
| **Broadcast incident events** | Post timeline updates as new messages instead of threading them. Noisier but harder to miss. |
| **Mention and tag @user** | Tag users mentioned by Rootly in timeline updates. Disable to reduce notification fatigue. |
***
### Incident Channel
Configure how incident channels are created and managed.
#### Channel Settings
| Setting | What It Does |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| **Create incident channel** | Auto-create a Slack channel for each new incident. Highly recommended. |
| **Channel naming convention** | Select from predefined formats or create custom names using [Liquid variables](/liquid/incident-variables) |
| **Auto-bookmark incident link** | Add a bookmark linking to the incident in Rootly web UI |
| **Auto-update channel topic** | Update topic when severity, status, type, or environment changes |
Slack doesn't allow duplicate channel names. Predefined options ensure uniqueness. For custom names, include unique identifiers like `{{ incident.sequential_id }}`.
**Example custom channel names:**
* `inc-{{ incident.sequential_id }}-{{ incident.title | slugify }}`
* `{{ incident.severity | downcase }}-{{ incident.created_at | date: '%Y%m%d' }}-{{ incident.title | truncate: 20 }}`
#### Bypass Slack Permissions
Some workspaces restrict channel creation to admins. Enable this to let Rootly create channels on behalf of admin users.
Check with your Slack admin before enabling. This requires additional user scopes.
#### Emoji Shortcuts
Configure emoji reactions to trigger actions:
| Default Emoji | Action |
| ------------- | -------------------------------- |
| 📌 | Add message to incident timeline |
| 🔧 | Create a follow-up action item |
| ⭐ | Create a task |
Choose uncommon emojis to avoid accidental triggers. Avoid 👍, 😄, or other frequently used reactions.
#### Archive Channels
| Setting | What It Does |
| ---------------------------------- | --------------------------------------------------------------------------------------- |
| **Auto-archive incident channels** | Archive channels after resolution. Set a delay (1-2 days recommended) to allow cleanup. |
| **Auto-archive test incidents** | Archive test/tutorial channels 24 hours after creation |
#### Member Tracking
| Setting | What It Does |
| ---------------------------- | ------------------------------------------------------ |
| **Require Slack connection** | Force all Rootly users to connect their Slack accounts |
| **Track joins** | Log when users join incident channels to the timeline |
| **Track leaves** | Log when users leave incident channels to the timeline |
***
### When to Use Custom Workflows Instead
Smart Defaults cover common scenarios, but use Custom Workflows when you need:
* **Conditional logic** — Different channels for different teams or severities
* **Multi-step automations** — Invite users, then send a message, then add a bookmark
* **Integration actions** — Create Jira tickets, page PagerDuty, update status pages
* **Scheduled/delayed actions** — Send reminders at specific intervals
* **Custom message formatting** — Use Block Kit for rich interactive messages
## Workflows
**Quick setup, no code**
Pre-configured settings for channel creation, topics, notifications, and reminders.
**Full control**
Build conditional automations with triggers, conditions, and 10+ Slack actions.
### Available Actions
Custom workflows give you full control over Slack automation. Create channels, send messages, invite users, and more based on triggers and conditions you define. If you're new to workflows, see the [Workflows](/workflows/workflows) documentation first.
***
| Action | What It Does |
| -------------------------------------------- | ----------------------------------------- |
| [Create Slack Channel](#action-reference) | Create a dedicated incident channel |
| [Send Slack Message](#action-reference) | Post a message to channels/users |
| [Send Slack Reminder](#action-reference) | Send recurring messages with snooze/pause |
| [Send Slack Blocks](#action-reference) | Send rich Block Kit messages |
| [Invite to Slack Channel](#action-reference) | Add users/groups to a channel |
| [Rename Slack Channel](#action-reference) | Change channel name dynamically |
| [Update Channel Topic](#action-reference) | Update the channel topic |
| [Add Slack Bookmark](#action-reference) | Pin links to channel bookmark bar |
| [Archive Slack Channel](#action-reference) | Archive inactive channels |
| [Change Channel Privacy](#action-reference) | Switch between public/private |
***
### Create a Workflow
Go to **Rootly → Workflows → Create Workflow**.
Select **Incident**, **Retrospective**, or **Pulse** depending on when you want the workflow to run.
Triggers define when the workflow runs.
| Trigger | When It Fires |
| ------------------------------- | ---------------------------------------------- |
| **Incident Created** | New incident declared |
| **Incident Updated** | Fields like severity or status change |
| **Incident Status Changed** | Status moves (for example, Active → Mitigated) |
| **Incident Commander Assigned** | Someone takes ownership |
| **Manual Trigger** | Run on-demand from Slack or web UI |
Conditions filter when the workflow should actually execute.
**Common conditions:**
* **Severity** — Only for SEV-1 or SEV-2
* **Team/Service** — Only for specific teams
* **Incident Type** — Only for actual incidents (not tests)
* **Environment** — Only for production
Click **Add Action** and search for **Slack**.
Select one or more Slack actions. Each action is configured independently.
***
### Action Reference
Creates a dedicated channel for the incident.
Which Slack workspace to create the channel in.
Channel name. Supports [Liquid variables](/liquid/incident-variables).
Example: `incident-{{ incident.sequential_id }}-{{ incident.title }}`
Controls channel visibility:
* `auto` — matches incident privacy (private incident → private channel)
* `true` — always private
* `false` — always public
If the incident already has a Slack channel, this action will skip channel creation to avoid duplicates.
Posts a message to channels, users, or user groups.
Target channels. Use `{{ incident.slack_channel_id }}` for the incident channel. Supports [Liquid variables](/liquid/incident-variables).
Individual users to message directly.
Groups to notify — all members receive the message.
Message content. Supports [Liquid variables](/liquid/incident-variables) and [Slack markdown](https://api.slack.com/reference/surfaces/formatting).
**Message Options:**
| Option | Description |
| -------------------------- | --------------------------------------- |
| **Pin to Channel** | Pin the message |
| **Send as Ephemeral** | Only visible to specified users |
| **Thread under parent** | Reply to an existing message |
| **Update Parent Message** | Replace the parent instead of threading |
| **Broadcast Thread Reply** | Also post threaded reply as new message |
**Action Buttons** — add interactive buttons to messages:
| Button | What It Opens |
| ------------------------ | ------------------------ |
| Update Summary | Edit incident summary |
| Manage Incident Roles | Assign/remove roles |
| Update Incident | Edit incident fields |
| Leave Feedback | Log incident feedback |
| Manage Action Items | Task/follow-up checklist |
| Add PagerDuty Responders | Page via PagerDuty |
| Add Opsgenie Responders | Page via Opsgenie |
Same as Send Message, but with **Snooze/Pause** buttons and support for **recurring schedules**.
Target channels. Supports [Liquid variables](/liquid/incident-variables).
Reminder message content. Supports [Liquid variables](/liquid/incident-variables).
How often the reminder fires. Options include once, every N minutes, hourly, and daily.
Use reminders for periodic nudges (for example, "Update the incident summary every 30 minutes"). The Snooze and Pause buttons allow responders to defer or stop reminders without leaving Slack.
Send rich, interactive messages using [Slack Block Kit](https://api.slack.com/reference/block-kit).
JSON payload following Block Kit format. Supports [Liquid variables](/liquid/incident-variables).
Text shown in push notifications when Block Kit content can't be rendered.
**Block Kit Examples:**
Text section with markdown:
```json theme={null}
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Incident:* {{ incident.title }}\n*Severity:* {{ incident.severity }}"
}
}
```
Button that triggers a workflow:
```json theme={null}
{
"type": "actions",
"elements": [{
"type": "button",
"text": { "type": "plain_text", "text": "View Action Items" },
"action_id": "trigger_custom_workflow",
"value": "incident-list-out-incomplete-action-items"
}]
}
```
**Available `action_id` values:**
| action\_id | What It Does |
| ----------------------------------------- | --------------------------------------------------- |
| `toolbar_update_incident_summary` | Edit summary modal |
| `toolbar_update_status` | Change status modal |
| `toolbar_update_incident` | Edit incident modal |
| `manage_incident_role_assignments_dialog` | Assign roles modal |
| `manage_incident_action_items` | Action items checklist |
| `add_feedback` | Feedback modal |
| `pagerduty_responders` | PagerDuty escalation |
| `opsgenie_responders` | Opsgenie escalation |
| `snooze_reminder` | Snooze recurring workflow |
| `pause_reminder` | Pause recurring workflow |
| `trigger_custom_workflow` | Run another workflow (set `value` to workflow slug) |
| `open_custom_form` | Open a custom form (set `value` to form slug) |
Slack's Block Kit Builder can't interpret Liquid variables. Test your templates in Rootly's [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer).
Adds users or user groups to a channel.
Target channel. Use `{{ incident.slack_channel_id }}` for the incident channel. Supports [Liquid variables](/liquid/incident-variables).
Individual users to invite. Use `{{ incident.creator }}` for the incident creator.
Groups to invite — all members are added to the channel.
Changes the channel name dynamically, useful for reflecting status changes.
Channel to rename. Use `{{ incident.slack_channel_id }}`. Supports [Liquid variables](/liquid/incident-variables).
New channel name. Supports [Liquid variables](/liquid/incident-variables).
Example: `resolved-{{ incident.title }}`
**Common use case:** Rename to include status when resolved (for example, `resolved-database-outage`).
Sets the channel topic to display key incident info at a glance.
Channels to update. Supports [Liquid variables](/liquid/incident-variables).
New topic text. Supports [Liquid variables](/liquid/incident-variables) and Slack markdown.
**Example topic:**
```liquid theme={null}
🔴 {{ incident.severity }} | {{ incident.status }} | Commander: {{ incident.commander.name | default: "Unassigned" }}
```
Pins a link to the channel's bookmark bar for quick access during an incident.
Channel to add the bookmark to. Supports [Liquid variables](/liquid/incident-variables).
Bookmark display text. Supports [Liquid variables](/liquid/incident-variables).
URL to bookmark. Common values: `{{ incident.url }}`, `{{ incident.jira_issue_url }}`. Supports [Liquid variables](/liquid/incident-variables).
Icon shown next to the bookmark.
Optionally link to a Rootly playbook instead of specifying a title and link manually.
Archives the channel to keep your workspace clean after an incident is resolved.
Channel to archive. Use `{{ incident.slack_channel_id }}`. Supports [Liquid variables](/liquid/incident-variables).
**Common trigger:** Incident status changed to "Closed" with a 24–48 hour delay to allow post-incident cleanup.
Switches a channel between public and private.
Channel to modify. Supports [Liquid variables](/liquid/incident-variables).
* `public` — make the channel visible to all workspace members
* `private` — restrict access to invited members only
Changing from private to public may not be allowed by your Slack workspace settings.
***
### Common Liquid Variables
| Variable | Description |
| ---------------------------------------- | --------------------------------------------- |
| `{{ incident.slack_channel_id }}` | Current incident's channel ID |
| `{{ incident.title }}` | Incident title |
| `{{ incident.severity }}` | Severity level |
| `{{ incident.status }}` | Current status |
| `{{ incident.url }}` | Link to incident in Rootly |
| `{{ incident.creator }}` | User who created the incident |
| `{{ parent_incident.slack_channel_id }}` | Parent incident's channel (for sub-incidents) |
Explore all variables in the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer).
## Slash Commands
| Icon | Meaning |
| ---- | -------------------------- |
| 🌐 | Works in any Slack channel |
| 🚨 | Requires incident channel |
***
### Getting Started
| Command | Description | Where |
| ----------------- | ---------------------------------------- | ----- |
| `/rootly connect` | Link your Slack account to Rootly | 🌐 |
| `/rootly help` | View available commands and descriptions | 🌐 |
| `/rootly support` | Report an issue to Rootly | 🌐 |
***
### Create & View Incidents
| Command | Description | Where |
| --------------------- | ----------------------------------------------- | ----- |
| `/rootly new` | Declare a new incident and create a channel | 🌐 |
| `/rootly test` | Create a test incident (not publicly announced) | 🌐 |
| `/rootly maintenance` | Schedule a maintenance window | 🌐 |
| `/rootly list` | View up to 10 active incidents | 🌐 |
| `/rootly overview` | Open incident control center | 🚨 |
| `/rootly catchup` | Get AI-powered incident summary | 🚨 |
***
### Update Incidents
| Command | Description | Where |
| -------------------- | --------------------------------------------------------------------------------------------------- | ----------------- |
| `/rootly update` | Edit incident fields (severity, type, etc.) | 🚨 |
| `/rootly summary` | Add or edit incident summary | 🚨 |
| `/rootly timeline` | Add an event to the incident timeline | 🚨 |
| `/rootly timestamps` | Edit status change timestamps | 🚨 |
| `/rootly convert` | Convert current channel to incident channel | 🌐 (non-incident) |
| `/rootly comms new` | Create a stakeholder communication from a template — see [Communications](/communications/overview) | 🚨 |
***
### Incident Status
| Command | Description | Where |
| ------------------ | -------------------------- | ----- |
| `/rootly status` | Change incident status | 🚨 |
| `/rootly mitigate` | Mark incident as mitigated | 🚨 |
| `/rootly resolve` | Mark incident as resolved | 🚨 |
***
### Teams & Services
| Command | Description | Where |
| --------------------------- | ------------------------------------ | ----- |
| `/rootly add team` | Attach a team to the incident | 🚨 |
| `/rootly add service` | Tag impacted services | 🚨 |
| `/rootly add functionality` | Tag impacted functionalities | 🚨 |
| `/rootly add alert` | Associate an alert with the incident | 🚨 |
***
### Roles & Assignments
| Command | Description | Where |
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `/rootly assign` | Assign, add, or remove incident roles | 🚨 |
| `/rootly escalate` \| `/rootly call` \| `/rootly page` | Open the paging dialog. In an incident channel this attaches the page to the incident and routes through any configured external provider (PagerDuty, Opsgenie, VictorOps); outside an incident channel it opens the manual Rootly On-Call paging dialog. All three words are aliases for the same command. | 🌐 / 🚨 |
***
### Action Items
| Command | Description | Where |
| ------------------------- | -------------------------------------------- | ----- |
| `/rootly task` | Create a task (to complete during incident) | 🚨 |
| `/rootly followup` | Create a follow-up (post-incident action) | 🚨 |
| `/rootly add action item` | Create a task or follow-up | 🚨 |
| `/rootly action items` | Manage the incident's action items | 🚨 |
| `/rootly todo` | View your assigned action items (to-do list) | 🚨 |
| `/rootly tasks` | View your assigned action items (to-do list) | 🚨 |
Alias: `/rootly action` also works for managing action items.
***
### On-Call & Paging
| Command | Description | Where |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | ------- |
| `/rootly oncall` | View on-call schedules | 🌐 |
| `/rootly page` \| `/rootly escalate` \| `/rootly call` | Alias for the paging dialog (see [Roles & Assignments](#roles-assignments) for full behavior). | 🌐 / 🚨 |
| `/rootly alerts` | View all alerts | 🌐 |
***
### Advanced
| Command | Description | Where |
| ----------------------- | -------------------------------------------------------- | ----------- |
| `/rootly manage fields` | Set values for custom incident fields | 🚨 |
| `/rootly integrations` | Manage links to integrated tools (Jira, PagerDuty, etc.) | 🚨 |
| `/rootly statuspage` | Publish an update to a status page | 🚨 |
| `/rootly feedback` | Log feedback about the incident response | 🚨 |
| `/rootly duplicate` | Mark incident as duplicate of another | 🚨 |
| `/rootly sub` | Create a sub-incident | 🚨 (parent) |
| `/rootly workflows` | Manually trigger a workflow | 🚨 |
***
### Command Details
### `/rootly new`
Opens the incident creation form. Fill in title, summary, severity, and type. Rootly will:
* Create a dedicated Slack channel
* Post the initial incident message
* Trigger configured workflows
### `/rootly test`
Same as `/rootly new`, but the incident is marked as a test and won't be publicly announced. Use for training and workflow testing.
### `/rootly maintenance`
Schedule planned maintenance. Maintenance incidents appear in the Rootly web UI and can be published to status pages.
### `/rootly status`
Opens a modal to change the incident status (In Triage → Active → Mitigated → Resolved → Closed).
### `/rootly mitigate`
Quick action to mark the incident as mitigated. You'll be prompted to add a comment explaining the mitigation.
### `/rootly resolve`
Quick action to mark the incident as resolved. You'll be prompted to add a resolution comment.
**Tasks** are actions to complete during the incident (for example, "Restart the database").
**Follow-ups** are post-incident actions (for example, "Add monitoring for this failure mode").
Use `/rootly action items` to manage this incident's action items, or `/rootly todo` (alias `/rootly tasks`) to see the checklist of items assigned to you.
### `/rootly oncall`
View who's currently on-call for any schedule. Works with Rootly On-Call and integrated providers (PagerDuty, Opsgenie, VictorOps).
### `/rootly escalate` · `/rootly call` · `/rootly page`
These three words are **aliases for the same command** — pick whichever your team prefers. The dialog that opens depends on where you invoke the command:
* **Inside an incident Slack channel** — the escalation dialog opens with the current incident's context. If your team has an external paging integration (PagerDuty, Opsgenie, VictorOps, PagerTree), the dialog routes the page through that provider; otherwise it uses Rootly On-Call.
* **In any other channel** — the manual page dialog opens for ad-hoc paging (Rootly On-Call schedules, teams, services, functionalities, or escalation policies).
You can prefill target users by `@`-mentioning them after the command: `/rootly page @alice @bob`. Non-mention trailing text is ignored.
If a team admin has enabled a custom Slack paging workflow (Team Settings), the alias set is disabled and these commands won't respond.
### `/rootly convert`
Convert an existing Slack channel into a Rootly incident channel. Use this when an incident discussion is already happening in a channel before it's formally declared.
Run this command in the channel you want to convert (not an existing incident channel).
## Troubleshooting
**Causes:**
* You're not an Admin or Owner of the workspace
* Workspace doesn't allow members to install apps
* Logged into wrong Slack account
**Solutions:**
* Ask a Slack Admin/Owner to install Rootly
* Check **Slack → Settings & Permissions → App Management**
* Try in a private browser window with the correct Slack account
**Causes:**
* Your org isn't on Enterprise Grid
* You're not an Org Owner/Admin
* Logged into a non-Grid workspace
**Solutions:**
* Verify your plan at [Slack's pricing page](https://slack.com/pricing)
* Ask an Org Owner/Admin to complete installation
* Log into your Enterprise org, not a standalone workspace
**Causes:**
* Rootly bot lacks channel creation permissions
* Workspace restricts channel creation to admins
**Solutions:**
* Enable **Bypass Slack permissions** in Smart Defaults
* Verify Rootly has `channels:manage` and `groups:write` scopes
* Check workflow logs for specific errors
**Causes:**
* Announcement channel isn't shared across workspaces
* Rootly not added to all required workspaces
**Solutions:**
* Create a shared channel for incident announcements
* Add Rootly to all workspaces via **Organization Settings → Installed Apps**
Slack includes a native, Slack-built Rootly connector in Workflow Builder that is separate from the Rootly Slack app. If you need to disable or restrict this connector at the workspace level, see the [FAQ on the Slack integration page](/integrating-with-slack#frequently-asked-questions) for step-by-step instructions.
If you're on Slack Enterprise Grid and pinning messages to the incident timeline isn't working, this is a sign that your Slack integration was installed as a **non-Grid** (single-workspace) installation rather than at the organization level. \
\
**Solutions:**
* Disconnect the Slack integration from Rootly
* Reconnect it, making sure to select **Slack Enterprise Grid** during installation and authorize at the **organization level** (not a single workspace)
## Uninstall
To remove the Slack integration:
1. Go to **Configuration → Integrations** and find **Slack**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
Disconnecting from Rootly does not remove Rootly from Slack. To fully revoke access:
1. In Slack, go to **Settings & Administration → Manage Apps**
2. Find **Rootly** and click **Remove**
***
# SMTP
Source: https://docs.rootly.com/integrations/smtp
Route Rootly workflow emails through your own SMTP server to send from your company domain with full control over delivery, authentication, and headers.
## Overview
By default, Rootly sends workflow emails from `workflows@rootly.com`. Connecting an SMTP server lets you route those emails through your own mail infrastructure — so emails arrive from your company domain and you retain full control over delivery, authentication, and TLS configuration.
Send workflow emails from your own domain instead of Rootly's default address.
Configure TLS, authentication type, port, and SSL verification to match your mail server's requirements.
All **Send an Email** workflow actions automatically route through SMTP once connected — no changes to existing workflows needed.
SMTP takes precedence over SendGrid. If both are connected, SMTP is always used.
## Before You Begin
* You must be a Rootly admin to set up the integration
* You need SMTP credentials for your mail server (address, port, username, password)
## Installation
Go to **Configuration → Integrations**, find **SMTP**, and click **Setup**.
Fill in your server configuration and click **Connect**.
## Configuration
The hostname of your SMTP server — for example, `smtp.gmail.com` or `smtp.sendgrid.net`. Must be a valid domain name. Stored encrypted at rest.
The port your SMTP server listens on. Defaults to `587` (STARTTLS). Common values: `25`, `465` (SMTPS), `587`.
The HELO/EHLO domain sent to the mail server during the SMTP handshake — for example, `yourcompany.com`. Optional; leave blank to use the default.
The username for SMTP authentication. Required if your server requires authentication. Stored encrypted at rest.
The password for SMTP authentication. Required if your server requires authentication. Stored encrypted at rest.
The authentication mechanism your server requires:
* `plain` — Sends credentials in plain text (use with TLS)
* `login` — Base64-encoded credentials (use with TLS)
* `cram_md5` — Challenge-response authentication (does not require TLS)
Defaults to `plain`.
Force STARTTLS when connecting. If enabled and the server does not support STARTTLS, the connection will fail. Defaults to `false`.
Automatically detect and use STARTTLS if the server supports it, but do not fail if it doesn't. Defaults to `true`. Disable if you are using direct TLS via SSL mode.
Use SMTPS — SMTP over a direct TLS connection on port 465. Defaults to `true`. Disable if your server uses STARTTLS instead.
How OpenSSL validates the server certificate:
* `None` — No certificate verification (useful for self-signed certs)
* `Peer` — Verify the server's certificate against trusted CAs
Defaults to `None`.
Once SMTP is connected, all **Send an Email** workflow actions are automatically routed through it. The **From** field in each workflow action controls the sender address — just ensure the address is authorized on your SMTP server.
## Uninstall
To remove the SMTP integration:
1. Go to **Configuration → Integrations** and find **SMTP**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
After disconnecting, workflow emails will fall back to SendGrid (if connected) or Rootly's default delivery.
## Frequently Asked Questions
No. All **Send an Email** workflow actions automatically route through SMTP once connected. No changes to existing workflows are required.
**SSL** (SMTPS) opens a TLS connection immediately on port 465. **StartTLS** begins as a plain connection on port 587, then upgrades to TLS. Most modern mail servers use port 587 with StartTLS — enable **StartTLS Auto** and disable **SSL** for this setup.
SMTP always takes priority. If both are connected, Rootly uses SMTP. To switch to SendGrid, disconnect the SMTP integration first.
Yes. Set **SSL Verify Mode** to `None` to skip certificate validation. This is useful for internal mail servers with self-signed certificates.
The **From** address must be authorized on your SMTP server. Rootly will not allow workflow emails to spoof Rootly-owned domains regardless of the From field value.
## Related resources
* [Email](/integrations/email)
* [SendGrid](/integrations/sendgrid)
* [Twitter / X](/integrations/twitter)
# Splunk
Source: https://docs.rootly.com/integrations/splunk
Connect Splunk to Rootly using the official Rootly Splunk app to forward saved search alerts, trigger on-call paging, and automate incident creation.
## Introduction
The Splunk integration connects Rootly with Splunk Enterprise or Splunk Cloud so teams can receive alerts from saved searches as Rootly alerts and trigger on-call paging directly from Splunk alert actions.
With the Splunk integration, you can:
* Forward Splunk saved search alerts to Rootly as alerts
* Page Rootly on-call targets directly from Splunk alert actions
* Use alert workflows to create incidents and automate follow-up actions from Splunk search results
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with permission to manage integrations and alert sources
* Splunk Enterprise or Splunk Cloud with admin access to install apps on search heads
* The integration URL or key from your Rootly Splunk alert source settings
The Rootly Splunk app must be installed on your **search heads**. It does not need to be installed on indexers or forwarders.
## Installation
Navigate to **Settings > Alert Sources** in Rootly and create a new alert source. Select **Splunk** and give it a descriptive name.
Copy the **integration URL** or **integration key** shown after saving — you will need this when configuring the Splunk app.
Install the Rootly app from Splunkbase:
[Rootly App on Splunkbase](https://splunkbase.splunk.com/app/7721)
Install the app via **Splunk Web Admin** on your search heads.
The app must be installed on search heads. Alerts in Splunk are triggered from search heads, so the Rootly alert action will not be available unless the app is installed there.
After installation, configure the Rootly app using the integration URL or key from your Rootly alert source settings.
Use the full integration URL if prompted, or the integration key alone depending on the app version. Both are available from your Rootly Splunk alert source settings.
In Splunk, open a saved search and navigate to its **Alert Actions**. Add the **Rootly** action and configure it to forward alerts when the search fires.
You can configure different saved searches to route to different Rootly on-call targets by using separate alert sources or by including notification target parameters in the action configuration.
## How Alerts Are Mapped
Rootly extracts the following fields from each Splunk alert payload:
* **Summary** — the `search_name` field (the name of the saved search that fired)
* **External ID** — the `sid` (search ID), used to identify the alert
* **External URL** — the `results_link`, linking back to the Splunk search results
* **Started at** — the `result._time` field, parsed as a Unix timestamp
The Splunk `search_name` becomes the alert summary in Rootly. Use descriptive saved search names to make it easy to identify alerts in Rootly workflows and the alert feed.
## Troubleshooting
Confirm the Rootly app is installed on the search head where you are configuring the saved search. The alert action is only available on nodes where the app is installed.
Verify that the integration URL or key configured in the Rootly app matches what is shown in your Rootly Splunk alert source settings. Check the Splunk alert action logs for delivery errors.
Rootly extracts these fields from the standard Splunk alert payload. Confirm the saved search is configured to include search results and metadata in the alert action payload.
## Uninstall
To remove the Splunk integration, open the integrations panel in Rootly and select **Configure > Delete**. You can also uninstall the Rootly app from Splunk Web Admin.
## Related resources
* [Prometheus Alertmanager](/integrations/alertmanager)
* [Checkly](/integrations/checkly)
* [Chronosphere](/integrations/chronosphere)
* [Dynatrace](/integrations/dynatrace)
# SSO
Source: https://docs.rootly.com/integrations/sso
Enable single sign-on for Rootly with SAML 2.0 compatible identity providers including Okta, Google, OneLogin, Auth0, Azure AD, JumpCloud, and more.
## Installation
You can set up this integration as a **logged in admin user** in the integrations page:
## Identity Providers
Rootly is compatible with **any identity provider** supporting **SAML 2.0.**
Depending on the identity provider, you might be asked for the following information during your setup process:
### Service Provider Details
| Field | Value |
| ---------------------------- | -------------------------------------------------------- |
| **ACS URL** | `https://rootly.com/users/saml/auth` |
| **Entity ID / Audience URI** | `https://rootly.com/users/saml/metadata` |
| **SP Metadata URL** | `https://rootly.com/users/saml/metadata` |
| **Name ID Format** | `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress` |
| **Binding** | HTTP-POST |
### SAML Attribute Mapping
Rootly reads the following attributes from the SAML assertion. Email is taken from the NameID element and is required. All other attributes are optional but recommended for accurate Just-In-Time (JIT) provisioning.
| Rootly field | SAML attribute |
| -------------- | ---------------------------- |
| Email | NameID (emailAddress format) |
| First name | `name.givenName` |
| Last name | `name.familyName` |
| Preferred name | `displayName` |
| Phone number | `phoneNumbers.work` |
### Certificate Requirements
Rootly requires a PEM-encoded X.509 certificate from your IdP to validate SAML assertions.
* Must be in PEM format with `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` headers
* Must not be expired — Rootly rejects expired certificates at save time
* Must match the certificate your IdP uses to sign SAML responses
### Okta
Let's go to the **Applications > Applications > Browse App Catalog**.
Search for "**Rootly"**.
Click on **Add Integration**.
Give the app a name.
TIP: If you're planning on using multiple orgs on Rootly, consider naming each Rootly app in Okta a name that corresponds to each org.
Select **SAML 2.0**.
With the app created, go back to **Applications > Rootly** and click **View Setup Instructions:**
Finally copy the fields as shown below into **Rootly**, this information from Okta is unique to your organization.
| Okta field | Rootly field |
| ------------------------------------ | -------------------- |
| Identity Provider Issuer | Identity Provider ID |
| Identity Provider Single Sign-On URL | Identity Login URL |
| X.509 Certificate | IdP Cert |
Test your SSO integration by assigning yourself or a test user to the app. Go to **Assignments > Assign > Assign to People**.
If you're already logged into Rootly, log out. Then navigate to the sign-on link [https://rootly.com/users/sign\_in](https://rootly.com/users/sign_in). Click on **SSO**.
Enter your full work email (not just the domain) and click **Sign In**.
You are all set!
### Google
You will need to access the **Google Admin Console:** [https://admin.google.com/ac/home](https://admin.google.com/ac/home).
Follow screenshot steps as below:
Make sure `Signed Response` is checked and the app `ON for everyone` is checked in your org unit.
And finally let's edit the attributes mapping.
| Google Workspace field | SAML attribute |
| ---------------------- | ----------------- |
| Primary email | NameID |
| First name | `name.givenName` |
| Last name | `name.familyName` |
Let's switch to Rootly. You can get the identity login url by clicking on the `TEST SAML LOGIN` button.
### OneLogin
Browse the Applications Store page and install Rootly.
Copy fields over Rootly like shown below
* Issuer URL **->** Identity Provider ID
* SAML 2.0 endpoint **->** Identity Login Url
* In the certificate section > View Details > X.509 Certificate **->** Idp Cert
You are all set!
### Auth0
Docs: [https://marketplace.auth0.com/integrations/rootly-sso-integration](https://marketplace.auth0.com/integrations/rootly-sso-integration)
### Azure
Install SSO integration through the Azure marketplace
* Marketplace: [https://azuremarketplace.microsoft.com/en-US/marketplace/apps/aad.rootly](https://azuremarketplace.microsoft.com/en-US/marketplace/apps/aad.rootly)
* Tutorial: [https://docs.microsoft.com/en-us/azure/active-directory/saas-apps/rootly-tutorial](https://docs.microsoft.com/en-us/azure/active-directory/saas-apps/rootly-tutorial)
### Rippling
Integrate Rippling SSO + SCIM in one click [https://www.rippling.com/app-shop/app/rootly](https://www.rippling.com/app-shop/app/rootly)
### Keycloak
Keycloak is an open-source identity and access management solution. Follow these steps to configure SAML SSO with Rootly.
#### Prerequisites
* Access to Keycloak admin console
* Keycloak realm set up (can use default `master` realm for testing)
* User account in Keycloak with email attribute configured
#### Step 1: Create SAML Client in Keycloak
1. Navigate to **Clients** in the Keycloak admin console
2. Click **Create Client**
3. Select **SAML** as the client type
4. Set **Client ID** to: `https://rootly.com/users/saml/metadata`
5. Click **Next** and **Save**
#### Step 2: Configure Client Settings
Navigate to your client's **Settings** tab and configure:
**Access Settings:**
* **Root URL**: `https://rootly.com/users/saml`
* **Home URL**: `https://rootly.com/users/saml`
* **Valid redirect URIs**:
* `https://rootly.com/*`
* `https://rootly.com/users/saml/auth`
* **Master SAML Processing URL**: `https://rootly.com/users/saml/auth`
**SAML Capabilities:**
* **Name ID format**: `email`
* **Force POST binding**: `On`
* **Include AuthnStatement**: `On`
**Signature and Encryption:**
* **Sign documents**: `On`
* **Sign assertions**: `On`
* **Signature algorithm**: `RSA_SHA256`
* **SAML signature key name**: `KEY_ID`
* **Canonicalization method**: `EXCLUSIVE`
#### Step 3: Configure Keys
Navigate to the **Keys** tab:
* **Client signature required**: `Off`
* **Encrypt assertions**: `Off`
#### Step 4: Configure Name ID Mapper
1. Go to **Client scopes** → **Dedicated scopes** → **Mappers**
2. Create or edit the **Email** mapper:
* **Mapper type**: `User Attribute Mapper For NameID`
* **Name**: `Email`
* **Name ID Format**: `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`
* **User Attribute**: `email`
#### Step 5: Configure User Email
Ensure your test user has an email address set:
1. Navigate to **Users** → Select your user
2. Go to **Details** tab
3. Set **Email** field (for example, `user@company.com`)
4. Set **Email verified**: `Yes`
#### Step 6: Get Keycloak Configuration
Collect the following information from Keycloak:
1. **Identity Provider ID**: `https://your-keycloak-host/realms/your-realm`
2. **Identity Login URL**: `https://your-keycloak-host/realms/your-realm/protocol/saml`
3. **Certificate**:
* Go to **Realm Settings** → **Keys** → **RS256** → **Certificate**
* Copy the certificate and format with proper PEM headers:
```text theme={null}
-----BEGIN CERTIFICATE-----
[certificate content]
-----END CERTIFICATE-----
```
#### Step 7: Configure Rootly
In your Rootly SSO integration modal, set:
| Rootly Field | Keycloak Value |
| ---------------------- | ------------------------------------------------------------ |
| `Identity Provider Id` | `https://your-keycloak-host/realms/your-realm` |
| `Identity Login Url` | `https://your-keycloak-host/realms/your-realm/protocol/saml` |
| `Identity Logout Url` | Leave blank or set logout URL |
| `Idp Cert` | PEM-formatted certificate from Keycloak |
| `Domain Name` | Your domain (for example, company.com) |
### Jumpcloud
Let's begin by navigating to the **SSO Applications** page from the left navigation.
Click **Add New Application**
Search for and install the **Rootly** application.
Once installed, select the Rootly application to enter edit mode and navigate to the **SSO** tab.
Update the `IdP Entity ID` from `JumpCloud` to `JumpCloud-`.
Download your **IDP Certificate**. It should download as a `.pem` file.
Navigate to your **Rootly SSO Integration** modal and fill in the following fields with the corresponding values from JumpCloud.
| Rootly Field | JumpCloud Field |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `Identity Provider Id` | `IdP Entity ID ` |
| `Identity Login Url` | `IDP URL` |
| `Identity Logout Url` | Leave blank or choose any page you'd want to navigate your user to when they log out. |
| `Idp Cert` | Open the certificate you downloaded in the previous step with a text editor of your choice. Copy and paste the text content. |
| `Domain Name` | Your domain (for example, mycompany.com) |
Go ahead `Enable` and `Save` your SSO setup in Rootly.
You're now SSO enabled!
If you want to set up **Just-In-Time (JIT) provisioning**, navigate to the **Identity Management** tab in edit mode and set the following fields according to the mappings below.
* `API Type`: `SCIM API`
* `SCIM Version`: `SCIM 2.0`
* `Base URL`: `https://rootly.com/scim`
* `Token Key`: Pick this value up from your SSO Configuration screen in Rootly
* `Test User Email`: You can use your own email as long as the email domain matches the one set in your Rootly SSO configuration page.
Go ahead and select `Test Connection`. You should see a successful message once a connection is confirmed.
If you'd like to **provision users by JumpCloud Groups**, go ahead and select the following option. This will allow you to provision the users in each JumpCloud Group with a specific Rootly Role.
Navigate to your **Rootly SSO Integrations** modal and map the desired JumpCloud Group to the desired Rootly Role.
Go ahead and `Save` your configuration. You're all set for JIT user provisioning!
## Login Behavior
If you have SSO enabled, all other login methods such as Google, Slack, Email/Password will automatically redirect to SSO for any user whose email domain matches a configured SSO account. Users on domains that are not associated with an active SSO configuration continue to use their regular login method.
## Misconfiguration
If you set up SSO incorrectly, you may not be able to sign in anymore. In that case please contact [support@rootly.com](mailto:support@rootly.com) or use the lower right chat widget for live assistance.
# Statuspage.io
Source: https://docs.rootly.com/integrations/status-page-io
Connect Atlassian Statuspage.io to Rootly to import status pages and templates, and publish incident updates to your customer-facing status page.
The Statuspage.io integration connects Rootly with Atlassian Statuspage so incident communication happens in one place. Import your existing status pages and update templates into Rootly, then publish customer-facing updates directly from an incident's Status Page Timeline.
With the Statuspage.io integration, you can:
* Import existing Statuspage.io pages into Rootly
* Import Statuspage.io update templates to standardize customer messaging
* Create a Statuspage incident from a Rootly incident
* Auto-populate status page updates from a template, including status and affected components
## Before You Begin
Before importing anything, make sure you have:
* A Rootly account with admin permission to manage integrations
* An Atlassian Statuspage account with at least one page
## Installation
Connect the integration before importing pages or templates.
Go to **Configuration → Integrations**, find **Statuspage.io**, and click **Setup**.
Follow the prompts to connect Rootly to your Atlassian Statuspage account.
Once connected, the integration shows as **Connected** on the integrations page and the import options below become available.
## Import Status Pages
Importing a page links it to Rootly so incidents can publish to it.
In the Rootly web app, navigate to **Configuration > Status pages**.
On the status pages configuration page, click **Import from statuspage.io**.
In the popup modal, select the Statuspage.io page you want to import into Rootly, then click **Import pages**.
The newly imported page appears in the list.
## Import Templates
Rootly supports Statuspage.io templates. Once imported, they auto-populate fields when you make a status page update.
Templates can only be imported for status pages that are already linked to Statuspage.io. Import the page first.
On the status page configuration page, select **Edit** on a page that has a Statuspage.io page linked. A linked page has the **STATUSPAGE.IO** column populated.
Scroll down to **Import from Statuspage.io** for templates.
In the popup modal, select which templates to import from Statuspage.io.
The imported template now appears in Rootly under your Statuspage.io integrated status page.
## Create a Statuspage Incident
Publish a Rootly incident to a linked Statuspage.io page.
Within any unpublished incident, click the **Status Page Timeline** tab, then click **Publish**.
In the publish dialog, select a status page integrated with Statuspage.io — these have "(Statuspage.io)" in the title. Fill out the publish form with your desired settings.
After publishing, the incident is added to the Rootly timeline. Click the hyperlink next to the incident event to open the newly created Statuspage.io incident.
## Use Status Page Templates
Templates are preset values that auto-populate an event update, so customer messaging stays consistent across incidents.
Within any incident in Rootly, click the **Status Page Timeline** tab, then **Add to Timeline**.
In the publish modal, select a status page with Statuspage.io integrated — these have "(Statuspage.io)" in the title.
In the same modal, select the template to use for this incident event update.
The template populates presets such as the event message, status, and any affected components.
## Related Resources
* [Status pages](/configuration/status-pages)
* [Integrations overview](/integrations/overview)
# Superplane
Source: https://docs.rootly.com/integrations/superplane
Connect Rootly with Superplane to trigger automated workflows from incident events, manage incidents programmatically, and orchestrate response automation.
## Introduction
The Superplane integration connects Rootly incidents to Superplane's workflow automation platform. You can trigger Superplane workflows when incidents or timeline events occur in Rootly, and take actions on Rootly incidents — creating, retrieving, updating, and annotating them — from within Superplane's workflow builder.
All configuration fields support dynamic expressions, enabling flexible automations that pull in live incident data and external inputs.
This integration is configured entirely from the Superplane side. Superplane automatically manages the Rootly webhook endpoints — no manual webhook setup is required in Rootly.
## Before You Begin
* A Rootly account with permission to manage integrations
* A Superplane account with permission to create and configure components
Visit [Superplane's Rootly component documentation](https://docs.superplane.com/components/rootly/) to connect Rootly and get started.
## Triggers
### On Incident
Starts a Superplane workflow when a Rootly incident event occurs. Superplane automatically creates and manages the webhook endpoint.
**Configuration**
Select which incident events to listen for:
* `incident.created`
* `incident.updated`
* `incident.mitigated`
* `incident.resolved`
* `incident.cancelled`
* `incident.deleted`
**Event data**
Each trigger payload includes:
| Field | Description |
| ---------- | ---------------------------------------------------------------------------- |
| `event` | Event type (for example, `incident.created`) |
| `incident` | Complete incident object — title, summary, severity, status, timestamps, URL |
**Example payload**
```json theme={null}
{
"data": {
"event": "incident.created",
"incident": {
"id": "abc123-def456",
"mitigated_at": null,
"resolved_at": null,
"severity": "sev2",
"started_at": "2026-01-19T12:00:00Z",
"status": "started",
"summary": "The API response times have increased significantly across all endpoints.",
"title": "API latency spike detected",
"url": "https://app.rootly.com/incidents/abc123-def456"
}
},
"timestamp": "2026-01-19T12:00:00Z",
"type": "rootly.onIncident"
}
```
***
### On Incident Timeline Event
Starts a Superplane workflow when a timeline event is created or updated on a Rootly incident. Only events with `kind: "event"` are emitted.
**Configuration**
All filters are optional:
| Filter | Description |
| --------------- | ----------------------------------------------------- |
| Incident Status | Filter by incident status (open, resolved, etc.) |
| Severity | Filter by incident severity |
| Service | Filter by service name |
| Team | Filter by team name |
| Event Source | Filter by event source (`web`, `api`, `system`) |
| Visibility | Filter by event visibility (`internal` or `external`) |
**Event data**
| Field | Description |
| ------------- | --------------------------------------------------------------- |
| `id` | Event ID |
| `event` | Event content |
| `event_raw` | Raw event content |
| `event_id` | Webhook event ID |
| `event_type` | `incident_event.created` or `incident_event.updated` |
| `kind` | Event kind |
| `source` | Event source |
| `visibility` | `internal` or `external` |
| `occurred_at` | When the event occurred |
| `created_at` | When the event was created |
| `updated_at` | When the event was last updated |
| `issued_at` | When the webhook was issued |
| `incident_id` | Parent incident ID |
| `incident` | Incident summary (id, title, severity, status, services, teams) |
**Example payload**
```json theme={null}
{
"data": {
"created_at": "2026-02-22T09:46:23.868-08:00",
"event": "Investigation started, will update accordingly",
"event_id": "b3065ca8-69a6-4781-b6b4-94d6f0317ccf",
"event_raw": "Investigation started, will update accordingly",
"event_type": "incident_event.created",
"id": "56f7b488-e3c5-4091-9bb4-cf132007f98c",
"incident": {
"id": "64c39fde-1626-4f78-874e-9db91c0639d3",
"services": ["UI - User Profile Block"],
"severity": "sev2",
"status": "mitigated",
"teams": ["Customer Relations"],
"title": "new remake from main"
},
"incident_id": "64c39fde-1626-4f78-874e-9db91c0639d3",
"issued_at": "2026-02-22T09:46:24.018-08:00",
"kind": "event",
"occurred_at": "2026-02-22T09:46:23.868-08:00",
"source": "web",
"updated_at": "2026-02-22T09:46:23.868-08:00",
"visibility": "internal"
},
"timestamp": "2026-02-22T17:46:40.603539728Z",
"type": "rootly.onIncidentTimelineEvent"
}
```
## Actions
### Create Event
Adds a timeline annotation or note to an existing Rootly incident.
**Configuration**
| Field | Description | Required |
| ----------- | ---------------------------------------------------------------- | -------- |
| Incident ID | Rootly incident UUID to add the event to | Yes |
| Event | Note or annotation text — supports expressions | Yes |
| Visibility | `internal` (responders only) or `external` (public status pages) | No |
**Output**
```json theme={null}
{
"data": {
"created_at": "2026-02-10T07:34:35.902-8:00",
"event": "Investigation update: database connections stabilized.",
"id": "a2d32bb7-0417-4d0d-8483-a583c3-7853",
"occurred_at": "2026-02-10T07:34:35.902-8:00",
"visibility": "internal"
},
"timestamp": "2026-02-10T15:34:36.09877478Z",
"type": "rootly.incident.event"
}
```
***
### Create Incident
Creates a new incident in Rootly from a Superplane workflow.
**Configuration**
| Field | Description | Required |
| -------- | ------------------------------------------------------------- | -------- |
| Title | A succinct description of the incident — supports expressions | Yes |
| Summary | Additional details about the incident — supports expressions | No |
| Severity | Incident severity level — supports expressions | No |
**Output**
```json theme={null}
{
"data": {
"id": "abc123-def456",
"severity": "sev1",
"started_at": "2026-01-19T12:00:00Z",
"status": "started",
"summary": "Users are experiencing slow database queries and connection timeouts.",
"title": "Database connection issues",
"url": "https://app.rootly.com/incidents/abc123-def456"
},
"timestamp": "2026-01-19T12:00:00Z",
"type": "rootly.incident"
}
```
***
### Get Incident
Retrieves full details for a Rootly incident by ID, including associated services, groups, timeline events, and action items.
**Configuration**
| Field | Description | Required |
| ----------- | --------------------------------------------------------- | -------- |
| Incident ID | The ID of the incident to retrieve — supports expressions | Yes |
**Output**
Returns the full incident object including `id`, `sequential_id`, `title`, `slug`, `status`, `summary`, `severity`, `url`, `started_at`, `mitigated_at`, `resolved_at`, `user`, `started_by`, `services`, `groups`, `events`, and `action_items`.
```json theme={null}
{
"data": {
"action_items": [
{ "id": "ai-001", "status": "open", "summary": "Investigate root cause of latency increase" }
],
"events": [
{ "created_at": "2026-01-19T12:00:00Z", "id": "evt-001", "kind": "incident_created", "visibility": "internal" }
],
"groups": [
{ "id": "grp-001", "name": "Backend Team", "slug": "backend-team" }
],
"id": "abc123-def456",
"mitigated_at": "2026-01-19T12:30:00Z",
"resolved_at": null,
"sequential_id": 42,
"services": [
{ "id": "svc-001", "name": "Production API", "slug": "production-api" }
],
"severity": "sev1",
"slug": "api-latency-spike-detected",
"started_at": "2026-01-19T12:00:00Z",
"started_by": { "email": "john@example.com", "full_name": "John Doe", "id": "user-002" },
"status": "mitigated",
"summary": "The API response times have increased significantly across all endpoints.",
"title": "API latency spike detected",
"url": "https://app.rootly.com/incidents/abc123-def456",
"user": { "email": "jane@example.com", "full_name": "Jane Smith", "id": "user-001" }
},
"timestamp": "2026-01-19T12:05:00Z",
"type": "rootly.incident"
}
```
***
### Update Incident
Modifies an existing Rootly incident. All fields except Incident ID are optional.
**Configuration**
| Field | Description | Required |
| ----------- | -------------------------------------------------------------------------- | -------- |
| Incident ID | UUID of the incident to update — supports expressions | Yes |
| Title | Updated incident title — supports expressions | No |
| Summary | Updated incident summary — supports expressions | No |
| Status | Updated incident status | No |
| Sub-Status | Updated sub-status — required by some Rootly accounts when changing status | No |
| Severity | Updated severity level | No |
| Services | Services to attach to the incident | No |
| Teams | Teams to attach to the incident | No |
| Labels | Key-value labels for the incident | No |
**Output**
Returns `id`, `sequential_id`, `title`, `slug`, `status`, and `updated_at`.
```json theme={null}
{
"data": {
"id": "abc123-def456",
"mitigated_at": "2026-01-19T13:30:00Z",
"sequential_id": 42,
"severity": "sev1",
"slug": "database-connection-issues",
"started_at": "2026-01-19T12:00:00Z",
"status": "mitigated",
"summary": "Root cause identified. Connection pool exhausted.",
"title": "Database connection issues - Updated",
"updated_at": "2026-01-19T13:30:00Z",
"url": "https://app.rootly.com/incidents/abc123-def456"
},
"timestamp": "2026-01-19T13:30:00Z",
"type": "rootly.incident"
}
```
## Troubleshooting
Confirm the Rootly component is connected in Superplane and the webhook is active. Superplane manages the webhook endpoint automatically — check the Superplane component settings to verify the connection status and that the correct incident events are selected.
Only timeline events with `kind: "event"` emit a trigger. System-generated events may use a different kind value. Also confirm any optional filters (severity, service, team, visibility) are not excluding the events you expect.
The integration uses your Rootly API credentials configured in Superplane. Confirm the credentials have not been revoked in Rootly. See the [Superplane Rootly component docs](https://docs.superplane.com/components/rootly/) for credential configuration steps.
Some Rootly accounts require a Sub-Status value when updating the incident status. If your update fails after a status change, set the Sub-Status field in the Update Incident action.
All configuration fields support Superplane's dynamic expression syntax. Check that expressions reference valid incident fields from the trigger payload and that the syntax is correct. Test with a real incident event to inspect the available data shape.
## Related Pages
Build native Rootly workflows alongside your Superplane automations.
The Rootly API reference — the same endpoints Superplane uses to take actions on incidents.
Full setup and configuration guide on the Superplane side.
# Swift SDK
Source: https://docs.rootly.com/integrations/swift-sdk
Swift client for the Rootly API, auto-generated with Apple's Swift OpenAPI Generator for incident, alert, and on-call automation on iOS and macOS.
The Rootly Swift SDK (`rootly-swift`) is a Swift client for the Rootly API, auto-generated from the OpenAPI specification using [Apple's Swift OpenAPI Generator](https://github.com/apple/swift-openapi-generator).
## Features
* **Auto-generated** — types and client code generated from the OpenAPI spec at build time
* **Swift-native** — uses structured concurrency with async/await
* **JSON:API compliant** — handles `application/vnd.api+json` content negotiation
* **Swift Package Manager** — simple dependency management
## Requirements
* Swift 6.0 or later
* Xcode 16+ or equivalent Swift toolchain
## Installation
Add the dependency to your `Package.swift`:
```swift theme={null}
dependencies: [
.package(url: "https://github.com/rootlyhq/rootly-swift.git", from: "1.0.0"),
]
```
Then add `Rootly` to your target dependencies:
```swift theme={null}
.target(
name: "YourTarget",
dependencies: [
.product(name: "Rootly", package: "rootly-swift"),
]
)
```
## Quick Start
The SDK provides a `makeClient` helper that configures the generated OpenAPI client with authentication and the default Rootly API base URL:
```swift theme={null}
import Rootly
// Uses https://api.rootly.com by default
let client = makeClient(token: "YOUR_API_TOKEN")
// Or specify a custom server URL
let client = makeClient(
token: "YOUR_API_TOKEN",
serverURL: URL(string: "https://your-instance.rootly.com")!
)
```
### Getting an API Key
1. Log in to your Rootly account
2. Navigate to **Settings** > **API Keys**
3. Create a new API key with the permissions you need
## Usage
### List Incidents
```swift theme={null}
let response = try await client.listIncidents()
switch response {
case .ok(let ok):
let incidents = try ok.body.applicationVnd_apiJson
for incident in incidents.data ?? [] {
print(incident.attributes?.title ?? "Untitled")
}
default:
print("Request failed")
}
```
### Filter Incidents
```swift theme={null}
let response = try await client.listIncidents(
query: .init(
filter_lbrack_status_rbrack_: "started",
filter_lbrack_severity_rbrack_: "sev0"
)
)
```
### Get a Single Incident
```swift theme={null}
let response = try await client.getIncident(
path: .init(id: .init(value1: "YOUR_INCIDENT_UUID"))
)
switch response {
case .ok(let ok):
let incident = try ok.body.applicationVnd_apiJson
print(incident.data?.attributes?.title ?? "")
default:
print("Not found")
}
```
### Create an Incident
```swift theme={null}
let response = try await client.createIncident(
body: .applicationVnd_apiJson(.init(
data: .init(
_type: .incidents,
attributes: .init(
title: "Database connection pool exhausted",
summary: "Primary database connection pool at 100% capacity",
kind: .normal,
severityId: "YOUR_SEVERITY_UUID"
)
)
))
)
switch response {
case .created(let created):
let incident = try created.body.applicationVnd_apiJson
print("Created: \(incident.data?.id ?? "")")
default:
print("Failed to create")
}
```
### Update an Incident
```swift theme={null}
let response = try await client.updateIncident(
path: .init(id: .init(value1: "YOUR_INCIDENT_UUID")),
body: .applicationVnd_apiJson(.init(
data: .init(
_type: .incidents,
attributes: .init(
status: "mitigated",
summary: "Connection pool scaled up, requests recovering"
)
)
))
)
```
### List Services
```swift theme={null}
let response = try await client.listServices()
switch response {
case .ok(let ok):
let services = try ok.body.applicationVnd_apiJson
for service in services.data ?? [] {
print(service.attributes?.name ?? "")
}
default:
break
}
```
## Configuration
### Custom Server URL
```swift theme={null}
let client = makeClient(
token: "YOUR_API_TOKEN",
serverURL: URL(string: "https://your-instance.rootly.com")!
)
```
## Feedback & Support
* **Source Code**: [GitHub Repository](https://github.com/rootlyhq/rootly-swift)
* **Issues**: [GitHub Issues](https://github.com/rootlyhq/rootly-swift/issues)
* **API Reference**: [Rootly API Docs](/api-reference/overview)
# Terraform
Source: https://docs.rootly.com/integrations/terraform
Manage Rootly resources using infrastructure as code with the official Terraform provider for services, severities, workflows, and more.
## Overview
The Rootly Terraform provider lets you manage your entire Rootly configuration as code — severities, services, workflows, on-call schedules, escalation policies, form fields, alert routes, and more. With over 200 resources and 59 data sources, virtually every Rootly configuration object can be declared, versioned, and reviewed through your existing IaC pipeline.
* **Provider**: [rootlyhq/rootly](https://registry.terraform.io/providers/rootlyhq/rootly/latest) on the Terraform Registry
* **Current version**: 5.17.2
* **Minimum Terraform version**: 1.0
* **Downloads**: 1.1M+
## Authentication
The provider authenticates using a Rootly API token. Generate one from **Account > API Tokens** in your Rootly dashboard.
You can supply credentials via the provider block or environment variables. The environment variable approach is recommended to avoid committing secrets.
**Environment variables (recommended):**
```bash theme={null}
export ROOTLY_API_TOKEN="your-api-token"
export ROOTLY_API_URL="https://api.rootly.com" # optional, defaults to https://api.rootly.com
```
**Provider block:**
```hcl theme={null}
provider "rootly" {
api_token = var.rootly_api_token # or set ROOTLY_API_TOKEN env var
api_host = "https://api.rootly.com" # optional
}
```
| Parameter | Env var | Required | Default |
| ----------- | ------------------ | ------------------------ | ------------------------ |
| `api_token` | `ROOTLY_API_TOKEN` | Yes (if env var not set) | — |
| `api_host` | `ROOTLY_API_URL` | No | `https://api.rootly.com` |
## Installation
Declare the provider in your Terraform configuration and run `terraform init`:
```hcl theme={null}
terraform {
required_providers {
rootly = {
source = "rootlyhq/rootly"
version = "~> 5.10"
}
}
}
provider "rootly" {
# Uses ROOTLY_API_TOKEN env var by default
}
```
## Supported Resources
The provider covers 200+ resources across all major Rootly configuration areas.
Manage the building blocks of incident response and on-call operations.
| Resource | Description |
| ------------------------------------- | ----------------------------------- |
| `rootly_severity` | Incident severity levels |
| `rootly_incident_type` | Incident types |
| `rootly_incident_role` | Incident roles and task assignments |
| `rootly_incident_sub_status` | Custom sub-statuses |
| `rootly_incident_permission_set` | Permission sets for incident fields |
| `rootly_cause` | Incident causes |
| `rootly_environment` | Environments |
| `rootly_on_call_role` | On-call roles |
| `rootly_schedule` | On-call schedules |
| `rootly_schedule_rotation` | Schedule rotations |
| `rootly_schedule_rotation_active_day` | Active days within rotations |
| `rootly_schedule_rotation_user` | Users assigned to rotations |
| `rootly_on_call_shadow` | Shadow assignments for learning |
| `rootly_override_shift` | Schedule override shifts |
| `rootly_escalation_policy` | Escalation policies |
| `rootly_escalation_level` | Escalation levels within a policy |
| `rootly_escalation_path` | Escalation paths |
| `rootly_team` | Teams |
Configure alert routing, sources, urgencies, and grouping rules.
| Resource | Description |
| --------------------------- | ------------------------------------ |
| `rootly_alerts_source` | Alert sources (inbound integrations) |
| `rootly_alert_route` | Alert routing rules |
| `rootly_alert_routing_rule` | Conditions within an alert route |
| `rootly_alert_group` | Alert grouping configuration |
| `rootly_alert_urgency` | Alert urgency levels |
| `rootly_alert_field` | Custom alert fields |
| `rootly_heartbeat` | Heartbeat monitors |
Automate incident response with workflows triggered by incidents, alerts, pulses, and more.
| Resource | Description |
| ---------------------------------------- | ----------------------------------------- |
| `rootly_workflow_incident` | Workflows triggered by incident events |
| `rootly_workflow_alert` | Workflows triggered by alert events |
| `rootly_workflow_pulse` | Workflows triggered by pulses |
| `rootly_workflow_post_mortem` | Workflows triggered by post-mortem events |
| `rootly_workflow_simple` | Simple scheduled or manual workflows |
| `rootly_workflow_group` | Workflow groups for organization |
| `rootly_workflow_action_item` | Action item automation within workflows |
| `rootly_workflow_custom_field_selection` | Custom field conditions on workflows |
| `rootly_workflow_form_field_condition` | Form field conditions on workflows |
**132 workflow task types** are available as individual resources, covering integrations with Slack, Jira, PagerDuty, Datadog, GitHub, Notion, and many more. See the [full resource list](https://registry.terraform.io/providers/rootlyhq/rootly/latest/docs) in the Terraform Registry.
Manage your service catalog, functionalities, and custom catalog entities.
| Resource | Description |
| ----------------------------------- | ---------------------------------------- |
| `rootly_service` | Services in your catalog |
| `rootly_functionality` | Functionalities |
| `rootly_catalog` | Custom catalogs |
| `rootly_catalog_entity` | Entities within a catalog |
| `rootly_catalog_property` | Properties on catalog entities |
| `rootly_catalog_checklist_template` | Checklist templates for catalog entities |
Declare form fields, options, and placement rules for incident and action item forms.
| Resource | Description |
| --------------------------------------- | -------------------------------------------- |
| `rootly_form_field` | Custom form fields |
| `rootly_form_field_option` | Options for multi-select and dropdown fields |
| `rootly_form_field_placement` | Field placement on incident forms |
| `rootly_form_field_placement_condition` | Conditions controlling field visibility |
| `rootly_form_field_position` | Field ordering within a form |
| `rootly_form_set` | Sets of form fields |
| `rootly_form_set_condition` | Conditions for form set activation |
| `rootly_custom_field` | Additional custom fields |
| `rootly_custom_field_option` | Options for custom fields |
| `rootly_custom_form` | Custom form configurations |
Manage retrospective templates and processes.
| Resource | Description |
| ----------------------------------------- | --------------------------------- |
| `rootly_post_mortem_template` | Post-mortem document templates |
| `rootly_retrospective_configuration` | Retrospective configuration |
| `rootly_retrospective_process` | Retrospective process definitions |
| `rootly_retrospective_process_group` | Process groups |
| `rootly_retrospective_process_group_step` | Steps within process groups |
| `rootly_retrospective_step` | Individual retrospective steps |
Manage status pages and their templates.
| Resource | Description |
| ----------------------------- | ---------------------------- |
| `rootly_status_page` | Status pages |
| `rootly_status_page_template` | Status page update templates |
Manage communication templates, channels, and RBAC roles.
| Resource | Description |
| -------------------------------- | ------------------------------- |
| `rootly_role` | RBAC roles |
| `rootly_authorization` | Role-based authorizations |
| `rootly_communications_template` | Communication message templates |
| `rootly_communications_type` | Communication types |
| `rootly_communications_stage` | Communication stages |
| `rootly_communications_group` | Communication groups |
| `rootly_webhooks_endpoint` | Outbound webhook endpoints |
| `rootly_secret` | Secrets for use in workflows |
| `rootly_dashboard` | Dashboards |
| `rootly_dashboard_panel` | Dashboard panels |
| `rootly_playbook` | Playbooks |
| `rootly_playbook_task` | Tasks within a playbook |
| `rootly_live_call_router` | Live call router configuration |
## Data Sources
59 data sources let you reference existing Rootly resources in your configuration without managing them through Terraform.
```hcl theme={null}
# Look up an existing service
data "rootly_service" "payments" {
slug = "payments"
}
# Look up an existing team
data "rootly_team" "platform" {
slug = "platform"
}
# Reference them in a resource
resource "rootly_escalation_policy" "platform" {
name = "Platform On-Call"
team_id = data.rootly_team.platform.id
}
```
Available data sources include: `service`, `services`, `team`, `teams`, `severity`, `severities`, `environment`, `environments`, `functionality`, `functionalities`, `schedule`, `user`, `role`, `incident`, `workflow`, `alert_route`, `escalation_policy`, `on_call_role`, and more.
## Examples
### Severities and services
```hcl theme={null}
resource "rootly_severity" "sev0" {
name = "SEV0"
color = "#FF0000"
}
resource "rootly_severity" "sev1" {
name = "SEV1"
color = "#FFA500"
}
resource "rootly_service" "payments_prod" {
name = "payments-prod"
color = "#800080"
}
```
### On-call schedule with rotation
```hcl theme={null}
resource "rootly_schedule" "platform_oncall" {
name = "Platform On-Call"
}
resource "rootly_schedule_rotation" "weekly" {
schedule_id = rootly_schedule.platform_oncall.id
name = "Weekly Rotation"
}
resource "rootly_schedule_rotation_user" "alice" {
schedule_rotation_id = rootly_schedule_rotation.weekly.id
user_id = "alice-user-id"
position = 0
}
```
### Workflow with Jira task
```hcl theme={null}
resource "rootly_workflow_incident" "jira" {
name = "Create a Jira Issue"
description = "Open Jira ticket whenever incident starts"
trigger_params {
triggers = ["incident_created"]
incident_condition_kind = "IS"
incident_kinds = ["normal"]
incident_condition_status = "IS"
incident_statuses = ["started"]
}
enabled = true
}
resource "rootly_workflow_task_create_jira_issue" "jira" {
workflow_id = rootly_workflow_incident.jira.id
task_params {
title = "{{ incident.title }}"
description = "{{ incident.summary }}"
project_key = "ROOT"
issue_type = {
id = "10001"
name = "Task"
}
status = {
id = "10000"
name = "To Do"
}
labels = "{{ incident.environment_slugs | concat: incident.service_slugs | join: \",\" }}"
}
}
```
### Custom form field
```hcl theme={null}
resource "rootly_form_field" "regions_affected" {
name = "Regions affected"
kind = "custom"
input_kind = "multi_select"
shown = ["web_new_incident_form", "web_update_incident_form"]
required = ["web_new_incident_form"]
}
resource "rootly_form_field_option" "us_east" {
form_field_id = rootly_form_field.regions_affected.id
value = "US East"
}
resource "rootly_form_field_option" "eu_west" {
form_field_id = rootly_form_field.regions_affected.id
value = "EU West"
}
```
### Custom field on an action item form
Custom fields can also be collected on the action item forms in both the web app and Slack. Show the field on the `web_action_item_form` and `slack_action_item_form` forms with `rootly_form_field`, then order it on each form with `rootly_form_field_position`.
The `web_action_item_form` and `slack_action_item_form` form keys are accepted by `rootly_form_field_position` in provider version **5.17.2 and later**. Set `version = ">= 5.17.2"` in your `required_providers` block so the constraint enforces the actual minimum (`~> 5.17` still allows 5.17.0 / 5.17.1, which will fail).
```hcl theme={null}
# 1. Define the custom field and show it on the action item forms
resource "rootly_form_field" "root_cause_category" {
name = "Root cause category"
kind = "custom"
input_kind = "select"
shown = ["web_action_item_form", "slack_action_item_form"]
required = ["web_action_item_form"]
}
resource "rootly_form_field_option" "code" {
form_field_id = rootly_form_field.root_cause_category.id
value = "Code"
}
resource "rootly_form_field_option" "infrastructure" {
form_field_id = rootly_form_field.root_cause_category.id
value = "Infrastructure"
}
# 2. Order the field on the web and Slack action item forms
resource "rootly_form_field_position" "root_cause_web" {
form_field_id = rootly_form_field.root_cause_category.id
form = "web_action_item_form"
position = 1
}
resource "rootly_form_field_position" "root_cause_slack" {
form_field_id = rootly_form_field.root_cause_category.id
form = "slack_action_item_form"
position = 1
}
```
## Importing Existing Resources
Resources already configured in Rootly can be imported into Terraform state without recreating them:
```bash theme={null}
terraform import rootly_severity.sev0
terraform import rootly_service.payments_prod
terraform import rootly_workflow_incident.jira
```
Resource IDs can be found in the Rootly API or in the URL when viewing a resource in the dashboard.
## Related Pages
Manage Rootly resources with Pulumi using JavaScript or TypeScript.
Explore the full Rootly REST API that powers the Terraform provider.
# Trello
Source: https://docs.rootly.com/integrations/trello
Connect Trello to Rootly to automatically create and update cards from incidents, action items, and follow-up workflows.
The Trello integration connects Rootly with your Trello account so teams can automatically create and update cards through Genius workflows. Cards can be placed on any board and list, assigned labels, and given due dates — all driven by incident data.
With the Trello integration, you can:
* Automatically create Trello cards when incidents are declared or reach a certain state
* Update card title, description, labels, due date, and position as incidents evolve
* Move cards between lists and boards as incident status changes
* Archive cards automatically when incidents are resolved
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A Trello account with access to the boards you want to use
Rootly recommends installing with a dedicated Trello service account so the integration does not break if an individual user leaves your organization.
## Installation
Navigate to the integrations page in Rootly and select **Trello**.
You will be redirected to Trello to sign in and grant Rootly permission to access your account.
Once authorized, the installation is complete.
After authorization, the **Create a Trello Card** and **Update a Trello Card** workflow actions are available in your Genius workflows.
## Workflow Actions
The Trello integration provides two workflow actions for managing cards from Rootly incidents. If you are unfamiliar with how Genius workflows work, visit the [Workflows](/workflows/workflows) documentation first.
Trello organizes content in a hierarchy: **Boards → Lists → Cards**. When configuring workflow actions, select the board first, then the list within that board.
### Create a Trello Card
This action creates a new card in a specified Trello list.
| Field | Description | Required |
| --------------- | ----------------------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Board** | Trello board where the card will be created | Yes |
| **List** | List within the selected board | Yes |
| **Title** | Card title. Defaults to `{{ incident.title }}`. Supports Liquid | Yes |
| **Description** | Card description. Supports Liquid | |
| **Labels** | One or more Trello labels to apply. Labels are loaded from the selected board | |
| **Due Date** | Card due date. Supports Liquid | |
Use the [Incident Variable Explorer](https://rootly.com/account/help/liquid-explorer) to preview what Liquid variables return for your incidents.
### Update a Trello Card
This action updates an existing Trello card.
When a **Create a Trello Card** action runs, Rootly stores the resulting card ID on the incident record. Reference it in subsequent update actions using Liquid variables.
| Field | Description | Required |
| --------------- | -------------------------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Card ID** | Trello card ID to update. Supports Liquid | Yes |
| **Board** | Board to move the card to. Leave blank to keep on current board | |
| **List** | List to move the card to. Leave blank to keep in current list | |
| **Title** | Updated card title. Supports Liquid. Leave blank to keep existing | |
| **Description** | Updated card description. Supports Liquid | |
| **Labels** | Updated labels. Filtered by the selected board | |
| **Due Date** | Updated due date. Supports Liquid | |
| **Archivation** | Whether to archive the card. **Auto** mirrors the incident or action item status | Yes |
## Troubleshooting
Rootly loads boards and lists from your authorized Trello account. If boards you expect to see are missing, confirm the authorizing user has access to those boards. Re-authenticating the integration may refresh the available list.
Labels in Trello are scoped to a specific board. Select a board first — labels will load automatically based on the selected board.
## Uninstall
To remove the Trello integration, open the integrations panel in Rootly and select **Configure > Delete**.
## Related Resources
* [Workflows](/workflows/workflows)
* [Liquid templating](/liquid/liquid)
* [Integrations overview](/integrations/overview)
# Terminal UI (TUI)
Source: https://docs.rootly.com/integrations/tui
View and manage Rootly incidents and alerts from your terminal with the Rootly TUI application, a fast keyboard-driven interface for on-call responders.
## Overview
The Rootly TUI is a terminal-based interface for monitoring and triaging incidents and alerts without leaving your command line. Built for engineers who prefer keyboard-driven workflows, it connects directly to the Rootly API using your API key.
Browse incidents and alerts with full detail views — severity, status, timeline, roles, labels, and more.
Vim-style navigation (`j`/`k`) and intuitive shortcuts for fast, mouse-free operation.
Available in 12 languages including Spanish, French, Japanese, Arabic, and more.
Fully open source at [rootlyhq/rootly-tui](https://github.com/rootlyhq/rootly-tui). Contributions welcome.
## Requirements
* Terminal with 256-color support
* Minimum terminal size: 80×24
* A Rootly API key (generate one from **Settings → API Keys**)
## Installation
```bash Homebrew (macOS/Linux) theme={null}
brew install rootlyhq/tap/rootly-tui
```
```bash Go theme={null}
go install github.com/rootlyhq/rootly-tui/cmd/rootly-tui@latest
```
```bash Build from source theme={null}
git clone https://github.com/rootlyhq/rootly-tui.git
cd rootly-tui && make build && ./bin/rootly-tui
```
Or download a pre-built binary from [GitHub Releases](https://github.com/rootlyhq/rootly-tui/releases).
## Quick Start
```bash theme={null}
rootly-tui
```
On first launch, you'll be prompted to configure:
| Setting | Description | Default |
| ---------------- | ------------------------------------------------- | ---------------- |
| **API Endpoint** | Usually `api.rootly.com`, or your custom endpoint | `api.rootly.com` |
| **API Key** | Your Rootly API key | — |
| **Timezone** | Timezone for displaying timestamps | `UTC` |
| **Language** | Display language | `en_US` |
| **Layout** | Panel layout: `horizontal` or `vertical` | `horizontal` |
To update settings later, press `s` in the app.
Use `Tab` to switch between the **Incidents** and **Alerts** tabs. Press `Enter` on any item to load its full details.
## Keyboard Shortcuts
### Navigation
| Key | Action |
| --------- | ---------------------------------------- |
| `j` / `↓` | Move cursor down |
| `k` / `↑` | Move cursor up |
| `g` | Go to first item |
| `G` | Go to last item |
| `[` | Previous page |
| `]` | Next page |
| `Tab` | Switch between Incidents and Alerts tabs |
### Actions
| Key | Action |
| ------- | -------------------------------- |
| `Enter` | View details / focus detail pane |
| `o` | Open in browser |
| `c` | Copy to clipboard |
| `r` | Refresh data |
| `S` | Sort menu |
### General
| Key | Action |
| ---------------------- | --------------- |
| `l` | View debug logs |
| `s` | Open settings |
| `A` | About |
| `?` | Show help |
| `q` / `Esc` / `Ctrl+C` | Quit |
## Command Line Options
| Flag | Description |
| -------------- | ------------------------------ |
| `--debug` | Enable debug logging to stderr |
| `--log ` | Write debug logs to a file |
| `--version` | Show version information |
### Debug Mode
```bash theme={null}
# Log to stderr
rootly-tui --debug
# Log to file
rootly-tui --log debug.log
# Log to stderr, redirect to file
rootly-tui --debug 2> debug.log
```
Press `l` in the app to open the built-in log viewer.
## Configuration File
Settings are stored at `~/.rootly-tui/config.yaml`:
```yaml theme={null}
api_key: "your-api-key"
endpoint: "api.rootly.com"
timezone: "UTC"
language: "en_US"
layout: "horizontal"
```
## Supported Languages
English (US/GB) · Spanish · French · German · Chinese (Simplified) · Japanese · Russian · Portuguese (Brazilian) · Hindi · Arabic · Bengali
## Feedback & Support
* **Bug reports & feature requests**: [GitHub Issues](https://github.com/rootlyhq/rootly-tui/issues)
* **Source code**: [github.com/rootlyhq/rootly-tui](https://github.com/rootlyhq/rootly-tui)
## Related resources
* [CLI](/integrations/cli)
* [Setup Wizard](/integrations/rootly-wizard)
* [Open Source at Rootly](/open-source/overview)
# Twitter / X
Source: https://docs.rootly.com/integrations/twitter
Post incident updates to Twitter directly from Rootly workflows or the incident timeline to keep customers and stakeholders informed in real time.
## Overview
Rootly's Twitter integration lets your team publish incident updates to your organization's Twitter/X account without leaving the incident response flow. You can tweet via a workflow action or directly from the incident timeline.
Automatically post status updates to Twitter at any point in an incident workflow — on creation, escalation, or resolution.
Share a timeline entry directly to Twitter by setting its visibility to **incident responders + private status page + twitter**.
## Before You Begin
* You must be a Rootly admin to set up the integration
* You need access to the Twitter/X account you want to post from
Use a **dedicated service account** rather than a personal Twitter account. If the user who connected the integration leaves or loses access, the integration will stop working.
## Installation
Connecting Twitter to Rootly is a single OAuth step — no API keys to copy.
Go to **Configuration → Integrations**, find **Twitter**, and click **Setup**.
You'll be redirected to Twitter to sign in and grant Rootly permission to post on your behalf. After authorizing, you'll be returned to Rootly and the integration will show as connected under your account's `@handle`.
## Posting from the Incident Timeline
You can tweet a timeline entry directly from the incident by changing the visibility of the update.
When adding a comment to the incident timeline, open the visibility dropdown and select **incident responders + private status page + twitter**. Rootly will post the entry as a tweet on your connected account.
## Workflow Action
### Tweet a Message
Posts a tweet to your connected Twitter account from a workflow.
The text content of the tweet. Supports [Liquid variables](/liquid/incident-variables) — for example, `{{ incident.title }}` or `{{ incident.status }}`. Twitter's character limit applies.
Use Liquid to make tweets dynamic — for example: `"Incident resolved: {{ incident.title }}. Thanks for your patience."` will automatically fill in the incident title at runtime.
## Uninstall
To remove the Twitter integration:
1. Go to **Configuration → Integrations** and find **Twitter**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
## Frequently Asked Questions
No. Rootly supports one connected Twitter account per organization. To switch accounts, disconnect the current integration and reconnect with the new account.
Rootly automatically refreshes the OAuth token in the background. If refresh fails — for example, if the connected account's permissions were revoked — tweets will fail until you reconnect. This is why a dedicated service account is recommended.
Yes — Twitter's standard 280-character limit applies. Rootly does not truncate the message automatically, so keep your Liquid templates short enough to stay within the limit.
Not currently. The workflow action supports text-only tweets.
# TypeScript SDK
Source: https://docs.rootly.com/integrations/typescript-sdk
Type-safe TypeScript client for the Rootly API, powered by openapi-typescript and openapi-fetch, for incident, alert, and on-call automation in Node.js.
The Rootly TypeScript SDK (`@rootly/ts`) is a type-safe client for the Rootly API. Types are generated directly from the OpenAPI specification, giving you full autocomplete and compile-time safety for every endpoint, parameter, and response.
## Features
* **Zero runtime overhead** — types are generated at build time, not runtime
* **Full type safety** — every endpoint, parameter, and response is typed from the OpenAPI spec
* **Tiny footprint** — `openapi-fetch` is \~6 KB and wraps the native `fetch`
* **ESM and CommonJS** — works in Node.js, Deno, Bun, and modern bundlers
* **Typed errors** — API error responses are typed per status code
## Requirements
Any JavaScript runtime with a native `fetch` implementation:
* Node.js 20+
* Deno, Bun, or modern bundlers (Vite, webpack, esbuild, etc.)
* Modern browsers
On older Node.js versions, supply a `fetch` polyfill via the `fetch` option (see [Custom Fetch](#custom-fetch)).
## Installation
```bash theme={null}
npm install @rootly/ts
```
```bash theme={null}
yarn add @rootly/ts
```
```bash theme={null}
pnpm add @rootly/ts
```
The package ships both ESM and CommonJS builds. In a CommonJS project, use `require`:
```javascript theme={null}
const { RootlyClient } = require("@rootly/ts");
```
## Quick Start
```typescript theme={null}
import { RootlyClient } from "@rootly/ts";
const rootly = new RootlyClient({
token: process.env.ROOTLY_API_TOKEN!,
});
```
### Getting an API Key
1. Log in to your Rootly account
2. Navigate to **Settings** > **API Keys**
3. Create a new API key with the permissions you need
## Usage
### List Incidents
```typescript theme={null}
const { data, error } = await rootly.client.GET("/v1/incidents", {
params: {
query: {
"page[number]": 1,
"page[size]": 10,
"filter[status]": "started",
},
},
});
```
### Get an Incident
```typescript theme={null}
const { data, error } = await rootly.client.GET("/v1/incidents/{id}", {
params: { path: { id: "abc123" } },
});
```
### Create an Incident
```typescript theme={null}
const { data, error } = await rootly.client.POST("/v1/incidents", {
body: {
data: {
type: "incidents",
attributes: {
title: "Service degradation",
kind: "normal",
summary: "Users are experiencing elevated latency",
severity_id: "sev-1",
},
},
},
});
```
### Update an Incident
```typescript theme={null}
const { data, error } = await rootly.client.PATCH("/v1/incidents/{id}", {
params: { path: { id: "abc123" } },
body: {
data: {
type: "incidents",
attributes: {
summary: "Root cause identified",
},
},
},
});
```
### Error Handling
```typescript theme={null}
async function fetchIncident(id: string) {
const { data, error } = await rootly.client.GET("/v1/incidents/{id}", {
params: { path: { id } },
});
if (error) {
console.error("Request failed:", error);
throw error;
}
return data;
}
```
`error` is typed per status code (for example, 401, 404), and `data` is typed with the endpoint's response schema.
## Using Types
Import generated schemas directly for DTOs, validation, or UI code:
```typescript theme={null}
import type { components } from "@rootly/ts";
type Incident = components["schemas"]["incident"];
type IncidentResponse = components["schemas"]["incident_response"];
type NewIncident = components["schemas"]["new_incident"];
type Service = components["schemas"]["service"];
type ErrorsList = components["schemas"]["errors_list"];
```
## Configuration
### Custom Base URL
```typescript theme={null}
const rootly = new RootlyClient({
token: "your-token",
baseUrl: "https://custom.rootly.com",
});
```
### Custom Fetch
Pass a custom `fetch` implementation for testing, retries, or logging:
```typescript theme={null}
const rootly = new RootlyClient({
token: "your-token",
fetch: customFetchImplementation,
});
```
## Advanced Usage
For direct access to the underlying `openapi-fetch` client with full type inference and middleware support:
```typescript theme={null}
import { createClient, createAuthMiddleware, type paths } from "@rootly/ts";
const client = createClient({
baseUrl: "https://api.rootly.com",
});
client.use(createAuthMiddleware("your-token"));
```
## Feedback & Support
* **Package**: [@rootly/ts on npm](https://www.npmjs.com/package/@rootly/ts)
* **Source Code**: [GitHub Repository](https://github.com/rootlyhq/rootly-ts)
* **Issues**: [GitHub Issues](https://github.com/rootlyhq/rootly-ts/issues)
## Related resources
* [Rust SDK](/integrations/rust-sdk)
* [Python SDK](/integrations/python-sdk)
* [Swift SDK](/integrations/swift-sdk)
# VictorOps (Splunk On-Call)
Source: https://docs.rootly.com/integrations/victor-ops
Connect VictorOps (Splunk On-Call) to Rootly for API-based escalation, optional inbound webhooks, linked incident workflows, and Slack-based paging.
## Introduction
The VictorOps integration connects Rootly with Splunk On-Call so teams can escalate incidents into VictorOps, receive supported VictorOps webhook activity in Rootly, and keep incident response workflows coordinated across both systems.
This integration is a strong fit for teams that already use VictorOps for alerting or on-call response and want Rootly to act as the central place for incident coordination and automation.
With the VictorOps integration, you can:
* Connect Rootly to VictorOps with API credentials
* Receive supported VictorOps webhook events in Rootly
* Create and update VictorOps incidents from Rootly escalation flows
* Resolve linked VictorOps incidents from Rootly
* Page VictorOps teams from Slack when the Slack integration is enabled
## Before You Begin
Before installing the integration, make sure you have:
* A Rootly account with permission to manage integrations
* A VictorOps (Splunk On-Call) account with access to API credentials
* Access to create outgoing webhooks or REST hook integrations in VictorOps
* The VictorOps teams you want Rootly to page or sync with
Rootly uses two separate credential types for this integration:
* The **VictorOps API ID and API Key** are used for Rootly-to-VictorOps API requests
* The **Rootly webhook secret** is used when VictorOps sends webhook events into Rootly
## Install the VictorOps Integration in Rootly
Go to the integrations page in Rootly and choose **VictorOps (Splunk On-Call)**.
Rootly recommends connecting VictorOps with a dedicated service account so the integration does not break if an individual user leaves your organization.
## Configure API Access in VictorOps
Rootly uses VictorOps API credentials to create incidents, reroute responders, and resolve linked incidents.
In the VictorOps portal, locate the API credentials you will use for the Rootly integration.
Paste the VictorOps API ID and API Key into the VictorOps integration settings in Rootly and save the integration.
## Configure VictorOps Webhooks
VictorOps can optionally send webhook events into Rootly so Rootly can create alerts and add linked incident activity.
In VictorOps, configure an outgoing webhook or REST hook for the integration.
Copy the webhook URL shown in Rootly and use it when creating the VictorOps webhook.
Rootly typically expects the webhook secret to be included as a query parameter on the URL it provides, such as `?secret=...`, unless the Rootly UI shows a different format for your workspace.
## Supported VictorOps Webhook Behavior
Rootly processes VictorOps webhooks in these cases:
* The notification type is **unset**, which is the typical new-alert style payload
* The notification type is **`ACKNOWLEDGEMENT`**
* The notification type is **`RECOVERY`**
Other notification types are ignored.
In general:
* Unset notification-type events can create Rootly alerts
* `ACKNOWLEDGEMENT` events can add linked incident activity in Rootly
* `RECOVERY` events can add linked incident activity in Rootly
If an incoming VictorOps event is already tied to a synced Rootly incident, Rootly may skip creating a duplicate alert.
## Escalate to VictorOps from Rootly
Rootly can create and update VictorOps incidents when a Rootly incident needs escalation.
This is commonly used when:
* A Rootly incident needs to notify a VictorOps team
* An escalation action should create a VictorOps incident
* A Slack-driven incident flow needs to page VictorOps responders
When Rootly escalates into VictorOps, it stores the linked VictorOps incident information on the Rootly incident for later synchronization.
## Reroute Incidents
Rootly can add responders to an existing VictorOps incident without creating a new one. This is useful when an incident is already active in VictorOps and you need to bring in additional teams or users.
You can configure this through a workflow action targeting the linked VictorOps incident. Rootly will route the incident to the specified users or teams using the VictorOps reroute API.
## Default Workflows
When the VictorOps integration is connected, Rootly can create default workflows to support common VictorOps actions.
These workflows typically include:
* Adding VictorOps on-call responders into the incident workflow
* Automatically resolving linked VictorOps incidents when the Rootly incident is resolved
Review these workflows after installation so they match your team’s escalation process.
## Import Teams
If your VictorOps migration flow is enabled in your workspace, you can import VictorOps teams into Rootly teams as part of your setup.
This is useful when you want to align Rootly team structure with your existing VictorOps configuration.
## Paging from Slack
If the Slack integration is enabled, responders can page VictorOps teams directly from Slack.
Use the Slack integration to trigger VictorOps paging directly from the incident workflow in Slack.
## Troubleshooting
The most common cause is an incorrect or missing Rootly webhook secret. Rootly uses that secret to authenticate incoming VictorOps webhook events.
Confirm that VictorOps is sending one of the supported webhook notification types and that the webhook is pointed at the correct Rootly URL. Unsupported notification types are ignored.
If the VictorOps event is already associated with a synced Rootly incident, Rootly may skip creating a duplicate alert and instead add linked incident activity.
Check your VictorOps API ID and API Key, and confirm the integration still has valid access. Incoming webhook-created alerts are also subject to your Rootly alert limits.
## Related resources
* [Opsgenie](/integrations/opsgenie)
* [PagerTree](/integrations/pager-tree)
# IBM watsonx
Source: https://docs.rootly.com/integrations/watsonx
Connect IBM watsonx.ai to Rootly to power incident summaries, alert summaries, and AI text editing with foundation models in your IBM Cloud region.
## Overview
IBM watsonx.ai hosts foundation models in your IBM Cloud account, in a region you control, with enterprise auth and audit. Connect a watsonx project to Rootly and the same AI features that run on OpenAI or Anthropic — incident summaries, alert summaries, text editor, title generation — route through your watsonx project instead. Your incident data and AI prompts stay inside IBM Cloud's regional boundary the entire time.
The integration uses an IBM Cloud API key plus a regional inference endpoint. Rootly exchanges the API key for IAM bearer tokens automatically and refreshes them as needed, so the customer-side configuration is just two fields: region and key.
Six IBM Cloud regions available (Dallas, Frankfurt, London, Tokyo, Sydney, Toronto) so inference happens in the jurisdiction your compliance team approved.
Choose any foundation model your watsonx project has access to — Granite, Llama variants, and others — pulled live from your project at configuration time.
Drives incident summarization, alert summarization, the in-app text editor, and incident title generation when WatsonX is the active provider.
IBM Cloud API keys exchanged for short-lived IAM bearer tokens. Rootly handles the token refresh dance; you never paste a long-lived bearer.
***
## Before You Begin
**You'll need access to both sides of the connection.**
* **In IBM Cloud** — permission to create an API key under your IBM Cloud account and a watsonx.ai project the API key has access to. Most enterprises require IAM access via a watsonx-specific role.
* **In Rootly** — an admin role so you can reach **Configuration → Integrations** and complete the WatsonX setup.
If you're evaluating IBM watsonx for the first time, IBM's [Quick start guide](https://www.ibm.com/watsonx/developer/get-started/quick-start/) walks through provisioning a watsonx instance and creating your first project before you reach the credential step.
***
## Generate Your IBM watsonx API Key
The vendor-side setup happens in IBM Cloud. Refer to [IBM's API key documentation](https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-credentials.html) for the latest UI specifics; the high-level flow is below.
Sign into IBM Cloud and navigate to **Manage → Access (IAM) → API keys**. Click **Create**.
Name the key something descriptive (`rootly-watsonx-production` works well). Choose an account-level or service-ID-scoped key based on your security policy. Click **Create**.
IBM Cloud shows the API key value **once**. Copy it now and store it in your secrets manager — you cannot retrieve it later, only revoke and reissue.
Open the watsonx.ai project Rootly should use, go to **Manage → Access control**, and confirm the IBM Cloud identity tied to the API key has at least **Editor** access to the project (Viewer is insufficient for inference calls).
Confirm which IBM Cloud region hosts your watsonx project. Rootly supports the six watsonx.ai regions — Dallas (`us-south`), Frankfurt (`eu-de`), London (`eu-gb`), Tokyo (`jp-tok`), Sydney (`au-syd`), and Toronto (`ca-tor`). The region you pick in Rootly must match the project's region exactly.
***
## Connect WatsonX to Rootly
With the API key in hand, the Rootly side is two fields and a save.
In Rootly, go to **Configuration → Integrations** and locate **WatsonX**. Click **Setup**.
Select the IBM Cloud region from the **Host** dropdown:
* `us-south.ml.cloud.ibm.com` — Dallas
* `ca-tor.ml.cloud.ibm.com` — Toronto
* `eu-de.ml.cloud.ibm.com` — Frankfurt
* `eu-gb.ml.cloud.ibm.com` — London
* `jp-tok.ml.cloud.ibm.com` — Tokyo
* `au-syd.ml.cloud.ibm.com` — Sydney
Pick the region that matches your watsonx.ai project. Inference requests route to this regional endpoint; data residency follows.
Paste the IBM Cloud API key into the **API Key** field. The value is stored encrypted at rest; Rootly exchanges it for short-lived IAM bearer tokens on each request and refreshes them automatically.
Click **Save**. Rootly tests the credentials against the regional endpoint immediately — a successful save confirms the API key authenticates against IAM and the watsonx project is reachable.
***
## Configuration Reference
IBM Cloud region for inference. Must match the region of the watsonx project the API key has access to.
Valid values: `us-south.ml.cloud.ibm.com`, `eu-de.ml.cloud.ibm.com`, `eu-gb.ml.cloud.ibm.com`, `jp-tok.ml.cloud.ibm.com`, `au-syd.ml.cloud.ibm.com`, `ca-tor.ml.cloud.ibm.com`.
IBM Cloud API key with at least Editor access to the watsonx.ai project. Stored encrypted at rest. Rotated by revoking the key in IBM Cloud and pasting a new one here.
The watsonx model Rootly invokes for AI tasks. Rootly defaults to a Llama variant but exposes any foundation model your watsonx project lists. Configurable per AI feature; the model list updates from your project on each Rootly configuration load.
***
## AI Features Powered by WatsonX
Once WatsonX is connected and enabled as the active AI provider, it drives the following Rootly features:
Auto-generated summaries of incident channels, timelines, and key events for retrospectives and stakeholder updates.
Condensed, plain-English versions of monitoring alert payloads so responders triage faster.
The in-app text editor's AI actions (rewrite, expand, simplify, tone-shift) call watsonx instead of the default provider.
Suggested incident titles based on the triggering alert and channel context.
Switching the active AI provider — between watsonx, OpenAI, Anthropic, and others — is a per-team configuration. WatsonX being connected doesn't automatically route every team's AI features through it. Contact Rootly support or your account team to activate WatsonX for specific teams or organization-wide.
***
## Selecting a Foundation Model
Rootly pulls the list of available foundation models live from your watsonx project. Whatever models your IBM Cloud identity has access to — IBM Granite, Meta Llama variants, third-party models published in watsonx, custom-tuned models — appear in the selector when configuring AI features.
Default model behavior:
* **Out of the box**, Rootly invokes a recent instruction-tuned Llama variant suitable for summarization and short-form generation
* **To override**, contact your Rootly account team — model selection is managed via a server-side configuration that maps each AI task type to a specific model ID
* **Model availability** depends on your IBM Cloud region; not all foundation models are available in every region
Refer to IBM's [foundation models documentation](https://www.ibm.com/products/watsonx-ai/foundation-models) for the current list of supported models and their regional availability.
***
## Test the Integration
After saving the WatsonX settings, verify end-to-end inference works.
Open any active incident and use the AI text editor (rewrite or summarize), or open the AI summary panel. If WatsonX is the active provider for your team, the request routes through your IBM Cloud project.
The AI response should appear within a few seconds. If it doesn't, see [Troubleshooting](#troubleshooting) below.
Optional — open IBM Cloud's Activity Tracker for your watsonx project to confirm the inference request arrived from Rootly and which foundation model it invoked. Useful for capacity planning and cost attribution.
A successful AI response in Rootly plus the corresponding inference event in IBM Cloud's Activity Tracker confirms WatsonX is wired correctly. From here, broaden the WatsonX rollout to additional teams as needed.
***
## Troubleshooting
The API key is invalid, expired, or doesn't have access to the chosen region's watsonx project. Confirm:
* The key value was copied without surrounding whitespace
* The IBM Cloud identity attached to the key has at least Editor access to the watsonx project in the selected region
* The key hasn't been revoked in IBM Cloud's API keys panel
Most common causes:
* The selected region's watsonx endpoint is throttling — check IBM Cloud's status page for region-specific incidents
* The foundation model selected isn't available in your region — switch to a model that lists your region in IBM's availability matrix
* Your IBM Cloud plan's monthly tokens-per-minute quota is exhausted — review usage in IBM Cloud and consider upgrading
The API key authenticates but the project has no models accessible to that identity. Open the watsonx project in IBM Cloud and confirm at least one foundation model is associated with the project under **Manage → Foundation models**. Refresh the Rootly WatsonX settings page after granting access.
Provider routing is per-team and managed server-side. Connecting WatsonX makes it available; activating it for specific teams or org-wide requires a Rootly account team change. Reach out to support to flip the routing.
The API key authenticated, but the IBM Cloud identity lacks permission for the specific watsonx operation. In IBM Cloud IAM, confirm the identity has the **watsonx.ai Service** access policy plus project-level Editor access. IBM's IAM separates platform-level and service-level permissions; both are required.
Revoke the existing key in IBM Cloud's API keys panel, create a new one with the same scope, and paste the new value into Rootly's WatsonX settings. The previous key continues to work in Rootly until you save the new value, then it's immediately replaced.
***
## Frequently Asked Questions
All three power the same AI features (incident summaries, alert summaries, text editor, title generation). WatsonX is the right choice when your security or compliance posture requires inference inside IBM Cloud's regional boundary, or when you've already committed to IBM Cloud for other workloads. OpenAI and Anthropic are simpler to set up but route data through their own hosted endpoints.
One watsonx project per Rootly organization. To use multiple regions, pick the one your primary compliance requirements demand and use that project across your watsonx workloads.
Inference requests from Rootly to watsonx travel over TLS to the regional endpoint you chose. The prompt and response are processed by IBM Cloud's watsonx service in that region; no data routes outside IBM Cloud during inference. Rootly stores the response back into the incident or alert record.
Yes, provided the model is published in your watsonx project and accessible to the IBM Cloud identity behind the API key. Contact your Rootly account team to set the custom model as the active model for specific AI tasks.
Inference cost is billed by IBM Cloud based on tokens consumed per foundation model. Rootly doesn't add a markup. Review IBM Cloud's watsonx.ai pricing for current per-model rates.
***
## Next Steps
Alternate AI provider — Claude models hosted by Anthropic, no IBM Cloud account required.
Alternate AI provider — GPT models hosted by OpenAI, simpler setup but no regional control.
Enterprise-hosted GPT models inside your Azure tenancy if you're already on Microsoft Cloud.
Control which users and roles can configure and trigger AI features.
# Webex
Source: https://docs.rootly.com/integrations/webex/webex
Connect Webex to Rootly to automatically create a meeting bridge for each incident and post the link into the incident's Slack channel.
Rootly's Webex integration automatically creates a dedicated meeting bridge for each incident so responders can jump into a call without manual setup. When an incident is declared, a workflow action spins up a Webex meeting and posts the link directly into the incident's Slack channel.
One Webex meeting per incident, created the moment the workflow triggers.
Set titles using Liquid variables like `{{ incident.title }}` or `{{ incident.severity }}`.
The meeting link is automatically posted to the incident's Slack channel.
Rootly generates a secure password for each meeting automatically.
## Before You Begin
* You must have a Webex account (a service account is recommended)
* You must be a Rootly admin to install the integration
* The Slack integration should already be configured if you want meeting links posted to incident channels
Rootly recommends installing with a **service account** (for example, `incidents@yourcompany.com`) rather than a personal account. This ensures the integration stays active if the installing user leaves the company.
## Installation
In Rootly, go to **Configuration → Integrations** and find **Webex**. Click **Setup**.
You'll be redirected to Webex. Sign in with your Webex account (or create one), then click **Allow** to grant Rootly access.
You'll be redirected back to Rootly. The integration will show as **Connected**.
## Workflow Actions
The Webex integration unlocks a workflow action that automatically creates a Webex meeting for each incident. If you're unfamiliar with how workflows function, see the [Workflows](/workflows/workflows) documentation first.
### Create Webex Meeting
This action creates a Webex meeting link for a specific incident.
Rootly enforces one Webex meeting per incident. If this action runs again for the same incident, it will be skipped.
The title of the Webex meeting. Defaults to `{{ incident.title }}`. Supports [Liquid variables](/liquid/incident-variables).
The meeting password. Leave blank to have Rootly generate a secure password automatically.
One or more Slack channels to post the meeting link to. Use `{{ incident.slack_channel_id }}` to post to the incident channel, or `{{ parent_incident.slack_channel_id }}` for the parent incident's channel.
Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to preview what values Liquid variables return before saving your workflow.
## Uninstall
To remove the Webex integration:
1. Go to **Configuration → Integrations** and find **Webex**
2. Click **Connected** to reveal the disconnect option
3. Click **Disconnect**
## Frequently Asked Questions
No. Rootly enforces one Webex meeting per incident. If the **Create Webex Meeting** action runs again for the same incident, it will be skipped.
A free Webex account works for basic meeting creation. However, some meeting features (longer durations, larger participant limits) require a paid Webex plan.
Yes. Use Liquid variables in the **Meeting Name** field. For example: `{{ incident.severity }} - {{ incident.title }}` will produce names like `SEV1 - Database Outage`.
The most common trigger is **Incident Created**. This creates the meeting immediately when an incident is declared. You can also use **Incident Updated** if you want to create a meeting only when certain conditions are met (for example, severity escalates to SEV1).
Set the **Slack Channels** field to `{{ incident.slack_channel_id }}`. This requires the Slack integration to be installed and a channel to already exist for the incident (typically created by a separate workflow action earlier in the same workflow).
Only one Webex account can be connected at a time per Rootly organization.
Rootly requests OAuth permissions to create meetings on behalf of the connected account. Rootly does not read your existing meetings or contacts.
If the Webex account used during OAuth setup is deactivated, the integration will stop working. Use a shared service account (for example, `incidents@yourcompany.com`) to avoid this.
## Related Resources
* [Workflows](/workflows/workflows)
* [Incident variables](/liquid/incident-variables)
* [Integrations overview](/integrations/overview)
# Zapier
Source: https://docs.rootly.com/integrations/zapier
Connect Rootly with thousands of apps through Zapier to automate incident workflows without code, including ticketing, notifications, CRM, and reporting.
## Introduction
The Rootly–Zapier integration lets you connect Rootly to thousands of apps without writing any code. You can trigger Zaps when incident events occur in Rootly, and take actions on Rootly — creating incidents, updating their status, and more — from any app in the Zapier ecosystem.
## Before You Begin
Before building Zaps with Rootly, make sure you have:
* A Rootly account with permission to manage integrations
* A Zapier account
* A Rootly API key — generate one in **Account** > **Manage API keys** > **Generate New API Key**
## Installation
Go to [zapier.com/apps/rootly/integrations](https://zapier.com/apps/rootly/integrations) and select **Connect Rootly**.
When prompted, paste your Rootly API key. Zapier uses this to authenticate all trigger and action calls on your behalf.
Rootly is connected. You can now select any Rootly trigger or action when building a Zap.
## Triggers
Rootly sends webhook events to Zapier when the following events occur. Use these as the starting point for your Zaps.
### Incident Events
| Event | Description |
| -------------------- | ---------------------------------- |
| `incident.created` | A new incident was opened |
| `incident.updated` | An incident's fields were modified |
| `incident.in_triage` | An incident moved to in triage |
| `incident.mitigated` | An incident was mitigated |
| `incident.resolved` | An incident was resolved |
| `incident.cancelled` | An incident was cancelled |
| `incident.deleted` | An incident was deleted |
### Scheduled Incident Events
| Event | Description |
| -------------------------------- | -------------------------------- |
| `incident.scheduled.created` | A scheduled incident was created |
| `incident.scheduled.updated` | A scheduled incident was updated |
| `incident.scheduled.in_progress` | A scheduled incident started |
| `incident.scheduled.completed` | A scheduled incident completed |
| `incident.scheduled.deleted` | A scheduled incident was deleted |
### Other Events
| Event | Description |
| -------------------------------------------------------------- | ---------------------------- |
| `incident_post_mortem.created/updated/published/deleted` | Post-mortem lifecycle events |
| `incident_status_page_event.created/updated/deleted` | Status page event changes |
| `incident_event.created/updated/deleted` | Incident timeline events |
| `alert.created` | A new alert was received |
| `genius_workflow_run.queued/started/completed/failed/canceled` | Workflow run state changes |
| `pulse.created` | A new pulse was created |
## Actions
Use Rootly actions as steps in any Zap to manage incidents from external apps.
### Create Incident
Creates a new Rootly incident. Supports setting the title, summary, and severity.
### Update Incident
Modifies an existing incident — title, summary, severity, status, services, teams, and labels are all updatable.
### Incident State Transitions
Trigger status changes on existing incidents:
* Mark as **In Triage**
* Mark as **Mitigated**
* Mark as **Resolved**
* Mark as **Cancelled**
### Create Alert
Creates or updates an alert in Rootly.
## Troubleshooting
Confirm the API key is active and has not been revoked. Go to **Account** > **Manage API keys** in Rootly and verify the key exists. Zapier authenticates each request using the key you provided during setup — if the key was regenerated or deleted, you'll need to reconnect the Rootly app in Zapier.
Zapier polls for new trigger data on a schedule based on your Zapier plan. Events are not delivered in real time on all plans. If you need immediate delivery, check your Zapier plan's polling frequency. Also confirm your Zap is turned on and the trigger step is configured with the correct event type.
Rootly's API requires that all fields passed to actions are valid. Check the error message returned by Zapier for details — common causes include an invalid incident ID, an unsupported severity value, or a missing required field. Refer to the [Rootly API reference](/api-reference/overview) for valid field values.
The events available in Zapier reflect what Rootly publishes via webhooks. If you need an event type that is not available, contact [support@rootly.com](mailto:support@rootly.com).
## Related Pages
Build native Rootly workflows for automation that doesn't require Zapier.
The full API reference — all endpoints Zapier actions call are documented here.
Browse all available Rootly triggers and actions in the Zapier app directory.
# Zendesk
Source: https://docs.rootly.com/integrations/zendesk
Connect Rootly with Zendesk to automatically create and update tickets from incidents, and receive Zendesk ticket events as Rootly alerts.
## Introduction
The Zendesk integration connects Rootly with your Zendesk Support account bidirectionally. Rootly can create and update tickets through workflow actions, and Zendesk can send ticket events to Rootly as alerts. You can also install the [Rootly app from the Zendesk Marketplace](https://www.zendesk.com/marketplace/apps/support/995423/rootly/) to manage incidents directly from the Zendesk agent interface.
With the Zendesk integration, you can:
* Automatically create Zendesk tickets when incidents are declared or reach a certain state
* Update ticket subject, priority, status, and custom fields as incidents evolve
* Link Zendesk tickets to Jira issues via a dedicated workflow action
* Receive Zendesk ticket events as Rootly alerts to trigger on-call workflows
* Create Rootly incidents and view active incidents directly from within Zendesk (Marketplace app)
## Before You Begin
Before setting up the integration, make sure you have:
* A Rootly account with admin permission to manage integrations
* A Zendesk Support account with admin access
* Your Zendesk subdomain (the part before `.zendesk.com`)
Rootly recommends installing with a dedicated Zendesk service account so the integration does not break if an individual user leaves your organization.
## Installation
Navigate to the integrations page in Rootly and select **Zendesk**.
Enter your Zendesk **Subdomain** (for example, `yourcompany` for `yourcompany.zendesk.com`) and click **Connect**. You will be redirected to Zendesk to authorize the integration.
Rootly requests the following OAuth scopes:
| Scope | Purpose |
| ---------------- | ------------------------------------------- |
| `users:read` | Read user profile information |
| `tickets:write` | Create and update tickets |
| `webhooks:write` | Register a webhook to receive ticket events |
| `triggers:write` | Create triggers to send events to Rootly |
Once authorized, Rootly automatically registers a webhook and trigger in your Zendesk account to deliver ticket events.
After installation, the **Create a Zendesk Ticket**, **Update a Zendesk Ticket**, and **Create a Zendesk-Jira Link** workflow actions are available in your Genius workflows. Zendesk ticket events will also appear as alerts in Rootly.
## Workflow Actions
### Create a Zendesk Ticket
This action creates a new ticket in Zendesk.
| Field | Description | Required |
| ------------------------- | ------------------------------------------------------------------------------ | -------- |
| **Name** | Display name for this workflow action | |
| **Type** | Ticket type: `problem`, `incident`, `question`, or `task` | Yes |
| **Subject** | Ticket subject line. Defaults to `{{ incident.title }}`. Supports Liquid | Yes |
| **Comment** | Ticket body. Supports Liquid. Defaults to `"Updated from rootly.com"` if blank | |
| **Priority** | Ticket priority. **Auto** mirrors the incident severity | |
| **Status** | Ticket status. **Auto** mirrors the incident status | |
| **Tags** | Comma-separated tags. Only applied on creation, not updates. Supports Liquid | |
| **Custom Fields Mapping** | JSON array of custom field objects. Supports Liquid | |
| **Ticket Payload** | Advanced JSON merged into the Zendesk ticket payload. Supports Liquid | |
Tags are only applied on ticket **creation**. They are not updated when using the Update a Zendesk Ticket action.
**Priority mapping (Auto)**
| Rootly Severity | Zendesk Priority |
| --------------- | ---------------- |
| Critical | Urgent |
| High | High |
| Medium | Normal |
| Low | Low |
**Status mapping (Auto)**
| Rootly Status | Zendesk Status |
| ------------- | -------------- |
| Started | Open |
| Mitigated | Solved |
| Resolved | Solved |
Available statuses: New, Open, Pending, Hold, Solved, Closed.
***
### Update a Zendesk Ticket
This action updates an existing Zendesk ticket.
When a **Create a Zendesk Ticket** action runs, Rootly stores the resulting ticket ID on the incident record. Reference it in subsequent update actions using Liquid variables.
| Field | Description | Required |
| ------------------------- | ----------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Ticket ID** | Zendesk ticket ID to update. Supports Liquid | Yes |
| **Subject** | Updated ticket subject. Supports Liquid | |
| **Priority** | Updated priority | |
| **Status** | Updated ticket status | |
| **Custom Fields Mapping** | Updated custom field values as JSON | |
| **Ticket Payload** | Advanced JSON merged into the Zendesk ticket update payload | |
***
### Create a Zendesk-Jira Link
This action links a Zendesk ticket to a Jira issue using the Zendesk-Jira integration.
| Field | Description | Required |
| --------------------- | --------------------------------------------------------------- | -------- |
| **Name** | Display name for this workflow action | |
| **Jira Issue ID** | Numeric ID of the Jira issue. Supports Liquid | Yes |
| **Jira Issue Key** | Key of the Jira issue (for example, `ENG-123`). Supports Liquid | Yes |
| **Zendesk Ticket ID** | Zendesk ticket ID to link. Supports Liquid | Yes |
***
## Inbound Events (Zendesk → Rootly)
When the integration is installed, Rootly registers a webhook and trigger in Zendesk to receive ticket events. Each event creates a Rootly alert with the following fields:
| Rootly Alert Field | Zendesk Source |
| ------------------ | ----------------------------- |
| Summary | `[New ticket] {ticket.title}` |
| External ID | `ticket.id` |
Alert labels:
| Label | Zendesk Field |
| ---------- | --------------------- |
| `id` | `ticket.id` |
| `type` | `ticket.type` |
| `priority` | `ticket.priority` |
| `account` | `ticket.account.name` |
***
## Zendesk Marketplace App
The [Rootly app for Zendesk](https://www.zendesk.com/marketplace/apps/support/995423/rootly/) brings Rootly directly into the Zendesk agent interface. With the Marketplace app, agents can:
* Create Rootly incidents directly from a Zendesk ticket
* View, search, and attach recent Rootly incidents in Zendesk
* View active or related Rootly incidents and attach them to the Zendesk ticket
## Troubleshooting
Verify that the authorized Zendesk account has permission to create tickets. If the type is `incident`, check that your Zendesk plan supports incident-type tickets. Confirm the subject field is not empty.
Tags are only set during ticket creation. To manage tags on existing tickets, use the **Ticket Payload** field to send a tags update directly in the Zendesk API format.
Confirm the webhook and trigger were registered successfully during installation. In Zendesk, check **Settings > Webhooks** and **Business Rules > Triggers** to verify Rootly entries exist and are active.
## Uninstall
To remove the Zendesk integration, open the integrations panel in Rootly and select **Configure > Delete**. Rootly will remove the registered webhook and trigger from your Zendesk account on deletion.
## Related resources
* [Jira (On-Premise)](/integrations/jira-on-premise)
* [Motion integration for Rootly incidents](/integrations/motion)
* [Shortcut](/integrations/shortcut)
# Zoom
Source: https://docs.rootly.com/integrations/zoom/zoom
Connect Zoom to Rootly to create an incident meeting automatically and capture transcripts and summaries with Meeting Scribe.
## Overview
Rootly's Zoom integration automatically creates a Zoom meeting when an incident starts and posts the link directly in the incident's Slack channel. Responders can join instantly without manual setup — no time wasted creating or sharing meeting links during a critical incident.
## Features
Zoom calls created automatically when incidents start.
Meeting links posted directly in the incident Slack channel.
Configure local or cloud recording and AI meeting capture.
Configure triggers, conditions, hosts, and recording options per workflow.
## Meeting Scribe on Zoom
The Zoom integration powers **[Rootly AI Meeting Scribe](/ai/meeting-scribe)** on your Zoom incident bridges — automatic recording, live transcription, PII-redacted transcripts, and Rootly AI meeting summaries fed straight into the incident's post-incident artifacts.
To enable:
1. Go to **Integrations → Zoom** in Rootly.
2. Toggle on **Meeting transcript and summary**.
3. **Enable Auto-join bot** — highly recommended. Without this, someone needs to manually admit the scribe on every call, and it drops off after 10 minutes if no one does.
Auto-join is the single biggest lever for reliable Zoom scribe behavior. If you're seeing intermittent "the bot never joined" reports, check this first.
Running into issues? See **Zoom Meeting Scribe Troubleshooting** for the common failure modes and fixes.
***
## Before You Begin
Rootly recommends performing the installation with a **shared service account** (for example, `incidents@yourcompany.com`) rather than a personal account. This ensures the integration continues working if someone leaves the company. Ensure you are logged in as an **Admin** in Rootly.
## Installation
To connect Zoom to Rootly, you will authorize Rootly via OAuth. This grants Rootly the permissions it needs to create and manage meetings on your behalf.
Navigate to **Configuration → Integrations** in Rootly.
Search for **Zoom** and click **Setup**.
Select your sign-in method — Google, SSO, or email and password.
Choose the Zoom account you want to connect to Rootly.
If no Zoom account exists for this email, you will be prompted to create one.
Review and accept the OAuth permissions to grant Rootly access to your Zoom account.
You will be redirected back to Rootly with a success message. The integration status will show **Connected** with your Zoom account email.
Your Zoom account is now connected to Rootly. You can configure meeting name defaults and recording preferences from the integration settings page.
### OAuth Scopes
Rootly requests the following Zoom permissions during authorization:
| Scope | Purpose |
| --------------- | -------------------------------------------------- |
| `meeting:write` | Create meetings on behalf of the connected account |
| `meeting:read` | Read meeting details to generate join links |
| `user:read` | Read user information to assign hosts |
| `user_zak:read` | Required by Zoom SDK — not actively used by Rootly |
## Creating the Incident Meeting
Rootly workflows automatically create Zoom meeting rooms when incidents occur. You can use the built-in **Auto-Create Incident Call** setting for quick setup, or build a **custom workflow** when you need conditional logic, specific triggers, or advanced routing.
Rootly enforces one Zoom meeting per incident. Running the same automation multiple times updates the existing link rather than creating a new one. For additional meetings, create a sub-incident.
### Option 1: Auto-Create Incident Call
The Auto-Create Incident Call setting lets you automatically generate a Zoom meeting when an incident begins — no workflow required.
Configure the following options directly in the integration settings:
| Setting | Description |
| -------------------------------------- | ---------------------------------------------------------- |
| **Create Zoom Call on Incident Start** | Automatically spin up a meeting when an incident opens |
| **Meeting Name** | Default or custom name using Liquid variables |
| **Bookmark in Slack** | Add the meeting link as a bookmark in the incident channel |
| **Notify Slack Channels** | Announce new calls in specific Slack channels |
| **Record Call** | Enable automatic recording — None, Local, or Cloud |
| **Specify Host** | Assign a specific host by email |
| **AI Meeting Capture** | Enable transcription and AI-generated meeting summaries |
| **Bot Recording** | Start recording automatically without host approval |
Use Auto-Create for quick setup. Build a custom workflow when you need conditions, specific triggers, or advanced routing.
### Option 2: Custom Workflow
For more control — such as only creating meetings for SEV-1 incidents or routing to specific hosts — build a custom Incident workflow.
Navigate to **Workflows** in Rootly and click **Create Workflow**.
Select **Incident** as the workflow type.
Choose when the workflow fires. Common triggers for Zoom meeting creation:
| Trigger | When it fires |
| --------------------------- | ----------------------------------------------------------- |
| **Incident Created** | Creates a Zoom call as soon as a new incident opens |
| **Incident Status Changed** | Creates a call when the incident moves to a specific status |
| **Commander Assigned** | Creates a call once someone takes ownership of the incident |
| **Manual Trigger** | Run the workflow on demand from the UI |
Use conditions to control when the workflow should run after triggering.
Common patterns:
* **Severity filter** — Only create calls for SEV-1 or SEV-2 incidents
* **Team filter** — Only for incidents affecting specific teams
* **Incident type** — Only when Kind is set to **Incident**
Click **Add Action**, search for **Zoom**, and select **Create Room**.
Configure the action fields:
| Field | Description |
| ---------------------- | ------------------------------------------------------------------------------- |
| **Meeting Name** | The Zoom meeting title. Supports Liquid syntax. Defaults to the incident title. |
| **Password** | Optional meeting password. Leave blank to let Rootly generate a secure one. |
| **Create as User** | Email of the Zoom account to create the meeting as. Supports Liquid syntax. |
| **Alternative Hosts** | Additional host email addresses. Must be existing Zoom accounts. |
| **Auto Recording** | `None`, `Local`, or `Cloud`. Can also be started manually during the meeting. |
| **AI Meeting Capture** | Enable transcription and AI-generated meeting summaries. |
| **Slack Channels** | Slack channels to post the meeting link to. |
For **Create as User**, use the incident creator's email via Liquid syntax, or set a dedicated service account like `zoom@yourcompany.com` to ensure meetings are always owned by a known account.
Name the workflow clearly (for example, `Create Zoom Call for SEV-1 Incidents`) and click **Create Workflow**.
### Variable Reference
Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to test variables with real incident data.
#### Zoom Variables
| Variable | Description |
| --------------------------- | ----------------------------- |
| `incident.zoom_meeting_url` | Link to join the Zoom meeting |
| `incident.zoom_meeting_id` | Unique Zoom meeting ID |
#### Incident Variables
| Variable | Description |
| ----------------------------- | ------------------------------ |
| `incident.title` | Incident title |
| `incident.summary` | Incident description |
| `incident.severity` | Severity level |
| `incident.status` | Current status |
| `incident.started_at` | When the incident started |
| `incident.creator.name` | Incident creator's name |
| `incident.creator.email` | Incident creator's email |
| `incident.commander.email` | Incident commander's email |
| `incident.slack_channel_name` | Incident Slack channel name |
| `incident.url` | Link to the incident in Rootly |
## Troubleshooting Meeting Scribe
Nearly every "the scribe didn't join our Zoom call" report traces back to one of a small set of causes. Work through them in this order. For the full Meeting Scribe reference (limitations, retention, subprocessors), see [Rootly AI Meeting Scribe](/ai/meeting-scribe).
### The Scribe Never Joins the Meeting
#### Auto-join isn't enabled
The single most common cause. Without **Auto-join bot** on, someone has to manually admit the scribe — it appears as **Rootly Scribe** in Zoom's participant list — on every call.
**Fix:** In Rootly, go to **Integrations → Zoom** and toggle **Auto-join bot** on.
Auto-join uses a Zoom-side capability that lets Rootly's scribe bypass the waiting room. If your Zoom account plan or admin policy blocks bypass tokens, Auto-join can't help — see the next section.
#### The Zoom account doesn't have permission to bypass the waiting room
Rootly's Auto-join relies on Zoom's "bypass waiting room" feature. Some Zoom account tiers or admin configurations don't allow it.
**Fix:** Ask your Zoom admin to confirm your account supports bypass tokens (typically Business, Education, and Enterprise plans). If it doesn't, either upgrade the plan or leave Auto-join off and admit the scribe manually — the fallback still works, it just needs a human.
#### The meeting URL isn't attached to the incident
The scribe joins the meeting URL attached to the incident. If a personal-meeting-room link is being used and it hasn't been attached, the scribe doesn't know about it.
**Fix:** Either use the Rootly-generated meeting link pinned in the incident's Slack channel (works automatically), or attach the URL you're using via [Updating incident integration links](/incidents/managing-incidents/updating-incident-integration-links).
#### The scribe is in the waiting room and no one admitted it in time
The scribe waits **10 minutes** in a Zoom waiting room. If no one admits it, it disconnects.
**Fix:** Reinvite the scribe from the **Scribe** tab on the incident and admit it promptly. Prevention: enable Auto-join.
***
### The Scribe Joined but Left Early
#### Nobody-joined timeout (5 minutes)
If the scribe enters the meeting but no other participants show up within **5 minutes**, it leaves.
**Fix:** Start the meeting on your side first, then reinvite the scribe. Alternatively, invite the scribe after your team is already on the call.
#### The host removed the scribe
Zoom hosts can eject any participant, including the scribe. If a host removed it (intentionally or by accident), the scribe leaves and does not auto-rejoin.
**Fix:** Reinvite from the **Scribe** tab. Consider giving your team a heads-up that the scribe should stay.
#### Network / Zoom-side disconnect
Rare, but the scribe can be disconnected by Zoom for reasons outside Rootly's control (network blip, Zoom service issue, plan-level restriction changing mid-call).
**Fix:** Reinvite. If it happens repeatedly across incidents, check Zoom's status page and open a support ticket with Rootly if the issue is inside Rootly.
***
### Transcript or Summary Missing
#### Post-meeting processing is still running
Transcripts and Rootly AI meeting summaries are generated after the meeting ends. Processing typically completes within a few minutes.
**Fix:** Wait \~5–10 minutes and refresh the **Scribe** tab.
#### The scribe never actually recorded
If the recording icon didn't appear in-meeting, the scribe was likely in a waiting room the whole time or was removed early.
**Fix:** Check the incident timeline for a "Recording started" event. If it isn't there, the scribe didn't record. Reinvite for the next session.
#### Recording was paused and not resumed
The Meeting Scribe supports pausing mid-call (useful for sensitive topics). If it was paused and no one resumed, that segment isn't captured.
**Fix:** Check the recording session status in the **Scribe** tab. Resume any paused session.
***
## Uninstall
**In Rootly:**
1. Go to **Configuration → Integrations** and find **Zoom**
2. Click the **Connected** button to reveal the disconnect option
3. Click **Delete**
**In Zoom** (to fully revoke access):
1. Log in to your Zoom account and navigate to the **Zoom App Marketplace**
2. Click **Manage → Apps on Account** or search for the Rootly app
3. Click the Rootly app and select **Remove** or **Disable**
## Frequently Asked Questions
Rootly enforces one Zoom meeting per incident. If you need additional meetings, declare a sub-incident from the main incident and create a separate Zoom link for it.
Ensure the **Slack Channels** field in the workflow action is configured with the correct channel. You can use Liquid syntax to reference the incident channel dynamically. Also confirm the Slack integration is connected under **Configuration → Integrations**.
The Meeting Name field supports Liquid syntax. Use the [Liquid Variable Explorer](https://rootly.com/account/help/liquid-explorer) to preview available variables. Common examples include the incident title, severity, and ID.
The meeting creation will fail if the email is not associated with a valid Zoom account. Use a dedicated service account email or verify the Liquid variable resolves to a known Zoom user.
### Meeting Scribe Questions
With **Auto-join** on, Rootly uses a Zoom bypass token so the scribe skips the waiting room. Without it, the scribe enters the waiting room like any external participant and needs a host or co-host to admit it. Auto-join is the recommended setup for reliable incident bridge coverage.
Auto-join works for meetings hosted on your own connected Zoom account. If your team joins someone else's Zoom meeting (an external partner, a vendor call), the scribe would need that host to admit it — Auto-join tokens don't carry across Zoom accounts.
Yes — declare a test incident (`/rootly test` in Slack) and the scribe will join the resulting bridge just like a real one. Test incidents are excluded from production metrics.
Each time the scribe joins or rejoins is a new **recording session**. Up to 10 sessions per platform per incident. Both sessions are valid — the transcripts and recordings are attached chronologically.
***
## Related Resources
* [Rootly AI Meeting Scribe](/ai/meeting-scribe)
* [Workflows](/workflows/workflows)
* [Integrations overview](/integrations/overview)
# Action Item Variables
Source: https://docs.rootly.com/liquid/action-item-variables
Reference guide for action item variables available in Liquid templates for Rootly Genius workflows, integration formatting, and action item automation.
You can use action item variables with genius workflows:
## Variables
Use the [Liquid Markup explorer](https://rootly.com/account/help/liquid-explorer) to navigate through all action item variables.
Rootly uses the [Liquid](https://shopify.github.io/liquid/) template language. The available variables are:
```ruby Ruby theme={null}
{{ action_item.id }} # returns string (uuid)
{{ action_item.summary }} # returns string
{{ action_item.description }} # returns string
{{ action_item.status }} # returns string
{{ action_item.priority }} # returns integer
{{ action_item.due_date }} # returns datetime
{{ action_item.url }} # returns string
{{ action_item.short_url }} # returns string
{{ action_item.created_at }} # returns datetime
{{ action_item.updated_at }} # returns datetime
{{ action_item.creator }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
{{ action_item.assigned_to }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
# Integrations
{{ action_item.jira_issue_id }} # returns string
{{ action_item.jira_issue_key }} # returns string
{{ action_item.jira_issue_url }} # returns string
{{ action_item.asana_task_id }} # returns string
{{ action_item.asana_task_url }} # returns string
{{ action_item.motion_task_id }} # returns string
{{ action_item.motion_task_url }} # returns string
# DEPRECATED {{ action_item.clubhouse_task_id }} # returns string (use shortcut_task_id)
# DEPRECATED {{ action_item.clubhouse_task_url }} # returns string (use shortcut_task_url)
{{ action_item.shortcut_story_id }} # returns string
{{ action_item.shortcut_story_url }} # returns string
{{ action_item.shortcut_task_id }} # returns string
{{ action_item.shortcut_task_url }} # returns string
{{ action_item.trello_card_id }} # returns string
{{ action_item.trello_card_url }} # returns string
{{ action_item.trello_check_item_id }} # returns string
{{ action_item.trello_check_item_url }} # returns string
{{ action_item.linear_issue_id }} # returns string
{{ action_item.linear_issue_key }} # returns string
{{ action_item.linear_issue_url }} # returns string
{{ action_item.zendesk_ticket_id }} # returns string
{{ action_item.zendesk_ticket_url }} # returns string
{{ action_item.service_now_case_id }} # returns string
{{ action_item.service_now_case_url }} # returns string
{{ action_item.airtable_base_key }} # returns string
{{ action_item.airtable_table_name }} # returns string
{{ action_item.airtable_record_id }} # returns string
{{ action_item.airtable_record_url }} # returns string
{{ action_item.freshservice_ticket_id }} # returns string
{{ action_item.freshservice_ticket_url }} # returns string
{{ action_item.freshservice_task_id }} # returns string
{{ action_item.freshservice_task_url }} # returns string
# Custom fields
{{ action_item.custom_fields }} # returns array of selection objects
{{ action_item.custom_fields_by_slug }} # returns hash of slug => value(s)
```
## Custom Fields
Action items can carry [custom field](/incidents/action-items/action-item-custom-fields) values. Two variables expose them:
### The custom\_fields\_by\_slug Variable
The simplest way to access a value. Keys are the field's slug (lower-cased and hyphenated); single-value fields return a string, while multiple select and tags fields return an array.
```ruby Ruby theme={null}
# Single-value field (text, number, date, select, etc.)
{{ action_item.custom_fields_by_slug.business-unit-owner }}
# => "Payments"
# Multi-value field (multiple select, tags)
{{ action_item.custom_fields_by_slug.impacted-regions | join: ', ' }}
# => "us-east-1, eu-west-2"
```
Values are returned in display form: user/team/service/catalog-backed selections return names, checkboxes return `Yes`/`No`, and date fields return formatted dates.
### The custom\_fields Variable
The structured form — an array of selection objects, each containing the `form_field` definition (name, slug, ID) and its selected values. Useful when you need field metadata alongside values, or a lookup key that survives renames.
Liquid's `find` and `where` filters only match on a top-level property — they can't follow a nested path like `form_field.id` (that lookup silently returns nothing). Loop over the array and compare inside the loop instead:
```ruby Ruby theme={null}
# Look up a selection by field ID — stable across renames, since slugs regenerate
{% assign target = "your-field-uuid" %}
{% for f in action_item.custom_fields %}
{% if f.form_field.id == target %}{{ f.form_field.name }}{% endif %}
{% endfor %}
```
Reading the value depends on the field type. For free-text values (text, textarea, number, date, etc.), `selected_options` is a single object whose `value` holds the entry. For option-backed fields (select, multiple select), `selected_options` is an array of option objects, each with `id` and `value`. Testing `selected_options.value` distinguishes the two shapes:
```ruby Ruby theme={null}
{% for f in action_item.custom_fields %}
{% if f.form_field.id == target %}
{% if f.selected_options.value %}
{{ f.selected_options.value }}
{% else %}
{% for o in f.selected_options %}{{ o.value }}{% unless forloop.last %}, {% endunless %}{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
```
Fields backed by Rootly records (users, teams, services, catalogs, environments, causes, incident types) do **not** expose their values through `selected_options` — read those through `custom_fields_by_slug`, which returns the record names. For day-to-day templating, prefer `custom_fields_by_slug`, which normalizes all of this for you — reach for `custom_fields` only when you need to key off `form_field.id` or inspect the full selection object.
Custom field slugs are regenerated when a field is renamed. If your templates reference fields by slug, renaming the field will break those references.
## Examples
```ruby Ruby theme={null}
action-item-{{ action_item.created_at | date: "%Y%m%d" }}
# Will result in: action-item-20210412
```
# Alert Variables
Source: https://docs.rootly.com/liquid/alert-variables
Reference for alert variables available in Liquid templates used by alert workflows, message templates, and other Liquid-rendered surfaces.
You can use alert variables in different parts of Rootly like:
* Alert workflow actions
* Slack and email message templates triggered by alerts
* Custom alert description templates
Alert routing rules use JSONPath and Alert Field conditions, not Liquid templates — see [Alert Routing](/alerts/alert-routing) for routing condition syntax.
Use the [Liquid Markup explorer](https://rootly.com/account/help/liquid-explorer) to navigate through all alert variables against real alert data.
Rootly uses the [Liquid](https://shopify.github.io/liquid/) template language. The variables below are available wherever an alert is in scope.
## Core
```ruby Ruby theme={null}
{{ alert.id }} # returns string (uuid)
{{ alert.short_id }} # returns string
{{ alert.summary }} # returns string
{{ alert.description }} # returns string
{{ alert.status }} # returns string — see Alert Statuses for the supported values
{{ alert.url }} # returns string — link to the alert in Rootly
{{ alert.created_at }} # returns datetime
```
## Source & External Links
```ruby Ruby theme={null}
{{ alert.source }} # returns string — name of the alert source (e.g., "datadog", "generic_webhook")
{{ alert.external_id }} # returns string — vendor-side identifier
{{ alert.external_url }} # returns string — link back to the originating monitor / alert
{{ alert.data }} # returns the raw inbound webhook payload as a JSON object
```
## Urgency
```ruby Ruby theme={null}
{{ alert.alert_urgency }} # returns object eg. {"id":"...", "name":"High", "description":"...", "team_id":...}
{{ alert.alert_urgency.id }} # returns string
{{ alert.alert_urgency.name }} # returns string
{{ alert.alert_urgency.description }} # returns string
```
## Responders & State Changes
```ruby Ruby theme={null}
{{ alert.responders }} # returns array of user objects (whoever was paged for the alert)
{{ alert.acknowledged_by }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
{{ alert.resolved_by }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
```
## Groups
Populated when alert grouping is configured.
```ruby Ruby theme={null}
{{ alert.groups }} # returns array of group objects the alert was grouped into
{{ alert.group_ids }} # returns array of string ids
{{ alert.group_slugs }} # returns array of slugs
{{ alert.raw_groups }} # returns array of full group objects with associations
```
## Linked Incidents
```ruby Ruby theme={null}
{{ alert.incidents }} # returns array of incident objects this alert is linked to
```
## Timeline
```ruby Ruby theme={null}
{{ alert.timeline }} # returns array of alert event objects (acknowledgements, escalations, resolution)
```
## Examples
Reaching into the raw webhook payload — the exact path depends on the source's payload shape, which you can inspect in the Liquid Explorer:
```ruby Ruby theme={null}
{{ alert.data | get: 'priority' }}
```
Building an urgency-aware Slack message:
```ruby Ruby theme={null}
*{{ alert.alert_urgency.name }}* — {{ alert.summary }}
Created at {{ alert.created_at | in_time_zone: 'America/New_York' | date: '%H:%M %Z' }}
{% if alert.acknowledged_by %}Acknowledged by {{ alert.acknowledged_by.name }}{% endif %}
```
Linking back to the originating monitor:
```ruby Ruby theme={null}
View in source: {{ alert.external_url }}
```
# Available Liquid Filters
Source: https://docs.rootly.com/liquid/filters
Comprehensive reference of built-in and custom Liquid filters for data manipulation, formatting, and string processing in Rootly workflows.
Rootly registers the filters below on top of the [standard Liquid filters](https://shopify.github.io/liquid/). Use them anywhere you can author a Liquid template — workflow tasks, message templates, post-mortem templates, custom field templates, and the in-product Liquid Explorer.
## Fallback Values
When a Liquid expression might resolve to `nil` — a missing field, an absent JSON path, an empty array — chain the standard Liquid **`default`** filter to fall back to another expression. This is the recommended pattern for alert-field mappings that need to coalesce across multiple possible payload paths.
```js JS theme={null}
{{ alert.data.data.srcip | default: alert.data.data.terminal_ip }}
```
The expression resolves to `alert.data.data.srcip` when present, otherwise to `alert.data.data.terminal_ip`. Chain multiple defaults for longer fallback chains:
```js JS theme={null}
{{ alert.data.client_ip | default: alert.data.source_ip | default: alert.data.terminal_ip | default: "unknown" }}
```
The final `"unknown"` literal guarantees a non-empty string output even when every JSON path is missing — useful for fields that downstream workflow conditions or alert routes depend on.
**`default` treats empty strings and empty arrays as truthy.** If you want the fallback to fire on empty values too, pass `allow_false: true`: `{{ value | default: "fallback", allow_false: true }}`. Standard Liquid semantics.
## Lookups & Filtering
### find
* `find: arg1, 'arg2'`
* `arg1`. String
* `arg2`. String
```js JS theme={null}
// Pretending object is the following object [{"id": "apple"}, {"id": "banana"}]
{{ object | find: 'id', 'banana' }}
// Output
// {"id": "banana"}
```
### where
Filters an array, returning every element that matches. Pair with `find` (returns the first match) when you need all results.
* `where: 'arg1', 'arg2'`
* `arg1`. String — key path, dot-separated for nested lookups
* `arg2`. String (optional) — when omitted, keeps elements where `arg1` is truthy
```js JS theme={null}
// Pretending object is [{"role":"commander","name":"Alice"},{"role":"commander","name":"Bob"},{"role":"scribe","name":"Cara"}]
{{ object | where: 'role', 'commander' }}
// Output
// [{"role":"commander","name":"Alice"},{"role":"commander","name":"Bob"}]
{{ incident.subscribers | where: 'role', 'commander' | size }}
// Count of commanders subscribed to the incident
```
### get
* `get: 'arg'`
* `arg`. String
```js JS theme={null}
// Pretending object is the following object {"id": "id", "incident": {"title": "Something is on fire!"}}
{{ object | get: 'incident.title' }}
// Output
// Something is on fire!
```
### slice
* `slice: '\*arg'`
* `arg`. String
* ... As many args as you need
```js JS theme={null}
// Pretending object is the following object {"key": "hello", "value": "world", "foo": "bar"}
{{ object | slice: 'key' }}
// Output
// {"key": "hello"}
{{ object | slice: 'key', 'foo' }}
// Output
// {"key": "hello", "foo": "bar"}
```
## Arrays & Hashes
### flatten
* flatten
```js JS theme={null}
// Pretending object is the following object \["1", "2", \["3"\]\]
{{ object | flatten }}
// Output
// \["1","2","3"\]
```
### push
Appends a value to the end of an array. A comma-separated string is split into an array first.
* `push: 'arg'`
* `arg`. String
```js JS theme={null}
{{ '1,2,3' | push: '4' }}
// Output
// ["1", "2", "3", "4"]
```
### pop
Removes the last `n` elements from an array.
* `pop: arg`
* `arg`. Integer (default `1`)
```js JS theme={null}
{{ '1,2,3,4' | pop: 2 }}
// Output
// ["1", "2"]
```
### shift
Removes the first `n` elements from an array.
* `shift: arg`
* `arg`. Integer (default `1`)
```js JS theme={null}
{{ '1,2,3,4' | shift: 2 }}
// Output
// ["3", "4"]
```
### unshift
Prepends a value to the start of an array. A comma-separated string is split into an array first.
* `unshift: 'arg'`
* `arg`. String
```js JS theme={null}
{{ '2,3,4' | unshift: '1' }}
// Output
// ["1", "2", "3", "4"]
```
### keys
Returns the keys of a hash as an array. Useful for iterating slug-keyed objects like `team.services`, `team.functionalities`, and `team.groups`.
* `keys`
```js JS theme={null}
// Pretending team.services is {"api": {...}, "web": {...}}
{{ team.services | keys }}
// Output
// ["api", "web"]
{% for slug in team.services | keys %}- {{ slug }}
{% endfor %}
```
### values
Returns the values of a hash as an array.
* `values`
```js JS theme={null}
{{ team.services | values | size }}
// Number of services on the team
```
### to\_values
* `to_values: 'key'`
* `key` is optional
```js JS theme={null}
// Pretending object is the following object {"key": "hello", "value": "world"}
{{ object | to_values }}
// Output
// \[{"value":"world"}\]
{{ object | to_values: 'key' }}
// Output
// \[{"value":"hello"}\]
```
## JSON
### to\_json
Also available as `json`.
* `to_json`
```js JS theme={null}
// Pretending object is the following object [{"key": "hello", "value": "world"}]
{{ object | to_json }}
// Output
// [{"key":"hello","value":"world"}]
```
### parse\_json
Parses a JSON string into a hash or array — the inverse of `to_json`. Useful when an alert payload field arrives as a stringified JSON blob.
* `parse_json`
```js JS theme={null}
{{ '{"key":"hello"}' | parse_json | get: 'key' }}
// Output
// hello
{{ alert.data.body | parse_json | get: 'severity' }}
// Reach into a stringified JSON payload nested in alert data
```
Returns the input unchanged if it can't be parsed.
## Dates & Time
### smart\_date
* `smart_date: 'arg'`
* `arg`. String
* This is using [https://github.com/mojombo/chronic](https://github.com/mojombo/chronic) under the hood.
```js JS theme={null}
{{ 'now' | smart_date: 'tomorrow' }}
// Output
// 2023-06-29 12:00:00 -0700
```
### date\_add
* `date_add: amount, 'date_part'`
* `amount`. Integer (positive to add, negative to subtract)
* `date_part`. String - one of: year, month, day, hour, minute, second, millisecond (plurals supported)
Adds a specified amount of time to a date. Works with 'now', 'today', ISO date strings, Time, and Date objects.
```js JS theme={null}
{{ 'now' | date_add: 1, 'day' | date: '%Y-%m-%d' }}
// Output
// 2023-06-30 (tomorrow)
{{ '2023-06-29T10:30:00Z' | date_add: 2, 'hours' | date: '%Y-%m-%d %H:%M' }}
// Output
// 2023-06-29 12:30
{{ incident.target_resolve_date | date_add: -30, 'minutes' }}
// Output
// 30 minutes before the target resolve date
```
### date\_minus
* `date_minus: amount, 'date_part'`
* `amount`. Integer (positive to subtract, negative to add)
* `date_part`. String - one of: year, month, day, hour, minute, second, millisecond (plurals supported)
Subtracts a specified amount of time from a date. Works with 'now', 'today', ISO date strings, Time, and Date objects.
```js JS theme={null}
{{ 'now' | date_minus: 7, 'days' | date: '%Y-%m-%d' }}
// Output
// 2023-06-22 (a week ago)
{{ incident.created_at | date_minus: 1, 'hour' | date: '%Y-%m-%d %H:%M' }}
// Output
// 1 hour before the incident was created
{{ 'today' | date_minus: 6, 'months' }}
// Output
// 6 months ago
```
### to\_iso8601
* `to_iso8601`
```js JS theme={null}
// Pretending object is the following datetime
{{ object | to_iso8601 }}
// Output
// 2023-06-29T12:00:00-07:00
```
### to\_utc
* `to_utc`
Converts a date to UTC timezone. Works with 'now', 'today', ISO date strings, Time, and Date objects.
```js JS theme={null}
{{ incident.started_at | to_utc | date: '%Y-%m-%d %H:%M:%S' }}
// Output
// 2023-06-29 15:30:00 (converted to UTC)
{{ 'now' | to_utc | date: '%Y-%m-%d %H:%M:%S UTC' }}
// Output
// 2023-06-29 19:45:23 UTC
{{ '2023-06-29T10:30:00-05:00' | to_utc | date: '%Y-%m-%d %H:%M:%S' }}
// Output
// 2023-06-29 15:30:00
```
Useful for synchronizing incident timestamps with timeline values, ensuring all dates display in UTC regardless of user timezone.
### in\_time\_zone
* ` in_time_zone: 'time_zone'`
* `time_zone`. Any timezone listed in [Timezones](/liquid/timezones)
```js JS theme={null}
{{ now | in_time_zone: 'Europe/London' | date: '%Y-%m-%d %H:%M %Z' }}
```
See [Timezones](/liquid/timezones) for available values.
### distance\_of\_time\_in\_words
* `distance_of_time_in_words: 'arg', 'precise'`
* `arg`. String (optional)
* `precise`. String (optional)
```js JS theme={null}
{{ 3720 | distance_of_time_in_words }}
// Output
// about 1 hour
{{ 3720 | distance_of_time_in_words: 0, 'precise' }}
// Output
// 1 hour and 2 minutes
{{ 'May 1, 2020' | distance_of_time_in_words: 'May 31, 2020' }}
// Output
// about 1 month
{{ 'May 1, 2020' | distance_of_time_in_words: 'May 31, 2020', 'precise' }}
// Output
// 4 weeks and 2 days
```
### distance\_of\_time\_in\_words\_to\_now
* `distance_of_time_in_words_to_now: 'precise'`
* `precise`. String (optional)
```js JS theme={null}
{{ 'May 1, 2020' | distance_of_time_in_words_to_now }}
// Output
// over 2 years
{{ 'May 1, 2020' | distance_of_time_in_words_to_now: 'precise' }}
// Output
// 2 years and 7 months
```
## Tables
### to\_table
* `to_table: 'table_type', 'title', 'time_zone', 'format'`
* `table_type`. String — `events` or `action_items`
* `title`. String — table heading
* `time_zone`. String — any timezone listed in [Timezones](/liquid/timezones)
* `format`. String — `ascii`, `markdown`, `html`, or `atlassian_markdown`
The `events` type renders timeline columns: Date, User, Event. The `action_items` type renders: Creation Date, Due Date, Kind, Priority, Status, Assignee, Summary.
```js JS theme={null}
{{ incident.events | to_table: 'events', 'Timeline', 'America/Los_Angeles', 'markdown' }}
{{ incident.action_items | to_table: 'action_items', 'Action Items', 'UTC', 'atlassian_markdown' }}
```
## Regex
### regex\_match
Find first match and return array with full match and capture groups
* `regex_match: 'regex', 'flags'`
* `regex` a ruby regular expression
* `flags` optional string with regex flags: 'i' (case insensitive), 'm' (multiline), 'x' (extended)
```js JS theme={null}
{{ 'Key1: value1' | regex_match: 'Key(\d+): (.+)' | first }}
// Output
// Key1: value1
{{ 'Key1: value1' | regex_match: 'Key(\d+): (.+)' | last }}
// Output
// value1
{{ 'user@example.com' | regex_match: '(\w+)@(\w+\.\w+)' | size }}
// Output
// 3 (full match + 2 capture groups)
```
```js JS theme={null}
// Case insensitive matching
{{ 'HELLO world' | regex_match: 'hello', 'i' | first }}
// Output
// HELLO
// Multiline matching
{{ "Line 1\nLine 2\nDone" | regex_match: 'line.*done', 'im' | first }}
// Output
// Line 1
// Line 2
// Done
```
Perfect for extracting data from email alert payloads:
```js JS theme={null}
{{ alert.body | regex_match: 'Severity: (.+)' | last }}
// Extract severity level from alert body
{{ alert.body | regex_match: 'Host: ([\w\.-]+)' | last }}
// Extract hostname from alert
```
### regex\_match\_all
Find all matches and return array of results
* `regex_match_all: 'regex', 'flags'`
* `regex` a ruby regular expression
* `flags` optional string with regex flags: 'i' (case insensitive), 'm' (multiline), 'x' (extended)
```js JS theme={null}
{{ 'foo 123 bar 456 baz 789' | regex_match_all: '\d+' | size }}
// Output
// 3
{{ 'foo 123 bar 456 baz 789' | regex_match_all: '\d+' | first }}
// Output
// 123
{{ 'foo 123 bar 456 baz 789' | regex_match_all: '\d+' | last }}
// Output
// 789
```
```js JS theme={null}
// Extract all email addresses
{{ 'Contact support@example.com or admin@test.org' | regex_match_all: '[\w\.-]+@[\w\.-]+\.\w+' | size }}
// Output
// 2
// Case insensitive matching
{{ 'ERROR: failed, error: timeout' | regex_match_all: 'error: (\w+)', 'i' | first }}
// Output
// failed
```
Ideal for parsing multiple values from alert payloads:
```js JS theme={null}
// Extract all IP addresses from alert body
{{ alert.body | regex_match_all: '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' }}
// Extract all key-value pairs
{{ alert.body | regex_match_all: 'Key\d+: ([^\n]+)' }}
```
### regex\_replace
Global replace
* `regex_replace: 'regex', 'replacement'`
* `regexp` a ruby regular expression
* `replacement` a ruby regular expression
```js JS theme={null}
{{ 'foo bar 123 456' | regex_replace: '\d+', 'baz' }}
// Output
// foo bar baz baz
```
### regex\_replace\_first
First match replace
* `regex_replace_first: 'regex', 'replacement'`
* `regexp` a ruby regular expression
* `replacement` a ruby regular expression
```js JS theme={null}
{{ 'foo bar 123 456' | regex_replace_first: '\d+', 'baz' }}
// Output
// foo bar baz 456
```
### regex\_remove
Global match remove
* `regex_remove: 'regex'`
* `regexp` a ruby regular expression
```js JS theme={null}
{{ 'foo bar 123 456' | regex_remove: '\d+' }}
// Output
// foo bar
```
### regex\_remove\_first
First match remove
* `regex_remove_first: 'regex'`
* `regexp` a ruby regular expression
```js JS theme={null}
{{ 'foo bar 123 456' | regex_remove_first: '\d+' }}
// Output
// foo bar 456
```
## Slack Helpers
### to\_slack\_markdown
Converts standard Markdown into Slack's mrkdwn flavor (for example, `**bold**` becomes `*bold*`, link syntax is rewritten, lists are formatted). Use in any task that posts to Slack.
* `to_slack_markdown`
```js JS theme={null}
{{ '**Critical**: payment service is down. See [runbook](https://example.com).' | to_slack_markdown }}
// Output
// *Critical*: payment service is down. See .
```
Returns an empty string for non-string inputs.
### format\_text\_for\_slack
Escapes characters that would break a Slack JSON payload — converts double quotes to single quotes and escapes newlines and carriage returns.
* `format_text_for_slack`
```js JS theme={null}
{{ 'She said "hello"
line two' | format_text_for_slack }}
// Output
// She said 'hello'\nline two
```
Use when interpolating user-supplied text into a hand-built Slack Block Kit JSON payload.
## String Manipulation
### dasherize
* `dasherize`
```js JS theme={null}
{{ 'hello_world' | dasherize }}
// Output
// hello-world
```
### parameterize
* `parameterize`
* `separator` (default to '-')
```js JS theme={null}
{{ 'Hello World' | parameterize }}
// Output
// hello-world
{{ 'Hello World' | parameterize: '_' }}
// Output
// hello_world
```
### camelize
* `camelize`
```js JS theme={null}
{{ 'hello world' | camelize }}
// Output
// Hello world
```
### titleize
* `titleize`
```js JS theme={null}
{{ 'hello world' | titleize }}
// Output
// Hello World
```
### singularize
* `singularize`
```js JS theme={null}
{{ 'cars' | singularize }}
// Output
// car
```
### pluralize
* `pluralize`
```js JS theme={null}
{{ 'car' | pluralize }}
// Output
// cars
```
### humanize
* `humanize`
```js JS theme={null}
{{ '0' | humanize }}
// Output
// No
{{ '1' | humanize }}
// Output
// Yes
{{ 'incident_management' | humanize }}
// Output
// Incident Management
```
### shuffle
* `shuffle`
```js JS theme={null}
{{ '123456789' | shuffle }}
// Output
// 973426581
```
## Encoding
### base64\_encode
Base64-encodes a string using strict encoding (no line breaks).
* `base64_encode`
```js JS theme={null}
{{ 'Aladdin:open sesame' | base64_encode }}
// Output
// QWxhZGRpbjpvcGVuIHNlc2FtZQ==
```
Common use — build a Basic auth header for a workflow HTTP task:
```js JS theme={null}
Authorization: Basic {{ secrets.username | append: ':' | append: secrets.password | base64_encode }}
```
### base64\_decode
Decodes a strict-Base64 string. Raises a Liquid argument error on invalid input.
* `base64_decode`
```js JS theme={null}
{{ 'QWxhZGRpbjpvcGVuIHNlc2FtZQ==' | base64_decode }}
// Output
// Aladdin:open sesame
```
### base64\_url\_safe\_encode
Base64-encodes using the URL-safe alphabet (`-` and `_` instead of `+` and `/`).
* `base64_url_safe_encode`
```js JS theme={null}
{{ 'subjects?ids=1,2,3' | base64_url_safe_encode }}
// Output
// c3ViamVjdHM_aWRzPTEsMiwz
```
### base64\_url\_safe\_decode
Decodes a URL-safe Base64 string.
* `base64_url_safe_decode`
```js JS theme={null}
{{ 'c3ViamVjdHM_aWRzPTEsMiwz' | base64_url_safe_decode }}
// Output
// subjects?ids=1,2,3
```
## Markdown & HTML
### markdown\_to\_html
Renders Markdown to sanitized HTML — useful when an integration expects HTML input (for example, email templates, webhook payloads).
* `markdown_to_html`
```js JS theme={null}
{{ '# Title
This is **bold** text.' | markdown_to_html }}
// Output
// Title
// This is bold text.
```
Output is sanitized to a safelist of tags and attributes; links get `rel="nofollow noopener noreferrer"`. Returns an empty string for nil input.
### html\_to\_markdown
Inverse of `markdown_to_html`. Handles most common HTML elements including headings, paragraphs, lists, links, code blocks, and tables.
* `html_to_markdown`
```js JS theme={null}
{{ 'Title
This is bold text.
' | html_to_markdown }}
// Output
// # Title
//
// This is **bold** text.
```
```js JS theme={null}
{{ '- Item 1
- Item 2
' | html_to_markdown }}
// Output
// - Item 1
// - Item 2
```
Returns empty string for nil or empty input. Preserves original HTML on conversion errors.
## URLs
### shortener
* `shortener`
```js JS theme={null}
{{ 'https://rootly.com/account/incidents/123456' | shortener }}
// Output
// https://root.ly/1234
```
## AI
### open\_ai\_completion
Sends the input string to OpenAI as the user prompt and returns the completion text. Useful for inline summarization or text transformation directly inside a Liquid template.
* `open_ai_completion`
```js JS theme={null}
{{ alert.description | open_ai_completion }}
// Returns OpenAI's completion using the alert description as the prompt
```
For most use cases, prefer the dedicated AI workflow tasks (`Create OpenAI Chat Completion`, `Create Anthropic Chat Completion`, etc.) over this filter — they expose model selection, system prompts, temperature, and message history, which this filter does not.
Returns `"something went wrong"` on failure.
## Integration Converters
Rootly's severity, priority, and status enums don't always map 1-to-1 to vendor enums. Converter filters translate a Rootly value to the equivalent vendor value when building HTTP payloads or workflow task arguments. They take no extra arguments unless noted.
```js JS theme={null}
{{ incident.severity | linear_severity_converter }}
// Maps Rootly severity to Linear's severity scale
{{ action_item.priority | clickup_priority_converter }}
// Maps Rootly priority to ClickUp's priority scale
```
| Filter | What it converts |
| ----------------------------------- | ------------------------------------------------- |
| `linear_severity_converter` | Rootly severity → Linear |
| `linear_priority_converter` | Rootly priority → Linear |
| `trello_archivation_converter` | Rootly status → Trello archivation |
| `asana_completion_converter` | Rootly status → Asana completion |
| `github_completion_converter` | Rootly status → GitHub issue state |
| `gitlab_completion_converter` | Rootly status → GitLab issue state |
| `shortcut_archivation_converter` | Rootly status → Shortcut archivation |
| `shortcut_completion_converter` | Rootly status → Shortcut completion |
| `zendesk_severity_converter` | Rootly severity → Zendesk |
| `zendesk_priority_converter` | Rootly priority → Zendesk |
| `zendesk_completion_converter` | Rootly status → Zendesk (takes a `type` arg) |
| `service_now_severity_converter` | Rootly severity → ServiceNow |
| `service_now_completion_converter` | Rootly status → ServiceNow |
| `freshservice_severity_converter` | Rootly severity → Freshservice |
| `freshservice_priority_converter` | Rootly priority → Freshservice |
| `freshservice_completion_converter` | Rootly status → Freshservice (takes a `type` arg) |
| `opsgenie_completion_converter` | Rootly status → Opsgenie (takes a `type` arg) |
| `clickup_severity_converter` | Rootly severity → ClickUp |
| `clickup_priority_converter` | Rootly priority → ClickUp |
| `motion_severity_converter` | Rootly severity → Motion |
| `motion_priority_converter` | Rootly priority → Motion |
# Incident Variables
Source: https://docs.rootly.com/liquid/incident-variables
Complete reference of all available incident variables for Liquid templating in workflows, Slack formatting, and postmortem templates.
You can use incident variables in different parts of Rootly like:
* Slack title format
* Postmortem templates
* Genius workflow blocks
* etc.
## Variables
Use the [Liquid Markup explorer](https://rootly.com/account/help/liquid-explorer) to navigate through all incident variables.
Rootly uses the [Liquid](https://shopify.github.io/liquid/) template language. The available variables are:
```ruby Ruby theme={null}
{{ incident.id }} # returns string
{{ incident.sequential_id }} # returns integer
{{ incident.slug }} # returns string
{{ incident.title }} # returns string
{{ incident.summary }} # returns string
{{ incident.status }} # returns string
{{ incident.labels }} # returns array
{{ incident.timeline }} # returns array
{{ incident.timeline_table }} # returns string
{{ incident.timeline_table_markdown }} # returns string
{{ incident.timeline_table_markdown2 }} # returns string
{{ incident.timeline_table_atlassian }} # returns string
# DEPRECATED {{ incident.status_page_timeline }} # returns array
# DEPRECATED {{ incident.status_page_timeline_table }} # returns string
# DEPRECATED {{ incident.status_page_timeline_table_markdown }} # returns string
# DEPRECATED {{ incident.status_page_timeline_table_markdown2 }} # returns string
# See section below for new way
{{ incident.severity }} # returns string
{{ incident.severity_slug }} # returns string
{{ incident.environments }} # returns array
{{ incident.environment_slugs }} # returns array
{{ incident.raw_environments }} # returns array of objects
{{ incident.types }} # returns array
{{ incident.types_slugs }} # returns array
{{ incident.raw_types }} # returns array of objects
{{ incident.services }} # returns array
{{ incident.services_slug }} # returns array
{{ incident.raw_services }} # returns array of objects
{{ incident.functionalities }} # returns array
{{ incident.functionality_slugs }} # returns array
{{ incident.raw_functionalities }} # returns array of objects
{{ incident.groups }} # returns array
{{ incident.group_slugs }} # returns array
{{ incident.raw_groups }} # returns array of objects
{{ incident.created_at }} # returns datetime
{{ incident.started_at }} # returns datetime
{{ incident.detected_at }} # returns datetime
{{ incident.acknowledged_at }} # returns datetime
{{ incident.mitigated_at }} # returns datetime
{{ incident.resolved_at }} # returns datetime
{{ incident.time_to_mitigation }} # returns integer (in hours)
{{ incident.mitigation_message }} # return string
{{ incident.time_to_resolution }} # returns integer (in hours)
{{ incident.resolution_message }} # return string
{{ incident.time_to_detection }} # returns integer (in hours)
{{ incident.detection_duration }} # returns integer (in seconds)
{{ incident.mitigation_duration }} # returns integer (in seconds)
{{ incident.time_to_acknowledge }} # returns integer (in hours)
{{ incident.acknowledge_duration }} # returns integer (in seconds)
{{ incident.duration }} # returns integer (in seconds)
{{ incident.url }} # returns string
{{ incident.short_url }} # returns string
{{ incident.retrospective_id }} # returns integer
{{ incident.retrospective_url }} # returns string
{{ incident.retrospective_short_url }} # returns string
{{ incident.retrospective_progress_status }} # returns string eg. not_started, active, completed, skipped
{{ incident.postmortem_url }} # returns string (legacy alias for retrospective_url)
{{ incident.notify_emails }} # returns array of string
{{ incident.creator }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
{{ incident.in_triage }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
{{ incident.started_by }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
{{ incident.mitigated_by }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
{{ incident.resolved_by }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
{{ incident.cancelled_by }} # returns object eg. {"id":49, "name":"John Doe", "email":"john@acme.com"}
{{ incident.roles }} # returns array of objects eg. [{"incident_role": {"name" : "Commander"}, "user": {name: "John Doe", email: "john@acme.com"}}]
{{ incident.custom_fields }} # returns array of objects eg. [{"custom_fields": {"slug" : "my-custom-field"}, "selected_options": {value: ["Foo", "Bar"]}}]
{{ incident.scheduled_for }} # Returns datetime
{{ incident.scheduled_until }} # Returns datetime
# Integrations
{{ incident.zoom_meeting_id }} # returns string
{{ incident.zoom_meeting_start_url }} # returns string
{{ incident.zoom_meeting_join_url }} # returns string
{{ incident.webex_meeting_id }} # returns string
{{ incident.webex_meeting_url }} # returns string
{{ incident.shortcut_story_id }} # returns string
{{ incident.shortcut_story_url }} # returns string
{{ incident.shortcut_task_id }} # returns string
{{ incident.shortcut_task_url }} # returns string
{{ incident.asana_task_id }} # returns string
{{ incident.asana_task_url }} # returns string
{{ incident.motion_task_id }} # returns string
{{ incident.motion_task_url }} # returns string
{{ incident.jira_issue_id }} # returns string
{{ incident.jira_issue_key }} # returns string
{{ incident.jira_issue_url }} # returns string
{{ incident.google_meeting_id }} # returns string
{{ incident.google_meeting_url }} # returns string
{{ incident.trello_card_id }} # returns string
{{ incident.trello_card_url }} # returns string
{{ incident.linear_issue_id }} # returns string
{{ incident.linear_issue_key }} # returns string
{{ incident.linear_issue_url }} # returns string
{{ incident.zendesk_ticket_id }} # returns string
{{ incident.zendesk_ticket_url }} # returns string
{{ incident.slack_channel_name }} # returns string
{{ incident.slack_channel_id }} # returns string
{{ incident.slack_channel_url }} # returns string
{{ incident.slack_channel_short_url }} # returns string
{{ incident.slack_channel_deep_link }} # returns string
{{ incident.microsoft_teams_channel_id }} # returns string
{{ incident.microsoft_teams_channel_name }} # returns string
{{ incident.microsoft_teams_channel_url }} # returns string
{{ incident.microsoft_teams_chat_id }} # returns string
{{ incident.microsoft_teams_chat_url }} # returns string
{{ incident.google_chat_space_id }} # returns string
{{ incident.google_chat_space_name }} # returns string
{{ incident.google_chat_space_url }} # returns string
{{ incident.google_chat_space_short_url }} # returns string
{{ incident.google_chat_space_archived }} # returns boolean
{{ incident.google_chat_space_domain_id }} # returns string
{{ incident.service_now_incident_id }} # returns string
{{ incident.service_now_incident_url }} # returns string
{{ incident.opsgenie_incident_id }} # returns string
{{ incident.opsgenie_incident_url }} # returns string
{{ incident.victor_ops_incident_id }} # returns string
{{ incident.victor_ops_incident_url }} # returns string
{{ incident.pagerduty_incident_id }} # returns string
{{ incident.pagerduty_incident_number }} # returns string
{{ incident.pagerduty_incident_url }} # returns string
{{ incident.mattermost_channel_id }} # returns string
{{ incident.mattermost_channel_name }} # returns string
{{ incident.mattermost_channel_url }} # returns string
{{ incident.confluence_page_id }} # returns string
{{ incident.confluence_page_url }} # returns string
{{ incident.airtable_base_key }} # returns string
{{ incident.airtable_table_name }} # returns string
{{ incident.airtable_record_id }} # returns string
{{ incident.airtable_record_url }} # returns string
{{ incident.google_drive_id }} # returns string
{{ incident.google_drive_url }} # returns string
{{ incident.notion_page_id }} # returns string
{{ incident.notion_page_url }} # returns string
{{ incident.datadog_notebook_id }} # returns string
{{ incident.datadog_notebook_url }} # returns string
{{ incident.freshservice_ticket_id }} # returns string
{{ incident.freshservice_ticket_url }} # returns string
{{ incident.freshservice_task_id }} # returns string
{{ incident.freshservice_task_url }} # returns string
```
## Examples
```ruby Ruby theme={null}
incident-{{ incident.started_at | date: "%Y%m%d" }}-{{ incident.slug }}
# Will result in: incident-20210412-customers-unable-to-place-orders-on-our-website
incident-{{ incident.created_at | date: "%Y%m%d" }}-{{ incident.jira_issue_url | split: "/" | last}}
# Will result in: incident-20210412-ROOT-233
{{ incident.created_at | in_time_zone: "Europe/London" | date: "%Y-%m-%d" }}
# Will result in: 2021-04-12
```
## List Roles
```ruby Ruby theme={null}
{%- for role in incident.roles -%}
{%- if role.user -%}
{{ role.incident_role.name }} : {{ role.user.full_name }}
{%- else -%}
{{ role.incident_role.name }} : N/A
{%- endif -%}
{%- endfor -%}
# Will result of:
# Commander: John Doe
# Scriber: N/A
```
## List Custom Fields
```ruby Ruby theme={null}
# Text Field
{{ incident.custom_fields | find: 'custom_field.slug', 'your_custom_field_slug' | get: 'selected_options.value' }}
# Select & Multi Select
{{ incident.custom_fields | find: 'custom_field.slug', 'your_custom_field_slug' | get: 'selected_options' | map: 'value' }}
# Select & Multi Select using Teams options
{{ incident.custom_fields | find: 'custom_field.slug', 'custom-field-groups' | get: 'selected_groups' | map: 'name' }}
# Select & Multi Select using Services options
{{ incident.custom_fields | find: 'custom_field.slug', 'custom-field-services' | get: 'selected_services' | map: 'name' }}
# Users Field
{{ incident.custom_fields | find: 'custom_field.slug', 'your_custom_field_slug' | get: 'selected_users' | map: 'full_name' }}
```
## List Timeline Events
```ruby Ruby theme={null}
{% for item in incident.events %}
{{ item.occurred_at }} - {{ item.event }}
{% endfor %}
```
## Convert Timeline Events to Table
```ruby Ruby theme={null}
# ASCII Table
{{ incident.events | to_table: 'events', 'Hello world', 'America/Los_Angeles' }}
# Returns
# +---------------------------------------------------+
# | Hello world |
# +------------------------------+----------+---------+
# | Date | User | Event |
# +------------------------------+----------+---------+
# | December 8 2022 23:04:28 PST | John D | Event 1 |
# | December 8 2022 23:04:28 PST | Dalyte K | Event 2 |
# +------------------------------+----------+---------+
# Markdown table
{{ incident.events | to_table: 'events', 'Hello world', 'America/Los_Angeles', 'markdown' }}
# Returns
# | Hello world |
# |------------------------------|----------|---------|
# | Date | User | Event |
# | December 8 2022 23:04:28 PST | John D | Event 1 |
# | December 8 2022 23:04:28 PST | Dalyte K | Event 2 |
# Atlassian table
{{ incident.events | to_table: 'events', 'Hello world', 'America/Los_Angeles', 'atlassian_markdown' }}
# Returns
# h2. Hello world
# ||Date||User||Event||
# |December 8 2022 23:04:28 PST|John D|Event 1. [Link|https://dummy]|
# |December 8 2022 23:04:28 PST|Dalyte K|Event 2. [Link|https://dummy]|
# HTML table
{{ incident.events | to_table: 'events', 'Hello world', 'America/Los_Angeles', 'html' }}
# Returns
# Hello world
#
#
# Date
# User
# Event
#
#
# December 8 2022 23:04:28 PST
# John D
# Event 1
#
#
# December 8 2022 23:04:28 PST
# Dalyte K
# Event 2
#
#
```
## List Action Items
```ruby Ruby theme={null}
{% for item in incident.action_items %}
{{ item.summary }}
Kind: {{item.kind}}
Priority: {{item.priority}}
Status: {{item.status}}
{% endfor %}
```
## Convert Action Items to Table
```ruby Ruby theme={null}
# ASCII Table
{{ incident.action_items | to_table: 'action_items', 'Hello world', 'America/Los_Angeles' }}
# Returns
# +------------------------------------------------------------------------------------------------------------------------+
# | Hello world |
# +------------------------------+------------------------------+-----------+----------+--------+----------+---------------+
# | Creation Date | Due Date | Kind | Priority | Status | Assignee | Summary |
# +------------------------------+------------------------------+-----------+----------+--------+----------+---------------+
# | December 7 2022 23:04:28 PST | December 8 2022 00:00:00 PST | Task | Low | Open | John D | Action Item 1 |
# | December 7 2022 23:04:28 PST | December 8 2022 00:00:00 PST | Follow Up | High | Done | Dalyte K | Action Item 2 |
# +------------------------------+------------------------------+-----------+----------+--------+----------+---------------+
# Markdown table
{{ incident.action_items | to_table: 'action_items', 'Hello world', 'America/Los_Angeles', 'markdown' }}
# Returns
# | Hello world |
# |------------------------------|------------------------------|-----------|----------|--------|----------|---------------|
# | Creation Date | Due Date | Kind | Priority | Status | Assignee | Summary |
# | December 7 2022 23:04:28 PST | December 8 2022 00:00:00 PST | Task | Low | Open | John D | Action Item 1 |
# | December 7 2022 23:04:28 PST | December 8 2022 00:00:00 PST | Follow Up | High | Done | Dalyte K | Action Item 2 |
# Atlassian table
{{ incident.action_items | to_table: 'action_items', 'Hello world', 'America/Los_Angeles', 'atlassian_markdown' }}
# Returns
# h2. Hello world
# ||Creation Date||Due Date||Kind||Priority||Status||Assignee||Summary||
# |December 7 2022 23:04:28 PST|December 8 2022 00:00:00 PST|Task|Low|Open|John D|Action Item 1. [Link|https://dummy]|
# |December 7 2022 23:04:28 PST|December 8 2022 00:00:00 PST|Follow Up|High|Done|Dalyte K|Action Item 2. [Link|https://dummy]|
# HTML table
{{ incident.action_items | to_table: 'action_items', 'Hello world', 'America/Los_Angeles', 'html' }}
# Returns
# Hello world
#
#
#
# Creation Date
# Due Date
# Kind
# Priority
# Status
# Assignee
# Summary
#
#
# December 7 2022 23:04:28 PST
# December 8 2022 00:00:00 PST
# Task
# Low
# Open
# John D
# Action Item 1
#
#
# December 7 2022 23:04:28 PST
# December 8 2022 00:00:00 PST
# Follow Up
# High
# Done
# Dalyte K
# Action Item 2
#
#
```
## Additional Filters
```ruby Ruby theme={null}
# Find
# Input: {"books": [{ "id": 1, title: "hello" }, { "id": 2, title: "world" }] }
# Output: { "id": 2, title: "world" }
{ hash.books | find: 'id', '2' }
# Get
# Input: {"books": [{ "id": 1, title: "hello", category: {name: "History"} }}, { "id": 2, title: "world", category: {name: "SciFi"} }] }
# Output: "SciFi"
{ hash.books | find: 'id', '2' | get: 'category.name'}
# in_time_zone
{ 'now' | in_time_zone: "Europe/London" }
# smart_date
{ 'now' | smart_date: '2 days ago' }
{ 'now' | smart_date: '2 days ago' | in_time_zone: "Europe/London" }
{ 'now' | smart_date: '4 days from now' | in_time_zone: "Europe/London" }
{ 'now' | smart_date: 'yesterday' | in_time_zone: "Europe/London" }
# iso8601
{ 'now' | to_iso8601 }
# Distance of time in words
{ 'now' | smart_date: '2 days ago' | distance_of_time_in_words_from_now } # 2 days
```
***
## Related Pages
Reference follow-ups linked to the incident from action item workflows.
Reference team attributes — owners, Slack channels, on-call responders — from workflows.
Reference alert attributes from alert workflows and routing actions.
# Liquid templating in Rootly workflows
Source: https://docs.rootly.com/liquid/liquid
Learn how to use the Liquid templating engine in Rootly workflows to dynamically manipulate data, format content, and create powerful automation expressions.
Rootly supports the use of the [Liquid](https://shopify.github.io/liquid/ "Liquid") templating engine in Workflows Tasks. Liquid provides a number of useful filters which can be used to manipulate the contents of options blocks. For example, the expression `{{ 'hello' | upcase }}` uses the upcase filter, when inserted into an options block it will render HELLO. You can string multiple Liquid filters together, with the expression processed left-to-right.
You can find the variables on the following pages:
* [Task Output Variables](/liquid/task-output-variables)
* [Incident Variables](/liquid/incident-variables)
* [Action Item Variables](/liquid/action-item-variables)
* [Alert Variables](/liquid/alert-variables)
* [Pulse Variables](/liquid/pulse-variables)
* [Team Variables](/liquid/team-variables)
* [Secrets](/liquid/secrets)
* [Timezones](/liquid/timezones)
## Examples
### Get the Current Date and Time in yyyymmdd Format
Expression: `{{ "now" | date: "%Y-%m-%d" }}`
Sample result: "2018-04-24"
[Reference](https://shopify.github.io/liquid/filters/date/ "Reference")
### Get the Size of an Array and Multiply by 10
Expression: `{{ .my_array | size | times: 10 }}`
Sample result: 50
[Reference](https://shopify.github.io/liquid/filters/size/ "Reference")
## Full List of Available Filters
[Available filters](/liquid/filters)
# Pulse Variables
Source: https://docs.rootly.com/liquid/pulse-variables
Reference for pulse variables available in Liquid templates for processing health check, deploy, and monitoring data in Rootly workflows and integrations.
You can use pulse variables in pulse workflows and any Liquid template evaluated in a pulse context.
Use the [Liquid Markup explorer](https://rootly.com/account/help/liquid-explorer) to navigate through all pulse variables against real pulse data.
Rootly uses the [Liquid](https://shopify.github.io/liquid/) template language. The variables below are available wherever a pulse is in scope.
## Variables
```ruby Ruby theme={null}
{{ pulse.id }} # returns string (uuid)
{{ pulse.short_id }} # returns string
{{ pulse.source }} # returns string — name of the pulse source (e.g., "github", "k8s", "generic")
{{ pulse.summary }} # returns string
{{ pulse.data }} # returns the raw pulse payload as a JSON object
```
## Examples
Reaching into the raw pulse payload:
```ruby Ruby theme={null}
{{ pulse.data | get: 'commit_sha' }}
```
Building a deploy-style summary line:
```ruby Ruby theme={null}
{{ pulse.source | titleize }} pulse {{ pulse.short_id }}: {{ pulse.summary }}
```
***
## Related Pages
The workflow type that consumes pulses — where these variables are used.
Reference incident attributes when a pulse converts into or updates an incident.
Reference alert attributes from adjacent alert workflows.
# Secrets
Source: https://docs.rootly.com/liquid/secrets
Learn how to access stored secrets in Liquid templates using the secrets variable for secure credential management in Rootly workflows and integrations.
The `secrets` variable lets you reference stored secrets — API keys, tokens, and passwords — inside Liquid templates. Instead of hardcoding sensitive values into your workflow configurations, you reference a secret by name and Rootly resolves the actual value at runtime, so the value itself never appears in your workflow definition.
## Variables
Rootly uses the [Liquid](https://shopify.github.io/liquid/ "Liquid") template language. The available variables are:
```ruby Ruby theme={null}
{{ secrets.name }} # returns secret value
```
## Usage
Secrets are most commonly used in workflow tasks that call external systems, such as HTTP request actions that need an authorization header. Because the expression is just Liquid, you can combine secrets with [filters](/liquid/filters) like any other variable. For example, to build a Basic authentication header:
```ruby Ruby theme={null}
Authorization: Basic {{ secrets.username | append: ':' | append: secrets.password | base64_encode }}
```
If your secrets are backed by the [HashiCorp Vault integration](/integrations/hashicorp-vault), values are read from Vault at runtime and JSON secret values are traversed using dot notation:
```ruby Ruby theme={null}
{{ secrets.SECRET_NAME.KEY_NAME }}
```
The key path in your template must match the JSON structure of the stored secret exactly, including case.
Managing secret definitions is restricted to Rootly owners and admins by default. If you need a new secret reference, ask an admin to create it for you.
## Related pages
* [Liquid templating overview](/liquid/liquid) — how Liquid works in Rootly workflows
* [Liquid filters](/liquid/filters) — the full list of filters you can chain with secrets
* [HashiCorp Vault integration](/integrations/hashicorp-vault) — read secrets from your Vault cluster at runtime
# Task Output Variables
Source: https://docs.rootly.com/liquid/task-output-variables
Reference previous workflow action outputs using Liquid template variables to chain Rootly actions together, pass data between steps, and build pipelines.
Every workflow action stores its output after it completes. Subsequent actions in the same workflow can reference those outputs using Liquid template syntax. This lets you chain actions together — for example, fetch data with an HTTP request and pass the response into an AI prompt or a second API call.
## Syntax
Reference a previous action's output using the `tasks` object and the action's **slug**:
```text theme={null}
{{ tasks.. }}
```
The action slug is a URL-friendly identifier derived from the action's name when the action is **first created**: the name is lowercased and spaces become hyphens, so an action named "Get service" becomes `get-service`.
An action's slug is locked in when the action is created and does **not** change if you rename the action later. An action first created as "Get service from Rootly" keeps the slug `get-service-from-rootly` even after it's renamed to "Get service". Slugs always use hyphens, never underscores — `get-service`, not `get_service`.
## Finding an Action's Slug
### While Authoring (Before The Workflow Has Run)
When you're building the workflow for the first time and don't yet have a completed run to copy from, derive the slug from the action's **original** name (the name set when the action was first created): lowercase it and replace spaces with hyphens. An action created as "Get service from Rootly" has the slug `get-service-from-rootly` — even if you later rename it to "Get service". Use this derived slug as your initial reference, then confirm it from the run results below as soon as the workflow runs once.
### After A Successful Run (Authoritative)
The slug isn't shown in the workflow editor or returned by the API, so the most reliable way to confirm it is from a completed run:
1. Run the workflow once, or open a previous run.
2. Open the action in the run results.
3. Select the **Output** tab. Rootly displays the exact `tasks....` reference to copy, so you never have to read it off the action name.
## Available Properties
Each completed action exposes the following properties:
| Property | Description |
| --------------------------- | ------------------------------------------------------------------------- |
| `tasks..name` | Action name |
| `tasks..slug` | Action slug identifier |
| `tasks..status` | Execution status (`queued`, `started`, `completed`, `failed`, `canceled`) |
| `tasks..output` | Action output (structure varies by action type — see below) |
| `tasks..logs` | Event logs from the action |
| `tasks..started_at` | When the action started |
| `tasks..completed_at` | When the action completed |
| `tasks..failed_at` | When the action failed (if applicable) |
***
## HTTP Request Action Output
The **Fetch an HTTP endpoint** action stores the full HTTP response. Access it through `output.response`:
| Path | Description |
| -------------------------------------- | ---------------------------------------------- |
| `tasks..output.response.status` | HTTP status code |
| `tasks..output.response.body` | Response body (parsed as JSON when applicable) |
| `tasks..output.response.headers` | Response headers |
### Accessing Nested JSON
When the HTTP response returns JSON, you can traverse the parsed structure directly:
```text theme={null}
{{ tasks.my-http-request.output.response.body.data.id }}
{{ tasks.my-http-request.output.response.body.items[0].name }}
```
***
## AI Chat Completion Action Output
The **OpenAI**, **Anthropic**, **Google Gemini**, and **Mistral** chat completion actions store the AI model's response in `output.response`. The exact structure depends on the provider and model.
### OpenAI
OpenAI uses two different API formats depending on the model:
**GPT models** (`gpt-4o`, `gpt-4o-mini`, etc.) use the Chat Completions API:
```text theme={null}
{{ tasks.my-openai-task.output.response.choices[0].message.content }}
```
**Reasoning models** (`o1-*`, `o3-*`) use the Responses API, which returns a different structure:
```text theme={null}
{{ tasks.my-openai-task.output.response.output[0].content[0].text }}
```
If you switch between GPT and reasoning models, you must update the output path in any downstream actions that reference the task output.
### Google Gemini
```text theme={null}
{{ tasks.my-gemini-task.output.response.candidates[0].content.parts[0].text }}
```
***
## Other Action Outputs
Most built-in actions (Create Jira Issue, Create Linear Issue, Send Slack Message, etc.) store their response in `output.response`. The structure matches the response from the underlying integration API.
Examples:
```text theme={null}
{{ tasks.create-a-jira-issue.output.response.key }}
{{ tasks.create-a-linear-issue.output.response.data.issueCreate.issue.url }}
{{ tasks.create-a-linear-issue.output.response.data.issueCreate.issue.identifier }}
```
***
## Examples
### Chain Two HTTP Requests
Fetch a service catalog entry, then use part of the response in a follow-up API call.
**Action 1** — "get-service-info" (HTTP GET):
```text theme={null}
URL: https://api.example.com/v1/catalog/{{ incident.services.first }}
```
**Action 2** — "get-owner" (HTTP GET) referencing Action 1's output:
```text theme={null}
URL: https://api.example.com/v1/catalog/{{ tasks.get-service-info.output.response.body.hierarchy.parents[0].tag }}
```
### Use HTTP response in action URL parameters
Look up a user by email from a previous action's response:
```text theme={null}
https://api.rootly.com/v1/users?filter[email]={{ tasks.get-on-call-from-opsgenie.output.response.body.data.onCallRecipients[0] | default: 'fallback@example.com' }}
```
### Feed HTTP response into an OpenAI prompt
Fetch logs from an observability tool, then have AI analyze them.
**Action 1** — "get-logs" (HTTP GET to your logging API)
**Action 2** — "analyze-logs" (OpenAI Chat Completion) with prompt:
```text theme={null}
Analyze the following service logs for errors and anomalies.
Format your response for Slack using mrkdwn.
{{ tasks.get-logs.output.response.body.data.result }}
```
### Pass AI output into a subsequent HTTP request
Generate a postmortem with AI, then post it to the incident timeline.
**Action 1** — "generate-postmortem" (OpenAI Chat Completion)
**Action 2** — "post-to-timeline" (HTTP POST):
```text theme={null}
URL: https://api.rootly.com/v1/incidents/{{ incident.id }}/events
Body:
{
"data": {
"attributes": {
"visibility": "internal",
"event": {{ tasks.generate-postmortem.output.response.choices[0].message.content | to_json }}
},
"type": "incident_events"
}
}
```
Use the `to_json` filter when inserting task output into a JSON body. AI-generated text often contains quotes and newlines that break JSON syntax without proper escaping.
### Use Jira/Linear issue output to update an alert
Create a ticket, then write the ticket URL back to a custom alert field.
**Action 1** — "create-a-linear-issue" (Create Linear Issue)
**Action 2** — "update-alert-with-ticket" (HTTP PATCH):
```text theme={null}
URL: https://api.rootly.com/v1/alerts/{{ alert.id }}
Body:
{
"data": {
"attributes": {
"alert_field_values_attributes": [
{
"alert_field_id": "",
"value": "{{ tasks.create-a-linear-issue.output.response.data.issueCreate.issue.url }}"
}
]
},
"type": "alerts"
}
}
```
### Assign a role based on an on-call lookup
Look up who is on-call, find them in Rootly, then assign them to an incident role.
**Action 1** — "get-on-call" (HTTP GET to your paging provider)
**Action 2** — "find-rootly-user" (HTTP GET):
```text theme={null}
https://api.rootly.com/v1/users?filter[email]={{ tasks.get-on-call.output.response.body.data.onCallRecipients[0] }}
```
**Action 3** — "assign-role" (HTTP POST):
```text theme={null}
URL: https://api.rootly.com/v1/incidents/{{ incident.id }}/assign_role_to_user
Body:
{
"data": {
"type": "incidents",
"attributes": {
"user_id": "{{ tasks.find-rootly-user.output.response.body.data[0].id }}",
"incident_role_id": ""
}
}
}
```
***
## Using Liquid Filters with Task Outputs
You can apply any [Liquid filter](/liquid/filters) to task output values. Common patterns:
```text theme={null}
{{ tasks.my-task.output.response.body.name | upcase }}
{{ tasks.my-task.output.response.body.email | default: 'fallback@example.com' }}
{{ tasks.my-task.output.response.body.query | replace: '+', '' }}
{{ tasks.my-task.output.response.body.items | size }}
```
***
## Troubleshooting
### Action Output Is Empty
* Verify the referenced action ran successfully. Check the workflow run log for errors.
* Check that the action slug matches exactly — slugs are case-sensitive and use hyphens, not underscores (for example, `my-http-request`, not `my_http_request`).
### JSON Path Returns Nothing
* The HTTP response body is only parsed as JSON when the response `Content-Type` is `application/json`. If the API returns a different content type, `body` may be a raw string.
* Use the workflow run log to inspect the actual response structure and verify your path.
### Subsequent Action Does Not See the Previous Output
* Actions run sequentially in order. An action can only reference outputs from actions that appear **above** it in the workflow editor.
* If the previous action has **Skip on Failure** enabled and failed, its output may be incomplete or missing.
### Variable Is Undefined After Renaming an Action
* A reference that broke after you renamed an action is using the new name. The slug is fixed at creation and doesn't change on rename. Use the original slug, or copy the exact reference from the **Output** tab of a completed run (see [Finding an action's slug](#finding-an-actions-slug)).
# Team Variables
Source: https://docs.rootly.com/liquid/team-variables
Reference guide for team variables available in Liquid templates including team metrics, member data, on-call assignments, and integration mappings in Rootly.
Team variables expose team-level data — names and slugs, incident and action item counts, configuration flags, user lists, and objects like services, schedules, and functionalities — for use in Liquid templates. You can use them anywhere Rootly supports [Liquid templating](/liquid/liquid), such as workflow task option blocks, to make your automations aware of team context.
Like [incident variables](/liquid/incident-variables), team variables are plain Liquid expressions, so you can chain [filters](/liquid/filters) onto them to transform values, look items up in arrays, or format output. The `team.users` array is particularly useful for reverse lookups — for example, resolving a user's Slack ID from their email address (see the example below).
## Variables
Use the [Liquid Markup explorer](https://rootly.com/account/help/liquid-explorer "Liquid Markup explorer") to navigate through all team variables.
Rootly uses the [Liquid](https://shopify.github.io/liquid/ "Liquid") template language. The available variables are:
```ruby Ruby theme={null}
# Basic team info
{{ team.id }} # returns string
{{ team.name }} # returns string
{{ team.slug }} # returns string
{{ team.time_zone }} # returns string
{{ team.generated_incident_title }} # returns string
# Incident counts
{{ team.incidents_count }} # returns integer
{{ team.incidents_test_count }} # returns integer
{{ team.incidents_normal_count }} # returns integer
{{ team.incidents_scheduled_count }} # returns integer
{{ team.incidents_backfilled_count }} # returns integer
# Action item counts
{{ team.action_items_count }} # returns integer
{{ team.action_items_follow_up_count }} # returns integer
{{ team.action_items_task_count }} # returns integer
{{ team.action_items_open_count }} # returns integer
{{ team.action_items_in_progress_count }} # returns integer
{{ team.action_items_cancelled_count }} # returns integer
{{ team.action_items_completed_count }} # returns integer
# Configuration flags
{{ team.config_ai_enabled }} # returns boolean
{{ team.config_ai_summarization_enabled }} # returns boolean
{{ team.config_ai_similarities_enabled }} # returns boolean
{{ team.config_sub_status_enabled }} # returns boolean
# User arrays
{{ team.users }} # returns array
{{ team.jira_users }} # returns array
{{ team.pagerduty_users }} # returns array
# Objects (keyed by slug)
{{ team.form_fields }} # returns object
{{ team.post_mortem_templates }} # returns object (keyed by slug)
{{ team.schedules }} # returns object (keyed by slug)
{{ team.services }} # returns object (keyed by slug)
{{ team.functionalities }} # returns object (keyed by slug)
{{ team.groups }} # returns object (keyed by slug)
```
## Examples
### User Reverse Lookup by Email
```ruby Ruby theme={null}
{{ team.users | find: 'email', 'john@doe.com' | get: 'name' }}
{{ team.users | find: 'email', 'john@doe.com' | get: 'slack_id' }}
```
***
## Related Pages
Reference the incident an action or workflow is running against.
Reference alert attributes from alert workflows and routing actions.
Reference follow-up and remediation action items from workflows.
# Timezones
Source: https://docs.rootly.com/liquid/timezones
Complete list of timezone identifiers for use with the in_time_zone Liquid filter in Rootly workflows to convert dates and times across global teams.
This page lists every timezone identifier you can use with the `in_time_zone` Liquid filter in Rootly. Use these values to convert dates and times into a specific timezone when formatting output in workflows and templates.
## How to use timezone values
To use with `in_time_zone` liquid filter
```js JS theme={null}
{{ now | in_time_zone: 'Europe/London' | date: '%Y-%m-%d %H:%M %Z' }}
```
## Supported Timezone Values
| Timezone | Offset |
| -------------------------------- | ------ |
| Pacific/Niue | UTC-11 |
| Pacific/Midway | UTC-11 |
| Pacific/Pago\_Pago | UTC-11 |
| America/Adak | UTC-10 |
| Pacific/Tahiti | UTC-10 |
| Pacific/Marquesas | UTC-10 |
| Pacific/Honolulu | UTC-10 |
| Pacific/Rarotonga | UTC-10 |
| America/Sitka | UTC-9 |
| America/Anchorage | UTC-9 |
| Pacific/Gambier | UTC-9 |
| America/Metlakatla | UTC-9 |
| America/Yakutat | UTC-9 |
| America/Nome | UTC-9 |
| America/Juneau | UTC-9 |
| America/Vancouver | UTC-8 |
| America/Tijuana | UTC-8 |
| Pacific/Pitcairn | UTC-8 |
| America/Los\_Angeles | UTC-8 |
| America/Boise | UTC-7 |
| America/Phoenix | UTC-7 |
| America/Dawson | UTC-7 |
| America/Whitehorse | UTC-7 |
| America/Fort\_Nelson | UTC-7 |
| America/Dawson\_Creek | UTC-7 |
| America/Mazatlan | UTC-7 |
| America/Cambridge\_Bay | UTC-7 |
| America/Hermosillo | UTC-7 |
| America/Creston | UTC-7 |
| America/Edmonton | UTC-7 |
| America/Inuvik | UTC-7 |
| America/Yellowknife | UTC-7 |
| America/Denver | UTC-7 |
| America/Managua | UTC-6 |
| America/Bahia\_Banderas | UTC-6 |
| America/Ojinaga | UTC-6 |
| America/Chihuahua | UTC-6 |
| America/Matamoros | UTC-6 |
| America/Monterrey | UTC-6 |
| America/Merida | UTC-6 |
| America/Mexico\_City | UTC-6 |
| America/North\_Dakota/Beulah | UTC-6 |
| America/North\_Dakota/New\_Salem | UTC-6 |
| America/North\_Dakota/Center | UTC-6 |
| America/Menominee | UTC-6 |
| America/Indiana/Knox | UTC-6 |
| America/Indiana/Tell\_City | UTC-6 |
| America/Chicago | UTC-6 |
| America/Belize | UTC-6 |
| America/Winnipeg | UTC-6 |
| America/Resolute | UTC-6 |
| America/Rankin\_Inlet | UTC-6 |
| America/Regina | UTC-6 |
| America/Swift\_Current | UTC-6 |
| Pacific/Easter | UTC-6 |
| America/Costa\_Rica | UTC-6 |
| America/El\_Salvador | UTC-6 |
| Pacific/Galapagos | UTC-6 |
| America/Guatemala | UTC-6 |
| America/Tegucigalpa | UTC-6 |
| America/Grand\_Turk | UTC-5 |
| America/Cancun | UTC-5 |
| America/Toronto | UTC-5 |
| America/Iqaluit | UTC-5 |
| America/Pangnirtung | UTC-5 |
| America/Atikokan | UTC-5 |
| America/Indiana/Vincennes | UTC-5 |
| America/Detroit | UTC-5 |
| America/Indiana/Indianapolis | UTC-5 |
| America/New\_York | UTC-5 |
| America/Port-au-Prince | UTC-5 |
| America/Eirunepe | UTC-5 |
| America/Jamaica | UTC-5 |
| America/Indiana/Winamac | UTC-5 |
| America/Cayman | UTC-5 |
| America/Kentucky/Monticello | UTC-5 |
| America/Rio\_Branco | UTC-5 |
| America/Nassau | UTC-5 |
| America/Indiana/Marengo | UTC-5 |
| America/Panama | UTC-5 |
| America/Guayaquil | UTC-5 |
| America/Bogota | UTC-5 |
| America/Lima | UTC-5 |
| America/Havana | UTC-5 |
| America/Indiana/Petersburg | UTC-5 |
| America/Kentucky/Louisville | UTC-5 |
| America/Indiana/Vevay | UTC-5 |
| America/Porto\_Velho | UTC-4 |
| America/Boa\_Vista | UTC-4 |
| America/Manaus | UTC-4 |
| America/St\_Lucia | UTC-4 |
| America/St\_Barthelemy | UTC-4 |
| America/Caracas | UTC-4 |
| America/Tortola | UTC-4 |
| America/St\_Vincent | UTC-4 |
| America/Marigot | UTC-4 |
| America/Santiago | UTC-4 |
| America/Martinique | UTC-4 |
| America/Port\_of\_Spain | UTC-4 |
| America/Curacao | UTC-4 |
| America/St\_Thomas | UTC-4 |
| America/Lower\_Princes | UTC-4 |
| America/St\_Kitts | UTC-4 |
| America/Dominica | UTC-4 |
| America/Santo\_Domingo | UTC-4 |
| America/Barbados | UTC-4 |
| America/Guyana | UTC-4 |
| America/Kralendijk | UTC-4 |
| America/Guadeloupe | UTC-4 |
| America/Thule | UTC-4 |
| America/Montserrat | UTC-4 |
| America/Puerto\_Rico | UTC-4 |
| America/Grenada | UTC-4 |
| America/Asuncion | UTC-4 |
| America/Halifax | UTC-4 |
| America/Glace\_Bay | UTC-4 |
| America/Moncton | UTC-4 |
| America/Goose\_Bay | UTC-4 |
| America/Blanc-Sablon | UTC-4 |
| America/Campo\_Grande | UTC-4 |
| America/Cuiaba | UTC-4 |
| Atlantic/Bermuda | UTC-4 |
| America/Anguilla | UTC-4 |
| America/Aruba | UTC-4 |
| America/Antigua | UTC-4 |
| America/La\_Paz | UTC-4 |
| America/Paramaribo | UTC-3 |
| America/Belem | UTC-3 |
| America/Fortaleza | UTC-3 |
| America/Recife | UTC-3 |
| America/Araguaina | UTC-3 |
| America/Maceio | UTC-3 |
| America/Bahia | UTC-3 |
| America/Sao\_Paulo | UTC-3 |
| America/Santarem | UTC-3 |
| America/Argentina/Catamarca | UTC-3 |
| America/Argentina/La\_Rioja | UTC-3 |
| America/Argentina/Ushuaia | UTC-3 |
| America/Argentina/Rio\_Gallegos | UTC-3 |
| America/Argentina/San\_Luis | UTC-3 |
| America/Argentina/Mendoza | UTC-3 |
| America/Montevideo | UTC-3 |
| America/Punta\_Arenas | UTC-3 |
| America/Argentina/San\_Juan | UTC-3 |
| Antarctica/Palmer | UTC-3 |
| Antarctica/Rothera | UTC-3 |
| America/Argentina/Buenos\_Aires | UTC-3 |
| Atlantic/Stanley | UTC-3 |
| America/Argentina/Cordoba | UTC-3 |
| America/Argentina/Salta | UTC-3 |
| America/Cayenne | UTC-3 |
| America/Argentina/Jujuy | UTC-3 |
| America/Nuuk | UTC-3 |
| America/Argentina/Tucuman | UTC-3 |
| America/Miquelon | UTC-3 |
| America/Noronha | UTC-2 |
| Atlantic/South\_Georgia | UTC-2 |
| America/Scoresbysund | UTC-1 |
| Atlantic/Cape\_Verde | UTC-1 |
| Atlantic/Azores | UTC-1 |
| Africa/Accra | UTC+0 |
| Africa/Monrovia | UTC+0 |
| Europe/Jersey | UTC+0 |
| America/Danmarkshavn | UTC+0 |
| Africa/Dakar | UTC+0 |
| Africa/Banjul | UTC+0 |
| Africa/Conakry | UTC+0 |
| Africa/El\_Aaiun | UTC+0 |
| Europe/Isle\_of\_Man | UTC+0 |
| Africa/Sao\_Tome | UTC+0 |
| Atlantic/Reykjavik | UTC+0 |
| Africa/Bissau | UTC+0 |
| Europe/Dublin | UTC+0 |
| Antarctica/Troll | UTC+0 |
| Africa/Nouakchott | UTC+0 |
| Africa/Lome | UTC+0 |
| Africa/Ouagadougou | UTC+0 |
| Atlantic/St\_Helena | UTC+0 |
| Atlantic/Madeira | UTC+0 |
| Europe/Lisbon | UTC+0 |
| Atlantic/Faroe | UTC+0 |
| Africa/Bamako | UTC+0 |
| Europe/London | UTC+0 |
| Africa/Abidjan | UTC+0 |
| Africa/Freetown | UTC+0 |
| Atlantic/Canary | UTC+0 |
| Africa/Casablanca | UTC+0 |
| Europe/Guernsey | UTC+0 |
| Europe/Andorra | UTC+1 |
| Europe/Tirane | UTC+1 |
| Africa/Luanda | UTC+1 |
| Europe/Vienna | UTC+1 |
| Europe/Sarajevo | UTC+1 |
| Europe/Brussels | UTC+1 |
| Africa/Porto-Novo | UTC+1 |
| Africa/Kinshasa | UTC+1 |
| Africa/Bangui | UTC+1 |
| Africa/Brazzaville | UTC+1 |
| Europe/Zurich | UTC+1 |
| Africa/Douala | UTC+1 |
| Europe/Prague | UTC+1 |
| Europe/Berlin | UTC+1 |
| Europe/Busingen | UTC+1 |
| Europe/Copenhagen | UTC+1 |
| Africa/Algiers | UTC+1 |
| Europe/Madrid | UTC+1 |
| Africa/Ceuta | UTC+1 |
| Europe/Paris | UTC+1 |
| Africa/Libreville | UTC+1 |
| Europe/Gibraltar | UTC+1 |
| Africa/Malabo | UTC+1 |
| Europe/Zagreb | UTC+1 |
| Europe/Budapest | UTC+1 |
| Europe/Rome | UTC+1 |
| Europe/Vaduz | UTC+1 |
| Europe/Luxembourg | UTC+1 |
| Europe/Monaco | UTC+1 |
| Europe/Podgorica | UTC+1 |
| Europe/Skopje | UTC+1 |
| Europe/Malta | UTC+1 |
| Africa/Niamey | UTC+1 |
| Africa/Lagos | UTC+1 |
| Europe/Amsterdam | UTC+1 |
| Europe/Oslo | UTC+1 |
| Europe/Warsaw | UTC+1 |
| Europe/Belgrade | UTC+1 |
| Europe/Stockholm | UTC+1 |
| Europe/Ljubljana | UTC+1 |
| Arctic/Longyearbyen | UTC+1 |
| Europe/Bratislava | UTC+1 |
| Europe/San\_Marino | UTC+1 |
| Africa/Ndjamena | UTC+1 |
| Africa/Tunis | UTC+1 |
| Europe/Vatican | UTC+1 |
| Europe/Riga | UTC+2 |
| Europe/Vilnius | UTC+2 |
| Africa/Maseru | UTC+2 |
| Europe/Kaliningrad | UTC+2 |
| Europe/Bucharest | UTC+2 |
| Asia/Hebron | UTC+2 |
| Asia/Gaza | UTC+2 |
| Europe/Athens | UTC+2 |
| Asia/Jerusalem | UTC+2 |
| Asia/Beirut | UTC+2 |
| Africa/Gaborone | UTC+2 |
| Africa/Mbabane | UTC+2 |
| Europe/Kyiv | UTC+2 |
| Asia/Famagusta | UTC+2 |
| Europe/Tallinn | UTC+2 |
| Africa/Juba | UTC+2 |
| Africa/Blantyre | UTC+2 |
| Europe/Chisinau | UTC+2 |
| Africa/Cairo | UTC+2 |
| Europe/Helsinki | UTC+2 |
| Africa/Bujumbura | UTC+2 |
| Africa/Khartoum | UTC+2 |
| Africa/Lusaka | UTC+2 |
| Africa/Tripoli | UTC+2 |
| Africa/Johannesburg | UTC+2 |
| Africa/Lubumbashi | UTC+2 |
| Asia/Nicosia | UTC+2 |
| Africa/Kigali | UTC+2 |
| Europe/Sofia | UTC+2 |
| Europe/Mariehamn | UTC+2 |
| Africa/Maputo | UTC+2 |
| Africa/Windhoek | UTC+2 |
| Africa/Harare | UTC+2 |
| Europe/Istanbul | UTC+3 |
| Africa/Dar\_es\_Salaam | UTC+3 |
| Europe/Simferopol | UTC+3 |
| Africa/Kampala | UTC+3 |
| Indian/Antananarivo | UTC+3 |
| Indian/Comoro | UTC+3 |
| Africa/Nairobi | UTC+3 |
| Asia/Amman | UTC+3 |
| Asia/Tehran | UTC+3 |
| Asia/Baghdad | UTC+3 |
| Asia/Kuwait | UTC+3 |
| Antarctica/Syowa | UTC+3 |
| Asia/Qatar | UTC+3 |
| Europe/Moscow | UTC+3 |
| Europe/Kirov | UTC+3 |
| Europe/Volgograd | UTC+3 |
| Asia/Riyadh | UTC+3 |
| Asia/Bahrain | UTC+3 |
| Asia/Aden | UTC+3 |
| Africa/Addis\_Ababa | UTC+3 |
| Indian/Mayotte | UTC+3 |
| Africa/Asmara | UTC+3 |
| Africa/Mogadishu | UTC+3 |
| Africa/Djibouti | UTC+3 |
| Asia/Damascus | UTC+3 |
| Europe/Minsk | UTC+3 |
| Asia/Muscat | UTC+4 |
| Europe/Astrakhan | UTC+4 |
| Europe/Saratov | UTC+4 |
| Europe/Ulyanovsk | UTC+4 |
| Europe/Samara | UTC+4 |
| Indian/Reunion | UTC+4 |
| Indian/Mahe | UTC+4 |
| Asia/Baku | UTC+4 |
| Asia/Yerevan | UTC+4 |
| Asia/Dubai | UTC+4 |
| Asia/Kabul | UTC+4 |
| Asia/Tbilisi | UTC+4 |
| Indian/Mauritius | UTC+4 |
| Asia/Kathmandu | UTC+5 |
| Asia/Oral | UTC+5 |
| Asia/Atyrau | UTC+5 |
| Asia/Aqtau | UTC+5 |
| Asia/Tashkent | UTC+5 |
| Asia/Kolkata | UTC+5 |
| Asia/Samarkand | UTC+5 |
| Asia/Yekaterinburg | UTC+5 |
| Indian/Kerguelen | UTC+5 |
| Asia/Qyzylorda | UTC+5 |
| Asia/Dushanbe | UTC+5 |
| Asia/Ashgabat | UTC+5 |
| Indian/Maldives | UTC+5 |
| Antarctica/Mawson | UTC+5 |
| Asia/Aqtobe | UTC+5 |
| Asia/Colombo | UTC+5 |
| Asia/Karachi | UTC+5 |
| Antarctica/Vostok | UTC+6 |
| Asia/Dhaka | UTC+6 |
| Indian/Chagos | UTC+6 |
| Asia/Qostanay | UTC+6 |
| Asia/Omsk | UTC+6 |
| Asia/Bishkek | UTC+6 |
| Asia/Urumqi | UTC+6 |
| Asia/Thimphu | UTC+6 |
| Asia/Yangon | UTC+6 |
| Asia/Almaty | UTC+6 |
| Indian/Cocos | UTC+6 |
| Asia/Phnom\_Penh | UTC+7 |
| Asia/Bangkok | UTC+7 |
| Asia/Hovd | UTC+7 |
| Antarctica/Davis | UTC+7 |
| Asia/Ho\_Chi\_Minh | UTC+7 |
| Asia/Vientiane | UTC+7 |
| Asia/Pontianak | UTC+7 |
| Asia/Jakarta | UTC+7 |
| Asia/Novosibirsk | UTC+7 |
| Asia/Barnaul | UTC+7 |
| Asia/Tomsk | UTC+7 |
| Indian/Christmas | UTC+7 |
| Asia/Novokuznetsk | UTC+7 |
| Asia/Krasnoyarsk | UTC+7 |
| Asia/Kuching | UTC+8 |
| Australia/Perth | UTC+8 |
| Asia/Singapore | UTC+8 |
| Asia/Irkutsk | UTC+8 |
| Asia/Brunei | UTC+8 |
| Asia/Ulaanbaatar | UTC+8 |
| Asia/Makassar | UTC+8 |
| Asia/Manila | UTC+8 |
| Asia/Taipei | UTC+8 |
| Asia/Macau | UTC+8 |
| Asia/Kuala\_Lumpur | UTC+8 |
| Asia/Hong\_Kong | UTC+8 |
| Australia/Eucla | UTC+8 |
| Asia/Shanghai | UTC+8 |
| Asia/Choibalsan | UTC+8 |
| Asia/Tokyo | UTC+9 |
| Asia/Seoul | UTC+9 |
| Asia/Pyongyang | UTC+9 |
| Asia/Jayapura | UTC+9 |
| Pacific/Palau | UTC+9 |
| Asia/Chita | UTC+9 |
| Asia/Yakutsk | UTC+9 |
| Asia/Khandyga | UTC+9 |
| Asia/Dili | UTC+9 |
| Australia/Darwin | UTC+9 |
| Australia/Adelaide | UTC+9 |
| Australia/Broken\_Hill | UTC+9 |
| Australia/Lindeman | UTC+10 |
| Pacific/Port\_Moresby | UTC+10 |
| Australia/Sydney | UTC+10 |
| Australia/Melbourne | UTC+10 |
| Australia/Hobart | UTC+10 |
| Antarctica/Macquarie | UTC+10 |
| Australia/Lord\_Howe | UTC+10 |
| Asia/Vladivostok | UTC+10 |
| Pacific/Guam | UTC+10 |
| Pacific/Chuuk | UTC+10 |
| Asia/Ust-Nera | UTC+10 |
| Antarctica/DumontDUrville | UTC+10 |
| Pacific/Saipan | UTC+10 |
| Australia/Brisbane | UTC+10 |
| Pacific/Pohnpei | UTC+11 |
| Pacific/Bougainville | UTC+11 |
| Pacific/Efate | UTC+11 |
| Asia/Srednekolymsk | UTC+11 |
| Asia/Sakhalin | UTC+11 |
| Pacific/Norfolk | UTC+11 |
| Asia/Magadan | UTC+11 |
| Antarctica/Casey | UTC+11 |
| Pacific/Guadalcanal | UTC+11 |
| Pacific/Noumea | UTC+11 |
| Pacific/Kosrae | UTC+11 |
| Antarctica/McMurdo | UTC+12 |
| Pacific/Wallis | UTC+12 |
| Asia/Anadyr | UTC+12 |
| Asia/Kamchatka | UTC+12 |
| Pacific/Kwajalein | UTC+12 |
| Pacific/Fiji | UTC+12 |
| Pacific/Chatham | UTC+12 |
| Pacific/Auckland | UTC+12 |
| Pacific/Nauru | UTC+12 |
| Pacific/Majuro | UTC+12 |
| Pacific/Tarawa | UTC+12 |
| Pacific/Wake | UTC+12 |
| Pacific/Funafuti | UTC+12 |
| Pacific/Kanton | UTC+13 |
| Pacific/Fakaofo | UTC+13 |
| Pacific/Apia | UTC+13 |
| Pacific/Tongatapu | UTC+13 |
| Pacific/Kiritimati | UTC+14 |
# Managing Custom Catalogs
Source: https://docs.rootly.com/managing-custom-catalogs
Create custom catalogs, define properties, link catalogs together, and add entities to represent your organization's unique business concepts.
Catalogs are the foundation of everything else. This section walks through how to create them, customize them, and link them together.
## **Creating a new Catalog**
To create a new Catalog, navigate to Catalog in your Rootly settings and click **+ New catalog**. Give it a name that reflects what it represents, for example, "Product Areas" or "Supported Regions". Add a description to your Catalog so teammates know what it’s for and when to use it.
Properties let you describe what makes each entity unique. For example, a "Region" Catalog might have a "Cluster" property that tells you which infrastructure clusters belong to that region.
To add properties, open a Catalog and click **Edit catalog**, and click **Add Property**. You can choose from several property types, including text, boolean, and importantly references to other Catalogs.
One of the most powerful things you can do in Catalog is connect different Catalogs to each other. This lets you capture real-world relationships between your business entities.
For example:
* A "Teams" Catalog can have a property for "Owned Services", where each value is drawn from your "Services" Catalog.
* A "Customer Tier" Catalog can include a "Related Products" property that references your "Product Areas" Catalog.
To link Catalogs, add a new property to your Catalog and choose the other Catalog as the property type. Once linked, you’ll be able to select entities from that Catalog when filling in property values.
## **Adding entities to a Catalog**
Once your Catalog is set up, start populating it with entities. Each entity represents one specific item in that category: for example, "Payments API" in your Services Catalog.
For each entity, fill in the properties you’ve defined. If a property references another Catalog, you’ll select the relevant entity from a dropdown of what’s already in that Catalog.
# Attaching Teams To Incidents
Source: https://docs.rootly.com/managing-teams/attaching-teams-to-incidents
Associate teams with incidents to coordinate response, and configure workflows that automatically invite team members to the incident Slack channel.
Teams can be attached to incidents in Rootly to record which groups own the response and to drive automation around that ownership.
When a team is attached to an incident, Rootly can record team ownership on the timeline and fire workflows that target the team — for example, broadcasting the incident to the team's channel, paging on-call, or inviting team members into the incident Slack channel. The exact behavior depends on which workflows you have configured.
If the **Slack integration** is enabled, teams can be attached directly from Slack using Rootly's slash commands. Teams can also be attached from the web UI when creating or editing an incident.
***
## Attaching Teams via Slack
If your organization has configured the Slack integration, you can attach teams directly from the Slack incident channel.
To attach a team using Slack:
1. Open the **Slack channel associated with the incident**
2. Type the following command:
```text theme={null}
/rootly add team
```
3. Press **Enter**
Rootly will open a Slack modal where you can select one or more teams to attach to the incident.
You must run this command from the **incident-specific Slack channel**. The command will not work in other Slack channels.
***
## Attaching Teams from the Web UI
Teams can also be attached when creating an incident or by editing an existing incident in the Rootly web UI. Open the incident, edit the **Teams** field, and select one or more teams from the searchable picker.
Workflows triggered by team attachment fire in both paths — Slack and the web UI — provided the workflow's trigger and conditions match.
***
## Selecting Teams
After running the command, a dialog appears in Slack with a searchable list of available teams.
From this dialog you can:
* Search for teams by name
* Select one or multiple teams
* Review currently attached teams
* Submit the changes
Once you click **Submit**, the selected teams are attached to the incident.
***
## What Happens When a Team Is Attached
Attaching a team records the team on the incident and fires workflow triggers. Which trigger fires depends on when the team is attached:
* Teams chosen **at incident creation time** — fire as part of the `incident_created` trigger.
* Teams attached **after creation** (via `/rootly add team` or by editing the incident in the web UI) — fire the `teams_added` and `teams_updated` triggers.
The actual side effects of attachment depend on which workflows you have configured.
Workflows commonly built around team attachment include:
* **Inviting team members** into the incident Slack channel
* **Broadcasting** to the team's configured Slack channel
* **Paging** the team's on-call (via Rootly On-Call, PagerDuty, Opsgenie, etc.)
* **Creating tickets** in the team's project (Jira, Linear, etc.)
If you expect a behavior on team attachment and it isn't happening, the first thing to check is whether a matching workflow exists and whether its trigger fired. The Workflow Runs view on each incident shows every workflow Rootly evaluated, whether it matched, and any task errors.
***
## Automatically Inviting Team Members
Inviting team members to the incident Slack channel is configured once as an Incident Workflow and reused across every incident that matches your chosen trigger.
### Setting Up the Workflow
Build an [Incident Workflow](/workflows/incident-workflows) with these settings:
Pick the moment you want invites to fire. The two most useful triggers for this use case are:
* `incident_created` — fires when teams are selected at creation time
* `teams_added` — fires when a team is attached *after* creation (for example, via `/rootly add team`)
If you want invites for both paths, configure one workflow per trigger or use a workflow with multiple triggers.
Add the **Invite Rootly On-Call to Slack Channel** task. Despite the name, this task can target a Team in addition to an on-call schedule, escalation policy, service, or individual user. Set the **Target** to the team(s) whose members should be invited.
Add workflow conditions (severity, environment, service, etc.) only if you want to limit when invites fire. Leaving conditions empty means it fires on every incident matching the trigger.
This workflow is **not installed by default**. The smart-default "Invite Slack users and groups to incident channel" workflow that ships with Rootly invites a configured list of Slack user groups (for example, `@oncall-infra`), not Rootly team members.
### Who Gets Invited
When the **Invite Rootly On-Call to Slack Channel** task is targeted at a Team, it:
* Includes every member of each targeted Rootly team
* Checks whether each member has connected their Slack account in Rootly
* Invites the matching users to the incident channel
* Skips members who haven't connected Slack, then fails at the end of the task with an error listing the skipped members by name
Members who haven't connected Slack to Rootly never receive an invite. The fix is for those users to connect their Slack account from their Rootly user profile.
Because this task fails when any team member hasn't connected Slack, [a single task failure halts the workflow by default](/workflows/incident-workflows). If you want downstream tasks (for example, posting a status message) to run regardless, enable **Skip on Failure** on the invite task or place it last in the workflow.
### Other Targets
The same task can also target an escalation policy, a service, a schedule, or an individual user — useful when you want "invite whoever is on-call for this team" instead of "invite everyone on this team."
***
## Permissions
Attaching teams to incidents requires permission to update incidents.
If you attempt to run the Slack command without the required permissions, Rootly will return an authorization error.
In most organizations, these permissions are granted to:
* Incident responders
* Incident commanders
* Team administrators
* Organization administrators
If the command does not work for you, contact your Rootly administrator to confirm your access level.
***
## Troubleshooting
The command must be used inside an **incident Slack channel**. If the command is run in a regular Slack channel or a channel that is not linked to an incident, Rootly will not be able to identify the incident.
You may not have permission to update incidents. Attaching teams requires update access to the incident. Contact your administrator if you need this permission.
If no teams appear in the selection dialog, it may mean that no teams have been created in your Rootly organization yet. Teams can be created from the **Configuration → Teams** page.
Inviting team members is driven by a workflow, not by a setting on the team. Walk through this checklist:
1. **Does an invite workflow exist?** Open **Workflows** and confirm there's an Incident Workflow that uses the **Invite Rootly On-Call to Slack Channel** task with the team as Target.
2. **Did the workflow's trigger match this incident?** A workflow with trigger `incident_created` won't fire when a team is attached *after* creation; for that path you also need a workflow with trigger `teams_added`.
3. **Did the workflow run?** Open the incident's **Workflow Runs** view to see whether Rootly evaluated the workflow and what happened. If conditions (severity, environment, etc.) didn't match, the workflow won't have run.
4. **Have the team members connected their Slack accounts?** Members who haven't connected Slack to Rootly are skipped, and the task fails at the end with an error listing them by name. Have them connect Slack from their user profile.
5. **Is the Rootly Slack bot in the channel?** A private channel that the bot hasn't been added to will reject invites.
***
## Frequently Asked Questions
Attaching a team records team ownership on the incident and fires the `teams_added` and `teams_updated` workflow triggers. Any side effect — inviting members, broadcasting, paging on-call — is driven by workflows you configure.
Yes. Multiple teams can be attached to the same incident. This is common when incidents involve several areas of responsibility, such as infrastructure, security, and application teams.
Only if you've configured a workflow that does it. There is no team-level toggle that auto-invites members on attach. Build an Incident Workflow with the **Invite to Slack channel (Rootly)** task targeting the team — see [Automatically Inviting Team Members](#automatically-inviting-team-members) above.
The `/rootly add team` command must be run inside the Slack channel associated with the incident. If the command is used in another channel, Rootly cannot determine which incident the command should apply to. Additionally, you must have permission to update the incident to attach or modify teams.
Yes. Teams can be removed from an incident if they were attached by mistake or if their involvement is no longer required. This can be done through Slack using the appropriate Rootly command or from the incident interface in the Rootly dashboard. Removal fires the `teams_removed` and `teams_updated` workflow triggers.
Yes, when a workflow is configured to send them. The most common pattern is a workflow that broadcasts to the team's configured Slack channel on `teams_added`. The behavior is fully driven by your workflow configuration.
Only users with permission to update incidents can attach or remove teams. These permissions are typically granted to incident responders, incident commanders, team administrators, or organization administrators depending on your Rootly permission model.
# Configuring Teams
Source: https://docs.rootly.com/managing-teams/configuring-teams
Create and manage teams in Rootly, including members, ownership, Slack channels, escalation policies, and integration mappings for incident response.
Teams allow you to organize responders, define ownership of operational resources, and configure how groups of users interact with incidents, alerts, and communication channels inside Rootly.
By creating teams, organizations can structure incident response responsibilities more clearly. Teams help determine who should be notified during incidents, which resources a group is responsible for maintaining, and how alerts or updates are distributed across communication platforms like Slack or email.
From the **Teams** page, administrators and authorized users can create new teams, manage membership, assign ownership to infrastructure components, configure routing channels, and link teams to third-party incident management tools.
***
## Adding properties
While Teams in Rootly come with built-in properties, additional properties can be added. This allows you to build automations and workflows for your incident response processes using this information: for example, quickly identifying the customer impact of an incident based on the related team.
To add custom properties, open **Teams**, click **Edit catalog**, and click **Add Property**. You can choose from several property types, including text, boolean, and importantly references to other Catalogs.
For each team, you'll be able to find the values of these properties in the **Custom Properties** tab.
## Create a Team
Creating a team allows you to group responders together and define how that group participates in incidents and operational workflows.
To create a new team:
1. Navigate to **Configuration → Teams**
2. Click **Add New Team**
3. Enter the team details:
* **Name** — A clear identifier for the team
* **Description** — Optional context about the team's role or responsibilities
* **Color** — A visual identifier used throughout the interface
4. Click **Save**
After the team is created, it becomes available for incident assignment, alert routing, schedule ownership, and workflow automation.
After creating a team, you are automatically added as a member. Membership, permissions, and administrative settings can be modified later from the **Members** tab.
Organizations often create teams that reflect operational structures such as **Infrastructure**, **Security**, **SRE**, **Customer Support**, or **Platform Engineering**. Teams should represent logical responder groups responsible for services or systems.
***
## Import Teams
If your organization already manages response teams in external tools, Rootly allows you to import those teams directly.
Teams can be imported from supported third-party integrations such as **PagerDuty** or **Opsgenie**, allowing organizations to maintain consistent team structures across platforms.
To import teams:
1. Navigate to **Configuration → Teams**
2. Select the relevant import option
3. Choose the teams you want to import
4. Confirm the import
Imported teams will automatically appear in your Rootly configuration and can then be customized further with additional members, channels, and ownership settings.
Learn how to import teams from supported integrations.
***
## Edit a Team
Once a team has been created, it can be updated at any time to reflect changes in organizational structure, staffing, or responsibilities.
To edit a team:
1. Navigate to **Configuration → Teams**
2. Select the team you want to configure
3. Open the relevant configuration tab
4. Update the settings as needed
5. Save your changes
Team settings can be modified without impacting historical incident data. Updates to members, ownership, or communication channels will apply to future incidents and alerts.
***
## Members
The **Members** tab is where you manage the people who belong to a team.
Adding users to a team ensures they can participate in incidents involving that team and receive relevant notifications.
From this section you can:
* Add existing Rootly users to the team
* Assign a **default Incident Role**
* Designate **team administrators**
### Adding Members
To add a member:
1. Click **Add Member**
2. Search for an existing Rootly user
3. Optionally assign a default **Incident Role**
4. Save the changes
Assigning a default incident role allows Rootly to automatically apply the correct role when the team is attached to an incident.
For example, a team member may automatically become an **Incident Commander**, **Responder**, or **Communications Lead** whenever the team is assigned to an incident.
Users must already exist in your Rootly organization before they can be added to a team.
***
### Team Admins
Team administrators have additional permissions for managing team-owned resources.
These users are typically responsible for maintaining operational configurations such as schedules, escalation policies, or services owned by the team.
Team admins may be able to:
* Edit team configuration
* Manage team members
* Update schedules owned by the team
* Maintain escalation policies
* Modify ownership of operational resources
To assign a team admin:
1. Add the user as a team member
2. Select them in the **Team Admin** field
Only existing team members can be assigned as team admins.
Organizations typically assign team admins to engineering leads, SRE managers, or other operational owners responsible for maintaining response readiness.
***
## Ownership
The **Ownership** section identifies which operational resources are managed by a particular team.
Ownership helps teams understand their responsibilities during incidents and determines which users are allowed to manage certain resources.
Teams can own the following resources:
* **Alert Sources**
* **Alert Routes**
* **Services**
* **Schedules**
* **Escalation Policies**
Ownership can help answer questions such as:
* Which team owns a service?
* Who is responsible for maintaining an escalation policy?
* Which responders should be contacted when a specific alert is triggered?
Alert sources represent systems or monitoring tools that generate alerts inside Rootly. When a team owns an alert source, that team is typically responsible for responding to alerts originating from that source.
Alert routes define how alerts are processed and where they are directed. Teams that own alert routes may manage routing logic, escalation behavior, and response procedures for those alerts.
Services can be associated with teams to represent operational ownership of infrastructure or applications. This ownership information helps responders quickly identify which team is responsible for investigating or resolving issues affecting a service.
Teams often own on-call schedules that define responder availability. When a schedule is owned by a team, that team is responsible for maintaining the rotation and ensuring responders are correctly assigned.
Escalation policies determine how alerts are escalated if they are not acknowledged. Teams that own these policies manage the escalation steps and ensure the correct responders are notified.
***
## Channels
The **Channels** tab connects a team to the communication systems used during incidents.
These configurations allow Rootly to automatically notify the correct Slack channels, user groups, or email recipients when the team is involved in an incident.
You can configure:
* **Slack channels**
* **Slack user groups**
* **Notify emails**
* **Default alert broadcast channels**
* **Default incident broadcast channels**
These settings are frequently used by **automation workflows** to route notifications or tag responders automatically.
***
### Broadcast Channels
Teams can define default Slack channels where Rootly will automatically post updates.
These channels provide centralized visibility for operational events related to the team.
Two broadcast types are available:
**Alerts Channel**
Used to post notifications when the team is paged or when alerts are triggered for that team.
**Incidents Channel**
Used to post updates whenever the team is attached to an incident.
This allows stakeholders and responders to monitor activity without needing to join each individual incident channel.
If you want team members invited to the incident Slack channel when a team is attached, configure an Incident Workflow with the **Invite Rootly On-Call to Slack Channel** task — see [Automatically Inviting Team Members](/managing-teams/attaching-teams-to-incidents#automatically-inviting-team-members) for setup steps.
***
## Integrations
The **Integrations** tab allows Rootly teams to be mapped to external systems.
These mappings connect Rootly to existing incident response or service management platforms, enabling synchronized ownership and automated workflows.
Supported integrations may include:
* **PagerDuty**
* **Opsgenie**
* **Splunk On-Call**
* **PagerTree**
* **Cortex**
* **OpsLevel**
* **ServiceNow**
* **Backstage**
Mapping external teams allows Rootly workflows to interact with those systems more effectively and ensures operational ownership stays aligned across tools.
The corresponding integration must already be configured before it can be linked to a team.
***
## Best Practices
When configuring teams, consider the following recommendations:
* Use **clear, descriptive team names** that match your operational structure
* Add **all relevant responders** so incidents reach the correct people
* Assign **team administrators** for teams responsible for schedules or escalations
* Configure **Slack channels** to improve incident visibility
* Map teams to **external systems** when using integrations
* Regularly review membership and ownership to keep team configuration accurate
A well-structured team configuration helps reduce confusion during incidents and ensures alerts reach the correct responders quickly.
***
## Frequently Asked Questions
Creating or editing teams typically requires administrative permissions within Rootly. Organization administrators or users with configuration access can create teams, update team settings, manage members, and configure ownership or integrations.
If you do not see the option to create or edit teams, you may not have the necessary permissions. In that case, contact your Rootly administrator for assistance.
Yes. Users must first be invited to your Rootly organization before they can be added to a team.
Once a user account exists, the user can be added as a team member, assigned a default incident role, or designated as a team admin.
Team admins help maintain team-level configurations and operational resources.
Depending on your organization's permissions model, team admins may be responsible for managing schedules, maintaining escalation policies, updating team ownership, and modifying communication channels or integrations associated with the team.
Yes. When adding or editing a team member, you can optionally assign a default incident role.
This role is automatically applied whenever the team is attached to an incident, ensuring responders receive the appropriate responsibilities without requiring manual assignment.
Teams can own operational resources across the Rootly platform.
These may include alert sources, alert routes, services, schedules, and escalation policies. Ownership helps identify which team is responsible for maintaining or responding to issues involving those resources.
Team channels connect a team to communication endpoints such as Slack channels, Slack user groups, or email addresses.
These channels allow Rootly to automatically route notifications, tag responders, and distribute updates whenever the team becomes involved in an incident or alert.
The **Alerts Channel** is used to broadcast notifications whenever the team is paged or when alerts are triggered.
The **Incidents Channel** posts updates whenever the team is added to an incident. This allows organizations to track team activity across multiple incidents in a centralized Slack channel.
Yes. Rootly supports mapping teams to external services such as PagerDuty or Opsgenie.
These integrations allow Rootly workflows to coordinate with existing incident response systems and help maintain consistent ownership across platforms.
Yes. If your organization already manages teams in a third-party system such as PagerDuty or Opsgenie, those teams can be imported directly into Rootly.
Imported teams can then be customized further with additional members, ownership settings, or communication channels.
Yes. Teams can be modified at any time.
You can update team members, adjust ownership, change Slack channels, or modify integration mappings without affecting historical incident records.
# Importing Teams
Source: https://docs.rootly.com/managing-teams/importing-teams
Import team names and structure from connected integrations like PagerDuty, Opsgenie, and Slack to quickly populate your Rootly teams without manual setup.
You can import teams from connected integrations such as [PagerDuty](/integrations/pagerduty/pagerduty) and [Opsgenie](/integrations/opsgenie) to quickly create your team structure in Rootly.
Importing teams helps you get started faster by creating Rootly teams from your external team configuration instead of rebuilding them manually.
## Before You Begin
Before importing teams, make sure:
* Your integration is already configured in Rootly
* You have permission to create teams
* You are importing team structure only
This import flow creates or updates team records in Rootly using the external team’s name and description. It does not import members, schedules, or escalation policies.
## Import Teams
To import teams from a connected integration:
1. Navigate to **Configuration → Teams**
2. In the top-right corner, click the integration button for the service you want to import from, such as **PagerDuty** or **Opsgenie**
3. In the import modal, review the list of available teams
4. Select the teams you want to import
5. Click **Import**
After the import finishes, the selected teams appear on the **Teams** page.
If a team is already linked to the external integration, Rootly updates the existing team instead of creating a duplicate.
Team import does not include members, on-call schedules, or escalation policies. Use the separate migration flow if you need to bring over on-call configuration.
## What Gets Imported
This flow imports the following team details:
* Team name
* Team description
* External integration link
This flow does not import:
* Team members
* On-call schedules
* Escalation policies
If you need to migrate on-call configuration, use the dedicated migration flow for that integration.
## Other Supported Integrations
Depending on which integrations are configured in your workspace, you may also be able to import teams from other providers using the same workflow.
## Troubleshooting
### I don’t see the import buttons
Confirm that the integration is connected and that you have permission to create teams. If either requirement is missing, the import option may not appear.
### I get an error when opening the import modal
Check that the integration is configured correctly and that Rootly can successfully connect to the provider. Configuration or authorization issues can prevent the import list from loading.
### I imported a team, but expected more data
This import only creates or updates the team record itself. Members, schedules, and escalation policies are not included in this step.
## Frequently Asked Questions
When you import a team, Rootly creates a new team or updates an existing linked team using the external team’s information. This helps you quickly mirror your team structure in Rootly without recreating each team manually.
No. If Rootly finds an existing team already linked to the same external team, it updates that team instead of creating a duplicate.
No. This flow imports team structure only. If you need members, schedules, or escalation policies, use the separate migration or on-call import flow for that integration.
PagerDuty and Opsgenie support team import, and other integrations may also support the same workflow when configured in your workspace.
The most common reasons are that the integration is not configured yet or your role does not have permission to create teams.
# Team Incident Roles
Source: https://docs.rootly.com/managing-teams/incident-roles
Configure Incident Roles in Rootly to automatically assign responsibilities like Incident Commander when teams are attached to incidents during response.
Incident Roles help your team respond faster by automatically assigning responsibilities when a team is attached to an incident.
By configuring Incident Roles in advance, you can make sure the right people are assigned to the right responsibilities without needing to coordinate everything manually during an incident.
## Before You Begin
Make sure you have:
* Access to **Configuration → Incident Roles**
* A team with members already created
* On-call schedules, teams, or escalation policies configured *(optional)*
* Permission to create or manage [Workflows](/workflows/workflows) *(required for paging automation)*
## How It Works
Assignments occur when a team is attached to an incident, either:
* During incident creation
* When a team is added later
When assignment runs, Rootly:
* Applies the Incident Role mappings configured for that team
* Assigns users to the appropriate Incident Roles
* Creates any Default Tasks attached to those roles
* Adds matched on-call users to the incident channel
For on-call assignments, Rootly uses the user who is actively on-call at the time the team is attached to the incident.
## Create an Incident Role
To create a new Incident Role:
1. Navigate to **Configuration → Incident Roles**
2. Click **Create Role**
3. Fill in the role details:
* **Name** *(required)*
* **Description** *(optional)*
* **Responsibilities** *(optional)* — A message shown to the user when they are assigned the role
* **Optional role** — Allows the role to remain unassigned during an incident
* **Allow multiple users** — Allows more than one user to be assigned to the role
4. Click **Create Role**
## Add Default Tasks
After creating the role, you can add Default Tasks to automatically assign follow-up work when that Incident Role is assigned during an incident.
To add Default Tasks:
1. Open the Incident Role you created
2. Edit the role
3. Add one or more **Default Tasks** for this role
4. Save your changes
When the role is assigned during an incident, those tasks are automatically created for the assigned user.
Changes to role mappings and Default Tasks generally apply to future assignments, not incidents that are already in progress.
## Assign Roles to Team Members
Once the Incident Role is created, assign it to members of the appropriate team.
1. Navigate to **Teams**
2. Open the team you want to update
3. Select the **Members** tab
4. Add or edit team members and choose their **Incident Role**
5. Save your changes
## Auto-Assign Roles from On-Call
You can also assign Incident Roles based on who is currently on-call for a:
* Schedule
* Team
* Escalation policy
If a matching user is actively on-call and configured for the role, they are automatically:
* Assigned to the role
* Added to the incident channel
> Role assignment and paging are separate behaviors. Users can be auto-assigned through Incident Role configuration, but paging requires a [Workflow](/workflows/workflows) action.
## Verify Your Setup
Create a test incident and attach the configured team. Then confirm that:
* The expected Incident Roles are assigned
* Default Tasks are created
* On-call users are assigned when applicable
* Any related Workflows run as expected
## Troubleshooting
### No Incident Role assignee appears
Confirm that the configured team was attached to the incident and that team members are mapped to the correct Incident Role. If the role should be assigned from on-call, verify that the on-call source is configured for that role.
### No on-call user is assigned
Verify the correct schedule, team, or escalation policy is configured and that someone is actively on-call at the time the team is attached. If coverage recently changed, check timezone or shift handoff timing.
### No Workflow actions run
Confirm that the Workflow is enabled and that its conditions match the incident. Role assignment alone does not notify or page users unless a Workflow action is configured.
## Frequently Asked Questions
Incident Roles are assigned when a team is attached to an incident, either during incident creation or when a team is added later.
During assignment, Rootly:
* Applies the Incident Role mappings configured for that team
* Assigns the appropriate users to each role
* Creates any Default Tasks attached to the assigned roles
* Adds matched on-call users to the incident channel
This helps your team start response work faster with ownership and next steps already in place.
These settings control how flexible an Incident Role assignment can be during an incident:
* **Optional role** means the role can remain unassigned if no one needs to fill it immediately
* **Allow multiple users** means more than one user can hold the same Incident Role at the same time
These options are useful when a responsibility is either not always required or is often shared across multiple responders.
Default Tasks are created automatically when the related Incident Role is assigned during an incident.
They are useful for standardizing recurring work, such as:
* Posting updates
* Reviewing logs
* Coordinating communications
* Following predefined response steps
Changes to Default Tasks generally apply to future assignments. Tasks that already exist on an incident usually remain unchanged unless someone updates them manually.
If an Incident Role is configured to use an on-call source, Rootly assigns the user who is actively on-call at the time the team is attached to the incident.
Supported sources can include:
* A schedule
* A team on-call setup
* An escalation policy
When a matching on-call user is found, they are assigned to the role and added to the incident channel.
Not always. Role assignment and paging are separate actions.
* **Role assignment** gives the user responsibility within the incident
* **Paging and notifications** depend on a configured [Workflow](/workflows/workflows)
If you want assigned users to be alerted automatically, make sure the Workflow conditions and actions are configured for that behavior.
This usually happens because of a configuration issue or because no matching user was available at the time of assignment.
Common reasons include:
* The team was not attached to the incident
* The Incident Role mapping is not configured correctly
* No eligible team member matched the role
* No active on-call user matched the configured source
* The wrong schedule, team, or escalation policy is connected
The fastest way to validate your setup is to create a test incident and attach the configured team.
Yes. A single user can hold multiple Incident Roles if your configuration supports it.
This is especially useful for:
* Smaller teams
* Lightweight incidents
* Situations where one responder needs to cover multiple responsibilities
# Managing teams in Rootly
Source: https://docs.rootly.com/managing-teams/managing-teams
Create and manage teams in Rootly for on-call schedules, alert routing, Slack automation, escalation policies, and third-party imports.
In Rootly, **Teams** represent groups of users responsible for a specific department, service, or product within your organization. Teams provide the organizational structure used to manage on-call coverage, route alerts, and configure team-specific workflows across the platform.
## What Teams Can Do
Teams in Rootly enable you to:
* **Own On-Call Schedules and Escalation Policies**\
Teams manage their own on-call rotations and escalation policies through Rootly On-Call.
* **Route Alerts to the Right Responders**\
Alerts from integrated monitoring tools or email sources can be routed directly to teams to ensure the correct responders are notified immediately.
* **Configure Slack Automation**\
Teams can be mapped to specific Slack channels and user groups, enabling automated notifications, incident collaboration, and response workflows.
## Managing Teams
Teams can be created and managed directly in the Rootly web interface, where you can assign members, configure team settings, and manage access.
Rootly also supports importing teams from third-party platforms to simplify migrations and maintain existing team structures.
### Supported Imports
* **PagerDuty**
* **Opsgenie**
Additional integrations and migration options will continue to be added.
## Frequently Asked Questions
### Team Membership
Yes. Users can belong to multiple teams in Rootly.
Each team membership has its own:
* **Role** (Owner, Admin, Member, etc.)
* **On-Call Role**
* **Permissions**
Users can switch teams using the **team selector** in the navigation bar.
**Team Switching:** When users switch teams, they only see the data, incidents, and configurations for that team.
Permissions in Rootly are **team-scoped**.
This means:
* Roles apply only within a specific team
* Permissions in one team do not affect another
* Users can have different roles across teams
Example: A user could be an **Owner** in Engineering but a **Member** in Operations.
Team members can be managed through:
* **Web UI:** Settings → Teams → Members
* **Email Invitations**
* **SCIM provisioning** when SSO is enabled
* **API** for programmatic management
Yes. Teams can restrict membership to specific **email domains**.
To configure this:
1. Navigate to **Settings → Team Settings**
2. Configure the **Email Domains** restriction
3. Only users with matching domains can be added
***
### Teams & Organizational Structure
**Teams** are top-level organizational units that contain users, schedules, alerts, and configurations.
**Groups** are sub-units within a team used for:
* On-call rotations
* Alert routing
* Incident assignment
* Slack channel mapping
Think of it as:
**Teams = organizations**\
**Groups = sub-teams within that organization**
No. Teams are **fully isolated**.
Each team has its own:
* Incident data
* Alerts and action items
* Configuration settings
* On-call schedules
* Alert routing rules
Users must be explicitly added to each team to access it.
Yes. Each team can configure its own settings including:
* AI features
* Alert routing
* Incident workflows
* Sub-statuses
* Retrospective templates
* Integrations
* Time zones
This allows teams to operate independently.
A **Team** is the organizational container that includes users, schedules, and configuration.
An **Escalation Policy** defines **how alerts notify responders within that team**, including:
* Who gets notified
* Escalation order
* Notification timing
* Notification methods
***
### Team Management
Yes. Team settings can be updated at any time.
You can modify:
* Team name
* Time zone
* Email domain restrictions
* Feature configurations
* Team logo and branding
All settings are available under **Settings → Team Settings**.
Teams are **soft deleted** rather than permanently removed.
When a team is deleted:
* Historical incident data is preserved
* Users immediately lose access
* Integrations are disconnected
**Important:** Team deletion is irreversible. Ensure you export any required data beforehand.
Yes. Teams can be duplicated to quickly create similar team structures.
Duplication can include:
* Team settings
* Schedules and escalation policies
* Groups and configurations
* Optional user memberships
The number of teams available depends on your **Rootly plan**.
You can review limits in **Settings → Billing** or contact your account manager.
***
### Migrations & Integrations
Rootly provides migration tools to import your existing team structure.
Supported imports include:
**PagerDuty**
* Teams
* Users
* Schedules
* Escalation policies
* On-call rotations
**Opsgenie**
* Teams
* Schedules
* Routing rules
* Escalation policies
Learn more about migrating from PagerDuty or Opsgenie
Slack channels can be configured in two ways:
1. **Team-level mapping** for default notifications
2. **Group-level mapping** for more granular routing
To configure:
1. Navigate to **Settings → Integrations → Slack**
2. Configure team-level settings
3. Map groups to Slack channels
Learn more about configuring Slack for teams
Yes. Teams can manage their own **public or private status pages**.
Status pages support:
* Custom domains
* Service components
* Incident communication templates
* Automated updates
Learn more about creating and managing status pages
# Viewing Teams
Source: https://docs.rootly.com/managing-teams/viewing-teams
View, search, and navigate the teams available in your Rootly organization, including team membership, on-call coverage, and owned services.
The **Teams** dashboard gives you a centralized view of the teams available in your Rootly organization. From this page, you can see the teams you belong to, review basic team information, and switch between team workspaces.
In Rootly, teams act as separate operational workspaces. Each team maintains its own configuration, users, schedules, alerts, integrations, and incident-related settings. This separation helps organizations keep ownership, response workflows, and configuration clearly scoped to the appropriate team.
If you work across multiple teams, the Teams dashboard makes it easy to move between them and quickly understand which workspace you are currently viewing.
## Open the Teams Dashboard
To open the Teams dashboard:
1. In the Rootly navigation bar, open **Configuration**
2. Select **Teams**
Once opened, the page displays the teams you belong to in your current organization.
## Teams Dashboard Overview
The Teams dashboard presents each available team as a separate card, making it easy to scan and navigate your team structure.
Each team card includes:
* **Team name**, which you can click to switch into that team
* **Team member avatars**, showing the first few users in the team
* A **“+ X more”** indicator when additional users belong to the team beyond those shown on the card
This layout is designed to give you a quick, lightweight overview of your available teams without requiring you to open each one individually.
If you only belong to one team, Rootly automatically opens that team’s dashboard instead of showing the Teams list first.
## Switching Teams
If you belong to more than one team, you can switch between them directly from the Teams dashboard.
To switch teams:
1. Open the **Teams** dashboard
2. Click the **team name** for the team you want to view
Rootly immediately switches your active workspace to that team and redirects you to the selected team’s dashboard.
This allows you to move between operational contexts without leaving the product or manually reconfiguring your view.
Each team has its own incidents, alerts, users, integrations, and configuration settings. When you switch teams, you are changing the active workspace context.
You cannot switch to teams that have been disabled.
## Team Selector
You can also switch teams from the **team selector** in the top-left navigation menu.
The team selector provides a faster way to move between teams without returning to the Teams dashboard. It displays:
* Your **current team**
* Other teams you belong to
* Teams sorted alphabetically for easier navigation
Selecting a team from this menu immediately switches your active workspace.
This is especially helpful for users who frequently work across multiple teams and need a quick way to move between configurations, incidents, and operational responsibilities.
## Why Team Context Matters
Because teams in Rootly operate as separate workspaces, the team you are currently viewing affects the data and settings available to you.
For example, the selected team determines which:
* incidents you see
* users and memberships are active
* schedules and escalation policies are available
* integrations and ownership settings apply
Understanding which team you are currently in is important when reviewing incident data, updating configuration, or making operational changes.
# Managing Invitations
Source: https://docs.rootly.com/managing-users/invitations
View, resend, and delete pending Rootly invitations from Organization Settings to manage who can join your workspace before they accept their invite.
The **Invitations** page lets you manage pending invitations for users who have not yet joined your Rootly organization. From here, you can review invitation details, resend an invitation email, or remove an invitation that is no longer needed.
Invitation emails are sent automatically when an invitation is created. If a recipient does not receive the email, you can resend it from the Invitations page.
## Access the Invitations Page
In the top-left corner, click the drop-down next to your organization name and select **Organization Settings**.
Select **[Invitations](https://rootly.com/account/invitations)** to view all pending invitations.
The table shows each invitation’s:
* **Email**
* **Incident Response role**
* **On-Call role**
* **Sent date**
* **Invited by**
Hover over an invitation row to access available actions:
* **Resend** to send the invitation email again
* **Delete** to remove the invitation
Invitations cannot be edited. To change the email address or assigned roles, delete the invitation and create a new one.
## What You Can Do
From the Invitations page, you can:
See all outstanding invitations and review the roles assigned to each recipient.
Send the invitation email again if the original message was not received.
Remove invitations that are no longer needed.
Confirm which Incident Response and On-Call roles will be assigned when the invitation is accepted.
## How Invitations Work
When you invite a user to Rootly:
1. An invitation email is sent to the specified email address
2. The recipient opens the invitation link
3. After accepting, the user joins the organization with the assigned roles
4. The invitation is removed from the pending list
If no roles are specified when the invitation is created, the team’s default roles are applied.
Invitations are tied to the invited email address. The recipient must accept the invitation using that email.
## Best Practices
* Double-check email addresses before sending invitations
* Assign roles carefully to avoid unnecessary permission changes later
* Resend invitations before creating duplicates
* Periodically remove stale invitations that are no longer needed
## Troubleshooting
Verify the email address is correct, ask the recipient to check their spam or junk folder, and resend the invitation if needed.
Confirm the user is signing in with the same email address that received the invitation. If the invitation was deleted or already accepted, create a new one.
Invitations cannot be edited. Delete the existing invitation and create a new one with the correct details.
## Related Documentation
Learn how to create new invitations.
Learn how to manage existing organization members.
Understand Incident Response and On-Call roles.
Learn how permissions are controlled across teams and products.
# Inviting Users via Third-Party Integrations
Source: https://docs.rootly.com/managing-users/inviting-users-via-third-party-integrations
Invite users to Rootly directly from supported integrations such as Slack, Microsoft Teams, Opsgenie, PagerDuty, and Splunk On-Call to onboard quickly.
You can invite users directly from supported third-party integrations to quickly onboard your team without manually entering email addresses.
Rootly currently supports inviting users from:
* **Slack**
* **Opsgenie**
* **PagerDuty**
* **Splunk On-Call (formerly VictorOps)**
The integration must be configured before users can be imported or invited.
## Invite Users from an Integration
In the top-left corner, click the drop-down next to your organization name and select **Organization Settings**.
Select **[Members](https://rootly.com/account/memberships)**, then choose **Invite from \[Integration]**.
Depending on the integrations configured for your organization, you may see:
* **Invite from Slack**
* **Invite from Opsgenie**
* **Invite from PagerDuty**
* **Invite from Splunk On-Call**
Rootly loads a list of users from the selected integration.
Use the search field to filter users by name or email (or username for Opsgenie).
Select the users you want to invite and click **Invite**.
Invitation emails are sent automatically to the selected users.
## Role Assignment
Users invited through third-party integrations are assigned roles the same way as standard invitations.
You can assign:
* **Incident Response roles** for incident management permissions
* **On-Call roles** for schedules, alerting, and escalation workflows
If roles are not selected during invitation, Rootly applies your team’s **default roles**.
Configure default roles in **Organization Settings** to standardize permissions for new users.
## Integration Behavior
### Slack
Slack invitations may be limited by your configured **email domain restrictions**.
If your organization restricts invitations by email domain, only Slack users with matching email addresses will appear in the list.
### PagerDuty, Opsgenie, and Splunk On-Call
Users are pulled from the connected integration account. If expected users do not appear, verify the integration connection and permissions.
## Browsing and Searching Users
The integration user list supports:
* **Search** to filter users by name, email, or username
* **Pagination** for navigating large user lists
* **Sorting** by user name
This helps you quickly locate users in large organizations.
## User Acceptance and Sign-Up
After an invitation is sent, the user receives an email with a link to join your Rootly organization.
Accepting the invite takes them to the sign-up page:
Users can sign in using:
* **Google**
* **Slack**
* **SSO**
* **Email and password**
Passwords must include:
* At least **10 characters**
* One **lowercase letter**
* One **uppercase letter**
* One **number**
* One **special character**
After completing sign-up, the user is added to your organization with the assigned roles.
## Best Practices
* Confirm integrations are configured before inviting users
* Review your default role configuration before onboarding users
* Use integration-based invitations to onboard large teams faster
* Use search to locate specific users in large integration lists
## Troubleshooting
Ensure the integration is configured and connected in **Organization Settings → Integrations**.
Verify the integration connection and permissions. If the integration cannot access user data, the list may appear empty.
Slack user visibility may depend on your configured email domains. Only users with matching domains may appear.
Invitations may fail if the email address is invalid, the user is already a member, or a duplicate invitation already exists.
Role assignment depends on your organization permissions and configuration. If roles are not set, default roles will be applied automatically.
## Related Documentation
Invite users manually by entering email addresses.
View, resend, or delete pending invitations.
Configure Slack for user imports and collaboration.
Configure PagerDuty before inviting users from it.
# Inviting Users
Source: https://docs.rootly.com/managing-users/inviting-users-via-web-ui
Invite new users to your Rootly organization through the web UI and assign Incident Response or On-Call roles, team memberships, and permissions.
Use invitations to add new users to your Rootly organization. You can invite one or more users at a time, assign roles during invitation, and let users join using the sign-in method configured for your organization.
Invitation emails are sent automatically after you create an invitation.
You can invite multiple users at once by entering more than one email address in the invite flow.
## Invite Users
In the top-left corner, click the drop-down next to your organization name and select **Organization Settings**.
Select **[Members](https://rootly.com/account/memberships)**, then click **+ Invite Member**.
Enter one or more email addresses for the users you want to invite.
You can separate multiple email addresses using:
**Commas**
[maria@candly.org](mailto:maria@candly.org),[tim@candly.org](mailto:tim@candly.org),[kirija@candly.org](mailto:kirija@candly.org)
**New lines**
[maria@candly.org](mailto:maria@candly.org)
[tim@candly.org](mailto:tim@candly.org)
[kirija@candly.org](mailto:kirija@candly.org)
**Spaces**
[maria@candly.org](mailto:maria@candly.org) [tim@candly.org](mailto:tim@candly.org) [kirija@candly.org](mailto:kirija@candly.org)
You can optionally assign:
* **Incident Response role**
* **On-Call role**
When inviting multiple users at once, the selected roles apply to all invited users in that batch.
If no role is selected, the team’s default role is applied.
Click **Invite** to send the invitation email.
## What You Can Do
From the invite flow, you can:
Add a single user or invite multiple users at the same time.
Set Incident Response and On-Call roles during invitation.
Allow Rootly to apply your team’s default roles when no role is selected.
Send users directly into the account creation or sign-in flow.
## Role Assignment
You can assign roles during invitation to control what access a user receives after joining.
* **Incident Response roles** control access to incidents, workflows, retrospectives, and related configuration
* **On-Call roles** control access to schedules, escalation policies, alerting, and responder workflows
If a role is not selected, Rootly assigns the team’s default role for that product.
Configure default roles in **Organization Settings** to standardize access for new users.
Ensure you have available seats for the roles you’re assigning. If seats are limited, some roles may be unavailable.
## Email Requirements
Invitations require valid email addresses that meet your organization’s requirements.
* **Valid format**
* **Not already a member**
* **Allowed email domain**, if your organization restricts invitations by domain
Rootly validates email addresses during invitation creation. Invalid addresses will return an error.
## User Acceptance and Sign-Up
After an invitation is sent, the user receives an email with a link to join your organization.
When they open the invitation, they can complete sign-up using one of the methods available in your environment, such as:
* **Google**
* **Slack**
* **SSO**
* **Email and password**
If the user signs up with email and password, the password must include:
* At least **10 characters**
* One **lowercase** letter
* One **uppercase** letter
* One **number**
* One **special character**
Once sign-up is complete, the user is added to your organization with the assigned roles.
## Bulk Invitations
When you invite multiple users at once, Rootly processes invitations in batches.
* Invitations may take longer to appear for larger batches
* Individual errors do not prevent valid invitations from being created
* You can review progress from the **Invitations** page
Large invitation batches may take a few minutes to complete.
## Who Can Send Invitations?
Invitation access depends on the user’s assigned permissions.
* **Owners** can send invitations
* **Admins** can send invitations
* **On-Call Admins** may be able to assign On-Call access, depending on configuration
Contact your team administrator if you do not have permission to invite users.
## Best Practices
* Configure default roles before inviting users with standard access needs
* Double-check email addresses before sending invitations
* Assign roles during invitation to reduce manual updates later
* Use bulk invitations when onboarding multiple users at once
* Review pending invitations and resend or remove them as needed
## Troubleshooting
Confirm the email address is correct, ask the user to check spam or junk folders, and resend the invitation if needed.
Invitations cannot be edited after they are sent. Delete the pending invitation and create a new one with the correct details.
Make sure the user is signing in with the same email address that received the invitation. If the invitation is no longer valid, send a new one.
This usually means your plan has reached its seat limit for that role type, or you do not have permission to assign that role.
At the limit, the invitation fails with an error that names the plan that ran out:
> You have reached the seat limit for your On-Call plan. Please email our team at [sales@rootly.com](mailto:sales@rootly.com) to upgrade your plan.
To check current usage, go to **Organization Settings → [Members](/managing-users/managing-users)** and hover over the information icon beside the **Incident Response** or **On-Call** column header.
The email may be invalid, already belong to an existing member, or fail your organization’s domain restrictions.
Large invitation batches may take time to process. Check the Invitations page to review progress.
## Related Documentation
View, resend, or delete pending invitations.
Manage existing users in your organization.
Learn more about Incident Response and On-Call roles.
Understand how permissions are controlled across teams and products.
# Manage Users
Source: https://docs.rootly.com/managing-users/managing-users
View and manage Rootly organization members, including their contact information, roles, team memberships, and integration linkage statuses across providers.
The **Members** page gives you a centralized view of everyone in your Rootly organization. From here, you can review member details, check connected integrations, and manage access and roles.
Contact information such as phone numbers and device status may only be visible to **Owners**, **Admins**, or users with the appropriate contact-viewing permissions.
## Access the Members Page
In the top-left corner, click the drop-down next to your organization name and select **Organization Settings**.
Select **[Members](https://rootly.com/account/memberships)**.
The Members table displays all active users along with their:
* **Name**
* **Email**
* **Phone number**
* **Mobile device status**
* **Slack connection status**
* **Incident Response**
* **On-Call**
Hover over a user row to access quick actions, or open a member to update their details.
## What You Can Do
From the Members page, you can:
Update incident response and on-call roles for members in your organization.
View member contact information used for alerts and escalations, based on your permissions.
See whether users have connected Slack or registered a mobile device.
Remove users who no longer need access to your Rootly organization.
Quickly find members by name, email, role, or connection status.
Export your member list for reporting or administrative review.
## Understand Member Information
### Contact Information
Each member record may include:
* **Email**: The member’s primary email address
* **Phone number**: Used for SMS or voice notifications
* **Mobile device status**: Indicates whether the member has connected a mobile device for push notifications
Phone numbers and device status may be restricted based on your role and organization permissions.
### Integration Status
The Members table also shows whether a user has connected:
* **Slack**
* **A mobile device**
These statuses help confirm whether members are ready to receive notifications through the expected channels.
### Roles
Each member can have separate roles for:
* **Incident response**, which determines access to incident management features
* **On-call**, which determines access to on-call schedules, escalations, and alerting workflows
## Manage Users
### Edit roles
To update a user’s role:
1. Hover over the member row or open the member record
2. Select **Edit**
3. Update the user’s **Incident Response Role** or **On-Call Role**
4. Save your changes
### Remove a user
To remove a member from the organization:
1. Hover over the member row
2. Select **Delete** or use the actions menu
3. Confirm the removal
Removing a user immediately revokes their access to the organization.
### Search and filter
Use search and filters to find members by:
* Name
* Email
* Slack connection status
* Mobile device status
* Incident Response
* On-Call
## Export Member Data
You can export the Members table for reporting or operational review.
1. Click **Export**
2. Choose your preferred format
3. Download the exported file
The exported data includes the member information visible to you based on your permissions.
## Frequently Asked Questions
Yes. Users can belong to multiple teams in Rootly, and each team membership can have its own roles and permissions.
**Incident Response Role** controls access to incident-related workflows and features. **On-Call Role** controls access to schedules, escalations, and alerting workflows.
Go to **Organization Settings → Members**, then hover over the information icon beside the **Incident Response** or **On-Call** column header to see that plan’s usage, shown as `18 of 25 seats used`. Plans without a seat limit read `unlimited`. Incident Response and On-Call seats are counted separately.
Phone numbers and device status may be hidden if you do not have the required permissions to view contact information.
Removing a user immediately revokes their access to the organization. Historical data may still remain for auditing or reporting purposes.
This usually means the user has not connected their Slack account, or the Slack integration is not fully configured for the organization.
Yes. You can export the Members table using the **Export** option, subject to the data visible to you based on your permissions.
## Related Documentation
Learn more about incident response and on-call roles.
Learn how to add new users to your organization.
Configure Slack for incident response and notifications.
Learn how the Rootly mobile app supports notifications and response.
# Manage User Permissions
Source: https://docs.rootly.com/managing-users/user-permissions
Control access in Rootly with team-scoped roles for Incident Response and On-Call, with configurable permission sets and custom role definitions.
## Overview
Permissions in Rootly are managed through **roles**, which determine what actions a user can perform within a team. Roles are intentionally **team-scoped** and **product-specific**, giving organizations fine-grained control over access.
Each team membership assigns **two roles** to a user:
* An **Incident Response role**, which governs incident creation, management, configuration, and analytics.
* An **On-Call role**, which governs alerting, paging, schedules, escalation policies, and responder workflows.
This separation allows teams to model real-world responsibilities. For example, a user may participate in incidents without being on-call, or be on-call without having permission to administer incident configuration.
When a user is added to a team, Rootly automatically assigns the team’s default roles for both Incident Response and On-Call. These defaults can be adjusted by administrators at any time.
Permissions are evaluated per team. A user may have different access levels across different teams within the same Rootly workspace.
***
### Default Roles
Rootly ships with system-defined roles for both Incident Response and On-Call. These roles are created automatically for every team and cannot be deleted. Some roles are editable, while others are intentionally fixed.
#### Incident Response Roles
Incident Response includes the following default roles:
* Owner
* Admin
* User
* Observer
* No Access
Owners have full access to Incident Response. They can configure incident settings, manage workflows and integrations, access all incident data (including private incidents), and administer platform-level features such as billing.
This role is typically reserved for platform owners or the core incident management team.
Admins can configure and manage most Incident Response features, including incident properties, workflows, retrospectives, and integrations.
This role is ideal for teams responsible for maintaining and improving incident processes.
Users are standard incident participants. They can respond to incidents, update incident details, assign roles, and collaborate during active incidents without having broad administrative permissions.
Observers primarily have read access but can still create incidents. This makes the role suitable for cross-functional teams such as support, operations, or customer success who need visibility into incidents.
No Access removes Incident Response permissions entirely for the team. This is useful when a user only needs On-Call access or should not interact with incidents in a given team.
***
#### On-Call Roles
On-Call includes a separate set of default roles:
* Admin
* User
* Observer
* No Access
In addition, On-Call supports **Custom roles** for more granular control.
On-Call Admins can manage schedules, escalation policies, routing rules, alert sources, and advanced features such as Live Call Routing and Heartbeats.
They can also perform bulk actions on alerts, including changing alert status, marking alerts as noise, or deleting alerts.
On-Call Users are standard responders. They receive alerts, acknowledge them, resolve incidents, and participate in on-call rotations.
On-Call Observers have limited access but can typically initiate paging. This role is commonly used for teams that need to trigger alerts without managing on-call configuration.
No Access removes all On-Call permissions for the team. Users with this role will not receive alerts or interact with paging features.
Custom roles allow teams to define precise On-Call access, such as allowing alert acknowledgement without permission to edit schedules or escalation policies.
On-Call does not include an **Owner** role. Administrative control is handled through **Admin** and **Custom roles**.
***
## Permission Sets
Permission sets define **what actions a role can perform on a specific entity**. Each permission set typically includes some combination of:
* Create
* Read
* Update
* Delete
Not all entities support all actions. Some include specialized actions beyond standard CRUD behavior.
### Incident Response Permission Sets
| Entity | Description | Links & Examples |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Alerts | View and create alert events sent to Rootly from external sources. Alerts cannot be deleted. Status updates are handled by On-Call permissions. | [https://rootly.com/account/alerts](https://rootly.com/account/alerts) |
| API Keys | Manage API tokens used to authenticate with Rootly APIs. | |
| Audits | View the audit log of configuration and permission changes. | [https://rootly.com/account/audits](https://rootly.com/account/audits) |
| Causes | Manage incident cause classifications used for analysis and reporting. | [https://rootly.com/account/causes](https://rootly.com/account/causes) |
| Custom Fields | Manage custom incident fields used to capture additional metadata. | [https://rootly.com/account/form-fields](https://rootly.com/account/form-fields) |
| Environments | Manage environment labels used to categorize incidents. | [https://rootly.com/account/environments](https://rootly.com/account/environments) |
| Functionalities | Manage functionality labels representing impacted features or systems. | [https://rootly.com/account/functionalities](https://rootly.com/account/functionalities) |
| Incident Feedback | Manage feedback collected during or after incident resolution. | |
| Incident Roles | Define roles assigned to responders during incidents. | [https://rootly.com/account/incident-roles](https://rootly.com/account/incident-roles) |
| Incident Types | Manage categories used to classify incidents. | [https://rootly.com/account/incident-types](https://rootly.com/account/incident-types) |
| Incidents | Manage public incident records, including status, severity, roles, and impacted services. | [https://rootly.com/account/incidents](https://rootly.com/account/incidents) |
| Integrations | Manage native integrations with external systems. | [https://rootly.com/account/integrations](https://rootly.com/account/integrations) |
| Invitations | Invite users to join your Rootly workspace. | [https://rootly.com/account/invitations](https://rootly.com/account/invitations) |
| Playbooks | Manage playbooks used during incidents. | [https://rootly.com/account/playbooks](https://rootly.com/account/playbooks) |
| Private Incidents | Manage private incidents with restricted visibility. | |
| Pulses | Manage CI/CD and deployment events sent to Rootly. | [https://rootly.com/account/pulses](https://rootly.com/account/pulses) |
| Retrospective | Manage retrospective processes and templates. | [https://rootly.com/account/retrospective-processes](https://rootly.com/account/retrospective-processes) |
| Roles | Manage Incident Response roles and permissions. | [https://rootly.com/account/roles](https://rootly.com/account/roles) |
| Teams | Manage teams participating in incidents. | [https://rootly.com/account/teams](https://rootly.com/account/teams) |
| Secrets | Manage secrets used securely in workflows. | [https://rootly.com/account/secrets](https://rootly.com/account/secrets) |
| Services | Manage services associated with incidents. | [https://rootly.com/account/services](https://rootly.com/account/services) |
| Severities | Manage severity levels used to classify incidents. | [https://rootly.com/account/severities](https://rootly.com/account/severities) |
| Status Pages | Manage Rootly-hosted status pages. | [https://rootly.com/account/status-pages](https://rootly.com/account/status-pages) |
| Webhooks | Manage outbound webhooks for incident and alert events. | [https://rootly.com/account/webhooks/outgoing/endpoints](https://rootly.com/account/webhooks/outgoing/endpoints) |
| Workflows | Manage automation workflows triggered by incident events. | [https://rootly.com/account/workflows](https://rootly.com/account/workflows) |
### On-Call Permission Sets
On-Call permission sets control **paging, alert handling, and responder operations**.\
These permissions determine how alerts are created, routed, escalated, acknowledged, and resolved, as well as who can configure the systems that support on-call coverage.
Unlike Incident Response permissions, On-Call permissions are focused on **real-time operational behavior** and responder availability.
| Entity | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Alerts | Create, view, acknowledge, resolve, and re-trigger alerts. Controls the alert lifecycle once paging has begun. |
| Alert Groups | Manage alert grouping rules used to reduce noise and consolidate related alerts. |
| Alert Sources | Configure inbound alert sources and define how external alerts enter Rootly. |
| Alert Routing Rules | Define routing logic that determines which team, service, or escalation policy an alert is sent to. |
| Alert Urgencies | Manage urgency levels that control escalation behavior and notification intensity. |
| Schedules | Manage on-call schedules and rotations that determine who is on duty at any given time. |
| Schedule Overrides | Create temporary overrides to adjust on-call coverage outside of normal rotations. |
| Escalation Policies | Configure escalation paths, levels, repeat behavior, and working-hours logic for paging. |
| Live Call Routing | Manage inbound phone numbers, IVR calling trees, voicemail behavior, and live call escalation. |
| Heartbeats | Configure heartbeat monitors used to detect when systems stop checking in. |
| On-Call Roles | Manage On-Call roles and permission assignments for team members. |
| On-Call Readiness Reports | View and manage reports that assess coverage, responsiveness, and on-call health. |
| Services | Manage services used for alert routing and ownership in on-call workflows. |
| Teams | Manage teams used as alert routing targets and on-call ownership groups. |
| Integrations | Manage alerting and paging integrations (monitoring tools, incident systems, etc.). |
| Webhooks | Manage outbound webhooks that emit alert and on-call events. |
| API Keys | Manage API tokens used for on-call and alerting integrations. |
On-Call permissions govern **who gets paged and how alerts behave**.\
They are evaluated independently from Incident Response permissions, which control incident records, workflows, and retrospectives.
***
## Best Practices
* Assign the minimum permissions required for each role.
* Use Observers to provide visibility without administrative access.
* Separate Incident Response administration from On-Call ownership where possible.
* Restrict Private Incident access to a small, trusted group.
* Clearly document Custom On-Call roles so future administrators understand their intent.
***
## Troubleshooting
This usually indicates missing On-Call permissions. Confirm the user’s On-Call role includes alert update access for the relevant team.
Paging and configuration permissions are separate by design. Assign an On-Call role that includes schedule and escalation policy management if needed.
Private incidents are controlled separately. Ensure the user’s Incident Response role includes **Private Incident** access for the team.
This may occur when seat limits are reached or when role assignments are managed through external identity systems such as SCIM.
Confirm the user is operating in the correct team and that the permission applies to the correct product (Incident Response vs On-Call).
***
## Related Pages
The parent workflow — permissions are assigned when adding or editing users.
Invite new users into Rootly and assign them roles up front.
Broader tenant hardening — SSO, RBAC, and least-privilege guidance.
# Customizing Dashboards
Source: https://docs.rootly.com/metrics/customized-dashboards
Build custom metric dashboards with panel types, filters, groupings, multiple datasets, and export options for incident analytics.
Rootly's default dashboards get you started, but the interesting questions come from your own combinations of collections, filters, aggregations, and groupings. This page covers how to build custom panels and shape them into dashboards that answer the questions your team actually asks.
Start with a question, not a chart type. Pick the collection, filters, and metric that answer the question — then choose how to visualize it.
***
## How metric panels work
A **panel** is the building block of every dashboard. Panels can be visual (charts), tabular (tables), or KPI-style (aggregate values). Every panel is defined by a combination of:
A **panel** is the building block of every dashboard. Every panel combines the same seven pieces:
* **Display type** — how the data appears (line, column, table, aggregate value, etc.)
* **Collection** — which records the panel pulls from (Incidents, Alerts, Retrospectives, Action Items, Users)
* **Filters** — which subset of the collection is included
* **Aggregation operation** — how results are calculated (Count, Average, Sum)
* **Metric key** — what you're measuring (`resolution_time`, `hours_worked`, etc.)
* **Group By** — how results are segmented across categories
* **One or more datasets** — combinations of the above for comparisons and multi-series charts
Data selection (collection + filters), calculation (operation + key), and display (panel type + grouping) are separate concerns. That's what makes panels composable — you can reuse the same dataset across visualizations or refine filters without redesigning the panel.
***
## Panel types
Rootly supports the following panel types:
Rootly supports these panel types:
* **Line Chart** — trend over time
* **Line Stepped Chart** — trend with discrete transitions
* **Column Chart** — volume comparison across categories
* **Stacked Column Chart** — composition within totals
* **Monitoring Chart** — time-series data optimized for monitoring-style visualization
* **Pie Chart** — proportional distribution
* **Table** — raw records for operational drill-down
* **Aggregate Value** — a single formatted number for KPI displays
Monitoring charts use the same configuration model as other panels (datasets, filters, group-by, export) but render optimized for high-frequency time-series data.
### Table Panels
Table panels display raw records rather than aggregated metrics. They support selecting visible columns, including custom fields and incident roles as columns, and exporting the full dataset.
Tables display up to **100 rows** in the UI for performance. Exports can include the full dataset.
### Aggregate Value Panels
Aggregate panels display a single formatted number — ideal for KPI dashboards, executive summaries, and top-of-dashboard headline metrics. Examples: total incidents, average time-to-resolve, total hours worked.
Because aggregate panels show a single value, use them sparingly at the top of a dashboard with deeper analytical panels below.
***
## Collections and access
Panels pull from one of five collections:
* **Alerts**
* **Incidents**
* **Retrospectives**
* **Action Items**
* **Users**
Which collections are available depends on your product access (seat type).
On-Call seats typically see **Alerts** only. Incident Response seats see **Incidents**, **Retrospectives**, **Action Items**, and **Users** in addition.
***
## Add a metric panel
To add a panel:
1. Go to **Metrics** and open the dashboard you want to edit
2. Click **+ Add Panel**
3. Configure the panel (type, collection, filters, operation, key, etc.)
4. Click **Create**
***
## Edit, Move, and Resize Panels
To edit a panel, hover it → click **⋯** → **Settings**, update, click **Update**. Rootly validates configuration on save and shows targeted errors for invalid keys, operations, or filter conditions.
## Edit panels
To edit a panel:
1. Open the dashboard in **Metrics**
2. Hover over the panel
3. Click **⋯**
4. Select **Settings**
5. Update configuration and click **Update**
**Validation happens on save**
Rootly validates your configuration before saving. If you select an invalid key, operation, or filter condition, you’ll see a targeted error message so you can correct it immediately.
***
## Move and resize panels
Filtering has two layers: **dashboard-level filters** (your personal view preferences) and **panel-level filters** (persistent and shared with everyone who views the panel).
### Dashboard-Level Filters
Panels are stored as grid coordinates (not pixels), meaning layouts stay consistent across screen sizes.
**Grid defaults**
Panels default to a grid size of **6 columns wide × 3 rows tall**, with a minimum height enforced for readability.
***
## Filters
Filtering determines *what counts*.
Without intentional filtering, dashboards become noise generators. With thoughtful filtering, they become precision tools.
In Rootly, filtering operates on two layers: global view preferences (personal and temporary) and panel-level filters (persistent and shared). Understanding the difference is critical for designing dashboards that are both flexible and consistent.
* **Dashboard-level filters** (your personal view preferences)
* **Panel-level filters** (saved as part of the panel configuration)
These two layers combine to determine what any panel actually shows.
***
## Dashboard-level filters (view preferences)
Dashboard-level filters apply to **all panels** and are saved **per user**:
* Date range (for example, Last 30 Days)
* Period (day / week / month / quarter / year)
* Team filters
* Service filters
Changing your dashboard filters does not edit the dashboard or affect what other viewers see. If you want a change to stick for everyone, edit the panel's own filters.
### Panel-Level Filters
Panel-level filters are stored with the panel and define exactly which records enter its dataset for every viewer. Supported operators depend on the field type:
* `=` (equals) / `!=` (not equals)
* `>=` / `<=`
* `exists` / `not_exists`
* `contains` / `not_contains`
* `assigned` / `unassigned` (incident roles only)
Incident roles support `assigned` and `unassigned` — useful for panels like *Incidents Missing an Incident Commander* or *SEV0s Where Comms Lead Is Unassigned*.
### Filter Groups (AND / OR Logic)
Filters can be grouped with AND / OR logic for expressive conditions:
* (SEV0 OR SEV1) AND (Environment = Production)
* (Service Contains Payments) OR (Functionality Contains Checkout)
AND groups require all rules to match. OR groups match if any rule matches.
## Group By
Group By segments results within a panel, turning a single metric into a comparison. Use it when the question is *"how does this split across…"*:
* Which teams generate the most incidents?
* Which services have the longest time-to-resolve?
* How do SEV0 counts differ by environment?
Group By creates multiple series for line and column charts, segments pie charts, and supports grouping by custom fields and incident roles.
Group By is often the difference between a dashboard that reports and a dashboard that informs. If a metric is actionable, it usually has an owner — grouping by team, service, or type makes accountability visible without extra panels.
***
## Multiple datasets (comparisons)
Chart panels can include multiple datasets. Each dataset can have its own collection, filters, operation, key, and series name. Use multiple datasets for side-by-side comparisons in a single panel:
* SEV0 count vs SEV1 count over time
* Time to mitigate vs time to resolve
* Incidents from Team A vs Team B
Multiple datasets keep executive dashboards compact — you can compare related signals in one panel instead of stacking separate panels vertically.
***
## Cumulative charts
Certain chart types support **cumulative mode**, which displays running totals over time.
Supported chart types:
* Line chart
* Line stepped chart
* Column chart
* Stacked column chart
Cumulative mode is useful for:
* “Incidents year-to-date”
* “Total alerts this quarter”
* “Action items created this month”
***
## Table panels
Table panels display **raw records** rather than aggregated metrics.
They are useful when you want a dashboard that supports both:
* macro analysis (charts and KPIs), and
* direct operational drill-down (lists of incidents, alerts, or action items)
Line, line-stepped, column, and stacked-column charts support **cumulative mode**, which displays running totals over time. Useful for "year-to-date incidents", "total alerts this quarter", "action items created this month".
***
## Aggregate value panels
Aggregate panels display a **single formatted number**—ideal for KPI dashboards.
Examples:
* Total incidents (count)
* Average time-to-resolve (average)
* Total hours worked until mitigated (sum)
These panels are best for:
* Exec summaries
* Weekly reliability reviews
* “Top row” dashboard metrics
Because aggregate panels show a single value, they should be used intentionally and sparingly. They are most effective when placed at the top of a dashboard as summary indicators — supported by deeper analytical panels below.
Think of aggregate panels as headlines. The charts beneath them are the supporting evidence.
***
## Operations and keys
## Operations
Operations vary depending on the collection:
* **Count** — available for all collections
* **Average** — commonly available for Alerts and Incidents
* **Sum** — available for Alerts, Incidents, and Users (depends on the metric key)
If an operation doesn't appear for a collection, there isn't a valid numeric metric to average or sum across those records.
**Keys** are collection-specific and depend on the operation you select.
### Incidents
* **Count:** `results`
* **Average / Sum:** `triage_time`, `detection_time`, `acknowledge_time`, `mitigation_time`, `resolution_time`, `cancellation_time`, `closed_time`
### Alerts
* **Count:** `results`
* **Average:** `acknowledge_time`, `resolution_time`, `time_between_failure`
* **Sum:** `acknowledge_time`, `resolve_time`
### Users
* **Count:** `results`
* **Sum:** `hours_worked_until_triaged`, `hours_worked_until_mitigated`, `hours_worked_until_resolved`
***
## Time-based behavior
Dashboards apply time filtering automatically based on the selected date range.
Depending on the collection, Rootly uses different timestamps to scope records (for example, incidents and alerts use their `started_at` timestamps). This ensures charts remain consistent when comparing across dashboards and periods.
Time scoping is applied consistently across collections to ensure analytical integrity. This means comparisons between alerts, incidents, and retros remain aligned when viewing the same date range.
If data appears incomplete or unexpectedly low, the first place to check is always your dashboard-level date range.
Panels inherit the dashboard's date range and period grouping. Different collections scope on different timestamps (incidents and alerts scope on `started_at`, for example) so cross-collection comparisons stay aligned.
If results look incomplete or unexpectedly low, check the dashboard-level date range first.
***
## Exporting dashboards and panels
### Export a Dashboard
Open the dashboard → **⋯** → **Download PDF**. The full dashboard renders as a PDF suitable for meeting decks and reliability reports.
### Export a Panel
Hover the panel → **⋯** → choose the format:
| Format | Available For |
| :------------ | :---------------- |
| **PDF** | All panel types |
| **CSV** | All panel types |
| **JSON** | All panel types |
| **PNG / JPG** | Chart panels only |
Table exports include the full dataset — the UI-side 100-row cap does not apply to exports.
***
## Duplicate a panel
Hover a panel → **⋯** → **Duplicate**. Duplicated panels copy every configuration (filters, keys, operations, display type) and land at a default grid position with a `Copy of {original title}` name. Reposition as needed.
***
## Full screen view
Full screen mode is ideal for TVs or wallboards.
Full-screen mode is optimized for TVs and wallboards. Open a dashboard, click the full-screen icon (top-right), and press **ESC** or the icon to exit. Full-screen hides sidebar navigation, maximizes panel readability, and reformats spacing for large displays.
***
## Performance, caching, and limits
Panel data is cached, typically for \~15 minutes. If you recently changed incident data, allow 15–20 minutes for updates to reflect — especially with auto-refresh enabled. Caching keeps dashboards responsive on large datasets and is not adjustable per panel.
Other constraints:
* Panel queries are limited to **10,000 records** by default (higher limits available for Enterprise customers on request).
* Panel titles have a length cap to keep dashboards scannable.
* Table panels cap visible rows in the UI for performance; exports include full datasets.
***
## Best Practices
* **Tie dashboards to a recurring cadence** — weekly reliability reviews, monthly execs, program retrospectives, on-call readiness. Dashboards that aren't tied to a workflow go stale.
* **Prefer fewer, stronger panels.** 6–10 focused panels beat 25 competing for attention. Duplicate and specialize dashboards instead of overloading one.
* **Use Group By as your default depth tool.** Grouping metrics by team, service, or incident type makes accountability visible without needing extra dashboards.
* **Start with the question.** A good panel begins with what you want to know. Pick the collection, filters, and metric that answer that question — the chart type is the last step, not the first.
* **Use tables for drill-down, aggregate values for headlines.** Charts sit between them for trend and comparison.
***
## Troubleshooting
Three things to check, in order: the dashboard-level date range (data outside the range won't appear), the panel-level filters (an over-narrow filter can zero out the panel), and the collection (an Alerts panel won't show Incident data). If all three look right, wait \~15 minutes for the cache to refresh, then reload.
Panel results are cached for \~15 minutes to keep dashboards responsive. Configuration changes save immediately, but the underlying data may take 15–20 minutes to reflect, especially with auto-refresh on. Force a refresh by editing and re-saving the panel, or wait for the cache window to expire.
A `None` group appears when some records don't have a value for the grouped field (incidents with no service assigned, for example). Remove it in two steps:
1. **Filter out the records.** Add a panel filter on the same field you group by, operator **Exists**. Filters apply before grouping, so records missing the value drop out and the `None` group empties. Use **Not Exists** to see only the missing-value records.
2. **Hide the empty group from the legend.** Turn off **Include Groups Without Values** on the panel.
When grouping by an incident role, use the role-specific operators — filter the role as `assigned` to drop unassigned incidents, or `unassigned` to see only those. Works on pie, column, and line charts.
PNG and JPG exports are chart-only. Export tables as **PDF**, **CSV**, or **JSON** instead — all three preserve the full row set and support drill-down analysis.
Operations are gated by whether the collection has a valid numeric metric for that calculation. Users doesn't support Average — there's no per-user numeric metric to average across. If a specific operation is missing that you expect, double-check the collection choice.
Panels support filtering and grouping by custom fields, but a custom field must be enabled for the relevant collection. Under **Configuration → Custom Fields**, confirm the field is enabled for Incidents (or Alerts, etc.) that the panel pulls from.
***
## Frequently Asked Questions
Collections are seat-based. On-Call seats typically see **Alerts** only; Incident Response seats see **Incidents**, **Retrospectives**, **Action Items**, and **Users** in addition.
Dashboard filters are personal view preferences (date range, period, team, service) that apply across all panels without changing the dashboard for other users. Panel filters are stored inside the panel configuration and define the dataset for everyone who views it.
Yes. Panels support filtering and grouping by custom fields, and custom fields can also appear as columns on tables for drill-down workflows.
Panel results are cached for \~15 minutes. Changes to underlying data may take that long to appear, especially with auto-refresh enabled.
Yes. A chart panel can include multiple datasets, each with its own collection, filters, operation, and key. Use this to compare, for example, incidents against alerts on the same time axis.
Mark the dashboard as **Public** in its Sharing settings. This exposes it at a `/public/dashboards/…` URL that renders read-only. Public dashboards use a boolean visibility flag, not per-viewer tokens, so anyone with the URL can view. See [Managing Dashboards → Sharing and Permissions](/metrics/managing-dashboards#sharing-and-permissions).
# Default Metrics
Source: https://docs.rootly.com/metrics/default-metrics
Reference for every panel in Rootly's default Incident Response, Workload, and On-Call dashboards — the collection, operation, and metric key behind each.
Every Rootly workspace ships with three built-in dashboards, each pre-configured with panels that cover the common reliability questions. This page is the panel-by-panel reference — what each metric measures, which collection it pulls from, and how it's calculated.
Rootly's three default dashboards:
* **Incident Response** — Incident volume, response times, and breakdowns by severity, environment, service, functionality, and type
* **Workload** — Hours worked across incidents and responders
* **On-Call Metrics** — Alert volume, acknowledgement, resolution, and response trends
Some default panels only appear when the related fields are enabled in your workspace configuration. For example, panels grouped by Functionality only appear when Functionalities are enabled.
For the "how it works" behind these panels — collections, filters, operations, keys — see [Customizing Dashboards](/metrics/customized-dashboards). To clone and specialize any default dashboard, see [Managing Dashboards → Duplicating Dashboards](/metrics/managing-dashboards#duplicating-dashboards).
## Incident Response Dashboard
The **Incident Response** dashboard includes default metrics for incident volume, retrospectives, action items, response times, and incident breakdowns.
### Number of Incidents
| Title | # of Incidents |
| :---------- | :------------------------------------ |
| Description | Total number of incidents |
| Type | Aggregate value |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Operation | Count |
| Key | Results |
### Number of Retrospectives
| Title | # of Retrospectives |
| :---------- | :----------------------------- |
| Description | Total number of retrospectives |
| Type | Aggregate value |
| Collection | Retrospectives |
| Filter by | — |
| Operation | Count |
| Key | Results |
### Number of Action Items
| Title | # of Action Items |
| :---------- | :--------------------------- |
| Description | Total number of action items |
| Type | Aggregate value |
| Collection | Action Items |
| Filter by | — |
| Operation | Count |
| Key | Results |
### Mean Time to Detection (MTTD)
| Title | MTTD (Mean Time to Detection) |
| :---------- | :-------------------------------------------- |
| Description | Average time from incident start to detection |
| Type | Aggregate value |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Operation | Average |
| Key | detection\_time |
### Mean Time to Acknowledge (MTTA)
| Title | MTTA (Mean Time to Acknowledge) |
| :---------- | :-------------------------------------------------- |
| Description | Average time from incident start to acknowledgement |
| Type | Aggregate value |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Operation | Average |
| Key | acknowledge\_time |
### Mean Time to Mitigation (MTTM)
| Title | MTTM (Mean Time to Mitigation) |
| :---------- | :--------------------------------------------- |
| Description | Average time from incident start to mitigation |
| Type | Aggregate value |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Operation | Average |
| Key | mitigation\_time |
### Mean Time to Resolution (MTTR)
| Title | MTTR (Mean Time to Resolution) |
| :---------- | :--------------------------------------------- |
| Description | Average time from incident start to resolution |
| Type | Aggregate value |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Operation | Average |
| Key | resolution\_time |
### Incidents by Severity
| Title | Incidents by Severity |
| :---------- | :------------------------------------ |
| Description | Breakdown of incidents by severity |
| Type | Line chart or Pie chart |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Group by | Severity |
| Operation | Count |
| Key | Results |
| Legend | Include groups without values |
### Incidents by Environment
| Title | Incidents by Environment |
| :---------- | :------------------------------------ |
| Description | Breakdown of incidents by environment |
| Type | Line chart or Pie chart |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Group by | Environments |
| Operation | Count |
| Key | Results |
| Legend | Include groups without values |
### Incidents by Service
| Title | Incidents by Service |
| :---------- | :------------------------------------ |
| Description | Breakdown of incidents by service |
| Type | Line chart or Pie chart |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Group by | Services |
| Operation | Count |
| Key | Results |
| Legend | Include groups without values |
### Incidents by Functionality
| Title | Incidents by Functionality |
| :---------- | :-------------------------------------- |
| Description | Breakdown of incidents by functionality |
| Type | Line chart or Pie chart |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Group by | Functionalities |
| Operation | Count |
| Key | Results |
| Legend | Include groups without values |
### Incidents by Type
| Title | Incidents by Type |
| :---------- | :-------------------------------------- |
| Description | Breakdown of incidents by incident type |
| Type | Line chart or Pie chart |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Group by | Incident Types |
| Operation | Count |
| Key | Results |
| Legend | Include groups without values |
### Retrospectives by Cause
| Title | Retrospectives by Cause |
| :---------- | :--------------------------------------------- |
| Description | Breakdown of retrospectives by cause |
| Type | Line chart or Pie chart |
| Collection | Retrospectives |
| Filter by | Incident Kind = Normal, Normal sub, Backfilled |
| Group by | Causes |
| Operation | Count |
| Key | Results |
| Legend | Include groups without values |
> **Note:** The **Incidents by Environment**, **Incidents by Functionality**, and **Retrospectives by Cause** panels only appear when the related fields are enabled in your workspace.
## Workload Dashboard
The **Workload** dashboard helps you understand time spent across incidents and responders.
### Hours Worked (Using Resolution Time)
| Title | Hours Worked (Using resolution time) |
| :---------- | :----------------------------------------------- |
| Description | Total hours worked until incidents were resolved |
| Type | Column chart |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
| Group by | — |
| Operation | Sum |
| Key | hours\_worked\_until\_resolved |
### Hours Worked by Incident (Using Resolution Time)
| Title | Hours Worked by Incident (Using resolution time) |
| :---------- | :----------------------------------------------- |
| Description | Hours worked for each incident until resolution |
| Type | Table |
| Collection | Incidents |
| Filter by | Kind = Normal, Normal sub, Backfilled |
### Hours Worked by User (Using Resolution Time)
| Title | Hours Worked by User (Using resolution time) |
| :---------- | :------------------------------------------- |
| Description | Hours worked by responder |
| Type | Table |
| Collection | Users |
| Filter by | — |
## On-Call Metrics Dashboard
The **On-Call Metrics** dashboard tracks alert volume, response times, and alert distribution.
### Total Alerts
| Title | Total Alerts |
| :----------- | :--------------------- |
| Description | Total number of alerts |
| Type | Line chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | — |
| Operation | Count |
| Key | Results |
### Mean Time to Acknowledge
| Title | Mean Time to Acknowledge |
| :----------- | :--------------------------------- |
| Description | Average time to acknowledge alerts |
| Type | Line chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | — |
| Operation | Average |
| Key | acknowledge\_time |
### Mean Time to Resolve
| Title | Mean Time to Resolve |
| :----------- | :----------------------------- |
| Description | Average time to resolve alerts |
| Type | Line chart |
| Collection | Alerts |
| Series Label | MTTR |
| Filter by | — |
| Group by | — |
| Operation | Average |
| Key | resolution\_time |
### Mean Time to Acknowledge by Responder
| Title | MTTA by Responder |
| :----------- | :------------------------------------ |
| Description | Average acknowledge time by responder |
| Type | Line chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | Responders |
| Operation | Average |
| Key | acknowledge\_time |
### MTTR by Service
| Title | MTTR by Service |
| :----------- | :--------------------------------- |
| Description | Average resolution time by service |
| Type | Line chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | Services |
| Operation | Average |
| Key | resolution\_time |
### Mean Time Between Failure
| Title | Mean Time Between Failure |
| :----------- | :---------------------------- |
| Description | Average time between failures |
| Type | Line chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | — |
| Operation | Average |
| Key | time\_between\_failure |
### Acknowledge Rate
| Title | Acknowledge Rate |
| :----------- | :-------------------------------- |
| Description | Percentage of alerts acknowledged |
| Type | Line chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | — |
| Operation | Average |
| Key | acknowledge\_rate |
### Alerts by Source
| Title | Alerts by Source |
| :----------- | :---------------------------- |
| Description | Breakdown of alerts by source |
| Type | Line chart or Pie chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | Source |
| Operation | Count |
| Key | Results |
| Legend | Include groups without values |
### Alerts by Responder
| Title | Alerts by Responder |
| :----------- | :------------------------------- |
| Description | Breakdown of alerts by responder |
| Type | Pie chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | Responders |
| Operation | Count |
| Key | Results |
| Legend | — |
### Response Effort
| Title | Response Effort |
| :----------- | :------------------------------------------------- |
| Description | Sum of time between acknowledgement and resolution |
| Type | Line chart |
| Collection | Alerts |
| Series Label | Response Effort |
| Filter by | Status = Resolved |
| Group by | — |
| Operation | Sum |
| Key | resolve\_time |
| Legend | — |
### Alerts by Urgency
| Title | Alerts by Urgency |
| :----------- | :----------------------------- |
| Description | Breakdown of alerts by urgency |
| Type | Line chart |
| Collection | Alerts |
| Series Label | Alerts |
| Filter by | — |
| Group by | Alert Urgency |
| Operation | Count |
| Key | Results |
| Legend | Include groups without values |
### Alerts by Escalation Policy
| Title | Alerts by Escalation Policy |
| :----------- | :--------------------------------------- |
| Description | Breakdown of alerts by escalation policy |
| Type | Pie chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | Escalation Policies |
| Operation | Count |
| Key | Results |
| Legend | — |
### Alerts by Service
| Title | Alerts by Service |
| :----------- | :----------------------------- |
| Description | Breakdown of alerts by service |
| Type | Line chart or Pie chart |
| Collection | Alerts |
| Series Label | — |
| Filter by | — |
| Group by | Services |
| Operation | Count |
| Key | Results |
| Legend | — |
# Managing Dashboards
Source: https://docs.rootly.com/metrics/managing-dashboards
Create, share, duplicate, and set default dashboards in Rootly. Ownership types, permission levels, exports, auto-refresh, and deletion.
Dashboards live under **Metrics**. Every dashboard has three dimensions: **ownership** (who controls it), **permissions** (who can modify it), and **visibility** (who can access it).
This page covers creating, sharing, duplicating, exporting, and deleting dashboards. For building panels inside a dashboard, see [Customizing Dashboards](/metrics/customized-dashboards).
## Dashboard Ownership and Visibility
### Ownership Types
Dashboards are owned either by an **organization** or by an individual user.
#### Personal Dashboards
Personal dashboards are owned by an individual user.
They are ideal for:
* Exploratory analysis
* Personal reporting workflows
* Temporary or experimental views
* Individual operational tracking
By default:
* You are the **Manager**
* No one else has access unless you explicitly share it
#### Organization Dashboards
Organization dashboards are shared at the organizational level and are best suited for standardized reporting across teams.
They are appropriate when:
* Multiple teams rely on the same metrics
* Dashboards support recurring reporting, such as weekly reviews or executive updates
* Standardized views are required across departments
Organization dashboards can be shared broadly across your Rootly account.
## Creating a Dashboard
To create a new dashboard:
1. Navigate to **Metrics**
2. Click **+ Create Dashboard**
3. Configure the dashboard settings
4. Save your dashboard
Dashboards are designed to provide sensible defaults while still supporting deeper customization when needed.
## Configuration Options
When creating a dashboard, you can define:
* **Name**
* **Description**
* **Icon**
* **Color theme**
* **Date range**
* **Period grouping**
* **Auto-refresh behavior**
### Default Values
If you create a dashboard without customizing every field, Rootly applies the following defaults:
* Icon: 📊
* Date range: **Last 30 Days**
* Period: **Day**
* Auto-refresh: **Disabled**
* Color: Randomly selected from the supported palette
Color system
Dashboard colors are selected from a predefined palette to maintain visual consistency across your workspace.
### Period Grouping
Metrics can be grouped by:
* Day
* Week
* Month
* Quarter
* Year
Choosing the right grouping affects how trends are interpreted.
For example:
* **Day** is useful for short-term incident spikes
* **Month** or **Quarter** is better for leadership-level trend reporting
## Personalizing Dashboard Views
Each user can personalize how they view a dashboard without affecting anyone else.
You can adjust:
* Date range
* Period grouping
* Team filters
* Service filters
These preferences are saved per user, per dashboard.
View preferences are private.
Changing filters or date ranges does not update the dashboard for other viewers.
## Sharing and Permissions
To share a dashboard:
1. Open the dashboard
2. Click **Share**
3. Assign permission levels to users or teams
### Permission Levels
Permissions are hierarchical:
* **Viewer**
* Can view data only
* **Editor**
* Can view and modify panels
* Inherits Viewer permissions
* **Manager**
* Can view, edit, share, and delete
* Inherits Editor permissions
A dashboard must always have at least one **Manager**. You cannot remove or downgrade the last Manager until another Manager has been assigned.
Permission hierarchy matters.
Editors inherit Viewer permissions, and Managers inherit both Viewer and Editor permissions.
## Setting a Default Dashboard
You can designate one dashboard as your default.
This dashboard will automatically open when you navigate to **Metrics**.
To set a default dashboard:
1. Open the dashboard
2. Click **⋯**
3. Select **Set default**
Each user can have one default dashboard per team. Setting a new default replaces your previous default for that team.
## Duplicating Dashboards
Duplicating a dashboard is useful when you want to:
* Create team-specific variants
* Compare different time periods
* Test new panel configurations without changing the original
To duplicate a dashboard:
1. Open the dashboard
2. Click **⋯**
3. Select **Duplicate**
Duplicated dashboards:
* Include all panels and dashboard configuration
* Are created as **Personal dashboards**
* Do not inherit sharing permissions
* Are automatically renamed to **Copy of \[original name] - YYYY-MM-DD**
For example: **Copy of Overview - 2025-03-16**
## Exporting Dashboards and Panels
Dashboards and panels can be exported for reporting and distribution outside of Rootly.
### Entire Dashboard
You can export the full dashboard as:
* **PDF**
### Individual Panels
From a panel’s **More (⋯)** menu, you can export:
* **CSV**
* **JSON**
* **PDF**
* **PNG** *(chart panels only)*
* **JPG** *(chart panels only)*
These export options help teams share insights while preserving the original data and visual context.
## Auto-Refresh Behavior
Dashboards support auto-refresh, but dashboard data is still cached.
Auto-refresh is not real-time.
Changes to underlying data may take 15–20 minutes to appear due to caching and refresh intervals.
## Deleting Dashboards
To delete a dashboard:
1. Navigate to **Metrics**
2. Open the dashboard’s **⋯** menu
3. Select **Delete**
Deletion is not user-recoverable.
Dashboards use soft deletion internally, but there is no self-serve restore flow. Duplicate important dashboards before deleting them.
## Best Practices
Well-designed dashboards improve operational clarity, not just reporting.
### Separate Strategic and Tactical Dashboards
Use different dashboards for different purposes.
* **Tactical dashboards** usually use short date ranges and higher granularity
* **Strategic dashboards** usually use monthly or quarterly grouping for trends
Avoid mixing both use cases into a single dashboard.
### Limit Panel Density
Too many panels reduce clarity.
Instead:
* Create multiple focused dashboards
* Duplicate and specialize dashboards for different audiences
* Use descriptive naming conventions
For example:
* 🚨 Critical Incidents — Last 30 Days
* 📈 Reliability Trends — Quarterly
### Use Organization Dashboards for Standardization
If a dashboard is referenced in:
* Weekly reviews
* Executive reporting
* Post-incident retrospectives
It should likely be an **Organization dashboard**.
## Frequently Asked Questions
Dashboard names must be unique within your team, excluding deleted dashboards. This helps prevent confusion and keeps shared reporting environments easier to manage.
If you receive a validation error, choose a different name.
Yes. Assign users as Viewers to give them read-only access. Only Editors and Managers can modify dashboard panels.
No. A duplicated dashboard is created as a new Personal dashboard owned by the user who duplicated it. Sharing permissions must be configured separately.
Each user can have one default dashboard per team. Setting a new default replaces your previous default for that team.
Every dashboard must have at least one Manager. If you need to remove or downgrade the current Manager, assign another user or team as Manager first.
The dashboard refreshes automatically at the configured interval, but the underlying data may still be delayed because of caching. In practice, changes can take around 15–20 minutes to appear.
Dashboards are most effective when they reflect how your organization thinks about reliability. Design them intentionally, share them responsibly, and revisit them as your operational needs evolve.
# Analytics
Source: https://docs.rootly.com/metrics/overview
Understand incident performance, on-call workload, and reliability trends with Rootly's default dashboards, custom panels, and dashboard sharing.
Analytics in Rootly answers three kinds of questions: *how is our incident response performing*, *where is the on-call load falling*, and *what's changing over time*. Every workspace starts with three default dashboards. From there, you build custom panels around the questions your team actually asks in reliability reviews.
Analytics uses seat-based access. **On-Call** seats see alert-response metrics; **Incident Response** seats see incident, retrospective, action item, and user metrics on top of that.
***
## In This Section
The three built-in dashboards — Incident Response, Workload, and On-Call Metrics — and every panel that ships with them.
Create, share, duplicate, and set default dashboards. Ownership, permissions, and public link behavior.
Panel types, filters, groupings, multiple datasets, operations, and export formats.
Programmatic access to dashboards and panels via the Rootly API.
***
## The Three Default Dashboards
Every workspace ships with three curated dashboards. Each is a starting point — clone and specialize whenever a team needs its own view.
Incident volume, MTTx response times, and breakdowns by severity, environment, service, functionality, and type.
Hours worked across incidents and responders. Useful for spotting responder burnout and load imbalance.
Alert volume, MTTA, MTTR, MTBF, acknowledge rate, and alerts broken down by source, responder, and urgency.
Full panel-by-panel reference is on the [Default Metrics](/metrics/default-metrics) page.
***
## How It Works, Briefly
Every panel combines seven pieces: a **display type**, a **collection** (Incidents, Alerts, Retrospectives, Action Items, Users), **filters**, an **aggregation operation** (Count, Average, Sum), a **metric key**, an optional **Group By**, and one or more **datasets**.
Dashboards apply **dashboard-level filters** (date range, period, team, service — saved per user) on top of any **panel-level filters** built into each panel. Results cache for about 15 minutes to keep dashboards responsive on large datasets.
For the full model, see [Customizing Dashboards → How Metric Panels Work](/metrics/customized-dashboards#how-metric-panels-work).
***
## Sharing Dashboards
Rootly supports four ownership types (private, team, organization, public) and four permission roles (viewer, editor, manager, admin). Public dashboards render at `/public/dashboards/…` — read-only, no login required — gated by a boolean visibility flag on the dashboard rather than per-viewer tokens.
See [Managing Dashboards → Dashboard Ownership and Visibility](/metrics/managing-dashboards#dashboard-ownership-and-visibility) for the ownership matrix and [Sharing and Permissions](/metrics/managing-dashboards#sharing-and-permissions) for the permission roles.
***
## Related Pages
Retrospective processes, templates, and Rootly AI drafting. Retrospective completion feeds several default metrics.
Custom fields become filterable and groupable panel dimensions once enabled for their collection.
Alert lifecycle drives the On-Call Metrics dashboard — MTTA, MTTR, acknowledge rate, and MTBF.
Programmatic access to dashboards, panels, incidents, alerts, and every other Rootly object.
***
## Frequently Asked Questions
Three: Incident Response, Workload, and On-Call Metrics. Every workspace gets them on creation. Clone and specialize whenever a team needs its own version.
Yes. Chart panels support multiple datasets, each with its own collection, filters, operation, and key. Overlay incident and alert trends on one time axis to compare volume patterns.
Panel results are cached for \~15 minutes. Very recent changes may take that long to reflect — especially with auto-refresh enabled.
Dashboards export as PDF. Individual panels export as PDF, CSV, or JSON; chart panels also export as PNG and JPG. See [Customizing Dashboards → Exporting](/metrics/customized-dashboards#exporting-dashboards-and-panels).
Yes. The Rootly API exposes dashboards and panels — list, create, read, update, duplicate, and default-set. See the [API Reference](/api-reference/dashboards/list-dashboards).
# Getting started with Rootly notifications
Source: https://docs.rootly.com/notifications/getting-started
Configure general and on-call notifications in Rootly including email, Slack, SMS preferences, shift reminders, escalation rule layers, and contact methods.
Rootly notifications ensure responders stay informed without needing to constantly monitor Slack channels or dashboards. Delivery is multi-channel (Email, Slack, SMS, Phone Calls, and Push Notifications), and you can configure how and when you receive signals depending on urgency and context.
Manage your preferences in **Configuration → Notifications**.
Notifications are divided into two categories:
* **General Notifications** — awareness-based updates (assignments, mentions, summaries).
* **On-Call Notifications** — paging and escalation behavior during active shifts.
***
## General Notifications
General notifications keep you informed about operational activity even when you are not actively on call. These updates are informational — they are not designed to page you urgently.
## Email Notifications
Email is optimized for durable updates and summaries you may want to reference later.
By default, new users are subscribed to:
* Weekly incident summaries
* Postmortem publications
Depending on configuration, you may also receive assignment-based updates (such as action items or incident role assignments).
**Email requires verification**
Rootly will only deliver email notifications if your email address is verified.\
If delivery fails, verify your address before testing rules again.
***
## Slack Notifications
Slack notifications are designed for real-time collaboration and in-channel visibility.
These may include:
* Incident invitations
* Assignment notifications
* Mentions in incident messages
* Mentions in timeline events
Slack delivery requires a connected Slack account and workspace authorization.
**Slack must be connected**
If Slack is not connected, Rootly will fall back to other enabled contact methods where possible.
***
## On-Call Notifications
On-call notifications control paging behavior during active shifts. These are designed for urgent, actionable signals.
There are two core components:
1. **Shift Reminders** — pre-shift and post-shift notifications
2. **Notification Rules** — escalation logic when alerts require action
***
## Shift Reminders
Shift reminders reduce missed handoffs and give responders time to prepare.
### Default Behavior
Shift reminders are **enabled by default** for new users. Rootly automatically creates reminders for:
* `at_start` — before a shift begins
* `at_end` — before a shift ends
By default:
* Email: enabled
* Slack: enabled
* SMS: disabled
* Push notifications: disabled
### Reminder Timing
Shift reminders use **human-readable delay values**, such as:
* `"3 days"`
* `"1 day"`
* `"1 hour"`
Additional minute-level options may be available depending on feature configuration.
**Shift reminder delays are string-based**
Reminder timing uses values like `"1 hour"` or `"3 days"` —\
this is different from escalation rules, which use integer delays measured in minutes.
### Guardrails
To prevent broken configurations:
* Maximum **3 reminders per kind** (`at_start` or `at_end`)
* Each enabled reminder must:
* Have a delay selected
* Include at least one contact method
* SMS and Phone delivery require verified numbers
***
## Notification Rules (Escalation Logic)
Notification rules define how Rootly pages you when action is required.
Each rule consists of **layers**, and each layer can:
* Wait a specified number of minutes
* Use one or more contact methods
* Escalate progressively if no acknowledgment occurs
***
### Rule Types: Quiet vs Audible
Rootly separates paging into two escalation categories:
* **Quiet** — respects Do Not Disturb and reduces disruption for lower-urgency notifications
* **Audible** — intended for urgent alerts and can break through suppression (for example, critical push alerts)
Both rule types are created automatically for new users.
### Default Rules
New users receive:
* One **Quiet** rule (0-minute delay, Email enabled)
* One **Audible** rule (0-minute delay, Email enabled)
These can be modified, but:
* You must always maintain **at least one Quiet rule**
* You must always maintain **at least one Audible rule**
* You cannot delete the final rule of either type
***
### Escalation Layers
Within each rule, you can:
1. Set a delay (**integer minutes**)
2. Choose contact methods
3. Reorder layers to control escalation flow
4. Test delivery
Delays are always measured in minutes (for example, `0`, `5`, `15`).
***
### Supported Contact Methods
Rootly supports:
* `email`
* `sms`
* `call`
* `device` (critical push notifications)
* `non_critical_device` (standard push notifications)
**Verification is enforced**
* SMS and Call require verified phone numbers
* Email requires a verified email address
* Push requires the Rootly mobile app
This prevents silent paging failures.
***
### Audible Rule Requirements
Audible rules include additional safeguards to ensure responders are actually reachable:
* Layer 1 must include **Critical Alerts (`device`)**
* Subsequent layers must include at least one of:
* Critical Alerts (`device`)
* Phone Call (`call`)
These constraints ensure urgent incidents cannot rely solely on passive delivery channels.
***
## Frequently Asked Questions
Rootly requires at least one **Quiet** rule and one **Audible** rule to ensure there is always a valid notification path.
You can modify rules, adjust layers, or change contact methods — but the final rule of each type cannot be deleted. This prevents misconfiguration where alerts cannot be delivered.
**Audible notifications** are designed for urgent alerts that require immediate attention. They:
* Can bypass Do Not Disturb (via Critical Alerts)
* Require Critical Alerts (`device`) on the first layer
* Require Critical Alerts or Phone Call on subsequent layers
**Quiet notifications** are intended for lower-urgency signals. They:
* Respect Do Not Disturb
* Can rely on email or standard push notifications
* Are suitable for informational updates
Both rule types are created automatically for new users and can be customized independently.
**Phone numbers**
1. Go to **Configuration → Notifications**
2. Add a number under **Phone Numbers**
3. Enter the verification code sent via SMS or call
**Email addresses**
* Primary emails are verified automatically
* Additional emails require confirmation via a verification link
Verification is required before email, SMS, or call delivery can be used in notification rules.
Common causes include:
* Reminder is disabled
* No contact methods selected
* Contact information is unverified
* No delay selected
* No scheduled shift
Use the **Test** option in notification settings to validate delivery.
Yes. Shift reminders support:
* 3 days before
* 1 day before
* 1 hour before
Additional minute-level options may be available depending on configuration.
You can configure up to **3 reminders per kind** (before shift start or end).\
Reminder delays use human-readable values (for example, `"1 hour"`), not integer minutes.
If your phone number is not verified:
* SMS will not be sent
* Phone calls will not be sent
Email, Slack, and push notifications will still function if configured.
For Audible rules, ensure either Critical Push (`device`) or Phone Call is properly set up to maintain compliance.
Rules escalate sequentially through configured layers:
1. The first layer triggers immediately (or after its delay)
2. If unacknowledged, Rootly waits the configured delay (in minutes)
3. The next layer activates
4. Escalation continues until acknowledgment or layers are exhausted
Delays are cumulative and measured in integer minutes.
**`device` (Critical Alerts)**
* Bypasses Do Not Disturb
* Required on layer 1 of Audible rules
* Designed for urgent wake-up scenarios
**`non_critical_device` (Standard Push)**
* Respects Do Not Disturb
* Suitable for Quiet rules
* Used for informational alerts
Both require the Rootly mobile app.
Yes. You can toggle reminders off without deleting them:
1. Go to **Configuration → Notifications → Shift Reminders**
2. Disable the reminder
Disabled reminders remain saved and can be re-enabled later.
Use the **Test** button on any rule layer:
1. Navigate to **Notifications → On-Call Notifications**
2. Select a rule layer
3. Click **Test**
Rootly will attempt delivery using the configured contact methods.\
Ensure contact information is verified before testing.
Notification rules are **user-level**, not team-level.
Teams and services control routing via **Escalation Policies**, while users control how they personally receive alerts.
Rootly will continue attempting delivery according to your configured layers.\
Failed attempts are logged, and escalation continues until all layers are exhausted.
To reduce risk:
* Configure multiple contact methods
* Verify all contact information
* Connect the mobile app
* Test regularly
***
**Need help configuring notifications?**
If you're unsure which channels to enable or are experiencing delivery issues, contact [**support@rootly.com**](mailto:support@rootly.com) or use **`/rootly support`** in Slack.
***
## Related Pages
Verify and manage the phone numbers Rootly uses for SMS and voice paging.
Configure how Rootly reaches you when you're paged — audible vs quiet, per step.
Install and configure the mobile app for push-based on-call paging.
# Phone & SMS Setup
Source: https://docs.rootly.com/notifications/notification-phone-numbers
Download Rootly contact cards so your phone can recognize incoming Rootly calls and SMS notifications from on-call paging, IVR routing, and escalations.
Phone and SMS delivery can vary by carrier and location. To help you recognize important notifications, Rootly provides a contact card with the phone numbers Rootly uses to call or text you.
These are Rootly’s **outgoing numbers** — the numbers used when Rootly sends you phone calls or SMS messages.
## What Is a vCard?
A vCard is a digital contact card that contains Rootly’s outgoing call and SMS numbers.
Once you import it, your device can recognize Rootly notifications more easily when you receive:
* Phone calls
* SMS messages
## Update from the Mobile App
If you use the Rootly mobile app, you can update the contact card directly from the app.
To update your contact card:
1. Open the Rootly mobile app
2. Tap **Settings**
3. Select **Update Contact Card**
4. Confirm the update
Using the app helps keep your contact card current if Rootly adds or updates notification numbers.
## Download the vCard Manually
If you do not use the mobile app, you can download the Rootly vCard directly and import it into your contacts.
The vCard is refreshed periodically. If Rootly adds or changes outgoing numbers, download it again or update it through the mobile app to keep your contacts current.
## Frequently Asked Questions
The vCard includes Rootly’s outgoing phone numbers used for notifications, such as calls and SMS messages sent from Rootly to you.
Importing the vCard helps your phone recognize Rootly notifications, which can make it easier to identify important calls and text messages when they arrive.
No. You can download the vCard manually and import it into your contacts without using the mobile app.
Yes. Rootly may update the outgoing numbers over time, so refreshing the contact card periodically helps keep your saved contact information accurate.
***
## Related Pages
The umbrella page — how phone paging fits alongside Slack, email, and push channels.
Configure when Rootly reaches you via SMS or voice as part of an audible or quiet rule.
Push paging as a complement to SMS and voice — install and configure the mobile app.
# Alert Muting
Source: https://docs.rootly.com/on-call/alert-muting
Temporarily mute automated Rootly alert notifications to yourself from the mobile app during an alert storm, without affecting escalations or teammates.
## Overview
Alert Muting lets you temporarily stop automated alert notifications addressed to you — push, SMS, phone calls, email, and Slack or Google Chat direct messages — for a short, fixed window. It's built for [alert storms](/glossary/alert-fatigue): when dozens of alerts fire at once, muting lets you actually use your phone to triage, communicate, and resolve instead of dismissing a page every few seconds.
A few things deliberately still reach you while muted: manually triggered pages, live call routing calls, and messages posted to shared Slack channels, Teams channels, or Google Chat spaces. See [What gets muted](#what-gets-muted) for the full breakdown.
Muting is controlled entirely from the **Rootly mobile app** and only affects you. Alerts are still created, routed, and escalated exactly as configured, and your teammates are paged as normal.
***
## How Alert Muting Works
* **It's personal.** A mute only suppresses notifications sent to *you*. Everyone else on the escalation policy is notified as usual.
* **It applies to your account, not a single device.** Muting from one phone mutes notifications to all your devices and channels, and the mute state syncs to your other logged-in devices.
* **Alerts keep flowing.** Alert creation, routing, grouping, and [escalation policies](/on-call/escalation-policies) are unaffected. Alerts remain visible on the Alerts screen in the mobile app and on the web while you're muted.
* **Muted notifications are dropped, not delayed.** Anything suppressed during the mute is *not* re-delivered when the mute ends. You'll only be notified again if the escalation policy fires a new notification.
* **Mutes end on their own.** Every mute has a fixed end time and expires automatically — there's no way to mute indefinitely.
You won't be notified of automated alerts while muted. Unacknowledged alerts can still escalate to the next step of the escalation policy — potentially paging your teammates. Use short mute windows and keep an eye on the Alerts screen.
***
## What Gets Muted
| Muted while active | Never muted |
| ------------------------------------- | --------------------------------------------------------------------------------- |
| Push notifications | Manually triggered pages (a person deliberately paging you from Rootly) |
| SMS | [Live call routing](/on-call/live-call-routing) calls and voicemail callbacks |
| Phone calls | Messages posted to a Slack channel, Microsoft Teams channel, or Google Chat space |
| Email | |
| Slack and Google Chat direct messages | |
Muting only suppresses notifications addressed to you personally. Messages posted to a shared channel or space are team-wide, so they're never suppressed — even if you're the only person watching that channel.
The other two exceptions are deliberate: a manual page means a human decided you specifically need to know, and live call routing would otherwise leave a caller waiting on hold for someone who can't hear the phone ring.
***
## Mute Alerts From the Mobile App
You can open the mute screen from several places in the app:
* **Settings → Mute alert notifications**
* The **Mute** button next to **View Alert** on the *You've been paged* card
* The **mute button** on an alert's detail screen (in the action menu at the bottom)
* The **Mute** action on an incoming alert push notification
Use any of the entry points above. The quickest during a storm is the **Mute** action directly on the push notification itself.
Choose how long to mute: **2, 5, 10, or 30 minutes** (5 minutes is preselected). Durations are fixed presets — there's no custom value.
Tap **Mute**. The mute takes effect immediately across your muted notification channels and all your devices, and a confirmation shows when it ends.
Need a longer or shorter window after muting? A mute can't be extended or shortened in place — unmute, then start a new mute with the duration you want.
***
## While You're Muted
Rootly makes the muted state hard to miss so you never silently stay unreachable:
* **In-app banner** — a persistent **Muted** banner appears above the app's main tabs, with a countdown until the mute ends and a running count of alerts that would have paged you (for example, *Muted · 3 missed alerts*). Tap it to review the mute or unmute.
* **iOS Live Activity** — a Lock Screen card (and Dynamic Island on supported iPhones) shows a live countdown, the most recent alert, and an **Unmute** button.
* **Android ongoing notification** — a pinned notification shows the same countdown with an **Unmute** action.
***
## Unmute
Notifications resume as soon as any of these happens:
* The mute window **expires** (automatic).
* You tap **Unmute** on the in-app banner's mute sheet. While a mute is active, the **Mute** button on the *You've been paged* card also reads **Unmute** and opens the same sheet.
* You tap **Clear mute** on the mute screen (**Settings → Mute alert notifications**).
* You tap **Unmute** on the iOS Live Activity or the Android ongoing notification — no need to open the app.
Unmuting applies to all your devices and channels at once.
***
## What Your Team Sees
Muting yourself never hides an alert from the rest of the team — alerts are created, routed, and escalated normally, and other responders are notified as usual.
Every notification that was suppressed by your mute is recorded on the alert's timeline as a skipped notification event, visible on both web and mobile — for example: *Skipped push notification: skipped due to user notifications being muted*. This gives your team a clear audit trail of who wasn't paged and why.
Alert Muting is different from muting paging for a **service under maintenance**, which suppresses paging for a service's alerts for all responders during a scheduled maintenance window. Alert Muting only affects notifications sent to you.
***
## Requirements
* Rootly mobile app **2.15.0 or later**.
* On-call/alerting must be enabled for your organization — the mute entry points are hidden otherwise.
* An on-call seat, like all mobile app functionality — see [Mobile App](/on-call/mobile-app).
***
## Frequently Asked Questions
No. To change the duration, unmute first and then start a new mute with the window you want.
No. Suppressed notifications are dropped, not queued. After the mute ends you'll only be notified of new activity — including any notification the escalation policy fires again on an unacknowledged alert.
Yes. When someone deliberately pages you from Rootly, that page bypasses your mute on every channel. Live call routing calls also always come through.
No. Escalation policies run on their normal timers, and everyone else is notified as usual. If you don't acknowledge an alert while muted, it escalates exactly as it would have if you'd simply not responded.
No. Muting is self-service only — each user can only mute and unmute themselves, from their own mobile app.
Not currently. Muting is available only in the mobile app. The web shows the skipped notification events on alert timelines but has no mute controls.
***
## Related Pages
Download, log in, and configure push notifications — the home of alert muting.
What keeps running while you're muted — and why unacknowledged alerts still escalate.
Your audible and quiet notification rules for each channel.
# Edit Schedules
Source: https://docs.rootly.com/on-call/edit-schedules
Update on-call schedules in Rootly, manage overrides, swap shifts, and pause paging without disrupting historical data, audit trails, or reporting.
## Overview
On-call schedules are living configurations that evolve as teams grow, coverage changes, and real-world situations arise. While schedules define *who* is responsible at any given moment, Rootly is designed so that edits to schedules are **safe, auditable, and non-destructive**.
When you update a schedule—whether by adding users, creating overrides, or temporarily pausing paging—Rootly ensures that **historical records remain intact**. Past incidents, alerts, and timelines continue to reflect exactly who was on call at that moment in time, while your changes only apply going forward.
This page walks through how to confidently edit schedules after they’ve been created, including managing overrides and pausing schedules without deleting them.
### How schedule changes work
Any changes made to a schedule only affect **future shifts**.\
Rootly intentionally prevents edits from modifying past on-call history to preserve accurate audits, incident timelines, and compliance records.
### Required permissions
Only users with the following **On-Call roles** can create, edit, or delete schedules:
* Admin
* User
Users with Observer access can view schedules but cannot make changes.
***
## Managing Overrides
Overrides are the safest and most flexible way to handle short-term coverage changes. Instead of editing a rotation—which can affect many future shifts—an override temporarily assigns a specific shift to a different user while leaving the underlying schedule unchanged.
Common use cases include vacations, sick days, training, or one-off coverage swaps.
Overrides always apply to **individual users** and automatically take precedence over rotation-based shifts. Rootly enforces guardrails to ensure overrides do not overlap or create paging conflicts.
### Reassigning or Reverting an Override
To manage an override, navigate to **On-Call → Schedules** and open the schedule you want to modify. Shifts that are currently overridden are clearly marked with an **Override** label, making it easy to distinguish them from standard rotation shifts.
***
### Reverting (Deleting) an Override
Reverting an override **deletes the override entirely** and restores the shift to its original assignee based on the schedule's rotation logic. There is no separate "Delete" action for overrides — **Revert** is the deletion mechanism. Use it whenever you want to cancel an override you created in error, or once a temporary coverage change is no longer needed.
Select the overridden shift, then choose **Revert to original**. The shift will immediately return to the user originally assigned by the rotation.
Overrides can also be reverted from the **On-Call Shifts** page.\
All override actions—including creation, reassignment, and reversion—are logged and auditable.
***
### Reassigning an Override
If coverage needs to change again, you can reassign an existing override to a different user.
After selecting the overridden shift, choose the new user who should cover it and click **Create Override**. Rootly validates the change automatically, ensuring the override does not overlap with other overrides or violate paging rules.
Overrides cannot be assigned to another schedule and must always map to a single user. This ensures accountability and predictable paging behavior.
***
## Pausing a Schedule
Sometimes a schedule needs to be temporarily disabled without being deleted. This might happen during a service deprecation, team reorganization, or a period where paging should be suppressed.
In Rootly, schedules do not page responders on their own. Paging only occurs when a schedule is referenced by an **Escalation Policy**. This makes pausing a schedule both simple and reversible.
To pause a schedule, remove it from any escalation policies that reference it. The schedule itself remains fully intact and can be reactivated later by re-adding it to an escalation policy.
### How to Pause a Schedule
Navigate to **On-Call → Escalation Policies**.
Open the escalation policy that includes the schedule.
Edit the policy and remove the schedule from the **Who do we notify?** section.
Save the escalation policy.
Once removed, the schedule will stop paging immediately, but no configuration or historical data is lost.
***
## Best Practices
When editing schedules, use overrides for short-term changes and reserve rotation edits for long-term structural updates. Pausing schedules by removing them from escalation policies is safer than deleting them outright, especially if you may need them again in the future.
Regularly reviewing schedules after team changes helps prevent stale paging paths and ensures alerts always reach the correct responder.
***
## Frequently Asked Questions (FAQs)
No. Overrides only apply to future shifts. Rootly never rewrites historical on-call data, ensuring incident timelines and audits remain accurate.
No. Overrides must always be assigned to an individual user. Schedules cannot be used as override targets.
Rootly records the change in the audit log and can notify responders through integrated channels such as Slack, ensuring visibility into coverage changes.
Remove the schedule from all associated escalation policies. This pauses paging while preserving the schedule for future use.
***
## Related Pages
The parent concept — schedules are what these edit / pause / delete operations act on.
Removing a schedule from every escalation policy is how you pause it without deleting it.
A lighter-weight alternative to editing the schedule for one-off swaps.
# Escalation policies for on-call alert routing
Source: https://docs.rootly.com/on-call/escalation-policies
Configure Rootly escalation policies with multi-step targets, time delays, and round robin to make sure on-call alerts get acknowledged and acted on.
## What Is an Escalation Policy?
Escalation Policies define **how Rootly notifies responders when an alert requires attention** and what happens if that alert is not acknowledged in time. They are the backbone of on-call reliability—ensuring alerts reach a human, escalate predictably, and never fall through the cracks.
An escalation policy answers three core questions:
* Who should be notified first?
* What should happen if no one responds?
* How long should Rootly keep escalating before stopping?
Escalation Policies can be assigned to a **Team** or **Service**. When that Team or Service is paged, their assigned escalation policy will trigger.
***
## Create an Escalation Policy
Escalation policies are created from the On-Call section of the web app.
To create a new escalation policy:
Navigate to **On-Call → Escalation Policies**.
Click **+ Add Escalation Policy**.
Enter an **Escalation Policy Name** (required) and an optional description.
When you create an escalation policy, a **Default Escalation Path** is automatically created with **Audible notifications** enabled. This default path cannot be deleted and acts as a fallback if no other escalation paths match.
***
## Step 1: Who Do We Notify?
Some alerts resolve themselves quickly. If this is common, consider adding a short **Wait period** at the top of your Escalation Path setup before the first escalation step so transient issues don’t immediately page responders.
This step defines **who is initially responsible** for responding when an alert is triggered.
Rootly supports notifying:
* Individual users
* On-call schedules
* Team members or team admins
* Slack channels (for visibility)
* Escalating to other Teams or Services
### Paging Strategies
Each escalation level has a **paging strategy** that controls which pageable responders are notified and in what order when the level triggers. You can configure the strategy when adding targets to a level.
Paging strategies apply only to **pageable targets** — users, schedules, and team responders. Slack channel targets (added for visibility) and Escalate targets always fire regardless of the strategy selected.
Pages the person currently on-call for any schedule targets in the level. Individual user targets are always paged directly. This is the standard strategy and the right choice for most escalation levels.
Pages all members of every schedule in the level at once, regardless of who is currently on-call. Use this for critical escalation levels where broad coverage matters more than targeted paging.
Randomly selects one pageable responder from the level and pages only them. Useful when any responder in the group is equally qualified and you want to avoid alerting everyone at once.
Rotates the first-paged responder across incoming alerts — Alert A pages User 1, Alert B pages User 2, and so on. Distributes alert load evenly over time. Learn more in the [Round Robin documentation](/on-call/round-robin-functionality#alert-based-paging).
Pages each pageable target in the level sequentially within a single alert, cycling through all members before escalating to the next step. Learn more in the [Round Robin documentation](/on-call/round-robin-functionality#cycle-based-paging).
When a **Team** is added as a notification target, you can choose to page all team members, team admins only, or escalate directly to the team's own escalation policy.
If an alert needs to be handed off to another group (such as a Team or Service), you can use an **Escalate** target. This triggers the target's escalation policy **in parallel**, while the original policy continues executing.
If your alert source sends a re-trigger event, Rootly will re-page the responder who last acknowledged the alert. If the alert remains unacknowledged, escalation continues according to the policy’s steps.
***
## Step 2: Add Escalation Steps
Escalation steps define **what happens next if an alert is not acknowledged**.
Each step includes:
* A delay (in minutes)
* One or more notification targets
Delays start counting from the previous step (or alert creation for the first step). This allows escalation to widen gradually as urgency increases.
***
## Step 3: Configure Repeat Behavior
If an alert remains unacknowledged after all steps complete, you can choose to **repeat the escalation policy**.
When enabled, Rootly restarts escalation from the beginning and continues until:
* The alert is acknowledged, or
* The repeat limit is reached
This is commonly used for high-severity alerts where acknowledgement is mandatory.
***
## Step 4: Save and Assign the Policy
Saving the policy does not activate it.
Escalation policies only run once they are assigned to a **Service** or **Team**: when the Service or Team is paged, their assigned escalation policy will trigger.
1. Assign the escalation policy to a **Team** using the **Owning team** field.
1. **Note**: Any admin of an Owning Team of an Escalation Policy will also inherit edit permissions for that Escalation Policy.
2. Assign the escalation policy to a **Service** from the Service Configuration section of the dashboard.
***
## Dynamic Paths
Escalation policies can contain **multiple paths**, each with its own rules and steps, allowing you to set up unique paging logic for different scenarios. Dynamic Paths allow you to model scenarios such as:
* Business hours vs after hours
* High vs low urgency alerts
* Deferring pages on weekends vs. weekdays
Rootly supports two kinds of dynamic paths: **Escalation Paths**, and **Deferral Paths**. Escalation Paths trigger the alert right away and begin paging based on the path's logic. Deferral Paths will hold off on triggering the alert for a window of time, then trigger the alert and begin paging based on a related Escalation Path.
Rootly evaluates Deferral Paths first, and can only be active during a certain time window. Once the time window lapses, Rootly will then evaluate Escalation Paths. All paths are evaluated top to bottom: the first path that matches the alert will be executed.
Create a new Dynamic Path by navigating to the Paths tab, and select **New Path**.
## Escalation Paths
Build Dynamic Escalation Paths when you want to have different paging logic for different types of alerts: for example, you may want to page different schedules depending on the time of day, or different users depending on the alert's urgency.
Set up your Escalation Path:
Give your path a detailed name. When the path is executed for an alert, the path name will show on the alert's timeline.
Add conditions for when the path should be executed. You can build conditions around alert details:
* Alert Urgency
* Alert Fields
* Services on the Alert
* Alert's Payload (represented as a JSONPath)
Time restrictions limit the times of day for when the path can execute. The path has a single time zone that applies to every time restriction on it — Rootly evaluates each window in that zone.
Select if the path will be executed if `Any` or `All` of the conditions are true. This logic applies to both the Conditions and Time Restrictions.
Set the notification type for the Path. See [Audible vs. Quiet Notifications](#audible-vs-quiet-notifications) below to learn more about notification types.
Click **Done**, and begin adding the paging logic following the same process as your Default Path.
As you continue adding additional Escalation Paths, use the left-hand sidebar to drag-and-drop the paths into the order you'd like them to be evaluated in.
### Audible vs Quiet Notifications
Each Escalation Path is either **Audible** or **Quiet**:
* **Audible paths** are designed to wake responders and trigger critical notifications
* **Quiet paths** respect Do Not Disturb and are used for lower-urgency alerts
Audible and Quiet paths map directly to each user’s notification rules. Learn more in [Audible and Quiet Notifications](/on-call/on-call-notifications).
### Limits and Constraints
Escalation Paths have a few important limits:
* **Maximum escalation levels:** 20 per path
* **Maximum targets per level:** 25
* **Repeat count:** 1–9 cycles
* **Maximum delay per step:** 10,080 minutes (1 week)
Keeping policies simple and within these bounds improves reliability and maintainability.
## Deferral Paths
Build Deferral Paths when you want to hold off on paging until a later time. Rootly recommends using Deferral Paths for **low-urgency alerts only**, so your responders never miss an urgent page.
When a Deferral Path is executed, it will hold off on triggering the Alert until the time window closes: once it closes, Rootly will trigger the alert and begin paging based on a matching Escalation Path.
Set up your Deferral Path:
Give your path a detailed name. When the path is executed for an alert, the path name will show on the alert's timeline.
Add conditions for the types of Alerts that the path can map to. You can build conditions around alert details:
* Alert Urgency
* Alert Fields
* Services on the Alert
* Alert's Payload (represented as a JSONPath)
Add a time interval: this is the window of time the path can match to an alert. Once the interval concludes, Rootly will trigger the alert.
All Deferral Paths must have a time interval.
Selecting **All day** covers the selected day from 12:00 AM to 12:00 AM — the window ends at midnight, not at the start of your next working day. For example, a weekend deferral set to **All day** on Saturday and Sunday closes at 12:00 AM on Monday: deferred alerts trigger at midnight, and alerts arriving between midnight and the start of business on Monday are not deferred. To hold alerts until Monday morning, add a Monday time block from 12:00 AM to your working start time (for example, 12:00 AM – 9:00 AM).
Define the **After Deferral** logic. Once the time interval lapses, this determines which Escalation Path gets triggered:
* **Re-evaluate the alert** — Rootly will review all Escalation Paths (in the priority order) and execute the first matching path.
* **Choose path** — Rootly will execute the defined path.
Rootly recommends choosing a specific path if you do not want to follow your standard paging logic like the alert came in during regular hours. For example, you may want to defer low-urgency alerts on weekends, and then come Monday start paging on the alert as if it was high-urgency.
Click **Done**. You can edit the path's details at any time.
## Frequently Asked Questions
No, only alerts from Alert Sources, Live Call Routing, and Rootly's API are deferred. This means that any manual pages (in other words, alerts created by a user either directly in the web app or on Slack), alerts created through workflows, and any alerts from Heartbeats will not be deferred.
Note: Rootly will only defer up to 50 Alerts at a time **per escalation policy**.
Deferred alerts can be grouped. However, Rootly only groups deferred alerts together: paging alerts will never be grouped with deferred alerts. This ensures that any urgent alerts that should page never get deferred until a later date.
***
## Edit or Delete an Escalation Policy
To edit or delete a policy:
Navigate to **On-Call → Escalation Policies**.
Click the `…` menu next to the policy.
Select **Edit** or **Delete**.
Deleting an escalation policy is permanent. To disable a policy temporarily, unassign it from all teams and services instead.
***
## Best Practices
* Use short delays for high-severity alerts
* Assign policies to services whenever ownership is clear
* Avoid overly complex escalation trees
* Test policies with non-critical alerts before production use
* Use escalation paths to model time-based or urgency-based behavior
***
## Frequently Asked Questions
Escalation continues through all steps and repeat cycles until the alert is acknowledged or the policy completes.
Yes. If an acknowledgment timeout is configured and expires without resolution, escalation may resume.
Yes. Using an Escalate target triggers the destination policy while the original policy continues in parallel.
Yes. A Slack channel isn't tied to a single policy — add it as a notification target on a level in each escalation policy where you want it to post. The same channel can appear on as many policies, and as many levels within them, as you need.
Slack channels are added [for visibility](#step-1-who-do-we-notify), so the channel is notified whenever a level it's attached to fires, regardless of that level's paging strategy.
No. Escalation policies page responders. Incident creation is controlled separately through alert routing and workflows.
The step still runs and waits its full delay before escalating. Rootly does **not** auto-skip a step that has no one on call — if you build a step that points at a schedule with a coverage gap (for example, a business-hours schedule outside business hours), the alert sits there for the configured delay, pages no one, then moves to the next step.
To get "skip the layer if nobody is on call" behavior, model it with [Dynamic Paths](#dynamic-paths) instead of relying on the order of steps in a single path:
* Build one **Escalation Path** with a **working-hour rule** (or a time restriction) that matches your business-hours coverage. Put the business-hours schedule as Step 1 and the 24/7 fallback schedule as Step 2.
* Build a second **Escalation Path** for the inverse window (no working-hour match) that goes straight to the 24/7 fallback as Step 1.
Outside business hours, the first path doesn't match, the second path fires immediately, and the 24/7 schedule pages without the empty-step delay.
For the alternative case where you want to *defer* a low-urgency alert until coverage resumes (rather than page the fallback right away), use a [Deferral Path](#deferral-paths) instead.
There's no in-product "Download" or "Export" button for escalation policies today — bulk export is programmatic. Two paths cover the common needs:
* **API.** `GET /v1/escalation_policies` returns every policy on your account. Walk into each policy with `GET /v1/escalation_policies/{id}/escalation_paths` and `GET /v1/escalation_paths/{id}/escalation_levels` to capture the full structure including paths and per-step targets. JSON output is the most flexible source for backups, audits, or feeding into other tools.
* **Terraform.** Use the [Terraform provider](/integrations/terraform) with the `rootly_escalation_policy`, `rootly_escalation_path`, and `rootly_escalation_level` resources. The [Importing Existing Resources](/integrations/terraform#importing-existing-resources) workflow pulls existing policies into Terraform state so they live in source control going forward.
Timestamps in Slack alert notifications use the time zone configured on the escalation path that routed the alert — the same zone that decided the path matched in the first place. Because a path has one time zone that applies to every time restriction on it, there's no ambiguity when a path has multiple restrictions.
If the matched path has no time zone set (for example, the Default Escalation Path with no time restrictions), timestamps fall back to your organization-wide time zone.
For example, an alert routed by a path configured for London time shows London time in its Slack notifications, even if your organization's time zone is set to a different region.
***
## Related Pages
Schedules feed into escalation policy steps — the coverage layer under this paging engine.
Urgency drives Dynamic Escalation Paths — which path an alert takes depends on its urgency.
Where each responder configures how audible / quiet notifications reach them across channels.
# Heartbeats
Source: https://docs.rootly.com/on-call/heartbeats
Continuously verify system health using Rootly Heartbeats and automatically trigger alerts on missed pings from cron jobs, schedulers, and background workers.
## Overview
Heartbeats allow you to monitor critical systems by requiring them to “check in” on a regular cadence.\
If a heartbeat fails to ping within the expected interval, Rootly automatically triggers an alert and notifies the appropriate on-call responders.
This ensures:
* Early detection of system failures
* Automatic paging when checks go silent
* Reliable uptime verification across services
* Zero reliance on external monitoring tools for liveness checks
***
## How Heartbeats Work
Each Heartbeat cycles through three statuses:
* **waiting** — newly created or recently updated; awaiting first ping
* **active** — successfully pinged and within its valid interval
* **expired** — missed its expected check-in; triggers a Heartbeat Alert
Each heartbeat is **disabled by default**. When enabled, Rootly tracks pings and expiration windows.
When a ping is received:
* `last_pinged_at` is updated
* `expires_at` is set to `now + interval`
* Status becomes **active**
* If transitioning from non-active → active, Rootly **resolves all open heartbeat alerts**
***
## Creating & Configuring Heartbeats
Navigate to **On-Call → Heartbeats** and click **+ New Heartbeat**.
Configure each field:
A unique name for this heartbeat within the team.
Optional context — what this heartbeat covers and why it exists.
Who or what gets paged when the heartbeat expires. The target determines which escalation path runs.
The summary that appears on the generated heartbeat alert.
Optional but recommended — controls how the missed-ping alert is escalated. Falls back to the team default if unset.
How often the heartbeat expects a ping. Interval accepts `1–300` (minimum `60` when the unit is seconds); the unit is one of seconds, minutes, hours, or days.
Heartbeats start in **waiting** and **disabled** until explicitly enabled.
Enabling a heartbeat begins the monitoring cycle. Note:
* Changing **interval**, **interval unit**, or **enabling** a heartbeat resets it back to **waiting**
* A heartbeat becomes **active** only after its **first successful ping**
***
## Pinging Heartbeats
Systems can ping heartbeats using **HTTP** or **email**.\
Both methods behave identically: they reset the timer and, if previously expired, will **resolve all heartbeat alerts**.
### HTTP Ping (recommended)
Use the automatically generated ping URL:
```bash theme={null}
curl -X POST https://api.rootly.com/v1/heartbeats/{heartbeat_id}/ping \
--header 'Authorization: Bearer {heartbeat_token}'
```
Replace `{heartbeat_id}` with your Heartbeat’s UUID and `{heartbeat_token}` with your Heartbeat's Auth token.\
Both are displayed directly in the Heartbeat’s configuration page.
Authorization header is required to send HTTP pings.
HTTP pings are ideal for scripts, cron jobs, containers, CI pipelines, and any system capable of making HTTP requests.
***
### Email Ping
Every Heartbeat is also assigned a **unique email address**:
```text theme={null}
heartbeat-@
```
Sending *any* email to this address counts as a valid ping.
**Common use cases:**
* Legacy systems that only support email notifications
* Backup/cron jobs that already send “success” emails
* Air-gapped or restricted systems that cannot perform HTTP requests
Behavior:
* Email subject/body do **not** matter
* Each valid email resets the Heartbeat’s timer
* Invalid addresses return a bounce notification
You can find the Heartbeat’s email address directly in its configuration panel.
***
## Heartbeat Expiration & Recovery
### When Does a Heartbeat Expire?
A Heartbeat transitions to **expired** when:
```text theme={null}
current_time > expires_at
```
When expired:
* A **Heartbeat Alert** is created
* Routing rules determine who gets paged
* Escalation Policies and Alert Urgency define notification behavior
***
### Automatic Recovery
If an expired heartbeat receives a ping:
1. Status transitions **expired → active**
2. All open Heartbeat Alerts are **automatically resolved**
3. A recovery event is added to the alert timeline
This avoids noisy follow-up alerts and validates system recovery.
***
## Who Gets Paged for a Missed Heartbeat
Every Heartbeat must be configured with **one notification target**:
* **Escalation Policy**
* **Service**
* **Team (Group)**
* **User**
Rootly applies your workspace's:
* Escalation rules
* Working hours
* Alert urgency
* The paged responder's [notification rules](/on-call/on-call-notifications), which decide which delivery methods reach them
Missed pings create a heartbeat alert that follows the routing of the target you chose.
***
## Best Practices
* Use **short intervals** (1–5 minutes) for critical services
* Set **High urgency** for production-impacting checks
* Use **email pings** for legacy or offline systems
* Name Heartbeats clearly (for example, `api-liveness`, `db-backup-success`)
* Use separate Heartbeats for independent components
* Review heartbeat alerts weekly to detect flapping or missing pings
***
## Troubleshooting
* Heartbeat may not be **enabled**
* Interval or unit was recently changed → resets to waiting
* No valid pings received yet
* Verify ping URL or email address is correct
* Interval may be too large
* System may be sending frequent pings
* Verify whether alert resolution is immediately resetting intervals
* Check whether status transitioned `expired → active`
* Ensure ping reached the correct Heartbeat ID
* Review timeline for recovery events
* Inbound email domain may not be configured
* MX records could be missing or misconfigured
* Invalid email formats will bounce
***
## Related Pages
Missed pings create heartbeat alerts — they flow through the same routing and paging pipeline.
Where a heartbeat alert is routed once it fires — the same escalation logic every other alert follows.
Each heartbeat carries an urgency that decides how aggressively responders are paged.
# Adding a Holiday Calendar
Source: https://docs.rootly.com/on-call/holiday-calendar
Preview team holidays and PTO directly alongside your Rootly on-call schedules to proactively identify coverage gaps and plan rotations around time off.
## Overview
Holiday calendars allow you to overlay your team’s **holidays, vacations, and paid time off (PTO)** directly on top of your Rootly on-call schedules. By visualizing time off alongside on-call coverage, teams can proactively identify potential gaps, avoid paging unavailable responders, and make adjustments before incidents occur.
Rather than reacting to conflicts after an alert fires, holiday calendars help you plan coverage with confidence—especially for global teams, shared rotations, and extended leave periods.
Holiday calendars are read-only previews. They do not automatically change schedules, but they make it easy to spot conflicts and quickly create overrides when needed.
***
## Creating a Holiday Calendar
Holiday calendars are added using an **iCal (ICS) feed**, which allows Rootly to continuously sync events from your existing calendar tools.
To create a new holiday calendar:
Navigate to **On-Call → Schedules** in the Rootly dashboard.
In the calendar preview, open the **Holiday calendars** dropdown.
Select **Add your team’s holiday calendar**, then choose **Add a holiday calendar**.
Paste the **iCal URL** for your team’s holiday or PTO calendar.
Provide a clear, descriptive name so teammates understand what the calendar represents.
Select the appropriate timezone (or leave it blank to allow Rootly to infer it from the calendar).
Click **Add** to save.
Once added, Rootly will fetch the calendar and sync its events automatically.
Back in the schedule view, you can select the holiday calendar from the dropdown to immediately see upcoming holidays and PTO displayed alongside your on-call shifts.
***
## How Holiday Calendars Work in Practice
When a holiday calendar is enabled for preview, Rootly overlays calendar events directly onto the on-call schedule timeline. This makes it easy to see when a responder is scheduled to be on call during a holiday or vacation period.
Rootly intelligently expands recurring events, applies the correct timezone, and normalizes all-day events so conflicts are accurately detected. If a shift overlaps with a holiday or PTO event, that shift is visually highlighted to draw attention to the potential issue.
Holiday calendars are continuously kept up to date. Rootly automatically resyncs events in the background, so changes made in your source calendar are reflected without manual intervention.
***
## Identifying and Resolving Conflicts
When Rootly detects a potential conflict—such as an on-call responder being on vacation—it highlights the affected shift directly in the schedule view.
From there, you have a few options:
* Review the conflict and confirm coverage is acceptable.
* Create a temporary override to assign another responder.
* Adjust the schedule to redistribute coverage.
* Intentionally ignore the conflict if the responder is still available.
To take action quickly, you can click directly into the highlighted event and start the override flow with dates and times prefilled.
For step-by-step guidance on making these adjustments, see\
[Create an Override](/on-call/on-call-shifts#create-an-override).
***
## Best Practices
Using holiday calendars effectively can significantly improve on-call reliability. Many teams follow these best practices:
* Maintain a single shared PTO calendar per team or region.
* Use clear naming conventions (for example, “EMEA Holidays & PTO”).
* Review upcoming conflicts during on-call handoffs or planning meetings.
* Combine holiday calendars with overrides rather than editing schedules directly.
* Keep calendars synced rather than manually managing time-off in multiple systems.
Holiday calendars work best as an early-warning system—helping teams stay ahead of coverage issues instead of reacting under pressure.
***
## Frequently Asked Questions
No. Holiday calendars are used for **visibility and planning only**.\
They do not automatically reassign shifts or remove responders. You remain in full control of when and how overrides are created.
Rootly supports standard **iCal / ICS feeds**. These can come from tools like Google Calendar, Outlook, or other calendar providers that expose an iCal URL.
Holiday calendars are synced automatically in the background.\
Rootly refreshes events on creation and continues to resync periodically to ensure changes in your source calendar are reflected accurately.
Rootly expands recurring events and normalizes all-day events so conflicts are detected correctly.\
This ensures that multi-day vacations and company-wide holidays are fully accounted for when reviewing coverage.
Yes. Teams can add multiple holiday calendars and choose which ones to preview in the schedule view.\
This is useful for organizations with multiple regions, departments, or distinct PTO policies.
***
## Related Pages
Attach a holiday calendar to a schedule so conflicts surface during on-call planning.
Where the holiday overlay shows conflicts and lets you create overrides in one click.
Self-service coverage swaps when a conflict lands on your shift.
# Live Call Routing
Source: https://docs.rootly.com/on-call/live-call-routing
Turn a phone call into a page. Route inbound calls to the on-call responder, or drop them to voicemail with an automatic alert.
## Overview
Live Call Routing gives your team a phone number that pages the right person. A caller dials the number, Rootly figures out who's on call, and either connects the two live or takes a message and pages the on-call responder. It's designed for the calls that shouldn't wait — a customer reporting an outage, an on-site engineer needing help, a vendor calling in — where email or a form is too slow.
Every routing number lives on the **On-Call → Live Call Routing** tab and combines four pieces:
* A **routing mode** — either connect the caller to a responder or drop to voicemail.
* A **number** — the phone number callers actually dial.
* **Routing rules** — who gets paged, at what urgency, optionally through an IVR menu.
* A **greeting** — what the caller hears when Rootly picks up.
***
## Choose a Routing Mode
Both modes result in a page — the difference is whether the caller waits on the line.
| Mode | What happens | Use when |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| **Connect Live** | Rootly answers, pages the responder, and connects the call once they answer. The caller waits on the line (with hold music if configured) until the responder picks up. | Live production issues where the caller needs someone on the line right now. |
| **Route to Voicemail** | Rootly answers, records a message, and pages the responder. | Lower-severity intake or when the responder needs context before calling back. |
***
## Create a Routing Number
Go to **On-Call → Live Call Routing** and choose **+ New Routing Number**.
Choose **Connect Live** or **Route to Voicemail** — see the table above.
Give it a name, pick a country, and choose a number type (local, mobile, or toll-free). Rootly provisions a number once you save; it appears under **Your Number** on the setup screen.
Choose **who to page**. Set an **alert urgency** on the routing number — or, if you add multiple targets and turn it into a [Calling Tree](#ivr-calling-trees), set urgency per mapping instead.
Add the message Rootly reads to callers. Keep it short — most callers hang up on long menus.
Save. The number appears in the Live Call Routing tab.
### Number Fields
Name for your new routing number.
See [Supported Countries](#supported-countries).
Availability varies by country.
Once saved, **Your Number** appears on the setup screen.
***
## Routing Rules
Routing rules decide who Rootly pages when a call comes in.
Required on the routing number **unless** you configure a Calling Tree. With a Calling Tree, urgency is set per mapping instead — see [IVR Calling Trees](#ivr-calling-trees) below and [Alert Urgency](/alerts/alert-urgency).
### IVR Calling Trees
Adding more than one paging target turns the number into an IVR menu. Rootly asks the caller to press a digit for their destination and pages the matching target.
* Each target has a digit shown in the first column of the target list. Digits must be unique across the list.
* With a Calling Tree, urgency is set per mapping rather than once at the routing-number level — see [Alert Urgency](/alerts/alert-urgency) for how to configure per-mapping urgency.
* Rootly reserves `*` for "repeat the menu."
* Your greeting must tell callers which digits map to which teams. *"Press 1 for Security, 2 for the Database team, or 3 for the On-Call Engineer."*
A single company-wide routing number with a calling tree usually beats one number per team. Callers only have to remember one phone number, and adding a new team is one row in the IVR, not a new number to publish.
### Advanced Settings (Connect Live only)
Connect Live exposes three extra settings under **Advanced Settings** in the routing rules tab.
Send the caller to voicemail if no one answers after the configured amount of time.
How long to wait between escalation-policy levels when a caller is on the line.
***
## Greetings
The greeting is the first thing your caller hears. Keep it short and load-bearing — a name, a menu (if there is one), and nothing else.
The initial message Rootly reads to your callers.
What the caller hears while waiting on hold. Applies to Connect Live.
The message played when the caller is sent to voicemail.
***
## Supported Countries
| Country | Code |
| -------------- | ---- |
| Australia | AU |
| Canada | CA |
| Germany | DE |
| Netherlands | NL |
| New Zealand | NZ |
| United Kingdom | GB |
| United States | US |
If your country isn't listed, contact your Rootly representative to discuss availability in your region.
***
## Best Practices
* **Use Connect Live for production issues.** A hold with music beats a callback for anything actively burning.
* **Use Voicemail for intake queues.** Vendor calls, internal help lines, and anything the responder should hear before calling back.
* **Publish one number, not one per team.** A single company-wide number with an IVR routes to any team and only needs updating once.
* **Keep the greeting short.** Long menus lose callers before they finish listening.
* **Assign meaningful digits and match them in the greeting.** For example, `1 = Security, 2 = Database, 3 = On-Call Engineer` — memorable digits reduce misdials.
* **Shorten escalation delays for live calls.** A caller on hold notices seconds — set the Connect Live escalation override low.
***
## Troubleshooting
Rootly couldn't provision a number matching your selections.
* The requested number type may be out of stock in that country. Try another type (local, mobile, toll-free).
* Try another country if the caller can dial internationally.
* Contact Rootly support if all combinations fail — regional inventory changes over time.
The IVR isn't accepting or acting on caller input.
* The greeting isn't telling the caller what to press. Add a menu prompt.
* Two targets have the same digit. IVR mappings must be unique — adjust the list so every target has a different digit.
* The number has only one target. IVR menus only appear when there are two or more.
The call connected but no one got paged.
* Alert urgency isn't set on the routing number or on the specific IVR mapping.
* The paging target has been removed or is no longer valid.
Callers hear silence while waiting on Connect Live.
* Waiting music must be selected from the approved Rootly list.
***
## Related Pages
Who gets paged when a caller comes in — and what happens if they don't answer.
Why live call routing rings responders even while their automated alerts are muted.
The channels a paged responder receives calls on.
# Rootly Mobile App
Source: https://docs.rootly.com/on-call/mobile-app
Download and use the Rootly mobile app for iOS and Android to receive, acknowledge, and escalate alerts while on-call, with critical alert and override support.
Required User Seats and User Permissions
Users will need an on-call seat to log in and access the app.
The Rootly mobile app lets you receive and acknowledge alerts, escalate alerts to incidents, and see all the information you need while you are on-call.
## Download the mobile app
Rootly's mobile app supports both iOS and Android devices.
Download from the App Store
Download from Google Play
After downloading:
1. Open the Rootly app on your device
2. Enter your Rootly credentials to log in
## Log in to Rootly
Log in to your Rootly account using any of the following methods:
* Email address and password
* Google SSO
* Slack SSO
* Third-party identity provider (SAML SSO)
### Compatibility
The minimum supported operating system versions are:
* Android 9+ (SDK 28+)
* iOS 17.6+
## Rootly AI
Rootly AI is built into the mobile app so on-call responders can get up to speed and ask questions from their phone — with an **Incident Summary** card on every incident's Details tab and a conversational **Rootly AI** assistant behind the **Ask Rootly** launcher.
Mobile is enabled by a separate toggle from the web assistant (**Rootly Agent in Mobile**), so an Admin can turn it on for phones independently of the other surfaces. For the full walkthrough — Incident Summary, Rootly AI chat, taking actions, prerequisites, and privacy — see **[Rootly AI on Mobile](/ai/rootly-ai-on-mobile)**.
## Push Notification
Pages not coming through, or arriving silently? See [**Notification Troubleshooting**](/troubleshooting) for symptom-by-symptom fixes across [iOS](/troubleshooting/ios) and [Android](/troubleshooting/android): Do Not Disturb, battery optimization, calls that don't ring, and device-specific (Samsung, Pixel, OnePlus) issues.
iOS uses critical alerts for high urgency alerts.
Apple Watch Compatibility
If you have an Apple Watch connected to your iPhone, critical alerts may not play sound on your iPhone. To fix this:
1. Open the Watch app on your iPhone
2. Go to Notifications
3. Scroll down to "Mirror iPhone Alerts from"
4. Unselect Rootly
This allows the full Rootly sound to play on your iPhone while on-call.
#### Battery-Saving Mode
Users may experience delayed notifications when using battery-saving mode. To resolve this for Rootly, navigate to Settings > Battery > Battery usage > Rootly, and choose Unrestricted.
On some devices, this setting might appear as Don't wake for notifications. Disabling this option can help ensure notifications are received promptly.
#### Samsung
Battery Optimization and App Restrictions: Samsung devices are known to aggressively manage background processes to optimize battery life. When an app is in the background or killed, Samsung’s battery optimization settings can block notifications entirely, or modify their behavior (such as muting sound or vibration). You can check if battery optimization is affecting your app:
`Go to Settings > Apps > Your App > Battery > Optimize Battery Usage and turn off optimization for your app.`
Device-Specific Notification Handling: Some Samsung devices (especially recent ones with One UI) impose additional restrictions on background notifications. You might need to guide users to allow the app to run in the background or turn off restrictions. For this:
`Go to Settings > Device Care > Battery > App power management and disable "Put unused apps to sleep" for your app.`
Android Work Profiles
Due to a Work Profile limitation from Android, overriding System Volume and Do Not Disturb will not work when the Rootly app is under a Work Profile.
For better behavior, it is recommended to also add **Google Chrome** to your Work Profile alongside the Rootly app. This ensures optimal functionality and performance.
## Alert Muting
During an alert storm you can temporarily mute automated alert notifications addressed to you — push, SMS, calls, email, and chat direct messages — for 2 to 30 minutes, directly from the app or from an alert push notification. Manually triggered pages and live call routing still come through. Alerts keep flowing and escalation policies run as normal; only your own notifications pause. See [Alert Muting](/on-call/alert-muting).
## Home Screen Widgets
Add the Rootly widget to your iPhone or Android home screen to see whether you're on call, when your current shift ends or your next one starts, and which schedules you're covering — without opening the app. See [Mobile Home Screen Widgets](/on-call/mobile-widgets).
## China Support
Rootly is available in China in the following stores.
| Store | Status | Link |
| :----- | :-------: | :--------------------------------------------------------------------------------------------------------------------------: |
| HUAWEI | Published | N/A |
| HONOR | Published | [Open Link](https://appmarket-h5.cloud.honor.com/h5/share/latest/index.html?shareId=2028301555266736128\&shareTo=copyLink#/) |
| OPPO | Published | N/A |
| VIVO | Published | [Open Link](https://h5coml.vivo.com.cn/h5coml/appdetail_h5/browser_v2/index.html?appId=4028419) |
| XIAOMI | Published | [Open Link](https://app.mi.com/details?id=cn.net.rootly.app) |
Store listings track the current Rootly mobile release — new versions are published to all five stores as part of the regular release process. Where no direct link is listed, search for **Rootly** in the store on your device.
On Huawei devices, Rootly requires an Android-based HarmonyOS build (HarmonyOS 2, 3, or 4). Devices shipping HarmonyOS NEXT / HarmonyOS 5 do not run Android apps and are not supported.
## Intune Support
Rootly's mobile app supports **Microsoft Intune Mobile Application Management (MAM)**, allowing your organization to enforce App Protection Policies on the Rootly app without requiring full device enrollment (MDM).
This means you can protect corporate data on both company-owned and personal (BYOD) devices by controlling actions like copy/paste, screenshots, and selective wipe — all scoped to the Rootly app.
### How It Works
When Intune MAM is enabled for your organization in Rootly:
1. Users log into Rootly normally (SSO, email, etc.)
2. Rootly detects that the organization requires Intune and prompts the user to sign in with their Microsoft work account
3. The Intune MAM SDK enrolls the app with your organization's App Protection Policy
4. The app restarts to apply the protection policies
After enrollment, Intune policies are enforced within the Rootly app (for example, screenshot blocking, data transfer restrictions) without managing the entire device.
### Prerequisites
**Before you start, ensure you have:**
* A **Microsoft Entra ID (Azure AD)** tenant with Intune licenses
* **Admin access** to the Microsoft Intune admin center and Entra ID
* An **App Protection Policy** for iOS/iPadOS created in Intune
* The **Microsoft Authenticator** app installed on end-user devices
Microsoft Authenticator is required on user devices because it acts as the authentication broker for Intune MAM enrollment. Without it, the MAM token acquisition will fail.
### Step 1: Enable Intune in Rootly
Contact Rootly support or your account manager to enable Intune MAM for your organization. Once enabled, Rootly will set the `mdm_provider` configuration to `intune` for your team, which activates the Intune enrollment gate in the mobile app.
### Step 2: Grant admin consent for the Rootly app registration
Rootly's mobile app uses a Microsoft Entra ID (Azure AD) app registration to authenticate with MSAL and enroll with the Intune MAM service. Your tenant admin must grant consent for this app.
**Rootly App Registration:**
* **Client ID:** `8a50cf17-45cf-41d2-8e32-2fe6fa0c5baf`
* **App Name:** Rootly (may appear as "Rootly \[Dev]" in sign-in logs)
In the [Microsoft Entra admin center](https://entra.microsoft.com), go to **Identity > Applications > Enterprise applications**.
Search for the Rootly client ID: `8a50cf17-45cf-41d2-8e32-2fe6fa0c5baf`.
If the app does not appear, you will need to grant admin consent first (see next step).
Open the following URL in your browser, replacing `{TENANT_ID}` with your Entra tenant ID:
```text theme={null}
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=8a50cf17-45cf-41d2-8e32-2fe6fa0c5baf
```
Sign in as a Global Administrator or Application Administrator and accept the requested permissions.
After granting consent, go back to **Enterprise applications > Rootly > Permissions**. Confirm that the following permissions are granted:
* **Microsoft Graph:** `User.Read` (delegated)
* **Microsoft Mobile Application Management:** device management permissions (delegated)
Both permissions must show **Granted for \[your tenant]** status.
**This step is critical.** Without admin consent for the Microsoft Mobile Application Management resource, the Intune MAM SDK cannot acquire the token it needs to enroll the app. Users will see an `MSALErrorDomain error -50002` on iOS or a similar error on Android.
### Step 3: Add Rootly to your App Protection Policy
In the [Microsoft Intune admin center](https://intune.microsoft.com), go to **Apps > App protection policies**.
Select the iOS/iPadOS policy you want to apply to Rootly (or create a new one).
In the policy, go to **Properties > Apps > Edit**. Under **Custom apps**, click **Select custom apps** and add:
* **Bundle ID:** `com.rootly.app`
* **Platform:** iOS/iPadOS
For Android, use the same bundle ID: `com.rootly.app`.
Under **Assignments > Included groups**, ensure the users who need Rootly are included in this policy's target groups.
The policy must target both the app (bundle ID) **and** the user/group. Adding the app without assigning users will not activate the policy.
Policy changes can take up to 8 hours to propagate to devices. Typically this takes 30 minutes to 2 hours.
Users can force a sync from **Company Portal > Settings > Sync** on their device.
### Step 4: User login flow
Once everything is configured, the end-user experience is:
Open the Rootly app and sign in using your organization's SSO (or email/password).
After Rootly authentication, the app detects that your organization requires Intune and displays the **"Organization Sign-In Required"** screen. Tap **Sign in with Microsoft**.
The Microsoft Authenticator app opens. Select your work account and complete MFA if prompted.
After successful enrollment, the app restarts to apply the App Protection Policies. This restart is required by the Intune MAM SDK and only happens on first enrollment.
On subsequent app launches, the enrollment is remembered and the user goes directly to the Rootly home screen.
### Supported Platforms
| Platform | MAM Support | Bundle ID |
| ------------ | ----------- | ---------------- |
| iOS / iPadOS | Supported | `com.rootly.app` |
| Android | Supported | `com.rootly.app` |
Intune MAM works on both managed (MDM-enrolled) and unmanaged (BYOD) devices. Full device enrollment via Company Portal is **not** required for app-level protection.
### Managed App Configuration (Android)
Rootly's Android app reads managed app configuration (AppConfig) pushed from Intune. AppConfig is how your tenant signals to Rootly that the app is operating in a managed context, and how you enable behaviors that require tenant intent — such as routing SSO through your APP policy's managed browser.
#### When to push AppConfig
* **You are on a BYOD / MAM-only deployment** (no Work Profile) and want Rootly's SSO launch to honor your APP policy's managed-browser redirect (for example, to Microsoft Edge). Without AppConfig, Rootly cannot tell that Intune is governing the app and falls back to the system default browser, which the MAM policy cannot intercept.
* **You use per-app VPN scoped to Rootly** and need authentication traffic to stay inside the app process. See `use_in_app_browser` below.
Pushing any AppConfig (even an empty key/value) is enough to flip Rootly's managed-device detection on. You can use the keys below to opt into specific behaviors.
#### Supported keys
| Key | Type | Default | Description |
| -------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `use_in_app_browser` | Boolean | `false` | When `true`, Rootly's Android SSO launch uses an embedded in-app web view instead of the system browser. Set this when the Rootly app is behind a per-app VPN scoped to Rootly only — the system browser runs outside that VPN tunnel and cannot reach corporate auth endpoints. Leave `false` (or omit) for normal MAM deployments so the Microsoft broker can attach device context to the auth flow. |
#### How to push AppConfig
In the [Microsoft Intune admin center](https://intune.microsoft.com):
Go to **Apps > App configuration policies > Add > Managed apps**. Choose Android, then add `com.rootly.app` as the targeted app.
Under **Configuration settings**, add the keys you need from the table above. For example, to opt into the in-app browser:
* **Configuration key:** `use_in_app_browser`
* **Value type:** `Boolean`
* **Configuration value:** `true`
Under **Assignments**, target the same users or groups that have your APP policy assigned.
Policy changes can take up to 8 hours to reach devices; users can force a sync from **Company Portal > Settings > Sync**.
### Intune Troubleshooting
#### MSALErrorDomain error -50002 (iOS)
This error means the Intune MAM SDK could not acquire a token for the Microsoft Mobile Application Management service. Common causes:
| Cause | Solution |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| **Admin consent not granted** for the Rootly app registration in your tenant | Grant admin consent using the URL in [Step 2](#step-2-grant-admin-consent-for-the-rootly-app-registration) |
| **Microsoft Authenticator not installed** or not signed in with the work account | Install Authenticator and sign in with the same work account used for Rootly |
| **User not assigned** to the App Protection Policy | Verify the user is in the policy's Included groups under Assignments |
| **Bundle ID mismatch** in the policy | Confirm the custom app entry is exactly `com.rootly.app` with platform iOS/iPadOS |
| **Policy sync delay** | Wait up to 8 hours or force sync via Company Portal |
To diagnose, ask your Entra ID admin to check **Sign-in logs** for the user and look for entries where the **Resource** is "Microsoft Mobile Application Management" with status "Interrupted". The error code (for example, `AADSTS65001`) will identify the exact cause.
#### App Protection Policy not applying
If the Rootly app is enrolled but policies don't seem active (for example, screenshots still work):
1. Verify the policy's **Data protection** settings are configured as expected
2. Check that the user appears in the Intune admin center under **Apps > Monitor > App protection status** with `com.rootly.app` showing "Checked in"
3. If `com.rootly.app` does not appear in the check-in list, enrollment did not complete. Re-trigger by signing out of Rootly and signing back in
#### Enrollment works but app keeps asking to sign in
This can happen if the MSAL token cache was cleared (for example, after an app update or device restart). The Rootly app automatically attempts to re-enroll silently on launch. If silent re-enrollment fails:
1. Ensure Microsoft Authenticator is still installed and signed in
2. Tap **Sign in with Microsoft** to re-authenticate
3. If the issue persists, sign out of Rootly completely and sign back in
## Rootly vCard
Incoming pages from Rootly can come from various numbers depending on the country you're located in. To ensure that each page appears as Rootly calling, you can download the Rootly vCard through this link: [https://rootly.com/rootly-outgoing-numbers.vcf](https://rootly.com/rootly-outgoing-numbers.vcf).
***
## Related Pages
The audible / quiet rules that decide how the mobile app pages you — Critical Alerts, DND handling, and channel chaining.
See your on-call status without opening the app — iOS and Android home screen widgets.
Pre-shift and post-shift notifications delivered to the mobile app and other channels.
# Mobile Home Screen Widgets
Source: https://docs.rootly.com/on-call/mobile-widgets
Add the Rootly on-call widget to your iPhone or Android home screen to see your on-call status, shift times, and schedules at a glance.
## Overview
The Rootly mobile app includes a home screen widget that shows your on-call status without opening the app. At a glance you can see whether you're on call right now, when your current shift ends or your next one starts, and which schedules you're covering.
The widget is available on **both iOS and Android**, in several sizes.
This page covers the widget you add to your phone's home screen. For the on-call status card in the Rootly web app's sidebar, see [On-Call Widget](/on-call/on-call-widget).
***
## What the widget shows
The widget always reflects **your own** on-call status — not your team's. It has three states:
| State | Appearance | When you see it |
| -------------------------- | ---------- | ----------------------------------------------- |
| **You're on-call.** | Green | You're currently on a shift |
| **You're always on-call.** | Green | You're on an escalation policy with no rotation |
| **Not on-call.** | Grey | You have no active shift |
Alongside the status, the widget shows:
* Your Rootly avatar
* **Shift ends at** when you're on call, or **Shift starts at** for your next upcoming shift
* **Always on-call for N Escalation Policies** when that applies
* The names of the schedules you're on call for, and an **N more shifts** row when there are more than fit
***
## Widget Sizes
All three sizes show your status and either a shift time or, when you're always on call, the **Always on-call for N Escalation Policies** summary. The larger sizes add a list of schedules — the ones you're currently on call for, or the ones your upcoming shifts are on when you're off call — and anything that doesn't fit collapses into an **N more shifts** row.
| Size | What it shows |
| ---------- | ------------------------------------------------------------------------------------ |
| **Small** | Your status and a single shift time or always-on-call summary, with no schedule list |
| **Medium** | Adds the schedule list |
| **Large** | The same list, with room for more entries before they collapse |
On iOS you pick the size when you add the widget, and you can add more than one. On Android there's a single widget you can resize on the home screen — it switches between the layouts above as you make it bigger or smaller.
When you're off call, the same space lists the schedules your upcoming shifts are on instead.
***
## Add the widget
Touch and hold an empty area of your home screen until the app icons jiggle, then tap **+** — or **Edit → Add Widget** on newer iOS versions — in the top-left corner.
Search for **Rootly** and select it. The widget is listed as **On-Call Widget**.
Swipe between the small, medium, and large previews, tap **Add Widget**, then drag it where you want it and tap **Done**.
Touch and hold an empty area of your home screen, then tap **Widgets**.
Scroll to **Rootly** and touch and hold the widget preview.
Drag the widget onto your home screen. Touch and hold it, then drag the handles to resize — the layout adapts as it grows.
Steps vary slightly between Android manufacturers and launchers.
***
## Requirements
* Rootly mobile app **2.0.0 or later** — see [Mobile App](/on-call/mobile-app) for download links and supported operating systems.
* You must be signed in to the app. Open Rootly at least once after adding the widget so it has your schedule data — until then it appears empty.
* An on-call seat, like all mobile app functionality.
***
## Frequently Asked Questions
No. The widget follows whichever organization is currently selected in the app. If you switch organizations, the widget shows the one you switched to.
The widget needs data from the app. Make sure you're signed in, then open Rootly and go to the home screen. If it stays empty, remove the widget and add it again.
No. Tapping the widget opens the Rootly app. There are no buttons or tappable areas within the widget itself.
No — the widget is for your home screen only. While your alert notifications are muted, Rootly does show a countdown outside the app — a Lock Screen Live Activity on iOS, an ongoing notification on Android — but that's a separate feature. See [Alert Muting](/on-call/alert-muting).
Yes. You can add several widgets in different sizes, but they all show the same account and the same on-call status.
No. It shows your on-call status and shifts only — it doesn't change when a page arrives. For alerts and incidents, open the app, where you'll also see a **You've been paged** card. The [On-Call Widget](/on-call/on-call-widget) in the web sidebar does show a paged state.
***
## Related Pages
Download, sign in, and set up push notifications for on-call responders.
The equivalent status card in the Rootly web app's sidebar.
How shifts, rotations, and overrides determine what the widget shows.
# Get started with Rootly On-Call paging and routing
Source: https://docs.rootly.com/on-call/on-call
Understand how Rootly On-Call ensures the right people are paged at the right time using schedules, escalation policies, and real-time routing.
## What Is Rootly On-Call?
Rootly On-Call is the decision engine that determines who should respond, how urgently, and through which channels when something requires immediate attention.\
It brings together all the components required for reliable paging—**schedules**, **escalation policies**, **notification rules**, **live call routing**, and **health checks**—and applies them consistently across alerts, incidents, phone calls, and automations.
Rootly’s goal is simple: **Every critical signal reaches the right human, right away, with zero manual coordination.**
To achieve this, On-Call unifies:
* **On-Call Schedules** — define coverage, rotations, and business-hour logic
* **Escalation Policies** — define how Rootly escalates until someone responds
* **Notification Channels** — voice, SMS, Slack, email, push, with urgency-aware delivery
* **Live Call Routing** — turn a phone call into a page or live connection
* **Heartbeats** — detect system failures proactively
* **Urgency Rules** — ensure critical alerts bypass delays and DND
If alerts are the *signal*, On-Call is the *routing system* that ensures the signal always reaches a human responder—reliably and consistently.
***
### Why It Matters
A robust on-call program is foundational to operational reliability. It’s the safety net that ensures issues are detected early, routed correctly, and acted on quickly—no matter when they occur or who is available. Rootly On-Call centralizes this responsibility by coordinating schedules, escalation logic, and notification channels so teams never have to wonder who should respond or how alerts should flow. It eliminates guesswork, reduces manual coordination, and brings consistency to the moments where clarity matters most. Rootly On-Call ensures:
#### **Fast, accurate detection**
Monitoring tools send alerts → Rootly immediately routes them to the correct responder based on urgency and routing rules.
#### **Predictable coverage**
Schedules define who is responsible at any moment—across time zones, rotations, and business hours.
#### **Reliable escalation**
If a responder does not acknowledge in time, Rootly automatically escalates until someone does—no pager fatigue, no dropped alerts.
#### **Multi-channel delivery**
Rootly intelligently chooses notification channels based on urgency, fallback logic, user preferences, and device availability.
#### **Consistent workflow integration**
All paging activity flows naturally into Incident Management, Workflows, Analytics, and communication channels like Slack.
***
### Key Components of On-Call
#### **1. Schedules**
Schedules define **who is on duty right now**. They support:
* Multi-person rotations
* Layered coverage (primary / secondary)
* Business-hour–only schedules
* Time-zone–aware planning
* Slack usergroup auto-updates
* Shift overrides and handoff workflows
Schedules provide the “real-time roster” that escalation policies use when selecting responders.
#### **2. Escalation Policies**
Escalation Policies define **how Rootly should escalate if no one responds**.
They support:
* Multiple sequential levels
* Paging Users, Groups (Teams), Services, or Schedules
* Working-hours logic (different paths for after-hours alerts)
* Custom repeat rules
* Dynamic escalation paths filtered by alert urgency or alert content
Escalation Policies guarantee alerts do not stall on a single unresponsive user.
#### **3. Notification Channels**
Rootly uses multiple channels to maximize responder reach:
* Phone calls (with DND override for critical alerts)
* SMS with retry logic
* Push notifications from the mobile app
* Slack notifications
* Email
Rootly automatically handles fallbacks, retries, and acknowledgement tracking.
#### **4. Live Call Routing**
Allows employees, customers, or automated systems to trigger a page via phone call.
Capabilities include:
* Live connection to the on-call responder
* Voicemail → auto-page flow
* IVR calling trees for multi-team routing
* Per-destination urgency settings
* Failover to voicemail if unanswered
* Custom greetings and waiting music
This is the fastest way for a human caller to reach “whoever is on call right now.”
#### **5. Heartbeats**
Heartbeats ensure systems are actively reporting in.\
If a system fails to ping Rootly within the expected interval:
* A heartbeat alert is triggered
* Escalation Policies route it to the correct team
* Recovery pings automatically resolve the alert
Heartbeats reduce reliance on external uptime tools and provide first-party liveness checks.
***
### How Rootly On-Call Fits Into the Incident Workflow
1. **Monitoring detects a problem**\
→ Datadog, Grafana, Sentry, or any alert source sends a signal.
2. **On-call routing determines who to notify**\
→ Escalation Policies + Schedules identify the correct responder.
3. **Rootly notifies them through the appropriate channels**\
→ Based on user preferences, urgency, and fallback rules.
4. **Responder acknowledges**\
→ Escalation pauses; Rootly records the event.
5. **An incident is optionally created or updated**\
→ Workflows determine whether to open a new incident, attach alerts, or notify stakeholders.
On-Call is the bridge between *systems detecting issues* and *humans resolving them*.
***
### Best Practices
* Keep rotation structures simple and predictable.
* Use escalation policies consistently across services.
* Set quiet vs. audible notification rules for each urgency level.
* Use business hours paths to avoid unnecessary nighttime paging.
* Pair schedules with Slack usergroups so teams always know who’s on call.
* Review unacknowledged alerts and escalation depth in On-Call Metrics.
***
### Frequently Asked Questions (FAQs)
Rootly looks at the alert’s routing target (service, team, escalation policy) and then uses schedules + escalation rules to select the responder.
Yes. Rootly can send voice calls, SMS, push notifications, Slack messages, and emails—based on urgency and user preferences.
Rootly automatically escalates to the next level in the escalation policy until someone acknowledges.
They’re optional but highly recommended:
* Live Call Routing lets callers reach on-call responders instantly
* Heartbeats detect silent system failures proactively
***
## Related Pages
Where signals originate — On-Call is the routing system that turns alerts into pages.
Rootly's main paging engine — how escalation moves through steps and paths.
Define coverage and rotations that feed into every escalation policy.
# On-Call Metrics
Source: https://docs.rootly.com/on-call/on-call-metrics
Analyze on-call performance using response time, alert volume, acknowledgement, and escalation metrics to continuously improve reliability and responder health.
## Overview
**On-Call Metrics** give you deep visibility into how effectively your team responds to alerts. These metrics help you understand not just *how many* alerts you receive, but *how quickly* they are acknowledged, *how long* they take to resolve, and *how evenly* response effort is distributed across teams, services, and escalation paths.
Every Rootly workspace includes a **pre-configured On-Call Metrics dashboard** out of the box. This dashboard is designed to surface the most important operational signals immediately, while still allowing full customization as your organization’s needs evolve.
Teams use On-Call Metrics to:
* Identify bottlenecks in alert routing and escalation
* Reduce alert fatigue and uneven on-call load
* Improve responder experience and accountability
* Make data-driven decisions about staffing, schedules, and escalation policies
## Getting Started
To access your on-call analytics, navigate to **Metrics** in the Rootly navigation and select the **On-Call Metrics** dashboard.
By default, the dashboard displays data for the **last 90 days**, aggregated weekly. You can adjust the time range and aggregation period at any time to zoom in on recent incidents or analyze longer-term trends.
## What the Default Dashboard Measures
The default dashboard focuses on three core areas:
* **Response speed** — how quickly alerts are acknowledged and resolved
* **Response effort** — how much time responders spend handling alerts
* **Alert distribution** — where alerts originate and who handles them
Together, these views provide a holistic picture of on-call performance across your organization.
### Core Response Metrics
These metrics focus on how quickly alerts move through the response lifecycle.
* **Total Alerts**\
The total number of alerts triggered in Rootly during the selected time period. This metric is often used as a baseline to understand alert load and detect spikes caused by deployments, outages, or noisy monitors.
* **Mean Time to Acknowledge (MTTA)**\
The average time between an alert firing and a responder acknowledging it. MTTA reflects notification reachability, escalation effectiveness, and responder availability.
* **Mean Time to Resolve (MTTR)**\
The average time between alert trigger and resolution. This includes investigation, mitigation, and recovery, making it a strong indicator of incident complexity and operational efficiency.
* **Mean Time Between Failures (MTBF)**\
The average time between alert triggers. A decreasing MTBF may signal instability or excessive alerting, while an increasing MTBF often reflects improving reliability.
* **Acknowledge Rate**\
The percentage of alerts that are acknowledged by responders. Lower acknowledge rates can indicate alert fatigue, misconfigured notifications, or routing issues.
### Performance Breakdown
These metrics help you understand *who* is responding and *where* time is being spent.
* **MTTA by Responder**\
Shows how quickly individual responders acknowledge alerts. This can surface timezone mismatches, training gaps, or uneven alert distribution.
* **MTTR by Service**\
Breaks resolution time down by affected service, helping teams identify systems that are consistently harder to recover.
* **Response Effort**\
Represents the total time spent responding to alerts, measured from acknowledgment to resolution. This metric helps quantify operational load and compare effort across teams or services.
### Alert Distribution Insights
Distribution metrics show how alerts flow through your organization.
* **Alerts by Source**\
Highlights which monitoring tools generate the most alerts, helping teams tune integrations and reduce noise.
* **Alerts by Responder**\
Shows how alerts are distributed across individuals, making it easier to identify overload or imbalance in rotations.
* **Alerts by Urgency**\
Breaks alerts down by priority, helping validate whether severity definitions align with real-world response behavior.
* **Alerts by Escalation Policy**\
Reveals which escalation workflows are most active and whether policies are triggering as expected.
* **Alerts by Service**\
Shows where alert volume is concentrated, helping teams prioritize reliability improvements for the most impactful systems.
## Customizing Your Dashboard
The On-Call Metrics dashboard is fully customizable, allowing you to tailor it to what reliability means for your organization.
You can modify existing panels to change time ranges, filters, aggregation methods, or visualization types. This makes it easy to answer targeted questions—such as how response times differ during business hours or how a recent rollout affected alert volume.
You can also add new panels using **alert data** or **incident data**, enabling teams to correlate paging behavior with broader incident trends.
For the most complete view of operational performance, combine **alert-based metrics** with **incident-based metrics** in the same dashboard.
## Sharing and Exporting Metrics
On-call metrics are often valuable beyond the immediate response team. Rootly allows you to export individual panels or entire dashboards for sharing with leadership, stakeholders, or external partners.
Exports can be generated directly from the dashboard using the panel or dashboard menu, making it easy to include on-call performance data in reports, reviews, and postmortems—without manual data collection.
***
## Best Practices
To get the most value from On-Call Metrics:
* Review metrics regularly, not just during incidents
* Use MTTA trends to validate notification reachability and escalation effectiveness
* Monitor MTTR by service to identify systems that need reliability investment
* Watch alert distribution to ensure on-call load is balanced fairly
* Treat metrics as a feedback loop—refine alerting and escalation, then measure again
***
## Frequently Asked Questions (FAQs)
On-Call Metrics are derived directly from **alert and incident events** in your Rootly workspace.\
Metrics such as MTTA, MTTR, and acknowledge rate are calculated using timestamps recorded when alerts are triggered, acknowledged, and resolved. Because the data is event-driven, metrics update automatically as new alerts and incidents occur.
On-Call Metrics only include alerts that are processed through Rootly’s alerting and escalation system.\
If a schedule is not attached to an escalation policy, or an alert source is misconfigured, those alerts may not appear in metrics. Reviewing escalation policies and alert routing is often the first step when counts seem lower than expected.
**Mean Time to Acknowledge (MTTA)** measures how quickly a responder acknowledges an alert after it fires.\
**Mean Time to Resolve (MTTR)** measures how long it takes to fully resolve the issue after the alert is triggered.\
Together, these metrics help distinguish between *notification speed* and *resolution efficiency*.
Response Effort represents the **total time spent actively responding to alerts**, measured from acknowledgment to resolution.\
This metric is useful for understanding operational load and comparing effort across teams or services, even when alert volume is similar.
Yes. Every panel on the On-Call Metrics dashboard can be edited, removed, or duplicated.\
You can also add new panels using alert or incident data to track metrics that are specific to your organization’s reliability goals.
By default, the team owner is granted manager access to the dashboard, and the team is granted edit access.\
Additional permissions can be managed through Rootly’s dashboard sharing and role-based access controls.
Metrics update continuously as new alert and incident events are recorded.\
There is no manual refresh required—changes to alerts, acknowledgements, or resolutions are reflected automatically in the dashboard.
On-Call Metrics focus on **paging and responder behavior**, while Incident Analytics focus on **incident lifecycle and outcomes**.\
For the most complete picture of reliability, Rootly recommends using both together to connect alert response performance with incident impact.
***
Reviewing On-Call Metrics alongside Retrospectives helps connect quantitative performance data with qualitative incident learnings.
***
## Related Pages
Where paging performance is decided — the metrics reflect how well your policies actually notify people.
Close the feedback loop — pair quantitative metrics with qualitative learnings from real incidents.
MTTA and Acknowledge Rate depend on whether notifications actually reach responders.
# Notification Rules
Source: https://docs.rootly.com/on-call/on-call-notifications
Configure how and when Rootly reaches you when you're paged — via push, phone call, SMS, or email — with safeguards that prevent quietly-broken paging.
## Overview
Notification Rules define how Rootly reaches you when an alert is assigned to you. They're evaluated as an ordered sequence of steps — if an alert stays unacknowledged, Rootly moves to the next step and keeps going until someone responds or the escalation path completes.
You configure **Audible** and **Quiet** rules separately so urgent pages can behave differently from informational ones: hard-to-miss for production issues, low-noise for signals that shouldn't wake anyone up.
Open **Account Settings → Notifications → On-Call Notifications** to manage everything on this page.
***
## Delivery Methods
Rootly supports several delivery methods for notification rules, each with a slightly different purpose:
Device push intended to bypass Do Not Disturb. Use for the loudest step of an audible rule.
Device push that respects Do Not Disturb — a quiet channel.
Real-time audible channel. Use as the reach-through if push doesn't wake you.
A reliable delivery path when push or phone can't reach the device.
Suited for non-urgent notifications where audible paging isn't needed.
If you want a setup that's *reliable but not disruptive*, reserve **Critical Alerts** and **phone calls** for audible paging, and use non-critical push, SMS, or email for quiet paging.
***
## Audible Rules
Audible rules are your wake-me-up configuration — the sequence Rootly runs through when an alert needs immediate action.
Rootly enforces guardrails on audible rules because urgent paging is only useful if it *can't* be configured into a silently-broken state. In other words: Rootly won't let you save an audible policy that can't actually reach you.
### Step 1 Requirements
The first step of an audible rule must include a real-time delivery method that matches your device state:
* **If you have a connected mobile device**, Critical Alerts are required on step 1.
* **If you don't have a connected mobile device**, a phone call is required on step 1.
Rootly won't let you save a level 1 audible step that doesn't meet the requirement for your current setup, so urgent alerts can't be configured into a state where they silently fail to reach you.
### Subsequent Steps
Level 2 and beyond still need at least one of **Critical Alerts** or **Phone Call** enabled — Rootly won't let escalation become "quiet" by accident. Beyond that requirement, later steps can add SMS or email alongside Critical Alerts or a phone call.
Audible rules are validated on save. If a step doesn't meet these requirements — no Critical Alerts on step 1 with a device connected, or no phone call on step 1 without one — Rootly blocks the save until the rule is made safe.
Pair Critical Alerts with a secondary channel (SMS or email). Even when push is reliable, redundancy makes paging more resilient under real-world conditions.
***
## Quiet Rules
Quiet rules are for alerts that still matter but shouldn't force immediate interruption. They still escalate through steps, but the intent is different: keep responders informed without waking anyone up unless it's truly necessary.
Email, SMS, and non-critical push are the typical quiet channels. Non-critical push is especially useful when you want the alert on someone's phone without cutting through Do Not Disturb.
### Making Quiet Notifications Audible on a Silenced Phone
By default, Quiet push respects both Do Not Disturb and silent mode — it arrives on the phone but stays silent when the device is silenced. That's the intent.
If you want quiet pushes to **ring through silent mode and DND** without reclassifying them as audible, enable **Critical Alerts** on the device contact method *inside the Quiet notification rule itself*.
**Navigation:** Account Settings → Notifications → On-Call Notifications → the Quiet rule → the device contact method → **Critical Alerts** toggle.
On supported devices this makes the phone treat the push as a Critical Alert (bypasses silent mode and DND) while Rootly still treats the rule as Quiet for paging logic. The audible-rule constraints (step 1 requirements, phone call fallback) don't apply.
The override doesn't work in two known device configurations — confirm yours before relying on this toggle.
* **iPhone with an Apple Watch mirroring notifications** — Critical Alerts may not play sound on the iPhone itself. See the [iPhone + Apple Watch caveat](/on-call/mobile-app#push-notification) for the fix.
* **Android in a Work Profile** — Work Profile can't override system volume or Do Not Disturb at the OS level, so the Critical Alerts toggle has no effect. See the [Android Work Profile caveat](/on-call/mobile-app#push-notification) for context.
***
## Test Your Notifications
The **Test Notifications** action sends test messages to the targets you've configured so you can validate delivery end-to-end. Testing is available for email, SMS, phone call, and device push — the same core methods used by notification rules.
Test any time you change phones, update a phone number, reinstall the mobile app, or want to confirm your current configuration still works.
Test at least one audible path (Critical Alerts or call) and one quiet path (email or non-critical push) after setting up notifications — before you go on call.
***
## Verification Requirements
Contact methods must be verified before they can be used for paging. Rootly enforces this so a rule that *looks* valid can't quietly fail to deliver.
* Unverified phone numbers block SMS and call configurations.
* Unverified email addresses block email configurations.
* Shift Reminders follow the same rule — reminder delivery methods must be verified when the reminder is enabled.
If you can't save notification rules or reminders, verification is the first thing to check. Unverified contact methods will block any configuration that depends on them.
***
## Shift Reminders
Shift Reminders notify you before your on-call shift starts and when it ends — separate from incident paging. Multiple delivery channels are supported and lead-time options range up to two weeks in advance when expanded options are enabled.
For the full reference — supported channels, timing tiers, nested-schedule behavior, and reminder-specific troubleshooting — see [Shift Reminders](/on-call/shift-reminders).
***
## Default Setup
If notification rules or reminders are missing, Rootly automatically creates a safe baseline so new responders aren't left unpaged.
Typically: a default quiet rule (commonly email), a default audible rule (email plus a high-reliability channel when available), and two shift reminders (one for shift start, one for shift end) delivered via email. These defaults are meant to be edited — they provide immediate coverage while a team finalizes their preferred setup.
***
## Best Practices
* **Configure an audible step that reaches you when your phone is silenced.** Then test it. This one step blocks the most common source of missed pages.
* **Pair Critical Alerts with SMS or email.** Redundancy on the first audible step is cheap insurance.
* **Reserve Critical Alerts for audible rules.** Using them on quiet rules by default trains you to ignore the DND bypass.
* **Test after every phone change.** New phone, updated phone number, or reinstalled app can affect push delivery — test to confirm.
* **Verify contact methods before your first shift.** Rootly enforces this on save, but the message reads as "why won't this save?" if you don't know why.
***
## Troubleshooting
Audible rules have strict safety requirements so urgent alerts can't be configured into a non-deliverable state. The most common causes:
* **Step 1 is missing the channel for your device state** — Critical Alerts if you have a connected mobile device, a phone call if you don't.
* **A later step dropped both Critical Alerts and Phone Call** — every audible step (not just step 1) must keep at least one of the two enabled so escalation can't become "quiet" by accident.
Notification rules and enabled shift reminders require verified contact methods. Verify the phone number or email address first, then return to On-Call Notifications and save again.
* Confirm whether you're expecting Critical Alerts (bypass DND) or non-critical push (respects DND).
* Confirm your mobile device is connected and registered.
* If you changed phones, reinstalled the app, or revoked notification permissions at the OS level, reconnect the device and restore permissions.
* Use **Test Notifications** to validate delivery immediately.
That's the default — Quiet push respects silent mode and Do Not Disturb. To make quiet pushes ring through silent mode without converting the rule to audible, enable **Critical Alerts** on the device contact method inside the Quiet rule.
See [Making Quiet Notifications Audible on a Silenced Phone](#making-quiet-notifications-audible-on-a-silenced-phone) for the full setup, including the iPhone + Apple Watch and Android Work Profile caveats.
***
## Related Pages
Pre-shift and post-shift notifications delivered on the channels you configure.
Temporarily silence your automated alert notifications during an alert storm.
See at a glance whether responders have working notification methods configured.
# On-Call Pay Calculator
Source: https://docs.rootly.com/on-call/on-call-pay-calculator
Calculate on-call compensation from real schedule data with configurable pay rules, then export to Excel or CSV for payroll.
## Overview
The On-Call Pay Calculator turns your Rootly schedules into a payroll-ready report. Instead of hand-stitching spreadsheets from a dozen schedules, you configure your pay rules once and generate reports that reflect the coverage your team actually ran. Reports can optionally include shadow-shift time (via **Include Shadow Shifts**) and break out active incident-response time from passive standby (via **Granular Time Breakdown**, hourly reports only).
Only schedules attached to an escalation policy are included, so what you see in the report is what would have actually paged someone. Reports are generated asynchronously — Rootly emails you when it's ready, and you download the **XLSX** and **CSV** files from the Pay Calculator page. Both are suitable for payroll processing, audits, or internal review.
Pay rules are **snapshotted at report generation time**. Editing rules later doesn't retroactively change reports you've already run — each report is self-describing and reproducible.
***
## How Pay Calculation Works
The calculator pulls on-call shift data from schedules, applies the pay rules you've configured, and aggregates time per user over a chosen date range. It supports two compensation models:
* **Hourly** — pays down to the minute, categorizing time into business hours, off-hours, and weekends.
* **Daily** — counts unique calendar days on-call, categorized into weekdays and weekends. Shift length within a day doesn't matter.
Only schedules assigned to an escalation policy are included. Any coverage gaps are attributed to the schedule owner. If a schedule looks like it should be paying out but isn't showing up, check that it's actually wired to an escalation policy.
***
## Configure Pay Rules
Open **On-Call → Pay Calculator** and choose **Configure Rules** to set up how time is counted and priced.
### Pay Type
**Hourly** or **Daily**.
* **Hourly** — tracks time to the minute and splits it into business hours (9 AM–5 PM weekdays), non-business weekday hours, and weekends. Best for teams paying based on actual availability or active response.
* **Daily** — counts unique calendar days on-call, split into weekdays and weekends. Each qualifying day counts once regardless of shift length. Best for teams paying a flat daily stipend.
### Rates
Enable to have Rootly compute total compensation. Disable to report time worked without pricing it — useful when rates vary by individual, seniority, or geography, or when final compensation is calculated outside Rootly.
Currency for the rate. Shown when Single Rate is enabled.
Hourly or daily rate (matching Pay Type). Applied uniformly across all users included in the report.
### Data Inclusion
Hourly pay only. When enabled, Rootly analyzes alert activity during each on-call hour and splits time into:
* **Non-paged hours** — on call with no alerts received.
* **Paged hours** — alerts triggered but not yet acknowledged or resolved.
* **Acknowledged / resolved hours** — time spent actively responding.
Use this when you compensate active incident response differently from passive standby.
Includes shadow-shift time in the report. Rootly automatically deduplicates overlap — a user who's on-call *and* shadowing during the same window isn't double-counted. See [On-Call Shadowing](/on-call/on-call-shadowing).
Adds per-shift columns to the export: schedule name, shift start (team timezone), and shift end (team timezone). Recommended for audits and payroll verification — it lets a reviewer see how totals rolled up.
***
## Generate a Pay Report
Select the specific schedules to include. Leave blank to include every schedule attached to an escalation policy.
Choose start and end dates. Rootly supports up to **six months** of data per report.
Options:
* **Organization default** (used unless overridden).
* **A specific timezone** — for teams calculating pay in a single locale.
* **Each responder's individual timezone** — for globally distributed teams where local time defines the workday.
Rootly processes it in the background. You'll get an email when it's ready — return to the Pay Calculator to download the CSV and XLSX files.
Each report includes a configuration summary — pay type, currency, whether Single Rate was on, shadow-shift inclusion — so reviewers can confirm the settings without opening the calculator.
***
## Best Practices
* **Attach every payable schedule to an escalation policy.** Schedules without a policy are silently excluded from calculations — a common source of "why is this user missing?"
* **Lock in rules before running a report.** Rules are snapshotted at generation time — review them before running to avoid reissuing reports later.
* **Enable granular time breakdown early if your model needs it.** Introducing a split between passive and active hours after payroll is already built around flat hours is disruptive.
* **Turn on Include Shadow Shifts if training is paid.** Check the toggle before your first run so trainee time is captured.
* **Show individual shift data on any report that goes to finance.** Per-shift context helps reviewers verify how totals rolled up.
***
## Frequently Asked Questions
Only schedules attached to an escalation policy are included. When generating a report you can filter to specific schedules — leave the field blank to include all eligible ones.
Yes — but changes only affect *future* reports. Each report captures a snapshot of the rules at generation time, so past reports remain reproducible.
9 AM to 5 PM on weekdays. All weekend time is categorized separately.
Rootly deduplicates the overlap. The user isn't paid twice for the same period.
Assuming all of the user's schedules are included in the report, Rootly will combine all of the times across shifts and accrue their time based on the time worked.
For example, if someone was scheduled for two on-call shifts during a 24 hour period, they'd accrue pay for just the 24 hour period rather than two 24 hour shifts (totalling 48 hours).
Two common causes:
* The schedule wasn't attached to an escalation policy during the report's date range.
* The date range exceeds the six-month limit — try splitting it into two runs.
***
## Related Pages
Schedules are the source of shift data pay reports run on.
Only schedules connected to an escalation policy count.
Includes shadow-shift time in a pay report when training is paid.
# On-Call Readiness
Source: https://docs.rootly.com/on-call/on-call-readiness
Ensure responders are prepared to receive alerts with the Rootly On-Call Readiness report, which surfaces missing contact methods and rules.
## Overview
The **On-Call Readiness** report gives you a centralized view into whether your responders are actually reachable when it matters most.\
It surfaces every Rootly user who participates in an on-call schedule and evaluates whether their notification preferences are properly configured to receive alerts.
This report is designed for **schedule owners, managers, and reliability leaders** who want confidence that on-call coverage is not only defined—but operationally effective. A schedule is only as reliable as the responders behind it, and this report helps you identify gaps *before* an incident occurs.
Each row in the report represents a responder, and each icon represents a notification method they can be reached through. Green icons indicate that the notification method is fully configured and enabled. Gray icons indicate that the method is missing or incomplete.
Hovering over an icon reveals the exact destination Rootly will use—such as the phone number, email address, or mobile device—so you can quickly validate accuracy without leaving the page.
Responders cannot opt out of **critical alerts** for audible notifications. Rootly enforces this to ensure on-call coverage remains reliable during high-urgency incidents.
## Understanding the Indicators
The readiness table is split across **audible** and **quiet** notification contexts, reflecting how responders are contacted for urgent versus low-priority alerts.
For **audible notifications**, the report shows whether a responder can receive:
* Critical mobile push notifications (that bypass Do Not Disturb)
* Phone calls
* SMS messages
* Email notifications
For **quiet notifications**, the report shows whether a responder can receive:
* Non-critical mobile push notifications (that respect Do Not Disturb)
* Phone calls
* SMS messages
* Email notifications
If at least one valid delivery method exists for the notification type, the corresponding icon appears green. This makes it easy to spot responders who may not be fully reachable for certain alert types.
## Using Filters to Assess Coverage
As teams and schedules grow, reviewing readiness manually becomes harder. The On-Call Readiness report includes filters that let you narrow the view to what matters most:
You can filter responders by **team**, **schedule**, or **escalation policy**, and you can also search by name or email. This allows you to answer questions like:
* Are all responders on this critical service reachable?
* Does this escalation policy include anyone without a working phone number?
* Are new team members fully set up before joining on-call?
Only users with an **on-call seat** appear in this report, ensuring the data reflects responders who may actually be paged.
## Exporting the Readiness Report
If you need to review readiness outside of Rootly, you can export the report as a CSV file.\
Exports are generated asynchronously and delivered via email with a secure download link. This makes it easy to share readiness data with managers, leadership, or auditors without requiring direct access to Rootly.
## Best Practices
Use the On-Call Readiness report proactively—not just during incidents—to keep your on-call program healthy.
* **Review readiness before adding someone to a rotation**\
Ensure responders have at least one working audible notification method configured before their first shift.
* **Make readiness checks part of onboarding**\
New hires should install the Rootly mobile app, verify contact details, and confirm notifications before shadowing or going on-call.
* **Re-audit after notification or policy changes**\
Changes to escalation policies, schedules, or alerting rules can introduce gaps. A quick readiness scan helps catch them early.
* **Encourage mobile app installation**\
Mobile push notifications provide the fastest and most reliable alert delivery, especially for critical incidents.
## Frequently Asked Questions
By default, **Admins and Owners** can view the On-Call Readiness report.\
Other on-call roles can be granted access through **Organization Settings → Roles and Permissions**, allowing teams to delegate readiness ownership without granting full admin access.
Gray icons indicate that a notification method has not been configured or verified.\
This may mean a phone number is missing, the mobile app is not installed, or the responder has not enabled that delivery method in their notification preferences.
This indicator reflects whether the responder has at least one registered mobile device connected to Rootly.\
Installing the mobile app is strongly recommended, as it enables critical push notifications that bypass Do Not Disturb settings.
No. For audible notifications, Rootly enforces at least one guaranteed delivery method—either a critical push notification or a phone call.\
This ensures that responders cannot accidentally make themselves unreachable during high-severity incidents.
Yes. The readiness report reflects responders’ current notification settings.\
If a user updates their contact information or notification rules, the report will update automatically.
***
## Related Pages
Configure the notification rules the readiness report validates.
Whether the mobile device is connected is one of the biggest readiness signals.
Enabled reminders are part of what "ready to go on-call" means for a responder.
# On-Call Shadowing
Source: https://docs.rootly.com/on-call/on-call-shadowing
Use on-call shadowing in Rootly to safely train new responders alongside primary on-call without duplicating schedules, paging both, or risking missed alerts.
## Overview
On-call shadowing is designed to help teams ramp new responders with confidence—without putting production reliability at risk.
Instead of duplicating schedules or manually coordinating training shifts, Rootly allows you to add **shadow users** directly onto an existing on-call schedule. Shadow users are notified alongside the primary on-call responder, giving them real-world exposure to alerts, workflows, and incident patterns while keeping ownership and accountability with the primary responder.
Shadowing is commonly used for onboarding new engineers, preparing responders for rotation changes, or temporarily training team members on unfamiliar systems.
Once a shadowing period ends, Rootly automatically removes the shadow user—no cleanup required.
***
## Shadow Setup
To get started, navigate to **On-Call → Schedules**, then either create a new schedule or edit an existing one.\
From the schedule editor, open the **Shadows** tab to manage shadow users.
From here, you can define *who* should shadow, *what* they should shadow, and *when* they should receive notifications.
***
## Define Active Hours for Shadow Paging
Not every team wants shadow users to be paged 24/7.
The **Page shadow user during specific hours** option allows you to restrict when shadow users are notified. This is especially useful if your primary schedule runs around the clock, but shadow users should only be paged during business hours.
When enabled, shadow paging respects the schedule’s configured business hours. You can optionally include weekends if desired, giving you fine-grained control over the shadowing experience without modifying the primary schedule.
This ensures shadowing is educational—not overwhelming.
***
## Add Shadow Users
Rootly supports two shadowing modes depending on how you want the training experience to work: **shadowing a specific user** or **shadowing an entire schedule**.
Once configured, click **Add shadow user** to begin.
***
### Shadow a User
Shadowing a specific user is ideal when you want a trainee to learn directly from a particular responder.
In **Shadow a user** mode, you select the individual on-call responder to shadow and define the timeframe during which shadowing should occur. During this period, the shadow user is notified whenever that responder is paged—subject to any active hour restrictions you’ve configured.
This approach works well for mentorship-driven onboarding or pairing junior responders with experienced engineers.
***
### Shadow a Schedule
Shadowing an entire schedule is useful when training should follow the rotation itself rather than a single person.
In **Shadow a schedule** mode, the shadow user is notified whenever *any* responder on the schedule is paged during the configured shadowing window. As the schedule rotates, the shadow user follows along automatically.
This provides a broader view of how a team handles incidents across shifts and responders.
***
You can configure **multiple shadow users at the same time**, each with their own shadowing targets and time windows. Shadowing periods may overlap, and Rootly will handle notification delivery accordingly.
***
## Viewing Shadow Users on the Calendar
Shadowing visibility is built directly into the schedule calendar.
Shifts that include shadow users are marked with a **ghost icon**, making it easy to identify shadowed coverage at a glance. Clicking into a shift reveals the shadow users listed beneath the primary on-call responder.
This makes it easy for managers and responders to understand who is learning alongside active coverage.
***
## Automatic Expiration
Shadowing is always time-bound.
Once a shadowing period reaches its configured end time, Rootly automatically removes the shadow user from the schedule. Paging stops immediately, and no manual action is required. Historical records remain intact for auditing and visibility, but shadow users are never left attached unintentionally.
This ensures shadowing stays intentional, controlled, and low-risk.
***
## Permissions
Only users with sufficient On-Call permissions can manage shadowing.\
Users with **On-Call Admin** or **On-Call User** roles can create, edit, and remove shadow users. Observers have read-only access.
***
## Frequently Asked Questions
When shadowing is active, **both the primary on-call responder and the shadow user are notified** for eligible alerts.\
The primary responder remains fully responsible for acknowledging and resolving alerts, while the shadow user receives the same notifications for learning and visibility purposes.
No. Shadowing does **not** change escalation behavior, alert ownership, or acknowledgement logic.\
Escalation policies continue to function exactly as configured, and alerts are still assigned to the primary responder. Shadow users are purely additive and do not interfere with alert flow.
Yes. Shadow paging can be restricted to specific hours by enabling the **Page shadow user during specific hours** option.\
When enabled, Rootly respects the schedule’s business hours configuration and optionally includes or excludes weekends. This is ideal for training during working hours without overnight interruptions.
Absolutely. You can configure **multiple shadow users simultaneously**, each with their own shadowing targets and time windows.\
Shadow users may overlap in time, and Rootly will ensure notifications are delivered appropriately without conflict.
Shadowing automatically expires at the configured end time.\
Once expired, the shadow user is removed from paging immediately—no manual cleanup is required. Historical records remain available for auditing, but the shadow user will no longer receive notifications.
Shadow users receive notifications but **do not replace the primary responder**.\
Depending on their permissions, they may view alerts and incidents, but operational responsibility and escalation remain with the primary on-call responder.
No. Shadowing supports **specific users or entire schedules only**.\
Teams cannot be shadowed directly. If you want team-level shadowing behavior, create a schedule for that team and shadow the schedule instead.
***
## Best Practices
* Use shadowing during onboarding instead of duplicating schedules
* Limit shadow paging to business hours for new responders
* Start with shadowing a specific user before moving to full schedule shadowing
* Use calendar visibility to communicate training coverage to the team
* Let shadowing expire naturally—avoid long-running, open-ended shadows
Shadowing is most effective when treated as a temporary learning tool, not a permanent paging mechanism.
***
## Related Pages
Where shadow shifts are configured — alongside the primary rotation for the same schedule.
How shadow-shift time is counted in pay reports — includes an Include Shadow Shifts toggle.
A different self-service coverage pattern — swap an active shift rather than shadow one.
# On-Call Shifts
Source: https://docs.rootly.com/on-call/on-call-shifts
See who's on call right now and next, spot coverage gaps, and reassign shifts with overrides — without touching the underlying schedule.
## Overview
The **On-Call Shifts** page is the operational view of who is actually going to get paged, right now and in the near future. Schedules define *how* coverage rotates; this page shows *what came out the other side* once the rotation, layers, and overrides have all been applied.
Both responders and managers use this view. Responders check it to see when they're next on-call. Managers use it to validate coverage, spot conflicts before they cause a missed page, and make short-term reassignments without editing the underlying schedule.
***
## Open the On-Call Shifts Page
Go to **On-Call → On-Call Shifts**.
Shifts are grouped by status so coverage is readable at a glance:
* **Currently On-Call** — active right now. These are the shifts that will receive a page if an alert fires this minute.
* **Upcoming On-Call** — future shifts generated by schedules and overrides.
* **Inactive** — shifts belonging to schedules that aren't attached to any escalation policy. They exist for visibility but will not page anyone until the schedule is added to an escalation policy.
If a schedule shows up as **Inactive** unexpectedly, no one on that rotation will be paged. Confirm it's attached to at least one escalation policy that's routing alerts.
***
## Understanding Shift Types
### Always On-Call Shifts
Always on-call shifts represent continuous coverage without a defined end time. These shifts appear under **Currently On-Call** and render as a solid horizontal bar across the calendar.
This pattern is commonly used for roles such as incident commanders, executive escalation paths, or safety officers who must always be reachable.
### Recurring On-Call Shifts
Recurring shifts are generated from rotation rules defined in schedules. These shifts appear under both **Currently On-Call** and **Upcoming On-Call**, depending on their timing, and render as vertical blocks that reflect each shift's start and end times.
***
## View Shifts for Other Users
The page isn't limited to your own coverage. Pick another user from the **User** dropdown to see their shift list and calendar — the whole view updates immediately.
Managers use this to validate coverage before an on-call handoff, and responders use it to see their upcoming shifts.
***
## Spot Holiday and PTO Conflicts
Overlay a holiday calendar on the shifts view to surface schedule risk before it turns into a missed page. When a holiday or PTO event overlaps with an on-call shift, Rootly highlights the conflict directly on the calendar so the affected shifts stand out.
You can create an override right from either the holiday event or the conflicting shift — no need to navigate to the schedule editor. See [Adding a Holiday Calendar](/on-call/holiday-calendar) for setting up the overlay.
***
## Create an Override
An override temporarily reassigns coverage without editing the schedule. Use them for PTO, sick days, or last-minute swaps — anything short-term that shouldn't leave a trace in the rotation itself.
Go to **On-Call → On-Call Shifts**.
Select the user whose coverage needs to change from the **User** dropdown.
Choose **Create Override**, or open a specific shift and pick **Create Override** from the shift details.
Set the time range and pick the user who will take over.
The override takes effect immediately. Overrides always beat rotation-generated shifts and are fully audited.
### Reassign or Revert an Override
Overrides are reversible. Shifts that are overrides are clearly labeled on the calendar and in the list so you can tell them apart from rotation-generated shifts.
* **Revert** restores the original assignee for that shift. Non-destructive — the underlying schedule and rotation aren't touched.
* **Reassign** hands the override to a different user. The override history is preserved in the audit trail.
Both actions are available from the shift details on the On-Call Shifts page and inside the schedule editor.
***
## Multi-Layer Schedules
Multi-layer schedules stack coverage windows on top of each other — for example, a weekday layer (Mon–Fri) plus a weekend layer (Fri–Mon).
* Each layer has its own **rotation, users, and time window**.
* Rootly evaluates layers in **priority order** — a higher-priority layer wins during its active window.
* Layer time windows must be precise. If they overlap or are misaligned, the wrong layer may be active at a given moment.
### Around-the-Sun Schedules
An around-the-sun schedule hands coverage between teams in different time zones so no one has to be paged at 4 a.m. Each region covers its own daylight hours and hands off to the next.
Sketch out each region's window in UTC first — Rootly's schedule engine works in UTC internally, even when it renders local times.
Example for three 8-hour regions:
| Region | UTC window |
| ------ | ------------- |
| APAC | 00:00 – 08:00 |
| EMEA | 08:00 – 16:00 |
| NA | 16:00 – 00:00 |
Go to **On-Call → Schedules → New schedule**. Name it, pick an owner, and set the schedule timezone to **UTC** so layer windows stay easy to reason about across regions.
Choose **Add Rotation** once per region and configure each:
The region's local timezone (for example, `Asia/Bangkok` for APAC). Rootly displays shift times in the local timezone even though the schedule itself stays in UTC.
The coverage window for that region.
Daily, Weekly, Biweekly, Monthly, or Custom.
The responders in that region's rotation.
***
## Best Practices
* **Treat the shifts page as a daily dashboard.** Reviewing upcoming shifts once a week catches gaps around holidays and long weekends before they become missed pages.
* **Use overrides for short-term changes.** Avoid modifying schedules for a one-off PTO day — overrides keep your rotation logic stable.
* **Investigate every Inactive entry.** A dormant schedule is fine; a schedule that should be paging but isn't attached to an escalation policy won't reach anyone.
* **Set multi-layer window times exactly.** Overlaps between layers can activate the wrong layer.
* **Overlay the holiday calendar during planning.** It surfaces conflicts before they turn into missed pages.
***
## Frequently Asked Questions
A shift is inactive when its schedule isn't attached to any escalation policy. It's visible for planning purposes but won't page anyone. Attach the schedule to an escalation policy connected to a service or team to activate it.
No. An override temporarily replaces the on-call assignee for a specific window without altering the schedule or rotation. Once it's reverted or expires, the original schedule resumes automatically.
Overrides cannot overlap with other overrides for the same shift. Rootly enforces this to ensure paging behavior remains predictable and unambiguous.
Users with **On-Call Admin** or **On-Call User** roles can create, update, and revert overrides. Observers have read-only access.
Shifts are generated continuously from schedule rotation rules and recalculated as schedules or overrides change. What you see in **Upcoming On-Call** always reflects the latest configuration.
***
## Related Pages
Where the rotations that generate these shifts are defined.
Self-service coverage swaps for when you can't take a shift.
Overlay holidays and PTO to catch conflicts before they hit.
# On-Call Widget
Source: https://docs.rootly.com/on-call/on-call-widget
See your live on-call status in the Rootly web sidebar—whether you're on call now, your next shift, active pages, and notification-setup gaps—from any page.
## Overview
The on-call widget is a compact status card in the Rootly web sidebar that shows **your** on-call status at a glance—without leaving the page you're on. It answers the questions responders ask most: *Am I on call right now? When am I next on? Have I been paged?*
The widget updates live as shifts hand off, pages arrive, and your status changes, so it always reflects the current moment.
The widget shows your **personal** status only. It doesn't change how schedules, escalation policies, or paging work—it's an additive view on top of your existing on-call configuration.
Looking for the widget you add to your phone's home screen? See [Mobile Home Screen Widgets](/on-call/mobile-widgets).
***
## Where to find it
The widget appears in the **left navigation sidebar** of the Rootly web app when the sidebar is expanded. It loads automatically for on-call-enabled teams—there's nothing to configure.
***
## What It Shows
The widget adapts to your current situation.
### On Call Now
When you're actively on call, the widget shows a progress bar counting down your current shift, along with the schedule you're covering.
For **"always on call"** coverage—where you're the sole owner of a 24/7 schedule, or a direct escalation-policy target—the widget shows an always-on indicator instead of a countdown.
### Off Call — Your Next Shifts
When you're not currently on call, the widget lists your upcoming shift(s), soonest first, with a **See all** link to your on-call calendar.
### You've Been Paged
When you have an active, unacknowledged page, the widget surfaces a banner with the alert and a link to open it. You can dismiss the banner, and it reappears if a new page comes in.
### Setup Incomplete
If you have no verified phone number and no active mobile device, Rootly can't page you. The widget shows a reminder—with links to add a phone number or install the mobile app—so you can fix it before it matters. See [On-Call Readiness](/on-call/on-call-readiness).
### Shadowing
If you're shadowing another responder (or being shadowed) for training, the widget reflects that too. See [On-Call Shadowing](/on-call/on-call-shadowing) for how shadowing works.
***
## Staying Up to Date
The widget refreshes on its own:
* The shift progress bar advances continuously.
* Pages, acknowledgements, and shift hand-offs update the widget in real time.
You don't need to reload the page to see your current status.
***
## Requirements
* Your team must have **on-call / alerting enabled**.
* Available in the **Rootly web app**. On-call status is also available in the [Rootly mobile app](/on-call/mobile-app).
To make sure you can actually be paged, verify a phone number and install the mobile app. See [On-Call Readiness](/on-call/on-call-readiness).
***
## Related Pages
The mobile companion — same on-call status, plus push notifications and Critical Alerts.
The dashboard the widget's notification-setup gap indicator surfaces.
The phone-native equivalent — home screen widgets for iOS and Android.
# Requesting Shift Coverage
Source: https://docs.rootly.com/on-call/request-coverage
Request coverage in Rootly when you can't work an on-call shift and automatically reassign responsibility to teammates with approval workflows.
## Overview
When you’re part of an on-call rotation, Rootly automatically assigns you shifts based on your team’s schedules and escalation policies. While this ensures consistent coverage, real life doesn’t always align perfectly with on-call rotations. Planned time off, unexpected conflicts, or last-minute changes can make it difficult to cover an assigned shift.
**Coverage Requests** are designed to solve this problem without disrupting schedules or requiring an administrator to intervene. Instead of editing schedules directly, you can request help from teammates who are already part of the same rotation. Rootly then coordinates notifications, tracks responses, and automatically reassigns the shift when someone accepts.
Coverage Requests are available across **Web, Slack, and the Rootly mobile app**, allowing teams to handle coverage quickly in the tools they already use.
## What Is a Coverage Request?
A Coverage Request is a lightweight way to say, “I can’t cover this shift—can someone else take it?”
When you submit a request, Rootly identifies the shifts affected during the selected time window and notifies other responders on the same schedule. Teammates can review the request, accept it if they’re available, or simply ignore it. Once a single person accepts, Rootly automatically creates the required override and closes the request.
This approach keeps schedules intact while ensuring accountability and visibility.
## Submitting Coverage Requests
If you have permission to create overrides directly, you can still reassign a shift manually. Coverage Requests are optimized for self-service coordination among teammates.
### Requesting Coverage on Web
Coverage Requests can be created directly from both the **On-Call Shifts** view and the **Schedule** editor.
From the **On-Call Shifts** page, select the shift you’re unable to cover and choose **Request Coverage**.
From a **Schedule**, edit the schedule you’re currently rotating on, navigate to the **Override & Coverage** tab, and select **Request Coverage**.
After opening the request modal, you’ll define the time range during which you’re unavailable. Rootly automatically detects all shifts assigned to you within that window and presents them for review. Once submitted, notifications are sent immediately.
### Requesting Coverage on Slack
If your team primarily operates in Slack, Coverage Requests can be created without ever leaving the conversation.
Run `/rootly override` in Slack, select the time window you need coverage for, and review the affected shifts. When you submit the request, Rootly sends actionable messages to eligible teammates and the schedule’s Slack channel (if configured).
### Requesting Coverage on Mobile
Coverage Requests can be created directly from the [Rootly mobile app](/on-call/mobile-app), from two places:
* From the **Home** tab, tap the **+** action button and choose **Create Override**.
* From the **Shifts** tab, tap one of your shifts and choose **Create Override** from the shift details sheet. The request form opens with that shift's time range pre-filled.
In the request form, set the time range during which you're unavailable. Rootly detects your shifts within that window and lists them for review. Choose **Request Coverage** to notify everyone on the schedule.
Or, if you have permission to create overrides, assign the shift directly to a specific teammate instead.
Enabling **Allow Partial Override** lets a shift be covered for just the portion that falls inside your selected window.
Once submitted, notifications go out immediately, and the request behaves exactly like one created on Web or Slack.
The shift details sheet offers coverage actions on your own shifts. Reassigning someone else's shift requires override permissions. Shadow shifts are read-only and can't be reassigned or covered.
## Managing Your Coverage Requests
All active Coverage Requests are visible in the Rootly web app. Navigate to **On-Call → Shifts**, then switch to the **Coverage Requests** view.
This page shows open requests, affected time ranges, and current status. Once a teammate accepts a request, it disappears from the list and the shift is immediately reassigned.
## Accepting Coverage Requests
Anyone who is part of the same schedule can accept a Coverage Request, as long as they are not already committed to overlapping on-call responsibilities.
Only **one** person can accept a request. As soon as it’s taken, Rootly creates an override, updates all relevant views, and notifies the original requester. If someone else attempts to accept after that point, they’ll be informed that the request has already been fulfilled.
If you rotate on multiple schedules, make sure accepting a request won’t conflict with another on-call commitment.
### Accepting on Web
Coverage Requests can be accepted from both the **On-Call Shifts** page and the **Schedule** editor.
From a schedule, navigate to the **Override & Requests** tab to review and accept open requests. Only users with schedule edit permissions can accept requests from this view.
### Accepting on Slack
When a Coverage Request is created, Rootly sends interactive Slack messages to:
1. All active users on the schedule
2. The schedule’s configured Slack channel, if one exists
These messages include actions to **Take the shift**, **View on web**, or ignore the request entirely.
### Accepting on Mobile
Accept coverage requests from Slack or Web. The mobile app does not support accepting them.
## Best Practices
Coverage Requests work best when they’re used early and intentionally. Submitting a request as soon as you know you’ll be unavailable gives teammates more time to plan and respond.
Avoid creating multiple overlapping requests for the same shift window. Rootly prevents duplicates by design, so updating an existing request is the best way to make changes.
Teams should also ensure schedules have a Slack channel configured. This improves visibility and dramatically increases response rates, especially for time-sensitive coverage gaps.
Finally, remember that Coverage Requests are meant for **user-assigned shifts**. If your shift is owned by a schedule rather than an individual, an administrator may need to intervene.
## Frequently Asked Questions (FAQs)
Coverage Requests can only be created for shifts that are assigned to individual users. If a shift is schedule-based, it must first be reassigned to a user before coverage can be requested.
Once a teammate accepts, Rootly automatically creates an override for the shift, reassigns responsibility, and closes the request. You don’t need to take any further action.
No. Only one person can accept a Coverage Request. If someone else tries to accept after it’s been taken, Rootly will notify them that the shift is no longer available.
Rootly sends notifications to eligible teammates via Slack (DMs and channels, if configured) and also sends a push notification to your device so you can track the request’s status.
Yes. If your plans change, you can delete the existing request and submit a new one with updated timing. Overlapping requests for the same window are not allowed.
***
## Related Pages
The parent concept — coverage requests operate on top of the underlying schedule.
See who is on-call before requesting or offering coverage.
When a swap is more than one-off — reach into the schedule directly instead.
# Round Robin Functionality
Source: https://docs.rootly.com/on-call/round-robin-functionality
Distribute alerts evenly among on-call team members in Rootly using alert-based and cycle-based round robin escalation strategies for fair workload sharing.
## Overview
Rootly's round robin feature introduces a streamlined way to manage escalation policies by automatically rotating the paging responsibilities among on-call team members. This ensures that alerts are distributed evenly and efficiently, reducing the burden on any single individual.
This feature is included out of the box and is available for use today.
## Key Features
### Paging Methods
#### Alert-Based Paging
This is the most common style of round robin paging. Incoming alerts are cycled through the rotation of users. For example, the first incoming alert will page User A, if User A doesn't respond, it will escalate to level 2. The next incoming alert will page User B to ensure even distribution of alerts.
#### Cycle-Based Paging
The cycle-based feature ensures each user in the escalation level is paged in sequential order before escalating to the next level.
### Dynamic Updates
Rootly's web UI dynamically updates to show the current pageable person and the order of escalation. Timeline events also indicate the strategy used for each page.
### Configuring Round Robin
1. Navigate to Escalation Policies:
* Go to the escalation policies section in your Rootly dashboard.
* On-Call --> Escalation Policies
2. Create/Select an Escalation Policy:
* Create a new escalation policy or choose an existing policy you want to configure for round robin.
3. Enable Round Robin:
* Toggle the round robin option in each escalation policy level.
4. Select either Alert-Based or Cycle-Based Paging:
* Set the levels to be alert-based, where each new alert pages the next person in line.
#### Example Scenario (Alert-based)
This example uses an escalation policy named "SRE - Round Robin EP" with one round robin alert-based level. The first pageable person is Alexandra. When alert A comes in, if Alexandra doesn't respond within five minutes, the alert moves to Andre, and then to Purvai.
* When alert B comes in, it will then go to Shadab and then escalate to the next level.
* When alert C comes in, it will then go to Andre and then escalate to the next level.
1. Initial Alert:
* Alexandra receives the first alert.
2. Escalation to Next Person:
* After five minutes without a response, the alert escalates to Andre.
3. Further Escalation:
* If Andre also doesn’t respond, the alert moves to Purvai.
4. Repeat Cycle:
* The repeat feature cycles the alerts back to Alexandra after Purvai.
#### Example Scenario (Cycle-Based)
This example uses an escalation policy named "SRE - Round Robin EP" with one cycle-based level. The first pageable person is Alexandra. When alert A comes in, it will first go to Alexandra and if she does not respond, then the alert moves to Shadab, and then to Andre.
1. Initial Alert:
* Alexandra receives the first alert.
2. Escalation to Next Person:
* After one minute without a response, the alert escalates to Shadab.
3. Further Escalation:
* If Shadab also doesn’t respond, the alert moves to Andre.
4. Repeat Cycle:
* The repeat feature cycles the alerts back to Alexandra after Andre.
### Timeline Events
Timeline events will now show an indication of the strategy used for each page, providing clarity on how the alert was escalated and which strategy was employed.
***
## Related Pages
Round-robin is a paging strategy option on escalation policy steps — this is where it lives.
The coverage source that round-robin distributes across.
See whether round-robin is actually distributing load evenly — MTTA by Responder and Alerts by Responder.
# On-call schedules, rotations, and overrides
Source: https://docs.rootly.com/on-call/schedules
Create, manage, and maintain on-call schedules in Rootly with rotations, layers, overrides, restrictions, and previews to keep coverage clear and predictable.
## What Are On-Call Schedules?
On-call schedules form the foundation of the Rootly On-Call system. They are critical tools that ensure **alert responsibility** is always clearly assigned and continuously rotating among your team members. These schedules determine **who is on-call at any given time** and control the **rotation** of on-call duties across users or teams.
In Rootly, schedules are not only useful for defining on-call responsibilities but also for organizing who will respond to incidents. A schedule can be as simple as a single user rotating weekly, or as complex as multiple schedules nested within one another, representing different teams or geographies.
However, schedules alone do not trigger notifications or paging—they need to be linked to **Escalation Policies** to become part of the actual alerting process. **Escalation Policies** control the process of how and when on-call users are paged.
***
## Permissions & Access
Before you can create, edit, or delete schedules, certain permissions are required. Only users with the **On-Call Admin** or **On-Call User** roles have the ability to manage schedules. **On-Call Observers**, on the other hand, have read-only access to schedules and cannot modify them.
**Required Permissions:**\
To create, edit, or delete schedules, users need the **On-Call Admin** or **On-Call User** role.\
Users without active on-call seats cannot be added to schedules.
***
## Creating a Schedule
To create a new on-call schedule in Rootly:
Navigate to **On-Call → Schedules** from the main menu.
Click **+ New Schedule** to start the process.
Enter a **Schedule Name** (required) and an optional **Description** that provides more context about the schedule’s purpose.
When naming your schedule, it’s best practice to choose a descriptive name that reflects the team or role associated with the schedule (for example, `Engineering Primary`, `Support - Weekend`, or `Platform Secondary`).
**Note:** The schedule name must be unique within your team to avoid conflicts. Schedule names should be concise, clear, and follow a consistent naming convention.
***
### Step 1: Define Rotations
Rotations dictate **how on-call responsibilities rotate** between team members. The **rotation** defines the order in which members are assigned on-call duties.
A rotation is essentially a cycle that determines **who is on call** and **when they will take over the responsibility**. Depending on your organization's needs, you may set up a rotation for a single user or multiple users who rotate through different time slots.
When you define a rotation, you’ll need to give it a **name** that reflects the group or role it pertains to. For example, a rotation for the `Security Team` might simply be called "Security Rotation."
**Important Reminder:**\
A schedule can only have **one active rotation at a time**. Make sure that you define the rotation rules clearly to avoid overlaps.
***
### Step 2: Add Rotation Members
In this step, you will **assign users to the rotation**. You can add individual users, teams, or other schedules to a rotation. Adding **schedules as members** allows for nesting, where a team’s schedule can be part of a higher-level schedule.
Each member of the rotation will be assigned a time period based on the rules you set in Step 3. For example, if you choose weekly rotation, the on-call duty will shift every week, and the members will rotate in order.
To assign members:
1. You can either search or use the filters to find the users, teams, or schedules you wish to add.
2. Once added, the members will rotate based on the order they are listed. You can easily adjust the order by **dragging and dropping** members within the list.
When a schedule is nested inside another schedule, the **parent schedule** will call the **current on-call responder** of the **child schedule** when it’s time for the escalation policy to trigger.
**Note:**\
A **Schedule cannot be part of more than one other schedule's rotation**. This restriction is in place to prevent infinite loops where schedules are circularly dependent on each other.
***
### Step 3: Configure Rotation Rules
Now that you've set up the members, it’s time to configure the rotation rules. This step is where you define the **frequency** and **timing** of the rotation.
Rootly provides several options for configuring your rotations:
* **Rotation Types:**
* Daily
* Weekly
* Biweekly
* Monthly
* Custom (for example, hourly, daily, weekly)
* **Active Days:**\
You can define which days of the week your rotation is active.
* **Active Hours:**\
You can specify whether the rotation is active all day or only for specific hours.
* **Timezone:**\
Choose the timezone for the rotation. Set it to UTC for around-the-sun setups; use a regional IANA timezone like `Asia/Bangkok` for single-region rotations.
For custom rotations, you can set specific timeframes and choose **shift length** (for example, 8-hour shifts, 12-hour shifts). You also have the option to adjust the **handoff time** for when one rotation ends and another begins.
**Important:**\
Only one rotation can be active at any given time. If two rotations overlap, Rootly will follow the **bottom-most** rotation logic.
***
### Step 4: Add Paging Logic
Once your schedule is set up with rotation rules, you’ll need to link it to an **Escalation Policy** to ensure that the correct person is paged.
An **Escalation Policy** defines **how and when users should be paged**. To page the on-call user, you must:
1. Create an **Escalation Policy**.
2. Assign the schedule to the policy by selecting it as a **notification target** within the escalation steps.
3. Make sure the escalation policy is connected to a **service** or **team** for active monitoring.
**Reminder:**\
Without being connected to an **Escalation Policy**, a schedule will not trigger any alerts. Ensure that you add the schedule to a policy so it becomes part of the alerting flow.
***
## Editing a Schedule
To modify a schedule:
Go to **On-Call → Schedules**.
Select the schedule you want to edit by clicking the **⋯** menu.
Click **Edit** to update the schedule name, description, members, or rotation rules.
***
## Deleting a Schedule
To delete a schedule:
Navigate to **On-Call → Schedules**.
Find the schedule and click the **⋯** menu.
Select **Delete**, and confirm your choice in the dialog window.
**Important:**\
Deleting a schedule is **permanent** and cannot be undone. If you want to temporarily stop a schedule, consider deactivating it or removing it from active escalation policies.
***
## Schedule Management Features
The **Schedules Page** in Rootly provides an overview of all schedules, showing:
* **Who is currently on-call** for each schedule
* The **next shift change**
* Which **Escalation Policy** is associated with the schedule
* Filter and search options for easy navigation
You can also sort schedules by **name**, **date created**, and **last updated**.
***
## Coverage Gaps And Fallback
A schedule has a **coverage gap** any time the rotation logic produces an interval with no on-call user — for example, a business-hours rotation outside its active window, a rotation whose users are all deleted or paused, or a layered schedule where no layer covers a particular hour. Rootly surfaces gaps in three places and provides an opt-in fallback to keep paging working through them.
### Where Gaps Show Up In The UI
| Surface | What You See |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Schedule list | A **Gaps Detected** badge appears on any schedule that currently contains one or more gaps. |
| Schedule editor | A banner at the top of the editor reads: *"We've detected gaps in your Schedule. Until gaps are filled we will automatically page the Schedule Owner \[name] as the fall-back to ensure full coverage."* The bracketed slot is replaced with the owner's actual name when rendered. |
| Schedule timeline | Hover any uncovered interval in the timeline to see the tooltip *"This is a gap in the schedule, falling back to the schedule owner."* The gap interval itself is not highlighted with a colored marker — gap detail surfaces on hover, not as a per-interval icon. |
The same surfaces are used for **unassigned shifts** (rotation interval exists but has no assignee — for example, after a user is removed from the rotation), with the badge labelled *Unassigned Shift Detected* instead.
### Schedule Owner And Fallback Assignee
Every schedule has a **Schedule Owner** and an optional **Fallback Assignee**. These users absorb pages whenever a gap or unassigned shift is detected — Rootly does not silently drop the page.
* **Schedule Owner** — the default fallback. If a gap is detected and no Fallback Assignee is set, the owner gets paged.
* **Fallback Assignee** — an explicit override for the owner. Use this when the owner role is administrative (a team admin) but the actual paging-capable user is someone else.
Both are configured in the schedule's settings under **Schedule Owner** and **Fallback Assignee**.
### Enabling 24/7 Coverage
Turn on **Enable 24/7 coverage for this Schedule** in the schedule settings to make gap detection active. When this is on, Rootly continuously evaluates the schedule for gaps and routes paging to the Fallback Assignee if one is configured, otherwise the Schedule Owner — preserving the precedence described above.
Gap detection only runs while a rotation is active. If a rotation has an **end date** in the past, Rootly stops detecting gaps after that date — the schedule will appear "gapless" because there is no active rotation to compare against. Audit rotation end dates regularly if you rely on the gap badge to surface coverage problems.
### Finding Gaps Before They Page
The gap surfaces above flag the *current* state of a schedule. To audit future coverage proactively, use:
* The [On-Call Readiness report](/on-call/on-call-readiness) — shows whether every responder in your on-call schedules has working notification methods configured. Confirms *the person* the schedule points to can actually be reached; use it alongside the schedule-side gap surfaces above, not as a replacement.
* The [On-Call Shifts page](/on-call/on-call-shifts) — visualizes generated shifts for the next several weeks; intervals with no assignee make gaps obvious well before they hit production.
***
## Exporting a Schedule to an External Calendar
Rootly allows you to export your on-call schedule to an external calendar so you and your team can view upcoming shifts directly from your preferred calendar app.
Open a schedule in **On-Call → Schedules**, select **Export to Calendar**, and choose **Google Calendar**, **Copy link to ICS File**, or **Download ICS File**. Schedule changes may take time to reflect on external calendars.
## Auditing Schedule Changes
Rootly tracks all changes made to schedules through an **audit log**. This provides transparency, allowing you to track:
* When a schedule was created or modified
* Updates to rotation members or rotation rules
* Changes in shift timings or handoff schedules
To access the audit log, simply start editing the schedule and click on **View Version History** in the top-right corner of the editor.
***
## Best Practices for Managing Schedules
* **Clearly name schedules:** Use descriptive names for schedules to make it easy for teams to identify the right schedule at a glance.
* **Simplify rotations:** Keep rotation cycles simple and clear. Avoid overly complex configurations unless absolutely necessary.
* **Use custom rotations when needed:** For specific teams or roles that need different rotation types, use the custom option to tailor schedules to your needs.
* **Review schedules periodically:** Regularly check schedules to ensure there are no overlaps or issues with rotation rules.
* **Add schedules to Escalation Policies:** Ensure that schedules are linked to the appropriate escalation policies to ensure timely paging.
***
## Frequently Asked Questions (FAQs)
To ensure on-call responders are actually notified, your schedule must be connected to an **Escalation Policy**.\
Schedules by themselves only define *who* is on call—they do not trigger paging. Once a schedule is added as a notification target in an escalation policy and that policy is assigned to a service or team, Rootly can page the active on-call responder reliably.
No. Schedules can only contain **individual users** or **other schedules**.\
Teams are not valid members of a schedule rotation. If you want a team to participate in on-call, create a schedule for that team and then nest that schedule inside a higher-level schedule if needed.
If you need to temporarily stop a schedule from paging responders, you do not need to delete it.\
Instead, remove the schedule from any associated escalation policies or deactivate it. This preserves the schedule configuration while preventing it from triggering alerts.
Rootly allows multiple rotations within a single schedule, but only **one rotation can be active at any given time**.\
If rotation rules overlap, Rootly automatically prioritizes the **bottom-most rotation** in the list. To control which logic applies, ensure your rotations are ordered intentionally and reviewed for overlap.
Three places: a **Gaps Detected** badge on the schedule list card, a banner on the schedule editor, and a hover tooltip on gap intervals in the timeline. There is no colored per-interval marker — timeline detail surfaces on hover. See [Coverage Gaps And Fallback](#coverage-gaps-and-fallback) for the full mechanism and the rotation-end-date caveat that can silently disable detection.
Rootly pages the **Schedule Owner** (or the **Fallback Assignee** if one is configured) so the alert never silently drops. Both are set in the schedule's settings. Enable **24/7 coverage** to make this fallback active.
There's no in-product "Download" or "Export" button for schedule configuration today — bulk export is programmatic. (Note: this is different from [exporting a schedule to an external calendar](#exporting-a-schedule-to-an-external-calendar), which produces an iCal feed for viewing shifts.) Three paths cover the common needs:
* **API.** `GET /v1/schedules` returns every schedule on your account. Walk into each schedule with `GET /v1/schedules/{id}/schedule_rotations`, then `GET /v1/schedule_rotations/{id}/schedule_rotation_users` and `/schedule_rotation_active_days` to capture the full structure.
* **CLI.** The [Rootly CLI](/integrations/cli) supports `rootly oncall list --format=json` to dump every schedule as JSON in one command.
* **Terraform.** Use the [Terraform provider](/integrations/terraform) with the `rootly_schedule`, `rootly_schedule_rotation`, `rootly_schedule_rotation_user`, `rootly_schedule_rotation_active_day`, and `rootly_override_shift` resources. The [Importing Existing Resources](/integrations/terraform#importing-existing-resources) workflow pulls your existing schedules into Terraform state so they live in source control going forward.
***
On-call schedules are central to keeping your team responsive, organized, and ready. Once set up, they enable seamless transitions and ensure that alerts are always addressed in a timely manner, no matter the time zone or time of day.
***
## Related Pages
Where schedules are wired in — a schedule pages nobody until an escalation policy references it.
How to modify existing schedules, pause without deleting, and manage rotations over time.
Overlay holidays and PTO to catch coverage conflicts before they turn into missed pages.
# Shift Reminders
Source: https://docs.rootly.com/on-call/shift-reminders
Configure Rootly on-call shift reminders that alert you before a shift starts and when it ends, with timing options, nested schedules, and troubleshooting.
## Overview
Shift Reminders notify you before your on-call shift starts and when your shift ends. Unlike notification rules (which page you about incidents), reminders are about **operational awareness** — knowing when you're going on-call so you can wind down other commitments, and knowing when you're going off-call so you can hand off cleanly.
Reminders are especially useful when you rotate frequently, cover multiple schedules, or switch between teams.
Shift Reminders are configured in **Account Settings → Notifications → On-Call Notifications**, alongside your audible and quiet notification rules. See [On-Call Notifications](/on-call/on-call-notifications) for the broader notification setup.
***
## Supported Delivery Channels
Shift reminders can be delivered through any of:
Most teams' default. Supports any verified email address.
Requires a verified mobile phone number.
Requires a connected mobile device.
Requires your Slack account to be connected to Rootly.
Reminder delivery methods must be verified when the reminder is enabled. Unverified phone numbers and email addresses will block save until verification completes — the same principle applies to notification rules.
***
## Reminder Timing
Reminders are configured by **delay** — how long before (or after) a shift boundary you want to be notified.
| Default Timing Options | Notes |
| ---------------------- | -------------------------------------------------------------------------------------------------------- |
| **3 days** | Useful for shifts that require pre-planning — for example, switching travel plans or arranging coverage. |
| **1 day** | The most common pre-shift reminder. Lets you mentally prepare without being too far ahead. |
| **1 hour** | The "you're about to be paged" warning. Useful for finishing up other tasks before going on-call. |
Some workspaces also support additional reminder options — **30 minutes**, **15 minutes**, and **1 minute** — for short rotations or handoff-heavy teams. When the expanded options are enabled, you can configure up to **three reminders per reminder type** (for example, three reminders before shift start). Without the expanded options, reminders are typically limited to one reminder per type.
If you only see one reminder available for start/end, your workspace may not have the additional shift reminder options enabled. Contact Rootly support to enable the expanded options.
***
## Slack Reminders
Slack delivery is available for shift reminders, but only when your Slack account is connected to Rootly. If Slack isn't connected, the UI prevents enabling Slack reminders because Rootly has no valid user destination to deliver to.
Connect your Slack account from your **user profile → Linked Accounts** — see [User Profile: Linked Accounts](/user-profile#linked-accounts) for the personal chat-connection flow. (This is separate from the org-level Slack installation your admin performs from Configuration → Integrations.)
***
## Nested Schedules
Shift reminders fire for shifts where you are **directly on-call** for the schedule. If your schedule is included in another schedule (a "parent schedule" pattern, where Schedule B is on rotation for Schedule A), reminders do not fire for the indirect coverage layer.
You won't receive shift reminders for shifts where your schedule is on-call indirectly through a parent schedule. This is intentional — it prevents duplicate reminders when multiple schedules layer on the same person.
If you need reminders for parent-schedule coverage, the only path is to be **directly rotated** on the parent schedule itself. Reminders are per-user (see the FAQ below), so there is no schedule-level reminder configuration to change — the coverage layer you're directly on is the layer that triggers reminders.
***
## Default Setup
When you first join an organization, Rootly creates a safe baseline so you aren't left without reminders — typically two shift reminders (one before shift start, one at shift end), both delivered via email. These defaults are starting points, not best-possible-forever configurations. Adjust the timing and delivery channels to match how you actually want to be reminded.
***
## Best Practices
* **Stack two reminders if you have the option.** A 1-day-out reminder for planning + a 1-hour-out reminder for "phone in hand" covers both bases. If your workspace only supports one reminder per type, the 1-hour-out reminder is usually more valuable.
* **Use email for the long-lead reminder and push or Slack for the short-lead reminder.** Email is durable and searchable; push/Slack are immediate but ephemeral.
* **Don't rely on Slack alone for shift end.** Shift-end reminders matter for handoff — if Slack is the only channel and Slack is having a bad day, you'll miss the handoff window. Pair Slack with email or SMS as a backup.
* **Verify every channel you enable.** Rootly blocks saves with unverified contact methods, but it's worth confirming verification status before you depend on a channel.
* **Audit your reminders after a schedule change.** If you switch teams or get added to a new rotation, your prior reminder configuration may not match the new schedule's cadence.
***
## Troubleshooting
Three common causes:
1. **Nested schedule coverage** — if your on-call coverage comes from a parent schedule rather than direct rotation, reminders won't fire for the indirect layer. Check whether the schedule you're on is the one you're directly rotated through.
2. **Reminder disabled** — confirm the reminder is enabled in Account Settings → Notifications → On-Call Notifications.
3. **Channel verification** — verify the contact method (email, phone) used for delivery, or (for Slack reminders) confirm your Slack account is connected.
Some workspaces support additional reminder timing options and allow up to three reminders per start/end type. If your workspace doesn't have that enabled, you may be limited to one reminder per type. Pick the single timing that best matches your handoff needs (1 hour before shift start is a common choice). Contact Rootly support to ask about enabling the expanded options.
Enabled shift reminders require verified contact methods. Rootly blocks saves on configurations that depend on unverified email addresses or phone numbers because delivery would fail at runtime. Verify the contact method (Account Settings → Notifications) and try saving again.
Slack delivery requires your personal Slack account to be linked from your user profile. Go to your profile menu → **My Profile → Linked Accounts** and connect Slack there (see [User Profile: Linked Accounts](/user-profile#linked-accounts)). Once linked, return to Shift Reminders and Slack will appear as a delivery option.
Duplicate reminders usually mean you've configured the same reminder on multiple delivery channels (for example, both email and SMS at the same timing). If you want a single notification per timing, choose one channel per reminder. If you want multi-channel coverage but no duplicates within a single channel, audit the reminders list and remove any redundant entries.
***
## Frequently Asked Questions
Yes. Reminders fire for the user actually on-call at the time, so if you take over someone else's shift via a trade or override, you'll receive their shift's reminders.
No. Reminders are personal to the user who is on-call. If you need awareness of teammates' shifts, use the schedule view in Rootly Web or sync the schedule to your calendar — see [Schedules](/on-call/schedules).
Push notification reminders respect Do Not Disturb by default. To make them ring through DND, enable **Critical Alerts** on the device contact method (the same mechanism used for quiet incident notifications). SMS and email reminders behave according to your phone's OS-level rules for those channels.
Reminders are per-user, not per-schedule, so you have one set of reminder configurations that applies to every schedule you're on. If you need different timing for different rotations, set the longest-lead reminder you need and rely on schedule awareness from the calendar sync for the rest.
***
## Related Pages
The companion configuration — audible and quiet notification rules for actual incident paging.
Creating and managing the on-call schedules that reminders fire against.
Required for push notification delivery — includes setup for Critical Alerts.
# Supported Countries
Source: https://docs.rootly.com/on-call/supported-countries
Reference list of countries supported for SMS, push, and phone call notifications in Rootly On-Call, including delivery routes and regional carrier information.
Rootly On-Call uses Twilio to deliver SMS and phone call notifications to on-call responders. This page lists the countries where these notification methods are supported.
**Deliverability is not guaranteed.** Even in supported countries, messages and calls may fail to deliver due to carrier filtering, local regulations, or network issues. Push notifications via the Rootly mobile app are more reliable and recommended as your primary notification method.
**Important considerations:**
* **Local regulations**: Many countries have strict telecom regulations that may affect message delivery, especially for A2P (Application-to-Person) messaging
* **Carrier filtering**: Mobile carriers may filter or block messages from unknown or international senders
* **Number registration**: Some countries require pre-registration of sender IDs or recipient numbers
* **Time-based restrictions**: Certain countries restrict messaging during specific hours
* **Content filtering**: Messages containing certain keywords may be blocked by local carriers
## Registered Sender IDs
Rootly has registered sender IDs in the following countries for improved deliverability:
| Country | Sender ID | Status |
| --------- | --------- | ----------------- |
| Hong Kong | Rootly-HK | Approved |
| Macao | Rootly-MO | Approved |
| Taiwan | Rootly-TW | Filing in process |
***
## Short Codes
Rootly uses dedicated short codes in the following countries for improved deliverability:
| Country | Short Code | Status |
| ----------- | ---------- | ------ |
| New Zealand | 8436 | Active |
***
## SMS Notifications
SMS notifications can be sent to phone numbers in the following countries. Delivery rates vary by country and carrier.
Country
Code
Afghanistan +93
Albania +355
American Samoa +1
Andorra +376
Anguilla +1264
Antigua and Barbuda +1268
Argentina +54
Armenia +374
Aruba +297
Australia +61
Austria +43
Bahamas +1242
Bahrain +973
Barbados +1246
Belarus +375
Belgium +32
Belize +501
Benin +229
Bermuda +1441
Bhutan +975
Bolivia +591
Bosnia and Herzegovina +387
Botswana +267
Brazil +55
Brunei +673
Bulgaria +359
Burkina Faso +226
Cambodia +855
Cameroon +237
Canada +1
Cape Verde +238
Cayman Islands +1345
Central African Republic +236
Chad +235
Chile +56
China +86
Colombia +57
Comoros +269
Congo +242
Congo (DRC) +243
Cook Islands +682
Costa Rica +506
Croatia +385
Cuba +53
Cyprus +357
Czech Republic +420
Denmark +45
Djibouti +253
Dominica +1767
Dominican Republic +1829
Egypt +20
El Salvador +503
Equatorial Guinea +240
Eritrea +291
Estonia +372
Ethiopia +251
Faroe Islands +298
Fiji +679
Finland +358
France +33
French Guiana +594
French Polynesia +689
Gabon +241
Gambia +220
Georgia +995
Germany +49
Ghana +233
Gibraltar +350
Greece +30
Greenland +299
Grenada +1473
Guadeloupe +590
Guam +1671
Guatemala +502
Guinea +224
Guinea-Bissau +245
Guyana +592
Haiti +509
Honduras +504
Hong Kong +852
Hungary +36
Iceland +354
India +91
Indonesia +62
Iraq +964
Ireland +353
Israel +972
Italy +39
Ivory Coast +225
Jamaica +1876
Japan +81
Jordan +962
Kazakhstan +7
Kenya +254
Kiribati +686
Korea (South) +82
Kuwait +965
Kyrgyzstan +996
Laos +856
Latvia +371
Lebanon +961
Lesotho +266
Liberia +231
Libya +218
Liechtenstein +423
Lithuania +370
Luxembourg +352
Macao +853
Macedonia +389
Madagascar +261
Malawi +265
Malaysia +60
Maldives +960
Mali +223
Malta +356
Marshall Islands +692
Martinique +596
Mauritius +230
Mexico +52
Micronesia +691
Moldova +373
Monaco +377
Mongolia +976
Montenegro +382
Montserrat +1664
Morocco +212
Myanmar +95
Namibia +264
Nepal +977
Netherlands +31
Netherlands Antilles +599
New Caledonia +687
New Zealand +64
Nicaragua +505
Niger +227
Norway +47
Palau +680
Panama +507
Papua New Guinea +675
Paraguay +595
Peru +51
Philippines +63
Poland +48
Portugal +351
Puerto Rico +1787
Qatar +974
Reunion +262
Romania +40
Russia +7
Samoa +685
San Marino +378
Saudi Arabia +966
Serbia +381
Sierra Leone +232
Singapore +65
Solomon Islands +677
Spain +34
St Kitts and Nevis +1869
St Lucia +1758
St Pierre and Miquelon +508
St Vincent Grenadines +1784
Suriname +597
Swaziland +268
Sweden +46
Switzerland +41
Taiwan +886
Thailand +66
Tonga +676
Trinidad and Tobago +1868
Turkey +90
Turkmenistan +993
Turks and Caicos Islands +1649
Ukraine +380
United Arab Emirates +971
United Kingdom +44
United States +1
Uruguay +598
Vanuatu +678
Vietnam +84
Virgin Islands (British) +1284
Virgin Islands (U.S.) +1340
Yemen +967
***
## Phone Notifications
Phone call notifications can be made to phone numbers in the following countries. Call connection rates vary by country, carrier, and network conditions.
Country
Code
Afghanistan +93
Albania +355
American Samoa +1
Andorra +376
Anguilla +1264
Antigua and Barbuda +1268
Argentina +54
Armenia +374
Aruba +297
Australia +61
Austria +43
Bahamas +1242
Bahrain +973
Barbados +1246
Belarus +375
Belgium +32
Belize +501
Benin +229
Bermuda +1441
Bhutan +975
Bolivia +591
Bosnia and Herzegovina +387
Botswana +267
Brazil +55
Brunei +673
Bulgaria +359
Burkina Faso +226
Cambodia +855
Cameroon +237
Canada +1
Cape Verde +238
Cayman Islands +1345
Central African Republic +236
Chad +235
Chile +56
China +86
Colombia +57
Comoros +269
Congo +242
Congo (DRC) +243
Cook Islands +682
Costa Rica +506
Croatia +385
Cuba +53
Cyprus +357
Czech Republic +420
Denmark +45
Djibouti +253
Dominica +1767
Dominican Republic +1829
Egypt +20
El Salvador +503
Equatorial Guinea +240
Eritrea +291
Estonia +372
Ethiopia +251
Faroe Islands +298
Fiji +679
Finland +358
France +33
French Guiana +594
French Polynesia +689
Gabon +241
Gambia +220
Georgia +995
Germany +49
Ghana +233
Gibraltar +350
Greece +30
Greenland +299
Grenada +1473
Guadeloupe +590
Guam +1671
Guatemala +502
Guinea +224
Guinea-Bissau +245
Guyana +592
Haiti +509
Honduras +504
Hong Kong +852
Hungary +36
Iceland +354
India +91
Indonesia +62
Iraq +964
Ireland +353
Israel +972
Italy +39
Ivory Coast +225
Jamaica +1876
Japan +81
Jordan +962
Kazakhstan +7
Kenya +254
Kiribati +686
Korea (South) +82
Kuwait +965
Kyrgyzstan +996
Laos +856
Latvia +371
Lebanon +961
Lesotho +266
Liberia +231
Libya +218
Liechtenstein +423
Lithuania +370
Luxembourg +352
Macao +853
Macedonia +389
Madagascar +261
Malawi +265
Malaysia +60
Maldives +960
Mali +223
Malta +356
Marshall Islands +692
Martinique +596
Mauritius +230
Mexico +52
Micronesia +691
Moldova +373
Monaco +377
Mongolia +976
Montenegro +382
Montserrat +1664
Morocco +212
Myanmar +95
Namibia +264
Nepal +977
Netherlands +31
Netherlands Antilles +599
New Caledonia +687
New Zealand +64
Nicaragua +505
Niger +227
Norway +47
Palau +680
Panama +507
Papua New Guinea +675
Paraguay +595
Peru +51
Philippines +63
Poland +48
Portugal +351
Puerto Rico +1787
Qatar +974
Reunion +262
Romania +40
Russia +7
Samoa +685
San Marino +378
Saudi Arabia +966
Serbia +381
Sierra Leone +232
Singapore +65
Solomon Islands +677
Spain +34
St Kitts and Nevis +1869
St Lucia +1758
St Pierre and Miquelon +508
St Vincent Grenadines +1784
Suriname +597
Swaziland +268
Sweden +46
Switzerland +41
Taiwan +886
Thailand +66
Tonga +676
Trinidad and Tobago +1868
Turkey +90
Turkmenistan +993
Turks and Caicos Islands +1649
Ukraine +380
United Arab Emirates +971
United Kingdom +44
United States +1
Uruguay +598
Vanuatu +678
Vietnam +84
Virgin Islands (British) +1284
Virgin Islands (U.S.) +1340
Yemen +967
If your country is not listed or you're experiencing delivery issues, please [contact support](/contacting-support) for assistance.
***
## Troubleshooting
If you're not receiving SMS or phone notifications:
1. **Verify phone number format**: Ensure your phone number is entered correctly with the full country code (for example, +1 for US, +44 for UK)
2. **Check notification settings**: Confirm notifications are enabled in your [user profile](/user-profile)
3. **Review carrier settings**: Your mobile carrier may be blocking messages from unknown or international numbers
4. **Check Do Not Disturb**: Ensure your phone's DND settings aren't blocking calls from unknown numbers
5. **Verify network connectivity**: Poor cellular coverage can prevent message and call delivery
### Common Delivery Issues by Region
**High-risk countries for SMS delivery**: Some countries have particularly strict filtering that may result in low delivery rates. Consider using phone calls or alternative notification methods (Slack, email, push notifications) as your primary contact method in these regions.
| Region | Common Issues |
| ------------- | -------------------------------------------------------------- |
| Asia Pacific | Strict sender ID registration requirements, content filtering |
| Middle East | Government-level filtering, restricted international messaging |
| Africa | Network infrastructure limitations, carrier filtering |
| Latin America | Sender ID requirements, variable carrier support |
| Europe | GDPR compliance requirements, sender verification |
### Best Practices
* **Use push notifications as primary**: Push notifications via the Rootly mobile app are more reliable than SMS/phone and work globally without carrier restrictions
* **Configure multiple notification methods**: Set up backup notification channels (email, Slack) in addition to push notifications
* **Use escalation policies**: Ensure your on-call schedules have proper escalation to catch missed notifications
* **Test notifications**: Periodically test your notification settings to ensure they're working
* **Keep contact info updated**: Ensure phone numbers are current and properly formatted
For persistent issues, contact [Rootly Support](/contacting-support).
# Sync Schedules to Slack User Groups
Source: https://docs.rootly.com/on-call/sync-schedules
Keep Slack user groups automatically in sync with your Rootly on-call schedules so the right responder is always reachable through @mentions and routing.
## Overview
Syncing an on-call schedule to a Slack user group makes it easy for teams to reach the correct on-call responder without needing to know who is currently covering a shift.
Instead of manually updating Slack user groups or relying on outdated documentation, Rootly keeps your Slack user groups continuously in sync with your on-call schedules. As schedules rotate, overrides are applied, or nested schedules take effect, Rootly automatically updates the Slack user group to reflect **who is on call right now**.
This allows anyone in Slack to simply mention a user group—such as `@oncall-engineering`—and reliably notify the active on-call responder, even as coverage changes behind the scenes.
***
## How Slack User Group Sync Works
When a schedule is linked to a Slack user group, Rootly treats that user group as a live reflection of the schedule’s current on-call assignee.
Each time the on-call user changes, Rootly updates the Slack user group membership to include only the active responder. This includes changes caused by:
* Normal rotation handoffs
* Overrides being created, updated, or reverted
* Nested schedules resolving to a downstream on-call user
Because Slack handles notifications when a user group is mentioned, tagging the group in a Slack message immediately notifies the on-call responder—without requiring any manual updates from your team.
Slack user group mentions are handled entirely by Slack.\
Rootly’s role is to ensure the **correct Slack user is always a member of the group** based on the current on-call state.
***
## Prerequisites
Before you can sync a schedule to a Slack user group, your workspace must meet a few requirements.
Your team must have a Slack integration connected to Rootly, and that integration must include the permissions required to manage user group membership. If the necessary scopes are missing, the Slack user group selector will not be available when editing a schedule.
Additionally, Rootly matches users to Slack accounts by email address. If a Rootly user does not have a corresponding Slack user with the same email, they cannot be added to the Slack user group.
If you don’t see Slack user groups listed when editing a schedule, ask a Slack administrator to verify that the Slack integration is connected and has the required user group permissions.
***
## Set Up a Slack User Group Sync
To sync a schedule with a Slack user group, open the schedule you want to configure or create a new one.
Within the schedule editor, navigate to the **Notifications** tab. From there, you can select an existing Slack user group from your connected Slack workspace. Once selected, save the schedule to apply the change.
As soon as the schedule is saved, Rootly will evaluate the current on-call shift and update the selected Slack user group to include the active responder.
***
## What Happens After Setup
Once configured, the Slack user group remains continuously updated as the schedule evolves.
When a rotation hands off, an override is applied, or a nested schedule resolves to a different user, Rootly automatically updates the Slack user group membership. No manual intervention is required.
If the Slack user group is mentioned in any Slack message, Slack will notify the current on-call responder immediately.
Overrides are fully supported.\
If an override changes who is on call, the Slack user group is updated automatically to reflect that change.
***
## Using One Slack User Group Across Multiple Schedules
You can associate the same Slack user group with multiple schedules.
This is useful if your organization wants a single user group—such as `@oncall`—that always represents *all* active on-call responders across different schedules. Rootly keeps the user group in sync across every schedule that references it, ensuring membership stays accurate even as individual schedules change.
If a schedule is removed from a Slack user group or switched to a different group, Rootly updates all affected schedules to prevent stale memberships.
***
## Best Practices
Slack user group sync works best when user emails are consistent between Rootly and Slack, schedules are connected to escalation policies, and overrides are used instead of editing rotations for short-term changes.
For critical paging paths, Slack user groups should complement—not replace—primary notification methods such as push notifications or phone calls. Slack is best used as a fast collaboration signal rather than the sole paging mechanism.
***
## Frequently Asked Questions (FAQs)
No. Mentioning a Slack user group only triggers Slack’s built-in notification behavior.\
Rootly ensures the correct user is a member of the group, but it does not create alerts or incidents from Slack mentions alone.
Rootly matches users to Slack accounts by email.\
If no matching Slack user exists, Rootly cannot add that person to the user group, and the sync will fail for that shift.
Yes.\
If a parent schedule includes another schedule as a member, Rootly resolves the final on-call user and updates the Slack user group based on that resolved assignee.
Yes.\
Simply remove the Slack user group from the schedule’s Notifications tab and save. The schedule remains intact, but Slack sync will stop.
Slack user groups belong to a single Slack workspace. In a Slack Connect or externally shared channel, participants from another organization can't see or mention your workspace's user groups, so a mention like `@oncall-engineering` returns a `user group unavailable` error for them.
This is a Slack platform restriction, not a Rootly setting—there is no toggle in Rootly that enables user group mentions for external participants.
As a workaround, have someone who is both a member of your Slack workspace and present in the shared channel post the mention. Because Rootly keeps the user group in sync with the current on-call responder, that mention still notifies whoever is on call. External participants can use `@channel` or `@here` to reach everyone in the channel instead.
***
## Related Pages
The Rootly-side representation that synced schedules ultimately produce.
How Rootly-native edits behave on top of synced schedules.
Where synced schedules get attached so they actually page responders.
# Rootly quick start: sign up, connect Slack, run a demo
Source: https://docs.rootly.com/quick-start-guide
Get up and running with Rootly in about 15 minutes, from signing up to connecting Slack, configuring teams, and creating your first incident end to end.
**Switching from PagerDuty?** Skip this checklist — see [Migrating From PagerDuty](/switch/pagerduty-migration), which covers the concept-to-concept mapping, schedule and escalation policy import, cutover planning, and validation.
## Watch the Demo
Get familiar with Rootly by watching the product demo:
## Up and Running in About 15 Minutes
This quick start path takes you from account setup to your first incident in just a few steps.
1. [**Sign up**](/signing-up)\
Create your Rootly account and join your organization.
2. [**Connect Slack**](/integrating-with-slack)\
Set up the Slack integration for your workspace, or connect your Slack user account if your organization has already configured Slack.
3. [**Create your first incident**](/incidents/creating-incidents/creating-incidents-via-slack)\
Create a test incident to learn the basics, or follow the Slack-based flow to see how incident creation works in practice.
If you’re using the dashboard, **Create Test Incident** is the fastest way to walk through the incident workflow for the first time.
Depending on your organization’s setup, you may also see a guided onboarding flow after sign-up that walks you through these steps.
## What’s Next
Once you’ve completed the basics, continue exploring the documentation to configure Rootly for your team.
If you’re an admin or owner, a good next step is creating your first workflow to automate incident tasks and processes.
## Need Help?
Visit the [Help and Support](https://rootly.com/help) page for more resources and assistance.
# Responder Checklist
Source: https://docs.rootly.com/responder-checklist
If you're the one jumping into the incident channel (not the one configuring forms and workflows), this part is for you.
Rootly is here as a tool to help you respond to incidents. Follow these steps from top-down to prepare for when things go wrong.
## 1. Declare an incident
Get the incident open and organized in seconds.
1. **Know the help command** — `/rootly help` run in any Slack channel shows every command available. You never need to memorize anything.
2. **Declare with the new-incident command** — `/rootly new` opens the incident form. Fill in title, summary, and severity — the fields you see are configured by your org, and picking a severity kicks off automations behind the scenes.
3. **Use private incidents when it's sensitive** — Security issues, customer escalations, or anything needing tightly controlled access should be declared private. AI features like catchup and summaries still work inside them.
## 2. Work from the command center
The incident channel is your home base — everything you need lives there.
1. **Know your command center block** — The pinned message at the top of the channel has the buttons and links you'll use most: paging, updating, resolving, and links out to your team's tools (bridge, ticketing, etc.).
2. **Catch up instantly when you join mid-incident** — Use the catch-up command instead of scrolling the whole channel history.
3. **Ask Rootly for a summary** — Get an AI-suggested summary of the incident so far, and use it as a starting point rather than writing one from scratch.
## 3. Know your role and your tasks
Roles come with built-in responsibilities — lean on them.
1. **Check what role you've been assigned** — Roles carry default tasks that get created automatically the moment you're assigned, so check your tasks as soon as you join.
2. **Use roles to get oriented fast** — If you're newer to on-call or IR, seeing who holds which role tells you exactly who to go to for what.
3. **Mark tasks done as you go** — Keeps the incident tidy and gives anyone joining later an accurate picture of what's already been handled.
## 4. Update the incident & use emoji reactions
A couple small habits that save everyone time later.
1. **Add the affected service when you know it** — The moment you attach a service, its runbook attaches automatically and new tasks get created from it — no one has to remember the checklist by hand.
2. **React with the pin emoji on anything retro-worthy** — This is the most important one: pinning builds your retrospective as you go. You can always edit or prune later, but you can't get back a moment nobody flagged.
3. **Know the other emoji shortcuts** — A star can turn a message into a task, and a memo/note emoji can turn one into a follow-up — check with your admin team which emoji are wired up for your org.
## 5. Page, escalate & resolve
Bring in the right people, and close it out cleanly.
1. **Use any of the three paging paths** — Ask Rootly who to page, run `/rootly page`, or hit the Escalate button in the command center. All three reach the same on-call rotations, so use whichever is fastest in the moment.
2. **Let severity changes do the notifying** — Updating severity (e.g. to Sev 2) automatically posts to the leadership channel — you don't need to separately ping anyone.
3. **Use the AI assist when you resolve** — The resolution form suggests a summary for you; review and adjust it rather than writing one cold.
## 6. Know the web UI tabs
Everything from Slack also lives here — useful once things slow down.
1. **Timeline** — The fastest way to find your pinned messages and reconstruct what happened, in order.
2. **Tasks** — Broken out by role assignment and by runbook, so you can see what's outstanding at a glance.
3. **Follow-ups** — Shows any auto-created tickets (e.g. Jira) so you can track post-incident work without leaving Rootly.
4. **Status page** — Not automatically in sync with incident status — someone needs to manually publish updates here.
5. **Retro** — Where the retrospective lives once the incident resolves; this is where your pinned messages end up.
6. **Scribe tab** — Reinvite the scribe if it dropped, and pull up the call recording/transcript afterward.
# Configuring Process Steps
Source: https://docs.rootly.com/retrospectives/configuring-process-steps
Customize retrospective process steps in Rootly with titles, requirements, role assignments, due dates, and reminder configurations to standardize follow-ups.
Retrospective process steps define the work responders should complete after an incident. Each process is made up of ordered steps that can be customized to match your organization’s retrospective workflow.
Each step is displayed in a list under the incident's Retrospective tab for them to follow while completing the Retrospective.
You can configure each step with:
* A title and description
* Required or optional completion
* A default owner based on an Incident Role
* A due date based on when the incident was resolved
* Slack and email reminders for the step owner
Each Process must include at least one step.
## Editing the Default Process
You are able to add additional steps to your Default Process: remember, the Default Process will be used if no other Custom Processes match the incident.
Note that there are a few built-in steps in your Default Process. These steps are marked with a `Built-In` label in the Process editor.
These built-in steps can be edited and deleted as needed. However, keep in mind that these steps show differently in the Retrospective tab of an incident and should be used as originally intended.
### How Built-In steps are displayed
#### Gather & Confirm Data
This step makes it easy for responders to fill out the necessary information for the incident. When viewing the Incident's Retrospective tab, the 'Edit Data' button makes it easy to fill out all necessary incident data in one modal.
#### Write the Retrospective Document
This step links any retrospective documents for easy access.
#### Create Follow-Up Action Items
Easily create any incident follow-ups from this step. You can easily view the current status, due date, and assignee from the step as well.
#### Share the Finalized Retrospective
Quickly publish any retrospective documents from this step.
## Editing Custom Processes
### Step Configuration Options
Each step can be configured in several ways to support your team’s process.
#### Title and Description
Use the title and description fields to clearly define what the step is for and what responders are expected to complete.
#### Required or Optional Steps
Steps can be either required or optional:
The step must be completed before the retrospective can be fully resolved. The due date can still be adjusted.
The step can be skipped if it is not needed for that incident.
#### Default Owner by Incident Role
You can assign a step to an **Incident Role** so the user holding that role on the incident becomes the default owner for the step.
This helps automatically route work to the right responder without needing to manually assign each step.
#### Due Dates
Step due dates are calculated relative to when the incident is resolved.
Due dates are:
* Based on business days after the incident is resolved
* Calculated using the team’s timezone
* Adjusted to business hours between **8am and 6pm**
* Moved forward when they would otherwise fall on a weekend
You can use standard due date options or enter a custom number of business days.
#### Reminder Notifications
Steps can send reminders to the assigned owner on any combination of channels and timings:
Where reminders are delivered. Enable one or both — Slack for real-time nudges, email for durable ones.
When reminders are sent. Combine any of the three — for example, one reminder 24 hours before the due date, one on the due date, and one after it becomes overdue.
### Process Phases with Custom Statuses
If your workspace uses **Custom Statuses**, you can assign each step to a **Retrospective Status**. This allows steps to appear in different resolved phases, such as:
* Retrospective
* Follow-ups
This is useful when your retrospective workflow spans multiple phases after the incident has already been resolved.
## Frequently Asked Questions
Each step can include a title, description, required or optional behavior, a default owner based on an Incident Role, a due date, and reminder notifications. These settings let you tailor each step to match your team’s retrospective workflow.
Due dates are based on business days after the incident is resolved. Rootly calculates them using the team’s timezone, keeps them within business hours, and skips weekends when determining the due date.
If a step is assigned to an Incident Role, the user holding that role on the incident becomes the default owner for the step. This helps automatically assign retrospective work to the right responder.
Yes. Optional steps can be skipped when they are not needed for a particular incident. Required steps must be completed before the retrospective can be resolved.
No. Every retrospective process must include at least one step. You can edit, reorder, or remove steps, but you cannot delete the last remaining step in the process.
The legacy setup creates a simplified two-step workflow by keeping only the data-gathering and retrospective-document steps in the default process. This is useful if you want a lighter process that resembles earlier retrospective behavior.
***
## Related Pages
The parent concept — processes group steps and decide which incidents get which process.
Templates define the shape of the retrospective document the write-up step produces.
The umbrella retrospectives page covering processes, editor, and AI drafting.
# Configuring Retrospective Processes
Source: https://docs.rootly.com/retrospectives/configuring-retrospective-processes
Configure retrospective processes and preferences in Rootly to right-size follow-up work based on severity, incident type, team ownership, or custom conditions.
Retrospective processes let you control which follow-up steps are created for an incident. By creating different processes for different incident scenarios, you can scale your retrospective workflow based on severity, incident type, or team.
A retrospective process contains an ordered set of steps that guide responders through post-incident work, such as gathering details, writing the retrospective document, hosting a review meeting, and creating follow-up actions.
## Setting up Processes
If you have different retrospective processes for different teams and incident types, you're able to configure each process separately in **Settings** > **Retrospectives** > **Processes**.
Each Process configured is set up with conditions: this lets Rootly know when to apply which Process to which incident. For example, you can configure a SEV0 Process with conditions to use it for any incident with a SEV0 severity.
Every workspace comes with a **Default Retrospective Process** to get you started. This Default Process can be edited, but cannot be deleted. If you add additional custom processes to Rootly, your Default Retrospective Process will become the fallback process, and will be used for any incident that does not match any conditions for the custom processes you've set up.
### Custom Processes
For more opinionated incident practices, you can create custom retrospective processes and apply them only to incidents that match specific conditions.
A custom process can be configured to apply based on:
* Severity
* Incident type
* Team
Rootly matches these conditions using **OR** logic. If an incident matches the severity, any incident type, or any team attached to the process, that process can be selected.
If multiple custom processes match the same incident, Rootly uses the most recently created matching process.
A custom process must have at least one condition. If no severity, incident type, or team is attached, the process is inactive and will not be used.
## Skip and Mandatory Preferences
In addition to choosing which process applies, you can also control whether a retrospective should be skipped or required for certain incidents.
Configure skip and mandatory rules under **Retrospectives > Preferences** or the equivalent area in your workspace.
These preferences use the same condition types:
* Severity
* Incident type
* Team
You can configure retrospectives to be:
Responders cannot skip the retrospective for matching incidents.
The retrospective is skipped by default for matching incidents. Responders can still resume it later if follow-up work is needed.
No mandatory or auto-skip rule applies, so responders can choose whether to skip the retrospective on a per-incident basis.
If an incident matches both a mandatory rule and an auto-skip rule, **auto-skip takes precedence**.
By default, responders can skip a retrospective from the bottom of the Retrospective tab. This option is not available when the retrospective is mandatory for that incident.
Auto-skipped retrospectives can still be resumed later by responders if follow-up work is needed.
## How Process Selection Works
When an incident is created or its status changes, Rootly evaluates the incident’s severity, incident types, and attached teams to determine which retrospective process should be used.
Rootly then:
* Selects the matching custom process, if one exists
* Falls back to the default process when no custom process matches
* Creates the steps for the selected process on the incident
Depending on your process configuration, steps can also include:
* Relative due dates
* Default assignees based on incident roles
* Required or skippable behavior
* Reminder notifications
If Custom Statuses are enabled, steps can also be organized by resolved phase, such as a retrospective phase and a follow-up phase.
## Example Configurations
### SEV1 Incident Example
A SEV1 incident might use a more rigorous retrospective process with steps such as:
* Gather information
* Hold retrospective meeting
* Peer review the generated document
* Publish the retrospective document
These steps can also include:
* Assigned owners based on incident role
* Relative due dates
* Reminder notifications
### SEV3 Incident Example
A SEV3 incident might use a lighter process with optional steps such as:
* Gather information
* Hold a self-facilitated team retrospective
* Capture lightweight follow-up actions only when needed
For lower-impact incidents, you can also configure the retrospective to be auto-skipped by default and resumed only when additional review is necessary.
## Frequently Asked Questions
A retrospective process is a named set of ordered steps used to guide post-incident follow-up work. Each process can include its own steps, due dates, assignees, and reminders.
Rootly checks the conditions attached to each custom process and looks for matches based on severity, incident type, or team. If more than one custom process matches, the most recently created one is used. If none match, the default retrospective process is used.
A custom process without any conditions is inactive. It will not be selected for any incident until at least one severity, incident type, or team condition is added.
Process conditions determine which retrospective process and steps are used for an incident. Skip and mandatory preferences determine whether responders can skip the retrospective for incidents that match those rules.
Yes, by default responders can skip a retrospective on an individual incident. However, if that incident matches a mandatory retrospective rule, the retrospective cannot be skipped.
Yes. Auto-skipped retrospectives can be resumed later if responders decide that follow-up work is still needed.
***
## Related Pages
Customize the ordered steps every process runs — required vs. optional, owners, due dates, reminders.
Standardize the retrospective document produced by the write-up step of every process.
The umbrella retrospectives page covering processes, editor, and AI drafting.
# Configuring Templates
Source: https://docs.rootly.com/retrospectives/configuring-templates
Create and manage retrospective templates in Rootly with dynamic content blocks and Liquid to pre-fill documents and apply the right template per incident.
## Overview
Retrospective templates let you define reusable document structures that Rootly pre-fills when a retrospective is created. Templates support Liquid for dynamic incident data, special embedded components for timelines and follow-up action items, and **AI blocks** that auto-draft narrative sections from incident context (see [Building AI Templates](/ai/ai-in-retrospectives/building-ai-templates)).
Templates are applied through retrospective workflows, which means you can use workflow conditions to select different templates based on incident properties such as severity, team, or incident type.
***
## AI Starter Templates
Rootly ships four curated, AI-powered starter templates on the **Document Templates** page. Pick a starter as the base for your team's default template — the AI general instructions are pre-tuned for each scenario so drafted sections match the voice and depth appropriate for that audience.
A balanced retrospective for most incidents. Tight, factual sections grounded in timeline and Slack discussion — a teammate can skim it in two minutes.
A detailed retrospective for high-severity incidents. Prioritizes completeness and causal depth over brevity — separates trigger, root cause, and contributing factors with evidence and timestamps.
A formal, blameless RCA ready to share externally. Free of internal jargon, code names, and individual names. Frames the resolution around the safeguards now in place.
A security-focused review. Leads with detection, scopes the exposure carefully, and treats containment and remediation as distinct phases with specifics on what was patched, rotated, or revoked.
Starter templates are a starting point, not a lock-in. Click **Use template** to create a new template pre-populated with the starter's structure and AI blocks — then edit, add, or remove sections to match your team's process.
***
## Create a Template
Go to **Retrospectives → Document Templates** and click **New Template**.
Give the template a descriptive name. Names must be unique within your team.
The display name for this template. Used when selecting a template in workflow actions and the retrospective editor.
Controls how template content is interpreted and rendered.
* **HTML** — for use with the Rootly rich-text retrospective editor and integrations that accept HTML (Confluence, Notion, Coda)
* **Markdown** — for integrations that render Markdown natively (GitHub, Linear, or custom pipelines)
Add structure, static text, Liquid variables, and dynamic blocks. See [Liquid in Templates](#liquid-in-templates) and [Dynamic Content Blocks](#dynamic-content-blocks) below.
Liquid syntax is validated when you save. If your template contains a Liquid error, Rootly will show the specific syntax error and prevent saving until it is fixed.
Marks this template as the default for the team. When a retrospective workflow action does not specify a template, the default template is used. Only one template can be the default at a time — enabling this on a new template automatically removes the default flag from the previous one.
Click **Save**. The template is immediately available for selection in workflow actions and the retrospective editor.
Every team must retain at least one template. Rootly prevents deletion of the last remaining template.
***
## Liquid in Templates
Templates support the full [Liquid](https://shopify.github.io/liquid/) templating language. Use `{{ variable }}` syntax to insert dynamic values and `{% %}` blocks for conditionals and loops.
All incident variables available in workflows are also available in templates. See [Incident Variables](/liquid/incident-variables) for the complete reference, or use the [Liquid Markup explorer](https://rootly.com/account/help/liquid-explorer) to browse variables interactively.
### Common patterns
**Pre-fill incident metadata**
```liquid theme={null}
# {{ incident.title }}
**Severity:** {{ incident.severity }}
**Status:** {{ incident.status }}
**Started:** {{ incident.started_at | date: "%B %d, %Y at %H:%M %Z" }}
**Resolved:** {{ incident.resolved_at | date: "%B %d, %Y at %H:%M %Z" }}
**Duration:** {{ incident.duration }}
```
**Conditional section by severity**
```liquid theme={null}
{% if incident.severity == "SEV1" or incident.severity == "SEV2" %}
## Executive Summary
This incident required escalation. Include a brief summary for leadership.
{% endif %}
```
**List responders**
```liquid theme={null}
## Response Team
{% if incident.commander %}
- **Incident Commander:** {{ incident.commander.name }}
{% endif %}
{% for responder in incident.responders %}
- {{ responder.name }}
{% endfor %}
```
**Fallback for optional fields**
```liquid theme={null}
**Jira ticket:** {{ incident.jira_issue_url | default: "None created" }}
```
Variables resolve to the value at the time the retrospective is generated. If incident data changes after the retrospective is published, the document retains the original resolved values.
***
## Dynamic Content Blocks
In addition to Liquid, templates can include special embedded components: **dynamic data blocks** that render live incident data, and **AI blocks** that draft narrative sections from incident context.
### Timeline block
Inserts the incident's full timeline into the retrospective. The timeline renders as an interactive component and respects the timeline display settings on the retrospective (ascending or descending order, starred-only filter).
To insert a timeline block, use the `/timeline` slash command in the retrospective editor when building the template.
### Follow-ups block
Inserts the incident's action items (follow-ups) as an interactive list. You can configure the sort order of the follow-ups block:
Controls the order in which follow-up action items appear in the rendered block.
* **due\_date** — sorted by due date, earliest first
* **status** — grouped by completion status
* **priority** — sorted by priority level
To insert a follow-ups block, use the `/followups` slash command in the retrospective editor when building the template.
Dynamic blocks are particularly useful in templates because they always reflect the current state of the incident at publish or export time, without requiring any Liquid logic.
### AI blocks
AI blocks are sections that Rootly drafts from the incident's data, Slack channel, and bridge-call transcripts when a retrospective is generated. Add them from the **AI Library** tab in the template builder. The preset blocks are **Summary**, **Impact**, **Root Cause**, **Mitigation**, **Resolution**, and **Curated Timeline**, plus a **Custom** block you define with your own prompt.
You can give each block custom instructions (or set template-level instructions for all of them), and preview the template against a real past incident before rolling it out. To skip the blank page entirely, start from one of the AI-powered **starter templates** on the Templates page.
See [Building AI Templates](/ai/ai-in-retrospectives/building-ai-templates) for the full guide.
***
## Apply Templates with Workflows
Templates are applied through **Retrospective workflows**. The workflow runs when a retrospective is created or updated and uses the **Create Incident Retrospective** or **Update Incident Retrospective** action to populate the document from a template.
### Basic setup
1. Go to **Workflows** and create or open a **Retrospective** workflow.
2. Set the trigger to **Retrospective Created**.
3. Add a **Create Incident Retrospective** action.
4. In the action, select the template to apply.
The initial retrospective is created when the incident is resolved, not when it is mitigated. A workflow triggered by **Retrospective Created** will run at resolution time.
### Conditional template selection
To apply different templates based on incident properties, create separate workflows with different run conditions — each pointing to a different template.
**Example: template per severity**
| Workflow | Run condition | Template |
| --------------------- | ---------------- | --------------------- |
| SEV1 retrospective | Severity is SEV1 | P1 deep-dive template |
| SEV2 retrospective | Severity is SEV2 | Standard template |
| Default retrospective | No conditions | Lightweight template |
Each workflow runs independently. The first whose run conditions match will apply its template. If you want exactly one template applied, ensure the conditions across workflows are mutually exclusive.
**Other useful condition fields:**
* **Team** — apply a team-specific template for teams with different retrospective processes
* **Incident type** — use a security-focused template for security incidents
* **Services** — apply a template tailored to a critical service
***
## Apply Templates Through Integrations
You can also use retrospective templates when pushing documentation to external tools. In the workflow action for the relevant integration, select a template to structure the generated document.
Supported integrations:
* [Confluence](/integrations/confluence/confluence)
* [Google Docs](/integrations/google-docs/overview)
* [Notion](/integrations/notion/overview)
* [Coda](/integrations/coda/coda)
***
## Default Template
One template can be marked as the default for the team. The default template is used when:
* A retrospective workflow action does not specify a template explicitly
* A user generates a retrospective from the UI without selecting a template
Only one template can be the default at a time. Setting a new default automatically clears the default flag from the previous one. If the default template is deleted, Rootly promotes the most recently updated remaining template to default.
***
## Frequently Asked Questions
A retrospective workflow with the **Retrospective Created** trigger runs when the incident is resolved. That is when the initial retrospective is created and the template is applied.
Yes. Create separate retrospective workflows with different run conditions — one per template. Use conditions on severity, team, incident type, or any other incident field to route each incident to the right template.
Rootly validates Liquid syntax when you save the template. If a syntax error is found, the save is blocked and the error message identifies the specific issue. Fix the syntax and save again.
Yes. Workflow actions for Confluence, Google Docs, Notion, and Coda support selecting a retrospective template to pre-fill the created document.
At least one. Rootly prevents deletion of the last remaining template for a team.
HTML and Markdown. Use HTML for the Rootly editor and most integrations. Use Markdown when your target integration renders Markdown natively or when you need plain-text portability.
***
## Related Pages
Let Rootly AI draft template sections from incident data — powered by AI blocks placed in templates.
Processes define the follow-up flow after an incident; retrospective workflows apply the template.
Configure the write-up step that renders the template into the finished retrospective document.
# Retrospectives
Source: https://docs.rootly.com/retrospectives/retrospectives
Right-size retrospective processes by severity, type, or team; auto-draft with Rootly AI; and drive follow-ups through configurable step-by-step processes.
Retrospectives are how teams learn from incidents. Rootly treats them as first-class incident artifacts, not a checkbox — every incident can trigger a **retrospective process** that lists the steps, owners, and deadlines that follow resolution.
Not every incident deserves the same process. Rootly lets you define multiple processes and route each incident to the right one based on severity, type, or team, so a SEV0 gets full formal treatment while a SEV3 gets a lightweight review.
Rootly ships with a **Default Retrospective Process** that runs on any incident not matched by a custom process. New workspaces can rely on it out of the box.
***
## In This Section
Trigger retrospective creation, reminders, and document generation automatically.
Create, condition, and reorder processes under **Configuration → Retrospectives**.
Step attributes, phases with Custom Statuses, and reminder configuration.
Reusable document structures — plain sections, Liquid variables, AI blocks, and the AI Starter Templates gallery.
Auto-draft Summary, Impact, Root Cause, Mitigation, Resolution, and Timeline sections with Rootly AI.
***
## Draft Retrospectives with Rootly AI
The heaviest lift in most retrospectives is the writing itself. **Rootly AI in Retrospectives** takes on the blank-page problem: sections like Summary, Impact, Root Cause, Mitigation, Resolution, and Curated Timeline get drafted automatically from the incident's data, Slack channel, and bridge-call transcripts. Owners edit, regenerate, or convert to plain text — nothing is frozen.
Most teams see the biggest lift from adding an AI-powered starter template to their default process. See [Building AI Templates](/ai/ai-in-retrospectives/building-ai-templates) for the four starter templates that ship with Rootly.
***
## How It Works, Briefly
A retrospective process is a named, ordered set of steps Rootly creates on an incident after resolution. When an incident is created or updated, Rootly evaluates the conditions on each process, picks the one that matches, and creates the process on the incident.
Retrospectives can be **mandatory**, **auto-skipped**, or **optional** based on incident context — configured separately from the process itself under **Retrospectives → Preferences**.
For the full picture, see [configuring processes](/retrospectives/configuring-retrospective-processes) for routing and preferences, [configuring process steps](/retrospectives/configuring-process-steps) for step attributes and phases, and [incident variables](/liquid/incident-variables) for the retrospective variables.
***
## Best Practices
* **Start with the default process.** Fastest way to see the flow end-to-end. Add custom processes only when a specific severity or team needs something different.
* **Add AI blocks to the template your default process uses.** Even one Summary block cuts retrospective time noticeably.
* **Assign by role, not by user.** A step assigned to "Commander" auto-routes to whoever ran the incident. Named-user assignments go stale.
* **Reserve required steps for the outputs that actually block the process from closing.** Retros with too many mandatory steps get abandoned.
* **Audit process conditions quarterly.** Severity definitions and team boundaries drift.
***
## Frequently Asked Questions
Rootly creates the retrospective when the incident is resolved. From that point, `Retrospective Created` and `Retrospective Updated` workflow triggers fire on lifecycle events.
On resolution, Rootly evaluates each process's conditions. All matching processes are candidates; if more than one matches, the most recently created wins. If none match, the Default Retrospective Process runs. Full match logic is in [configuring processes](/retrospectives/configuring-retrospective-processes#how-process-selection-works).
Yes — the mechanism is separate from the process. Whether a retrospective is **mandatory**, **auto-skipped**, or **optional** is configured under **Retrospectives → Preferences** with its own conditions on severity, type, or team.
Retrospective **processes** (this section) define *when and how* to run a retrospective — steps, owners, deadlines, routing. **[Collaborative Retrospectives](/collaborative-retrospectives/overview)** is the editor experience for the retrospective *document*: real-time co-authoring, comments, exports, Liquid variables.
Rootly renamed *Postmortem* to *Retrospective*. Older workflows, integrations, and Liquid variables that use `postmortem_*` continue to resolve — see [incident variables](/liquid/incident-variables) on the Reference page.
***
## Related Pages
Let Rootly AI draft retrospective sections directly inside your templates.
The document editor experience — real-time co-authoring, comments, exports, Liquid variables.
Automate retrospective creation, notifications, and external document generation.
Standardize retrospective structure with reusable templates that pull in Liquid variables.
Follow-ups created from a retrospective — track, assign, and close them.
Liquid variables for referencing the retrospective from workflows and templates.
# Signing Up
Source: https://docs.rootly.com/signing-up
Create a Rootly account or accept an invitation from your organization to get started with incident management, on-call scheduling, and integrations.
To start using Rootly, create an account or accept the invitation your organization sent you.
You can sign up with:
* Google
* Slack
* SSO
* Email and password
If your company has already invited you to Rootly, use the link in that invitation email to join your organization.
If your email domain is configured for SSO, Rootly will redirect you to your organization’s sign-in page instead of showing the standard sign-up flow.
## Sign Up with Email and Password
If you choose to create an account with email and password, enter your details and create a password that meets Rootly’s requirements.
Passwords must be at least **10 characters** and include:
* One lowercase letter
* One uppercase letter
* One digit
* One special character
Then:
1. Check the box to accept the [**Terms of Service**](https://rootly.com/terms) and [**Privacy Policy**](https://rootly.com/privacy)
2. Click **Sign Up**
## Already Invited?
If your company sent you an invitation, open the email and follow the link to complete setup. Depending on your organization’s configuration, you may finish joining with Google, Slack, SSO, or by creating a password.
## Already Have an Account?
If you already have a Rootly account, use **Sign in** instead of creating a new one.
Once you finish signing up, you’re ready to start using Rootly.
***
## Related Pages
Connect Rootly to Slack so responders can declare and run incidents from the channels they already use.
Connect Rootly to Microsoft Teams for chat-based incident response.
Finish onboarding — link contact methods, verify email and phone, and connect Slack.
# Opsgenie Migration
Source: https://docs.rootly.com/switch/opsgenie-migration
Migrate users, schedules, teams, services, routing rules, and notification settings from Opsgenie to Rootly On-Call with a Rootly-led, API-based import.
## Overview
Migrating from Opsgenie to Rootly On-Call is a **Rootly-led, API-driven import process** that recreates your on-call configuration in Rootly so you can cut over with confidence. The migration is designed to preserve the operational structure your responders rely on—who is on call, how rotations work, how overrides are applied, and how responders are notified—while also applying Rootly’s guardrails to keep the resulting configuration safe and maintainable.
A typical migration has two goals:
1. **Parity at cutover:** responders can acknowledge and resolve alerts in Rootly with familiar routing and escalation behavior.
2. **Clean operational ownership:** once you cut over, schedules, routing rules, and responder preferences in Rootly become your new source of truth going forward.
Rootly migrations are performed using **read-only Opsgenie API access**, meaning Rootly does not modify or delete any resources in Opsgenie. Your Opsgenie instance remains intact and can be kept running in parallel during a transition window if you want an added safety net.
To get started, simply **contact Rootly**. Your onboarding or customer success representative will walk you through scope, timing, and required access, then coordinate and execute the migration for you.
## What You Can Migrate
Rootly can migrate the core building blocks of Opsgenie on-call operations. Each section below explains what is migrated, how Rootly maps it, and where you should expect differences.
### Users
Rootly imports users in a way that prioritizes safe, deterministic matching and produces a usable on-call configuration immediately.
#### How users are matched
* Rootly matches Opsgenie users to Rootly users using the Opsgenie user `username`, which is treated as the user’s **email address**.
* If a Rootly user already exists with that email (including soft-deleted users), Rootly reuses that user rather than creating a duplicate.
* If no Rootly user exists for that email, Rootly creates a new Rootly user automatically and populates the email and name fields from Opsgenie.
#### User profile and time zone normalization
* Rootly imports the user’s name from Opsgenie (for example, `full_name`) and applies a normalized time zone value when available.
* If a user’s time zone in Opsgenie is empty or does not map cleanly, Rootly will fall back to your workspace defaults. Time zones primarily affect how times are displayed (and certain time-based features), not the underlying schedule logic.
#### Membership and on-call access
* Imported users are added to the target Rootly team/workspace.
* If your workspace uses on-call seat limits, users without an available on-call seat cannot be placed into rotations until seats are available. This is an operational constraint rather than a migration failure; it simply means you may need to assign seats before final cutover.
#### Contact methods and notification rules
Opsgenie user notification behavior is represented as **notification rule steps**, and Rootly translates those steps into Rootly’s notification rules:
* Opsgenie contact method `email` maps to Rootly email targets.
* Opsgenie contact method `sms` maps to Rootly SMS targets.
* Opsgenie contact method `voice` maps to Rootly call targets.
* The Opsgenie delay per step (for example, `sendAfter.timeAmount`) maps to the Rootly rule delay so responders are notified at the intended time offset.
Imported contact targets are created as verified targets during migration so that the resulting notification rules are immediately usable. After migration, responders can review and update their targets and preferences in Rootly (for example, changing their primary number or adding a mobile device for push notifications).
#### Default rule seeding (safety baseline)
After importing a user’s Opsgenie-derived rules, Rootly will seed any missing default Rootly notification rules that are required to give responders a safe baseline configuration. This ensures that users do not end up with a partially configured state if Opsgenie rules were missing, sparse, or not fully mappable.
### Teams and Routing
Opsgenie team structure typically represents operational ownership and routing boundaries. Rootly can import this structure into Rootly’s grouping model and import routing rules when present.
#### Teams to groups
* Opsgenie teams are imported as Rootly groups (teams/groups in Rootly terminology), allowing you to preserve ownership and organize responders in Rootly the same way they are organized in Opsgenie.
* Group membership and the imported users are aligned so schedules and routing rules can reference the correct owners.
#### Routing rules
* If your Opsgenie setup includes team routing logic, Rootly imports the team’s routing rules so that inbound alert flows can preserve the same “where should this go?” behavior.
* Routing rule import is handled as part of the team import stage so that teams exist before schedules and downstream references are created.
#### Slack integration import (optional, conditional)
Slack-related migration is supported only when all of the following are true:
* You choose to include `slack_integrations` in the migration scope.
* Your Rootly team has a connected Slack integration.
* You include one or more Opsgenie team IDs so Rootly knows which teams should have Slack integration configuration imported.
If those prerequisites are not met, Slack integration import is skipped. This prevents partially configured Slack behavior and keeps the resulting Rootly configuration deterministic.
### Services (Optional)
If you want Rootly to preserve Opsgenie service structure, Rootly can import Opsgenie services into Rootly services.
#### Service matching and name behavior
* Rootly attempts to match a service by Opsgenie service ID first.
* If no match exists by ID, Rootly attempts to match by name.
* If a name collision exists (for example, a different service already uses that name), Rootly may uniquify the imported service name by appending the Opsgenie service ID so you can distinguish them cleanly.
Imported services can then be used in analytics, ownership, and downstream routing/alerting workflows in Rootly.
### Schedules
Schedules are one of the most sensitive parts of an on-call migration because they affect real paging behavior. Rootly migrates schedules with the goal of preserving rotation logic and ensuring future coverage is computed correctly.
#### What schedule data is migrated
* Schedule definitions (name, ownership context)
* Rotations (including rotation rules)
* Overrides (coverage changes applied over time)
* Future shift generation derived from the imported rotation configuration
#### Overlapping rotations and schedule strategy
Opsgenie schedules can contain rotation patterns that overlap in ways that are difficult to represent cleanly as a single schedule in some systems. Rootly supports two strategies:
* **Single schedule strategy:** rotations are imported into one Rootly schedule, and overrides are created from Opsgenie schedule overrides.
* **Split rotations into separate schedules:** when enabled (`import_rotations_as_separate_schedules`), Rootly detects overlapping rotations and creates **one Rootly schedule per rotation**. This can make the resulting schedules easier to reason about and reduces ambiguity in overlap resolution.
The best choice depends on how your Opsgenie schedules are structured and how you expect schedule ownership to work after cutover. Rootly will recommend an approach during scoping if your environment has overlap-heavy schedules.
#### Syncing schedules vs. create-only schedules
Rootly can run an Opsgenie migration in either of these modes:
* **Create-only import:** recommended for clean cutovers or staged testing. Rootly creates new schedules without attempting to reconcile with existing Rootly schedules.
* **Sync existing:** recommended when you have already created Rootly resources and want the migration to update them. In sync mode, Rootly may remove and rebuild base (non-override) shifts and clean up removed overrides to maintain parity with the Opsgenie source.
Because sync mode can rebuild future shifts, it is typically used deliberately and validated carefully in a controlled window.
#### Shift recreation and throttling
When syncing schedules, Rootly can introduce a configurable delay before recreating shifts (`schedule_shift_recreation_delay`). This is a practical safety mechanism to avoid partial computations in environments with many schedules or heavy background job load.
Rootly can also throttle schedule imports (`schedule_import_delay`) to keep the migration stable and predictable for larger workspaces.
## Configuration Options You May Be Asked To Choose
Opsgenie migrations often include a few explicit choices so the resulting Rootly configuration matches your operational intent.
Common migration options include:
* **Migration scope controls (resources):**
* `users`
* `teams`
* `schedules`
* `services`
* `slack_integrations`
* **Filtering and inclusion controls:**
* Migrate only specific Opsgenie teams (`team_ids`)
* Exclude specific Opsgenie teams (`excluded_team_ids`)
* Migrate only a subset of users by email (`user_emails`)
* **Schedule behavior:**
* Import overlapping rotations as separate schedules (`import_rotations_as_separate_schedules`)
* Synchronize into existing Rootly resources (`sync_existing`)
* Add delays for stability (`schedule_import_delay`, `schedule_shift_recreation_delay`)
* **Responder hygiene:**
* Disable shift reminders for imported users (`disable_shift_reminders`)
* **Dry run mode:**
* Validate and produce a report of what would be imported (including validation errors) without writing resources into Rootly (`dry_run`)
If you are unsure which options to select, a strong default is to begin with a dry run, then perform a create-only migration into a staging workspace (or a safe test team) before importing into production.
## Migration Process
### Step 1: Define scope and success criteria
Before any technical setup, define what “success” means for your organization. This reduces rework and prevents ambiguous expectations.
Recommended scoping questions:
* Are you migrating one Opsgenie team or many?
* Are you importing only schedules, or also services and routing rules?
* Do you need Slack integration behavior imported, or will it be reconfigured natively in Rootly?
* Do you need to preserve existing Rootly schedules (sync), or can this be a clean import?
Example success criteria:
* Every responder can be paged in Rootly via at least one reliable channel.
* Each core schedule generates correct upcoming shifts for the next 2–4 weeks.
* Critical services and teams have the correct ownership structure and routing.
* Overrides and coverage changes are represented correctly for upcoming time windows.
### Step 2: Create a read-only Opsgenie API key
Rootly migrations use the Opsgenie API to read configuration.
In Opsgenie:
1. Navigate to **Settings → App Settings → API key management**
2. Click **Add new API key**
3. Name the key clearly (example: “Rootly Migration – Read Only”)
4. Assign **Read** permissions for the relevant resources (users, teams, schedules, services as needed)
5. Copy the key securely and share it with the Rootly team using your approved secure channel
Use read-only permissions. Rootly does not need write access to Opsgenie to perform migration.
### Step 3: Run a dry run (strongly recommended)
A dry run validates what Rootly can import and highlights any resources that will be skipped or require attention. This is especially valuable if your Opsgenie environment contains complex schedule overlap patterns or historical artifacts that are no longer actively used.
Dry runs typically surface:
* Users that cannot be matched cleanly (missing/invalid emails)
* Schedules that require a split-rotation strategy to preserve clarity
* Validation errors that would prevent import
* A summary report you can use to confirm the migration plan before anything is written
### Step 4: Execute the migration
After dry run validation, Rootly runs the migration asynchronously. Imports are staged so dependencies resolve correctly and scheduling logic remains stable.
At a high level, a migration commonly progresses through:
* Users and services
* Teams (and routing rules)
* Schedules (rotations, overrides, then shift generation)
* Slack integrations (only when configured and included)
Because the migration runs in the background, you can continue normal work while it completes, and then validate the results after completion.
### Step 5: Validate in Rootly before cutover
After import, treat validation as an explicit step. You should validate configuration correctness and real paging behavior.
Recommended validation checklist:
* Confirm each core schedule shows a correct “currently on-call” responder and upcoming shifts.
* Confirm rotation structure matches expected handoffs and time zones.
* Confirm overrides appear where you expect them for upcoming windows.
* Confirm a sample of responders have correct notification rules and reachable targets.
* Confirm team/group membership matches expectations and routing rules are present if imported.
* If Slack integration behavior matters, validate it only after Slack is fully connected in Rootly and `slack_integrations` was included in scope.
### Step 6: Cut over and monitor
When you are ready, shift your alert sources to route into Rootly On-Call, then actively monitor the first hours/days of production usage.
The most common cutover issues are not schedule logic problems—they are responder readiness and deliverability issues (for example, responders missing a mobile device connection or carriers filtering SMS). Validate reachable channels proactively.
## Best Practices
* **Start with a dry run.** Dry runs catch schedule edge cases early, when changes are easiest.
* **Decide schedule strategy up front.** If your Opsgenie schedules rely on overlapping rotations, consider splitting rotations into separate schedules for clarity.
* **Migrate in a controlled window.** Even without downtime, you want time reserved for validation and quick fixes.
* **Validate paging with real tests.** It’s not enough for rules to exist; verify a handful of responders can actually receive notifications via the channels you rely on.
* **Plan a staged cutover.** Many organizations keep Opsgenie running briefly while validating Rootly paging reliability, then fully cut over.
* **Communicate responder expectations early.** Tell responders what to install, what to verify, and what to expect during the transition.
* **Document any skipped or excluded resources.** If you exclude teams or only migrate specific users, keep a written record so the end state remains intentional.
## Frequently Asked Questions
No. Rootly migrations use read-only Opsgenie API access. Rootly reads your Opsgenie configuration and recreates equivalent resources in Rootly, but does not write back to Opsgenie or delete anything in your Opsgenie account.
Users are matched by email address. Opsgenie’s user username is treated as the user’s email. If a Rootly user exists with the same email (including soft-deleted users), Rootly reuses that user. If no match exists, Rootly creates a new Rootly user and adds them to the team so schedules and routing can reference them.
Opsgenie notification rule steps are translated into Rootly notification rules. The Opsgenie contact method (email, sms, voice) maps to Rootly’s email, SMS, and call targets. The step delay (sendAfter.timeAmount) maps to the Rootly rule delay so the timing behavior stays consistent.
Rootly can import schedules in one of two ways. By default, rotations are imported into a single Rootly schedule and overrides are recreated. If your environment has overlapping rotations and you enable import\_rotations\_as\_separate\_schedules, Rootly can split rotations into separate Rootly schedules to keep overlap behavior clearer and reduce ambiguity.
Yes. The migration supports scope controls such as importing only specific team IDs, excluding specific team IDs, or limiting users by email address. This is useful for phased migrations where you transition one department or service group at a time.
Slack integrations are imported only when you include slack\_integrations in migration scope and your Rootly workspace has a connected Slack integration. If those prerequisites are not met, Slack import is skipped to prevent partial or misleading configuration.
Contact your Rootly onboarding representative or Rootly Support. Share the relevant Opsgenie resource identifiers (team IDs, schedule IDs, service IDs) and a short description of what doesn’t match expectations so the Rootly team can diagnose quickly.
***
Need help planning or executing a migration? Contact your Rootly onboarding representative or email **[support@rootly.com](mailto:support@rootly.com)**.
***
## Related Pages
The umbrella page — how Rootly-led migrations work regardless of the source tool.
The parallel migration path — schedules, escalation policies, and integrations from PagerDuty.
Where your migrated schedules and escalation policies land in Rootly.
# Migrating From PagerDuty
Source: https://docs.rootly.com/switch/pagerduty-migration
Migrate from PagerDuty to Rootly On-Call: concept mapping, what gets imported, timeline, parallel-running patterns, and cutover validation steps.
## Overview
Migrating from PagerDuty to Rootly On-Call is an API-driven import process that recreates your paging configuration in Rootly so you can cut over with confidence. The migration is designed to preserve the structure your responders rely on—who is on-call, how alerts escalate, and how responders are notified—while also applying Rootly's operational guardrails (for example, preventing schedule dependency loops and ensuring notification rules remain actionable).
A typical migration has two goals:
1. **Parity at cutover:** responders can acknowledge and resolve alerts in Rootly with familiar routing and escalation behavior.
2. **Clean operational ownership:** once you cut over, schedules and escalation policies in Rootly become your new source of truth going forward.
Rootly migrations are performed using **read-only PagerDuty API access**, meaning Rootly does not modify or delete any resources in PagerDuty. Your PagerDuty instance remains intact and can be kept running in parallel during a transition window if you want an added safety net.
To get started, **contact Rootly**. Your onboarding or customer success representative will walk you through scope, timing, and required access, then coordinate and execute the migration for you.
***
## How PagerDuty Concepts Map To Rootly
This table answers two distinct questions at once:
* **Does Rootly have an equivalent concept for this PagerDuty resource?** — the Rootly column.
* **Will the on-call migration import this for me, or do I configure it natively in Rootly?** — the **Imported by migration?** column.
Most paging primitives are imported automatically; most everything else has a Rootly equivalent that you set up natively. For full import scope and the exhaustive out-of-scope list, see [What You Can Migrate](#what-you-can-migrate) and [What's Not Migrated](#whats-not-migrated) below.
| PagerDuty | Rootly | Imported by migration? | Notes |
| ------------------------------------ | -------------------------------------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------- |
| Service | [Service](/configuration/services) | ✓ Optional | Included when service import is enabled |
| Team | [Team](/managing-teams/managing-teams) | ✓ Optional | Included when team import is enabled. API/Liquid refers to this as `group` |
| Escalation Policy | [Escalation Policy](/on-call/escalation-policies) | ✓ | 1:1 — Rootly optionally creates separate quiet and audible paths to mirror PagerDuty urgency behavior |
| Schedule | [Schedule](/on-call/schedules) | ✓ | Rotation members can be users or other schedules (nested), not teams directly |
| Rotation | Rotation inside a Schedule | ✓ | Multiple rotations per schedule supported; bottom-most wins on overlap |
| Override | [Override](/on-call/edit-schedules) | ✓ | Per-shift, individual-user only |
| User | [User](/managing-users/managing-users) | ✓ | Matched by email; pre-existing users (including soft-deleted) are reused |
| Contact method (email / SMS / phone) | Contact method | ✓ | + critical mobile push (bypasses DND) and non-critical mobile push (respects DND) |
| Notification rule | [Notification rule](/on-call/on-call-notifications) | ✓ | Mapped where compatible; unmappable rules are skipped rather than partially imported |
| Urgency (low) | Quiet notification rule | ✓ | |
| Urgency (high) | Audible notification rule | ✓ | |
| Incident | [Incident](/incidents/incidents) | — | Rootly starts fresh on cutover; historical incidents stay in PagerDuty |
| Alert | [Alert](/alerts/alerts) | — | Set up alert sources in Rootly natively |
| Event rule | [Alert routing rule](/alerts/alert-routing) | — | Recreate in Rootly's alert routing UI |
| Stakeholder | [Subscriber](/configuration/status-pages) | — | Configure in Rootly status pages or per-incident subscriber lists |
| Maintenance window | [Scheduled Maintenance Incident](/incidents/incident-operations/scheduling-a-maintenance-incident) | — | Rebuild as scheduled maintenance incidents in Rootly |
| Postmortem | [Retrospective](/collaborative-retrospectives/overview) | — | New retrospectives are authored in Rootly going forward |
| Runbook / Response Play | [Workflow](/workflows/workflows) / [Playbook](/configuration/playbooks) | — | Workflows replace the automation side; playbooks replace the documented procedure side |
| Priority | [Severity](/configuration/severities) | — | Configure Rootly severities to match your PagerDuty priority model |
| Custom field | [Custom field](/configuration/custom-fields) | — | Definitions can be recreated in Rootly; historical incident values stay in PagerDuty |
| Outbound webhook | [Outgoing Webhook](/configuration/webhooks) | — | Reconfigure outbound destinations against Rootly's webhook events |
| Round robin | [Round robin paging](/on-call/round-robin-functionality) | — | Rootly-only configuration applied on top of escalation policy levels after migration |
If a PagerDuty concept you depend on isn't in this table, ask your Rootly onboarding rep — many edge cases are supported but not always under the same name.
***
## What You Can Migrate
Rootly can migrate the core building blocks of on-call operations. Each section below explains what is migrated, how Rootly maps it, and where you should expect differences.
### Users
Rootly imports users in a way that prioritizes safe, deterministic matching.
**How users are matched**
* Rootly matches PagerDuty users to Rootly users using **email address**.
* If a Rootly user with that email already exists (including soft-deleted users), Rootly will reuse that user rather than creating a duplicate.
* If no Rootly user exists for the email, Rootly creates a new Rootly user automatically.
**Team membership and on-call access**
* Imported users are added to the target Rootly Team.
* Your Team's defaults (and any relevant workspace configuration) may apply to newly created memberships, including default on-call role assignment.
* If your workspace uses on-call seat limits, users without an available on-call seat cannot be added into schedule rotations until seats are available.
**Contact methods that are migrated**
Rootly migrates user contact information used for paging, including:
* Email address(es)
* SMS-capable phone number(s)
* Call-capable phone number(s)
**How notification rules are migrated**
PagerDuty notification rules are translated to Rootly’s notification rule model where compatible:
* PagerDuty **urgency = low** maps to Rootly **quiet** notification rules.
* PagerDuty **urgency ≠ low** maps to Rootly **audible** notification rules.
* PagerDuty notification start delays map to Rootly rule delays when possible.
* Contact method types are mapped into Rootly’s supported contact methods, which include:
* Email
* SMS
* Phone call
* Critical mobile push (bypasses device Do Not Disturb when configured)
* Non-critical mobile push (respects device Do Not Disturb when configured)
**What happens when a rule cannot be mapped**
* If a PagerDuty rule uses a configuration that does not translate cleanly, Rootly skips that rule rather than importing a partial or misleading configuration.
* After import, Rootly can also seed defaults (if needed) so every responder has a safe baseline configuration (for example, an email-based quiet rule).
**Important behavioral expectations**
* Rootly enforces practical paging constraints in the UI for audible notification rules. For example, initial audible steps typically must include an immediately actionable path (critical push or call) so responders cannot accidentally configure an audible chain that can never reach them.
* Where your PagerDuty rules include escalations or multi-step paging, validate your Rootly notification rules post-import to ensure the “audible” versus “quiet” intent matches your team’s reality.
### Schedules
Rootly imports schedules with the intent of preserving rotation logic and future coverage.
**What schedule data is migrated**
* Schedule definitions (name, description where applicable)
* Rotations and rotation membership
* Overrides
* Shift generation behavior (Rootly will generate future shifts based on imported rotation configuration)
**Supported schedule membership types**
Rootly schedules support rotation members that are:
* Individual users
* Other schedules (nested schedules), with safeguards to prevent circular dependencies
If your PagerDuty design effectively represents a team as a “target,” Rootly typically models that as a schedule rather than embedding a “team” directly inside a schedule rotation.
**Schedule validation and skip behavior**
Some schedules may be intentionally skipped for safety or compatibility. A notable case:
* Schedules with rotation turn lengths shorter than **24 hours** may be skipped during migration.
If schedules are skipped, the migration should record them as skipped resources so you can review and decide whether to recreate them manually using Rootly-native patterns.
**Syncing schedules vs. creating schedules**
Depending on migration settings:
* You can import schedules into a clean workspace (create-only), or
* You can **synchronize** against existing Rootly schedules (sync mode). In sync mode, Rootly may rebuild base shifts and clean up removed overrides to match the source.
Because schedule sync can rebuild future shifts, migrations often support a configurable delay between shift recreation steps to prevent racing or partial computations.
### Escalation Policies
Escalation policies are imported to preserve “who is notified, when, and in what order.”
**What escalation policy data is migrated**
* Escalation policy definitions and levels
* Targets within each level (where compatible)
* Ordering and delays
**Audible vs. quiet escalation paths**
Rootly can optionally create separate escalation paths to mirror PagerDuty urgency behavior, such as:
* A quiet path designed for low urgency routing
* An audible path designed for urgent paging
Whether you enable this depends on how strictly you separate low urgency vs. high urgency in your operational model.
**Target types you can expect**
Escalation levels in Rootly can target combinations of:
* Users
* Schedules
* Teams
* Slack channels
* Services (depending on configuration)
Rootly also supports paging strategies and targeting modes (including round robin strategies) that you can layer on top after migration if you want more control than your original PagerDuty setup provided.
### Services and Teams (Optional)
Depending on migration settings, Rootly can also import:
* PagerDuty teams into Rootly Teams
* PagerDuty services into Rootly services
If enabled, Rootly can optionally set owning Teams for services to preserve operational ownership and improve reporting and routing downstream.
***
## What's Not Migrated
The on-call import covers paging configuration — users, schedules, escalation policies, and optionally services and teams. Everything below is **out of scope** and either has to be reconfigured natively in Rootly or migrated by a separate process. Knowing this list upfront prevents the "I assumed X would come over" surprise during cutover.
| PagerDuty resource | Why it's out of scope |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| Active incidents | Incidents in flight at migration time stay in PagerDuty. Rootly starts fresh on cutover. |
| Historical incidents and timelines | Past incident records, postmortems, and timeline events are not pulled. Export from PagerDuty if you need archival. |
| Event rules / event orchestrations | Handled by a separate migration path. Discuss with your onboarding rep if you depend on these. |
| Maintenance windows | Recreate as [Scheduled Maintenance Incidents](/incidents/incident-operations/scheduling-a-maintenance-incident) in Rootly. |
| Response Plays / Runbooks | Rebuild as [Workflows](/workflows/workflows) or [Playbooks](/configuration/playbooks). |
| Stakeholder subscribers | Reconfigure in Rootly's [status pages](/configuration/status-pages) or per-incident subscriber lists. |
| Status pages | Set up natively in Rootly. The page model differs in ways that don't translate cleanly. |
| Custom fields and their incident values | Custom field definitions can be recreated in [Configuration → Custom Fields](/configuration/custom-fields); historical values stay in PagerDuty. |
| AIOps content (intelligent alert grouping, dynamic notifications) | Rebuild using Rootly's [alert grouping](/alerts/alert-grouping) and [alert routing](/alerts/alert-routing) primitives. |
| Integration credentials (for example, Datadog → PagerDuty webhook secrets) | Reconfigure the sending tool to point at Rootly's webhook URL with the Rootly-issued secret. |
| User mobile app installs and verified contact methods | Each responder installs the [Rootly mobile app](/on-call/mobile-app) and verifies their own phone/email after import. |
If something you depend on isn't listed, flag it to your onboarding rep during scope review — many edge cases are handled but not always under the same name.
***
## Configuration Options You May Be Asked To Choose
PagerDuty migrations often include a small number of explicit choices so the resulting Rootly configuration matches your intent.
Common migration options include:
* **PagerDuty region:** US or EU
* **Import scope controls:**
* Import all escalation policies, or only specific escalation policy IDs
* Exclude certain schedule IDs
* Import all users, or restrict to users referenced by migrated schedules/policies
* **Resource strategy:**
* Create-only import
* Synchronize existing Rootly resources
* **Escalation policy behavior:**
* Create separate quiet and audible escalation paths
* **Operational hygiene options:**
* Disable shift reminders for imported users (helpful if you want responders to opt in later)
* **Timing controls:**
* Delay between escalation policy imports and schedule imports
* Delay before schedule shift recreation in sync mode
* **Dry run mode:**
* Validate and produce a report of what would be imported (including validation errors) without writing resources into Rootly
If you are unsure which options to select, a good default is to start with a dry run, then run a create-only import into a staging workspace (or a safe test team) before importing into production.
***
## Typical Timeline
Most PagerDuty migrations land inside a **2–4 week window** from kickoff to full cutover. The actual import is fast — the time goes into scoping, dry-run review, and the parallel-validation period.
Onboarding rep walks through your PagerDuty footprint with you. Outcome: agreed scope (which teams, what to include, whether services and teams are imported), success criteria, and a target cutover date.
You generate the read-only PagerDuty API key and share it through your approved secure channel. The key is stored encrypted by Rootly and used only for the migration window.
Rootly runs a dry-run import that validates the full set of resources and produces a report listing what would be imported and what would be skipped (with reasons). You review the report with your onboarding rep and resolve any cleanup items in PagerDuty before the real import.
The actual write phase. Most imports complete in under an hour; very large environments can take several hours. The import runs in the background — your team continues normal operations while it runs.
PagerDuty stays primary. Rootly is configured but not routed to from production alert sources yet. Responders verify their notification rules, install the mobile app, and confirm test pages. See [Running PagerDuty And Rootly In Parallel](#running-pagerduty-and-rootly-in-parallel) below.
Flip alert sources to Rootly during a low-traffic window. Monitor the first hours and days actively. Most teams keep PagerDuty available (un-routed but configured) for 1–2 weeks as an explicit fallback before fully decommissioning.
Smaller environments (one or two teams, no services/teams import) can compress this to roughly a week. Larger or more complex environments — many policies with custom urgency rules, heavy parallel validation, multi-region cutover — typically take the full 4 weeks.
***
## Migration Process
### Step 1: Define Scope and Success Criteria
Before any technical setup, define what “success” means for your organization. This reduces rework and prevents ambiguous expectations.
Recommended scoping questions:
* Are you migrating one team or multiple teams?
* Are you migrating only schedules and escalation policies, or also services and teams?
* Do you need parity for low-urgency workflows (quiet routing), or only urgent paging?
* Do you need to preserve existing Rootly resources, or can this be a clean import?
Common “success criteria” examples:
* Every responder can be paged in Rootly via at least one reliable channel.
* Every critical service has an escalation policy attached and can page an on-call responder.
* The most important schedules generate correct upcoming shifts for the next 2–4 weeks.
* Escalation policies correctly notify schedules/users in the intended order with expected delays.
### Step 2: Create a Read-Only PagerDuty API Key
Rootly migrations use the PagerDuty API to read configuration.
In PagerDuty:
1. Navigate to **Integrations → Developer Tools → API Access Keys**
2. Create a new API key
3. Name the key clearly (example: “Rootly Migration – Read Only”)
4. Ensure the key is **read-only**
5. Copy the key securely and share it with the Rootly onboarding team using your approved secure channel
Use a read-only key. Rootly does not need write access to PagerDuty to perform migration.
### Step 3: Run a Dry Run (Strongly Recommended)
A dry run validates what Rootly can import and highlights any resources that will be skipped or require attention. This is especially valuable if your PagerDuty instance contains edge cases (complex layers, unusual rotation lengths, legacy artifacts).
A dry run typically surfaces:
* Users that cannot be matched cleanly (missing emails, invalid data)
* Schedules that will be skipped (for example, short turn lengths)
* Policies that reference unsupported patterns
* Any validation errors that would prevent import
If you are migrating a large environment, a dry run is the safest way to avoid surprises.
### Step 4: Execute the Migration
After dry run validation, Rootly runs the migration asynchronously. Imports are typically staged so dependencies resolve correctly (for example, users exist before schedules reference them).
At a high level, a migration commonly progresses through:
* Users (and optional Teams)
* Services (optional)
* Schedules (and overrides, then shift generation)
* Escalation policies
Because the migration runs in the background, you can continue normal work while it completes, and then validate the results after completion.
### Step 5: Validate in Rootly Before Cutover
After import, treat validation as an explicit step—not an afterthought. You should validate both configuration correctness and real paging behavior before you flip any alert sources.
The [On-Call Readiness](/on-call/on-call-readiness) report in Rootly is your fastest path to a tenant-wide view of paging readiness — it surfaces missing escalation policy attachments, unverified contact methods, and responders not installed on the mobile app in one place. Use it as the dashboard you walk through before sign-off.
**Schedules**
* Each core schedule shows the correct "currently on-call" responder and the next 2–4 weeks of upcoming shifts.
* Overrides imported from PagerDuty are visible on the [On-Call Shifts page](/on-call/on-call-shifts) and labeled correctly.
* No schedules show a [Gaps Detected badge](/on-call/schedules#coverage-gaps-and-fallback) unexpectedly (or, if they do, the Schedule Owner fallback is intentional).
* Nested schedules (schedules used as rotation members in other schedules) resolve to the correct on-call user.
**Escalation Policies**
* Each escalation policy references the intended schedules, users, or targets at each level.
* Level delays match what PagerDuty had (or the agreed-upon override).
* If you opted into separate quiet/audible paths, both are present and target the right groups.
**Users And Notification Rules**
* Every responder has at least one **audible** notification rule that reaches them within the expected delay.
* Phone numbers are verified (a phone number on the user record without verification will not receive SMS or calls).
* Responders intended for low-urgency routing have **quiet** rules configured.
* Sample 3–5 responders across teams and confirm their per-user notification rule chain matches expectations.
**Mobile App Readiness**
* Responders intended to receive critical mobile push have the [mobile app](/on-call/mobile-app) installed and logged in.
* Critical push permissions are granted (the mobile app prompts for this — verify it was accepted, not deferred).
**Routing And Services**
* Test alert sources route into Rootly's [Alerts page](/alerts/alerts) without errors.
* For each critical service, confirm the alert routing rule maps to the correct escalation policy.
**Real-Paging Validation**
* Send a test notification from at least one schedule per team. Confirm the on-call user receives it on every channel they're configured for (push, SMS, call, email).
* For services with the highest production importance, simulate a real alert (using the source tool's test webhook) and confirm the page reaches the on-call responder end-to-end.
**Skipped Resources**
* Review the dry-run report's skipped resources list. For each: decide whether to recreate manually in Rootly using a native pattern, or accept that it stays in PagerDuty until decommissioned.
### Step 6: Cut Over and Monitor
When you are ready, shift your alert sources to route into Rootly On-Call, then actively monitor the first hours/days of production usage.
During cutover, the most common issues are not configuration problems—they are deliverability or responder readiness issues (for example, a responder never installed the mobile app or has not verified a phone number). Use Rootly's readiness tooling and test notifications proactively.
***
## Running PagerDuty And Rootly In Parallel
Because Rootly imports from PagerDuty using a **read-only API key**, PagerDuty stays fully untouched and operational throughout the migration. That gives you a real safety net: you can keep PagerDuty live during validation and cut over without committing burned bridges.
Two parallel-running patterns are common, depending on how much risk tolerance your team has during cutover.
### Pattern A: Mirror Mode (Lower Risk)
PagerDuty stays primary. Alert sources continue routing to PagerDuty. In parallel, you configure the same alert sources to also send to Rootly as a second destination. Pages fire in both systems; responders acknowledge in PagerDuty as usual.
The goal is to **observe**, not act. Compare what Rootly does to what PagerDuty does for the same incoming alert. Did the right responder get paged? At the right delay? With the right urgency? Discrepancies caught here are cheap to fix — no production responders are relying on Rootly yet.
This pattern works best when:
* Your sending tools (Datadog, AWS, Sentry, etc.) support multiple webhook destinations or fan-out via a forwarder
* You have a defined validation period (typically 1–2 weeks) before committing
* Stakeholders are nervous about a hard cutover
### Pattern B: Cutover With Warm Fallback
Flip alert sources from PagerDuty to Rootly on a planned date. PagerDuty stays configured (escalation policies, schedules intact) but no longer receives alerts. If something serious breaks in the first 1–2 weeks, you can re-point alert sources back to PagerDuty in under an hour and operate normally while the issue is diagnosed.
The goal is to **commit**, but keep an undo path. Most teams find that after a week of clean operation, PagerDuty can be decommissioned with confidence.
This pattern works best when:
* You've completed thorough Step 5 validation and have high confidence in the import
* Your alert sources don't easily support sending to two destinations
* Your team has a clear rollback runbook (who flips the switch, how the call is made)
### What To Avoid
* **Don't pay for both indefinitely without a decision date.** Set a cutover deadline. Parallel-running is a transitional state, not a destination.
* **Don't disconnect PagerDuty the same day you cut over.** Keep it configured for at least a week. Configuration is free; rebuilding it from scratch on day-three because of a deliverability issue is expensive.
* **Don't skip the parallel period because validation looks clean.** Real-world paging surfaces edge cases that no checklist catches — a misconfigured phone country code, a Slack workspace install issue, a responder who set Do Not Disturb. The parallel window catches these cheaply.
***
## Best Practices
These practices reduce risk and make the migration easier to validate and operate.
* **Start with a dry run.** Dry runs catch incompatible schedules and policy edge cases early, when changes are easiest.
* **Migrate in a controlled window.** Even if Rootly doesn’t require downtime, you want your team mentally prepared for validation and quick fixes.
* **Plan a staged cutover.** Many organizations keep PagerDuty live briefly while they validate Rootly paging reliability, then fully cut over.
* **Validate paging with real test notifications.** It’s not enough for rules to exist; verify that responders actually receive calls/SMS/push.
* **Decide your urgency model up front.** If you rely heavily on low urgency workflows, enable separate quiet and audible escalation paths. If you don’t, keep it simple.
* **Communicate responder expectations early.** Tell responders what to install (mobile app), what to verify (phone numbers), and what to expect during the transition.
* **Document “skipped resources.”** If something is skipped (such as a schedule layer with short rotation length), write down why and your replacement approach in Rootly.
## Frequently Asked Questions
No. Rootly migrations use read-only PagerDuty API access. Rootly reads your PagerDuty configuration and recreates equivalent resources in Rootly, but does not write back to PagerDuty or delete anything in your PagerDuty account.
Users are matched by email address. If a Rootly user exists with the same email (including soft-deleted users), Rootly reuses that user. If no match exists, Rootly creates a new Rootly user and adds them to the team so schedules and escalation policies can reference them.
Notification rules are migrated when compatible. PagerDuty low urgency rules map to Rootly quiet rules, while all other rules map to Rootly audible rules. Delays are preserved where supported, and contact methods are mapped into Rootly’s supported channels (email, SMS, call, and mobile push). If a rule cannot be mapped reliably, Rootly skips it to avoid creating misleading paging behavior.
Some schedules may be skipped due to compatibility guardrails—most commonly when a schedule layer uses rotation turn lengths shorter than 24 hours. Skipped resources should be reviewed and recreated using Rootly-native patterns if they are operationally important.
Yes. You can limit migration scope—for example, importing only specific escalation policy IDs, excluding certain schedules, or controlling whether all users are imported. This is useful for phased migrations where you transition one team or service group at a time.
Yes. Migrations can be configured to synchronize against existing resources rather than always creating new ones. Sync mode may rebuild future shifts and clean up removed overrides to maintain parity with the PagerDuty source, so it should be used deliberately and validated carefully.
Validate that schedules show correct on-call responders, escalation policies point to the right targets, and a sample of responders can receive pages via at least one reliable channel. If you use mobile push, confirm responders have devices connected. If you use SMS/calls, confirm phone numbers are correct and deliverability is acceptable for your region and carriers.
Contact your Rootly onboarding representative or Rootly Support. Come prepared with the PagerDuty resource IDs (schedule IDs, escalation policy IDs) and a short description of the mismatch you’re seeing so the issue can be diagnosed quickly.
***
Need help planning or executing a migration? Contact your Rootly onboarding representative or email **[support@rootly.com](mailto:support@rootly.com)**.
# Switching to Rootly
Source: https://docs.rootly.com/switch/switch
Move to Rootly from your current on-call tool. Rootly-led migrations bring your users, schedules, and escalation policies over without a rebuild.
Rootly migrations are led by the Rootly team and powered by API-based imports, so you keep your
schedules, escalation policies, users, and routing rules — no rebuilding from scratch.
Most teams run Rootly in parallel with their existing tool during the transition and cut
over once everything is validated.
Concept-to-concept mapping, what gets imported, timeline, parallel-running patterns, and cutover validation steps.
Migrate users, schedules, teams, services, routing rules, and notification settings with a Rootly-led, API-based import.
Coming from a different tool, or want help planning your cutover?
[Book a demo](https://rootly.com/demo) or [contact support](/contacting-support) and the Rootly
team will walk you through it.
# Notification Troubleshooting
Source: https://docs.rootly.com/troubleshooting
Fix missed or silent Rootly pages: no sound, Do Not Disturb, battery optimization, calls that don't ring, login, and device-specific issues on iOS and Android.
Missed a page, or got it silently? Start here. Most paging issues come down to a single device setting, and the fixes below are quick. If you're actively on-call, run the checklist first, then jump to the area that's failing.
If a page came in silent, first confirm it was **high-urgency**. Only **Audible** notification rules (Critical Alerts and/or a phone call) are built to break through Do Not Disturb; **Quiet** rules don't force sound. See [On-Call Notifications](/on-call/on-call-notifications) for how the rules work.
## Most common fixes
In the mobile app, go to **Settings → Troubleshooting** and tap **Send a test alert** (it also checks your notification permissions and connection). From the web, go to **Configuration → Notifications → On-Call Notifications** and use **Test Notifications**. Either confirms delivery in seconds.
Critical Alerts must be enabled, and Rootly must be allowed to override Do Not Disturb. The exact path differs by platform, so see your device guide below.
Critical Alerts are built to break through Do Not Disturb, silent, and vibrate, so you can keep your phone however you like. The usual culprit is battery optimization, so set Rootly's battery usage to **Unrestricted**. (If your phone has a **physical alert slider**, like some OnePlus and Samsung models, also check it isn't set to Silent. See the [Android](/troubleshooting/android) guide.)
## Find your problem
Jump to the area that matches what you're seeing:
Critical Alerts, Focus modes, and Apple Watch.
Do Not Disturb, battery optimization, and Samsung, Pixel, OnePlus, and more.
Calls that don't ring through Do Not Disturb, or audio that's quiet or garbled.
SSO loops, Okta/Google, and managed (Intune) devices.
| Symptom | Most likely cause | Where to fix |
| ------------------------------ | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| Pages arrive but make no sound | Critical Alerts or Bypass DnD not enabled, or a physical alert slider set to Silent | [iOS](/troubleshooting/ios) · [Android](/troubleshooting/android) |
| Pages arrive late or batched | Battery optimization is sleeping the app | [Android](/troubleshooting/android) |
| A phone call doesn't ring | Do Not Disturb only allows calls from saved contacts | [Phone calls](/troubleshooting/calls) |
| Call audio is quiet or garbled | The alert tone is playing over the call | [Phone calls](/troubleshooting/calls) |
| Can't sign in / SSO loops | In-app browser handoff or a stale session | [Login & SSO](/troubleshooting/login) |
| No notifications at all | App notifications disabled, or the wrong device is registered | [iOS](/troubleshooting/ios) · [Android](/troubleshooting/android) |
## Test before you rely on it
After any change (new phone, new number, reinstalling the app, or editing notification rules), send yourself a test page before you go on-call. Test both an audible path (Critical Alerts or a call) and a quiet path (email or non-critical push). See [On-Call Notifications](/on-call/on-call-notifications) for how rules and testing work.
**Still missing pages?** See [**Contacting Support**](/contacting-support) for exactly what to send us (including how to grab a device dump), or email [**support@rootly.com**](mailto:support@rootly.com).
# Android Notification Troubleshooting
Source: https://docs.rootly.com/troubleshooting/android
Fix silent, delayed, or missed Rootly pages on Android: Do Not Disturb, battery optimization, Work Profiles, and Samsung, Pixel, OnePlus specifics.
Android notification behavior varies a lot by manufacturer. Start with the checklist, then open the section for your device. Unlike iOS, Android has no single "critical alert" switch, so Rootly relies on a high-importance notification channel plus Do Not Disturb override, and some manufacturers add their own restrictions on top.
## Start here
In the Rootly app, go to **Settings → On-Call Notifications**, enable **Bypass DnD**, and drag **Alert Volume** to the top (it overrides your phone's volume).
Still under **Settings → On-Call Notifications**, open **Notification Devices** and make sure this phone is set to receive your alerts.
In the Rootly app, open **Settings → Battery Optimization** and disable it for Rootly (or in your phone's **Settings → Apps → Rootly → Battery**, choose **Unrestricted**).
Software silent mode and Do Not Disturb are fine, since Critical Alerts break through them. Some phones (like OnePlus and a few Samsung models) also have a **physical** sound switch or alert slider. If yours does, check it isn't set to **Silent** (see below).
In the Rootly app, go to **Settings → Troubleshooting** and tap **Send a test alert** to confirm an audible page comes through.
## Find the setting for your device
* **Battery:** Settings ▸ Apps ▸ Rootly ▸ Battery ▸ **Unrestricted**
* **Sleeping apps:** Settings ▸ Device care ▸ Battery ▸ **Background usage limits** ▸ remove Rootly from **Sleeping** and **Deep sleeping apps**
* **Sound mode:** Critical Alerts break through silent and Do Not Disturb. If Vibrate-only still stays silent, update the app (an older One UI bug, fixed in a recent version).
* **Battery:** Settings ▸ Apps ▸ Rootly ▸ Battery ▸ **Unrestricted**
* **Adaptive Battery / Doze:** avoid deep battery saver while on-call.
* **Battery:** Settings ▸ Battery ▸ Rootly ▸ **Allow all background activity** (don't restrict)
* **Alert slider:** the physical slider must be on **Ring** or **Vibrate**, not **Silent** (see below).
* **Autostart:** enable **Autostart** for Rootly.
* **Battery saver:** set Rootly to **No restrictions**.
* Look for an OEM "background restriction" or "app sleep" setting and exclude Rootly.
## Reported issues
**Devices:** some OnePlus and Samsung models with a physical sound switch or alert slider.
**Likely cause:** the phone's **physical** sound switch is set to Silent.
**Likely cause:** On some Samsung One UI versions, the vibrate-only profile suppresses the alert sound even when Do Not Disturb override is enabled.
**Fix:** Update the Rootly app to the latest version, which fixes this. On older versions, keeping the phone on **Ring** is a workaround. If it persists on the latest version, contact support with your exact model and One UI version.
**Likely cause:** Battery optimization (Doze / App Standby) is suspending the app's network access while the phone is idle, so pages queue until you wake it.
**Likely cause:** Older app versions could leave the device in a Rootly-managed Do Not Disturb state after an alert was acknowledged.
**Fix:** Update the Rootly app to the latest version from Google Play. If you still see a Do Not Disturb labeled "managed by Rootly," turn it off once after updating.
**Likely cause:** Android restricts apps inside a Work Profile from overriding system volume and Do Not Disturb.
**Fix:** Install Rootly on your **personal profile** for full override behavior. If Rootly must stay in the Work Profile, also add **Google Chrome** to the Work Profile alongside it for better behavior.
Phone-call ring-through and audio fixes live on the [**Phone calls**](/troubleshooting/calls) page.
**Still not paging?** See [**Contacting Support**](/contacting-support) for what to send us (including a device dump from the app), or email [**support@rootly.com**](mailto:support@rootly.com).
# Phone Call Troubleshooting
Source: https://docs.rootly.com/troubleshooting/calls
Fix Rootly phone-call pages: calls that don't ring through Do Not Disturb on iPhone or Android, and call audio that's quiet, garbled, or delayed.
Rootly can page you with a **phone call** and a recorded message. If the call doesn't ring, comes through silent, or the recorded message is hard to hear, it's almost always how your phone treats calls from numbers it doesn't recognize, and the fix differs by platform.
Rootly places calls from a **range of numbers**, so your phone may not recognize them as Rootly. Saving the Rootly contact card is the foundation for every fix below: in the app, **Settings → Update Contact Card**, or import the [Rootly contact card](/notifications/notification-phone-numbers) manually.
## The call doesn't ring through Do Not Disturb
Adding Rootly to Favorites isn't enough on its own. Turn on **Emergency Bypass** on the Rootly contact, which rings through the silent switch, Focus, and Do Not Disturb:
1. Save the contact card (**Settings → Update Contact Card** in the app).
2. Open **Contacts → Rootly → Edit → Ringtone** and turn **Emergency Bypass** on.
Allow calls from your saved contacts through Do Not Disturb, then make sure Rootly is one:
1. Save the contact card (**Settings → Update Contact Card** in the app).
2. In your phone's **Settings → Do Not Disturb → Calls** (wording varies by manufacturer), allow **Starred contacts**.
## Call audio is quiet, garbled, or delayed
**Likely cause (mostly iPhone):** when a critical alert and the call arrive at the same moment, the alert tone plays over the first few seconds of the call on a louder audio channel. That can sound like low volume, or like a delay before the recorded message starts. (On iOS there's no per-notification volume control, so this shows up there more than on Android.)
**Fix:**
* Turn your device volume **up during the call**. The message comes through once the alert tone finishes.
Without the Rootly app there's no Critical Alerts permission to lean on, so the call is just an inbound call from an unknown number, which Do Not Disturb silences. Save the contact card and apply the Do Not Disturb step for your platform above (iPhone **Emergency Bypass**, Android **starred contact**).
**Still not getting calls?** See [**Contacting Support**](/contacting-support) for what to send us (including a device dump and the specific alert link), or email [**support@rootly.com**](mailto:support@rootly.com).
# iOS Notification Troubleshooting
Source: https://docs.rootly.com/troubleshooting/ios
Fix silent or missed Rootly pages on iPhone: Critical Alerts, Focus modes, the Ring/Silent switch, Apple Watch mirroring, Low Power Mode, and call audio.
On iOS, high-urgency Rootly pages are delivered as **Critical Alerts**, which are designed to break through the Ring/Silent switch and Do Not Disturb. If an iPhone stays silent on a page, it's almost always one of the settings below.
## Start here
In **Settings → Notifications → Rootly** (your iPhone's Settings), make sure **Allow Notifications** and **Critical Alerts** are both on. Critical Alerts is what lets Rootly break through the Ring/Silent switch and Do Not Disturb.
If you use a Focus, make sure it isn't filtering Rootly (see below).
In the Rootly app, go to **Settings → Troubleshooting** and tap **Send a test alert** to confirm an audible page comes through.
## Reported issues
**Likely cause:** When an Apple Watch is connected, your iPhone can route Rootly alerts to the watch and stay silent itself.
**Fix:**
1. Open the **Watch** app on your iPhone
2. Go to **Notifications**
3. Scroll to **Mirror iPhone Alerts from** and unselect **Rootly**
This lets the full Rootly sound play on your iPhone while on-call.
**Likely cause:** Critical Alerts is turned off, so pages fall back to standard notifications that respect the Ring/Silent switch and Do Not Disturb.
**Likely cause:** A Focus (Work, Sleep, Personal, and so on) is filtering Rootly's notifications.
**Fix:** Critical Alerts bypass Focus by design. If standard pages are being filtered, add Rootly as an **Allowed app** in the Focus, or rely on Critical Alerts and calls for audible paging.
**Likely cause:** Low Power Mode can delay background delivery of standard push.
**Fix:** Critical Alerts and calls are unaffected, so keep an audible path on Critical Alerts. If you depend on standard push, avoid Low Power Mode while on-call.
Phone-call ring-through and audio fixes (including iPhone **Emergency Bypass**) live on the [**Phone calls**](/troubleshooting/calls) page.
**Still not paging?** See [**Contacting Support**](/contacting-support) for what to send us (including a device dump from the app), or email [**support@rootly.com**](mailto:support@rootly.com).
# Login & SSO Troubleshooting
Source: https://docs.rootly.com/troubleshooting/login
Fix Rootly sign-in problems by platform: Android (Chrome / Custom Tabs) vs iOS (Safari), plus managed (Intune) devices, lockouts, and web SSO.
Most mobile login problems are the **sign-in browser handoff** or a **stale session**, and the fix depends on your platform, because the app signs in differently on each: **Android** hands off to **Chrome (Custom Tabs)**, while **iOS** uses **Safari (ASWebAuthenticationSession)**. Jump to yours.
Chrome / Custom Tabs, Samsung Internet, Android System WebView, Okta passkey errors.
Safari sign-in, clearing website data, managed (Intune) devices.
## Android
On Android, Rootly signs in through **Chrome Custom Tabs**, so most login issues trace back to Chrome, a non-Chrome default browser, or a stale Android System WebView.
**Likely cause:** sign-in completes in the browser, but the session handed back to the app is out of sync, often because a previous web login is still active.
**Fix:**
1. On the sign-in screen, tap the **⋮** menu (top-right) and choose **Open in Chrome**, then complete sign-in there.
2. If it still loops, open Chrome, sign out of rootly.com, then reopen the app and sign in again.
**Likely cause:** your Okta org requires a passkey / security key / biometric (WebAuthn), and sign-in opened in a browser context that can't perform it (commonly Samsung Internet, or a stale WebView).
**Fix:**
1. Make sure **Chrome is your default browser** (Settings → Apps → Default apps → Browser app). Some phones default to a browser that can't complete this step, such as Samsung Internet.
2. Force-stop Rootly, **clear its cache and storage**, and in Chrome clear cookies for `rootly.com` and `okta.com`.
3. Update **Chrome** and **Android System WebView**, then retry.
If WebAuthn is required org-wide, your **Okta admin** can add a fallback MFA method or a mobile sign-on rule that doesn't force WebAuthn. See [Okta's article](https://support.okta.com/help/s/article/the-user-agent-does-not-support-public-key-credentials-error-message-during-mfa-enrolment-on-mobile-devices).
**Likely cause:** a stale Android System WebView / Chrome cache fails before the handoff to your identity provider (so your IdP logs show nothing).
**Likely cause:** Conditional Access rejects the embedded browser; older app versions could leave the app waiting for a callback that finished elsewhere.
**Fix:** update to the latest app, ensure **Microsoft Authenticator** is installed, and sign in with Microsoft. If it loops, **close and reopen the app**. You're usually already signed in. See the [Intune setup notes](/on-call/mobile-app#intune-support).
## iOS
On iOS, Rootly signs in through **Safari (ASWebAuthenticationSession)**, so there is no "Open in Chrome." Issues here are usually a stale Safari session or a managed-device policy.
**Likely cause:** the Safari sign-in session is stale or didn't hand back to the app.
**Fix:**
1. Update the Rootly app. The latest version uses a native in-app sign-in.
2. Clear Safari data: **Settings → Apps → Safari → Clear History and Website Data** (to target just Rootly, use **Settings → Safari → Advanced → Website Data**, find `rootly.com`, and remove it).
**Likely cause:** Conditional Access requires an approved client; the older Safari/WebView path could stall.
**Fix:** update to the latest app, ensure **Microsoft Authenticator** is installed, and tap **Sign in with Microsoft**. If it loops, **close and reopen the app**. See the [Intune setup notes](/on-call/mobile-app#intune-support).
**Fix:** your **Okta (or IdP) admin** can add a fallback MFA method or a mobile sign-on rule so mobile sign-in isn't forced through a security key. (The Android-specific browser steps don't apply on iOS.)
## Web & admin (any platform)
**Likely cause:** some Chromium-based browsers (for example Brave) break the auth/refresh flow.
**Fix:** use **Google Chrome**.
**Likely cause:** once SSO is enabled for an email domain, password sign-in is blocked for that domain, so a SAML misconfiguration can lock everyone out.
**Fix:** validate the SAML connection **before** enforcing SSO. If you're already locked out, contact [**support@rootly.com**](mailto:support@rootly.com) to recover access.
These are admin / configuration issues. Reach out to [**support@rootly.com**](mailto:support@rootly.com) and Rootly support will review your SSO/SCIM setup.
**Still stuck?** See [**Contacting Support**](/contacting-support) for what to send us (your sign-in method, whether web login works, and a device dump), or email [**support@rootly.com**](mailto:support@rootly.com).
# User Profile
Source: https://docs.rootly.com/user-profile
Manage your Rootly account settings, contact details, notification preferences, linked accounts, and subscriptions from your personal user profile page.
Your user profile is where you manage your personal account settings in Rootly. This includes your contact information, notification preferences, password settings, linked accounts, and subscriptions.
## Access Your User Profile
You can open your user profile in either of these ways:
* From the Dashboard, click your **profile photo** next to the greeting
* From the left sidebar, open **Configuration** and select one of your account settings pages, such as **My Information**
From your profile, you can manage the following areas:
* **My Information**
* Update your personal details, contact information, and account preferences
* **Reset Password**
* Change your password if your organization does not use SSO
* **Notifications**
* Manage your incident and on-call notification settings
* **Linked Accounts**
* View connected accounts such as Slack or Mattermost
* **Subscriptions**
* Manage broadcast group subscriptions and communication preferences
## My Information
The **My Information** section is where you manage your personal and account details.
This section includes settings such as:
* Name and profile photo
* Email addresses
* Phone numbers
* Mobile devices
* Time zone
* Theme and other account preferences
## Reset Password
Use **Reset Password** to change your current password.
To update your password, enter your current password and your new password, then save your changes.
If your organization uses **SSO**, this section is not available for password changes. In that case, your password is managed by your identity provider.
## Notifications
Use the **Notifications** section to control how Rootly contacts you.
Depending on your plan and permissions, this section may include:
* **Incident Notifications** for email, Slack, and related incident updates
* **On-Call Notifications** for paging and on-call delivery settings
If you have access to on-call features, you may also be able to send test notifications to verify your setup.
## Linked Accounts
The **Linked Accounts** section shows chat accounts connected to your profile, such as **Slack** or **Mattermost**.
This section is available only when your organization has those integrations enabled.
### Connect your Slack account
Linking your Slack account lets Rootly recognize you in Slack, so you can run slash commands, receive pages, and act on incidents without leaving the conversation. Connect it ahead of time so you are ready before an incident starts, rather than linking under pressure once one is underway.
1. Go to **Configuration → Linked Accounts**.
2. Click **Sign in with Slack**.
3. Authorize the request in Slack to finish linking.
Once linked, the section shows a green confirmation that your account is connected. You can unlink from the same page at any time.
Run `/rootly connect` in Slack and follow the prompt to link your account.
The Slack option appears only when your organization has the [Slack integration](/integrating-with-slack) enabled.
## Subscriptions
In **Subscriptions**, you can manage your **broadcast groups** and choose which communications you want to receive.
This section is available when your organization has **Incident Communications** enabled.
Use it to control which updates and communication groups you are subscribed to.
## Frequently Asked Questions
You can open your user profile by clicking your profile photo from the Dashboard or by opening Configuration in the left sidebar and selecting one of your account settings pages.
If your organization uses SSO, your password is managed by your identity provider instead of Rootly. In that case, the Reset Password section will not allow password changes.
My Information includes your personal and account settings, such as your name, profile photo, email addresses, phone numbers, mobile devices, time zone, and other account preferences.
If you have access to on-call features, Rootly may show both notification types. Incident Notifications control general incident updates, while On-Call Notifications are used for paging and on-call delivery settings.
These sections appear only when the related features are enabled for your organization. Linked Accounts depends on chat integrations such as Slack or Mattermost, and Subscriptions depends on Incident Communications being enabled.
Go to **Configuration → Linked Accounts** and click **Sign in with Slack**, or run `/rootly connect` in Slack. Connecting ahead of time means you are ready to respond before an incident starts. Slack must be enabled for your organization for this option to appear.
# Action Item Workflows
Source: https://docs.rootly.com/workflows/action-item-workflows
Automate follow-up and remediation work by triggering workflows on action item changes—keeping tickets, owners, and notifications in sync across systems.
## Overview
**Action item workflows** automate what happens after work is identified—whether that work comes from an incident, a retrospective, or ongoing operational reviews. In Rootly, action items are first-class objects tied to incidents, and workflows can react whenever those action items are created, updated, assigned, or completed.
These workflows are especially useful for eliminating manual handoffs. Instead of relying on responders to remember to open Jira tickets, assign owners, or notify teams, you can encode those rules once and let Rootly enforce them consistently.
Common use cases include:
* Automatically creating or updating Jira (or other ticketing) issues when an action item is created or completed
* Assigning tickets based on the user or team assigned to the Rootly action item
* Notifying teams or owners when work is assigned, completed, or overdue
Action item workflows are triggered by **action item events**, not incident events. However, you can still use **incident properties as run conditions** (such as severity, services, or teams) to precisely control when the workflow should execute.
***
## Supported Triggers
Action item workflows support the following trigger events:
* **Action Item Created** (`action_item_created`)
* **Action Item Updated** (`action_item_updated`) – catch-all trigger
* **Assigned User Updated** (`assigned_user_updated`)
* **Summary Updated** (`summary_updated`)
* **Description Updated** (`description_updated`)
* **Status Updated** (`status_updated`)
* **Priority Updated** (`priority_updated`)
* **Due Date Updated** (`due_date_updated`)
* **Teams Updated** (`teams_updated`)
* **Incident Updated** (`incident_updated`)
* **Slack Command** (`slack_command`)
* **\[CustomField] «Field Name» Updated** (`custom_fields..updated`) – one trigger per custom field, fired when that field's value changes on an action item
### Catch-All Trigger Behavior
`Action Item Updated` is a catch-all trigger that fires for *any* change to the action item. Do not combine it with more specific field-level triggers (such as Status Updated or Priority Updated), or the workflow may fire more often than intended.
Custom field triggers appear once [custom fields for action items](/incidents/action-items/action-item-custom-fields) is enabled for your organization — one trigger per enabled custom field, whether or not it is placed on an action item form. They fire for both tasks and follow-ups.
***
## Create an Action Item Workflow
Navigate to **Workflows → Create Workflow → Action Item**.
Select the action item events that should initiate the workflow. For example, a workflow can start when a **new action item is created**.
You can also include a **Slack Command** trigger if you want the workflow to be runnable manually.
Action item workflows can evaluate **both action item properties and incident properties**. This allows you to build rules like:
* “Only create tickets for high-priority action items”
* “Only notify teams when the parent incident was SEV0 or SEV1”
#### Action item fields
The following action item fields can be used in conditions:
Separates remediation work (`task`) from informational follow-ups (`follow_up`).
Commonly used to trigger workflows when work is completed.
In an action item workflow, "status" always refers to the **action item status**, not the incident status.
Often used to restrict automation to higher-impact follow-ups. Action item priority is distinct from incident severity — they are separate fields and should not be conflated.
The team the action item is assigned to. This is independent of the incident's team assignment — an incident can belong to one team while its action items are owned by another. Action item workflows evaluate the **action item's assigned teams**, not the incident's.
Any [custom field placed on an action item form](/incidents/action-items/action-item-custom-fields) can be used as a condition. Supports `is`, `is not`, `is one of`, `is set`, and `is unset` semantics, plus `contains any / all / none of` for multi-value fields. Evaluates the **action item's own field values**, not the parent incident's — use incident conditions (below) for incident custom fields.
Because action items are tied to incidents, you can further narrow execution using incident properties such as:
* Incident severity
* Impacted services
* Incident teams
* Custom incident fields
For details on operators and condition logic, see: [Condition Checks](/workflows/workflows).
Once the workflow passes all conditions, its actions are executed. Available actions depend on your integrations, but action item workflows commonly include:
* Ticketing actions (create or update Jira, Linear, Shortcut, Asana, ClickUp, and more)
* Messaging actions (send Slack or Microsoft Teams messages)
* Rootly actions (create or update action items, add timeline entries)
* Notifications (email, SMS, or phone where configured)
Two actions are worth calling out for custom field automation:
* **Update Action Item** can set an action item's [custom field values](/incidents/action-items/action-item-custom-fields) via its **Custom Fields Mapping** input. Values support Liquid, so you can populate a field from incident context (for example, `{{ incident.severity }}`).
* **Ticketing actions** (Create/Update Jira Issue, Linear Issue, GitHub Issue, Asana Task, and others) support custom field mappings, letting you write an action item's field values into the external ticket with Liquid — for example, `{{ action_item.custom_fields_by_slug.business-unit-owner }}`. See [Action Item Variables](/liquid/action-item-variables#custom-fields).
By default, a failing action halts the workflow. Enable **Skip on Failure** on non-critical actions to allow the workflow to continue even if one step fails.
***
## Best Practices
Action item workflows are most effective when they reinforce ownership and accountability without creating noise.
* **Trigger on meaningful changes.** Status transitions (for example, to `done`) are usually better triggers than generic updates.
* **Use priority as a gate.** Many teams only want automation for high-impact action items.
* **Let Rootly be the source of truth.** Use the action item as the canonical object and sync outward to ticketing systems, not the other way around.
* **Avoid catch-all triggers unless necessary.** `Action Item Updated` should almost always be paired with strict run conditions.
* **Create ownership explicitly.** When creating tickets, assign owners and due dates automatically so work does not stall.
***
## Frequently Asked Questions
Yes. They can run automatically based on action item events and can also be triggered manually using a Slack command if that trigger is enabled.
Yes. Action item workflows can evaluate both action item fields and incident fields, allowing very precise control over when the workflow runs.
This is usually caused by using the catch-all `Action Item Updated` trigger without restrictive run conditions. Narrow the workflow using specific triggers or conditions such as status or priority.
No. Action item workflows are triggered by changes inside Rootly. Updates in external tools only trigger workflows if they sync back and modify the Rootly action item.
Yes — this is a common pattern. The **Export to ticketing** modal itself does not support Liquid variables, but the act of exporting fires the `Action Item Updated` trigger (it writes the external ticket reference back to the action item). You can build an action item workflow that runs on that trigger and uses the relevant Update action (Update Jira Issue, Update Linear Issue, Update Asana Task, etc.) to populate a field with `{{ incident.url }}` or any other [incident variable](/liquid/incident-variables). Full walkthrough: [Linking Exported Tasks Back to the Incident](/incidents/action-items/adding-action-items-via-web-ui#linking-exported-tasks-back-to-the-incident).
***
Need help designing reliable follow-up automation? Contact your Rootly onboarding representative or email **[support@rootly.com](mailto:support@rootly.com)**.
***
## Related Pages
The companion type — action items belong to incidents, so most action-item automation follows an incident-workflow chain.
The full set of workflow types and when to reach for each.
The object these workflows read and write — tasks and follow-ups on an incident.
# Workflow Actions Reference
Source: https://docs.rootly.com/workflows/actions-reference
Reference for all 152 Rootly workflow action types, grouped by category: Slack, Google Chat, Jira, on-call, AI, and incident operations.
Workflow actions are the individual steps that execute when a workflow runs. Each action connects to a specific integration or Rootly capability. This page lists every available action grouped by category.
Many text fields support [Liquid templating](/liquid/liquid) for dynamic values drawn from incident, alert, or on-call context. Selector fields (dropdowns, user pickers, etc.) do not accept Liquid.
Available actions depend on your enabled integrations and the workflow type (incident, alert, on-call, etc.). Actions for integrations that are not connected will not appear when building a workflow.
The **Key fields** column lists internal field names as they appear in the API and workflow schema. Labels in the UI may differ slightly (for example, `workspace` appears as **Workspace** in the form).
***
## Slack
| Action | Description | Key fields |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------ |
| **Add Slack Bookmark** | Add a bookmark to the incident Slack channel | `channel`, `name`, `link`, `emoji` |
| **Archive Slack Channel** | Archive the incident Slack channel | `channels`, `name` |
| **Change Slack Channel Privacy** | Change a Slack channel's privacy setting | `channel`, `privacy` |
| **Create Slack Channel** | Create a Slack channel for the incident | `name`, `private`, `workspace` |
| **Invite Rootly On-Call to Slack Channel** | Invite users to the channel based on a Rootly target — on-call from a schedule, escalation policy, service, team, or individual user | `channel`, `escalation_policy`, `service`, `team`, `user`, `schedule` |
| **Invite On-Call to Slack Channel (PagerDuty)** | Invite the PagerDuty on-call user to the channel | `channel`, `escalation_policy`, `schedule`, `service` |
| **Invite On-Call to Slack Channel (Opsgenie)** | Invite the Opsgenie on-call user to the channel | `channel` |
| **Invite On-Call to Slack Channel (VictorOps)** | Invite the VictorOps on-call user to the channel | `channel` |
| **Invite Users to Slack Channel** | Invite specific users or user groups to a channel | `channel`, `slack_users`, `slack_user_groups`, `slack_emails` |
| **Rename Slack Channel** | Rename a Slack channel | `channel`, `title` |
| **Send Slack Blocks** | Send a rich interactive Block Kit message to a Slack channel | `channels`, `blocks`, `attachments`, `broadcast_thread_reply_to_channel` |
| **Send Slack Message** | Send a plain or formatted message to a Slack channel | `channels`, `color`, `actionables`, `broadcast_thread_reply_to_channel` |
| **Send Slack Reminder** | Send a recurring reminder with snooze and pause buttons | `channels`, `message`, `interval` |
| **Update Slack Channel Topic** | Update the topic of a Slack channel | `channel`, `topic` |
***
## Microsoft Teams
| Action | Description | Key fields |
| ------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| **Add Microsoft Teams Chat Tab** | Add a tab to a Teams chat | `chat`, `title`, `link` |
| **Add Microsoft Teams Tab** | Add a tab to the incident Teams channel | `channel`, `title`, `link` |
| **Archive Microsoft Teams Channel** | Archive the incident Teams channel | `channels`, `team` |
| **Create Microsoft Teams Channel** | Create a Teams channel for the incident | `name`, `title`, `team` |
| **Create Microsoft Teams Chat** | Create a Teams group or one-on-one chat | `chat_type`, `members`, `topic` |
| **Create Microsoft Teams Meeting** | Create a Teams meeting link | `record_meeting`, `recording_mode`, `post_to_incident_timeline`, `post_to_slack_channels` |
| **Invite Users to Microsoft Teams Channel** | Invite users to a private Teams channel | `channel`, `team`, `emails` |
| **Rename Microsoft Teams Channel** | Rename a Teams channel | `channel`, `team`, `title` |
| **Send Microsoft Teams Attachments** | Send a rich attachment message to a Teams channel | `channels`, `attachments` |
| **Send Microsoft Teams Chat Message** | Send a message to a Teams chat | `chats`, `text` |
| **Send Microsoft Teams Message** | Send a message to a Teams channel | `channels`, `text` |
***
## Google Chat
| Action | Description | Key fields |
| ---------------------------------------- | ----------------------------------------------- | ---------------------------------- |
| **Archive Google Chat Spaces** | Delete incident Google Chat spaces | `spaces` |
| **Change Google Chat Space Privacy** | Switch a space between private and discoverable | `space`, `audience` |
| **Create Google Chat Space** | Create a dedicated space for the incident | `title`, `description`, `audience` |
| **Invite to Google Chat Space** | Invite users to a space by email | `space`, `emails` |
| **Rename Google Chat Space** | Rename a Google Chat space | `space`, `title` |
| **Send Google Chat Attachments** | Send Cards v2 to Google Chat spaces | `spaces`, `attachments` |
| **Send Google Chat Message** | Send a text message to Google Chat spaces | `spaces`, `text`, `thread_key` |
| **Update Google Chat Space Description** | Update a space's description | `space`, `description` |
***
## Incident Management
| Action | Description | Key fields |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| **Add Action Item** | Create a task or follow-up on the incident | `kind`, `summary`, `description`, `assignee` |
| **Add Incident Role** | Assign a user to an incident role | `role`, `user` |
| **Add Team** | Set the team on the incident | `group_id` |
| **Add to Timeline** | Add a custom event to the incident timeline | `event`, `url` |
| **Create Incident** | Create a new incident | `custom_fields_mapping` |
| **Create Incident Retrospective** | Create a Rootly retrospective for the incident | `incident_id` |
| **Create Sub Incident** | Create a sub-incident linked to the current incident | `incident_id`, `sync_info` |
| **Create ServiceNow Incident** | Create a ServiceNow ticket for the incident | `description`, `status`, `custom_fields_mapping`, `acts_as_user` |
| **Update Action Item** | Update an existing action item, including its [custom field values](/incidents/action-items/action-item-custom-fields) | `kind`, `summary`, `description`, `attribute_to_query_by`, `custom_fields_mapping` |
| **Update Incident** | Update fields on the incident | `custom_fields_mapping`, `attribute_to_query_by`, `acknowledged_at`, `mitigated_at` |
| **Update Incident Retrospective** | Update the incident's retrospective | `postmortem_id` |
| **Update Incident Status** | Update incident status after a period of inactivity | `inactivity_timeout`, `message` |
| **Update Incident Status Timestamp** | Update a lifecycle timestamp on the incident | `status`, `timestamp` |
| **Update ServiceNow Incident** | Update an existing ServiceNow ticket | `incident_id`, `description`, `status`, `custom_fields_mapping`, `acts_as_user` |
***
## On-Call & Paging
| Action | Description | Key fields |
| ----------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| **Auto Assign Role (Rootly)** | Assign an incident role from a Rootly on-call rotation | `escalation_target`, `incident_role_id` |
| **Auto Assign Role (PagerDuty)** | Assign an incident role from a PagerDuty on-call rotation | `incident_role_id`, `escalation_policy`, `schedule`, `service` |
| **Auto Assign Role (Opsgenie)** | Assign an incident role from an Opsgenie on-call rotation | `incident_role_id` |
| **Auto Assign Role (VictorOps)** | Assign an incident role from a VictorOps on-call rotation | `incident_role_id` |
| **Page Rootly On-Call** | Page a Rootly on-call escalation target | `escalation_target`, `title`, `description` |
| **Page PagerDuty On-Call** | Page a PagerDuty on-call rotation | `service`, `escalation_policies`, `message`, `priority`, `create_new_incident_on_conflict` |
| **Page Opsgenie On-Call** | Page an Opsgenie on-call rotation | `title`, `message`, `description` |
| **Page VictorOps On-Call** | Page a VictorOps on-call rotation | `title` |
| **Page JSM Ops On-Call** | Page a Jira Service Management on-call rotation | `title`, `message`, `description` |
| **Create PagerTree Incident** | Create a PagerTree incident to trigger paging | `title`, `description` |
| **Create PagerDuty Status Update** | Post a status update to an existing PagerDuty incident | `pagerduty_incident_id`, `message` |
| **Update PagerDuty Incident** | Update an existing PagerDuty incident | `pagerduty_incident_id`, `title`, `priority`, `resolution` |
| **Update PagerTree Incident** | Update an existing PagerTree incident | `pagertree_alert_id` |
| **Publish Incident to Status Page** | Publish the incident to a status page | `status_page`, `status_page_template`, `public_title`, `status`, `event` |
***
## Project Management
| Action | Description | Key fields |
| ------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| **Create Jira Issue** | Create a Jira ticket for the incident | `project`, `issue_type`, `description`, `labels`, `due_date`, `assign_user_email`, `custom_fields_mapping` |
| **Create Jira Subtask** | Create a subtask under an existing Jira ticket | `parent_issue_id`, `description`, `labels`, `due_date`, `assign_user_email`, `custom_fields_mapping` |
| **Update Jira Issue** | Update an existing Jira ticket | `issue_id`, `description`, `labels`, `due_date`, `assign_user_email`, `custom_fields_mapping` |
| **Create Linear Issue** | Create a Linear issue for the incident | `title`, `description`, `priority`, `assign_user_email`, `custom_fields_mapping` |
| **Create Linear Subtask** | Create a subtask under an existing Linear issue | `parent_issue_id`, `title`, `description`, `priority`, `assign_user_email`, `custom_fields_mapping` |
| **Create Linear Issue Comment** | Add a comment to a Linear issue | `issue_id`, `body` |
| **Update Linear Issue** | Update an existing Linear issue | `issue_id`, `description`, `priority`, `assign_user_email`, `custom_fields_mapping` |
| **Create Asana Task** | Create an Asana task for the incident | `due_date`, `labels`, `assign_user_email`, `custom_fields_mapping` |
| **Create Asana Subtask** | Create a subtask under an existing Asana task | `parent_task_id`, `due_date`, `assign_user_email`, `custom_fields_mapping` |
| **Update Asana Task** | Update an existing Asana task | `task_id`, `due_date`, `completion`, `assign_user_email`, `custom_fields_mapping` |
| **Create ClickUp Task** | Create a ClickUp task for the incident | `description`, `due_date`, `tags`, `parent_task_id`, `custom_fields_mapping` |
| **Update ClickUp Task** | Update an existing ClickUp task | `task_id`, `description`, `due_date`, `completion`, `custom_fields_mapping` |
| **Create Shortcut Story** | Create a Shortcut story for the incident | `description`, `due_date`, `labels`, `group` |
| **Create Shortcut Task** | Create a task under an existing Shortcut story | `parent_story_id`, `description` |
| **Update Shortcut Story** | Update an existing Shortcut story | `story_id`, `description`, `due_date`, `labels` |
| **Update Shortcut Task** | Update an existing Shortcut task | `task_id`, `parent_story_id`, `description`, `completion` |
| **Create Trello Card** | Create a Trello card for the incident | `board`, `list`, `description`, `due_date` |
| **Update Trello Card** | Update an existing Trello card | `card_id`, `board`, `list`, `description`, `due_date` |
| **Create Motion Task** | Create a Motion task for the incident | `description`, `due_date`, `duration`, `labels` |
| **Update Motion Task** | Update an existing Motion task | `task_id`, `description`, `due_date`, `duration`, `labels` |
***
## Docs & Pages
| Action | Description | Key fields |
| --------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------- |
| **Create Confluence Page** | Create a Confluence page from a retrospective template | `title`, `content`, `template`, `post_mortem_template_id` |
| **Update Confluence Page** | Update an existing Confluence page | `file_id`, `content`, `template`, `post_mortem_template_id` |
| **Create Coda Page** | Create a Coda page from a retrospective template | `doc`, `folder_id`, `content`, `format`, `post_mortem_template_id` |
| **Update Coda Page** | Update an existing Coda page | `doc_id`, `page_id`, `content`, `format`, `post_mortem_template_id` |
| **Create Datadog Notebook** | Create a Datadog notebook for the incident | `content`, `kind`, `template`, `post_mortem_template_id` |
| **Update Datadog Notebook** | Update an existing Datadog notebook | `file_id`, `content`, `kind`, `post_mortem_template_id` |
| **Create Dropbox Paper** | Create a Dropbox Paper document from a template | `parent_folder`, `permissions`, `content`, `post_mortem_template_id` |
| **Update Dropbox Paper** | Update an existing Dropbox Paper document | `file_id`, `title`, `content`, `post_mortem_template_id` |
| **Create Google Doc** | Create a Google Doc from a retrospective template | `drive`, `parent_folder`, `permissions`, `content`, `post_mortem_template_id` |
| **Update Google Doc** | Update an existing Google Doc | `file_id`, `content`, `template_id`, `post_mortem_template_id` |
| **Create Google Doc Permissions** | Grant users access to a Google Doc | `file_id`, `permissions` |
| **Remove Google Doc Permissions** | Revoke user access to a Google Doc | `file_id`, `attribute_to_query_by` |
| **Create Notion Page** | Create a Notion page for the incident | `title`, `show_action_items_as_table`, `show_timeline_as_table` |
| **Update Notion Page** | Update an existing Notion page | `file_id`, `title`, `show_action_items_as_table`, `show_timeline_as_table` |
| **Create Quip Page** | Create a Quip page from a template | `parent_folder_id`, `content`, `template_id`, `post_mortem_template_id` |
| **Update Quip Page** | Update an existing Quip page | `file_id`, `content`, `template_id`, `post_mortem_template_id` |
| **Create SharePoint Page** | Create a SharePoint document from a template | `site`, `drive`, `parent_folder`, `content`, `post_mortem_template_id` |
| **Update SharePoint Page** | Update an existing SharePoint document | `file_id`, `title`, `content`, `post_mortem_template_id` |
***
## Developer Tools
| Action | Description | Key fields |
| ------------------------------ | ------------------------------------------------ | -------------------------------------------------------------------------------------------- |
| **Create GitHub Issue** | Create a GitHub issue for the incident | `repository`, `issue_type`, `body`, `labels`, `parent_issue_number`, `custom_fields_mapping` |
| **Update GitHub Issue** | Update an existing GitHub issue | `issue_id`, `body`, `labels`, `labels_mode`, `issue_type`, `custom_fields_mapping` |
| **Get GitHub Commits** | Retrieve recent commits from a GitHub repository | `github_repository_names`, `branch`, `service_ids`, `past_duration` |
| **Create GitLab Issue** | Create a GitLab issue for the incident | `repository`, `issue_type`, `body`, `labels`, `due_date` |
| **Update GitLab Issue** | Update an existing GitLab issue | `issue_id`, `description`, `labels`, `due_date`, `issue_type` |
| **Get GitLab Commits** | Retrieve recent commits from a GitLab repository | `gitlab_repository_names`, `branch`, `service_ids`, `past_duration` |
| **Create Zendesk Ticket** | Create a Zendesk ticket for the incident | `subject`, `comment`, `tags`, `custom_fields_mapping` |
| **Update Zendesk Ticket** | Update an existing Zendesk ticket | `ticket_id`, `subject`, `tags`, `completion`, `custom_fields_mapping` |
| **Create Zendesk Jira Link** | Link a Zendesk ticket to a Jira issue | `zendesk_ticket_id`, `jira_issue_id`, `jira_issue_key` |
| **Create FreshService Ticket** | Create a FreshService ticket for the incident | `subject`, `description`, `priority`, `status`, `request_user_email` |
| **Update FreshService Ticket** | Update an existing FreshService ticket | `subject`, `description`, `priority`, `status`, `tags` |
| **Create FreshService Task** | Create a task under a FreshService ticket | `parent_ticket_id`, `title`, `description`, `priority`, `status` |
| **Update FreshService Task** | Update an existing FreshService task | `task_id`, `parent_ticket_id`, `description`, `priority`, `status` |
| **Create Airtable Record** | Create an Airtable record for the incident | `custom_fields_mapping` |
| **Update Airtable Record** | Update an existing Airtable record | `record_id`, `base_key`, `table_name`, `custom_fields_mapping` |
| **Run Heroku Command** | Execute a command in a Heroku app | `post_to_incident_timeline`, `post_to_slack_channels` |
| **HTTP Client** | Make an outbound HTTP request to any REST API | `method`, `url`, `headers`, `body`, `event_url`, `event_message` |
| **Redis Client** | Execute commands against a Redis instance | `commands`, `post_to_incident_timeline` |
***
## Observability
| Action | Description | Key fields |
| ------------------------------ | ---------------------------------------------------------------- | --------------------------------------------------------------------- |
| **Snapshot Datadog Graph** | Post a Datadog graph to the incident timeline | `post_to_incident_timeline`, `post_to_slack_channels` |
| **Attach Datadog Dashboards** | Post a Datadog dashboard link to the timeline | `post_to_incident_timeline`, `post_to_slack_channels` |
| **Snapshot Grafana Dashboard** | Post a Grafana dashboard snapshot to the timeline | `post_to_incident_timeline`, `post_to_slack_channels` |
| **Snapshot Grafana Panel** | Post a specific Grafana panel to the timeline | `post_to_incident_timeline`, `post_to_slack_channels` |
| **Snapshot Looker Graph** | Post a Looker graph to the incident timeline | `post_to_incident_timeline`, `post_to_slack_channels` |
| **Snapshot New Relic Graph** | Post a New Relic graph to the incident timeline | `metric_query`, `post_to_incident_timeline`, `post_to_slack_channels` |
| **Get Alerts** | Retrieve alerts matching a filter for use in subsequent actions | `sources`, `environment_ids`, `labels`, `past_duration` |
| **Get Pulses** | Retrieve deploys and changes matching a filter | `sources`, `environment_ids`, `labels`, `past_duration` |
| **Update Attached Alerts** | Update the status or position of alerts attached to the incident | `status`, `position`, `created_at` |
| **Create Opsgenie Alert** | Create an alert in Opsgenie | `description`, `details` |
| **Update Opsgenie Alert** | Update an existing Opsgenie alert | `alert_id` |
| **Update Opsgenie Incident** | Update an existing Opsgenie incident | `opsgenie_incident_id` |
| **Create JSM Alert** | Create an alert in Jira Service Management | `description`, `details` |
| **Update VictorOps Incident** | Update an existing VictorOps incident | `victor_ops_incident_id`, `resolution_message` |
| **Send Dashboard Report** | Send a dashboard snapshot report via email | `dashboard_ids`, `from`, `cc`, `bcc`, `body` |
***
## Meetings & Calendar
| Action | Description | Key fields |
| -------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| **Create Google Meet** | Create a Google Meet link | `record_meeting`, `post_to_incident_timeline`, `post_to_slack_channels` |
| **Create Zoom Meeting** | Create a Zoom meeting link | `password`, `record_meeting`, `create_as_email`, `post_to_incident_timeline`, `post_to_slack_channels` |
| **Create Webex Meeting** | Create a Webex meeting link | `password`, `record_meeting`, `recording_mode`, `post_to_incident_timeline`, `post_to_slack_channels` |
| **Create GoToMeeting** | Create a GoToMeeting link | `subject`, `post_to_incident_timeline`, `post_to_slack_channels` |
| **Create Google Calendar Event** | Schedule a meeting on Google Calendar | `calendar_id`, `attendees`, `description`, `conference_solution_key`, `exclude_weekends` |
| **Update Google Calendar Event** | Update an existing Google Calendar event | `event_id`, `attendees`, `conference_solution_key`, `exclude_weekends` |
| **Create Outlook Event** | Schedule a meeting on Outlook Calendar | `calendar`, `attendees`, `description`, `enable_online_meeting`, `exclude_weekends` |
***
## Notifications
| Action | Description | Key fields |
| ------------------------- | ----------------------------------------- | --------------------------------------------------------------------- |
| **Send Email** | Send an email to any address | `from`, `to`, `cc`, `bcc`, `body`, `include_header`, `include_footer` |
| **Send SMS** | Send an SMS to a phone number | `phone_numbers`, `content` |
| **Send WhatsApp Message** | Send a WhatsApp message to a phone number | `phone_numbers`, `content` |
| **Call People** | Make outbound phone calls | `phone_numbers`, `content` |
| **Send Tweet** | Post a tweet on Twitter / X | `message` |
***
## AI
| Action | Description | Key fields |
| ----------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------ |
| **OpenAI Chat Completion** | Send a prompt to OpenAI and use the response in subsequent actions | `model`, `prompt`, `system_prompt` |
| **Anthropic Chat Completion** | Send a prompt to Anthropic Claude and use the response in subsequent actions | `model`, `prompt`, `system_prompt` |
| **Gemini Chat Completion** | Send a prompt to Google Gemini and use the response in subsequent actions | `model`, `prompt`, `system_prompt` |
| **Mistral Chat Completion** | Send a prompt to Mistral AI and use the response in subsequent actions | `model`, `prompt`, `system_prompt`, `max_tokens` |
AI actions require the corresponding LLM integration to be configured in **Settings → Integrations**. The response from any AI action can be referenced in downstream actions using Liquid variables.
***
## Utility
| Action | Description | Key fields |
| -------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------- |
| **Trigger Workflow** | Trigger another workflow from the current one | `kind`, `check_workflow_conditions`, `attribute_to_query_by`, `match_header` |
| **Print** | Print a message to the workflow run log for debugging | `message` |
**HTTP Client** and **Redis Client** are also available as utility-style actions — see [Developer Tools](#developer-tools) above.
# Alert Workflows
Source: https://docs.rootly.com/workflows/alert-workflows
Automate responses to incoming alerts by triggering workflows that declare incidents, page responders, create tickets, and notify teams based on alert data.
## Overview
**Alert workflows** allow you to react automatically when external systems send alerts into Rootly. Alerts represent incoming signals from monitoring, ticketing, and paging tools such as Datadog, Grafana, PagerDuty, Jira, and others. Once ingested, those alerts become first-class objects that workflows can evaluate and act upon.
Alert workflows are most commonly used to bridge the gap between raw signals and coordinated incident response. Instead of waiting for a human to interpret an alert, you can codify rules that immediately declare incidents, notify teams, or create follow-up work.
Common use cases include:
* Automatically declaring incidents when critical alerts are received
* Paging on-call responders or notifying shared channels when alerts meet specific criteria
* Creating or updating tickets and action items based on alert lifecycle changes
Alert workflows only run if alerts are successfully flowing into Rootly. Before configuring workflows, verify that your alert integrations are connected and producing alerts.
***
## Supported Triggers
Alert workflows support **two trigger events**:
* **Alert Created** (`alert_created`)\
Fires immediately when a new alert is received in Rootly.
* **Alert Status Updated** (`alert_status_updated`)\
Fires whenever an alert’s status changes (for example, from open to resolved).
Unlike incident or action item workflows, alert workflows **cannot be triggered manually** via Slack command. They only run in response to alert events.
***
## Configure an Alert Workflow
Ensure alerts are arriving in Rootly by visiting **Alerts** in the Rootly UI. If no alerts are present, review your integrations on the [Alerts](/alerts/alerts) page.
Navigate to **Workflows → Create Workflow → Alert**.
Select one or both of the available alert triggers depending on when you want the workflow to run.
* Use **Alert Created** to respond immediately to new alerts
* Use **Alert Status Updated** to respond to acknowledgements or resolutions
***
## Define Run Conditions
Alert workflows can evaluate multiple properties of an alert. Conditions are optional but strongly recommended to avoid over-triggering.
### Source
The **source** condition matches on the **source type** of the integration that generated the alert — values like `datadog`, `pagerduty`, `generic_webhook`, `aws_cloudwatch`, and so on. Use this to scope a workflow to alerts coming from a specific kind of integration.
**The source condition takes a source type, not an alert source UUID.** If you paste in a specific source ID (for example, `a410cb8d-2851-447b-bba9-076b20d664bc`), the condition will never match incoming alerts and the workflow will silently never run. To scope a workflow to a specific alert source *instance* rather than all sources of a given type, combine the source-type condition with a `source_name` label condition (see [Scoping to a specific source instance](#scoping-to-a-specific-source-instance) below).
***
### Scoping To A Specific Source Instance
If you have multiple alert sources of the same type — for example, two Generic Webhook sources named "Harbor Image Scan" and "Deployments" — the Source condition alone can't tell them apart. Every alert ingested from a generic-webhook source is automatically tagged with a **`source_name`** label whose value is the alert source's name parameterized (lowercased, spaces and other non-alphanumeric characters replaced with hyphens):
| Alert source name | Auto-added label |
| ------------------------ | ---------------------------------- |
| `Harbor Image Scan (c1)` | `source_name:harbor-image-scan-c1` |
| `Deployments` | `source_name:deployments` |
| `Prod Kafka Consumer` | `source_name:prod-kafka-consumer` |
Combine a source-type condition with a `source_name` label condition (using **contains any of**) to route alerts from a specific source instance to a specific workflow. The source-type condition keeps the workflow scoped to webhook traffic only; the `source_name` label condition selects the exact source.
***
### Status
Alerts move through lifecycle states. Valid values include:
* `open`
* `triggered`
* `acknowledged`
* `resolved`
Status conditions are commonly used with the **Alert Status Updated** trigger to run workflows only when alerts are resolved or acknowledged.
***
### Labels
Alerts include a set of labels derived from the source system. Labels are stored as an **array of values**.
You can condition on labels using operators such as “contains any of” or “contains all of.”
***
### Payload
Each alert includes a **JSON payload** containing source-specific data. Payload conditions allow advanced filtering using:
* **JSONPath** to extract values from the payload
* Optional **regular expressions** to match extracted values
For example, you can match alerts where `$.data.type` equals `incident`, regardless of case.
Payload conditions are powerful but should be tested carefully. A malformed JSONPath or overly broad regex can cause workflows to misfire.
***
## Configure Actions
Alert workflows support a wide range of actions. Available actions depend on which integrations are connected to your workspace.
Common actions include:
* Declaring incidents in Rootly
* Paging on-call responders
* Sending Slack or Microsoft Teams messages
* Creating or updating tickets in Jira or other systems
* Creating action items for follow-up work
### Downstream Workflow Cascades
If an alert workflow declares an incident, that will immediately trigger **incident workflows** that listen for “Incident Created” or related events.
When testing alert workflows, it is strongly recommended to:
* Temporarily disable incident workflows, or
* Add restrictive run conditions to prevent unintended cascades.
***
## Best Practices
Alert workflows are most effective when they are precise and conservative.
* **Start narrow.** Use source, status, and payload conditions to target only the alerts that truly require automation.
* **Avoid duplicate incident creation.** Ensure alert grouping or deduplication is considered when declaring incidents from alerts.
* **Test in isolation.** Disable downstream workflows during initial testing to avoid accidental paging or ticket creation.
* **Use status-based triggers intentionally.** “Alert Created” is best for immediate response, while “Alert Status Updated” is better for follow-up automation.
* **Document your logic.** Complex payload conditions should be explained in the workflow description for future maintainers.
***
## Frequently Asked Questions
No. Alert workflows only run in response to alert events. Manual Slack commands are not supported for this workflow type.
Yes. Declaring incidents is a common use case. Be aware that doing so may trigger incident workflows downstream.
Check that alerts are flowing into Rootly, confirm the trigger event fired, and review run conditions — especially payload and label filters. A common silent failure is using an **alert source UUID** in the Source condition instead of the source **type** (`datadog`, `generic_webhook`, etc.). See [Source](#source) for the correct values.
Yes. Use the source condition to filter by integration type, plus payload or labels to match severity or priority fields provided by the source system. To scope to a specific source instance rather than all sources of a given type, see [Scoping to a specific source instance](#scoping-to-a-specific-source-instance).
No. Advanced Alert Routing and `alert_created` workflows are independent and run alongside each other. Enabling Advanced Alert Routing does not disable, supersede, or otherwise gate alert workflows — you do not need an Alert Route configured for an `alert_created` workflow to fire. If a workflow isn't firing on real alerts, the cause is almost always a run condition that doesn't match (see the Source condition FAQ above), not Advanced Alert Routing.
***
Need help designing safe and effective alert automation? Contact your Rootly onboarding representative or email **[support@rootly.com](mailto:support@rootly.com)**.
***
## Related Pages
The most common downstream — many alert workflows declare an incident, which then fires incident workflows.
Similar low-level event workflows, but for code-change events instead of alerts.
Where alerts come from before workflows can react to them.
# Workflow Conditions
Source: https://docs.rootly.com/workflows/conditions
How Rootly workflows evaluate run conditions — all-of / any-of / none-of join operators, per-field operators, recipes, and troubleshooting misfires.
## Overview
After a workflow's trigger fires, Rootly evaluates **run conditions** to decide whether the workflow's actions should execute. Conditions are the difference between a workflow that fires once a quarter on real SEV0s and one that fires hundreds of times a day on every minor update.
Every condition has two layers:
1. **A join operator** — how the individual conditions combine (**all of**, **any of**, **none of**).
2. **A per-condition operator** — how each condition compares its target field to the value(s) you configured (`is`, `is one of`, `contains any of`, `is set`, etc.).
Getting the join operator wrong is the most common cause of workflows that run more often than expected — the default is **all of**, but a slip to **any of** turns every condition into an OR.
***
## Join Operators
Rootly supports three operators for joining multiple run conditions:
| Operator | Meaning | When to Use |
| ----------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| **all of** | Every condition must be true. | The default and most common choice. Use when you want the workflow to fire only on a specific combination. |
| **any of** | At least one condition is true. | Use when any of several conditions independently warrants firing (for example, SEV0 *or* Security incident type). |
| **none of** | Every condition must be false. | Use to exclude — for example, "fire on all incidents except Test Kind". |
If a workflow is running more often than expected, verify the join operator. Defaulting to **all of** is the safe choice; **any of** turns N conditions into an OR and dramatically widens the match set.
***
## Per-Condition Operators
Each individual condition picks an operator that determines how Rootly compares the field's current value to the value(s) you configured.
| Operator | Returns true when… | Common Field Types |
| ------------------ | ------------------------------------------------------------------ | ---------------------- |
| `is` | The field's value matches exactly. | Single-select, boolean |
| `is one of` | A single-select field matches any of the provided values. | Single-select |
| `none of` | A single-select field matches none of the provided values. | Single-select |
| `contains any of` | A multi-select field includes at least one of the provided values. | Multi-select |
| `contains all of` | A multi-select field includes all of the provided values. | Multi-select |
| `contains none of` | A multi-select field includes none of the provided values. | Multi-select |
| `is set` | The field has any value. | Any |
| `is unset` | The field has no value. | Any |
### Operator Selection by Field Type
The right operator depends on whether the field stores a single value, multiple values, or a boolean:
* **Boolean fields** (for example, `Is Private`) — use `is set` / `is unset`, or `is true` / `is false` patterns.
* **Single-select fields** (for example, `Severity`, `Kind`, `Status`) — use `is`, `is one of`, `none of`.
* **Multi-select fields** (for example, `Services`, `Teams`, `Functionalities`) — use `contains any of`, `contains all of`, `contains none of`.
* **Presence checks** — `is set` and `is unset` work on any field type and are useful for "fire only when an optional field has been filled in" patterns.
***
## Try It: Condition Evaluator
The widget below evaluates a condition group against a sample incident context so you can see the operator semantics in action before you build the real thing. Pick a preset, tweak the incident fields on the left, adjust the condition rows on the right, and watch the verdict flip. Each row shows whether it individually matched, and the top-level verdict applies the join operator across all rows.
This evaluator mirrors the operator semantics from Rootly's condition engine (`is`, `is one of`, `contains any of`, `contains all of`, `contains none of`, `is none of`, `is set`, `is unset`) exactly. The available fields are a representative subset — production workflows expose more fields including all your custom fields.
***
## Common Condition Recipes
The patterns below cover the majority of real-world **incident workflow** conditions — each is a starting point you can extend with additional conditions joined by **all of** to scope further. Recipes for alert, action item, retrospective, or pulse workflows follow the same operator patterns but with different available fields.
Field examples like **Services**, **Teams**, **Environments**, **Functionalities**, and **Incident Types** can be configured as either single-select or multi-select per workspace (see [Built-in Fields](/configuration/built-in-fields)). The recipes below assume the default multi-select configuration; if your workspace has one of these set to single-select, use `is` / `is one of` / `none of` in place of the contains-family operators.
All values shown in the recipes are the **user-facing labels** visible in the workflow editor. In the raw API and audit-log payloads, some of these correspond to different internal identifiers (for example, the Kind label **Sub Test Incident** is `test_sub`); use the labels shown in the UI when authoring conditions.
### Fire Only on SEV0 Production Incidents
```text theme={null}
all of
Severity is one of: SEV0
Environments contains any of: Production
Kind is: Incident
```
The `Kind is: Incident` clause is the easiest miss — without it, a Test Incident at SEV0 will fire the workflow. This example assumes Environments is multi-select (the default); if it's configured as single-select, use `Environment is: Production` instead.
### Fire Only on Incidents Owned by a Specific Team
```text theme={null}
all of
Teams contains any of: Platform
```
`contains any of` (not `is`) because Teams is multi-select by default. `Teams is one of` would silently fail to match incidents tagged with multiple teams that include Platform. If your workspace has Teams configured as single-select, use `Teams is one of: Platform`.
### Exclude Test Incidents From a Paging Workflow
```text theme={null}
all of
Kind is: Incident
Severity is one of: SEV0, SEV1
```
Or, equivalently, list the kinds to exclude explicitly:
```text theme={null}
none of
Kind is one of: Test Incident, Sub Test Incident, Scheduled Maintenance, Sub Scheduled Maintenance, Backfill Incident
```
The positive form (`Kind is: Incident`) is usually clearer and survives the addition of new Kind values better than an exclusion list. See [Incident Kind](/configuration/incident-kind) for the full list of kinds and what each one triggers.
### Fire Only When a Custom Field Is Filled In
```text theme={null}
all of
Custom Field "Customer Tier" is set
```
Combine with another condition like `Severity is one of: SEV0` to scope further.
### Fire on any status update except cancellation
```text theme={null}
none of
Status is one of: Cancelled
```
Paired with a Status Updated trigger.
***
## How Conditions Interact with Triggers
Triggers are **OR-joined** — if any selected trigger fires, the workflow initiates. Conditions are then evaluated against the incident's state at the moment the trigger fired.
This has two consequences worth knowing:
1. **Triggers do not contribute to conditions.** A workflow with a Status Updated trigger and a `Status is mitigated` condition will fire only when status changes *to* mitigated — but `Status` in the condition refers to the *new* status, not the trigger event.
2. **Conditions evaluate post-trigger.** If a workflow's trigger is Incident Created and a condition references `Mitigated At`, the condition evaluates against the just-created incident — which has no `mitigated_at` yet. Use `is unset` deliberately if you want to fire only on freshly-created incidents.
***
## Best Practices
* **Default to `all of` and verify the operator before saving.** A workflow that fires too often is almost always an `any of` slip.
* **Always include a `Kind is: Incident` condition on any workflow that pages or notifies people.** Without it, Test Incidents will trigger the workflow during training and demos.
* **Prefer positive conditions over exclusion lists.** `Kind is: Incident` survives the introduction of a new kind value; a `none of` exclusion list (`Test Incident, Sub Test Incident, Scheduled Maintenance, Sub Scheduled Maintenance, Backfill Incident`) breaks the next time a kind is added.
* **Use `contains any of` for multi-select fields.** `is` and `is one of` silently fail to match when the field stores multiple values that include your target — use the contains-family operators instead.
* **Test new conditions on Test Incidents first.** Run a `/rootly test` and confirm the workflow fires (or doesn't) as expected before relying on it in production.
***
## Troubleshooting
Check the join operator. The default is **all of** — if it's been switched to **any of**, the workflow fires whenever a single condition matches. Open the workflow's run conditions block and verify the operator is **all of** (or the value you actually intended).
Three common causes:
1. **Trigger mismatch.** Workflows fire only on the triggers you selected. If you expect a workflow to fire on Severity Updated but only Status Updated is selected, it won't run.
2. **Multi-select condition using `is`.** A condition like `Teams is Platform` evaluates to false when Teams contains \[Platform, Database]. Switch to `Teams contains any of: Platform`.
3. **Kind filter exclusion.** If the workflow has `Kind is: Incident` and you're testing with a `/rootly test`, the condition correctly filters out the test incident. Drop the Kind filter temporarily or run a real `/rootly new` for the test.
Add a `Kind is: Incident` condition to scope the workflow to real production incidents only. Test incidents trigger workflows by default, which is desirable when you want to validate workflow logic — but undesirable for workflows that page humans or notify customers.
Custom field conditions evaluate against the field's current value at the time the trigger fires. If the field is populated later in the incident's lifecycle, an Incident Created trigger will see the field as unset. Either change the trigger to a later event (for example, Status Updated) or add a separate workflow keyed off the field being populated.
`none of` returns true when **none** of the listed values match — so an empty/unset field returns true (none of the values match because there's no value to match). If you want the condition to require the field to be set, combine `none of` with `is set` under an **all of** join.
***
## Frequently Asked Questions
No. Rootly's condition editor is flat — every condition in a workflow uses the same join operator (**all of**, **any of**, or **none of**). To express compound boolean logic (for example, `(A AND B) OR (C AND D)`), split into two workflows or restructure as a single workflow with conditions that can be joined under one operator.
Post-update. When a Status Updated trigger fires after an incident moves from Started to Mitigated, conditions reference the post-mitigation state — `Status is mitigated` returns true.
Run conditions use a structured comparison interface (field + operator + value), not Liquid. For dynamic logic, use Liquid in workflow actions instead. Custom field values can still be compared structurally.
Yes. A workflow with zero conditions fires every time any of its triggers fires. This is usually unintended — add at least one condition to scope when the workflow runs.
***
## Related Pages
The umbrella page covering the full workflow execution model.
Workflow type for standard incident lifecycle automation.
The full catalog of actions a workflow can execute once conditions pass.
# Incident Workflows
Source: https://docs.rootly.com/workflows/incident-workflows
Automate incident response in Rootly by triggering workflows on incident events like creation, status changes, severity updates, and field updates.
## Overview
**Incident workflows** are the backbone of automation in Rootly. They run when something meaningful happens to an incident—an incident is created, severity changes, a service is added, a Slack channel is created, responders join the channel, and more. Instead of relying on responders to remember every manual step during a high-stress event, incident workflows let you encode your process once and run it consistently every time.
Incident workflows are especially useful because incidents sit at the center of the response lifecycle. A single workflow can coordinate tooling across chat, paging, ticketing, documentation, and observability—so when an incident changes, everything else stays aligned automatically.
Common use cases include:
* Creating and configuring a Slack or Microsoft Teams channel when an incident begins
* Creating tickets (Jira, Linear, ServiceNow, etc.) based on incident severity, service, or team ownership
* Posting periodic reminders (status updates, stakeholder comms, runbook prompts) while an incident is active
* Paging on-call responders when specific services or severities are involved
* Generating post-incident artifacts (retrospectives, action items) when an incident resolves
* Synchronizing incident metadata to external systems (status page timelines, docs, dashboards)
You can chain workflows across types. For example, an **Alert workflow** can create an incident, which then triggers **Incident Created** or **Incident Started** workflows to run the rest of your incident process.
***
## How Incident Workflows Run
An incident workflow always follows the same execution model:
1. **Trigger event occurs** (for example, *Status Updated*).
2. Rootly evaluates **run conditions** (if configured).
3. If conditions pass, Rootly executes the workflow’s **actions in order**.
Two behaviors are worth calling out early because they shape how you design automations:
* **Triggers are OR’d together.** If you select multiple triggers, *any one* of them can initiate the workflow.
* **Run conditions are your guardrails.** Use conditions to prevent noisy automation and ensure workflows only run when they should (for example, only for SEV0/SEV1, only for certain services, only when visibility is public, etc.).
***
## Create an Incident Workflow
Navigate to **Workflows → Create Workflow → Incident**.
Trigger events define **when** Rootly initiates the workflow. Incident workflows support a broad set of triggers, ranging from lifecycle events (created/started) to field changes (severity/status) to channel and subscriber events.
For example, a workflow can start when the incident **status changes** or when it is manually run using a **Slack command**.
#### Incident trigger events available
The following triggers are available for incident workflows:
* `incident_in_triage`
* `incident_created`
* `incident_started`
* `incident_updated` (catch-all update trigger)
* `title_updated`
* `summary_updated`
* `status_updated`
* `severity_updated`
* `visibility_updated`
Field list changes:
* `environments_added`, `environments_removed`, `environments_updated`
* `incident_types_added`, `incident_types_removed`, `incident_types_updated`
* `services_added`, `services_removed`, `services_updated`
* `functionalities_added`, `functionalities_removed`, `functionalities_updated`
* `teams_added`, `teams_removed`, `teams_updated`
* `causes_added`, `causes_removed`, `causes_updated`
Timeline and post timelines:
* `timeline_updated`
* `status_page_timeline_updated`
Role assignment events:
* `role_assignments_added`
* `role_assignments_removed`
* `role_assignments_updated`
Channel and membership events:
* `slack_channel_created`
* `slack_channel_converted`
* `microsoft_teams_channel_created`
* `google_chat_space_created`
* `user_joined_slack_channel`
* `user_left_slack_channel`
#### Pick `slack_channel_created` when your workflow's actions need the channel
`incident_created` fires the moment the Rootly incident record is created — which can be a beat *before* the Slack channel is finished being created. If your workflow's actions depend on the channel already existing (posting messages or bookmarks into the channel, inviting users, archiving the channel, setting channel metadata, etc.), use **`slack_channel_created`** as the trigger instead. That trigger fires only after the channel is fully ready, so channel-dependent actions can't race against the channel's creation.
A useful rule of thumb:
* **`incident_created`** — for actions that only touch the incident record itself (set fields, page on-call, create Jira ticket, send an email).
* **`slack_channel_created`** — for actions that interact with the incident's Slack channel.
If your team creates incidents by converting an existing Slack channel instead of auto-creating a new one, pair `slack_channel_created` with `slack_channel_converted` so the workflow fires in both scenarios — the created trigger only fires for auto-created channels.
The same pattern applies to `microsoft_teams_channel_created` and `google_chat_space_created` for those platforms.
Subscriber events:
* `subscribers_added`
* `subscribers_removed`
* `subscribers_updated`
Manual trigger:
* `slack_command`
#### Avoid overlapping triggers
Some triggers are “catch-all” events that cover other triggers.
* `incident_updated` is a catch-all trigger for incident updates. If you use it, you should **not** also add field-specific triggers like `status_updated` or `severity_updated` in the same workflow.
* Rootly also prevents certain redundant combinations (for example, selecting triggers that would cause duplicate initiation for the same underlying event).
#### Custom field update triggers
In addition to the built-in triggers above, incident workflows can also trigger from **custom field updates**. These appear in the UI as:
`[CustomField] Updated`
Use these when a particular custom field is a critical step in your incident process (for example, “Customer Impacted,” “Root Cause Category,” or “External Status”).
Run conditions define **which incidents the workflow should apply to**. Conditions can be based on standard incident fields (severity, status, service, environment, teams, etc.) or custom fields you’ve configured in your workspace.
A strong incident workflow typically has at least one condition to avoid unnecessary automation. Examples:
* Only run for incidents where severity is SEV0 or SEV1
* Only run when a specific service is impacted
* Only run when the incident is public
* Only run when a particular team is assigned
You can learn more about how run condition operators work (including how “all of / any of / none of” behaves) in the main workflows overview: [Condition Checks](/workflows/workflows).
Actions define **what the workflow does** once it has initiated and conditions pass. Available actions depend on the applications integrated with your Rootly workspace.
For example, after connecting Jira, Jira actions become available and can be configured to create issues, set fields, assign owners, and link incidents.
#### What actions can an Incident workflow run?
Incident workflows support actions across Rootly and common incident tooling, including (not exhaustive):
* Rootly actions (update incident fields, add timeline entries, create action items, create post-mortems, trigger other workflows)
* Slack and Microsoft Teams actions (create/configure channels, send messages/reminders, update channel metadata, manage channel settings)
* Paging actions (page responders through integrated on-call providers)
* Ticketing/PM tools (Jira, Linear, ServiceNow, Zendesk, etc.)
* Documentation and collaboration tools (Google Drive/Docs, Confluence, Notion, SharePoint, etc.)
* Observability tools (Datadog, New Relic, Grafana, and others depending on integration availability)
Actions run **in order** from top to bottom. If the order matters (for example, create a Slack channel before posting a message into it), place the actions in the sequence you want them executed.
#### Failure behavior matters
By default, **a single failing action halts the workflow run**. If you want a workflow to continue even if an action fails (for example, “post to Slack” should not block “create a Jira ticket”), enable **Skip on Failure** on the actions where continuing is safe.
***
## Best Practices
The best incident workflows are the ones that remain reliable under real incident pressure. These practices help you build workflows that are both powerful and predictable:
* **Start narrow, then expand.** Begin with specific triggers (like `severity_updated`) and tight conditions. Once you trust the behavior, broaden scope if needed.
* **Use conditions as guardrails.** Treat conditions as the safety layer that prevents noisy automation, especially when you use broad triggers like `incident_updated`.
* **Separate “setup” and “ongoing” automation.** A workflow that sets up Slack/tickets is often different from a workflow that posts reminders every 30 minutes.
* **Be intentional with repeat workflows.** If you use recurring reminders, make sure they stop when conditions are no longer true (for example, when status becomes Resolved).
* **Keep actions resilient.** Enable Skip on Failure for non-critical actions so a partial integration outage doesn’t break your entire process.
* **Name workflows by outcome, not mechanics.** Good names describe intent (for example, “Create incident channel and ticket for SEV0/SEV1”), which makes auditing easier later.
* **Validate manual Slack triggering.** If you rely on Slack commands, document the command and ensure it’s memorable and unique for your team.
***
## Frequently Asked Questions
Triggers define **when** a workflow is initiated (for example, when `status_updated` occurs). Run conditions define **which incidents** the workflow should actually apply to. In practice, triggers start the workflow, and conditions prevent it from executing when it shouldn’t.
Use `incident_updated` when you truly want the workflow to consider **any** incident update, then rely on conditions to narrow behavior. If you only care about specific changes (like severity/status/team/service changes), use the specific trigger to reduce noise and unintended runs.
Yes. Incident workflows can include custom-field update triggers that appear as `[CustomField] Updated`. This is useful when a custom field represents a process milestone or decision point.
Yes, if you include the `slack_command` trigger. When command feedback is enabled, Rootly posts an ephemeral confirmation message in Slack (and will indicate if the workflow is configured with a wait/delay).
By default, workflows fail fast: a failing action halts the run. To allow later actions to continue, enable **Skip on Failure** on the actions that should not block the rest of the workflow.
Rootly prevents overlapping triggers that would cause redundant firing (for example, selecting a catch-all update trigger together with the specific field updates it already covers). This avoids duplicate runs and keeps workflow behavior easier to predict.
**Slack Channel Created.** `incident_created` fires when the Rootly incident record exists, which can be a moment before the Slack channel is fully ready. Any action that depends on the channel — sending a message, inviting users, adding a bookmark, archiving the channel — should run on `slack_channel_created` so it can't race against the channel creation. Use `incident_created` only for actions that touch the incident record itself (set fields, page on-call, create a Jira ticket, send an email). If your team creates incidents by converting an existing Slack channel, also select `slack_channel_converted` so the workflow fires for converted channels too. The same distinction applies to `microsoft_teams_channel_created` and `google_chat_space_created`.
***
Need help designing incident workflows that match your process? Contact Rootly Support at [support@rootly.com](mailto:support@rootly.com) or reach out to your onboarding/customer success representative.
***
## Related Pages
Alert-declared incidents are the most common upstream — most incident workflows fire after an alert workflow creates the incident.
The downstream companion — most action items belong to incidents.
The full set of workflow types and when to reach for each.
# Locking Workflows
Source: https://docs.rootly.com/workflows/locking-workflows
Lock a workflow in Rootly to restrict edit access to Admins and Owners, protecting critical automation from accidental or unauthorized changes.
Locking a workflow restricts who can edit it to **Admins** and **Owners** only. Once a workflow is locked, other roles can still see it and it keeps running normally—they just can't modify or delete it. Locking protects the automation your incident response depends on from accidental edits, well-meaning tweaks, and unauthorized changes.
## Why Lock a Workflow?
Workflows often encode critical, hard-won response logic—who gets paged, which channels get created, how stakeholders are notified. As more people gain access to build and edit workflows, a single accidental change to a load-bearing workflow can quietly break part of your response. Locking the workflows you rely on most keeps them stable while still letting your team build and iterate on everything else.
## How to lock or unlock a workflow
Go to your list of workflows in Rootly.
On the far right of the workflow you want to protect, select the **ellipsis** (**⋯**).
Select **Lock** to restrict edit access to Admins and Owners, or **Unlock** to restore normal edit access.
You can also lock or unlock a workflow from the ellipsis while editing it. Only Admins and Owners can lock or unlock a workflow.
## How Do I Know a Workflow Is Locked?
A locked workflow shows a **lock icon** in the workflow list, so it's clear at a glance which workflows are protected. Users without Admin or Owner permissions will find the edit and delete controls unavailable on those workflows.
***
## Related Pages
The umbrella page — locking is one of the safeguards you apply to a workflow.
Understand which trigger events and objects a workflow can react to before locking it.
Conditions govern when a workflow runs — worth double-checking before you lock the workflow.
# Manually Running Workflows
Source: https://docs.rootly.com/workflows/manually-running-workflows
Trigger Rootly workflows manually through Slack commands, Slack modals, and the web interface for on-demand automation, ad-hoc tasks, and one-off operations.
## Overview
Most workflows run automatically when their trigger events occur. Rootly also supports **manual workflow execution**, which is useful when you want on-demand automation (for example, sending a message, creating an external ticket, or running a one-off operational task).
Manual execution is supported through:
* **Slack command** (manual invocation by workflow command)
* **Slack modal** (interactive workflow picker)
* **Web UI** (trigger a workflow directly from an incident)
Manual runs still respect permissions. If you do not have permission to trigger workflows for a given incident, Rootly will block the action.
***
## Manual Runs via Slack
Rootly supports two Slack-based methods for running workflows manually.
### Option 1: Slack command
You can run a workflow using:
```text theme={null}
/rootly workflow
```
This command looks up a workflow by its configured **Slack Command** value.
#### Configure the command on the workflow
Each workflow can be assigned a command in the **Slack Command** field.
#### Required: include Slack Command as a trigger
To run a workflow through Slack, the workflow must explicitly include **Slack Command** as one of its trigger events. If it is not selected, Slack will not run the workflow and will instead guide you to enable the trigger.
#### Important behavior for incident workflows
Incident workflows have an additional requirement:
* **Incident workflows must be triggered from the incident’s Slack channel.**
If you attempt to run an incident workflow from a non-incident channel (or outside incident context), Rootly will not run it.
#### Optional: Slack confirmation message (Command feedback)
If **Command feedback** is enabled on the workflow, Rootly posts an **ephemeral confirmation** to the user in Slack after the workflow is started.
* If the workflow has a configured **Wait** delay, the confirmation indicates the workflow will start after that delay.
* If there is no wait, the confirmation indicates the workflow has started.
Ephemeral confirmations may not be posted if the channel is archived or the user is not in the channel.
***
### Option 2: Slack modal
You can also trigger workflows through Rootly’s Slack modal experience. This is useful when you do not remember the command or want to select from a list interactively.
The modal triggers the selected workflow using the workflow’s command value, the same underlying command-driven logic, and the same permission checks.
***
## Manual Runs via Web UI
You can manually trigger workflows from the Rootly web app for a specific incident.
Navigate to the incident, then select **View Workflow Runs** in the right-hand pane.
From the workflow runs view, select **Trigger Workflow**. You’ll be presented with a list of available workflows. Selecting a workflow triggers it **for the incident you are currently viewing**.
#### Which workflows appear in the web picker
The web UI workflow picker is intentionally constrained:
* Only **incident workflows** are listed
* Only workflows that are **enabled** are listed
* Internal workflows are excluded
This prevents accidentally running disabled or internal-only automation from the incident UI.
#### Web-triggered runs execute immediately
Manual runs triggered from the web UI are executed with **immediate execution** semantics. Practically, this means:
* The run starts right away rather than waiting for a configured **Wait** delay.
Use the web UI when you need to run a workflow immediately against a specific incident.
***
## Slack Command Requirements and Validation
Commands must be:
* **Unique per team**
* **Well-formed**, using only letters, numbers, dashes, underscores, and periods
* Not starting/ending with a period or underscore
* Not containing repeated separators (for example `..` or `__`)
If you do not set a command explicitly, Rootly auto-generates one based on the workflow’s kind and name (and will append a suffix if needed to avoid collisions).
***
## Permissions
Manual workflow triggering is permission-gated.
* Triggering workflows on incidents requires incident update-level access (including the permission that covers triggering workflows).
* For private incidents, Rootly applies private incident permission rules.
If a user lacks permission, the workflow will not run from Slack or the web UI.
***
## Best Practices
* **Always include Slack Command as a trigger** if you want Slack-based manual invocation.
* **Use clear, short commands** and keep naming consistent across teams.
* **Enable Command feedback** so users get immediate confirmation after triggering.
* **Prefer the web UI** when you need to trigger immediately against a specific incident and bypass any wait delay.
* **Validate permissions early** when rolling out workflow tooling to non-admin responders.
***
## Frequently Asked Questions
Only workflows that include **Slack Command** as a trigger can be run via `/rootly workflow `.
The most common reasons are: the workflow is missing the **Slack Command** trigger, you are running it outside the incident’s Slack channel, or you do not have permission to trigger workflows for that incident.
The incident web picker lists only enabled incident workflows to prevent accidental execution of disabled or internal workflows during incident response.
Slack-triggered runs respect the workflow’s configured **Wait** delay. Web-triggered runs execute immediately.
***
## Related Pages
The workflow type designed specifically for manual runs — Slack-command triggered, no automatic firing.
Run conditions still apply on manual runs — the workflow does not bypass them just because a human triggered it.
The umbrella page covering trigger events, run conditions, actions, and execution phases.
# Pulse Workflows
Source: https://docs.rootly.com/workflows/pulse-workflows
Automate responses to code change events from CI/CD systems in Rootly to pre-declare incidents, notify teams, track deployments, and capture rollback context.
## Overview
**Pulse workflows** run automatically when Rootly receives a **pulse**. Pulses are code-change events (for example, pushes, merges, and deployments) streamed into Rootly from supported source control and CI/CD integrations such as GitHub and GitLab.
Pulse workflows are designed for teams that want to connect delivery signals to operational response. Instead of treating deployments as “background noise,” you can use pulses to proactively notify responders, create artifacts for visibility, and even pre-declare incidents when the change itself represents elevated risk.
Pulse workflows are particularly useful for:
* Pre-declaring incidents when risky changes ship, so responders have a shared coordination space ready if impact appears
* Broadcasting deployments into shared channels (for example, release, infrastructure, or product channels) with consistent formatting and context
* Creating follow-up work automatically when a pulse matches a high-risk pattern (specific repo, branch, environment, or payload value)
Pulse workflows only run if pulses are successfully flowing into Rootly. Before building automation, confirm your pulse integration is connected and producing pulse events.
***
## Supported Trigger
Pulse workflows support **one trigger event**:
* **Pulse Created** (`pulse_created`)\
Fires immediately when a new pulse is received in Rootly.
Pulse workflows cannot be triggered manually via Slack command. They only run when Rootly receives a pulse.
***
## Configure a Pulse Workflow
To use a pulse workflow, you must first ensure Rootly is receiving pulses.
Navigate to **Configuration → Pulses** to verify recent pulse events exist. If you do not see pulses, review your integration configuration on the [Pulses](/configuration/pulses) page.
Navigate to **Workflows → Create Workflow → Pulse**.
Because pulse workflows only support one trigger, choose **Pulse Created**. This causes the workflow to initiate as soon as the pulse arrives in Rootly.
***
## Define Run Conditions
Pulse workflows can be filtered using three pulse properties. These conditions let you target only the pulses you care about (for example, production deploys, changes from a specific repository, or events with a specific payload field).
### Source
The **source** represents where the pulse originated from (for example, GitHub or GitLab). Source conditions can optionally use regular expressions, which is helpful when your source naming varies by integration or workspace.
The source is listed on the main **Configuration → Pulses** page.
***
### Label
Each pulse includes a set of **labels** derived from the source system. Labels are stored as an **array of values**, and you can filter on them using operators such as “contains any of” or “contains all of.” Label conditions can also optionally use regular expressions.
You can find labels on the pulse details page:
**Configuration → Pulses → select a pulse**
***
### Payload
Each pulse includes a JSON **payload** containing source-specific data (commit metadata, repository identifiers, environment details, and other fields depending on the integration).
Payload filtering supports:
* **JSONPath** (configured as the payload query) to extract the value you want to evaluate from the pulse JSON
* Optional **regular expression matching** against the extracted value
For example, you can extract a specific field like an environment ID or branch name and require an exact match, partial match, or regex match.
You can find payload data on the pulse details page:
**Configuration → Pulses → select a pulse**
Payload conditions are powerful but should be tested carefully. Incorrect JSONPath expressions or overly broad regex matches can cause workflows to run unexpectedly.
***
## Configure Actions
Pulse workflows do **not** have a fixed action set. The actions available to your workflow depend on which integrations are connected in your Rootly workspace.
Common actions teams use with pulse workflows include:
* Declaring or updating an incident in Rootly
* Sending Slack or Microsoft Teams messages with structured deployment context
* Creating or updating follow-up work items (tickets, action items, tasks) when a pulse matches a risk condition
* Triggering additional workflows (for example, handing off from a “deployment detected” workflow into a more complex automation chain)
### Downstream Workflow Cascades
If a pulse workflow creates or updates an incident, that can immediately trigger **incident workflows** that listen for incident events such as “Incident Created” or “Status Updated.”
When testing pulse workflows that touch incidents, consider temporarily disabling incident workflows or using restrictive run conditions to prevent unintended cascades.
***
## Best Practices
Pulse workflows are most effective when they are scoped intentionally and validated with real examples.
* **Start narrow and expand.** Begin with conditions that target a specific repository, branch, or environment before broadening to all pulses.
* **Prefer labels and payload for precision.** Source-only filters are rarely enough; labels and payload fields usually provide the reliable signal you need.
* **Use pre-declared incidents sparingly.** Pre-declare incidents only when the change itself represents elevated risk, otherwise you may create alert fatigue through too many “false starts.”
* **Test with recent pulses.** Always validate your JSONPath and label logic against real pulse examples visible in the UI.
* **Document intent in the workflow description.** Pulse workflows often encode operational policy (what constitutes a risky change). Make that intent explicit so future maintainers do not guess.
***
## Frequently Asked Questions
No. Pulse workflows run only when Rootly receives a pulse event. Manual Slack commands are not supported for this workflow type.
Pulses are code-change events typically sent by source control or CI/CD systems (for example, GitHub and GitLab). The exact set depends on which integrations your workspace has connected.
Confirm pulses are present in Rootly, verify the workflow is enabled, check that the trigger is Pulse Created, and then review run conditions—especially JSONPath payload filters and label matching.
Yes. Many teams use pulses to pre-declare incidents or create coordination space for risky changes. If you do this, be aware it may trigger incident workflows downstream.
***
Need help designing safe pulse automation? Contact your Rootly onboarding representative or email **[support@rootly.com](mailto:support@rootly.com)**.
***
## Related Pages
Similar low-level event workflows, but for alert events instead of code-change events.
The change events these workflows react to — pushes, merges, deploys from your source-control and CI/CD tools.
The full set of workflow types and when to reach for each.
# Retrospective Workflows
Source: https://docs.rootly.com/workflows/retrospective-workflows
Automate retrospective tasks in Rootly like doc publishing, ticket creation, and notifications triggered by retrospective lifecycle events and milestones.
## Overview
**Retrospective workflows** (also called **post-mortem workflows**) automate the work that happens *after* an incident—capturing learnings, publishing the review, assigning follow-ups, and keeping stakeholders in the loop.
In Rootly, each incident can have an associated retrospective object. Retrospective workflows run when that retrospective changes, letting you standardize what “good follow-through” looks like across every team and every incident. This is especially valuable because retrospective work often spans multiple systems (docs, tickets, chat notifications, leadership updates), and the most common failure mode is simple: people forget steps or do them inconsistently.
Typical uses include:
* Keeping a draft retrospective document in sync as the review evolves
* Publishing a retrospective automatically when it reaches a “Published” state
* Creating action items or tickets and assigning owners when the retrospective is published
* Notifying the right audiences (incident channel, leadership channels, email lists) when a retrospective is ready
Retrospective workflows are triggered by **retrospective events**, not incident events. You *can* still use **incident fields as conditions** (for example, severity, services, teams) to control when the workflow should run—but the trigger itself comes from the retrospective lifecycle.
***
## Supported Triggers
Retrospective workflows support the following trigger events:
* **Post Mortem Created** (`post_mortem_created`): fires when a retrospective is created
* **Post Mortem Updated** (`post_mortem_updated`): fires when a retrospective is updated (catch-all)
* **Status Updated** (`status_updated`): fires when the retrospective status changes
* **Slack Command** (`slack_command`): fires when the workflow is manually executed via Slack command
### “Post Mortem Updated” is a catch-all trigger
If your workflow uses **Post Mortem Updated**, it can fire for any retrospective change. This is powerful, but it’s easy to create noisy automations unless you add tight **run conditions** (for example, “status is published”).
***
## Create a Retrospective Workflow
Navigate to **Workflows → Create Workflow → Retrospective**.
Select one or more trigger events that should initiate your workflow. For example, a workflow can initiate when the **retrospective status changes**.
When you see “Status Updated” in a retrospective workflow, it refers to the **retrospective status**, not the incident status.
Run conditions let you control *which* retrospectives (and incidents) the workflow applies to. Retrospective workflows can evaluate both:
* **Retrospective properties** (most importantly: retrospective status)
* **Incident properties** (severity, services, teams, environments, custom fields, etc.)
#### Retrospective status
Retrospective status is typically one of:
* `draft`
* `published`
A very common pattern is:
* Trigger: **Status Updated**
* Condition: **Retrospective status is published**
* Actions: publish docs, notify leadership, create follow-ups
This ensures you get a clean, one-time automation when the review is officially ready.
#### Incident-based conditions
Even though the workflow is retrospective-triggered, you can narrow it using incident properties. Examples:
* Only run for SEV0/SEV1 incidents
* Only run when a specific service is involved
* Only run when the incident team matches a particular org
For details on condition operators (all of / any of / none of, plus per-field operators like “is”, “is one of”, “contains any of”), see: [Condition Checks](/workflows/workflows).
Actions are what the workflow actually does once it passes conditions. The available actions depend on your integrations, but retrospective workflows commonly automate:
* Document creation and updates (for example, Confluence pages, Google Docs, Notion pages)
* Notifications (Slack messages, Microsoft Teams messages, email)
* Follow-up tracking (create action items, create tickets, assign owners, set due dates)
Some document-creation actions can be configured to **publish** the retrospective automatically (for example, when creating a Confluence page), which is useful when “publishing” is part of your definition of done.
By default, if an action fails, the workflow run halts. If a non-critical action should not block the rest (for example, posting a Slack message), enable **Skip on Failure** for that action.
***
## Best Practices
A retrospective workflow should make your post-incident process *more consistent*, not noisier. These patterns tend to work well in production:
* **Trigger on Status Updated, condition on “published.”** This gives you a clean “one-time publish event” you can treat as a milestone.
* **Use incident severity as a gate.** Many organizations only want leadership notifications and full doc automation for higher severities.
* **Separate “draft upkeep” from “publish actions.”** If you want to keep a doc updated while the review is in progress, put that in a separate workflow from the one that runs when the retrospective is published.
* **Make notifications intentional.** Use different destinations for different audiences (incident channel vs. a leadership channel vs. email).
* **Ensure ownership is created, not implied.** If the workflow creates action items or tickets, assign owners and due dates so the follow-up work doesn’t stall.
***
## Frequently Asked Questions
No. Retrospective workflows trigger from retrospective events (created, updated, status updated, or Slack command). You can still *use incident fields as conditions* to control whether the workflow should run.
In a retrospective workflow, “Status Updated” refers to the **retrospective status** (typically `draft` or `published`), not the incident status.
Use **Status Updated** as the trigger and add a run condition like “retrospective status is published.” This avoids running the workflow on unrelated retrospective changes.
Yes. Retrospective workflows support the **Slack Command** trigger, which lets you run the workflow manually using its configured command.
The most common cause is using **Post Mortem Updated** (a catch-all trigger) without strict conditions. Add conditions like retrospective status, incident severity, or service/team filters to narrow the workflow to the exact cases you want.
***
Need help designing retrospective automation that matches your process? Contact Rootly Support at [support@rootly.com](mailto:support@rootly.com) or reach out to your onboarding/customer success representative.
***
## Related Pages
The object these workflows read and write — retrospective status, templates, and follow-up publishing.
The upstream companion — incident workflows handle the response phase; retrospective workflows handle post-incident.
The full set of workflow types and when to reach for each.
# Standalone Workflows
Source: https://docs.rootly.com/workflows/standalone-workflows
Create manual Slack command-triggered workflows in Rootly for ad-hoc tasks like emailing dashboards, making calls, querying repos, and running scripts.
## Overview
**Standalone workflows** (internally referred to as *Simple workflows*) are workflows that are **triggered exclusively by a Slack command**. They are not tied to any Rootly object such as incidents, action items, alerts, pulses, or retrospectives.
Because they are manually invoked, standalone workflows are ideal for ad-hoc, on-demand tasks where timing and intent are explicitly controlled by a human rather than by system events.
Standalone workflows are particularly useful for:
* Emailing or posting metrics dashboards on demand
* Making ad-hoc phone calls or sending notifications during an incident
* Fetching repository data such as recent GitHub or GitLab commits
* Running utility actions (HTTP requests, Redis queries, AI prompts)
* Triggering other workflows manually as part of a runbook or checklist
Standalone workflows do not evaluate incident, action item, alert, pulse, or retrospective data. They run purely based on user intent at invocation time.
***
## Supported Trigger
Standalone workflows support **only one trigger**:
* **Slack Command** (`slack_command`)
This trigger allows a user to explicitly run the workflow from Slack using a command.
No other triggers are available or supported for this workflow type.
***
## Configure a Standalone Workflow
Navigate to **Workflows → Create Workflow → Standalone**.
Standalone workflows must be invoked via Slack using the pattern:
```text theme={null}
/rootly workflow
```
#### Command behavior and defaults
* If you do not explicitly set a command, Rootly automatically generates one using the pattern:
```text theme={null}
standalone-
```
* Commands must be **unique per team**.
* Commands must:
* Start with a letter or number
* Contain only letters, numbers, dashes, underscores, or periods
* Not begin or end with a period or underscore
* Not contain consecutive separators (for example `..` or `__`)
If a generated command conflicts with an existing one, Rootly automatically appends a short random suffix to ensure uniqueness.
For usability, keep commands short, descriptive, and easy to remember. Standalone workflows are often used under pressure.
***
### Trigger Behavior in Slack
When a user runs:
```text theme={null}
/rootly workflow
```
Rootly will:
1. Locate the workflow by its command
2. Start the workflow run
3. Optionally post an **ephemeral confirmation message** if **Command feedback** is enabled
If the workflow has a configured **Wait** delay, the confirmation message will include the delay duration before execution begins.
***
## Run Conditions
Standalone workflows intentionally have **no run conditions**.
Because these workflows are invoked manually, adding conditional gates based on object state would reduce their usefulness and predictability.
However, standalone workflows **can still use timing controls**, including:
* **Wait before executing**
* Minimum delay: 10 seconds
* Common options include 30 seconds, 1 minute, 5 minutes, 1 hour, and longer intervals
* **Repeat Every / Repeat On**
* Supported repeat intervals include:
* 10 minutes
* 30 minutes
* 1 hour
* 1 day
* 5 days
* Repeat days use the following codes:
* S (Sunday)
* M (Monday)
* T (Tuesday)
* W (Wednesday)
* R (Thursday)
* F (Friday)
* U (Saturday)
These controls are especially useful for scheduled reporting or temporary recurring jobs that you want to start manually and let run for a period of time.
***
## Configure Actions
The actions available in a standalone workflow depend on which integrations are connected in your Rootly workspace. Standalone workflows support a wide range of utility-style actions.
Common examples include:
### Communication and notifications
* Send Slack or Microsoft Teams messages
* Send emails, SMS, WhatsApp messages, or place phone calls
* Create or manage Slack and Microsoft Teams channels
### Reporting and data retrieval
* Email dashboard reports
* Fetch recent alerts or pulses
* Query GitHub or GitLab commits
* Print structured output to Slack for quick inspection
### Automation and utilities
* Run HTTP requests against internal or external APIs
* Execute Redis commands
* Trigger other workflows programmatically
* Invoke AI models (OpenAI, Gemini, Mistral, Anthropic, Watsonx) for summaries or analysis
Standalone workflows are often used as building blocks in runbooks. Keep actions modular and focused so workflows remain easy to reason about.
***
## Execution Behavior and Failure Handling
Actions execute **in order**, from top to bottom.
By default:
* If an action fails, the workflow stops immediately and is marked as failed.
Optional behavior:
* You can enable **Skip on Failure** on individual actions.
* When enabled, Rootly records the failure and continues executing subsequent actions.
This is especially useful for non-critical steps such as logging, notifications, or optional data enrichment.
***
## Best Practices
* **Design for human invocation.** Assume the user triggering the workflow wants immediate, clear feedback.
* **Enable command feedback.** Ephemeral confirmations reduce uncertainty and accidental re-runs.
* **Use standalone workflows for tooling, not policy.** If logic depends on incident state or system events, use a different workflow type.
* **Keep commands discoverable.** Document common commands internally and keep naming consistent.
* **Use repeat controls sparingly.** Long-running repeats should be intentional and well-scoped.
***
## Frequently Asked Questions
No. Standalone workflows only run when triggered by a Slack command. They do not respond to system events.
Yes. They are commonly used during incidents for ad-hoc tasks such as fetching data, sending updates, or running utility actions.
Yes. Standalone workflows can trigger other workflows, making them useful as entry points for manual runbooks.
They are designed to be explicit and predictable. Conditions based on object state would make manual execution harder to reason about.
***
Need help designing powerful manual workflows or runbook commands? Contact your Rootly onboarding representative or email **[support@rootly.com](mailto:support@rootly.com)**.
***
## Related Pages
Standalone workflows fire from Slack commands — the how-to for triggering them from Slack.
The full set of workflow types and when to reach for each.
The umbrella page covering trigger events, run conditions, actions, and execution phases.
# Wait and Repeat
Source: https://docs.rootly.com/workflows/workflow-scheduling
Delay workflow execution, repeat actions on a schedule, and set stop conditions in Rootly that control when a repeating workflow ends or pauses automatically.
## Overview
Workflows support two scheduling controls that can be used independently or together:
* **Wait before executing** — delays the start of actions after a workflow is initiated
* **Repeat every / Repeat on** — re-runs the workflow's actions on a recurring schedule after the first execution
These controls are most commonly used to build reminder workflows, periodic status update messages, and escalation nudges that fire at regular intervals during an incident.
***
## Wait Before Executing
A wait delays the start of actions after the workflow's trigger fires and run conditions are satisfied.
Predefined UI options: 30 seconds, 1 minute, 2 minutes, 5 minutes, 1 hour, 1 day, 3 days, 1 week, 2 weeks, 1 month.
The shortest selectable wait in the UI is **30 seconds**. The underlying validation accepts any value down to 10 seconds, but the predefined options start at 30 seconds. Rootly re-evaluates run conditions after the wait period elapses. If conditions are no longer satisfied at that point, the workflow stops without executing actions.
### Execution Flow With a Wait
```text theme={null}
Trigger fires
→ Run conditions checked → fail → stop
→ Run conditions pass → wait
→ Run conditions re-checked → fail → stop
→ Run conditions pass → actions execute
```
This means a workflow that was eligible when it triggered can still be stopped before it acts if the situation has changed during the wait window — useful for "if still unresolved after 30 minutes" patterns.
***
## Repeat Every
Sets the interval between successive executions after the first run. Predefined UI options: 10 minutes, 30 minutes, 1 hour, 1 day, 5 days. Each repeat cycle re-checks run conditions before executing actions, so the workflow naturally stops repeating when the conditions are no longer true.
### Repeat On (Day-of-Week Filter)
Restricts repeats to specific days of the week. Select any combination of days; repeat cycles that fall outside the selected days are skipped.
| Day | Code used internally |
| --------- | -------------------- |
| Sunday | S |
| Monday | M |
| Tuesday | T |
| Wednesday | W |
| Thursday | R |
| Friday | F |
| Saturday | U |
Use **Repeat on** with a **1 day** interval to build weekday-only reminder workflows without needing separate conditions for weekends.
### Execution Flow With Repeat
```text theme={null}
Trigger fires
→ Run conditions checked → pass
→ Wait (if configured) → Run conditions re-checked → fail → stop
→ Run conditions pass → actions execute
→ Stop-repeat conditions checked → any match → stop
→ Wait for repeat interval
→ Run conditions re-checked → fail → stop
→ Run conditions pass → (wait if configured) → Run conditions re-checked → fail → stop
→ Run conditions pass → actions execute
→ … continues until a stop condition is met
```
***
## Stop Repeat Conditions
Without explicit stop conditions, a repeating workflow continues indefinitely as long as run conditions remain true. Stop repeat conditions give you precise control over when repeating ends.
Any one of the following conditions stops the loop:
The workflow stops after executing this many times. Accepts values from **2 to 100**.
Use this when you want a fixed number of reminders regardless of how long the incident stays open.
The workflow stops once this much time has elapsed since the first execution. Options: **10 minutes, 30 minutes, 1 hour, 1 day, 5 days**.
Use this to cap the reminder window — for example, stop sending updates after 1 day even if the incident is still active.
Stop repeat conditions are evaluated using OR logic — the workflow stops as soon as any single condition is met, not when all conditions are met.
***
## Common Patterns
Configure:
* **Repeat every:** 30 minutes
* **Time since first run:** 1 hour
* **Run condition:** incident status is not Resolved
The workflow sends a reminder at 0, 30, and 60 minutes and then stops — or stops earlier if the incident resolves.
Configure:
* **Repeat every:** 1 day
* **Repeat on:** Monday, Tuesday, Wednesday, Thursday, Friday
* **Run condition:** incident is still active
The workflow fires once per weekday and skips Saturdays and Sundays automatically.
Configure:
* **Wait:** 30 minutes
* **Run condition:** incident severity is P1 and status is not Resolved
The workflow initiates when a P1 opens, waits 30 minutes, re-checks whether it is still open and still P1, then fires the escalation action. If the incident resolved during the wait, no action is taken.
Configure:
* **Wait:** 1 hour
* No repeat
The workflow fires once, one hour after the trigger, as long as run conditions still hold. Useful for a one-time follow-up nudge without building a full repeat loop.
***
## Troubleshooting
The most common cause is run conditions becoming false. Rootly re-evaluates run conditions before every repeat cycle. If the incident moved to a status, severity, or field value that no longer satisfies the conditions, repeating stops.
Check the workflow run history to see which condition evaluation caused the stop. Also verify that no stop repeat condition (max repeats or time since first run) was reached.
Confirm that **Repeat every** is set. A wait-only workflow (no repeat interval) executes once after the delay and does not loop. Also check whether a stop repeat condition was already satisfied after the first run — for example, a **Maximum number of repeats** of 2 means the workflow runs twice total (the initial run plus one repeat).
Conditions are checked at trigger time and again after any wait period, but not continuously during the wait. If conditions briefly become false and then true again during a wait window, the post-wait check is what matters. Design conditions around the state you care about at execution time, not the state at trigger time.
***
## Related Pages
The umbrella page covering trigger events, run conditions, actions, and execution phases.
Conditions run at trigger time and re-check after any wait period — the mechanics scheduled workflows rely on.
The opposite pattern — trigger a workflow on demand from Slack, the web UI, or a Slack command.
# Workflow Types
Source: https://docs.rootly.com/workflows/workflow-types
Understand the six workflow types (incident, post-mortem, action item, alert, pulse, and standalone) and the trigger events available for each.
## Overview
Rootly workflows are grouped into **six workflow types**. The workflow type determines two things:
1. **What object the workflow runs against** (incident, alert, action item, etc.)
2. **Which trigger events are available** (because not every object emits the same events)
Most workflow types are tied to a Rootly object and are triggered by changes to that object. For example, an **Incident workflow** can trigger when an incident’s status changes, while an **Action Item workflow** can trigger when a due date changes.
**Standalone workflows** (called **Simple** workflows in Rootly’s internal model) are different: they do not depend on any Rootly object and can only be triggered manually through a Slack command.
You can chain workflow types together. For example, an **Alert workflow** can create an incident, which can then trigger one or more **Incident workflows** configured for **Incident Created** or **Incident Started**.
## How Trigger Events Work
Workflows are **not executed in a fixed order**. A workflow runs when:
1. One of its **trigger events** occurs (triggers are evaluated using OR logic), and then
2. Its **run conditions** pass (if configured)
Because workflows are event-driven, two workflows can run “in parallel” if they share the same trigger, and a workflow configured with multiple triggers will run whenever *any* of them occur.
### Avoid Overlapping Triggers
Some triggers are **catch-all** events (for example, **Incident Updated**) that already include more specific triggers (like **Status Updated** or **Severity Updated**). Rootly prevents overlapping configurations to avoid duplicate runs and hard-to-debug behavior.
***
## Workflow Types and Trigger Events
Below are the trigger events grouped by workflow type. These names reflect how Rootly defines triggers internally and how they appear in the workflow builder.
***
## Incident Workflows
Incident workflows trigger from incident lifecycle changes, field updates, timeline events, channel events, and subscriber changes.
| Trigger | When it’s triggered |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| **Incident In Triage** | When an incident enters triage (used for triage-first workflows). |
| **Incident Created** | When an incident record is created in Rootly. |
| **Incident Started** | When an incident is started (for teams that distinguish creation vs start). |
| **Incident Updated** | Catch-all trigger for incident updates. Use this instead of specific field update triggers when you want “any incident change.” |
| **Status Updated** | When incident status changes. |
| **Severity Updated** | When incident severity changes. |
| **Title Updated** | When incident title changes. |
| **Summary Updated** | When incident summary changes. |
| **Visibility Updated** | When incident visibility changes (for example, public vs private, depending on your configuration). |
| **Environments Added** | When a value is added to environments. |
| **Environments Removed** | When a value is removed from environments. |
| **Environments Updated** | When the environments list changes (covers add/remove). |
| **Incident Types Added** | When a value is added to incident types. |
| **Incident Types Removed** | When a value is removed from incident types. |
| **Incident Types Updated** | When incident types list changes (covers add/remove). |
| **Services Added** | When a service is added. |
| **Services Removed** | When a service is removed. |
| **Services Updated** | When services list changes (covers add/remove). |
| **Functionalities Added** | When a functionality is added. |
| **Functionalities Removed** | When a functionality is removed. |
| **Functionalities Updated** | When functionalities list changes (covers add/remove). |
| **Teams Added** | When a team is added. |
| **Teams Removed** | When a team is removed. |
| **Teams Updated** | When teams list changes (covers add/remove). |
| **Causes Added** | When a cause is added. |
| **Causes Removed** | When a cause is removed. |
| **Causes Updated** | When causes list changes (covers add/remove). |
| **Role Assignments Added** | When an incident role assignment is added. |
| **Role Assignments Removed** | When an incident role assignment is removed. |
| **Role Assignments Updated** | When a role assignment changes (assign/reassign/unassign). |
| **Timeline Updated** | When a timeline event is added, updated, or removed. |
| **Status Page Timeline Updated** | When a status page timeline event is added, updated, or removed. |
| **Slack Channel Created** | When an incident Slack channel is created for the incident. |
| **Slack Channel Converted** | When an existing Slack channel is converted into an incident channel. |
| **Microsoft Teams Channel Created** | When a Microsoft Teams channel is created for the incident (if enabled). |
| **Google Chat Space Created** | When a Google Chat space is created for the incident (if enabled). |
| **User Joined Slack Channel** | When a user joins the incident Slack channel. |
| **User Left Slack Channel** | When a user leaves the incident Slack channel. |
| **Subscribers Added** | When a subscriber is added. |
| **Subscribers Removed** | When a subscriber is removed. |
| **Subscribers Updated** | When subscriber list changes (covers add/remove). |
| **Slack Command** | When the workflow is manually triggered via Slack command. |
### Important: "Incident Created" vs "Slack Channel Created"
These two triggers fire at slightly different points in the incident lifecycle, and the choice matters for any workflow that touches the Slack channel.
* **Incident Created** fires when the Rootly incident record is created. This can happen a beat before the Slack channel is fully created.
* **Slack Channel Created** fires only after the incident's Slack channel is fully ready to receive messages, invites, and bookmarks.
**Which to pick:**
* If the workflow's actions only touch the incident record itself — set fields, page on-call, create a Jira ticket, send an email — use **Incident Created**.
* If any action depends on the Slack channel existing — sending a message into the channel, inviting users, adding bookmarks, archiving the channel, posting to a thread — use **Slack Channel Created** instead.
If your team creates incidents by converting an existing Slack channel (not by auto-creating a new one), pair **Slack Channel Created** with **Slack Channel Converted** so the workflow fires in both cases. The `slack_channel_created` trigger only fires for auto-created channels; conversions are covered by `slack_channel_converted`.
Don't select both **Incident Created** and **Slack Channel Created** for the same workflow unless you explicitly want it to run twice. Rootly guards against trigger overlap patterns that would produce redundant firing.
The same timing distinction applies to **Microsoft Teams Channel Created** and **Google Chat Space Created** for workflows that interact with those platforms.
***
## Post-mortem Workflows (Retrospectives)
Post-mortem workflows trigger based on retrospective creation/updates and retrospective status changes.
| Trigger | When it’s triggered |
| ----------------------- | ---------------------------------------------------------- |
| **Post Mortem Created** | When a post-mortem (retrospective) is created. |
| **Post Mortem Updated** | Catch-all trigger for post-mortem updates. |
| **Status Updated** | When post-mortem status changes. |
| **Slack Command** | When the workflow is manually triggered via Slack command. |
Post-mortem workflows do not use a dedicated “Causes Updated” trigger. If your process depends on causes, use **Post Mortem Updated** (with run conditions) or condition on causes directly where supported.
***
## Action Item Workflows
Action item workflows trigger based on action item lifecycle changes and field updates. They also support a catch-all update trigger.
| Trigger | When it’s triggered |
| ------------------------- | -------------------------------------------------------------------------------- |
| **Action Item Created** | When an action item is created. |
| **Action Item Updated** | Catch-all trigger for action item updates. |
| **Assigned User Updated** | When the assigned user changes. |
| **Summary Updated** | When the summary changes. |
| **Description Updated** | When the description changes. |
| **Status Updated** | When the status changes. |
| **Priority Updated** | When the priority changes. |
| **Due Date Updated** | When the due date changes. |
| **Teams Updated** | When the assigned team(s) changes. |
| **Incident Updated** | When the linked incident updates (useful when action items are incident-driven). |
| **Slack Command** | When the workflow is manually triggered via Slack command. |
***
## Alert Workflows
Alert workflows trigger from alert creation and alert lifecycle changes.
| Trigger | When it’s triggered |
| ------------------------ | ------------------------------------ |
| **Alert Created** | When an alert is received in Rootly. |
| **Alert Status Updated** | When an alert status changes. |
***
## Pulse Workflows
Pulse workflows trigger from pulse ingestion events.
| Trigger | When it’s triggered |
| ----------------- | ----------------------------------- |
| **Pulse Created** | When a pulse is received in Rootly. |
***
## Standalone Workflows (Simple)
Standalone workflows do not run against a Rootly object. They are manually triggered and are ideal for “utility” workflows (for example, running a set of Slack actions on demand).
| Trigger | When it’s triggered |
| ----------------- | ---------------------------------------------------------- |
| **Slack Command** | When the workflow is manually triggered via Slack command. |
***
## Best Practices
* **Prefer specific triggers when possible.** If you only care about severity changes, use **Severity Updated** rather than **Incident Updated**.
* **Use catch-all triggers intentionally.** Catch-all triggers are powerful, but can lead to high execution volume if paired with broad conditions.
* **Avoid redundancy.** If two triggers represent the same functional event for your use case, pick the one you actually want to represent “start.”
* **Design for chaining.** A common pattern is: Alert workflow → create incident → Incident workflow → run structured response actions.
* **Test with narrow scopes first.** Start by scoping run conditions tightly (severity/team/service), confirm behavior, then expand.
***
## Frequently Asked Questions
Workflows are event-driven. They execute when their trigger event fires and their conditions pass—not because they are “first” or “second” in a sequence. If multiple workflows listen to the same trigger, they may run around the same time.
Use a catch-all trigger when you truly want to react to *any* update on that object, then refine behavior using run conditions. If you only care about a specific change (like Status Updated), prefer the specific trigger to reduce noise and unintended execution.
Slack Command triggers are available on several workflow types (including Incident, Post-mortem, Action Item, and Standalone). Alert and Pulse workflows are designed to run from ingestion and lifecycle events instead of manual command triggers.
Yes. If a workflow action causes another object event (for example, creating an incident from an alert), any workflows listening for that downstream event can run. This is a common way to build multi-stage automation.
Some triggers are broad and implicitly include other triggers (for example, an object-level “Updated” trigger covering multiple specific field changes). Overlaps can cause duplicate workflow runs and confusing behavior, so Rootly prevents or warns on combinations that represent the same logical event.
***
## Related Pages
The umbrella page covering trigger events, run conditions, actions, and execution phases.
How run conditions gate whether a workflow's actions execute after a trigger fires.
The complete catalog of actions available across all workflow types.
# Rootly workflows for incident response automation
Source: https://docs.rootly.com/workflows/workflows
Learn how Rootly workflows automate incident response through trigger events, conditions, actions, execution phases, and scheduling for end-to-end automation.
## Overview
Workflows are Rootly’s automation engine. They let you run structured actions automatically (or manually) based on:
* **Trigger events** (what starts a workflow run)
* **Run conditions** (what must be true before actions execute)
* **Actions** (what Rootly and your integrations do when conditions pass)
Workflows are designed to remove repetitive coordination tasks during incident response and standardize follow-up processes across teams.
### Common Automation Patterns
Examples of things teams commonly automate with workflows:
* Create or manage an incident communication channel (Slack or Microsoft Teams)
* Post periodic reminders to keep status pages and stakeholders updated
* Notify internal teams (for example, legal, security, or customer support) when high-impact incidents occur
* Create tickets in external systems (for example, Jira or Linear) based on impacted services or teams
* Create a conferencing bridge (for example, Zoom or Google Meet) for high severity incidents
* Page on-call responders via your paging provider when specific services are impacted
* Create or update retrospective documents and templates after resolution
If you need help configuring a workflow or cannot find a supported pattern, contact Rootly via Slack or email [**support@rootly.com**](mailto:support@rootly.com).
***
## Workflows at a Glance
This section maps the key fields you configure on a workflow to how Rootly behaves when it runs.
| **Field** | **What it controls** |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | A human-readable identifier for the workflow. |
| **Description** | A detailed explanation of what the workflow does and when it should be used. |
| **Workflow folder** | Optional grouping used for organization and filtering. Folders do not affect execution behavior. |
| **Enabled** | When disabled, the workflow does not run automatically from events. Manual Slack command runs may still be possible if the workflow is discoverable by command and permissions allow it. |
| **Slack command** | The command value used to trigger a workflow manually through Slack. If you do not set one at creation time, Rootly generates a default command. |
| **Command feedback enabled** | When enabled, Rootly posts an ephemeral Slack confirmation to the requesting user when the workflow is triggered via Slack command (including indicating the configured wait delay when applicable). |
| **Repeat every / Repeat on** | Scheduling controls used to run a workflow repeatedly after the initial trigger. Repeat behavior continues only while run conditions remain true. |
| **Wait before executing** | A delay before actions begin. Rootly enforces a minimum delay of 10 seconds. Rootly re-checks run conditions after the wait period before executing actions. |
| **Trigger events** | Events that initiate a workflow run. Trigger events are OR-joined (any selected event can initiate a run). |
| **Run condition operator** | How Rootly joins multiple run conditions: **all of**, **any of**, or **none of**. |
| **Run conditions** | The rule set that must be satisfied before actions execute. Available condition fields depend on workflow type. |
| **Actions** | The steps executed when run conditions pass. Actions are ordered and run in sequence. Available actions depend on workflow type and your enabled integrations. |
### Slack Command Defaults and Uniqueness
If you do not define a Slack command explicitly, Rootly generates a default command derived from:
* The workflow **kind** and the workflow **name** (not just the name)
If the generated command collides with an existing command in the same team, Rootly appends a suffix to keep commands unique.
Slack commands must be unique within a team and must follow strict formatting rules (letters, numbers, dashes, underscores, and periods with restrictions on placement).
***
## How Workflows Execute
Workflow execution has three major phases:
1. **Initiation**
2. **Condition check**
3. **Execution**
These phases are consistent across workflow types (incident, post-mortem, action item, alert, pulse, and standalone).
***
## Phase 1: Initiation
A workflow run begins when one of its configured trigger events is met.
### Trigger Events Are OR-Joined
When you select multiple trigger events, Rootly evaluates them using OR logic:
* If **any** selected trigger event occurs, the workflow run initiates.
Example: if you select “Status Updated” and “Severity Updated,” the workflow initiates when either status changes or severity changes.
### Trigger Overlap Rules
Some triggers are intentionally considered “catch-all” triggers and overlap with more specific triggers. Rootly enforces rules to prevent redundant or confusing configurations.
Common examples:
* A catch-all “updated” trigger covers all attribute updates and should not be combined with field-specific update triggers.
* Some channel creation triggers overlap with incident creation triggers and cannot be selected together.
If you see an error while saving triggers, check whether you selected both a catch-all update trigger and one or more specific update triggers.
***
## Phase 2: Condition Check
After initiation, Rootly evaluates **run conditions** against the incident (or alert, action item, pulse, retrospective) to decide whether the workflow's actions should execute. Conditions combine under a join operator (**all of**, **any of**, **none of**), and each individual condition uses a per-condition operator (`is`, `is one of`, `contains any of`, `is set`, etc.) appropriate to the field type.
The default join operator is **all of** — if a workflow is running more often than expected, that's usually the first thing to check.
For the full conditions reference — every operator, common condition recipes, field-type-by-operator guidance, and troubleshooting workflows that fire wrong — see **[Workflow Conditions](/workflows/conditions)**.
***
## Phase 3: Execution
If run conditions pass, Rootly executes actions in order.
### Action Ordering
Actions run sequentially in the order they are listed in the workflow editor.
* If the workflow has multiple actions, the earlier actions run first.
* Actions can be individually disabled.
* Each action's output is available to subsequent actions via Liquid template variables. See [Task Output Variables](/liquid/task-output-variables) for syntax and examples.
### Failure Behavior and Skip on Failure
By default:
* If an action fails, the workflow run halts and later actions do not execute.
If **Skip on Failure** is enabled for an action:
* Rootly records the failure for that action
* Rootly continues executing subsequent actions
***
## Scheduling Behavior
Workflows support delays and repeating schedules using the **Wait before executing** and **Repeat every / Repeat on** controls. These are most commonly used for reminder workflows, periodic status updates, and escalation nudges.
Key behaviors:
* Rootly re-evaluates run conditions after a wait period and before every repeat cycle. If conditions are no longer true, the workflow stops.
* Stop repeat conditions (maximum number of repeats, time since first run) give explicit control over when a repeat loop ends.
For available intervals, day-of-week options, stop conditions, execution flow details, and example patterns, see [Wait and Repeat](/workflows/workflow-scheduling).
***
## Manual Runs (Slack and Web)
Workflows can also be triggered manually, which is useful for ad-hoc operational tasks.
* Slack command runs require the workflow to include **Slack Command** as a trigger.
* Incident workflows have additional context requirements and permission checks.
* Web UI triggering from an incident runs the workflow immediately for that specific incident and only lists enabled incident workflows.
See [Manually Running Workflows](/workflows/manually-running-workflows) for a complete, code-aligned guide.
***
## Organizing Workflows
Workflows are easier to maintain when they are organized consistently.
| **Area** | **What it’s used for** |
| ---------------------- | ------------------------------------------------------------------------ |
| **All workflows** | A global view of workflows in your organization. |
| **Folders** | Optional organization structure for grouping workflows. |
| **Enabled / Disabled** | Quick control for automatic execution. |
| **Expand / Collapse** | Quickly view trigger and condition summaries without editing. |
| **Workflow summary** | Displays configured triggers, conditions, and actions for fast auditing. |
| **Filter and sort** | Locate workflows by folder, enabled status, and other attributes. |
***
## Best Practices
* **Use descriptive names and descriptions.** Treat workflows like operational code: explain intent, scope, and expected behavior.
* **Avoid trigger overlap.** Do not combine catch-all update triggers with field-specific update triggers unless you are intentionally broadening behavior.
* **Start with conservative conditions.** Begin with strict conditions, validate behavior, then widen scope intentionally.
* **Validate failure behavior.** Decide which actions should halt the run versus which can be skipped safely.
* **Use wait and repeat carefully.** When repeating workflows, confirm the run conditions stay true long enough for your reminder cadence.
* **Document ownership.** Use folders and naming conventions so teams know which workflows are actively maintained versus legacy.
***
## Troubleshooting
### A Workflow Runs When Not All Conditions Are Met
Most commonly:
* The run condition operator is set to **any of** rather than **all of**.
* A catch-all update trigger is firing more frequently than expected.
### A Slack command cannot find the workflow
Most commonly:
* The Slack command value does not match the workflow’s configured command.
* The workflow does not include **Slack Command** as a trigger.
### A Workflow Does Not Run Automatically
Most commonly:
* The workflow is disabled.
* The trigger event selected is not the event that is actually occurring.
* Run conditions are too restrictive.
***
## Frequently Asked Questions
No. Workflows are initiated when their trigger events occur. There is no global ordering across workflows, and multiple workflows may initiate independently as events happen.
By default, the workflow run halts when an action fails. If you enable Skip on Failure for an action, Rootly records the failure and continues to the next action.
Disabled workflows do not run automatically from trigger events. Depending on configuration and permissions, some manual Slack command runs may still be possible. If you want to prevent all manual execution, remove Slack Command as a trigger and/or restrict permissions.
Repeating workflows stop when run conditions no longer evaluate as true, or when a stop repeat condition is met — such as a maximum number of repeats or a time-since-first-run limit. See [Wait and Repeat](/workflows/workflow-scheduling) for full details.
Go to **Settings > Organization** and select a Slack channel under **Notify workflow failures channel**. When a workflow fails, Rootly will post a message to that channel with the workflow name, the failed task, and any error output.
No. Workflows only trigger on new state transitions that happen after the workflow exists. If you publish a workflow that archives Slack channels 24 hours after an incident reaches Closed, the workflow won't fire on incidents already in Closed status — it watches for *new* transitions to Closed going forward. The same applies to every trigger event: workflows don't backfill against historical state.
To act on existing incidents, run the workflow manually on each affected one — see [Manually Running Workflows](/workflows/manually-running-workflows).
***
## Related Pages
The full set of workflow types — incident, alert, action item, pulse, retrospective, standalone — and when to reach for each.
How run conditions decide whether a workflow's actions execute after a trigger fires.
The complete catalog of actions a workflow can execute, grouped by category.