Get started
Quickstart
By the end of this page your workspace has a project with a development environment, a connection to your own Stripe or Paddle account, a plan with an entitlement, customer authentication configured, and a usage decision returned by the API. Every step uses routes that exist today; there is no SDK to install.
Before you start
Paycux is a control plane. It keeps your catalog, entitlements and usage decisions and creates checkout, portal and cancellation sessions on your own provider account. It never holds funds or acts as merchant of record.
- A Paycux account. During private beta nothing is billed, and no charge starts until you complete checkout for a workspace plan.
- Your own Stripe or Paddle account, in test or sandbox mode first.
- An application that can complete an OpenID Connect login against the environment's identity realm and serve HTTPS return URLs. Loopback addresses are accepted in development.
Examples call https://api.paycux.com, the live control-plane host. Console routes carry the __Host-paycux_session cookie; end-user routes carry a realm access token. There are no secret API keys. See the three credentials.
Create a workspace
Create your account at /sign-up. Registration runs through the identity provider with the authorization code flow and PKCE; Paycux creates your isolated workspace only after a verified e-mail address comes back, then signs you in with a host-bound, HttpOnly session cookie.
- Invite teammates from workspace settings. An invitation returns its accept link once; when the platform mail scope is configured the same link is also e-mailed to the invitee.
- Owners and admins register projects and connections; production environments are created by an owner.
- Every write to members, catalog and lifecycle is appended to the workspace audit ledger.
Register a project and environment
From the console home, register an application. One request creates the project, its first environment named development and a setup draft, atomically. You generate and keep the two UUIDs, so a retry of the same body is idempotent.
1POST https://api.paycux.com/v1/applications2Cookie: __Host-paycux_session=<console session>34{5 "projectId": "<uuid you generate and keep>",6 "environmentId": "<uuid you generate and keep>",7 "name": "Example",8 "slug": "example",9 "environmentName": "development",10 "applicationUrl": "https://app.example/",11 "identityMode": "external"12}1314# 201 { "projectId": "…", "environmentId": "…", "created": true }15# an identical retry answers 200 with "created": false
Environments are isolated: catalog, connections, customers and usage never cross between them. Add a production environment later from an owner session with POST /v1/environments.
Connect your provider
Open the environment’s Connections screen and add your Stripe or Paddle account. The key is verified with a read-only, ten-second provider call before anything is stored, written to the secret store by reference, and never returned or logged.
1POST https://api.paycux.com/v1/environments/<environmentId>/provider-connections2Cookie: __Host-paycux_session=<console session>34{5 "projectId": "<projectId>",6 "name": "Paddle sandbox",7 "provider": "paddle",8 "mode": "sandbox",9 "apiKey": "pdl_sdbx_…",10 "webhookSecret": "…"11}1213# 20114{15 "id": "<connectionId>", "name": "Paddle sandbox", "provider": "paddle", "mode": "sandbox",16 "status": "active", "hasWebhookSecret": true, "createdAt": "…", "updatedAt": "…",17 "webhookPath": "/v1/provider-connections/<connectionId>/webhooks/paddle"18}
- The key prefix must match the mode: sk_ or rk_ plus test or live on Stripe, pdl_sdbx_ for a Paddle sandbox.
- Register https://api.paycux.com plus the returned webhookPath at the provider, with the same signing secret. A connection created without a secret can have one attached later through the rotate route.
- Failures store nothing: INVALID_SCOPE for a format or mode mismatch, PROVIDER_REJECTED when the provider refuses the key, PROVIDER_UNAVAILABLE when it cannot be reached.
Define a plan
The Catalog screen creates products, plans, prices, features, meters, entitlements and provider price mappings. The same routes are available to the console session cookie; this is the shortest sequence that produces a sellable plan with one metered limit.
1# Console session cookie on every call; projectId travels in the body.2POST /v1/environments/<env>/catalog/products3 { "projectId": "…", "key": "starter_suite", "name": "Starter suite" }4POST /v1/environments/<env>/catalog/products/<productId>/plans5 { "projectId": "…", "key": "starter", "name": "Starter" }6POST /v1/environments/<env>/catalog/plans/<planId>/prices7 { "projectId": "…", "key": "monthly", "currency": "USD", "unitAmountMinor": 4900, "billingInterval": "month" }8POST /v1/environments/<env>/catalog/features9 { "projectId": "…", "key": "api_calls", "name": "API calls", "seatRequired": 0 }10POST /v1/environments/<env>/catalog/features/<featureId>/meters11 { "projectId": "…", "key": "api_calls", "name": "API calls", "aggregation": "sum" }12PUT /v1/environments/<env>/catalog/plans/<planId>/entitlements13 { "projectId": "…", "featureId": "<featureId>", "quantityLimit": 1000 }14POST /v1/environments/<env>/catalog/plans/<planId>/price-mappings15 { "projectId": "…", "connectionId": "<connectionId>", "providerPriceId": "pri_…" }
- Keys match ^[a-z][a-z0-9_-]*$ and are unique per environment and version. Re-using a key answers 409 unless the body passes newVersion: true; the highest version is what checkout and the console treat as current.
- Products, plans and prices are archived, never deleted, because a row that has ever been sold must stay resolvable.
- The price mapping must point at an active connection of the same environment; checkout sells the highest mapped plan version of the key.
Configure customer authentication
Your application’s users sign in against an identity realm Paycux provisions per environment. Open the environment’s Authentication screen, or send the same configuration from an owner or admin session. Every entry is a full, exact URL; HTTPS is required except for loopback hosts in development or preview.
1curl -X PUT "https://api.paycux.com/v1/environments/<environmentId>/auth?projectId=<projectId>" \2 -H "Cookie: __Host-paycux_session=<console session>" \3 -H "Content-Type: application/json" \4 -d '{5 "displayName": "Example",6 "redirectUris": ["https://app.example/auth/callback"],7 "logoutRedirectUris": ["https://app.example/"],8 "checkoutReturnUrls": ["https://app.example/billing?checkout=success", "https://app.example/billing?checkout=cancelled"]9 }'1011# 202 while the environment worker provisions the realm, 200 once it is ready12{13 "setup": {14 "status": "pending",15 "revision": 1,16 "appliedRevision": 0,17 "realmId": "…",18 "issuer": "…/realms/pcx-<environment uuid>",19 "clientId": "…",20 "discoveryUrl": "…/.well-known/openid-configuration",21 "lastErrorCode": null22 }23}
- The setup is durable: pending until the environment maintenance worker has provisioned the realm and validated discovery, then ready, or failed with a visible lastErrorCode. Ready also requires the realm's mail settings, so verification e-mail can be sent.
- Once ready, run an OpenID Connect authorization-code login with PKCE against the issuer with the returned clientId and one of the redirectUris. Passwords go to the identity provider, never to the Paycux API.
- The access token that login returns is the end-user credential. Paycux verifies it against the realm's keys and audience, requires a verified e-mail and maps the subject to a realm-scoped identity on first use. GET /v1/identity/me returns that identity.
Send the first usage event
Two calls with the realm access token: create the user’s billing account, then record a usage event and read the decision.
1# 1 — a billing account for the signed-in user (idempotent per identity)2curl -X POST https://api.paycux.com/v1/billing/accounts \3 -H "Authorization: Bearer $REALM_ACCESS_TOKEN" \4 -H "Content-Type: application/json" \5 -d '{ "projectId": "<projectId>", "environmentId": "<environmentId>", "realmId": "<realmId>", "displayName": "Ada" }'67# 2 — the first usage event8curl -X POST https://api.paycux.com/v1/usage/events \9 -H "Authorization: Bearer $REALM_ACCESS_TOKEN" \10 -H "Idempotency-Key: usage-2026-10-13-000001" \11 -H "Content-Type: application/json" \12 -d '{13 "projectId": "<projectId>",14 "environmentId": "<environmentId>",15 "realmId": "<realmId>",16 "billingAccountId": "<billingAccountId>",17 "meterKey": "api_calls",18 "quantity": 1,19 "occurredAt": "2026-10-13T09:00:00Z"20 }'2122# 200 UsageDecision23{24 "allowed": true,25 "reason": "WITHIN_LIMIT",26 "consumed": 1,27 "limit": 1000,28 "eventId": "…",29 "duplicate": false30}
- The body scope (projectId, environmentId, realmId) must match the credential, and the identity must be an active member of the billing account.
- Idempotency-Key is 8 to 128 characters. Repeating a key returns the same decision with duplicate: true; it never counts twice.
- reason is WITHIN_LIMIT, LIMIT_EXCEEDED, NO_ENTITLEMENT or SEAT_REQUIRED. A billing account without a subscription has no entitlements, so expect NO_ENTITLEMENT until checkout completes and the provider webhook projects the subscription.
Hosted checkout
Checkout, portal and cancellation sessions are created on your own provider account. The checkout URL is a short-lived page hosted by Paycux that opens the provider’s checkout; completing it never grants entitlements by itself. The signed webhook, event processing and subscription projection stay authoritative.
1curl -X POST https://api.paycux.com/v1/billing/checkout-sessions \2 -H "Authorization: Bearer $REALM_ACCESS_TOKEN" \3 -H "Idempotency-Key: checkout-2026-10-13-000001" \4 -H "Content-Type: application/json" \5 -d '{6 "projectId": "<projectId>",7 "environmentId": "<environmentId>",8 "realmId": "<realmId>",9 "billingAccountId": "<billingAccountId>",10 "planKey": "starter",11 "successUrl": "https://app.example/billing?checkout=success",12 "cancelUrl": "https://app.example/billing?checkout=cancelled"13 }'1415# 20116{ "provider": "paddle", "mode": "sandbox", "checkoutUrl": "https://paycux.com/checkout/customer/<token>",17 "expiresAt": "…", "billingAccountId": "<billingAccountId>", "planKey": "starter" }
- successUrl and cancelUrl must exactly match the checkoutReturnUrls you configured in step 5.
- provider defaults to paddle. A Paddle connection also needs its public client token saved once from the console; the contract under What exists today records the current state of the Stripe path.
- Identical retries keep the same session for up to 30 minutes; a changed payload answers 409, and an expired session needs a new idempotency key.
Next steps
Everything on this page is implemented. The rest of the documentation describes the planned product surface and says so on every page.
What exists today
Every implemented route, its credential and its error codes, rendered from the release source.
The three credentials
Console session, realm access token and agent token, with curl for each.
Portal and cancellation
Portal sessions and cancellation at period end on the customer's own provider account.
Agent tooling
The paycux-mcp server and the paycux CLI, bound to a project's development environment.