Portal — Billing
Billing endpoints return subscription and usage information, and allow you to initiate a Stripe checkout session to subscribe to or upgrade a plan.
All portal endpoints require a JWT Bearer token. See Authentication for how to obtain one.
GET /api/billing/info
Retrieve billing and subscription details for your organization, including current plan, usage, and quota.
Request
GET https://api.pdfcanon.com/api/billing/info
Authorization: Bearer <access_token>
Response (200 OK)
| Field | Type | Description |
|---|---|---|
planTier | string | Current plan: free, starter, growth, or pro |
monthlyDocLimit | integer | Maximum normalizations allowed per billing cycle |
currentMonthUsage | integer | Normalizations used in the current billing cycle |
remainingQuota | integer | Remaining normalizations for the current cycle |
usagePercent | number | Percentage of quota consumed |
stripeCustomerId | string (nullable) | Stripe customer ID, if a paid subscription exists |
stripeSubscriptionId | string (nullable) | Stripe subscription ID, if a paid subscription exists |
billingInterval | string | month or year |
subscriptionStatus | string | Stripe subscription status (e.g. active, past_due) |
currentPeriodEnd | datetime (nullable) | End of the current billing period |
cancelAtPeriodEnd | boolean | Whether the subscription will cancel at period end |
overageRatePerDoc | number | Per-document overage rate (decimal) |
Example
- cURL
- Node.js
- Python
curl https://api.pdfcanon.com/api/billing/info \
-H "Authorization: Bearer eyJ..."
const response = await fetch('https://api.pdfcanon.com/api/billing/info', {
headers: { Authorization: `Bearer ${accessToken}` },
});
const billing = await response.json();
console.log(`Plan: ${billing.planTier}, Used: ${billing.currentMonthUsage}/${billing.monthlyDocLimit}`);
import httpx
resp = httpx.get(
"https://api.pdfcanon.com/api/billing/info",
headers={"Authorization": f"Bearer {access_token}"},
)
resp.raise_for_status()
b = resp.json()
print(f"Plan: {b['planTier']}, Used: {b['currentMonthUsage']}/{b['monthlyDocLimit']}")
POST /api/billing/checkout-session
Create a Stripe Checkout session to subscribe to or upgrade a plan. Returns a redirect URL to the Stripe-hosted payment page.
Request
POST https://api.pdfcanon.com/api/billing/checkout-session
Authorization: Bearer <access_token>
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
tier | string | ✅ | Target plan: starter, growth, or pro |
interval | string | ✅ | Billing interval: month or year |
successUrl | string (uri) | ✅ | URL to redirect to after successful checkout |
cancelUrl | string (uri) | ✅ | URL to redirect to if checkout is cancelled |
Response (200 OK)
| Field | Type | Description |
|---|---|---|
url | string | Stripe Checkout session URL — redirect the user here |
Example
- cURL
- Node.js
- Python
curl -X POST https://api.pdfcanon.com/api/billing/checkout-session \
-H "Authorization: Bearer eyJ..." \
-H "Content-Type: application/json" \
-d '{
"tier": "starter",
"interval": "month",
"successUrl": "https://app.yourcompany.com/billing?success=true",
"cancelUrl": "https://app.yourcompany.com/billing"
}'
const response = await fetch('https://api.pdfcanon.com/api/billing/checkout-session', {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
tier: 'starter',
interval: 'month',
successUrl: 'https://app.yourcompany.com/billing?success=true',
cancelUrl: 'https://app.yourcompany.com/billing',
}),
});
const { url } = await response.json();
window.location.href = url; // redirect to Stripe Checkout
resp = httpx.post(
"https://api.pdfcanon.com/api/billing/checkout-session",
headers={"Authorization": f"Bearer {access_token}"},
json={
"tier": "starter",
"interval": "month",
"successUrl": "https://app.yourcompany.com/billing?success=true",
"cancelUrl": "https://app.yourcompany.com/billing",
},
)
resp.raise_for_status()
checkout_url = resp.json()["url"]
print("Redirect to:", checkout_url)