Get started with Amazon Alexa Skills Proactive Events API

Sergey Smolnikov
The Startup
Published in
11 min readJun 10, 2019

Amazon Alexa Skills are serverless applications, which allows people interact with Alexa enabled devices with voice or on-screen controls — voice and on-screen assistance.

Amazon Echo Dot

Usually it is expected that a user starts interaction, triggering an Alexa Skill to respond on commands or questions. This way the user decides when to start interaction.

Request-respond voice interaction

However, in some cases users would have to regularly request for updated or new information. In such cases — notifications, initiated by an Alexa device, could be preferable. Proactive Events API provide this option.

Short video presentation provides quick introduction about Alexa and Proactive Events.

To start with Proactive Events API, we need to create a simple Alexa Skill and AWS Lambda function, which will be used as a playground in this article. This article and video tutorial maybe used as a guide.

Setup ASK-CLI

Install ASK CLI — Alexa Skills Kit command line tool. It is needed, because Alexa Skill Management API (SMAPI) is used for setup and some features, supported in SMAPI, are not supported on the Amazon Developer Portal. The skill events feature is one of them, it can only be managed with ASK CLI, and not with the Amazon Developer Portal.

sudo npm install -g ask-cli
ask init

During the initialization process a browser with a login page will be automatically opened. Please follow the instruction to fill in the requested AWS Access Key ID and AWS Secret Access Key.

Alternative of using ask init is to configure AWS CLI with admin user’s AWS Access Key ID and AWS Secret Access Key we will use

Add events to skill

With ASK CLI — proactive events need to be added to the manifest of the skill. Select one or several event schemas to be sent as notifications (they have different payload structures and properties). List of event schemas is regularly extending, please vote for missed schemas and features. Currently available event schemas:

AMAZON.WeatherAlert.ActivatedAMAZON.SportsEvent.UpdatedAMAZON.MessageAlert.ActivatedAMAZON.OrderStatus.UpdatedAMAZON.Occasion.UpdatedAMAZON.TrashCollectionAlert.ActivatedAMAZON.MediaContent.AvailableAMAZON.SocialGameInvite.Available

Get the skill manifest as a json-file
ask api get-skill -s skill_id > skill.json

Open this file in your favourite text editor

Add notification.write permission to the manifest section

"permissions": [{"name": "alexa::devices:all:notifications:write"}],

Add selected event names to the manifest section. In this example — two event schemas were selected: AMAZON.OrderStatus.Updated and AMAZON.MediaContent.Available. Put the Alexa Skill AWS Lambda function ARN to the endpoint property (more details about endpoints and Lambda functions in this guideline)

Revise carefully double quote characters, which may be replaced by some editors with similar alternative characters.

Update the skill with the corrected manifest (put the actual skill_id in the command)

ask api update-skill -s skill_id -f skill.json

Check skill status — if it is updated correct, status will contain SUCCESS

ask api get-skill-status -s skill_id

Skill Client Id and Client Secret

Developer Console for the Alexa Skill should contain now Client Id and Client Secret for this skill

Open an Alexa mobile app (iOS, Android) or Alexa web-dashboard. Open the skill and enable it

Alexa Skill should have now a section THIS SKILL NEEDS PERMISSION TO ACCESS with Alexa Notifications

Hit the SETTINGS button, and the MANAGE PERMISSIONS button

Turn on the switch to allow notifications, hit the SAVE PERMISSIONS button to save changes

Now the Alexa device with this skill can receive Proactive events, specified in the skill manifest. Events can be sent by regular HTTP clients. For example: Postman, cUrl, IntelliJ IDEA “HTTP Client”-plugin, etc.

This is a test with Postman client.

Request a bearer token

In the Postman — hit a “+” tab to add a new request tab, select POST as a request type and enter the bearer token API URL

https://api.amazon.com/auth/o2/token

Open the Headers tab and add a key Content-Type with a value

application/x-www-form-urlencoded

Optional Bulk Edit mode allows to fill-in key-value pairs as a text, Key-Value Edit mode fills-in pairs as a table

Open the Body tab and add following key-values, with selected option x-www-form-urlencoded. Put actual client_id and client_secret taken from Developer Console, Build tab, PERMISSIONS tab (described earlier)

Key:"grant_type"      Value:"client_credentials"
Key:"client_id" Value:"amzn1.application-oa2-client.a478..."
Key:"client_secret" Value:"ef1286b2..."
Key:"scope" Value:"alexa::proactive_events"

Note: the value of the key scope contains double semicolon, which might confuse some HTTP clients, when setup request with bulk/text edit mode.

