Integrating the Reminders API in your skill is a great way to actively extend its utility without requiring customers to launch your skill. With the Reminders API, you can engage more frequently with your customers and become a part of their routines.
In this tutorial, we will go over how to integrate the Reminders API into your skill. We'll be using Node.js and the Alexa Skills Kit (ASK) SDK. This tutorial uses an Alexa-hosted skill, but it can easily be adapted to use a local development process with the ASK Command-Line Interface (CLI).
Before we get started, let’s first go over the basics of how users can interact with a skill that utilizes the Reminders API, as well as how developers can interact with the Reminders API. To understand how users can interact with a skill that uses the Reminders API, consider the following interaction:
Alexa: Would you like to schedule a daily reminder at one p.m. to get a banana from the stand?
User: Sounds good.
In this example, a reminder will be scheduled at 1:00 p.m. and when it comes time, the Alexa-enabled device will chime and announce the reminder. If you have the Alexa mobile app and have push notifications enabled, it will send the reminder as a push notification as well.
For developers, there are two ways to interact with the Reminders API: in-session interactions and out-of-session interactions. For the purposes of this tutorial, we are only going to focus on in-session interactions.
In-session interactions allows a user interacting directly with the skill to create, read, update, and delete reminders. It’s important to note that reminders can only be created through in-session interactions, so it’s important to be clear and upfront about what customers can expect when they create the reminder, so they are not surprised by the outcome later. See our documentation for best practices integrating reminders in your skill and how to develop a good customer experience with reminders. If we recall the dialog shown earlier in this tutorial, a best practice is to specify frequency, time, and purpose.
Would you like to schedule a daily (frequency) reminder at one p. m. (time) to get a banana from the stand (purpose)?
Out-of-session interactions do not require a user to interact directly with a skill to read, update, and delete a reminder. These operations can be managed through the skill code on behalf of the user. However, out-of-session interactions cannot create a reminder. The functionality is limited to read, update, and delete. We are only focusing on in-session interactions in this tutorial, but if you’d like to learn more about out-of-session interactions, see the documentation.
Now that we've covered the basics of the Reminders API and best practices for using it, let's see how we can implement the code to create a reminder. You can follow along here, watch the video, or both.
Now we're going to create a basic Hello World skill, using the Alexa-hosted option for our back end. If you are already familiar with this process, you can skip to the next section. Otherwise you can watch a video on setting up an Alexa-hosted Skill or click on Create Skill and take the following steps:
Click on Code and open package.json and update the packages to the latest versions:
const speechText = “Welcome to Banana Stand. Would you like a daily reminder at one p.m. to pickup a banana from the stand?"
const CreateReminderIntentHandler = {
... // handler code
}
const CreateReminderIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === "IntentRequest" &&
/* Update it to check for AMAZON.YesIntent */
handlerInput.requestEnvelope.request.intent.name === "AMAZON.YesIntent";
},
handle(handlerInput) {
... // handler code
}
}
return exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
... // other intent handlers
/* register CreateReminderIntentHandler */
CreateReminderIntentHandler,
)
.addErrorHandlers(ErrorHandler)
.lambda()
Create an Instance of theRemindersManagementServiceClient:
return exports.handler = Alexa.SkillBuilders.custom()
... // RequestHandlers
.addErrorHandlers(ErrorHandler)
/* add API Client Builder */
.withApiClient(new Alexa.DefaultApiClient())
.lambda()
handle(handlerInput) {
const remindersApiClient = handlerInput.serviceClientFactory.getReminderManagementServiceClient()
}
handle(handlerInput) {
const remindersApiClient = handlerInput.serviceClientFactory.getReminderManagementServiceClient(),
/* Use ES6 destructor assignment syntax to declare and set permissions object in one step */
{ permissions } = handlerInput.requestEnvelope.context.System.user
}
handle(handlerInput) {
const apiClient = handlerInput.serviceClientFactory.getReminderManagementServiceClient(),
{ permissions } = handlerInput.requestEnvelope.context.System.user
/*
Check if user has granted the skill permissions.
If not, send consent card to request reminders read and write permission for skill
*/
if(!permissions) {
return handlerInput.responseBuilder
.speak("Please enable reminders permissions in the Amazon Alexa app")
.withAskForPermissionsConsentCard(["alexa::alerts:reminders:skill:readwrite"])
.getResponse()
}
}
3. Click Deploy and test skill on a device
handle(handlerInput) {
... // Continuing from the code we wrote to check if the customer has granted the reminders permission to the skill
/* Declare the reminderRequest object to make a request to schedule a reminder */
const reminderRequest = {
trigger: {
type: "SCHEDULED_RELATIVE",
offsetInSeconds: "20",
},
alertInfo: {
spokenInfo: {
content: [{
locale: "en-US",
text: "Time to get yo banana",
}],
},
},
pushNotification: {
status: "ENABLED"
}
}
}
handle(handlerInput) {
... // reminderRequest variable and other variables
/*
Use the remindersApiClient that was previously instantiated with
the reminderRequest object that specifies specifics of the reminder
to schedule a reminder
*/
remindersApiClient.createReminder(reminderRequest)
return handlerInput.responseBuilder
.speak("A reminder to get a banana in 20 seconds has been successfully created.")
.getResponse();
}
3.Click Deploy.
4. Test the skill on an Alexa-enabled device by saying “Alexa, open my banana stand” (reminders cannot be tested through the simulator).
5. Now let’s utilize the JavaScript ES6 async-await and try-catch pattern to better handle any potential errors when using the remindersApiClient to make an asynchronous HTTP request to schedule a reminder.
async handle(handlerInput) {
... // handle function declared variables and code
}
async handle(handlerInput) {
... // handle function declared variables and code
await remindersApiClient.createReminder(reminderRequest)
}
async handle(handlerInput) {
... // handle function declared variables and code
try {
await remindersApiClient.createReminder(reminderRequest)
} catch(error) {
console.log("~~~~~ createReminder Error ${error} ~~~~~")
return handlerInput.responseBuilder
.speak("There was an error creating your reminder. Please let the skill publisher know.")
.getResponse();
}
}
const Alexa = require("ask-sdk-core"),
moment = require('moment-timezone') // Add moment-timezone package
const CreateReminderIntentHandler = {
canHandle(handlerInput) {
... // can handle logic
},
async handle(handlerInput) {
... // Variable declarations
... // Code to check for permissions
const currentTime = moment().tz("America/Los_Angeles"), // Use Moment Timezone to get the current time in Pacific Time
reminderRequest = {
requestTime: currentTime.format("YYYY-MM-DDTHH:mm:ss"), // Add requestTime
trigger: {
type: "SCHEDULED_ABSOLUTE", // Update from SCHEDULED_RELATIVE
scheduledTime: currentTime.set({
hour: "13",
minute: "00",
second: "00"
}).format("YYYY-MM-DDTHH:mm:ss"),
timeZoneId: "America/Los_Angeles", // Set timeZoneId to Pacific Time
recurrence: {
freq : "DAILY" // Set recurrence and frequency
}
},
alertInfo: {
spokenInfo: {
content: [{
locale: "en-US",
text: "Time to get yo daily banana. You better go before the banistas pack up.",
}]
}
},
pushNotification: {
status: "ENABLED"
}
}
}
... // Code to create reminders
}
reminderRequest = {
requestTime: currentTime.format("YYYY:MM:DDTHH:mm:ss"),
trigger: {
type: "SCHEDULED_ABSOLUTE",
scheduledTime: currentTime.add(20, "seconds").format("YYYY-MM-DDTHH:mm:ss"),
... // other request parameters
}
... // other request parameters
}
In this tutorial, we used the Reminders API to create a skill that reminds users to pick up a banana. I think we can rest assured that we will be getting our daily banana! I hope you will take what we went over in this tutorial and adapt it to enhance your skill’s functionality and deepen engagement with your users.
We look forward to what you will build! Follow me on Twitter at @ItsPanW for more content like this and keep checking the Amazon Developer Blogs for updates.