---
title: "Building a Monetized API, Part 2: Adding Monetization"
description: "Add usage-based billing, metered plans, and Stripe checkout to your API gateway. Set up meters, create free and paid plans with overage pricing, and enable self-serve subscriptions in the developer portal."
canonicalUrl: "https://zuplo.com/blog/2026/04/01/building-a-monetized-api-part-2"
pageType: "blog"
date: "2026-04-01"
authors: "martyn"
tags: "API Monetization, API Gateway"
image: "https://zuplo.com/og?text=Building%20a%20Monetized%20API%2C%20Part%202%3A%20Adding%20Monetization"
---
This is Part 2 of the "Building a Monetized API" series. In
[Part 1](/blog/2026/03/31/building-a-monetized-api-part-1), we set up the Zuplo
API gateway for our Vercel-hosted changelog API, imported endpoints, added
authentication, and configured rate limiting. In this post, we're adding the
monetization layer on top of that.

<CalloutVideo
  variant="card"
  title="Building a Monetized API, Part 2"
  description="Watch the video walkthrough of adding meters, plans, Stripe integration, and self-serve subscriptions to the developer portal."
  videoUrl="/videos/building-a-monetized-api-part-2"
  thumbnailUrl="https://img.youtube.com/vi/jKDroS-xqe0/maxresdefault.jpg"
  duration="23:14"
/>

## Setting Up Meters and Features

Everything starts in the Zuplo monetization service. Before you create any
plans, you need to define what you're actually charging for. That means setting
up **meters** (the things you count) and **features** (the things customers get
access to).

