Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.solvapay.com/llms.txt

Use this file to discover all available pages before exploring further.

Table of contents

Products and plans

Products

A product represents the API, app, or MCP server you monetize.
  • Product reference (prd_...)
  • Name and description
Products are created in SolvaPay Console and are available for SDK integration by default.
const payable = solvaPay.payable({
  product: 'prd_myapi',
})

Plans

A plan defines pricing and access for a product.
  • Plan reference (pln_...)
  • Type: recurring, usage-based, one-time, or hybrid
  • Price and currency
  • Features
  • Status: active, inactive, or archived
Plans are configured as part of product setup. Customers select a plan during activation; the SDK resolves the correct plan from the customer’s purchase automatically.

Product-plan relationship

  • One product can have multiple plans
  • Plans are embedded in products
  • One default plan per product
  • Paywall checks verify plan access for a product

Plan types

TypeDescriptionBest for
RecurringFixed price billed on a cycleSaaS subscriptions
Usage-basedPay-per-use tracked by a meterAPIs and token services
HybridRecurring fee plus usage overageEnterprise mixed workloads
One-timeSingle purchase without recurring billingDigital goods and lifetime access
See Plans overview for full plan behavior.

Meters

Meters define what usage to measure.
  • Default meters: api_requests, requests, api_calls, tokens
  • MCP tool meters: tool:{toolName}
  • Custom meters for business-specific usage
Plans can enforce limits using meter data. See Meters overview for details.

Customer references

A customer reference (customerRef) maps your user identity to SolvaPay.
const customerRef = await solvaPay.ensureCustomer('user_123', 'user_123', {
  email: 'user@example.com',
  name: 'Jane Doe',
})
For HTTP adapters, pass customer identity in headers or auth context.
app.post('/tasks', payable.http(async req => {
  const customerRef = req.headers['x-customer-ref']
  return { ok: true, customerRef }
}))
When you call POST /v1/sdk/customers (or ensureCustomer / syncCustomer) with an email that already exists under this provider and the caller supplies an externalRef, the API links the externalRef onto the existing customer instead of returning 409 Conflict. This lets you idempotently adopt pre-existing SolvaPay customers when wiring up your own auth layer for the first time. Callers without externalRef still get 409 on duplicate email so the behavior is explicit.

Update a customer

Use PATCH /v1/sdk/customers/:reference to backfill or change externalRef, name, or email. Only the fields you supply are modified.
await fetch(`https://api.solvapay.com/v1/sdk/customers/${ref}`, {
  method: 'PATCH',
  headers: { Authorization: `Bearer ${process.env.SOLVAPAY_SECRET_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ externalRef: 'auth_user_12345' }),
})

Data helpers

Three read-only endpoints power customer-facing UI without bloating check_purchase:
  • GET /v1/sdk/platform-config — browser-safe platform values (today: the SolvaPay Stripe publishable key used to initialize the Stripe.js client). Resolves against the sandbox or live environment matching your secret key. Call it once on page load before mounting <PaymentForm>; additions will land here rather than in /sdk/merchant.
  • GET /v1/sdk/merchant — provider identity safe to render in checkout and mandate copy: name, legalName, supportContact, termsUrl, privacyUrl, iconUrl (square app icon), and logoUrl (absolute URL resolved against ASSETS_BASE_URL). Used by SDK components like MandateText and CheckoutSummary.
  • GET /v1/sdk/payment-method?customerRef=… — returns { kind: 'card', brand, last4, expMonth, expYear } or { kind: 'none' }. The card brand and last4 are mirrored onto the Customer by the payment_intent.succeeded webhook, so this endpoint reads from SolvaPay’s database with no Stripe round-trip. Safe to poll alongside check_purchase.
All three are exposed as route-wrapper helpers in @solvapay/next (getMerchant, getProduct, getPaymentMethod), as fetch handlers in @solvapay/server/fetch, and as MCP tools in the default createSolvaPayMcpServer tool surface.

Paywall protection flow

When your handler is wrapped with payable(), the SDK:
  1. Resolves customer reference
  2. Checks purchase status
  3. Checks usage limits
  4. Executes business logic when allowed
  5. Tracks usage
  6. Returns a paywall response when blocked

Example blocked response

{
  error: 'PaywallError',
  message: 'Purchase required',
  checkoutUrl: 'https://checkout.solvapay.com/...',
}

Purchase lifecycle

Purchase states:
  • Active — customer has access
  • Pending cancellation — active with cancelledAt set; access continues until period end, can be reactivated
  • Cancelled — cancel confirmed at period end
  • Expired — purchase ended (period elapsed or plan switch)
  • Past due — payment failed; may be suspended

Cancel and reactivate renewal

import { cancelRenewal, reactivateRenewal } from '@solvapay/next'

// Cancel auto-renewal (access continues until period end)
await cancelRenewal(request, { purchaseRef: 'pur_...', reason: 'Too expensive' })

// Undo cancellation while still in active period
await reactivateRenewal(request, { purchaseRef: 'pur_...' })

Activate a plan directly

Activate a product for a customer on a specific plan without checkout. Handles free plans, credit-based activation, usage-based (PAYG) plans, and plan switching.
import { activatePlan } from '@solvapay/next'

const result = await activatePlan(request, {
  productRef: 'prd_...',
  planRef: 'pln_...',
})
// result.status: 'activated' | 'already_active' | 'topup_required' | 'payment_required' | 'invalid'
Activation policy by plan type:
  • Free — always activated.
  • Usage-based (PAYG)activated immediately at zero balance. The customer can start using the product and pay per action; top-up is a separate optional step via createTopupPaymentIntent.
  • Recurring / hybrid — return topup_required or payment_required when the customer has no credits and no card on file. Route them to checkout before granting access.
When the customer already has an active purchase on a different plan, activatePlan automatically expires the old purchase and creates a new one. See Purchase lifecycle management for the full guide.

Authentication flow

You keep your existing auth and map identities to SolvaPay customers. Common pattern:
  1. Extract user ID from your auth layer
  2. Use ID as customerRef
  3. Sync email/name as needed
  4. Run purchase checks

Usage tracking

Use payable() for automatic usage tracking, or record usage directly.
await solvaPay.trackUsage({
  customerRef: 'user_123',
  actionType: 'api_call',
  units: 1,
  outcome: 'success',
  productRef: 'prd_P9Q0R1S2',
})
Usage-based and hybrid plans enforce limits from meter data.

Next steps