--------------------------------------------------------------------------------
/app/tools/copyAssets.ts:
--------------------------------------------------------------------------------
1 | import * as shell from "shelljs";
2 |
3 | // Copy all the view templates
4 | shell.cp( "-R", "src/views", "dist/" );
5 |
6 | // Copy all the public files
7 | shell.cp( "-R", "src/public", "dist/" );
--------------------------------------------------------------------------------
/app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "esModuleInterop": true,
5 | "target": "es6",
6 | "noImplicitAny": true,
7 | "moduleResolution": "node",
8 | "sourceMap": true,
9 | "outDir": "dist",
10 | "baseUrl": ".",
11 | "paths": {
12 | "*": [
13 | "node_modules/*"
14 | ]
15 | }
16 | },
17 | "include": [
18 | "src/**/*"
19 | ],
20 | "exclude": [
21 | "src/public"
22 | ]
23 | }
--------------------------------------------------------------------------------
/app/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint:recommended"
5 | ],
6 | "jsRules": {},
7 | "rules": {
8 | "trailing-comma": [ false ]
9 | },
10 | "rulesDirectory": []
11 | }
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | $ErrorActionPreference = "Stop"
2 | $here = Split-Path -Parent $PSCommandPath
3 | $toolsDir = "$here/tools"
4 |
5 | if ($IsWindows) {
6 | $os = "win"
7 | }
8 | elseif ($IsLinux) {
9 | $os = "linux"
10 | }
11 | elseif ($IsMacOS) {
12 | $os = "osx"
13 | }
14 | else {
15 | throw "Unsupported OS"
16 | }
17 |
18 | function installBicep {
19 | $version = "v0.3.126"
20 | $extension = $IsWindows ? ".exe" : ""
21 | $bicepUri = "https://github.com/Azure/bicep/releases/download/$version/bicep-$os-x64$extension"
22 |
23 | $dir = New-Item -Path $toolsDir/bicep/$version -ItemType Directory -Force
24 | $bicep = "$dir\bicep$extension"
25 |
26 | if (Test-Path $dir/* -Filter bicep*) {
27 | Write-Host "Bicep already installed."
28 | }
29 | else {
30 | (New-Object Net.WebClient).DownloadFile($bicepUri, $bicep)
31 | }
32 |
33 | return $bicep
34 | }
35 |
36 | try {
37 | Write-Host "Installing Bicep..."
38 | $bicep = installBicep
39 |
40 | Write-Host "Building main Bicep template..."
41 | . $bicep build $here/templates/main.bicep --outdir $here/output
42 | }
43 | catch {
44 | Write-Warning $_.ScriptStackTrace
45 | Write-Warning $_.InvocationInfo.PositionMessage
46 | Write-Error ("Build error: `n{0}" -f $_.Exception.Message)
47 | }
--------------------------------------------------------------------------------
/deploy.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param (
3 | [Parameter(Mandatory=$true)]
4 | [string]
5 | $TenantId,
6 |
7 | [Parameter(Mandatory=$true)]
8 | [string]
9 | $SubscriptionId,
10 |
11 | [Parameter(Mandatory=$true)]
12 | [string]
13 | $ResourceGroupName,
14 |
15 | [Parameter(Mandatory=$true)]
16 | [string]
17 | $ResourceGroupLocation,
18 |
19 | [Parameter(Mandatory=$true)]
20 | [string]
21 | $ArtifactStorageAccountName,
22 |
23 | [Parameter()]
24 | [string]
25 | $ParameterFilePath = "$(Split-Path -Parent $PSCommandPath)/output/main.parameters.json"
26 | )
27 |
28 | $ErrorActionPreference = "Stop"
29 | $here = Split-Path -Parent $PSCommandPath
30 |
31 | $deploymentName = "apim-monetization-{0}" -f (Get-Date).ToString("yyyyMMddHHmmss")
32 |
33 | $account = (az account show) | ConvertFrom-Json
34 |
35 | if (!$account -or $account.tenantId -ne $TenantId) {
36 | az login --tenant $TenantId
37 | }
38 |
39 | if ($account.id -ne $SubscriptionId) {
40 | az account set --subscription $SubscriptionId
41 | }
42 |
43 | az group create --name $ResourceGroupName --location $ResourceGroupLocation
44 |
45 | az storage account create -n $ArtifactStorageAccountName -g $ResourceGroupName -l $ResourceGroupLocation
46 | az storage container create -n default --account-name $ArtifactStorageAccountName --public-access blob
47 | az storage blob directory upload -c default --account-name $ArtifactStorageAccountName -s "$here/apiConfiguration/*" -d "/apiConfiguration" --recursive
48 | az storage blob directory upload -c default --account-name $ArtifactStorageAccountName -s "$here/payment/*" -d "/payment" --recursive
49 | $artifactsBaseUrl = "https://$ArtifactStorageAccountName.blob.core.windows.net/default"
50 |
51 | az deployment group create --resource-group $ResourceGroupName --name $deploymentName --template-file "$here/output/main.json" --parameters (Resolve-Path $ParameterFilePath) --parameters artifactsBaseUrl=$artifactsBaseUrl
--------------------------------------------------------------------------------
/documentation/advanced-steps.md:
--------------------------------------------------------------------------------
1 | # Advanced steps
2 |
3 | This article takes you beyond initial Adyen or Stripe deployment and integration with API Management.
4 |
5 | ## Running the build script
6 |
7 | To modify the infrastructure templates, you'll run a build script to generate a new Azure Resource Manager template output for deployment.
8 |
9 | 1. Run the `build.ps1` PowerShell script at the root of the repo.
10 |
11 | 1. The build script generates deployment scripts for all Azure resources required to support the demo project.
12 | * See the [deployment details](./deployment-details.md) for more details.
13 |
14 | 1. The build script executes the following steps:
15 | * Installs the Bicep CLI into the `build` folder.
16 | * Transpiles the `main.bicep` template into a single `main.json` Azure Resource Manager template in the `output` folder.
17 |
18 | ## Running the billing portal app locally
19 |
20 | To modify the billing portal app and run the app locally:
21 |
22 | 1. Install [NodeJS](https://nodejs.org/en/download/) (version 20.10 or later).
23 | 1. Deploy an instance of the API Management infrastructure, following the instructions in either:
24 | * [Deploy with Stripe](./stripe-deploy.md), or
25 | * [Deploy with Adyen](./adyen-deploy.md) documents).
26 | 1. Make a copy of `.env.sample` in `/app`, rename to `.env`, and fill in the variables as per your environment.
27 | 1. Use a tunneling app such as [ngrok](https://ngrok.com/) to create a public URL forwarding port 8080. If using ngrok:
28 | * [Download ngrok](https://ngrok.com/download).
29 | * Unzip the executable.
30 | * From the command line, run the ngrok executable to start an HTTP tunnel, using port 8080: `./ngrok http 8080`.
31 | * Continue with the following steps, replacing `` with the output URL (for example, https://\.ngrok.io).
32 | 1. Update the API Management delegation URL via the Azure portal to point to `/apim-delegation`.
33 | * For Stripe, update the Stripe webhook endpoint URL to `/webhook/stripe`.
34 | * For Adyen, update the allowed origins to include ``.
35 | 1. Run `npm run dev` from the `/app` folder to start the app.
36 | 1. If you're running from VS Code, enable debugging by:
37 | * Opening the command palette.
38 | * Selecting **Debug: Toggle Auto Attach**.
39 | * Setting to **Smart**.
40 |
41 | ## Re-building the docker image
42 |
43 | If you make code changes to the custom billing portal app, you will need to:
44 |
45 | 1. Re-build the docker image from `app/Dockerfile`.
46 | 1. Publish the docker image to a publicly accessible container registry.
47 | 1. When deploying, set the value of the `appServiceContainerImage` parameter to the URL for your published container image.
48 |
--------------------------------------------------------------------------------
/documentation/adyen-deploy.md:
--------------------------------------------------------------------------------
1 | # Deploy demo with Adyen
2 |
3 | In this tutorial, you'll deploy the demo Adyen account and learn how to:
4 |
5 | > [!div class="checklist"]
6 | > * Set up an Adyen account, the required PowerShell and `az cli` tools, an Azure subscription, and a service principal on Azure.
7 | > * Deploy the Azure resources using either Azure portal or PowerShell.
8 | > * Make your deployment visible to consumers by publishing the Azure developer portal.
9 |
10 | ## Pre-requisites
11 |
12 | To prepare for this demo, you'll need to:
13 |
14 | > [!div class="checklist"]
15 | > * Create an Adyen test account.
16 | > * Install and set up the required PowerShell and Azure CLI tools.
17 | > * Set up an Azure subscription.
18 | > * Set up a service principal in Azure.
19 |
20 | ### [Create an Adyen test account](https://www.adyen.com/signup)
21 |
22 | From within an Adyen test account:
23 | 1. Expand the **Accounts** tab on the pages panel on the left side of the Adyen test account homepage, select the **Merchant accounts** option.
24 | 1. If you do not have one already, create a **merchant account** for an **ecommerce sales channel**.
25 |
26 | Three values should be copied from the Adyen test account that are required as input parameters during the deployment process:
27 | 1. Copy the **Merchant account name** which is the displayed in the top left corner of the Adyen test account homepage.
28 | 1. Expand the **Developers** tab on the pages panel on the left side of the Adyen test account homepage, select the **API Credentials** option.
29 | 1. Select the **ws** (Web Service) API.
30 | 1. Generate and copy an **API key** and copy the **Client key**.
31 |
32 | After the deployment of the Azure resources (see below) has completed, you should return to the Adyen test account homepage to:
33 | 1. Expand the **Developers** tab on the pages panel on the left side of the Adyen test account homepage, select the **API Credentials** option.
34 | 1. Select the **ws** (Web Service) API.
35 | 1. Add a new origin to the list of allowed origins which is the URL of the App Service that has been deployed.
36 |
37 | ### Install and set up the required tools
38 |
39 | - Version 7.1 or later of [PowerShell](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.1).
40 | - Version 2.21.0 or later of [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli).
41 |
42 | ### Set up an Azure subscription with admin access
43 |
44 | For this sample project, you will need admin access in order to deploy all the included artifacts to Azure. If you do not have an Azure subscription, set up a [free trial](https://azure.microsoft.com/).
45 |
46 | ### Set up a service principal on Azure
47 |
48 | For the solution to work, the Web App component needs a privileged credential on your Azure subscription with the scope to execute `read` operations on API Management (get products, subscriptions, etc.).
49 |
50 | Before deploying the resources, set up the service principal in the Azure Active Directory (AAD) tenant used by the Web App to update the status of API Management subscriptions.
51 |
52 | The simplest method is using the Azure CLI.
53 |
54 | 1. [Sign in with Azure CLI](https://docs.microsoft.com/cli/azure/authenticate-azure-cli#sign-in-interactively):
55 |
56 | ```azurecli-interactive
57 | az login
58 | ```
59 | 2. [Create an Azure service principal with the Azure CLI](https://docs.microsoft.com/cli/azure/create-an-azure-service-principal-azure-cli#password-based-authentication):
60 |
61 | ```azurecli-interactive
62 | az ad sp create-for-rbac --name --skip-assignment
63 | ```
64 |
65 | 3. Take note of the `name` (ID), `appId` (client ID) and `password` (client secret), as you will need to pass these values as deployment parameters.
66 |
67 | 4. Retrieve the **object ID** of your new service principal for deployment:
68 |
69 | ```azurecli-interactive
70 | az ad sp show --id ""
71 | ```
72 |
73 | The correct role assignments for the service principal will be assigned as part of the deployment.
74 |
75 | ## Deploy the Azure monetization resources
76 |
77 | You can deploy the monetization resource via either Azure portal or PowerShell script.
78 |
79 | >[!NOTE]
80 | > For both options, when filling in parameters, leave the `stripe*` parameters blank.
81 |
82 | ### Azure portal
83 |
84 | Click the button below to deploy the example to Azure and fill in the required parameters in the Azure portal.
85 |
86 | [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2Fazure-api-management-monetization%2Fmain%2Foutput%2Fmain.json)
87 |
88 | ### PowerShell script
89 |
90 | You can deploy by running the `deploy.ps1` PowerShell script at the root of the repo.
91 |
92 | 1. Provide a parameters file for the `main.json` ARM template.
93 | * Find a template for the parameters file provider in `output/main.parameters.template.json`.
94 | * Rename this JSON file to `output/main.parameters.json` and update the values as necessary.
95 |
96 | 2. Execute the `deploy.ps1` script:
97 |
98 | ```powershell
99 | deploy.ps1 `
100 | -TenantId "" `
101 | -SubscriptionId "" `
102 | -ResourceGroupName "apimmonetization" `
103 | -ResourceGroupLocation "uksouth" `
104 | -ArtifactStorageAccountName ""
105 | ```
106 |
107 | ## Publish the API Management developer portal
108 |
109 | This example project uses the hosted [API Management developer portal](https://docs.microsoft.com/azure/api-management/api-management-howto-developer-portal).
110 |
111 | You are required to complete a manual step to publish and make the resources visible to customers. See the [Publish the portal](https://docs.microsoft.com/azure/api-management/api-management-howto-developer-portal-customize#publish) for instructions.
112 |
113 | ## Next Steps
114 | * Learn more about [deploying API Management monetization with Adyen](adyen-details.md).
115 | * Learn about the [Stripe deployment](stripe-details.md) option.
--------------------------------------------------------------------------------
/documentation/adyen-details.md:
--------------------------------------------------------------------------------
1 | # How to implement monetization with Azure API Management and Adyen
2 |
3 | You can configure the API Management and Adyen to implement products defined in the revenue model (Free, Developer, PAYG, Basic, Standard, Pro, Enterprise). Once implemented, API consumers can browse, select, and subscribe to products via the developer portal.
4 |
5 | To deliver a consistent end-to-end API consumer experience, you'll synchronize the API Management product policies and the Adyen configuration using a shared configuration file [payment/monetizationModels.json](../payment/monetizationModels.json).
6 |
7 | In this demo project, we'll implement the example revenue model defined in [the monetization overview](https://docs.microsoft.com/azure/api-management/monetization-overview#step-4---design-the-revenue-model) to demonstrate integrating Azure API Management with Adyen.
8 |
9 | ## Adyen
10 |
11 | [Adyen](https://adyen.com/) is a payment provider with which you can securely take payment from consumers.
12 |
13 | With Adyen, you can [tokenize](https://docs.adyen.com/online-payments/tokenization) a consumer's card details to be:
14 |
15 | * Securely stored by Adyen.
16 | * Used to authorize recurring transactions.
17 |
18 | ## Architecture
19 |
20 | The following diagram illustrates:
21 | * The components of the solution across API Management, the billing app, and Adyen.
22 | * The major integration flows between components, including the interactions between the API consumer (both developer and application) and the solution.
23 |
24 | 
25 |
26 | ## API consumer flow
27 |
28 | The API consumer flow describes the end-to-end user journey supported by the solution. Typically, the API consumer is a developer tasked with integrating their organization's own application with your API. The API consumer flow aims to support bringing the user from API discovery, through API consumption, to paying for API usage.
29 |
30 | ### API consumer flow
31 |
32 | 1. Consumer selects **Sign up** in the API Management developer portal.
33 | 2. Developer portal redirects consumer to the billing portal app to register their account via [API Management delegation](https://docs.microsoft.com/azure/api-management/api-management-howto-setup-delegation).
34 | 3. Upon successful registration, consumer is authenticated and returned back to the developer portal.
35 | 4. Consumer selects a product to subscribe to in the developer portal.
36 | 5. Developer portal redirects consumer to the billing portal app via delegation.
37 | 6. Consumer enters a display name for their subscription and selects checkout.
38 | 7. Billing portal app redirects consumer to an embedded Adyen checkout page to enter their payment details.
39 | 8. Adyen saves their payment details.
40 | 9. Consumer's API Management subscription is created.
41 | 10. Usage calculates the invoice monthly, which is then charged to the consumer.
42 |
43 | ### Steps 1 - 3: Register an account
44 |
45 | 1. Find the developer portal for an API Management service at `https://{ApimServiceName}.developer.azure-api.net`.
46 | 1. Select **Sign Up** to be redirected to the billing portal app.
47 | 1. On the billing portal app, register for an account.
48 | * This is handled via [user registration delegation](https://docs.microsoft.com/azure/api-management/api-management-howto-setup-delegation#-delegating-developer-sign-in-and-sign-up).
49 | 1. Upon successful account creation, the consumer is authenticated and redirected to the developer portal.
50 |
51 | Once the consumer creates an account, they'll only need to sign into the existing account to browse APIs and products from the developer portal.
52 |
53 | ### Steps 4 - 5: Subscribe to products and retrieve API keys
54 |
55 | 1. Log into the developer portal account.
56 | 1. Search for a product and select **Subscribe** to begin a new subscription.
57 | 1. Consumer will be redirected to the billing portal app.
58 | * This is handled via [product subscription delegation](https://docs.microsoft.com/azure/api-management/api-management-howto-setup-delegation#-delegating-product-subscription).
59 |
60 | ### Steps 5 - 6: Billing portal
61 |
62 | 1. Once redirected to the billing portal, enter a display name for the subscription.
63 | 1. Select **Checkout** to be redirected to the Adyen checkout page.
64 |
65 | ### Steps 7 - 8: Adyen checkout
66 |
67 | 1. On the [Adyen checkout page](../app/src/views/checkout-adyen.ejs), enter the payment details.
68 | * This page collects the consumer's payment details using an Adyen plugin.
69 | 1. Once the card details are confirmed, Adyen sends the request through to the [API for initiating payments](../app/src/routes/adyen.ts).
70 | 1. Create a 0-amount payment for the consumer, passing in:
71 | * A flag to store the payment method and keep the card on file.
72 | * The API Management user ID as the shopper reference.
73 | * A combination of the API Management user ID, API Management product ID, and subscription name as payment reference.
74 |
75 | The saved card details will be used for future transactions related to this subscription.
76 |
77 | ### Step 9: API Management subscription created
78 |
79 | Once the consumer's payment details have been successfully tokenized, we create their API Management subscription so they can use their API keys and access the APIs provided under the subscribed product.
80 |
81 | Unlike the [Stripe](./stripe-deploy.md) implementation, Adyen's subscription creation is done as part of the same API call, with no need for a callback/webhook.
82 |
83 | ### Step 10: Billing
84 |
85 | On the first of each month, a [CRON job](https://www.npmjs.com/package/node-cron) is run. The CRON job is defined in the main [index.ts file](../app/src/index.ts) for the app, and:
86 | * Calls into the [calculateInvoices method on the AdyenBillingService](../app/src/services/adyenBillingService.ts) to calculate the invoices for all API Management subscriptions.
87 | * Charges the consumer's cards.
88 |
89 | This method contains the logic for calculating the payment amount, using:
90 | * The product to which the consumer has subscribed.
91 | * The usage data from API Management.
92 |
93 | 1. The CRON job calculates `UsageUnits` by dividing the total number of API calls by 100 (since our pricing model works in units of 100 calls).
94 |
95 | 1. The following logic is used to calculate the amount, based on the pricing model for the product:
96 |
97 | ```ts
98 | // Calculate the amount owing based on the pricing model and usage
99 | switch (monetizationModel.pricingModelType) {
100 | case "Free":
101 | amount = 0;
102 | currency = "";
103 | break;
104 | case "Freemium":
105 | case "TierWithOverage":
106 | // We floor this calculation as consumers only pay for full units used
107 | let usageOverage = Math.floor(usageUnits - monetizationModel.prices.unit.quota);
108 |
109 | if (usageOverage < 0) {
110 | usageOverage = 0;
111 | }
112 |
113 | amount = monetizationModel.prices.unit.unitAmount + usageOverage * monetizationModel.prices.metered.unitAmount;
114 | currency = monetizationModel.prices.metered.currency;
115 | break;
116 | case "Tier":
117 | amount = monetizationModel.prices.unit.unitAmount;
118 | currency = monetizationModel.prices.unit.currency;
119 | break;
120 | case "Metered":
121 | // We floor this calculation as consumers only pay for full units used
122 | amount = Math.floor(usageUnits) * monetizationModel.prices.metered.unitAmount;
123 | currency = monetizationModel.prices.metered.currency;
124 | break;
125 | case "Unit":
126 | // We ceiling this calculation as for "Unit" prices, you buy full units at a time
127 | let numberOfUnits = Math.ceil(usageUnits / monetizationModel.prices.unit.quota);
128 |
129 | // The minimum units that someone pays for is 1
130 | if (numberOfUnits <= 0) {
131 | numberOfUnits = 1;
132 | }
133 |
134 | amount = numberOfUnits * monetizationModel.prices.unit.unitAmount;
135 | currency = monetizationModel.prices.unit.currency;
136 | break;
137 | default:
138 | break;
139 | }
140 | }
141 |
142 | ```
143 |
144 | 1. The invoices are passed to the `takePaymentViaAdyen` function.
145 | * This uses the API Management user ID to retrieve the stored payment methods for the subscription.
146 | 1. We use the ID of the stored payment method to authorize a payment for the amount on the invoice.
147 |
148 | ### Step 11: Subscription suspended
149 |
150 | If the payment fails, the API Management subscription is placed in a suspended state.
151 |
152 | ## Next steps
153 |
154 | * Follow [Deploy demo with Adyen](adyen-deploy.md) to deploy the solution described in this document.
155 | * See if [deploying with Stripe](stripe-details.md) is a better method for you.
--------------------------------------------------------------------------------
/documentation/architecture-adyen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/azure-api-management-monetization/6398ea1cad3de0e6c1d13b2000459852729dd02e/documentation/architecture-adyen.png
--------------------------------------------------------------------------------
/documentation/architecture-stripe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/azure-api-management-monetization/6398ea1cad3de0e6c1d13b2000459852729dd02e/documentation/architecture-stripe.png
--------------------------------------------------------------------------------
/documentation/deployment-details.md:
--------------------------------------------------------------------------------
1 | # Azure API Management monetization strategy deployment details
2 |
3 | In this article, you will learn about the technology, resources, and tools that API Management uses to deploy your monetization strategy. Using the provided demo, you will deploy a monetization strategy and define a set of products, APIs, and named values.
4 |
5 | As part of the demo, you'll deploy the following resources:
6 | - An [API Management service](https://azure.microsoft.com/services/api-management/), with the API Management resources required to support the demo project (APIs, Products, Policies, Named Values).
7 | - An [App Service plan](https://docs.microsoft.com/azure/app-service/overview).
8 | - A [Web App for containers](https://azure.microsoft.com/services/app-service/containers/), using the billing portal app container image.
9 | - A [Service Principal role-based access control assignment](https://docs.microsoft.com/azure/role-based-access-control/overview).
10 |
11 | ## Bicep templates
12 |
13 | This project is currently using [Bicep](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep) for local development and deployment. Bicep is a templating language for declaratively deploying Azure resources. Currently, the **Deploy to Azure** button does not support Bicep.
14 |
15 | * Prior to deployment, Bicep must be decompiled into an Azure Resource Manager template, which happens when the solution is built by running the [build.ps1](../build.ps1) script.
16 | * You can find the Azure Resource Manager template generated on build in the [/output](../output/) folder.
17 | * You can run the deployment using the [deploy.ps1](../deploy.ps1) script. Follow the steps in the [README](../README.md) file.
18 |
19 | ## API Management Service
20 |
21 | With the demo, you deploy an instance of Azure API Management service. As part of this deployment, we define a set of products, APIs (with accompanying policies), and named values.
22 |
23 | ### Products
24 |
25 | The API Management instance products are defined as resources as part of the Bicep templates in [templates/apimmonetization-products.bicep](../templates/apimmonetization-products.bicep).
26 |
27 | In the following example product definition, we:
28 | * Define the basic product.
29 | * Define a name, display name, and description.
30 | * Require subscription in order to use this product.
31 | * Require approval before activating the subscription.
32 |
33 | ```bicep
34 | resource ApimServiceName_basic 'Microsoft.ApiManagement/service/products@2019-01-01' = {
35 | properties: {
36 | description: 'Basic tier with a monthly quota of 50,000 calls.'
37 | terms: 'Terms here'
38 | subscriptionRequired: true
39 | approvalRequired: true
40 | state: 'published'
41 | displayName: 'Basic'
42 | }
43 | name: '${ApimServiceName}/basic'
44 | dependsOn: []
45 | }
46 | ```
47 |
48 | We link a separate resource to a policy file for that product.
49 |
50 | ```bicep
51 | resource ApimServiceName_basic_policy 'Microsoft.ApiManagement/service/products/policies@2019-01-01' = {
52 | properties: {
53 | value: concat(artifactsBaseUrl, '/apiConfiguration/policies/products/basic.xml')
54 | format: 'xml-link'
55 | }
56 | name: '${ApimServiceName_basic.name}/policy'
57 | }
58 | ```
59 |
60 | In the following policy file for the basic product, we define an inbound policy that:
61 | * Limits a single subscription to 50,000 calls/month.
62 | * Adds a rate limiting policy, ensuring a single subscription is limited to 100 calls/minute.
63 |
64 | ```xml
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | ```
82 |
83 | We also define who can access each product in the [/templates/apimmonetization-productGroups.bicep](../templates/apimmonetization-productGroups.bicep) Bicep file. Developers and guests are able to sign up to the following products:
84 |
85 | - Free
86 | - Developer
87 | - PAYG
88 | - Basic
89 | - Standard
90 | - Pro
91 | - Enterprise
92 |
93 | Since the *Admin* product is only used internally for communication between services, we don't want to expose it as a product available for consumer sign-up and use.
94 |
95 | ### APIs
96 |
97 | Two APIs are defined as part of the API Management instance deployment:
98 | * Address API (external)
99 | * Billing API (internal)
100 |
101 | Resources of these APIs are defined in the following Bicep templates:
102 | * [templates/apimmonetization-apis-billing.bicep](../templates/apimmonetization-apis-billing.bicep)
103 | * [templates/apimmonetization-apis-address.bicep](../templates/apimmonetization-apis-address.bicep)
104 |
105 | Links between APIs and products are defined in [templates/apimmonetization-productAPIs.bicep](../templates/apimmonetization-productAPIs.bicep).
106 |
107 | Each of these APIs and products:
108 | * Are defined in the Bicep templates.
109 | * Has a set of policies defined.
110 | * Has an Open API definition attached.
111 |
112 | #### Address API
113 |
114 | Address APIs are external APIs. Consumers can only subscribe to address APIs, using a set of differently priced products.
115 |
116 | We provided consumers access to an example address API via API Management and Stripe. In your own solution, replace the example API with the APIs to which your consumers will subscribe. In our example, a subscriber can post an address to the API, which will then be validated.
117 |
118 | See [apiConfiguration/openApi/address.yaml](../apiConfiguration/openApi/address.yaml) for the example address API definition.
119 |
120 | See in [templates/apimmonetization-productAPIs.bicep](../templates/apimmonetization-productAPIs.bicep) how the example API can be accessed using a range of products:
121 |
122 | * Free
123 | * Developer
124 | * PAYG
125 | * Basic
126 | * Standard
127 | * Pro
128 | * Enterprise
129 |
130 | Anyone signing up to any of the above products can access this API using their API key. However, they may be limited to a specific number of calls/month or rate of calls/minute, depending on the product.
131 |
132 | #### Billing API
133 |
134 | Billing APIs are internal APIs with two endpoints defined:
135 |
136 | * **`monetizationModels`** endpoint.
137 | Used to retrieve the monetization models defined in the [payment/monetizationModels.json](../payment/monetizationModels.json) file.
138 | * **`products`** endpoint.
139 | Incoming requests are redirected to the management API. Used to retrieve the products defined on the API Management instance.
140 |
141 | See [apiConfiguration/openApi/billing.yaml](../apiConfiguration/openApi/billing.yaml) for the billing API definition.
142 |
143 | >[!NOTE]
144 | > The billing API is only exposed under the `Admin` product and will not be exposed to consumers.
145 |
146 | ### Named Values
147 |
148 | API Management also provides a concept of named values as part of deployment. Named values allow you to define specific terms, which will be replaced within your policies. For example:
149 |
150 | ```xml
151 |
152 |
153 |
154 |
155 | ```
156 | In the above policy definition, certain values will need to be replaced. We can define named values on the API Management instance and thus automatically override these values.
157 |
158 | Named values are defined in the [templates/apimmonetization-namedValues](../templates/apimmonetization-namedValues.bicep) file. In this file, we set up:
159 | * A list of values
160 | * What the values should be replaced by in the deployed instance.
161 |
162 | ## Billing portal
163 |
164 | Aside from API Management, the deployment script also deploys the billing portal resource. The billing portal is a `Node.js` app. Consumers directed to the billing portal to activate their subscriptions. You can handle the integration between API Management and the billing portal with the [user registration and product subscription delegation features in API Management](https://docs.microsoft.com/azure/api-management/api-management-howto-setup-delegation).
165 |
166 | As part of the main deployment, the billing portal app is deployed to [Azure Web App for Containers](https://azure.microsoft.com/services/app-service/containers/). The container image is pulled from the [GitHub Container Registry](https://docs.github.com/en/packages/guides/about-github-container-registry) associated with this repo.
167 |
168 | You can also add configuration to the app as part of the payment provider initialization (Adyen and Stripe).
169 |
170 | ## Next Steps
171 | * Learn more about configuring and initializing both [Stripe](stripe-details.md) and [Adyen](adyen-details.md) in more detail.
172 | * Understand how [API Management supports monetization](https://docs.microsoft.com/azure/api-management/monetization-support).
--------------------------------------------------------------------------------
/documentation/stripe-deploy.md:
--------------------------------------------------------------------------------
1 | # Deploy demo with Stripe
2 |
3 | In this tutorial, you'll deploy the demo Stripe account and learn how to:
4 |
5 | > [!div class="checklist"]
6 | > * Set up a Stripe account, the required PowerShell and `az cli` tools, an Azure subscription, and a service principal on Azure.
7 | > * Deploy the Azure resources using either Azure portal or PowerShell.
8 | > * Make your deployment visible to consumers by publishing the Azure developer portal.
9 | > * Initialize the Stripe products and prices.
10 |
11 | ## Pre-requisites
12 |
13 | To prepare for this demo, you'll need to:
14 |
15 | > [!div class="checklist"]
16 | > * Create a Stripe account.
17 | > * Install and set up the required PowerShell and Azure CLI tools.
18 | > * Set up an Azure subscription.
19 | > * Set up a service principal in Azure.
20 |
21 | ### [Create a Stripe account](https://dashboard.stripe.com/register)
22 |
23 | 1. Once you've [created a Stripe account](https://dashboard.stripe.com/register), navigate to the **Developers** tab in the Stripe dashboard.
24 | 1. Use the **API keys** menu to create the following two API keys with specific permissions on different APIs.
25 |
26 | | Key name | Description | Permissions |
27 | |------------------------|--------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
28 | | **Initialization key** | Use to initialize Stripe with products, prices, and webhooks |
Products: `write`
Prices: `write`
Webhook endpoints: `write`
|
29 | | **App key** | Used by application to create checkout sessions, subscriptions, and payments for consumers |
Checkout sessions: `write`
Subscriptions: `write`
Usage records: `write`
Prices: `read`
Products: `read`
|
30 |
31 | ### Install and set up the required tools
32 |
33 | - Version 7.1 or later of [PowerShell](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.1).
34 | - Version 2.21.0 or later of [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli).
35 |
36 | ### Set up an Azure subscription with admin access
37 |
38 | For this sample project, you will need admin access in order to deploy all the included artifacts to Azure. If you do not have an Azure subscription, set up a [free trial](https://azure.microsoft.com/).
39 |
40 | ### Set up a service principal on Azure
41 |
42 | For the solution to work, the Web App component needs a privileged credential on your Azure subscription with the scope to execute `read` operations on API Management (get products, subscriptions, etc.).
43 |
44 | Before deploying the resources, set up the service principal in the Azure Active Directory (AAD) tenant used by the Web App to update the status of API Management subscriptions.
45 |
46 | The simplest method is using the Azure CLI.
47 |
48 | 1. [Sign in with Azure CLI](https://docs.microsoft.com/cli/azure/authenticate-azure-cli#sign-in-interactively):
49 |
50 | ```azurecli-interactive
51 | az login
52 | ```
53 | 2. [Create an Azure service principal with the Azure CLI](https://docs.microsoft.com/cli/azure/create-an-azure-service-principal-azure-cli#password-based-authentication):
54 |
55 | ```azurecli-interactive
56 | az ad sp create-for-rbac --name --skip-assignment
57 | ```
58 |
59 | 3. Take note of the `name` (ID), `appId` (client ID) and `password` (client secret), as you will need to pass these values as deployment parameters.
60 |
61 | 4. Retrieve the **object ID** of your new service principal for deployment:
62 |
63 | ```azurecli-interactive
64 | az ad sp show --id --query '{displayName: displayName, appId: appId, objectId: id}'
65 | ```
66 |
67 | The correct role assignments for the service principal will be assigned as part of the deployment.
68 |
69 | ## Deploy the Azure monetization resources
70 |
71 | You can deploy the monetization resource via either Azure portal or PowerShell script.
72 |
73 | >[!NOTE]
74 | > For both options, when filling in parameters, leave the `adyen*` parameters blank.
75 |
76 | ### Azure portal
77 |
78 | Click the button below to deploy the example to Azure and fill in the required parameters in the Azure portal.
79 |
80 | [](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fmicrosoft%2Fazure-api-management-monetization%2Fmain%2Foutput%2Fmain.json)
81 |
82 | ### PowerShell script
83 |
84 | You can deploy by running the `deploy.ps1` PowerShell script at the root of the repo.
85 |
86 | 1. Provide a parameters file for the `main.json` ARM template.
87 | * Find a template for the parameters file provider in `output/main.parameters.template.json`.
88 | * Rename this JSON file to `output/main.parameters.json` and update the values as necessary.
89 |
90 | 2. Execute the `deploy.ps1` script:
91 |
92 | ```powershell
93 | deploy.ps1 `
94 | -TenantId "" `
95 | -SubscriptionId "" `
96 | -ResourceGroupName "apimmonetization" `
97 | -ResourceGroupLocation "uksouth" `
98 | -ArtifactStorageAccountName ""
99 | ```
100 |
101 | ## Publish the API Management developer portal
102 |
103 | This example project uses the hosted [API Management developer portal](https://docs.microsoft.com/azure/api-management/api-management-howto-developer-portal).
104 |
105 | You are required to complete a manual step to publish and make the resources visible to customers. See the [Publish the portal](https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-developer-portal-customize#publish) for instructions.
106 |
107 | ## Initialize Stripe products and prices
108 |
109 | Once you've deployed the billing portal, the API Management service, and the products defined within API Management, you'll need to initialize the products in Stripe. Use [the Stripe initialization PowerShell script](../payment/stripeInitialisation.ps1).
110 |
111 | 1. Run the script using the following parameters:
112 |
113 | ```powershell
114 | ./payment/stripeInitialisation.ps1 `
115 | -StripeApiKey "" `
116 | -ApimGatewayUrl "" `
117 | -ApimSubscriptionKey "" `
118 | -StripeWebhookUrl "https:///webhook/stripe" `
119 | -AppServiceResourceGroup "" `
120 | -AppServiceName ""
121 | ```
122 |
123 | 1. The script makes two API calls:
124 |
125 | * To retrieve the API Management products.
126 | * To retrieve the monetization model definitions.
127 |
128 | 1. For each of the monetization models defined, the script:
129 |
130 | * Finds the corresponding APIM product.
131 | * Uses the Stripe CLI to create a Stripe product.
132 | * For that Stripe product, creates the corresponding price for the model.
133 |
134 | 1. The script:
135 |
136 | * Creates a webhook in Stripe to listen for:
137 | * Stripe subscription created events (to create API Management subscriptions when a consumer completes checkout).
138 | * Failed/cancelled Stripe subscription events (to deactivate API Management subscriptions when consumers cease payment).
139 | * Adds the secret for webhook connection to the billing portal app settings, so that the app can attach listeners and handle these events.
140 |
141 | ## Next Steps
142 |
143 | * Learn more about [deploying API Management monetization with Stripe](stripe-details.md).
144 | * Learn about the [Adyen deployment](adyen-details.md) option.
145 |
--------------------------------------------------------------------------------
/documentation/stripe-details.md:
--------------------------------------------------------------------------------
1 | # How to implement monetization with Azure API Management and Stripe
2 |
3 | You can configure the API Management and Stripe to implement products defined in the revenue model (Free, Developer, PAYG, Basic, Standard, Pro, Enterprise). Once implemented, API consumers can browse, select, and subscribe to products via the developer portal.
4 |
5 | To deliver a consistent end-to-end API consumer experience, you'll synchronize the API Management product policies and the Stripe configuration using a shared configuration file [payment/monetizationModels.json](../payment/monetizationModels.json).
6 |
7 | In this demo project, we'll implement the example revenue model defined in [the monetization overview](https://docs.microsoft.com/azure/api-management/monetization-overview#step-4---design-the-revenue-model) to demonstrate integrating Azure API Management with Stripe.
8 |
9 | ## Stripe
10 |
11 | As a tech company, [Stripe](https://stripe.com/) builds economic infrastructure for the internet. Stripe provides a fully featured payment platform. With Stripe's platform, you can monetize your APIs hosted in Azure API Management to API consumers.
12 |
13 | Both API Management and Stripe define the concept of products and subscriptions, but only Stripe has the notion of pricing.
14 |
15 | In Stripe, you can define one or more associated prices against a product. Recurring prices (billed more than once) can be `Licensed` or `Metered`.
16 |
17 | | Recurring prices | Description |
18 | | ---------------- | ----------- |
19 | | `Licensed` | Billed automatically at the given interval. In the example, it's set to monthly. |
20 | | `Metered` | Calculates the monthly cost based on
Usage records
The set price per unit
|
21 |
22 | The following table builds on the conceptual revenue model in [the monetization overview](https://docs.microsoft.com/azure/api-management/monetization-overview) and provides more detail about implementing using API Management and Stripe:
23 |
24 | | Products implemented in both API Management and Stripe | Pricing model | Stripe configuration | Quality of service (API Management product policies) |
25 | |------------------------------------------------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
26 | | Free | `Free` | No configuration required. | Quota set to limit the consumer to 100 calls/month. |
27 | | Developer | `Freemium ` | Metered, graduated tiers:
First tier flat amount is $0.
Next tiers per unit amount charge set to charge $0.20/100 calls.
| No quota set. Consumer can continue to make and pay for calls with a rate limit of 100 calls/minute. |
28 | | PAYG | `Metered` | Metered. Price set to charge consumer $0.15/100 calls. | No quota set. Consumer can continue to make and pay for calls with a rate limit of 200 calls/minute. |
29 | | Basic | `Tier` | Licensed. Price set to charge consumer $14.95/month. | Quota set to limit the consumer to 50,000 calls/month with a rate limit of 100 calls/minute. |
30 | | Standard | `Tier + Overage` | Metered, graduated tiers:
First tier flat amount is $89.95/month for first 100,000 calls.
Next tiers per unit amount charge set to charge $0.10/100 calls.
| No quota set. Consumer can continue to make and pay for extra calls with a rate limit of 100 calls/minute. |
31 | | Pro | `Tier + Overage` | Metered, graduated tiers:
First tier flat amount is $449.95/month for first 500,000 calls.
Next tiers per unit amount charge set to charge $0.06/100 calls.
| No quota set. Consumer can continue to make and pay for extra calls with a rate limit of 1,200 calls/minute. |
32 | | Enterprise | `Unit` | Metered, graduated tiers. Every tier flat amount is $749.95/month for 1,500,000 calls. | No quota set. Consumer can continue to make and pay for extra calls with a rate limit of 3,500 calls/minute. |
33 |
34 | ## Architecture
35 |
36 | The following diagram illustrates:
37 | * The components of the solution across API Management, the billing app, and Stripe.
38 | * The major integration flows between components, including the interactions between the API consumer (both developer and application) and the solution.
39 |
40 | 
41 |
42 |
43 | ## API consumer flow
44 |
45 | The API consumer flow describes the end-to-end user journey supported by the solution. Typically, the API consumer is a developer tasked with integrating their organization's own application with your API. The API consumer flow aims to support bringing the user from API discovery, through API consumption, to paying for API usage.
46 |
47 | ### API consumer flow
48 |
49 | 1. Consumer selects **Sign up** in the API Management developer portal.
50 | 2. Developer portal redirects consumer to the billing portal app to register their account via [API Management delegation](https://docs.microsoft.com/azure/api-management/api-management-howto-setup-delegation).
51 | 3. Upon successful registration, consumer is authenticated and returned back to the developer portal.
52 | 4. Consumer selects a product to subscribe to in the developer portal.
53 | 5. Developer portal redirects consumer to the billing portal app via delegation.
54 | 6. Consumer enters a display name for their subscription and selects checkout.
55 | 7. Stripe checkout session starts, using the product definition to retrieve the product prices.
56 | 8. Consumer inputs credit card details into Stripe checkout session.
57 | 9. On successful checkout, the API Management subscription is created and enabled.
58 | 10. Based on the product and usage amount, consumer is billed monthly.
59 | 11. If payment fails, subscription is suspended.
60 |
61 | ### Steps 1 - 3: Register an account
62 |
63 | 1. Find the developer portal for an API Management service at `https://{ApimServiceName}.developer.azure-api.net`.
64 | 1. Select **Sign Up** to be redirected to the billing portal app.
65 | 1. On the billing portal app, register for an account.
66 | * Handled via [user registration delegation](https://docs.microsoft.com/azure/api-management/api-management-howto-setup-delegation#-delegating-developer-sign-in-and-sign-up).
67 | 1. Upon successful account creation, the consumer is authenticated and redirected to the developer portal.
68 |
69 | Once the consumer creates an account, they'll only need to sign into the existing account to browse APIs and products from the developer portal.
70 |
71 | ### Steps 4 - 5: Subscribes to products and retrieve API keys
72 |
73 | 1. Log into the developer portal.
74 | 1. Search for a product and select **Subscribe** to begin a new subscription.
75 | 1. Consumer will be redirected to the billing portal app.
76 | * This is handled via [product subscription delegation](https://docs.microsoft.com/azure/api-management/api-management-howto-setup-delegation#-delegating-product-subscription).
77 |
78 | ### Steps 5 - 6: Billing portal
79 |
80 | 1. Once redirected to the billing portal, enter a display name for the subscription.
81 | 1. Select **Checkout** to be redirected to the Stripe checkout page.
82 |
83 | ### Steps 7 - 8: Stripe checkout session
84 |
85 | 1. From the Stripe checkout page, [create a new Stripe checkout session](https://stripe.com/docs/api/checkout/sessions) using a [checkout session API](../app/src/routes/stripe.ts) defined within the application.
86 | 1. Pass into this API:
87 | * The API Management user ID.
88 | * The API Management product ID you wish to activate.
89 | * The URL to return to on checkout completion.
90 | 1. With the product name, retrieve the list of prices linked to that product within Stripe using the [Stripe Node SDK](https://stripe.com/docs/api?lang=node).
91 | * You can also use the monetization model API to retrieve the registered product type using the product name (`Freemium`, `Metered`, `Tier`, `TierWithOverage`, `Unit`, or `MeteredUnit`).
92 | 1. Create a Stripe checkout session using following parameters:
93 |
94 | | Parameter | Description |
95 | | --------- | ----------- |
96 | | **Success url** | The URL consumers are redirected to if the checkout is successful. Hosted within the web application. |
97 | | **Cancel url** | The URL consumers are redirected to if the checkout is canceled. Hosted within the web application. |
98 | | **Payment method types** | Set to "card". |
99 | | **Mode** | Set to "subscription". Consumer will receive recurring charges. |
100 | | **Metadata** | Pass the API Management user ID, product ID, and subscription name.
Retrieve this metadata in the event raised by creating a Stripe subscription.
Use within event listener to create associated API Management subscription.