Skip to content

Commit

Permalink
new step 1
Browse files Browse the repository at this point in the history
  • Loading branch information
ntotten committed Feb 21, 2024
1 parent 06a5794 commit cf5dd32
Show file tree
Hide file tree
Showing 17 changed files with 148 additions and 86 deletions.
103 changes: 103 additions & 0 deletions docs/articles/monetization-dev-portal-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
title: Step 1 - Setup Developer Portal Monetization
---

This tutorial will walk through the steps required to monetize your Zuplo
managed API. If you don't already have a Zuplo API, you can create a new project
and use the "Todo" sample or follow the
[getting started quickstart](./step-1-setup-basic-gateway.md).

After you have a working Zuplo API, you can proceed to monetizing your API.

The first step to monetize our API is to enable the pricing page and checkout in
the API Developer Portal.

## 1/ Stripe Pricing Table

Before you can enable monetization, you need to have a couple things setup in
stripe. If you don't already
[have a Stripe account](https://dashboard.stripe.com/register) you'll need to
create one.

::: tip

You don't need to go through the full setup of Stripe. You can follow this
tutorial using Stripe's test mode.

:::

Your API customers will subscribe to "Plans". Plans are associated with
[Stripe Products](https://docs.stripe.com/products-prices/overview). The Stripe
Product is what determines the price your customers will pay for access to your
API. 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 and the
"Premium" plan is limited to 1,000,000 requests per month.

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)

After you have 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/ Add Stripe Environment Variable

In order for your Zuplo API to connect to Stripe, you'll need to set add your
Stripe API Key as an environment variable.

1. 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 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-1.png)

## 3/ Configure Dev Portal Monetization

Next, you will enable the monetization pages in your developer portal.

1. Open the **Code** tab in the Zuplo Portal and select the file
`dev-portal.json`.
2. Scroll to the bottom of the form 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_test_` or `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-2.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.

## 4/ Preview Your Developer Portal

Now that your Developer Portal is configured for monetization you can open it up
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-3.png)

Open the **Pricing** page in your developer portal to see the pricing table.

:::caution

Don't go through the process of purchasing an API plan yet. In the next step we
will configure the Stripe Webhook that will tell your API that a subscription
was created.

:::

![NICE PRICING TABLE IMAGE HERE](https://example.com)
20 changes: 0 additions & 20 deletions docs/articles/monetization-understanding-stripe.md

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 2 additions & 8 deletions sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,7 @@
"label": "Monetization",
"items": [
"articles/monetization-intro",
"articles/monetization-understanding-stripe",
"articles/monetization-create-stripe-product",
"articles/monetization-create-zuplo-api",
"articles/monetization-creating-api-plan",
"articles/monetization-pricing-page",
"articles/monetization-configure-webhook",
"articles/monetization-test-api"
"articles/monetization-dev-portal-setup"
]
},
{
Expand Down Expand Up @@ -342,4 +336,4 @@
}
]
}
]
]
66 changes: 33 additions & 33 deletions src/components/Icon.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useId } from 'react'
import clsx from 'clsx'
import clsx from "clsx";
import { useId } from "react";

import { InstallationIcon } from '@/components/icons/InstallationIcon'
import { LightbulbIcon } from '@/components/icons/LightbulbIcon'
import { PluginsIcon } from '@/components/icons/PluginsIcon'
import { PresetsIcon } from '@/components/icons/PresetsIcon'
import { ThemingIcon } from '@/components/icons/ThemingIcon'
import { WarningIcon } from '@/components/icons/WarningIcon'
import { InstallationIcon } from "@/components/icons/InstallationIcon";
import { LightbulbIcon } from "@/components/icons/LightbulbIcon";
import { PluginsIcon } from "@/components/icons/PluginsIcon";
import { PresetsIcon } from "@/components/icons/PresetsIcon";
import { ThemingIcon } from "@/components/icons/ThemingIcon";
import { WarningIcon } from "@/components/icons/WarningIcon";

const icons = {
installation: InstallationIcon,
Expand All @@ -15,25 +15,25 @@ const icons = {
theming: ThemingIcon,
lightbulb: LightbulbIcon,
warning: WarningIcon,
}
};

const iconStyles = {
blue: '[--icon-foreground:theme(colors.gray.900)] [--icon-background:theme(colors.white)]',
blue: "[--icon-foreground:theme(colors.gray.900)] [--icon-background:theme(colors.white)]",
amber:
'[--icon-foreground:theme(colors.amber.900)] [--icon-background:theme(colors.amber.100)]',
}
"[--icon-foreground:theme(colors.amber.900)] [--icon-background:theme(colors.amber.100)]",
};

