-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add draft monetization docs * update image * last touch * new step 1 * fixed sitebar * fixed image uploader * updated image urls * fix typo and icon * step 2 * fixed sidebar * Updates to intro and step2 * section 3 * Fix small typos * minor fixes * edit stripe note * updated intro image * updated url * added missing image * added new image * images * small changes * More intro edits * Minor tweaks to dev-portal-setup * more intro tweaks * tweak intro v3 * Update step 1 title * edit step 1 * edit section 1 step 1 * More tweaks to step 1 * edit intro & zuplo setup in step 1 * step 1 fixes * Change steps to begin with verbs * tweaks to step 1 title and intro * updated sidebar * first edits step 2 * more edits step 2 * fix build * Added programatic docs * More tweaks to step 2 * step 3 initial changes --------- Co-authored-by: Nathan Totten <[email protected]> Co-authored-by: Luis Campos Guajardo <[email protected]> Co-authored-by: Nick Chen <[email protected]> Co-authored-by: Josh Twist <[email protected]>
- Loading branch information
1 parent
2245356
commit 53a76c8
Showing
49 changed files
with
780 additions
and
179 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,9 @@ | ||
--- | ||
name: Policies Doc | ||
about: File a bug or suggestion for a policy | ||
title: '' | ||
labels: '' | ||
assignees: '' | ||
|
||
title: "" | ||
labels: "" | ||
assignees: "" | ||
--- | ||
|
||
<!-- Describe the issue or suggestion for the policy --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,6 @@ | ||
name: Static Assets | ||
on: | ||
push: | ||
branches: | ||
- main | ||
- nextjs_v2 | ||
|
||
jobs: | ||
policies: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
--- | ||
title: Step 1 - Set Up Developer Portal | ||
sidebar_label: Step 1 - Set Up Developer Portal | ||
--- | ||
|
||
This guide will walk you through the steps required to set up your Zuplo API's | ||
Developer Portal. This is where your customers will see and subscribe to your | ||
API plans. | ||
|
||
If you don't already have a Zuplo API, you can create a new project using the | ||
"ToDo" sample or following step 1 of the | ||
[Getting Started quickstart](./step-1-setup-basic-gateway.md). | ||
|
||
You'll also need a Stripe account. If you don't already have one, you'll need to | ||
[register](https://dashboard.stripe.com/register) for one. | ||
|
||
::: tip | ||
|
||
You don't need to go through the full set up process in Stripe. You can follow | ||
this tutorial using Stripe's test mode. We recommend using | ||
[Test Mode](https://docs.stripe.com/test-mode) on your Stripe account. This will | ||
allow you to test creating subscriptions with different plans without using real | ||
money. | ||
|
||
::: | ||
|
||
Once you have a working Zuplo API and a Stripe account, we can move forward! | ||
|
||
## 1/ Set Up in Stripe | ||
|
||
You need to have a couple things set up in Stripe before enabling Zuplo | ||
monetization. | ||
|
||
Your API customers will subscribe to a "Plan" in Zuplo. Plans are associated | ||
with [Stripe Products](https://docs.stripe.com/products-prices/getting-started). | ||
The Stripe Product is what determines the price your customers will pay to use | ||
your API. | ||
|
||
![](https://cdn.zuplo.com/assets/aa34975a-2906-4869-9dd6-bd13e5b0dcda.png) | ||
|
||
The "Plan" in Zuplo is where you will define the limits of each plan. For | ||
example, the "Basic" plan might be limited to 10,000 requests per month while | ||
the "Premium" plan may be limited to 1,000,000 requests per month. | ||
|
||
### Creating Stripe Products | ||
|
||
When you create your products in Stripe, set each product as **Recurring** on a | ||
**Monthly** billing cycle. | ||
|
||
![](https://cdn.zuplo.com/assets/0b7bc4e5-9e92-4b24-a4d5-16fe389bec8f.png) | ||
|
||
### Creating a Stripe Pricing Table | ||
|
||
Once you've created your products, you will need to create a Stripe Pricing | ||
table. Follow | ||
[Stripe's guide for creating a Pricing Table](https://docs.stripe.com/payments/checkout/pricing-table). | ||
|
||
## 2/ Set Up in Zuplo Portal | ||
|
||
In order for your Zuplo API to connect to Stripe, you'll need to set your Stripe | ||
API Key as an environment variable. | ||
|
||
1. In Stripe, navigate to the | ||
[API keys section](https://dashboard.stripe.com/apikeys) of Stripe's | ||
developer dashboard. Copy the value of the **Secret Key**. | ||
2. Return to the Zuplo Portal, go to your project and open the **Environment | ||
Variables** section in the **Settings** tab. | ||
3. Click **Add Variable** and name your new environment variable | ||
`STRIPE_SECRET_KEY`. | ||
4. Set this variable as a **secret** and paste the Stripe API Key as the value. | ||
Click **Save**. | ||
|
||
![Save Environment Variable](../../public/media/monetization-dev-portal-setup/image-1a.png) | ||
|
||
### Configure Your Developer Portal | ||
|
||
Next, you will enable the monetization pages in your Developer Portal. | ||
|
||
1. In your Zuplo project, go to the **Code** tab and select the file | ||
`dev-portal.json`. | ||
2. Scroll to the **Monetization Settings** section and select the checkbox | ||
**Enable Monetization**. | ||
3. The values for the fields **Pricing Table ID** and **Publishable Key** can be | ||
found by opening the pricing table in the Stripe Dashboard | ||
[Pricing Table](https://dashboard.stripe.com/pricing-tables) section. | ||
4. Copy the value for `pricing-table-id` (it starts with `prctbl_`) and set it | ||
as the value for **Pricing Table ID** in the form in the Zuplo Portal. | ||
5. Copy the value for `publishable-key` (it starts with `pk_`) and set it as the | ||
value for **Publishable Key** in the form in the Zuplo Portal. | ||
|
||
![Pricing Table](../../public/media/monetization-dev-portal-setup/image-2a.png) | ||
|
||
6. Finally, click the <EnvironmentVariablePicker/> icon next to the **Secret | ||
Key** field and select the environment variable `STRIPE_SECRET_KEY` you | ||
created earlier. This will prefill the form with the value | ||
`$env(STRIPE_SECRET_KEY)`. | ||
7. Click save to publish your changes. | ||
|
||
## 3/ Preview Your Developer Portal | ||
|
||
Now that your Developer Portal is configured for monetization you can open it | ||
and view the pricing page. Click the toolbar on the bottom of the Zuplo Portal | ||
to find the URL of your Developer Portal. | ||
|
||
![Dev Portal Link](../../public/media/monetization-dev-portal-setup/image-3a.png) | ||
|
||
Once you open your Developer Portal, you will find a link to the **Pricing** | ||
page on the top right menu section. Open the **Pricing** page in your Developer | ||
Portal to see the pricing table that you have configured as the **Pricing Table | ||
ID** in the previous step. | ||
|
||
![Pricing Table](../../public/media/monetization-dev-portal-setup/image.png) | ||
|
||
:::caution | ||
|
||
Don't go through the process of subscribing to an API plan yet. In the next step | ||
we will configure the Stripe Webhook that will tell your API that a subscription | ||
was created. | ||
|
||
::: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
title: Monetization Glossary | ||
sidebar_label: Glossary | ||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
--- | ||
title: Step 3 - Configure Monetization Policy | ||
sidebar_label: Step 3 - Configure Monetization Policy | ||
--- | ||
|
||
In the previous steps you learned how to set up Stripe and configure your | ||
Developer Portal for monetization. In this step, you will configure your Zuplo | ||
API to ensure that users are allowed to use your API according to the plan they | ||
subscribe to. | ||
|
||
We will configure this using Zuplo's | ||
[API Key Authentication Policy](/docs/policies/api-key-inbound) and the | ||
[Monetization Inbound Policy](/docs/policies/monetization-inbound). | ||
|
||
The Monetization Inbound Policy is what ensures that customers are only able to | ||
call your API withing the quotas set in their Plan. | ||
|
||
## 1/ Add API Key Authentication | ||
|
||
In order to identify customers calling your API, you'll add the | ||
[API Key Authentication Policy](/docs/policies/api-key-inbound). This policy | ||
validates the API Key sent to your API and identifies the user in order to | ||
associate them with the plan which they have subscribed. | ||
|
||
:::tip | ||
|
||
For a full tutorial on the API Key Auth Policy see the | ||
[Getting Started guide](/docs/articles/step-2-add-api-key-auth). | ||
|
||
::: | ||
|
||
1. Open the **Code** section of the Zuplo Portal and select your | ||
`routes.oas.json` file. | ||
|
||
2. Open the route you want to add monetization to and click **Policies**, then | ||
click **+ Add Policy**. | ||
|
||
3. Type `API Key` in the search and select the **API Key Authentication** | ||
policy. | ||
|
||
4. Leave the default configuration and click **OK**. | ||
|
||
Now, all requests to this route will require an API Key to successfully call the | ||
endpoint. | ||
|
||
## 2/ Add the Monetization Policy | ||
|
||
With the user identified via the API Key Authentication policy, next you will | ||
enforce that they are calling the API within the limits of their plan. | ||
|
||
1. Open the **Policies** section of the same route and click **Add Policy**. | ||
|
||
2. Type `Monetization` in the search and select **Monetization**. | ||
|
||
The configuration of this policy is where you specify the meters that are | ||
required in order to call this API. For now, leave the configuration as is, you | ||
can always change it later. | ||
|
||
3. Be sure to save your changes. | ||
|
||
![Policy pipeline](../../public/media/monetization-policy-setup/image.png) | ||
|
||
## 3/ Test the API | ||
|
||
With both policies added to the route, you can now call the API with your | ||
subscription's API Key. | ||
|
||
1. Return to your Developer Portal and open the **API Reference** section. | ||
|
||
2. Find the route you added the policies to in the previous steps. | ||
|
||
3. Above the code sample, next to the route, click the **Test** button. This | ||
will open up the API Playground that you can use to call the API. | ||
|
||
:::note | ||
|
||
The API Key for your subscription will be pre-populated in the `Authorization` | ||
header. | ||
|
||
::: | ||
|
||
4. Edit the API Request if needed and click **Test**. You should see a | ||
successful response. Click **Test** a few more times. | ||
|
||
![Successful response](../../public/media/monetization-policy-setup/image-1.png) | ||
|
||
5. Close the API Playground and click the **Subscription** link in the Dev | ||
Portal header. Notice the Analytics section now shows that you have consumed | ||
some of your request quota from your plan. | ||
|
||
6. Return to the API Playground and click **Test** until you receive an error | ||
response telling you that you have exhausted your quota. | ||
|
||
:::note | ||
|
||
If you set a large number in the **Max Value** of your request quota in the | ||
earlier steps, this is going to take a while. | ||
|
||
::: | ||
|
||
![Max quota status](../../public/media/monetization-policy-setup/image-2.png) | ||
|
||
Congratulations, you are now ready to monetize your API! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
--- | ||
title: Monetization Programmatic Quotas | ||
sidebar_label: Programmatic Quotas | ||
--- | ||
|
||
Typically, when adding monetization to your API, you set the number of meters a | ||
request will consume in the settings of the | ||
[Monetization Policy](https://zuplo.com/docs/policies/monetization-inbound). For | ||
example, the policy below specifies that the request will consume 1 `requests` | ||
meter and 5 `computeUnits` meters. | ||
|
||
```json | ||
{ | ||
"export": "MonetizationInboundPolicy", | ||
"module": "$import(@zuplo/runtime)", | ||
"options": { | ||
"allowRequestsOverQuota": false, | ||
"allowedSubscriptionStatuses": ["active", "incomplete"], | ||
"meterOnStatusCodes": "200-399", | ||
"meters": { | ||
"requests": 1, | ||
"computeUnits": 5 | ||
} | ||
} | ||
} | ||
``` | ||
|
||
However, in some cases, you may not know up front how many units of a particular | ||
meter will be consumed until after the response is sent. For example, maybe your | ||
backend is responsible for computing the `computeUnits` on a request and send | ||
the result in the response in the `compute-units` header. | ||
|
||
In Zuplo, you can support these dynamic meters by writing a little code. To make | ||
the `computeUnits` meter dynamic, first update the policy by setting the | ||
`computeUnits` meter to `0` as shown below. | ||
|
||
```json | ||
{ | ||
"export": "MonetizationInboundPolicy", | ||
"module": "$import(@zuplo/runtime)", | ||
"options": { | ||
"allowRequestsOverQuota": false, | ||
"allowedSubscriptionStatuses": ["active", "incomplete"], | ||
"meterOnStatusCodes": "200-399", | ||
"meters": { | ||
"requests": 1, | ||
"computeUnits": 0 | ||
} | ||
} | ||
} | ||
``` | ||
|
||
Next you can create a | ||
[custom code outbound policy](/docs/policies/custom-code-outbound) that reads | ||
data from the Response (in this case the `compute-units` header) and sets the | ||
meter programmatically. | ||
|
||
```ts title="/modules/set-compute-units-outbound.ts" | ||
import { | ||
MonetizationInboundPolicy, | ||
ZuploRequest, | ||
ZuploContext, | ||
} from "@zuplo/runtime"; | ||
|
||
export default async function ( | ||
response: Response, | ||
request: ZuploRequest, | ||
context: ZuploContext, | ||
options: any, | ||
policyName: string, | ||
) { | ||
const headerValue = response.headers.get("compute-units"); | ||
let computeUnits; | ||
if (headerValue && typeof headerValue === "string") { | ||
computeUnits = parseInt(headerValue); | ||
} | ||
|
||
// Throw an error if the server doesn't send compute units | ||
// Alternatively, you could have a default value | ||
if (!computeUnits) { | ||
throw new Error("Invalid response, no compute units sent."); | ||
} | ||
|
||
// Set the compute units for the request | ||
MonetizationInboundPolicy.setMeters(context, { | ||
computeUnits, | ||
}); | ||
|
||
return response; | ||
} | ||
``` |
Oops, something went wrong.