Overview
SolvaPay bills and meters on the server side. Your product keeps its own client (CLI, web app, mobile) and its own identity provider (Auth0, Cognito, a custom IdP, or a provider CLI likelogin / init). Your backend holds sk_* and links each signed-in user to a SolvaPay customer via a stable externalRef.
This is the canonical integration shape when you own the customer experience. SolvaPay does not need a credential in the CLI, a SolvaPay-hosted approval page, or IdP access tokens on SolvaPay APIs.
Quick start (any Node backend)
ensureCustomer is idempotent: repeated calls with the same externalRef return the same SolvaPay customerRef.
The externalRef contract
| Rule | Detail |
|---|---|
| Stable | Use an identifier that does not change for the lifetime of the user (IdP sub, internal UUID, etc.). Do not use email alone. |
| Deterministic | The same user must always map to the same externalRef. |
| IdP-agnostic | Any string your backend controls is valid. Auth0 sub is a common choice, not a requirement. |
| Provider-scoped | externalRef is unique per SolvaPay provider (your account), not globally. |
| Server-only linkage | Call ensureCustomer from code that holds sk_*. Never send IdP access tokens to SolvaPay. |
| Secret key stays server-side | sk_* never belongs in a CLI, browser, or mobile app. |
REST equivalent
The SDK wraps existing SDK customer endpoints:GET /v1/sdk/customers?externalRef=— find by linkagePOST /v1/sdk/customers— create with{ externalRef, email, name }PATCH /v1/sdk/customers/:reference— updateexternalRefon an existing customer
ensureCustomer implements find-or-create-by-externalRef so you do not need to manage that flow yourself.
When you create a customer with an email that already exists under your provider and you supply
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.Provider-owned CLI pattern
A provider that ships its own CLI (for exampleyour-cli login backed by Auth0) already has an authenticated user id after login. The CLI talks to your API; your API calls SolvaPay:
- CLI completes your IdP login and stores your session token (not
sk_*). - CLI calls your backend with that session.
- Backend resolves
externalReffrom the session (e.g. JWTsub). - Backend calls
ensureCustomer(externalRef)thentrackUsage/payable/checkLimits.
Web app pattern (Auth0 reference)
For Next.js + Auth0, the SDK ships a ready reference that forwardssession.user.sub as billing identity:
- Example: examples/nextjs-auth0
- Scaffold:
npm create solvapay -- --type mcp --auth auth0(or--auth auth0on the Next template) - Adapter details: Custom authentication adapters
externalRef contract applies with any IdP.
Protecting routes after linkage
Once you havecustomerRef, pass it into paywall helpers:
createAuth0AuthMiddleware (or your own adapter) so route handlers receive x-user-id / externalRef automatically. For Express and other frameworks, resolve externalRef in middleware, call ensureCustomer, then set x-customer-ref for payable.http().
What not to do
- Do not put
SOLVAPAY_SECRET_KEYin a customer CLI or browser. - Do not send Auth0 (or other IdP) access tokens to SolvaPay APIs.
- Do not rely on email alone as
externalRef— emails can change; subjects and internal ids should not. - Do not assume SolvaPay will host your customer login. Use MCP OAuth only when your OAuth clients need SolvaPay as the authorization server (e.g. MCP / third-party apps), which is separate from provider-owned CLI linkage.