The aws:ssmcontacts/plan:Plan resource, part of the Pulumi AWS provider, defines escalation plans that control when and how AWS Systems Manager Incident Manager engages contacts during incidents. This guide focuses on two capabilities: single-stage engagement timing and multi-stage escalation with parallel targets.
Plans reference existing SSM Contacts and contact channels by ARN. The examples are intentionally small. Combine them with your own contact definitions and notification channels.
Define a plan for a contact resource
Most incident response workflows start by creating a contact and defining when to engage them.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const contact = new aws.ssmcontacts.Contact("contact", {
alias: "alias",
type: "PERSONAL",
});
const plan = new aws.ssmcontacts.Plan("plan", {
contactId: contact.arn,
stages: [{
durationInMinutes: 1,
}],
});
import pulumi
import pulumi_aws as aws
contact = aws.ssmcontacts.Contact("contact",
alias="alias",
type="PERSONAL")
plan = aws.ssmcontacts.Plan("plan",
contact_id=contact.arn,
stages=[{
"duration_in_minutes": 1,
}])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ssmcontacts"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
contact, err := ssmcontacts.NewContact(ctx, "contact", &ssmcontacts.ContactArgs{
Alias: pulumi.String("alias"),
Type: pulumi.String("PERSONAL"),
})
if err != nil {
return err
}
_, err = ssmcontacts.NewPlan(ctx, "plan", &ssmcontacts.PlanArgs{
ContactId: contact.Arn,
Stages: ssmcontacts.PlanStageArray{
&ssmcontacts.PlanStageArgs{
DurationInMinutes: pulumi.Int(1),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var contact = new Aws.SsmContacts.Contact("contact", new()
{
Alias = "alias",
Type = "PERSONAL",
});
var plan = new Aws.SsmContacts.Plan("plan", new()
{
ContactId = contact.Arn,
Stages = new[]
{
new Aws.SsmContacts.Inputs.PlanStageArgs
{
DurationInMinutes = 1,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ssmcontacts.Contact;
import com.pulumi.aws.ssmcontacts.ContactArgs;
import com.pulumi.aws.ssmcontacts.Plan;
import com.pulumi.aws.ssmcontacts.PlanArgs;
import com.pulumi.aws.ssmcontacts.inputs.PlanStageArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var contact = new Contact("contact", ContactArgs.builder()
.alias("alias")
.type("PERSONAL")
.build());
var plan = new Plan("plan", PlanArgs.builder()
.contactId(contact.arn())
.stages(PlanStageArgs.builder()
.durationInMinutes(1)
.build())
.build());
}
}
resources:
contact:
type: aws:ssmcontacts:Contact
properties:
alias: alias
type: PERSONAL
plan:
type: aws:ssmcontacts:Plan
properties:
contactId: ${contact.arn}
stages:
- durationInMinutes: 1
The contactId property links the plan to a specific contact. The stages array defines escalation timing; each stage’s durationInMinutes controls how long to wait before moving to the next stage. Here, the plan engages the contact immediately (1 minute after incident creation).
Build multi-stage escalation with parallel targets
Complex incident response requires escalating through multiple contacts and channels, with some marked as essential and others as optional backups.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const escalationPlan = new aws.ssmcontacts.Contact("escalation_plan", {
alias: "escalation-plan-alias",
type: "ESCALATION",
});
const contactOne = new aws.ssmcontacts.Contact("contact_one", {
alias: "alias",
type: "PERSONAL",
});
const contactTwo = new aws.ssmcontacts.Contact("contact_two", {
alias: "alias",
type: "PERSONAL",
});
const test = new aws.ssmcontacts.Plan("test", {
contactId: escalationPlan.arn,
stages: [{
durationInMinutes: 0,
targets: [
{
contactTargetInfo: {
isEssential: false,
contactId: contactOne.arn,
},
},
{
contactTargetInfo: {
isEssential: true,
contactId: contactTwo.arn,
},
},
{
channelTargetInfo: {
retryIntervalInMinutes: 2,
contactChannelId: channel.arn,
},
},
],
}],
});
import pulumi
import pulumi_aws as aws
escalation_plan = aws.ssmcontacts.Contact("escalation_plan",
alias="escalation-plan-alias",
type="ESCALATION")
contact_one = aws.ssmcontacts.Contact("contact_one",
alias="alias",
type="PERSONAL")
contact_two = aws.ssmcontacts.Contact("contact_two",
alias="alias",
type="PERSONAL")
test = aws.ssmcontacts.Plan("test",
contact_id=escalation_plan.arn,
stages=[{
"duration_in_minutes": 0,
"targets": [
{
"contact_target_info": {
"is_essential": False,
"contact_id": contact_one.arn,
},
},
{
"contact_target_info": {
"is_essential": True,
"contact_id": contact_two.arn,
},
},
{
"channel_target_info": {
"retry_interval_in_minutes": 2,
"contact_channel_id": channel["arn"],
},
},
],
}])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ssmcontacts"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
escalationPlan, err := ssmcontacts.NewContact(ctx, "escalation_plan", &ssmcontacts.ContactArgs{
Alias: pulumi.String("escalation-plan-alias"),
Type: pulumi.String("ESCALATION"),
})
if err != nil {
return err
}
contactOne, err := ssmcontacts.NewContact(ctx, "contact_one", &ssmcontacts.ContactArgs{
Alias: pulumi.String("alias"),
Type: pulumi.String("PERSONAL"),
})
if err != nil {
return err
}
contactTwo, err := ssmcontacts.NewContact(ctx, "contact_two", &ssmcontacts.ContactArgs{
Alias: pulumi.String("alias"),
Type: pulumi.String("PERSONAL"),
})
if err != nil {
return err
}
_, err = ssmcontacts.NewPlan(ctx, "test", &ssmcontacts.PlanArgs{
ContactId: escalationPlan.Arn,
Stages: ssmcontacts.PlanStageArray{
&ssmcontacts.PlanStageArgs{
DurationInMinutes: pulumi.Int(0),
Targets: ssmcontacts.PlanStageTargetArray{
&ssmcontacts.PlanStageTargetArgs{
ContactTargetInfo: &ssmcontacts.PlanStageTargetContactTargetInfoArgs{
IsEssential: pulumi.Bool(false),
ContactId: contactOne.Arn,
},
},
&ssmcontacts.PlanStageTargetArgs{
ContactTargetInfo: &ssmcontacts.PlanStageTargetContactTargetInfoArgs{
IsEssential: pulumi.Bool(true),
ContactId: contactTwo.Arn,
},
},
&ssmcontacts.PlanStageTargetArgs{
ChannelTargetInfo: &ssmcontacts.PlanStageTargetChannelTargetInfoArgs{
RetryIntervalInMinutes: pulumi.Int(2),
ContactChannelId: pulumi.Any(channel.Arn),
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var escalationPlan = new Aws.SsmContacts.Contact("escalation_plan", new()
{
Alias = "escalation-plan-alias",
Type = "ESCALATION",
});
var contactOne = new Aws.SsmContacts.Contact("contact_one", new()
{
Alias = "alias",
Type = "PERSONAL",
});
var contactTwo = new Aws.SsmContacts.Contact("contact_two", new()
{
Alias = "alias",
Type = "PERSONAL",
});
var test = new Aws.SsmContacts.Plan("test", new()
{
ContactId = escalationPlan.Arn,
Stages = new[]
{
new Aws.SsmContacts.Inputs.PlanStageArgs
{
DurationInMinutes = 0,
Targets = new[]
{
new Aws.SsmContacts.Inputs.PlanStageTargetArgs
{
ContactTargetInfo = new Aws.SsmContacts.Inputs.PlanStageTargetContactTargetInfoArgs
{
IsEssential = false,
ContactId = contactOne.Arn,
},
},
new Aws.SsmContacts.Inputs.PlanStageTargetArgs
{
ContactTargetInfo = new Aws.SsmContacts.Inputs.PlanStageTargetContactTargetInfoArgs
{
IsEssential = true,
ContactId = contactTwo.Arn,
},
},
new Aws.SsmContacts.Inputs.PlanStageTargetArgs
{
ChannelTargetInfo = new Aws.SsmContacts.Inputs.PlanStageTargetChannelTargetInfoArgs
{
RetryIntervalInMinutes = 2,
ContactChannelId = channel.Arn,
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ssmcontacts.Contact;
import com.pulumi.aws.ssmcontacts.ContactArgs;
import com.pulumi.aws.ssmcontacts.Plan;
import com.pulumi.aws.ssmcontacts.PlanArgs;
import com.pulumi.aws.ssmcontacts.inputs.PlanStageArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var escalationPlan = new Contact("escalationPlan", ContactArgs.builder()
.alias("escalation-plan-alias")
.type("ESCALATION")
.build());
var contactOne = new Contact("contactOne", ContactArgs.builder()
.alias("alias")
.type("PERSONAL")
.build());
var contactTwo = new Contact("contactTwo", ContactArgs.builder()
.alias("alias")
.type("PERSONAL")
.build());
var test = new Plan("test", PlanArgs.builder()
.contactId(escalationPlan.arn())
.stages(PlanStageArgs.builder()
.durationInMinutes(0)
.targets(
PlanStageTargetArgs.builder()
.contactTargetInfo(PlanStageTargetContactTargetInfoArgs.builder()
.isEssential(false)
.contactId(contactOne.arn())
.build())
.build(),
PlanStageTargetArgs.builder()
.contactTargetInfo(PlanStageTargetContactTargetInfoArgs.builder()
.isEssential(true)
.contactId(contactTwo.arn())
.build())
.build(),
PlanStageTargetArgs.builder()
.channelTargetInfo(PlanStageTargetChannelTargetInfoArgs.builder()
.retryIntervalInMinutes(2)
.contactChannelId(channel.arn())
.build())
.build())
.build())
.build());
}
}
resources:
escalationPlan:
type: aws:ssmcontacts:Contact
name: escalation_plan
properties:
alias: escalation-plan-alias
type: ESCALATION
contactOne:
type: aws:ssmcontacts:Contact
name: contact_one
properties:
alias: alias
type: PERSONAL
contactTwo:
type: aws:ssmcontacts:Contact
name: contact_two
properties:
alias: alias
type: PERSONAL
test:
type: aws:ssmcontacts:Plan
properties:
contactId: ${escalationPlan.arn}
stages:
- durationInMinutes: 0
targets:
- contactTargetInfo:
isEssential: false
contactId: ${contactOne.arn}
- contactTargetInfo:
isEssential: true
contactId: ${contactTwo.arn}
- channelTargetInfo:
retryIntervalInMinutes: 2
contactChannelId: ${channel.arn}
Each stage can contain multiple targets that are engaged in parallel. The contactTargetInfo block specifies a contact to engage; isEssential marks whether engagement must succeed before proceeding. The channelTargetInfo block specifies a notification channel with retryIntervalInMinutes controlling how often to retry failed deliveries. Setting durationInMinutes to 0 means the stage engages immediately.
Beyond these examples
These snippets focus on specific plan-level features: single-stage and multi-stage escalation, parallel target engagement, and essential vs optional contacts. They’re intentionally minimal rather than full incident response workflows.
The examples reference pre-existing infrastructure such as SSM Contacts (referenced by ARN) and contact channels for notifications. They focus on configuring the plan rather than provisioning the entire incident management system.
To keep things focused, common plan patterns are omitted, including:
- Multiple escalation stages with different durations
- Channel-only engagement (without contact targets)
- Complex retry strategies across stages
- Integration with incident management workflows
These omissions are intentional: the goal is to illustrate how each plan feature is wired, not provide drop-in incident response modules. See the SSM Contacts Plan resource reference for all available configuration options.
Let's create AWS Systems Manager Contacts Plans
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Contact Configuration
contactId is immutable. Changing it will force resource replacement, so plan carefully when setting this value.arn output property as the contactId, like contactId: contact.arn.Escalation Stages & Timing
durationInMinutes to 0 triggers immediate escalation to that stage without waiting.isEssential flag on contactTargetInfo determines whether the contact must acknowledge before proceeding to the next stage.Targets & Channels
contactTargetInfo and channelTargetInfo in the same targets array.Using a different cloud?
Explore integration guides for other cloud providers: