Billing API¶
Inklet uses Stripe for subscription management. The billing endpoints let users subscribe, manage their payment methods, and view invoices. All endpoints require authentication unless otherwise noted.
Endpoints¶
GET /auth/subscription¶
:material-lock: Requires authentication
Retrieve the authenticated user's current subscription information.
Request Headers:
Response: 200 OK
| Field | Type | Description |
|---|---|---|
status |
string | One of none, active, past_due, canceled, trialing |
plan |
string or null | Subscription plan name |
interval |
string or null | monthly or yearly |
currentPeriodStart |
timestamp or null | Start of the current billing period |
currentPeriodEnd |
timestamp or null | End of the current billing period |
cancelAtPeriodEnd |
boolean | Whether the subscription cancels at the end of the current period |
stripeCustomerId |
string | Stripe Customer ID |
stripeSubscriptionId |
string or null | Stripe Subscription ID (null if no subscription) |
Errors:
| Code | Cause |
|---|---|
401 |
Missing or invalid access token |
POST /auth/subscription/checkout¶
:material-lock: Requires authentication
Create a Stripe Checkout session for starting a new subscription. Returns a URL to redirect the user to Stripe's hosted checkout page.
Request Headers:
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
interval |
string | Yes | monthly or yearly |
Response: 200 OK
Client Integration
Redirect the user to the returned url using window.location.href or open it in a new tab. After successful payment, Stripe redirects the user back to your portal.
Errors:
| Code | Cause |
|---|---|
400 |
Invalid interval value |
401 |
Missing or invalid access token |
409 |
User already has an active subscription |
POST /auth/subscription/portal¶
:material-lock: Requires authentication
Create a Stripe Billing Portal session. The billing portal lets users manage their payment methods, view invoices, and cancel or modify their subscription.
Request Headers:
Response: 200 OK
Redirect the user to the returned url. The portal provides a Stripe-hosted UI for self-service billing management.
Errors:
| Code | Cause |
|---|---|
401 |
Missing or invalid access token |
GET /auth/subscription/invoices¶
:material-lock: Requires authentication
Retrieve the authenticated user's invoice history from Stripe.
Request Headers:
Response: 200 OK
{
"invoices": [
{
"id": "in_1abc2def3ghi",
"date": "2026-01-15T10:30:00Z",
"amount": 999,
"currency": "usd",
"status": "paid",
"invoiceUrl": "https://invoice.stripe.com/i/acct_123/live_abc",
"pdfUrl": "https://pay.stripe.com/invoice/acct_123/live_abc/pdf"
},
{
"id": "in_4jkl5mno6pqr",
"date": "2025-12-15T10:30:00Z",
"amount": 999,
"currency": "usd",
"status": "paid",
"invoiceUrl": "https://invoice.stripe.com/i/acct_123/live_def",
"pdfUrl": "https://pay.stripe.com/invoice/acct_123/live_def/pdf"
}
]
}
| Field | Type | Description |
|---|---|---|
id |
string | Stripe Invoice ID |
date |
timestamp | Invoice creation date |
amount |
integer | Amount in the smallest currency unit (e.g., cents for USD) |
currency |
string | Three-letter ISO currency code |
status |
string | One of draft, open, paid, void, uncollectible |
invoiceUrl |
string | URL to the hosted invoice page |
pdfUrl |
string | URL to download the invoice PDF |
Amount Format
The amount field is in the smallest currency unit. For USD, 999 means $9.99. Divide by 100 for display.
Errors:
| Code | Cause |
|---|---|
401 |
Missing or invalid access token |
POST /auth/webhook/stripe¶
Stripe webhook endpoint. This is called by Stripe's servers when subscription events occur --- it is not called by clients.
No Authentication Required
This endpoint does not use Bearer token authentication. Instead, it verifies the request using the Stripe-Signature header and the webhook signing secret configured in the backend.
Handled Events:
| Event | Action |
|---|---|
checkout.session.completed |
Activates the subscription in the database |
invoice.paid |
Updates the billing period |
invoice.payment_failed |
Marks subscription as past_due |
customer.subscription.updated |
Syncs plan, interval, and cancellation status |
customer.subscription.deleted |
Marks subscription as canceled |
Response: 200 OK
Returns an empty 200 response to acknowledge receipt. Stripe retries on non-2xx responses.