Billing & subscription
Subscription lifecycle for the authenticated customer — create, switch plan, cancel — plus paginated invoice history. Stripe is the payment processor; mutating endpoints return a Stripe Checkout URL when card collection is needed.
The POST /api/subscription/webhook endpoint is Stripe-internal (HMAC-signed) and intentionally excluded from these docs — clients should never call it.
Endpoint summary
| Method | Path | Operation ID | Auth scope |
|---|---|---|---|
| GET | /api/subscription | — | bearer |
| POST | /api/subscription/create | — | bearer |
| POST | /api/subscription/change | — | bearer |
| POST | /api/subscription/cancel | — | bearer |
| POST | /api/subscription/cancel-downgrade | — | bearer |
| GET | /api/subscription/prices | — | none (public) |
| GET | /api/billing-history | — | bearer |
Get current subscription — GET /api/subscription
curl -H "Authorization: Bearer $KEY" \
https://portal.scrapewise.ai/api/scraper-api/api/subscriptionResponse (200)
{
"plan": "PRO",
"status": "ACTIVE",
"currentPeriodEnd": "2026-06-19T23:59:59Z",
"scheduledPlan": null,
"payment": null
}scheduledPlan is non-null when a downgrade has been scheduled (effective at currentPeriodEnd). payment is non-null on create/change responses when the customer needs to be redirected to Stripe Checkout.
Errors — 400 (N/A) / 401 / 403 (N/A) / 404 (N/A) / 429 / 500. (The customer is read from the auth principal, so 400/403/404 don’t apply.)
Create subscription — POST /api/subscription/create
POST /api/subscription/create
Authorization: Bearer <key>
Content-Type: application/json
{ "plan": "PRO" }If the customer already has an ACTIVE subscription, the existing subscription is returned with no Checkout URL. Otherwise a new Stripe Checkout Session is created and the URL is returned in payment.url. Redirect the customer to that URL.
Response (200)
{
"plan": "PRO",
"status": "INACTIVE",
"payment": { "url": "https://checkout.stripe.com/c/pay/cs_..." }
}Errors — 400 (invalid plan) / 401 / 403 (N/A) / 404 (N/A) / 429 / 500.
Change plan — POST /api/subscription/change
POST /api/subscription/change
Authorization: Bearer <key>
{ "plan": "BUSINESS" }Switch the customer to a different plan. Behaviour depends on direction:
- Upgrade (higher
level): Stripe Checkout URL returned inpayment.url; redirect to collect new card / take immediate proration charge. - Downgrade:
scheduledPlanis set; the actual switch happens atcurrentPeriodEnd. No immediate charge. - No-op (same plan): existing subscription returned, no payment URL.
STARTERfromINACTIVE: free plan set inline, no Stripe round-trip.STARTERfromACTIVE: schedules downgrade toSTARTERat period end.
Errors — 400 (invalid plan / no active subscription) / 401 / 403 (N/A) / 404 (N/A) / 429 / 500.
Cancel subscription — POST /api/subscription/cancel
POST /api/subscription/cancel
Authorization: Bearer <key>Cancels the active subscription at the end of the current billing period. The customer retains access until currentPeriodEnd, then drops to STARTER.
Errors — 400 (no active subscription / no Stripe subscription id) / 401 / 403 (N/A) / 404 (N/A) / 429 / 500.
Cancel scheduled downgrade — POST /api/subscription/cancel-downgrade
POST /api/subscription/cancel-downgrade
Authorization: Bearer <key>Reverts a previously-scheduled downgrade — clears scheduledPlan and restores the Stripe subscription to the current plan’s price.
Errors — 400 (no downgrade scheduled) / 401 / 403 (N/A) / 404 (N/A) / 429 / 500.
Get product prices — GET /api/subscription/prices
curl https://portal.scrapewise.ai/api/scraper-api/api/subscription/pricesNo auth — public. Returns the Stripe product catalogue. Used by the marketing site’s pricing page.
Response (200)
[
{ "plan": "BASIC", "monthly": { "amount": 29, "currency": "eur" } },
{ "plan": "PRO", "monthly": { "amount": 79, "currency": "eur" } },
{ "plan": "BUSINESS", "monthly": { "amount": 199, "currency": "eur" } }
]Errors — 400 (N/A) / 401 (N/A — public) / 403 (N/A — public) / 404 (N/A) / 429 / 500. No auth-related codes (this endpoint is public).
Get billing history — GET /api/billing-history
curl -H "Authorization: Bearer $KEY" \
"https://portal.scrapewise.ai/api/scraper-api/api/billing-history?page=0&size=20&from=2026-01-01&to=2026-05-31"Paginated invoice history. Filters:
| Param | Type | Description |
|---|---|---|
page | int | Zero-indexed page (default 0) |
size | int | Page size (default 20) |
status | enum | PAID, OPEN, UNCOLLECTIBLE, VOID, DRAFT |
from | yyyy-MM-dd | Filter to invoices on or after this date (UTC) |
to | yyyy-MM-dd | Filter to invoices on or before this date (UTC) |
Response (200) — Spring Page<InvoiceDTO>:
{
"content": [
{
"id": "in_...",
"amount": 79,
"currency": "eur",
"status": "PAID",
"issuedAt": "2026-04-19T12:00:00Z",
"hostedInvoiceUrl": "https://invoice.stripe.com/i/..."
}
],
"totalElements": 14,
"totalPages": 1,
"size": 20,
"number": 0
}Errors — 400 (malformed from/to) / 401 / 403 (N/A) / 404 (N/A) / 429 / 500.
See also
- Plan features — what each plan tier includes
- Customer profile — profile + preferences