Create AWS SNS Platform Applications

The aws:sns/platformApplication:PlatformApplication resource, part of the Pulumi AWS provider, registers mobile push notification platforms with SNS for sending notifications to iOS and Android devices. This guide focuses on three capabilities: iOS certificate-based authentication, iOS token-based authentication, and Android GCM registration.

Platform applications require credentials from external providers: APNS certificates or signing keys from Apple Developer, or GCM API keys from Google Cloud Console. The examples are intentionally small. Combine them with your own device endpoint registration and notification publishing logic.

Register iOS apps with certificate-based authentication

iOS applications traditionally use certificate-based push notifications, requiring an APNS certificate and private key from Apple Developer.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const apnsApplication = new aws.sns.PlatformApplication("apns_application", {
    name: "apns_application",
    platform: "APNS",
    platformCredential: "<APNS PRIVATE KEY>",
    platformPrincipal: "<APNS CERTIFICATE>",
});
import pulumi
import pulumi_aws as aws

apns_application = aws.sns.PlatformApplication("apns_application",
    name="apns_application",
    platform="APNS",
    platform_credential="<APNS PRIVATE KEY>",
    platform_principal="<APNS CERTIFICATE>")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sns"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sns.NewPlatformApplication(ctx, "apns_application", &sns.PlatformApplicationArgs{
			Name:               pulumi.String("apns_application"),
			Platform:           pulumi.String("APNS"),
			PlatformCredential: pulumi.String("<APNS PRIVATE KEY>"),
			PlatformPrincipal:  pulumi.String("<APNS CERTIFICATE>"),
		})
		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 apnsApplication = new Aws.Sns.PlatformApplication("apns_application", new()
    {
        Name = "apns_application",
        Platform = "APNS",
        PlatformCredential = "<APNS PRIVATE KEY>",
        PlatformPrincipal = "<APNS CERTIFICATE>",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sns.PlatformApplication;
import com.pulumi.aws.sns.PlatformApplicationArgs;
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 apnsApplication = new PlatformApplication("apnsApplication", PlatformApplicationArgs.builder()
            .name("apns_application")
            .platform("APNS")
            .platformCredential("<APNS PRIVATE KEY>")
            .platformPrincipal("<APNS CERTIFICATE>")
            .build());

    }
}
resources:
  apnsApplication:
    type: aws:sns:PlatformApplication
    name: apns_application
    properties:
      name: apns_application
      platform: APNS
      platformCredential: <APNS PRIVATE KEY>
      platformPrincipal: <APNS CERTIFICATE>

The platform property specifies “APNS” for iOS. The platformCredential holds your APNS private key, while platformPrincipal contains the APNS certificate. SNS stores these as hashes in state, so they can’t be referenced by other resources. Once registered, you create platform endpoints for individual devices and publish notifications through SNS.

Register iOS apps with token-based authentication

Token-based authentication simplifies credential management by using a signing key instead of certificates, allowing one key to work across multiple apps.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const apnsApplication = new aws.sns.PlatformApplication("apns_application", {
    name: "apns_application",
    platform: "APNS",
    platformCredential: "<APNS SIGNING KEY>",
    platformPrincipal: "<APNS SIGNING KEY ID>",
    applePlatformTeamId: "<APPLE TEAM ID>",
    applePlatformBundleId: "<APPLE BUNDLE ID>",
});
import pulumi
import pulumi_aws as aws

apns_application = aws.sns.PlatformApplication("apns_application",
    name="apns_application",
    platform="APNS",
    platform_credential="<APNS SIGNING KEY>",
    platform_principal="<APNS SIGNING KEY ID>",
    apple_platform_team_id="<APPLE TEAM ID>",
    apple_platform_bundle_id="<APPLE BUNDLE ID>")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sns"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sns.NewPlatformApplication(ctx, "apns_application", &sns.PlatformApplicationArgs{
			Name:                  pulumi.String("apns_application"),
			Platform:              pulumi.String("APNS"),
			PlatformCredential:    pulumi.String("<APNS SIGNING KEY>"),
			PlatformPrincipal:     pulumi.String("<APNS SIGNING KEY ID>"),
			ApplePlatformTeamId:   pulumi.String("<APPLE TEAM ID>"),
			ApplePlatformBundleId: pulumi.String("<APPLE BUNDLE ID>"),
		})
		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 apnsApplication = new Aws.Sns.PlatformApplication("apns_application", new()
    {
        Name = "apns_application",
        Platform = "APNS",
        PlatformCredential = "<APNS SIGNING KEY>",
        PlatformPrincipal = "<APNS SIGNING KEY ID>",
        ApplePlatformTeamId = "<APPLE TEAM ID>",
        ApplePlatformBundleId = "<APPLE BUNDLE ID>",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sns.PlatformApplication;
import com.pulumi.aws.sns.PlatformApplicationArgs;
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 apnsApplication = new PlatformApplication("apnsApplication", PlatformApplicationArgs.builder()
            .name("apns_application")
            .platform("APNS")
            .platformCredential("<APNS SIGNING KEY>")
            .platformPrincipal("<APNS SIGNING KEY ID>")
            .applePlatformTeamId("<APPLE TEAM ID>")
            .applePlatformBundleId("<APPLE BUNDLE ID>")
            .build());

    }
}
resources:
  apnsApplication:
    type: aws:sns:PlatformApplication
    name: apns_application
    properties:
      name: apns_application
      platform: APNS
      platformCredential: <APNS SIGNING KEY>
      platformPrincipal: <APNS SIGNING KEY ID>
      applePlatformTeamId: <APPLE TEAM ID>
      applePlatformBundleId: <APPLE BUNDLE ID>

