In part 1 of a two-part series we have covered how to use voice permission and call the Timer API to set timers in Alexa skill. Now in this second part, we will cover how you can perform read, pause, resume and delete operations to Timer API.
To perform read operations you need to have permission enabled in your skill. Whenever a skill creates a timer using the Timer API, a unique “id” is sent back to your skill in response. This “id” will be used to identify the specific timer set in Alexa device.
Now we will use this “id” to perform all read, delete, pause and resume operations.
Below is a sample request used to call the Read Timer API:
GET /v1/alerts/timers/{id}
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json
No request body is needed to call this API.
This API call then returns a response, which will contain the timer id, status, duration, triggerTime, createdTime and updatedTime.
Example response:
{
"id": "a3aac326-c504-458b-8520-15fd048f086a",
"status": "ON",
"duration": "PT10M",
"triggerTime": "2021-08-13T10:25:30Z",
"createdTime": "2021-08-13T10:15:30Z",
"updatedTime": "2021-08-13T10:15:30Z"
}
If the created timer has been previously paused, then the “remainingTimeWhenPaused” property will be added in the response. Here is an example where the timer has three minutes and three seconds left:
{
"id": "a3aac326-c504-458b-8520-15fd048f086a",
"status": "PAUSED",
"duration": "PT5M",
"timerLabel": "Pizza",
"createdTime": "2019-12-03T10:15:30Z",
"updatedTime": "2019-12-03T10:12:03Z",
"remainingTimeWhenPaused": "PT3M3S"
}
Get timers for a specified customer. Timers that are created within the skill will be visible on all devices associated with the Alexa account, and are returned, sorted in order from the timer with the shortest duration to the longest duration.
GET /v1/alerts/timers
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json
No request body is needed to call this API.
This API will return details for all timers created for this user through the skill.
Example response where one timer is active and another one is paused:
{
"timers": [
{
"id": "a3aac326-c504-458b-8520-15fd048f086a",
"status": "ON",
"duration": "PT10M",
"triggerTime": "2019-12-03T10:25:30Z",
"createdTime": "2019-12-03T10:15:30Z",
"updatedTime": "2019-12-03T10:15:30Z",
},
{
"id": "a3aac326-c504-458b-8520-15fd048f086a",
"status": "PAUSED",
"duration": "PT5M",
"timerLabel": "Pizza",
"createdTime": "2019-12-03T10:15:30Z",
"updatedTime": "2019-12-03T10:12:03Z",
"remainingTimeWhenPaused": "PT3M3S"
}
],
"totalCount": 2,
"nextToken": null
}
We also provide ASK SDK support to perform read operation so you don’t have to worry about API calls.
async handle(handlerInput) {
const {serviceClientFactory} = handlerInput;
try {
const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
// getTimers() will send list of all timers created.
const timersList = await timerServiceClient.getTimers();
console.log('Read timers: ' + JSON.stringify(timersList));
const totalCount = timersList.totalCount;
if(timerId || totalCount > 0) {
timerId = timerId ? timerId : timersList.timers[0].id;
// getTimer(timerId) will send details of specific timer as per "id" provided in "timerId".
let timerResponse = await timerServiceClient.getTimer(timerId);
console.log('Read timer: ' + JSON.stringify(timerResponse));
const timerStatus = timerResponse.status;
return handlerInput.responseBuilder
.speak("Read timer operation completed")
.getResponse();
} else {
return handlerInput.responseBuilder
.speak("No timer was created")
.getResponse();
}
} catch (error) {
console.log('Read timer error: ' + JSON.stringify(error));
// If error code is passed 401 then send voice permission to user to grant Timer permission.
if(error.statusCode === 401) {
console.log('Unauthorized!');
// we send a request to enable by voice
// note that you'll need another handler to process the result, see AskForResponseHandler
return handlerInput.responseBuilder
.addDirective({
type: 'Connections.SendRequest',
'name': 'AskFor',
'payload': {
'@type': 'AskForPermissionsConsentRequest',
'@version': '1',
'permissionScope': TIMERS_PERMISSION
},
token: 'verifier'
}).getResponse();
}
else
return handlerInput.responseBuilder
.speak("You haven't set a timer. Try saying, set a timer.")
.getResponse();
}
}
This API is invoked to delete a specific timer for the current device. “id” is the unique identifier of specific timer.
DELETE /v1/alerts/timers/{id}
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json
No request body is needed to call this API.
This API will delete all timers created by user.
DELETE /v1/alerts/timers
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json
No request body is needed to call this API.
You can also use the ASK SDK here to form delete operations like below:
async handle(handlerInput) {
const {serviceClientFactory} = handlerInput;
try {
const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
const timersList = await timerServiceClient.getTimers();
console.log('Read timers: ' + JSON.stringify(timersList));
const totalCount = timersList.totalCount;
if(totalCount === 0) {
return handlerInput.responseBuilder
.speak("No timer has created.")
.getResponse();
}
// warning, since there's no timer id we cancel all timers by the user
await timerServiceClient.deleteTimers();
console.log('Timer deleted!');
return handlerInput.responseBuilder
.speak("All created timers deleted")
.getResponse();
} catch (error) {
console.log('Delete timer error: ' + JSON.stringify(error));
if(error.statusCode === 401) {
console.log('Unauthorized!');
// we send a request to enable by voice
// note that you'll need another handler to process the result, see AskForResponseHandler
return handlerInput.responseBuilder
.addDirective({
type: 'Connections.SendRequest',
'name': 'AskFor',
'payload': {
'@type': 'AskForPermissionsConsentRequest',
'@version': '1',
'permissionScope': TIMERS_PERMISSION
},
token: 'verifier'
}).getResponse();
}
else
return handlerInput.responseBuilder
.speak("Something went wrong in performing delete operation")
.getResponse();
}
}
You can only pause a timer that is scheduled but has not started yet. The timer's remaining time is frozen and saved. For example, if you pause a timer that is due to go off in 45 minutes, then the timer will go off 45 minutes from when you resume the timer.
POST /v1/alerts/timers/{id}/pause
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json
No request body is needed to call this API.
Below are the details on how you can use ASK SDK to perform a pause operation for a specific timer:
async handle(handlerInput) {
const {serviceClientFactory} = handlerInput;
try {
const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
const timersList = await timerServiceClient.getTimers();
console.log('Read timers: ' + JSON.stringify(timersList));
const totalCount = timersList.totalCount;
if(totalCount === 0) {
return handlerInput.responseBuilder
.speak("No timer has created.")
.getResponse();
}
// pauses all timers
for(const timer of timersList.timers ) {
if(timer.status === 'ON'){
// This will pause specific timer provided in “timer.id”.
await timerServiceClient.pauseTimer(timer.id);
}
};
return handlerInput.responseBuilder
.speak("Timer has been paused.")
.getResponse();
} catch (error) {
console.log('Pause timer error: ' + JSON.stringify(error));
if(error.statusCode === 401) {
console.log('Unauthorized!');
// we send a request to enable by voice
// note that you'll need another handler to process the result, see AskForResponseHandler
return handlerInput.responseBuilder
.addDirective({
type: 'Connections.SendRequest',
'name': 'AskFor',
'payload': {
'@type': 'AskForPermissionsConsentRequest',
'@version': '1',
'permissionScope': TIMERS_PERMISSION
},
token: 'verifier'
}).getResponse();
}
else
return handlerInput.responseBuilder
.speak("Something went wrong while pausing timer.")
.getResponse();
}
}
Use this API to resume a previously paused timer. The timer will then run for the remaining time after resuming, unless it is otherwise paused or stopped.
POST /v1/alerts/timers/{id}/resume
Host: https://api.amazonalexa.com
Authorization: Bearer <Access token>
Content-Type: application/json
No request body is needed to call this API.
Below are the details on how you can perform the resume operation using the ASK SDK:
async handle(handlerInput) {
const {serviceClientFactory} = handlerInput;
try {
const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
const timersList = await timerServiceClient.getTimers();
console.log('Read timers: ' + JSON.stringify(timersList));
const totalCount = timersList.totalCount;
if(totalCount === 0) {
return handlerInput.responseBuilder
.speak("No timer has created.")
.getResponse();
}
// resumes all timers
for(const timer of timersList.timers ) {
if(timer.status === 'PAUSED'){
// This will resume Timer which has been paused.
await timerServiceClient.resumeTimer(timer.id);
}
};
return handlerInput.responseBuilder
.speak("Timer has resumed successfully.")
.getResponse();
} catch (error) {
console.log('Resume timer error: ' + JSON.stringify(error));
if(error.statusCode === 401) {
console.log('Unauthorized!');
// we send a request to enable by voice
// note that you'll need another handler to process the result, see AskForResponseHandler
return handlerInput.responseBuilder
.addDirective({
type: 'Connections.SendRequest',
'name': 'AskFor',
'payload': {
'@type': 'AskForPermissionsConsentRequest',
'@version': '1',
'permissionScope': TIMERS_PERMISSION
},
token: 'verifier'
}).getResponse();
}
else
return handlerInput.responseBuilder
.speak("Something went wrong while resuming Timer.")
.getResponse();
}
}
With this blog we covered operations possible in Timer API and showcase how you can leverage the ASK SDK to call this API, and create a timer skill which will be useful for customers. If you have any question about what we’ve talked about in this blog, please visit the tech docs here.