Plans are pricing options embedded within products. They define how customers pay for access — whether through a flat recurring fee, per-unit usage charges, a one-time purchase, or a combination of recurring and usage-based billing.
Plan Types
SolvaPay supports four plan types, each optimized for different monetization strategies:
Recurring
Fixed-price plans billed on a regular cycle. Best for SaaS subscriptions with predictable pricing.
| Field | Type | Description |
|---|
billingCycle | enum | weekly, monthly, quarterly, yearly, or custom |
setupFee | number | One-time fee charged on first billing |
trialDays | number | Free trial period before billing starts |
autoRenew | boolean | Whether the plan auto-renews at period end |
cancellationNoticeDays | number | Notice required to cancel (default: 1 day) |
pricingTiers | array | Optional tiered pricing (e.g. Basic, Pro, Enterprise) |
prorationPolicy | object | How to handle mid-cycle upgrades/downgrades |
limits | object | Optional maxTransactions cap |
{
"type": "recurring",
"price": 1900,
"currency": "USD",
"billingCycle": "monthly",
"trialDays": 14,
"autoRenew": true,
"features": {
"api_access": true,
"priority_support": true
}
}
Usage-based
Pay-per-use plans where customers are billed based on actual consumption tracked through usage events.
| Field | Type | Description |
|---|
measures | string | What the plan measures for usage tracking (value: 'requests') |
billingModel | enum | pre-paid (pay upfront for a quota) or post-paid (pay after usage) |
creditsPerUnit | number | Credits deducted per metered unit |
limit | number | Hard usage cap per period (0 = unlimited) |
freeUnits | number | Units included before billing starts |
rolloverUnusedUnits | boolean | Carry unused units to the next period |
billingCycle | string | Required for post-paid plans |
limits | object | Optional maxTransactions, maxUsage |
{
"type": "usage-based",
"price": 0,
"billingModel": "post-paid",
"billingCycle": "monthly",
"measures": "requests",
"creditsPerUnit": 10,
"freeUnits": 100,
"limit": 10000
}
Each usage-based plan is automatically linked to the provider’s requests meter. When checking limits, SolvaPay queries the Usage timeseries for the customer’s total usage in the current billing period and compares it against the plan’s limit.
Hybrid
Combines a recurring base price with usage-based overage billing. Best for enterprise SaaS where customers pay a base fee that includes some usage, with additional charges for overages.
| Field | Type | Description |
|---|
basePrice | number | Fixed recurring portion |
billingCycle | enum | Same options as recurring plans |
measures | string | What the plan measures for usage tracking (value: 'requests') |
limit | number | Included units in the base price |
freeUnits | number | Additional free units beyond the base |
creditsPerUnit | number | Flat per-unit credit rate (fallback if no tiers) |
usageTiers | array | Volume-based tiered pricing for the usage component |
overagePolicy | object | allowOverage, overageRate, maxOverage |
billingStrategy | object | Whether to bill recurring_first, usage_first, or combined |
{
"type": "hybrid",
"basePrice": 4900,
"currency": "USD",
"billingCycle": "monthly",
"measures": "requests",
"limit": 1000,
"freeUnits": 0,
"creditsPerUnit": 5,
"overagePolicy": {
"allowOverage": true,
"overageRate": 8,
"maxOverage": 5000
},
"usageTiers": [
{ "name": "Standard", "minUsage": 0, "maxUsage": 500, "creditsPerUnit": 5 },
{ "name": "High Volume", "minUsage": 501, "maxUsage": 2000, "creditsPerUnit": 3 },
{ "name": "Enterprise", "minUsage": 2001, "creditsPerUnit": 1 }
]
}
One-Time
Single-purchase plans for digital goods, lifetime access, or physical products.
| Field | Type | Description |
|---|
isRecurring | boolean | Whether the one-time purchase can be repeated |
limits | object | Optional maxTransactions |
availability | object | startDate, endDate, maxQuantity, currentQuantity |
fulfillment | object | type (digital/physical), deliveryMethod, estimatedDelivery |
warranty | object | duration, unit, terms |
returnPolicy | object | allowed, period, conditions |
{
"type": "one-time",
"price": 9900,
"currency": "USD",
"fulfillment": {
"type": "digital",
"deliveryMethod": "instant"
}
}
Common Plan Fields
All plan types share these base fields:
| Field | Type | Description |
|---|
reference | string | Auto-generated identifier (pln_XXXXXXXX) |
price | number | Base price in smallest currency unit (e.g. cents) for recurring/one-time plans |
currency | string | ISO 4217 currency code for recurring/one-time plans |
status | enum | active, inactive, or archived |
requiresPayment | boolean | Server-derived. true when the plan’s pricing requires payment (based on price, creditsPerUnit, and plan type) |
default | boolean | Whether this is the product’s default plan |
maxActiveUsers | number? | Maximum concurrent users on this plan |
accessExpiryDays | number? | Days until access expires |
features | object | Provider-defined feature flags |
metadata | object | Arbitrary provider-defined metadata |
Plans Are Embedded in Products
Plans are stored as sub-documents inside product documents — there is no separate plans collection. Each product has a plans[] array where each entry is discriminated by the type field.
This means:
- A product owns its plans
- Plans are created, updated, and deleted through the product
- Plan references (
pln_...) are globally unique across all products
Product (prd_myapi)
├── Plan: Free Tier (pln_abc123) — recurring, $0/month
├── Plan: Pro (pln_def456) — usage-based, 10 credits/request
└── Plan: Enterprise (pln_ghi789) — hybrid, $49/month + overage
Plan API
All plan endpoints are scoped to a product:
| Method | Endpoint | Description |
|---|
GET | /sdk/products/:productRef/plans | List plans for a product |
GET | /sdk/products/:productRef/plans/:planRef | Get a single plan |
POST | /sdk/products/:productRef/plans | Create a plan |
PUT | /sdk/products/:productRef/plans/:planRef | Update a plan |
DELETE | /sdk/products/:productRef/plans/:planRef | Delete a plan |
Plans can also be managed via the REST API endpoints listed above.
Default Plan
Each product can have one default plan. Setting a new plan as default automatically un-defaults all other plans in that product. The default plan is used as the fallback for:
- MCP server tool access (when no specific plan is assigned to a tool)
- New customer sign-ups (when auto-provisioning is configured)
For free tiers, freeUnits: 0 means unlimited free usage, not zero available usage.
Plans and MCP Servers
Plans integrate with MCP servers in two ways:
- Server default plan — the
defaultPlanRef on an MCP server determines which plan is used for general tool access
- Per-tool plan assignments — individual MCP tools can reference specific plans via
planIds, enabling tool-level access tiering
When plans are created, updated, or deleted, MCP server configurations are automatically synced.
Purchase Snapshots
When a customer purchases a plan, the plan’s configuration is frozen into a snapshot on the purchase record:
{
"planSnapshot": {
"reference": "pln_abc123",
"price": 1900,
"currency": "USD",
"planType": "usage-based",
"billingCycle": "monthly",
"meterRef": "mtr_abc123",
"limit": 10000,
"freeUnits": 100,
"creditsPerUnit": 10
}
}
This ensures billing is deterministic — changing a plan’s price or limits does not retroactively affect existing purchases.
Next steps