ZuploZuplo
LoginStart for Free
  • Documentation
  • API Reference
Introduction
Getting Started
    Develop on the web portal
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingDynamic MCP Server - Quickstart
    Develop locally with the CLI
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingDynamic MCP Server - Quickstart
Concepts
Development
Policies
Handlers
API Keys
Rate Limiting
MCP Server
MCP Gateway
AI Gateway
Developer Portal
Monetization
    OverviewQuickstart
    Concepts
    Guides
      Stripe IntegrationDeveloper PortalMonetization PolicySubscription DataDynamic MeteringProgrammatic MonetizationSubscription LifecyclePrivate PlansTax CollectionGoing to Production
    Reference
    TroubleshootingThird-Party IntegrationsCustom Monetization
Deploying & Source Control
Analytics
Observability
Networking & Infrastructure
Account Management
Programming API
Build with AI
Zuplo CLI
Migration Guides
Platform LimitsSecuritySupportTrust & ComplianceChangelog
powered by Zudoku
Guides

Reading Subscription Data

When the MonetizationInboundPolicy authenticates a request, it looks up the caller's subscription — their plan, entitlements, payment status, and billing dates — and stores it on the request context. Read that data from your own code with the static MonetizationInboundPolicy.getSubscriptionData method to make decisions, personalize responses, or log which plan a request ran on.

Where you can call it

getSubscriptionData returns data that the monetization policy puts on the context, so it only returns a value after the monetization-inbound policy has run. Call it from:

  • A custom code inbound policy placed after monetization-inbound in the route's inbound pipeline.
  • The route handler, which always runs after inbound policies.

On a route without the monetization policy — or in a policy that runs before it — the method returns undefined. Always handle that case.

The monetization-inbound policy must come before any policy that reads the subscription. If your policy runs first, the subscription data isn't on the context yet. See pipeline ordering.

Basic usage

Code
import { MonetizationInboundPolicy, HttpProblems, ZuploContext, ZuploRequest, } from "@zuplo/runtime"; export default async function (request: ZuploRequest, context: ZuploContext) { const subscription = MonetizationInboundPolicy.getSubscriptionData(context); if (!subscription) { return HttpProblems.forbidden(request, context, { detail: "No active subscription", }); } context.log.info(`Request on plan: ${subscription.plan.key}`); return request; }

The subscription object

getSubscriptionData returns a MonetizationSubscription. The fields you reach for most are the plan and the entitlements map:

Code
interface MonetizationSubscription { id: string; customerId: string; name: string; status: string; currency: string; plan: { id: string; name: string; key: string; // Stable identifier — switch on this in code version: number; description?: string; }; // Keyed by meter or feature key entitlements: Record< string, { balance: number; // Remaining allowance this period hasAccess: boolean; // false when no access or quota spent overage: number; // Usage beyond the included allowance usage: number; // Consumed this period } >; paymentStatus?: { status: "paid" | "not_required" | "pending" | "failed" | "uncollectible"; isFirstPayment: boolean; lastPaymentFailedAt?: string; lastPaymentSucceededAt?: string; }; billingCadence: string; // ISO 8601 duration, e.g. "P1M" for monthly billingAnchor: string; nextBillingDate: string; activeFrom: string; activeTo?: string; maxPaymentOverdueDays: number; accessBlocked?: boolean; createdAt: string; updatedAt: string; }

Switch on plan.key rather than plan.name in your logic — the key is a stable identifier, while the name is a display label that can change.

Reading entitlements

Each entry in entitlements describes one metered feature or static feature on the subscription. The key is the meter or feature key; the value reports the caller's standing against it:

Code
const subscription = MonetizationInboundPolicy.getSubscriptionData(context); const apiCalls = subscription?.entitlements["api_requests"]; if (apiCalls) { context.log.info( `api_requests — used ${apiCalls.usage}, ${apiCalls.balance} remaining`, ); }
  • hasAccess is the quickest check for "can this caller use this feature" — it's false when the plan doesn't include the feature or the quota has run out.
  • balance is the remaining allowance. A balance of 0 or less means no allowance remains.
  • usage and overage report consumption this billing period.

Caveats

  • Returns undefined when the monetization policy hasn't run. Guard every call.
  • The policy caches the data. Subscription and entitlement data is cached for up to cacheTtlSeconds (60 seconds minimum), so balance, usage, and overage can lag real-time consumption by the length of the cache window. Treat them as recent, not exact.

Next steps

  • Programmatic Monetization — gate operations by plan and meter requests based on the response.
  • Dynamic Metering — set meter values at runtime from code.
  • Monetization Policy Reference — every policy configuration option.
Edit this page
Last modified on June 20, 2026
Monetization PolicyDynamic Metering
On this page
  • Where you can call it
  • Basic usage
  • The subscription object
  • Reading entitlements
  • Caveats
  • Next steps
TypeScript
TypeScript
TypeScript