Account API
Objective
Section titled “Objective”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.
Endpoints
Section titled “Endpoints”https://storefront.job-rss-processor.workers.dev| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /v1/catalog | Public | What we sell, price per hour, in stock |
GET | /v1/prices | Public | The price of every shape |
GET | /v1/prices/comparison | Public | What each shape costs elsewhere |
GET | /v1/prices/rates | Public | Every dimension of the bill at every other provider |
GET | /v1/me | Session | The caller’s account |
POST | /v1/onboard | Session, verified email | Become a customer. Idempotent |
GET | /v1/access-keys | Session, onboarded | The caller’s EC2 keys |
POST | /v1/access-keys | Session, onboarded | Mint one. 201 |
DELETE | /v1/access-keys/{access} | Session, onboarded | Withdraw one. 204 |
POST | /v1/console/session | Session, onboarded | A the identity service token for the web console |
GET | /v1/usage | Session | Machines running, and the month to date |
POST | /v1/machines/{id}/console | Session | A browser console URL for one machine |
POST | /v1/billing/checkout | Session | Stripe’s page to put a card on file |
POST | /v1/billing/card | Session | Attach the card that page collected |
GET | /v1/billing/portal | Session, onboarded | Stripe’s hosted portal URL, as JSON |
[!primary]
The host above is the Worker’s
workers.devaddress. 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 onshelfcs.com.
/v1/catalog,/v1/pricesand/v1/prices/comparisonare 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:
- The site asks the hosted auth service for a short-lived JWT (
POST /tokenon Better Auth’s own base path). - It sends it on every call as
Authorization: Bearer <jwt>. - 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.
GET /v1/catalog and GET /v1/prices
Section titled “GET /v1/catalog and GET /v1/prices”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.
POST /v1/onboard
Section titled “POST /v1/onboard”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:
- A Stripe customer, tagged
metadata["tenant"] = cust-<userId>— the name metering’s tenant resolver depends on. - A Stripe subscription on the metered price,
collection_method: send_invoice, 30 days to pay. An existing subscription is judged over every status butcanceledandincomplete_expired, so apast_duesubscription is still your one subscription. - A the identity service project named
cust-<userId>, found by name before being created. - 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 itRunInstanceshas nothing to attach a machine to. See Networking. - A the identity service user in that project — your cloud login, from the request
body — found before created, then granted the
memberrole 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/onboardcall with a different password does not change it, and there is no password-reset endpoint yet. Choose it once, and keep it.
Response
Section titled “Response”The Account object, which once onboarded also carries:
| Field | Meaning |
|---|---|
openstack_auth_url | Your cloud identity endpoint — https://identity.shelfcs.com |
openstack_username | cust-<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.
GET /v1/usage
Section titled “GET /v1/usage”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.
Access keys
Section titled “Access keys”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.
Consoles
Section titled “Consoles”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.
GET /v1/me
Section titled “GET /v1/me”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.
GET /v1/billing/portal
Section titled “GET /v1/billing/portal”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.
Quotas set at onboarding
Section titled “Quotas set at onboarding”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.
What this API deliberately does not do
Section titled “What this API deliberately does not do”- 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
admintoday, 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.