For our changelog API, we're metering API requests and gating access to an MCP
server (which we'll add in Part 3).

### Create a Meter

Go to **Services > Monetization Service** in your Zuplo project. Add a blank
meter and call it `requests`, with an event name of `requests`. This meter will
count every API request that gets made.

### Define Features

Features map to what shows up on your pricing table. Not all features work the
same way. Some are metered (counted against a usage limit), some are boolean (on
or off), and some are purely for display on the pricing page. We need three:

**Requests**: linked to the `requests` meter. This is the usage-based feature
that gets counted against a limit. When a subscriber makes an API call, this
feature's counter increments.

**MCP Server**: not linked to any meter. This is a boolean feature: you either
have access or you don't. Plans can grant or deny it.

**Monthly Fee**: not linked to any meter. This represents the flat subscription
cost on paid plans. It shows the price on the pricing table but doesn't gate
anything.

## Creating the Plans

With meters and features in place, you can start defining plans. We're building
three: Free, Starter, and Pro.

### Free Plan

Add a new plan called `free` with monthly billing. This is a single-phase plan
that runs indefinitely (or until the subscriber cancels).

Add the `requests` feature to the phase with a **free pricing model**. Set the
usage limit to 20. That's intentionally low for demonstration purposes, but it
shows how hard limits work on free plans. Once a free user hits 20 requests in a
billing period, they're cut off.

### Starter Plan ($29.99/month)

The Starter plan introduces two concepts: a flat monthly fee and graduated
overage pricing.

First, add the **monthly fee** feature as a flat fee of $29.99, paid in advance
once per month.

Then add the **requests** feature using a **tiered pricing model** with
**graduated** mode. Set up two tiers:

- First 5,000 requests: $0 (included in the monthly fee)
- 5,001 to unlimited: $0.10 per request

Set the usage limit to 5,000 and toggle on **soft limit**. This is important. A
soft limit means that when a subscriber hits 5,000 requests, access doesn't
stop. Instead, every request beyond 5,000 gets billed at $0.10 each. At the end
of the billing cycle, Stripe charges the subscriber for $29.99 plus whatever
overage they incurred.

Finally, add the **MCP server** feature with a free pricing model and a
**boolean entitlement** set to `true`. Starter subscribers get MCP server access
included in their monthly fee.

### Pro Plan ($99.99/month)

The Pro plan follows the exact same setup steps as Starter, just with different
values: $99.99/month, 50,000 included requests, and $0.01 per request overage
(also with a soft limit). MCP server access is included. There's nothing new to
configure here. If you set up the Starter plan, you already know how to do this
one.

### Publish and Reorder

Once all three plans are created as drafts, reorder them in the pricing table so
they display as Free, Starter, then Pro. Then publish them. These become the
live plans available on your developer portal.

If you want to change plans later, you create new drafts and publish them when
ready. They'll replace the existing versions or sit alongside them as additional
options.

<CalloutDoc
  title="Monetization Plans and Pricing"
  description="Details on phases, free trials, pricing models, and advanced plan configuration."
  href="/docs/articles/monetization/plans"
/>

## Connecting Stripe

Before monetization can work end to end, you need a payment provider. Go to the
monetization service settings and configure your Stripe integration by pasting
in your Stripe secret key. You can find this in the
[Stripe Dashboard](https://dashboard.stripe.com/apikeys) under **Developers >
API keys**.

Use your **Stripe test key** (`sk_test_...`) during development. The sandbox
environment lets you simulate the full checkout flow with fake credit card
numbers from the Stripe documentation. Swap to your production key when you go
live.

<CalloutDoc
  title="Stripe Integration"
  description="Full setup instructions for connecting Stripe to the Zuplo monetization service."
  href="/docs/articles/monetization/stripe-integration"
/>

## Adding the Monetization Policy to Endpoints

With plans, meters, and Stripe configured, you still need to tell your endpoints
to actually meter requests. This is done with the **monetization inbound
policy**.

The monetization policy does double duty. It handles both API key authentication
and request metering in a single policy, so you don't need a separate API key
auth policy anymore. If you had one set up previously (like we did in Part 1 for
testing), remove it.

The policy configuration is straightforward. The only thing you need to specify
is the meter name and the increment value:

```json
{
  "handler": {
    "export": "MonetizationInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "meters": {
        "requests": 1
      }
    }
  }
}
```

Apply this policy to all your endpoints. In the policy chain, make sure
monetization comes first (before rate limiting and any other policies) since it
needs to authenticate the API key and meter the request before anything else
happens.

<CalloutDoc
  title="Monetization Policy"
  description="Full policy reference including metering options, caching, and advanced configuration."
  href="/docs/articles/monetization/monetization-policy"
/>

## Enabling Monetization on the Developer Portal

The developer portal doesn't know about monetization by default. You need to add
the monetization plugin to your Zudoku configuration.

In your project's `docs` folder, open the Zudoku config file and import the
monetization plugin:

```typescript
import { zuploMonetizationPlugin } from "@zuplo/zudoku-plugin-monetization";
```

Then add it to your plugins array:

```typescript
plugins: [
  // ...other plugins
  zuploMonetizationPlugin(),
],
```

Once saved, the developer portal pulls in all the plan data, pricing tables, and
subscription management UI from the monetization service automatically.

<CalloutDoc
  title="Developer Portal Setup"
  description="Full setup instructions for enabling monetization in the developer portal."
  href="/docs/articles/monetization/developer-portal"
/>

## Testing the Full Flow

With everything wired up, the developer portal now shows a pricing table with
all three plans. Here's what the subscriber experience looks like:

**Sign up and subscribe.** A new user logs in (or signs up) on the developer
portal. They see the pricing table and can select a plan. Subscribing to the
free plan skips Stripe checkout entirely. Paid plans redirect to a Stripe
checkout page.

![The developer portal pricing table showing Free, Starter, and Pro plans](/media/posts/2026-04-01-building-a-monetized-api-part-2/pricing-table.png)

**Get API keys.** After subscribing, the user lands on a "My Subscriptions" page
with their subscription details, usage analytics, and API keys. Keys are
provisioned automatically and can be rolled or deleted from this page.

**Make requests.** API keys work immediately. The user can test directly from
the interactive API reference in the developer portal, where their key is
pre-populated in the auth dropdown.

**Track usage.** Every request increments the meter. The subscription page shows
real-time usage against the plan's limit. On the free plan with a hard limit of
20, the 21st request gets blocked. On paid plans with soft limits, requests
beyond the included amount get billed as overage.

![The My Subscriptions page showing plan details, usage tracking, and API key management](/media/posts/2026-04-01-building-a-monetized-api-part-2/subscriptions.png)

**Upgrade plans.** Subscribers can switch plans from the subscription management
page. Upgrading to a paid plan triggers Stripe checkout. Downgrading is
available too. Plan changes take effect immediately, and the previous plan shows
as expired in the subscription history.

**View subscribers.** Back in the Zuplo monetization service, the subscribers
table shows every customer, their subscription history, and their current plan
status.

![The subscriber detail view in the Zuplo monetization service showing subscription history](/media/posts/2026-04-01-building-a-monetized-api-part-2/subscribers.png)

## What we built in Part 2

At this point, the monetization layer is fully wired up:

- [x] Meters tracking every API request
- [x] Three plans (Free, Starter, Pro) with hard and soft limits
- [x] Stripe connected for checkout and billing
- [x] Monetization policy replacing the standalone API key auth
- [x] Developer portal with a self-serve pricing table and subscription
      management
- [x] End-to-end flow tested: sign up, subscribe, get keys, make requests, track
      usage

Everything from Part 1 (origin auth, consumer isolation, rate limiting) still
works. The monetization policy took over API key authentication, but the custom
header policy that sets the gateway secret and consumer ID didn't need to change
at all.

## What's Next

In [Part 3](/blog/2026/04/02/building-a-monetized-api-part-3), we'll add an MCP
server to the project and write custom code to feature-gate it so that only paid
subscribers can access it. After that, in
[Part 4](/blog/2026/04/03/building-a-monetized-api-part-4), we'll polish the
developer portal to make it look production-ready.