Skip to Content
REST APIBilling & subscription

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

MethodPathOperation IDAuth scope
GET/api/subscriptionbearer
POST/api/subscription/createbearer
POST/api/subscription/changebearer
POST/api/subscription/cancelbearer
POST/api/subscription/cancel-downgradebearer
GET/api/subscription/pricesnone (public)
GET/api/billing-historybearer

Get current subscription — GET /api/subscription

curl -H "Authorization: Bearer $KEY" \ https://portal.scrapewise.ai/api/scraper-api/api/subscription

Response (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 in payment.url; redirect to collect new card / take immediate proration charge.
  • Downgrade: scheduledPlan is set; the actual switch happens at currentPeriodEnd. No immediate charge.
  • No-op (same plan): existing subscription returned, no payment URL.
  • STARTER from INACTIVE: free plan set inline, no Stripe round-trip.
  • STARTER from ACTIVE: schedules downgrade to STARTER at 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/prices

No 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:

ParamTypeDescription
pageintZero-indexed page (default 0)
sizeintPage size (default 20)
statusenumPAID, OPEN, UNCOLLECTIBLE, VOID, DRAFT
fromyyyy-MM-ddFilter to invoices on or after this date (UTC)
toyyyy-MM-ddFilter 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