Alexa In-Skill Purchases (ISP)
Learn how to implement Alexa in-skill purchasing (ISP) with Jovo.
Introduction
Alexa Skill developers can make money through in-skill purchasing. It allows you to sell items either through one-time purchases, consumables, or subscriptions. Learn more in the official Alexa docs.
While the official Alexa documentation is a great starting point showing you how to create ISP products in the Alexa Developer Console, this documentation shows you how to add support for ISP to your Skill code built with Jovo. The official Alexa documentation on adding ISP to a Skill can also be helpful here.
The delegate to ISP flow section introduces ways to hand off to Alexa for the purchasing flow. For example, to delegate to a Buy
ISP flow from a handler, you can do something like this:
import { Handle } from '@jovotech/framework'; import { IspBuyOutput } from '@jovotech/platform-alexa'; // ... @Handle({ intents: ['BuySkillItemIntent'], platforms: ['alexa'] }) async askForBuyConfirmation() { // Call the Alexa ISP API to retrieve the products added in the Alexa Developer Console const products = await this.$alexa!.isp.getProductList(); const firstProduct = products.inSkillProducts[0]; return this.$send(IspBuyOutput, { message: 'This is the plan I have to offer', productId: firstProduct.productId, }); }
The handle purchase results section explains how to accept requests from Alexa with information about the user's purchase decision. For example, you can react to an accepted purchase of the type Buy
like this:
import { Handle } from '@jovotech/framework'; import { AlexaHandles, IspType, PurchaseResult } from '@jovotech/platform-alexa'; // ... @Handle(AlexaHandles.onIsp(IspType.Buy, PurchaseResult.Accepted)) // or ('Buy', 'ACCEPTED') successfulPurchase() { return this.$send({ message: 'Thanks for buying.' }); }
All ISP helpers that are part of the this.$alexa.isp
property can be found in the ISP helpers section.
Delegate to ISP Flow
To add support for purchase requests, you need to send requests of the type Connections.SendRequest
. These requests hand off the control from your Jovo app code to the Alexa ISP flow.
Jovo offers output classes that make it easier to send those requests for each ISP type:
Buy
Here is an example how you could react to a BuySkillItemIntent
in a Jovo handler and use the IspBuyOutput
output class to hand off to the Alexa ISP flow:
import { Handle } from '@jovotech/framework'; import { IspBuyOutput } from '@jovotech/platform-alexa'; // ... @Handle({ intents: ['BuySkillItemIntent'], platforms: ['alexa'] }) async askForBuyConfirmation() { // Call the Alexa ISP API to retrieve the products added in the Alexa Developer Console const products = await this.$alexa!.isp.getProductList(); const firstProduct = products.inSkillProducts[0]; return this.$send(IspBuyOutput, { message: 'This is the plan I have to offer', productId: firstProduct.productId, }); }
Under the hood, the output looks like this:
{ message: this.options.message, platforms: { alexa: { nativeResponse: { response: { shouldEndSession: true, directives: [ { type: 'Connections.SendRequest', name: 'Buy', payload: { InSkillProduct: { productId: this.options.productId, }, }, token: this.options.token || '', }, ], }, }, }, }, }
Upsell
Here is an example how a askForUpsell
handler could use the IspUpsellOutput
output class to hand off to the Alexa ISP flow. For more information about purchase suggestions, take a look at the official Alexa docs.
import { Handle } from '@jovotech/framework'; import { IspUpsellOutput } from '@jovotech/platform-alexa'; // ... async askForUpsell() { // Call the Alexa ISP API to retrieve the products added in the Alexa Developer Console const products = await this.$alexa!.isp.getProductList(); const firstProduct = products.inSkillProducts[0]; return this.$send(IspUpsellOutput, { productId: '<your-product-id>', upsellMessage: 'This is my product... Do you want to know more?', }); }
Under the hood, the output looks like this:
{ message: this.options.message, platforms: { alexa: { nativeResponse: { response: { shouldEndSession: true, directives: [ { type: 'Connections.SendRequest', name: 'Upsell', payload: { InSkillProduct: { productId: this.options.productId, }, upsellMessage: this.options.upsellMessage, }, token: this.options.token || '', }, ], }, }, }, }, }
Cancel
Here is an example how you could react to a CancelSkillItemIntent
in a Jovo handler and use the IspCancelOutput
output class to hand off to the Alexa ISP flow:
import { Handle } from '@jovotech/framework'; import { IspCancelOutput } from '@jovotech/platform-alexa'; // ... @Handle({ intents: ['CancelSkillItemIntent'], platforms: ['alexa'] }) async askForCancelConfirmation() { // ... return this.$send(IspCancelOutput, { productId: '<your-product-id>', }); }
Under the hood, the output looks like this:
{ message: this.options.message, platforms: { alexa: { nativeResponse: { response: { shouldEndSession: true, directives: [ { type: 'Connections.SendRequest', name: 'Cancel', payload: { InSkillProduct: { productId: this.options.productId, }, }, token: this.options.token || '', }, ], }, }, }, }, }
Handle Purchase Results
After a user interacted with the ISP flow, Alexa sends a Connections.Response
request to your Jovo app. Learn more in the official Alexa docs: Resume your skill after the purchase flow.
To accept these requests, you can use the onIsp
helper for the @Handle
decorator.
Here is an example for accepted purchases of the type Buy
:
import { Handle } from '@jovotech/framework'; import { AlexaHandles, IspType, PurchaseResult } from '@jovotech/platform-alexa'; // ... @Handle(AlexaHandles.onIsp(IspType.Buy, PurchaseResult.Accepted)) // or ('Buy', 'ACCEPTED') successfulPurchase() { return this.$send({ message: 'Thanks for buying.' }); }
The method onIsp(type: IspType, purchaseResult?: PurchaseResult)
accepts the following parameters:
type: IspType
: This can beBuy
,Upsell
, orCancel
.purchaseResult?: PurchaseResult
: This can beACCEPTED
,DECLINED
,ALREADY_PURCHASED
, andERROR
.
The purchaseResult
parameter is optional. You can also retrieve it like this:
import { Handle } from '@jovotech/framework'; import { AlexaHandles, PurchaseResult } from '@jovotech/platform-alexa'; // ... @Handle(AlexaHandles.onIsp('Buy')) successfulPurchase() { const purchaseResult = this.$alexa!.isp.getPurchaseResult(); if(purchaseResult === PurchaseResult.Accepted) { // ... } }
Under the hood, the object that is returned for the @Handle
decorator looks like this:
{ global: true, types: ['Connections.Response'], platforms: ['alexa'], if: (jovo: Jovo) => { const result = purchaseResult ? (jovo.$request as AlexaRequest).request?.payload?.purchaseResult === purchaseResult : true; return (jovo.$request as AlexaRequest).request?.name === type && result; }, }
ISP Helper Methods
You can access the Alexa ISP property like this:
this.$alexa.isp
It offers the following methods to interact with the Alexa ISP API:
await this.$alexa.isp.getProductList(); await this.$alexa.isp.getProductByReferenceName(referenceName: string)
There are also the following helpers that help you read data from an ISP request:
this.$alexa.isp.getPurchaseResult(); this.$alexa.isp.getProductId();