Token-based authentication requires the signing key as platformCredential and the signing key ID as platformPrincipal. The applePlatformTeamId and applePlatformBundleId properties identify your Apple Developer account and app. This approach eliminates certificate expiration concerns and supports multiple apps with a single key.

Register Android apps with GCM credentials

Android applications use Google Cloud Messaging to deliver push notifications, requiring only an API key from Google Cloud Console.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const gcmApplication = new aws.sns.PlatformApplication("gcm_application", {
    name: "gcm_application",
    platform: "GCM",
    platformCredential: "<GCM API KEY>",
});
import pulumi
import pulumi_aws as aws

gcm_application = aws.sns.PlatformApplication("gcm_application",
    name="gcm_application",
    platform="GCM",
    platform_credential="<GCM API KEY>")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sns"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sns.NewPlatformApplication(ctx, "gcm_application", &sns.PlatformApplicationArgs{
			Name:               pulumi.String("gcm_application"),
			Platform:           pulumi.String("GCM"),
			PlatformCredential: pulumi.String("<GCM API KEY>"),
		})
		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 gcmApplication = new Aws.Sns.PlatformApplication("gcm_application", new()
    {
        Name = "gcm_application",
        Platform = "GCM",
        PlatformCredential = "<GCM API KEY>",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sns.PlatformApplication;
import com.pulumi.aws.sns.PlatformApplicationArgs;
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 gcmApplication = new PlatformApplication("gcmApplication", PlatformApplicationArgs.builder()
            .name("gcm_application")
            .platform("GCM")
            .platformCredential("<GCM API KEY>")
            .build());

    }
}
resources:
  gcmApplication:
    type: aws:sns:PlatformApplication
    name: gcm_application
    properties:
      name: gcm_application
      platform: GCM
      platformCredential: <GCM API KEY>

The platform property specifies “GCM” for Android. The platformCredential contains your GCM API key. Unlike APNS, GCM doesn’t require a platformPrincipal property. After registration, you create endpoints for Android devices and publish notifications through the same SNS APIs used for iOS.

Beyond these examples

These snippets focus on specific platform application features: iOS certificate and token authentication, and Android GCM registration. They’re intentionally minimal rather than full push notification systems.

The examples require pre-existing infrastructure such as APNS certificates or signing keys from Apple Developer, and GCM API keys from Google Cloud Console. They focus on platform registration rather than device endpoint management or notification publishing.

To keep things focused, common platform application patterns are omitted, including:

  • Event notification topics (endpoint lifecycle events)
  • CloudWatch logging with IAM roles (success/failure feedback)
  • Success feedback sampling (successFeedbackSampleRate)

These omissions are intentional: the goal is to illustrate how each platform authentication method is wired, not provide drop-in notification systems. See the SNS Platform Application resource reference for all available configuration options.

Let's create AWS SNS Platform Applications

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Platform Configuration & Authentication
What's the difference between certificate-based and token-based APNS authentication?
Certificate-based authentication uses platformCredential (private key) and platformPrincipal (certificate). Token-based authentication uses platformCredential (signing key), platformPrincipal (signing key ID), plus applePlatformTeamId and applePlatformBundleId.
What credentials do I need for GCM push notifications?
GCM only requires platformCredential set to your GCM API key. The platformPrincipal property is not needed for GCM.
Why can't I reference credential values in other resources?
The platformCredential and platformPrincipal values are stored as hashes in state, making them impractical to reference elsewhere. Store credentials in a secure parameter store or secrets manager and reference them directly where needed.
APNS-Specific Configuration
What format does applePlatformBundleId need to follow?
The applePlatformBundleId may only include alphanumeric characters, hyphens (-), and periods (.). This is your iOS app’s bundle identifier.
What's the required format for applePlatformTeamId?
The applePlatformTeamId must be exactly 10 alphanumeric characters, matching your Apple developer account team identifier.
When do I need to provide Apple team ID and bundle ID?
These fields are required only when using APNS token-based authentication. Certificate-based APNS authentication doesn’t require them.
Event Notifications & Monitoring
How do I monitor platform endpoint lifecycle events?
Configure SNS topic ARNs for lifecycle events: eventEndpointCreatedTopicArn for new endpoints, eventEndpointUpdatedTopicArn for changes, eventEndpointDeletedTopicArn for deletions, and eventDeliveryFailureTopicArn for permanent delivery failures.
How do I configure delivery feedback with CloudWatch?
Set successFeedbackRoleArn and failureFeedbackRoleArn to IAM role ARNs that give SNS write access to CloudWatch logs. Optionally set successFeedbackSampleRate (0-100) to control the percentage of successful deliveries logged.
Resource Management
What properties can't I change after creating the application?
The name and platform properties are immutable and require resource replacement if changed.

Using a different cloud?

Explore messaging guides for other cloud providers: