Billing
Base URL: https://billing-api.pcampus.co
Overview
Billing is the subscription management service responsible for everything related to money and plans in Pcampus — from managing each organization's tier and processing payments via Stripe, to providing the entitlement API that every service calls to check which features an org is permitted to use.
Developer note: During development, use the entitlement stub that always returns the pro plan until the Billing service is fully implemented, so other services can continue development immediately.
Who uses this
| Persona | What they do |
|---|---|
| Internal service | Every service calls /billing/orgs/:orgId/entitlements to verify entitlements |
| Org Admin | Purchase plans, view invoices, manage payment methods via Console |
| Enterprise customer | Contact the sales team for a custom plan |
| Finance Admin | View revenue, subscription status, and invoices for all orgs |
Key features
- Plan management — Free / Starter / Pro / Enterprise tiers per organization
- Add-on management — Purchase add-ons to increase per-service limits (e.g. +MAU, +storage)
- Stripe integration — Accept payments via credit card and PromptPay through Stripe
- Entitlement API — Lets other services check the plan + effective limits per org
- Self-serve checkout — Starter / Pro can be purchased self-serve in Console via Stripe Checkout
- Invoice management — Automatically generate and send invoices every billing cycle
- Usage tracking — Receive usage metrics from services to check against plan limits
Plans
| Plan | Price | Target |
|---|---|---|
| Free | ฿0 / month | Trial, early-stage startups |
| Starter | ฿990 / month / org | Small teams, early traction |
| Pro | ฿3,900 / month / org | Established teams, production |
| Enterprise | Contact sales | Large organizations, custom SLA |
How it works
Plan enforcement flow
Every service must check entitlements before processing a request:
Self-serve purchase flow
Stripe webhook events
Data model
Entitlement API
Other services call this endpoint before processing every request that has a limit:
GET /billing/orgs/:orgId/entitlementsResponse:
{
"orgId": "org_xxxx",
"plan": "pro",
"status": "active",
"limits": {
"pip": { "mau": 10000, "applications": 10 },
"cockpit": { "campaigns": -1, "members": 20 },
"content_os": { "brands": 5, "assets_gb": 50 },
"notification": { "sends_per_month": 100000 },
"mail": { "sends_per_month": 50000 },
"storage": { "gb": 100 }
},
"addOns": [
{ "service": "pip", "resource": "mau", "quantity": 5000 }
]
}-1 means unlimited.
Effective limit = base plan limit + sum of add-ons
Other services do not need to calculate this themselves — the limits returned are already the effective limits.
Plan enforcement responses
# Feature / service not included in plan
HTTP 403
{
"code": "SERVICE_NOT_INCLUDED",
"service": "cockpit",
"requiredPlan": "starter",
"upgradeUrl": "https://console.pcampus.co/billing/upgrade"
}
# Limit exceeded
HTTP 402
{
"code": "PLAN_LIMIT_EXCEEDED",
"service": "pip",
"limit": "mau",
"current": 5000,
"max": 5000,
"upgradeUrl": "https://console.pcampus.co/billing/upgrade"
}Security
stripe_customer_id,stripe_subscription_id,stripe_price_idare stored in the database only- Card numbers must never be stored — everything is tokenized through Stripe
STRIPE_SECRET_KEYandSTRIPE_WEBHOOK_SECRETmust be stored as environment variables only — never hardcode them in code or in the repo- Always verify the webhook signature with
STRIPE_WEBHOOK_SECRET
Integration
- Every service — calls the Billing entitlement API before enforcing limits
- PIP — access check (
billing.read,billing.subscription.write) - Notification → Mail — sends invoice, payment success/failure notifications to the org admin
API overview
| Method | Endpoint | Description |
|---|---|---|
GET | /billing/orgs/:orgId/entitlements | Get plan + effective limits |
GET | /billing/orgs/:orgId/subscription | Get subscription details |
POST | /billing/checkout | Create Stripe Checkout session |
POST | /billing/addons | Purchase add-on |
GET | /billing/invoices | List invoices |
GET | /billing/invoices/:id | Get invoice detail |
GET | /billing/payment-methods | List payment methods |
DELETE | /billing/payment-methods/:id | Remove payment method |
POST | /billing/webhooks/stripe | Stripe webhook receiver |
POST | /billing/usage | Report usage from service |
POST /billing/webhooks/stripe must be publicly accessible without going through the PIP access check, but must verify the Stripe signature on every request.