Get started with Amazon Alexa Skills Proactive Events API
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.
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.
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
- Initialize ASK CLI. This will setup an access to API services. Please find more details in the Manage Credentials with ASK CLI guideline.
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-fileask 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.