{ "access_token”:”accessToken”, "expires_in":3600, "scope":"alexa::proactive_events", "token_type":"Bearer" }

Hit the Send button an with Pretty/JSON options — look at the respond, which should contain the access_token

This token is expired in 3600 second (in one hour). After this period a new request will get respond-code 403 (Unauthorized) — new token need to be requested to proceed with further requests.

This bearer token should accompany each requests to the event API. This API has separate endpoints for three regions, and also development and production environments. With development environment endpoints events will not be send to real customers, it is made for testing purpose:

Development
https://api.amazonalexa.com/v1/proactiveEvents/stages/development (North America)
https://api.eu.amazonalexa.com/v1/proactiveEvents/stages/development (Europe)
https://api.fe.amazonalexa.com/v1/proactiveEvents/stages/development (Far East)

Production
https://api.amazonalexa.com/v1/proactiveEvents/ (North America)
https://api.eu.amazonalexa.com/v1/proactiveEvents/ (Europe)
https://api.fe.amazonalexa.com/v1/proactiveEvents/ (Far East)

Send Proactive notification

In the Postman application — hit another “+” tab to add a new request tab, select POST as a request type and enter the development event API URL

https://api.amazonalexa.com/v1/proactiveEvents/stages/development

Open the Headers tab and add a key Content-Type with a value

application/json

Add another key Authorization with a value

Bearer Atc|...

Where “Atc|…” is a value from the access_token property of the response from bearer token API, received earlier.

Note: there is a space between the term Bearer and the token value.

Open the Body tab and add event’s json-content, with the selected option raw

{
. . .
"event": {
"name": "AMAZON.MediaContent.Available",
. . .
"localizedAttributes": [
{
"locale": "en-US",
"providerName": "Alexa Events Example",
"contentName": "Some event"
}
],
"relevantAudience": {
"type": "Multicast",
"payload": {}
` }
}

This body content corresponds to the AMAZON.MediaContent.Available schema and in this example a media-related event is:

Alexa Events Example” (“providerName”) notifies that a new “episode” (“contentType”) of “Some event” (“contentName") will take place via “air” (“method”) at “8pm June 8th 2019 EDT” (“startTime”).

This notification will expire at “2pm June 8th 2019” (“expiryTime”).

Hit the Send button. If the bearer token and event content are correct — the respond-code will be 202 (Accepted) and the content-length is zero (no respond-body). Turned on Alexa device makes the notification sound and start blinking.

To read notifications — ask, “Alexa, what are my notifications?” or “Alexa, what did I miss?”, and all notifications, collected by this time, will be pronounces.

Notice that time will be pronounced not for the Alexa device time-zone. I guess it corresponds to the API region or its configured AWS Lambda function, or a skill region — I have not found this certainly. Date-time values should be in ISO 8601 format, ended with “Z” (for UTC) or with time-zone shift period

“startTime”: “2019–06–10T00:00:00Z
"startTime": "2019-06-10T05:00:00+05:00"

After a notification is read, it is archived in the cloud for few hours and then automatically deleted. To read those archived notifications — ask Alexa: “Alexa, what are my old notifications?”

Notifications can be deleted with the command “Alexa, delete all my notifications”.

Failures

If something is wrong with the request — the respond-code will have 4** code and respond-body will contain error description. Examples of such issues:

Set invalid “expiryTime”. It should be at least 5 minutes in the future and no more than 24 hours after the current time:

Set invalid property value, not supported in the event schema. Look through the “message” value, which contains information, relevant to a particular issue. In value characters “\n” can be replaced with new-line, “\”” with double-quote, then it become more readable. But even without such correction the issue can be figure-out

As an example of correction in the Visual Studio Code - characters can be replaced with Regular Expression option. Fix new lines:

Fix double-quotes

Save the corrected file with json-extension gives some highlight in addition

Event audience options

Event can be sent to all particular skill users (those, who allowed notifications from this skill) or to specific users, using their user-id. The property “relevantAudience” controls this option with values “Multicast” and “Unicast”.

Send en event to all users (broadcasting or multicasting):

"relevantAudience": {
"type": "Multicast",
"payload": {}
}

Send en event to specific user:

"relevantAudience": {
"type": "Unicast",
"payload": { "user": "specific-user-Id" }
}

To track user-ids — subscribe on an event, notifying that a user turned on/off proactive notifications. To make the skill’s Lambda function receive this event — add following subscription section to the Alexa skill manifest (to the “events” property) and update the manifest with the ASK-CLI

"subscriptions": [
{
"eventName": "SKILL_PROACTIVE_SUBSCRIPTION_CHANGED"
}
]

Update the skill with the corrected manifest (put the actual skill_id in the command)

ask api update-skill -s skill_id -f skill.json

Add a request handler to the Alexa Skill AWS Lambda function to handle this event (the example code extends an Lambda function, created in this tutorial)

Add the instance of this handler to the SkillStreamHandler builder

Build the jar-file and upload it to the Lambda function. Open an Alexa mobile app or Alexa web-dashboard, open the skill, hit the SETTINGS button and turn on or off the switch to allow notifications, hit the SAVE PERMISSIONS button to save changes

Subscribe to proactive events request in the CustomProactiveSubscriptionChangedRequestHandler. Request body contains “subscriptions” as “eventName” list:

proactiveSubscriptionChangedRequest.getBody().getSubscriptions()

Un-subscribe from proactive events request in the CustomProactiveSubscriptionChangedRequestHandler. Request body does not exist

proactiveSubscriptionChangedRequest.getBody() == null

Pick “userId” and a list of event names to manage individual notifications

String userId = input.getRequestEnvelope().getContext().getSystem().getUser().getUserId();
//userId looks like "amzn1.ask.account.AFE2..."

and send notifications to particular users with and “Unicast” “relevantAudience

"relevantAudience": {
"type": "Unicast",
"payload": {"user": "amzn1.ask.account.AFE2..."}
}

Possible issues

Attempt to send a notification to a particular user, which has not allowed notifications for the skill — returns an error:

Can’t find any subscription for stage=development, skillId=amzn1.ask.skill.e2af…, topicId=AMAZON.MediaContent.Available

In the response message: “stage” can be “development” or “live”, corresponding “skillId” and an event schema name, for which event has been sent.

Following issue might happen with a request about an event to a particular user, with valid bearer-token and correct userId, but this bearer-token is for different skill then the userId generated for. Maybe there are other causes for this issue.

{
“type”: “Forbidden”,
“message”: “No enablement for clientId: amzn1.application-oa2-client.d6ad..., userId: amzn1.ask.account.AFE...”
}

Event ProactiveSubscriptionChanged will not be send when a user disables the skill. When this user enables this skill again — the user is assigned with a new userId. Because of this it makes sense to track at least an event “AlexaSkillEvent.SkillDisabled”. also events about activate/deactivate skill, enable/change/disable permissions (including permission to receive proactive notifications). To make the skill’s Lambda function receive these events — add following subscription section to the Alexa skill manifest (to the “events” property) and update the manifest with the ASK-CLI

"subscriptions": [
{
"eventName": "SKILL_ENABLED"
},
{
"eventName": "SKILL_DISABLED"
},
{
"eventName": "SKILL_PERMISSION_ACCEPTED"
},
{
"eventName": "SKILL_PERMISSION_CHANGED"
}
]

RequestHandlers are similar to the CustomProactiveSubscriptionChangedRequestHandler — all they implement interfaces with names, corresponding to event names (e.g. PermissionAcceptedRequestHandler), which has boilerplate code in the default method implementations

@Override
default boolean canHandle(HandlerInput handlerInput) {
if (handlerInput.getRequest() instanceof PermissionAcceptedRequest) {
return canHandle(handlerInput, (PermissionAcceptedRequest)handlerInput.getRequest());
}
return false;
}

@Override
default Optional<Response> handle(HandlerInput handlerInput) {
return handle(handlerInput, (PermissionAcceptedRequest)handlerInput.getRequest());
}

Technically boilerplate logic from these handlers can be merged to one handler.

Final skill manifest with all these events would look like this

Using the code build the jar-file an upload it to the Lambda function, connected to the Alexa Skill. There is pre-build release with jar-file for this function. Enable/disable the skill and turn on/off notification settings in the mobile app of web-dashboard and look at the Cloud Watch log for the Lambda function to see activity.

Note: events can arrive out of order, use the timestamp in the event to correctly record the latest subscription state for a customer.

Language and region

Creating Alexa Skills and Lambda for their backend has options for different regions. AWS Lambda should be configured for each geographic region where the skill requires permissions. For example, a skill sends change report events in the US and the UK, AWS Lambdas need to be configured for both North America and Europe. For training and evaluation purpose it would be easier to make skills for US language, Lambda function for N. Virginia (us-east-1) region.

Source code

Published on GitHub. Pre-build release with jar-file.

Participate in API improvements

You can vote for features and missed event types on the Alexa Skills developer forum.

This article as a video-tutorial. Simple Java ASK Proactive API kit source.

Amazon Web Services, and AWS Lambda are trademarks of Amazon.com, Inc. or its affiliates in the United States and/or other countries.

--

--