Docsary
Markdown Ask Claude Ask ChatGPT
On this page

Billing

Self-service checkout and the billing portal are not currently available. Email hello@robota.us to arrange Pro access. GET /v1/orgs/:org/billing reports your current plan.

The checkout and portal examples below describe the API when billing is enabled. They do not establish a subscription or authorize a charge today.

Checkout and the portal use payment-provider pages. Docsary does not store card numbers; it records billing references and subscription status.

All three need an organization API key. The two POST calls need a write-capable one; GET /billing works with a read-only key.

Pro is $9 a month or $90 a year, per organization. See Pricing and access for what that buys.

Start a subscription

POST /v1/orgs/:org/billing/checkout
curl -s -X POST "$DOCSARY_API/v1/orgs/acme/billing/checkout" \
  -H "authorization: Bearer $DOCSARY_KEY" \
  -H "content-type: application/json" \
  -d '{ "interval": "month" }'
{
  "url": "https://checkout.stripe.com/c/pay/cs_example_SESSION",
  "session_id": "cs_example_SESSION",
  "interval": "month"
}

When enabled, 201 returns a payment URL. After payment, check GET /billing to confirm the plan update. No content push is required.

Field Type Required Notes
interval string no month or year. Defaults to month.
success_url string no Where the browser lands after paying. Defaults to https://docsary.com/access?checkout=success.
cancel_url string no Where it lands if you back out. Defaults to https://docsary.com/access?checkout=cancel.

Omitting the body selects monthly billing and the default return URLs.

Return URLs

Return URLs must meet both rules:

Other hosts return 400. Example using a verified custom domain:

curl -s -X POST "$DOCSARY_API/v1/orgs/acme/billing/checkout" \
  -H "authorization: Bearer $DOCSARY_KEY" \
  -H "content-type: application/json" \
  -d '{
    "interval": "year",
    "success_url": "https://docs.acme.com/thanks",
    "cancel_url": "https://docs.acme.com/pricing"
  }'

Discount codes

The checkout page accepts promotion codes. If we have given you one, enter it there rather than sending it through this call.

Errors

Response Cause
400 {"error":"interval must be 'month' or 'year'"} Anything else in interval
400 containing must be an https URL A return URL that is not https
400 containing attached and verified A return URL on a host that is not yours
401 {"error":"missing bearer token"} No key
403 containing read-only A read-only key. Starting a subscription is a mutation
404 {"error":"org not found"} Unknown organization — or somebody else's. The two answer identically on purpose
409 containing already has an active subscription You are already subscribed; use the portal below
409 containing already open You have a checkout session open. Finish it, or wait for it to expire
502 containing could not create a checkout session The payment provider refused the request or could not be reached. Retry once; if it repeats, email us rather than looping — a repeat means something needs fixing on our side, not on yours
503 {"error":"billing is not configured"} Self-service checkout is not switched on. Email us and we will upgrade you by hand

One checkout at a time

Send checkout requests sequentially and reuse the returned link. Concurrent requests can create duplicate subscriptions. An already-recorded open checkout returns 409 with its session ID and expiry:

{
  "error": "a checkout session is already open for this organization",
  "detail": "Finish or abandon the one you started. It expires by itself, and after that a new one can be created.",
  "session_id": "cs_example_SESSION",
  "expires_at": 1790001800000
}

expires_at uses Unix milliseconds; current_period_end uses Unix seconds. Use the returned expiry before requesting another session.

Errors, continued

An existing subscription returns the portal endpoint:

{
  "error": "this organization already has an active subscription",
  "detail": "Use POST /v1/orgs/acme/billing/portal to change the plan, switch between monthly and yearly, update the card, or cancel.",
  "billing_status": "active",
  "billing_interval": "month"
}

Change or cancel

POST /v1/orgs/:org/billing/portal
curl -s -X POST "$DOCSARY_API/v1/orgs/acme/billing/portal" \
  -H "authorization: Bearer $DOCSARY_KEY"
{
  "url": "https://billing.stripe.com/p/session/bps_example_SESSION",
  "session_id": "bps_example_SESSION"
}

When enabled, 201 returns a portal URL for changing billing interval, updating payment details, downloading invoices, or cancelling.

503 billing is not configured means the portal is unavailable. Contact us about your paid arrangement.

For a subscription managed through this portal, cancellation keeps Pro through the paid period, then applies Free limits. Downgrading does not delete content. See downgrade behavior.

Response Cause
401 / 403 / 404 As above
404 containing no billing customer This organization has never bought anything. Start with checkout
502 containing could not create a portal session The payment provider was unreachable. Retry
503 {"error":"billing is not configured"} As above

What am I on

GET /v1/orgs/:org/billing
curl -s -H "authorization: Bearer $DOCSARY_KEY" \
  "$DOCSARY_API/v1/orgs/acme/billing"
{
  "org": "acme",
  "plan": "pro",
  "plan_source": "stripe",
  "billing_status": "active",
  "billing_interval": "year",
  "current_period_end": 1790000000,
  "current_period_end_unit": "unix_seconds",
  "cancel_at_period_end": false,
  "customer": "…7f21",
  "subscription": "…c904"
}

This endpoint reads the recorded plan without contacting the payment provider.

Field Meaning
plan The effective plan used for quotas: free or pro for customers. owner is reserved for the service operator and is not a customer subscription
plan_source stripe if a subscription is paying for it, manual if a human set it, none once a subscription has ended and nothing is paying for the plan
billing_status The subscription's status, verbatim: active, trialing, past_due, canceled, unpaid, incomplete, incomplete_expired, paused, or null if you have never subscribed
billing_interval month or year
current_period_end When the period you have paid for ends, in unix seconds — not milliseconds, unlike every other timestamp in this API. current_period_end_unit says so in the response. It moves when a renewal is actually paid, so for the hour or so between a renewal being raised and its invoice clearing, it still shows the period before
cancel_at_period_end true once you have cancelled and are running out the period you paid for
customer, subscription The last four characters of the provider's ids, enough to match against an invoice in a support email. The full ids are not returned

GET /v1/whoami also reports the same effective plan, without the billing detail.

The statuses that keep you on Pro

For a subscription-backed plan, active and trialing qualify for Pro unless payment collection is paused. past_due qualifies only within its grace period and while the subscription has not ended.

The grace cutoff uses current_period_end plus the configured period, normally 14 days. When applicable, past_due_grace_ends reports that cutoff in milliseconds. Earlier subscription termination can end Pro before that date. Successful payment restores Pro without another content push.

Paused subscriptions do not qualify for Pro. Check the returned effective plan; status alone is not sufficient.

What happens after a payment

When billing is enabled, successful payment updates the plan. A paid renewal advances current_period_end; failed payment can start the grace period described above. Portal cancellation takes effect at the paid period’s end, while nonpayment can end the subscription earlier.

Confirm changes with GET /billing rather than assuming that opening or returning from a payment page completed them.

What a downgrade does not do

A downgrade does not delete pages, versions, redirects, or assets. Existing custom hostnames keep serving. Free limits can prevent new sites, new custom domains, and additional storage.

GET /billing lists limits your organization exceeds:

{ "plan": "free", "over_plan": ["sites", "custom_domains"] }

This list does not schedule content deletion. A manually assigned plan is not revoked by subscription events; contact us about changes to a separate paid arrangement.

If checkout is not available

503 {"error":"billing is not configured"} is the current availability response for self-service billing. Retrying will not enable it. Email hello@robota.us with the organization you want upgraded.