export function Icon({
icon,
color = 'blue',
color = "blue",
className,
...props
}: {
color?: keyof typeof iconStyles
icon: keyof typeof icons
} & Omit<React.ComponentPropsWithoutRef<'svg'>, 'color'>) {
let id = useId()
let IconComponent = icons[icon]
color?: keyof typeof iconStyles;
icon: keyof typeof icons;
} & Omit<React.ComponentPropsWithoutRef<"svg">, "color">) {
let id = useId();
let IconComponent = icons[icon];

return (
<svg
Expand All @@ -45,27 +45,27 @@ export function Icon({
>
<IconComponent id={id} color={color} />
</svg>
)
);
}

const gradients = {
blue: [
{ stopColor: '#0EA5E9' },
{ stopColor: '#22D3EE', offset: '.527' },
{ stopColor: '#818CF8', offset: 1 },
{ stopColor: "#0EA5E9" },
{ stopColor: "#22D3EE", offset: ".527" },
{ stopColor: "#818CF8", offset: 1 },
],
amber: [
{ stopColor: '#FDE68A', offset: '.08' },
{ stopColor: '#F59E0B', offset: '.837' },
{ stopColor: "#FDE68A", offset: ".08" },
{ stopColor: "#F59E0B", offset: ".837" },
],
}
};

export function Gradient({
color = 'blue',
color = "blue",
...props
}: {
color?: keyof typeof gradients
} & Omit<React.ComponentPropsWithoutRef<'radialGradient'>, 'color'>) {
color?: keyof typeof gradients;
} & Omit<React.ComponentPropsWithoutRef<"radialGradient">, "color">) {
return (
<radialGradient
cx={0}
Expand All @@ -78,19 +78,19 @@ export function Gradient({
<stop key={stopIndex} {...stop} />
))}
</radialGradient>
)
);
}

export function LightMode({
className,
...props
}: React.ComponentPropsWithoutRef<'g'>) {
return <g className={clsx('dark:hidden', className)} {...props} />
}: React.ComponentPropsWithoutRef<"g">) {
return <g className={clsx("dark:hidden", className)} {...props} />;
}

export function DarkMode({
className,
...props
}: React.ComponentPropsWithoutRef<'g'>) {
return <g className={clsx('hidden dark:inline', className)} {...props} />
}: React.ComponentPropsWithoutRef<"g">) {
return <g className={clsx("hidden dark:inline", className)} {...props} />;
}
26 changes: 2 additions & 24 deletions src/components/markdown/index.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,12 @@
import Pre from "@/components/Pre";
import GithubButton from "@/components/markdown/GithubButton";
import { MDXProvider } from "@mdx-js/react";
import { ChevronLeftIcon } from "lucide-react";
import Callout from "./Callout";
import ZupIt from "./ZupIt";
import {
ApiTestConsoleTabIcon,
BuildStatusTabIcon,
CodeEditorTabIcon,
CopyIcon,
DashboardTabIcon,
DeveloperPortalIcon,
GitHubIcon,
LiveLogsTabIcon,
SettingsTabIcon,
ShowIcon,
} from "./ui-icons";
import * as UIIcons from "./ui-icons";

const components: React.ComponentProps<typeof MDXProvider>["components"] = {
ChevronLeftIcon,
CodeEditorTabIcon,
ApiTestConsoleTabIcon,
LiveLogsTabIcon,
DashboardTabIcon,
BuildStatusTabIcon,
SettingsTabIcon,
DeveloperPortalIcon,
CopyIcon,
ShowIcon,
GitHubIcon,
...UIIcons,
GithubButton,
Callout,
ZupIt,
Expand Down
9 changes: 8 additions & 1 deletion src/components/markdown/ui-icons.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {
CogIcon,
CopyIcon as CopyIconLucide,
EyeIcon,
FileTextIcon,
LayoutTemplateIcon,
ListEnd,
ListIcon,
PresentationIcon,
RssIcon,
ZapIcon,
CopyIcon as CopyIconLucide,
} from "lucide-react";
import { FC, PropsWithChildren } from "react";

Expand Down Expand Up @@ -73,6 +74,12 @@ export const ShowIcon: FC = () => (
</SvgWrapper>
);

export const EnvironmentVariablePicker: FC = () => (
<SvgWrapper>
<ListEnd />
</SvgWrapper>
);

export const GitHubIcon: FC = () => (
<svg
style={{ height: "21px", width: "21px", verticalAlign: "middle" }}
Expand Down

0 comments on commit cf5dd32

Please sign in to comment.