Skip to content

Account API

This is the only API that turns a signup into a customer of the cloud. Everything else on this platform assumes you already are one.

It implements as little as possible: a hosted auth service owns identity, Stripe owns money, the identity service owns tenancy. The Account API is the glue, and the window that shows what is for sale.

https://storefront.job-rss-processor.workers.dev
MethodPathAuthPurpose
GET/v1/catalogPublicWhat we sell, price per hour, in stock
GET/v1/pricesPublicThe price of every shape
GET/v1/prices/comparisonPublicWhat each shape costs elsewhere
GET/v1/prices/ratesPublicEvery dimension of the bill at every other provider
GET/v1/meSessionThe caller’s account
POST/v1/onboardSession, verified emailBecome a customer. Idempotent
GET/v1/access-keysSession, onboardedThe caller’s EC2 keys
POST/v1/access-keysSession, onboardedMint one. 201
DELETE/v1/access-keys/{access}Session, onboardedWithdraw one. 204
POST/v1/console/sessionSession, onboardedA the identity service token for the web console
GET/v1/usageSessionMachines running, and the month to date
POST/v1/machines/{id}/consoleSessionA browser console URL for one machine
POST/v1/billing/checkoutSessionStripe’s page to put a card on file
POST/v1/billing/cardSessionAttach the card that page collected
GET/v1/billing/portalSession, onboardedStripe’s hosted portal URL, as JSON

[!primary]

The host above is the Worker’s workers.dev address. No domain is attached yet (workers_dev = true), so this hostname changes when one is. It is the one endpoint on this platform that is not on shelfcs.com.

/v1/catalog, /v1/prices and /v1/prices/comparison are cached for 60 seconds at the edge; every other route is per-request.

Authentication: a Bearer JWT from the hosted auth service

Section titled “Authentication: a Bearer JWT from the hosted auth service”

Identity is the hosted auth service, the ledger database’s managed Better Auth. This API and the site are on different hosts, so a browser never sends the hosted auth service’s session cookie here — there is nothing to forward, and this service does no cookie handling at all.

Instead:

  1. The site asks the hosted auth service for a short-lived JWT (POST /token on Better Auth’s own base path).
  2. It sends it on every call as Authorization: Bearer <jwt>.
  3. This service verifies it against the hosted auth service’s JWKS (EdDSA/Ed25519) and issuer.

Default token expiry is 15 minutes. Refresh from the hosted auth service; there is no refresh endpoint here.

Three claims are read: sub (user id), email, emailVerified. A call to /v1/onboard with emailVerified: false is refused.

Public — anyone can call them at any rate. Each answer still costs an admin the identity service token plus the compute service round trip (and, for prices, the rating service), so both are cached for 60 seconds at the edge, keyed on the request URL. A burst of shop traffic costs one round trip, not one per request.

Use these to build a price page or a size picker without an account. See How prices are set for where the numbers come from.

Makes five facts true, in order, recording each before moving to the next, so a half-finished onboarding — a crash, a timeout, an upstream error — is finished by calling again:

  1. A Stripe customer, tagged metadata["tenant"] = cust-<userId> — the name metering’s tenant resolver depends on.
  2. A Stripe subscription on the metered price, collection_method: send_invoice, 30 days to pay. An existing subscription is judged over every status but canceled and incomplete_expired, so a past_due subscription is still your one subscription.
  3. A the identity service project named cust-<userId>, found by name before being created.
  4. A network of your own — the networking service network, subnet (10.200.0.0/24, Quad9 DNS) and router with an external gateway, each looked up by name before being created. Without it RunInstances has nothing to attach a machine to. See Networking.
  5. A the identity service user in that project — your cloud login, from the request body — found before created, then granted the member role and a starting quota. Both are idempotent PUTs and are re-applied on every call until onboarding completes, so a retry that crashed between creating the user and granting its role still ends with both.

Finding before creating is what makes a retry converge instead of hitting the identity service’s 409 on a duplicate name.

The request body carries your cloud password. It goes to the identity service — and it is also kept by this service, in recoverable form, so that POST /v1/console/session can sign you into the console without asking for it again. Read Credentials and trust before choosing it.

[!warning]

The password is used only the first time the user is created. A later /v1/onboard call with a different password does not change it, and there is no password-reset endpoint yet. Choose it once, and keep it.

The Account object, which once onboarded also carries:

FieldMeaning
openstack_auth_urlYour cloud identity endpoint — https://identity.shelfcs.com
openstack_usernamecust-<userId>, the name the identity service knows you by

Those two identify you to the cloud’s own control APIs. Most customers never need them — the EC2 endpoint and your access keys are the supported path. See Account developer guide.

Machines running and the month-to-date bill, in one call — the only cost-before-the-invoice surface this API has. It reads the compute service for what is running and the rating service for what it has cost so far, both scoped to your project.

This is what the console’s overview renders. There is still no cost explorer, no budget alert and no per-resource breakdown; for the rated rows behind the total, query the rating service directly — Metering and invoicing.

GET, POST and DELETE /v1/access-keys mint and withdraw the EC2 credentials the AWS-shaped API signs with. They have a page of their own, including the one way they do not behave like AWS: Access keys.

POST /v1/console/session returns { username, password, region, console_url } — your own cloud password, handed back to your own session, so the page opens the console without asking you to type it. It requires an onboarded account that has a console password on file. What that implies: Credentials and trust.

POST /v1/machines/{id}/console returns a single-use, time-limited browser console URL for one machine, and refuses a machine that is not yours. See Web console and VNC.

POST /v1/billing/checkout returns a Stripe-hosted page for collecting a card; POST /v1/billing/card attaches the card that page collected, and rejects a request that does not name the checkout session it came from.

Note that onboarding still creates a send_invoice subscription — a card on file does not by itself switch you to automatic collection.

The caller’s account, including the same two the cloud platform fields once onboarded. Call it to find out whether onboarding has completed rather than assuming a POST succeeded.

Returns Stripe’s hosted portal URL as JSON. Requires an onboarded account. The portal is where usage, invoices and payment method live — there is no billing UI of ours. See Metering and invoicing.

the compute service only — cores and RAM. The Quota type carries no volumes or gib fields at all, because the block-storage service had no published hostname when this was written. It has one now (volume.shelfcs.com), so this is a gap that can close; until it does, a new project takes the block-storage service’s deployment default rather than a quota chosen for it.

the compute service’s the quota API is itself the legacy quota API. the cloud platform’s unified limits API replaces it eventually; that migration has not happened.

  • It does not handle a password for your site login — the hosted auth service does. It does hold your cloud password; see above.
  • It does not compute any amount of money — the rating service and Stripe do.
  • It knows nothing about internal teams. There is one signup path, this one.
  • There is no console (the web console) provisioning step: the console exists and is reached with the same the identity service credentials.

[!warning]

The the identity service account this Worker authenticates as is the cloud admin today, not a least-privilege service account. That account does not exist yet (the infrastructure repository). It is a known gap in the deployment, recorded here because it affects the blast radius of this service.