Docs menu
- Docs
- Reference
- Billing
Billing
POST /v1/account/checkout
Open a Stripe payment page that adds credits to this account.
Owner only. A pack tops up an active subscription, and only the packs of your plan are on sale; without one the answer is 409 no_subscription. The credits land on this account once Stripe confirms the payment. It makes no keys. Open checkout_url in a browser; the page expires after 30 minutes. ref_token and ref_code are read on every checkout, but only the account’s first paid purchase binds a referral (MEG-504). A bad ref is dropped, never an error. Stripe sends the buyer back to the dashboard: /buy?paid, or /buy?cancelled.
Parameters
| name | in | required | type or values | what it is |
|---|---|---|---|---|
Idempotency-Key |
header | no | string | Your own id for this call, 1 to 128 printable ASCII characters. A second call with the same key from the same account key inside 24 hours answers 200 with the same checkout_url, and opens no new payment page. A call that failed frees its key. |
Body
| field | required | type or values | what it is |
|---|---|---|---|
pack |
yes | string | The pack’s public name, like starter. A name we do not sell is 404 not_found. |
campaign |
no | string | Where the buyer came from, like reddit-launch. Never a URL or an email. |
ref_token |
no | string | Added by MEG-237. The ref_token the /r/{code} link put on the page’s address. Checked with our secret; a bad, forged or expired one (older than 60 days) is dropped without an error. Binds only on the account’s first paid purchase. |
ref_code |
no | string | Added by MEG-237. A referral code typed by the buyer, 8 of a-z and 0-9. An unknown code is dropped without an error. ref_token wins when both are sent. |
Answers
| status | what it means |
|---|---|
200 |
The Stripe payment page. Open checkout_url in a browser. It expires after 30 minutes. |
400 |
bad_parameter: pack is missing (field pack), campaign is wrong (field campaign), Idempotency-Key is not 1 to 128 printable ASCII characters (field Idempotency-Key), or a key this request does not take (field names it). bad_request: the body is not one JSON object. |
401 |
bad_token. The key is missing, not valid, expired, revoked, of an unknown prefix or wrong length, or sent as the api_key query parameter, which no route accepts. |
403 |
wrong_scope (a scrape key on a route that needs an account key, or an account key on a scraping or batches route) or owner_only (your role is member). |
404 |
not_found. No pack with that name. |
413 |
body_too_large. The body was larger than 4 KiB. |
415 |
unsupported_media_type. Send Content-Type: application/json, even for an empty {} body. |
422 |
idempotency_mismatch. This Idempotency-Key already opened a checkout for a different body. Send the same body, or a new key. |
429 |
rate_limited. Too many requests to this endpoint right now. Wait Retry-After seconds, then send the same request again. |
500 |
internal. Our bug. Try again in a minute; if it stays, report the X-Request-Id. |
503 |
checkout_failed (Stripe did not open the payment page; nothing was charged, try again in a minute), checkout_closed (buying is off on this server) or busy (the account store is not configured, or a request with this Idempotency-Key is still opening its page; send it again in a few seconds). |
POST /v1/account/subscription
Subscribe to a plan, or change it.
Owner only. With no subscription, opens a Stripe payment page for the plan. With one, moves to the plan: a higher plan is charged in full now and starts a new month with its full credits; a lower plan starts at your next renewal. Two identical changes sent at once are charged once. Credits come only with a paid invoice. Packs top up a subscription (POST /v1/account/checkout).
Body
| field | required | type or values | what it is |
|---|---|---|---|
plan |
yes | string |
Answers
| status | what it means |
|---|---|
200 |
New subscription: checkout_url, a Stripe payment page that expires after 30 minutes. Stripe sends you back to /plan?subscribed or /plan?cancelled. A plan change: change is upgrade (paid now, the month restarts, the new credits land when Stripe confirms) or downgrade (from your next renewal; no money moves now). |
400 |
bad_parameter: plan is missing or not a plan (field plan). bad_request: the body is not one JSON object. |
401 |
bad_token. The key is missing, not valid, expired, revoked, of an unknown prefix or wrong length, or sent as the api_key query parameter, which no route accepts. |
402 |
payment_failed. The payment for the higher plan failed. Your plan did not change. |
403 |
wrong_scope (a scrape key on a route that needs an account key, or an account key on a scraping or batches route) or owner_only (your role is member). |
409 |
checkout_open (a payment page is still open), past_due (the last payment failed; update the card in the billing portal) or already_on_plan. |
413 |
body_too_large. The body was larger than 4 KiB. |
415 |
unsupported_media_type. Send Content-Type: application/json, even for an empty {} body. |
429 |
rate_limited. Too many requests to this endpoint right now. Wait Retry-After seconds, then send the same request again. |
500 |
internal. Our bug. Try again in a minute; if it stays, report the X-Request-Id. |
503 |
checkout_failed (Stripe did not answer; nothing was charged, try again in a minute) or checkout_closed (buying is off on this server). |
POST /v1/account/billing-portal
Open the Stripe billing portal.
Owner only. Your card, your invoices, and canceling.
Answers
| status | what it means |
|---|---|
200 |
portal_url, a Stripe page for your card, your invoices and canceling. A cancel takes effect at the end of the paid month; your credits stay until they expire. |
401 |
bad_token. The key is missing, not valid, expired, revoked, of an unknown prefix or wrong length, or sent as the api_key query parameter, which no route accepts. |
403 |
wrong_scope (a scrape key on a route that needs an account key, or an account key on a scraping or batches route) or owner_only (your role is member). |
404 |
not_subscribed. This account has no subscription yet. |
429 |
rate_limited. Too many requests to this endpoint right now. Wait Retry-After seconds, then send the same request again. |
500 |
internal. Our bug. Try again in a minute; if it stays, report the X-Request-Id. |
503 |
checkout_failed (Stripe did not answer) or checkout_closed (buying is off on this server). |
GET /v1/plans
The free tier and the plans you can subscribe to.
No key. From the plan rows in Postgres; the price is the one Stripe charges.
Answers
| status | what it means |
|---|---|
200 |
The free tier first, then the plans you can subscribe to, cheapest first. price is per month, in currency; both are null on the free tier, which needs no subscription. |
500 |
internal. Our bug. Try again in a minute; if it stays, report the X-Request-Id. |
503 |
Error. The code is in the body. |