{"openapi":"3.1.0","info":{"title":"cloud","description":"CrabTalk cloud client-facing API.\n\n## Error shapes\n\nMost endpoints return [`ErrorResponse`] (`{\"error\": \"message\"}`) on failure. A handful of conditions return the structured [`ApiError`] envelope (`{\"error\": {\"code\", \"message\", \"reset_at\"?}}`) — clients should switch on `error.code`, not the HTTP status, when surfacing UX. Today this includes:\n\n- `403 orgs_closed` — `POST /orgs` on a deployment not taking new orgs. A switch, not a judgement about the caller, and no retry resolves it.\n- `429 rate_limited` or `429 concurrency_limited` — request admission refused; `Retry-After` gives the wait in seconds.\n","license":{"name":"MIT OR Apache-2.0","identifier":"MIT OR Apache-2.0"},"version":"0.1.0"},"servers":[{"url":"https://api.crabtalk.ai"}],"paths":{"/accounts/{owner}/overview":{"get":{"tags":["profiles"],"operationId":"overview","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Profile, visible services and templates, and owner metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountOverview"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/accounts/{owner}/status":{"get":{"tags":["profiles"],"operationId":"status","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Owner billing period, credit and live memory","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Status"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/auth/callback":{"get":{"tags":["auth"],"summary":"Complete a sign-in or link flow.","description":"A sign-in redirects to the FE with `#token=` or `#error=`; a link to the\nweb page it started from, else security settings, with `error=` when it\nfailed. A missing or expired\nCSRF state is a 401, not a redirect, because we no longer know which\nsurface — or which provider — the user came from.","operationId":"auth_callback","parameters":[{"name":"code","in":"query","description":"Authorization code returned by the provider.","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state echoed back from the consent redirect.","required":true,"schema":{"type":"string"}}],"responses":{"307":{"description":"Redirect to frontend: a sign-in with token or error in the URL fragment, a link to the page it started from"},"401":{"description":"Unknown or expired CSRF state"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/github":{"get":{"tags":["auth"],"summary":"Start the GitHub login flow.","description":"Answers `404` on a deployment that has configured no GitHub OAuth app,\nwhich is what a client should read as \"this deployment offers Google only\".","operationId":"auth_github","parameters":[{"name":"client","in":"query","description":"Front-end surface that should receive the session token after the\nOAuth round-trip completes.","required":true,"schema":{"$ref":"#/components/schemas/Client"}},{"name":"port","in":"query","description":"Localhost port the terminal is listening on. Required when `client=terminal`.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"307":{"description":"Redirect to human verification or GitHub consent"},"400":{"description":"Missing or invalid `client` query param"},"404":{"description":"GitHub login is not configured here"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["auth"],"operationId":"auth_github_start","parameters":[{"name":"client","in":"query","description":"Front-end surface that should receive the session token after the\nOAuth round-trip completes.","required":true,"schema":{"$ref":"#/components/schemas/Client"}},{"name":"port","in":"query","description":"Localhost port the terminal is listening on. Required when `client=terminal`.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkResponse"}}}},"403":{"description":"Human verification required or failed"},"404":{"description":"GitHub login is not configured here"},"default":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/github/link":{"get":{"tags":["auth"],"summary":"Start the GitHub link flow. Caller must already be logged in.","operationId":"auth_github_link","parameters":[{"name":"return_to","in":"query","description":"The web page to return to, as a path: `/verify/WDJB-MJHT`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Redirect URL to GitHub consent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkResponse"}}}},"400":{"description":"`return_to` is not a path on the web app"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"GitHub login is not configured here"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/auth/google":{"get":{"tags":["auth"],"summary":"Start the Google login flow.","operationId":"auth_google","parameters":[{"name":"client","in":"query","description":"Front-end surface that should receive the session token after the\nOAuth round-trip completes.","required":true,"schema":{"$ref":"#/components/schemas/Client"}},{"name":"port","in":"query","description":"Localhost port the terminal is listening on. Required when `client=terminal`.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"307":{"description":"Redirect to human verification or Google consent"},"400":{"description":"Missing or invalid `client` query param"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["auth"],"operationId":"auth_google_start","parameters":[{"name":"client","in":"query","description":"Front-end surface that should receive the session token after the\nOAuth round-trip completes.","required":true,"schema":{"$ref":"#/components/schemas/Client"}},{"name":"port","in":"query","description":"Localhost port the terminal is listening on. Required when `client=terminal`.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkResponse"}}}},"403":{"description":"Human verification required or failed"},"default":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/google/link":{"get":{"tags":["auth"],"summary":"Start the Google link flow. Caller must already be logged in.","operationId":"auth_google_link","parameters":[{"name":"return_to","in":"query","description":"The web page to return to, as a path: `/verify/WDJB-MJHT`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Redirect URL to Google consent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkResponse"}}}},"400":{"description":"`return_to` is not a path on the web app"},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/avatars/{owner}":{"get":{"tags":["profiles"],"summary":"The current avatar of a person or organization, without a session.","operationId":"account_avatar","parameters":[{"name":"owner","in":"path","description":"Account handle or id","required":true,"schema":{"type":"string"}}],"responses":{"307":{"description":"Current avatar URL"},"404":{"description":"No such account or no avatar"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/avatars/{owner}/{file}":{"get":{"tags":["profiles"],"operationId":"get_avatar","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"file","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Uploaded avatar"},"404":{"description":"No such avatar"},"502":{"description":"The upload bucket did not serve the image","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/catalog":{"get":{"tags":["catalog"],"summary":"The catalog.","description":"Each category with its platforms, each platform with the jobs the tools of\nservices the caller sees do, most called first. A job lists every such\ntool as a provider, with its price and its calls over the last 30 days.","operationId":"catalog","parameters":[{"name":"category","in":"query","description":"Only this category, by its id.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Each category","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategoryJobs"}}}}},"404":{"description":"No such category"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/catalog/{platform}":{"get":{"tags":["catalog"],"summary":"A platform's jobs.","description":"The category the platform is listed in, holding the platform alone, with\nits jobs as `GET /catalog` answers them.","operationId":"platform","parameters":[{"name":"platform","in":"path","description":"Platform, as `tiktok`","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Its category, holding it alone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryJobs"}}}},"404":{"description":"No such platform"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/catalog/{platform}/{job}":{"get":{"tags":["catalog"],"summary":"A job's providers.","description":"The category and platform the job is under, holding the job alone: every\ntool of a service the caller sees whose `catalog` is `{platform}.{job}`,\nmost called first.","operationId":"job","parameters":[{"name":"platform","in":"path","description":"Platform, as `tiktok`","required":true,"schema":{"type":"string"}},{"name":"job","in":"path","description":"The job after the platform, as `user.videos`","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Its category and platform, holding it alone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryJobs"}}}},"404":{"description":"No such platform, or no tool does the job"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/explore":{"get":{"tags":["catalog"],"operationId":"explore","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"category","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"availability","in":"query","required":false,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Availability"}]}},{"name":"credentials","in":"query","required":false,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Credentials"}]}},{"name":"page","in":"query","description":"Starts at 1; defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"limit","in":"query","description":"Between 1 and 100; defaults to 24.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"200":{"description":"Public services and published templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Discovery"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/meta/errors/{code}":{"get":{"tags":["meta"],"summary":"What an error code means.","description":"The explanation a refusal's `explain` names, in Markdown, as `crab explain`\nprints it.","operationId":"explain","parameters":[{"name":"code","in":"path","description":"The error code, as `E0001`, in any case","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Explanation"}}}},"404":{"description":"No error has that code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/meta/health":{"get":{"tags":["meta"],"summary":"Liveness probe.","description":"Probes the database, because a cloud that cannot reach Postgres can serve\nalmost nothing. `docker compose` reads this to decide whether the container\nis up.","operationId":"health","responses":{"200":{"description":"Serving, and the database answered"},"503":{"description":"The database probe failed"}}}},"/meta/keys":{"get":{"tags":["meta"],"operationId":"key_defaults","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyDefaults"}}}}}}},"/meta/login":{"get":{"tags":["meta"],"operationId":"login_config","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginConfig"}}}}}}},"/meta/plans":{"get":{"tags":["meta"],"summary":"List subscription plans the cloud server offers, including limits.","operationId":"list_plans","responses":{"200":{"description":"Available plans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublicPlan"}}}}}}}},"/meta/rates":{"get":{"tags":["meta"],"summary":"What a service's meters cost.","description":"The rates an owner is charged for its services' meters, each in USD micros\nper billion units. With a tool's terms, they bound what one run of it costs\nto run, its calls to other services aside.","operationId":"rates","responses":{"200":{"description":"The rates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Metering"}}}}}}},"/meta/version":{"get":{"tags":["meta"],"summary":"This deployment: the build it is running and the schema it is on.","description":"No database access, so it still answers when the probe above is failing:\n\"what is deployed here\" is the first question of an incident.\n\n`schema` keeps that property while still being true of the database — see\n[`store::schema`], which is why it is answered from the binary.","operationId":"version","responses":{"200":{"description":"Running build and schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionInfo"}}}}}}},"/orgs":{"post":{"tags":["org"],"summary":"Create a new org. The caller becomes the owner.","description":"Hobby occupies the creator's free slot. A paid organization activates\nafter checkout, with its handle reserved for 30 minutes.","operationId":"create_org","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgRequest"}}},"required":true},"responses":{"200":{"description":"Created org (with checkout_url when tier is paid)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgResponse"}}}},"400":{"description":"A handle that cannot be claimed, an unknown tier slug, or paid tier requested without `client`"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"`orgs_closed` — this deployment is not taking new orgs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Handle already taken"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}":{"get":{"tags":["org"],"summary":"One org, as much of it as the caller may see.","description":"Requires a session. `private` is present only for members.\n\nTakes a handle or an id. A person's own account is not one of these: it is\nanswered by `GET /user`, where the token names it.","operationId":"get_org","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The org, with `private` when the caller is a member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgView"}}}},"401":{"description":"Missing or invalid session"},"403":{"description":"An API key cannot read account profiles"},"404":{"description":"No such org"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["org"],"summary":"Delete an org. Owner only.","description":"Everything keyed to it goes: members, teams and keys. There is no undo and\nno export, and the handle returns to the shared namespace for anyone to\nclaim.\n\nA subscription that can still bill is refused — cancel it through the\nbilling portal first, so Stripe stops before the org it charges is gone.","operationId":"delete_org","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can delete an org"},"404":{"description":"No such org"},"409":{"description":"A subscription still bills this org"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"patch":{"tags":["org"],"summary":"Update an org. Owner only; absent fields are left alone.","description":"`handle` shares one namespace across every account, so a person and an\norganization can never claim the same `/<handle>`.","operationId":"update_org","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrgRequest"}}},"required":true},"responses":{"200":{"description":"Updated org","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Org"}}}},"400":{"description":"Invalid or reserved handle, a non-https avatar, a bio past 160 characters, or links past 4 or not https"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can update an org"},"409":{"description":"Handle already taken"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/alerts":{"get":{"tags":["org"],"summary":"Which alerts email the org's owners. Owner only.","operationId":"org_alerts","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The org's alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alerts"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage alerts"},"404":{"description":"No such org — a person reads theirs at `/user/alerts`"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"put":{"tags":["org"],"summary":"Set which alerts email the org's owners. Owner only.","operationId":"set_org_alerts","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alerts"}}},"required":true},"responses":{"200":{"description":"The org's alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alerts"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage alerts"},"404":{"description":"No such org — a person sets theirs at `/user/alerts`"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/apps":{"get":{"tags":["org"],"summary":"List an org's apps. Owner only.","operationId":"list_apps","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The org's apps","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/App"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners manage apps"},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["org"],"summary":"Create an app for an org. Owner only.","description":"A browser on one of its origins calls the services it lists, sending its\nid as `X-App` and, for a signed-in user, an ID token from one of its issuers\nas the bearer.","operationId":"create_app","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppRequest"}}},"required":true},"responses":{"200":{"description":"The app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/App"}}}},"400":{"description":"A bad origin, issuer or service"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners manage apps"},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/apps/{app_id}":{"put":{"tags":["org"],"summary":"Replace an org's app. Owner only.","operationId":"replace_app","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"app_id","in":"path","description":"App id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppRequest"}}},"required":true},"responses":{"200":{"description":"The app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/App"}}}},"400":{"description":"A bad origin, issuer or service"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners manage apps"},"404":{"description":"No such org or app"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["org"],"summary":"Delete an org's app. Owner only.","operationId":"delete_app","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"app_id","in":"path","description":"App id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners manage apps"},"404":{"description":"No such org or app"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/avatar":{"put":{"tags":["org"],"summary":"Upload an org's picture. Owner only.","description":"The body is the image itself — PNG, JPEG or WebP, at most 1024 px on its\nlongest edge and under 1 MiB, read by its magic bytes rather than by\n`Content-Type`. Cloud stores it and points\n`avatar` at the result; `PATCH /orgs/{org}` still takes a URL for an image\nhosted elsewhere.","operationId":"upload_org_avatar","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"PNG, JPEG or WebP bytes","content":{"application/octet-stream":{}},"required":true},"responses":{"200":{"description":"Stored; the URL `avatar` now holds","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvatarResponse"}}}},"400":{"description":"Not a PNG, JPEG or WebP"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can update an org"},"404":{"description":"No such org"},"410":{"description":"This org was deleted"},"413":{"description":"Image is over 1 MiB, or over 1024 px on an edge"},"501":{"description":"This deployment has no image storage configured"},"502":{"description":"The object store refused it"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/billing/checkout":{"post":{"tags":["org"],"summary":"Create a Stripe Checkout Session for the requested plan. Owner only.","description":"Returns a URL the client should open in a browser. After payment,\nStripe redirects to the frontend matching the `client` parameter. An\naccount already subscribed moves onto the plan in place and gets no URL: a\ndearer plan starts now,\nits prorated difference charged; a cheaper one starts when the period ends.\nThe plan already held drops a change scheduled away from it.","operationId":"org_checkout","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"client","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Client"}},{"name":"plan","in":"query","description":"Plan slug from `[plans.*]`. Must be a paid plan (one with a\n`stripe_price_id`).","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Checkout session URL, or none when the subscription moved onto the plan in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeResponse"}}}},"400":{"description":"Unknown plan, plan is not purchasable, or the plan does not sell to an org"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage billing"},"404":{"description":"No such org — a person buys through `/user/billing/checkout`"},"409":{"description":"Org is already on the requested plan, with no change scheduled away from it"},"410":{"description":"This org was deleted"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/billing/credit":{"get":{"tags":["org"],"summary":"The org's credit balance. Owner only.","operationId":"org_credit","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The credit balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credit"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage billing"},"404":{"description":"No such org — a person reads theirs at `/user/billing/credit`"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["org"],"summary":"Buy credit for the org. Owner only.","description":"Returns a Checkout URL where the amount is entered, $20 or more. The\ncredit is deposited when Stripe reports the session paid.","operationId":"org_buy","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"client","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Client"}}],"responses":{"200":{"description":"Checkout session URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeLink"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage billing"},"404":{"description":"No such org — a person buys through `/user/billing/credit`"},"410":{"description":"This org was deleted"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/billing/credit/history":{"get":{"tags":["org"],"summary":"Where the org's credit came from and went. Owner only.","operationId":"org_history","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Each month's credit and what is left of each purchase","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditHistory"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage billing"},"404":{"description":"No such org — a person reads theirs at `/user/billing/credit/history`"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/billing/invoices":{"get":{"tags":["org"],"summary":"List the org's invoices, newest first. Owner only.","description":"Each row carries Stripe's `invoice_pdf` and `hosted_invoice_url` so the\nclient can render the list itself and link out for downloads. An org with\nno billing account yet gets an empty list, not an error.","operationId":"org_invoices","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Invoices, newest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage billing"},"404":{"description":"No such org — a person reads theirs at `/user/billing/invoices`"},"410":{"description":"This org was deleted"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/billing/payment-method":{"get":{"tags":["org"],"summary":"The card the org's subscription charges. Owner only.","description":"`null` for an org with no card on file.","operationId":"org_payment_method","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The card on file, or null","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaymentMethod"}]}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage billing"},"404":{"description":"No such org — a person reads theirs at `/user/billing/payment-method`"},"410":{"description":"This org was deleted"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/billing/portal":{"post":{"tags":["org"],"summary":"Open the Stripe Customer Portal for an org. Owner only.","description":"Returns a URL to Stripe's hosted billing portal where the user can\nmanage their subscription, update payment methods, or cancel. Pass `flow` to\nopen on one of those actions and come straight back when it is done.","operationId":"org_portal","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"client","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Client"}},{"name":"flow","in":"query","description":"Open the portal on one action. Omit for the full portal.","required":false,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PortalFlow"}]}}],"responses":{"200":{"description":"Portal session URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeLink"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage billing"},"404":{"description":"No billing account linked, or no such org — a person opens theirs at `/user/billing/portal`"},"409":{"description":"`flow=subscription_cancel` with no active subscription"},"410":{"description":"This org was deleted"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/billing/refill":{"put":{"tags":["org"],"summary":"Set the org's monthly auto-refill cap and what one refill buys. Owner only.","description":"While the org holds a paid plan and its credit is below $5, the amount is\ncharged to its card, as long as this month's refills stay within the cap.\nA cap of `0` turns refill off.","operationId":"org_refill","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefillRequest"}}},"required":true},"responses":{"204":{"description":"Cap set"},"400":{"description":"A negative cap, or an amount under $20 or over the cap"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage billing"},"404":{"description":"No such org — a person sets theirs at `/user/billing/refill`"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/billing/usage":{"get":{"tags":["org"],"summary":"What an org used of its plan this period.","description":"What the plan includes over the billing period, what the org's services\nused of it, as last pushed by their nodes, the credit drawn, the warnings it\nwas given, and what it paid other accounts' tools' prices.","operationId":"org_usage","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The current period","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Period"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the org, or a key bound to another account"},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/calls":{"get":{"tags":["org"],"summary":"An org's calls.","description":"Each run of the org's services retained for one year, newest first,\n`limit` a page: as a service's calls are, each also naming its service, as\nlast pulled from the nodes running them every 30 seconds. `Link` names the\n`next` page, the calls below the last one's `id` as `before`, while there\nmay be more.","operationId":"org_calls","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Only calls of this service","required":false,"schema":{"type":"string"}},{"name":"project","in":"query","description":"Only calls of the services deployed in this project","required":false,"schema":{"type":"string"}},{"name":"tool","in":"query","description":"Only calls of this tool","required":false,"schema":{"type":"string"}},{"name":"event","in":"query","description":"Only calls that emitted a log carrying this topic","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","description":"Only calls that emitted a log whose data or a topic holds this text, in either case","required":false,"schema":{"type":"string"}},{"name":"outcome","in":"query","description":"Only calls that ended so: `done`, `failed`, `denied` or `refused`","required":false,"schema":{"type":"string"}},{"name":"since","in":"query","description":"Only calls begun at or after this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"until","in":"query","description":"Only calls begun before this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"before","in":"query","description":"Only calls below the call of this id, newest first","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"limit","in":"query","description":"At most this many, up to 1000; 100 by default","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"The calls","headers":{"Link":{"schema":{"type":"string"},"description":"The `next` page, relative to the request"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AccountCall"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the org, or a key bound to another account"},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/calls/stats":{"get":{"tags":["org"],"summary":"An org's calls, counted.","description":"What the calls of its services on the page the query asks for count to,\nthe same filters as its calls take but `before` and `limit`: by `bucket`\nmilliseconds of their start, as many as cut the range into at most 60, and\nby each service, tool and outcome, every filter but that one's applied.\nThe range is the last 30 days through now without `since` and `until`.\n`synced` is when the calls counted were last pulled.","operationId":"org_call_stats","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Only calls of this service","required":false,"schema":{"type":"string"}},{"name":"project","in":"query","description":"Only calls of the services deployed in this project","required":false,"schema":{"type":"string"}},{"name":"tool","in":"query","description":"Only calls of this tool","required":false,"schema":{"type":"string"}},{"name":"event","in":"query","description":"Only calls that emitted a log carrying this topic","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","description":"Only calls that emitted a log whose data or a topic holds this text, in either case","required":false,"schema":{"type":"string"}},{"name":"outcome","in":"query","description":"Only calls that ended so: `done`, `failed`, `denied` or `refused`","required":false,"schema":{"type":"string"}},{"name":"since","in":"query","description":"Only calls begun at or after this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"until","in":"query","description":"Only calls begun before this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"The counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Counted"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the org, or a key bound to another account"},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/earnings":{"get":{"tags":["org"],"summary":"What an org's priced tools earned.","description":"A UTC calendar month each, newest first: the calls charged, their prices,\nthe platform's cut of them, the compute every priced call used at the\npublished rates, and what is left; each by service and tool. Beside them,\nwhether the account has a Stripe Connect account and can receive payouts,\nwhat closed months owe it, a month below zero counted as zero, and its\npayouts, newest first. Payout accounts are US only.","operationId":"org_earnings","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The org's earnings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Earnings"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the org, or a key bound to another account"},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/earnings/connect":{"post":{"tags":["org"],"summary":"Open Stripe's onboarding for the org's payout account. Owner only.","description":"Creates the org's Stripe Express account the first time, a US one that\nreceives transfers, and answers a link to Stripe's hosted onboarding,\nwhich returns to the org's Earnings page. An unfinished onboarding asks\nfor a fresh link.","operationId":"org_connect","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Onboarding URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeLink"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage payouts"},"404":{"description":"No such org — a person connects theirs at `/user/earnings/connect`"},"410":{"description":"This org was deleted"},"501":{"description":"Payouts are not offered"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/earnings/dashboard":{"post":{"tags":["org"],"summary":"Open the org's payout account's Stripe dashboard. Owner only.","description":"A login link to the Express dashboard, for bank details, payouts and tax\nforms.","operationId":"org_dashboard","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Login URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeLink"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage payouts"},"404":{"description":"No payout account, or no such org — a person opens theirs at `/user/earnings/dashboard`"},"410":{"description":"This org was deleted"},"501":{"description":"Payouts are not offered"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/invites":{"get":{"tags":["org"],"summary":"Pending invitations to an org. Owner only.","description":"Expired invitations are listed rather than hidden — a dead one is why\nnobody arrived, which is exactly what an owner is looking for.","operationId":"list_invites","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Pending invitations, newest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Invite"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can list invitations"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["org"],"summary":"Invite an address to an org. Owner only.","description":"Unlike `POST /orgs/{org}/members`, the address need not have an account yet —\ntheir first login takes any invitation waiting for it. Cloud sends no mail,\nso the returned `token` is the owner's to deliver; accepting it also\nrequires the accepter's verified email to match. Inviting an address that\nalready has a pending invitation replaces it, minting a fresh token and\nrestarting the two-week clock.","operationId":"create_invite","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteRequest"}}},"required":true},"responses":{"200":{"description":"The pending invitation, with the token to deliver","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invite"}}}},"400":{"description":"The email is empty"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can invite"},"409":{"description":"That address is already a member"},"410":{"description":"This org was deleted"},"422":{"description":"Role is not `owner` or `member`"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/invites/{token}":{"delete":{"tags":["org"],"summary":"Revoke a pending invitation. Owner only.","operationId":"revoke_invite","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"token","in":"path","description":"Invitation token","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can revoke invitations"},"404":{"description":"No such invitation on this org"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/keys":{"get":{"tags":["org"],"summary":"List an org's keys, active and revoked. Owner only.","description":"Each with what it spent on tool prices today, UTC, the other accounts'\npriced services it may call and its pending grant request.","operationId":"list_keys","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Org's keys, newest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Key"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can list keys"},"404":{"description":"No such org"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["org"],"summary":"Mint an API key for an org. Owner only.","operationId":"create_key","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}},"required":true},"responses":{"200":{"description":"New key + raw token (shown once)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"400":{"description":"A name outside 1–100 characters or a budget below zero"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can mint a key"},"404":{"description":"No such org"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/keys/{key_id}":{"delete":{"tags":["org"],"summary":"Revoke one of an org's keys. Owner only.","description":"Soft-deletes the key — it stays in the database but can no longer\nauthenticate requests.","operationId":"revoke_key","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"key_id","in":"path","description":"Key id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can revoke a key"},"404":{"description":"No such org, or no active key with that id for it"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"patch":{"tags":["org"],"summary":"Change one of an org's keys. Owner only.","description":"Apply budget, scope and service access atomically. Omitted fields stay unchanged.","operationId":"update_key","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"key_id","in":"path","description":"Key id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKeyRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Key"}}}},"400":{"description":"A budget below zero"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can change a key"},"404":{"description":"No such org, or no active key with that id for it"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/keys/{key_id}/services/{owner}/{name}":{"put":{"tags":["org"],"summary":"Let one of an org's keys call a priced service. Owner only.","description":"Another account's public service, which the key may call from now on\nwithout a grant request. Granting one already granted changes nothing.","operationId":"grant_key","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"key_id","in":"path","description":"Key id","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"The service's account, by handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"The service's name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Granted"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can change a key"},"404":{"description":"No such org, no active key with that id for it, or no such public service"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["org"],"summary":"Stop one of an org's keys calling a priced service. Owner only.","operationId":"ungrant_key","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"key_id","in":"path","description":"Key id","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"The service's account, by handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"The service's name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No longer granted"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can change a key"},"404":{"description":"No such org, no active key with that id for it, or the key may not call that service"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/members":{"get":{"tags":["org"],"summary":"List members of an org. Caller must be a member.","operationId":"list_members","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Org members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Member"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not a member of this org"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["org"],"summary":"Add a member to an org. Owner only.","description":"The invitee must already have an account; `404` otherwise.","operationId":"add_member","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddMemberRequest"}}},"required":true},"responses":{"200":{"description":"Added member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can add members"},"404":{"description":"No user with that email"},"410":{"description":"This org was deleted"},"422":{"description":"Role is not `owner` or `member`"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/members/{member_id}":{"delete":{"tags":["org"],"summary":"Remove a member from an org, or leave one.","description":"Owner only, except that anyone may name themselves — leaving is removing\nyourself, so it is the same act on the same URL rather than a second route.\nThe last-owner rule binds either way.","operationId":"remove_member","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"member_id","in":"path","description":"Member id to remove; your own to leave","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can remove another member"},"404":{"description":"Member not found"},"409":{"description":"That member is the last owner"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"patch":{"tags":["org"],"summary":"Change a member's role. Owner only.","description":"Addressed by member id, which is what a listing hands back; adding someone\nby the address they signed up with is `POST /orgs/{org}/members`. The last\nowner cannot be demoted, for the reason they cannot be removed — every route\nthat could appoint one is itself owner-gated.","operationId":"update_member","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"member_id","in":"path","description":"Member id to change","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRequest"}}},"required":true},"responses":{"200":{"description":"The updated membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can change a role"},"404":{"description":"Member not found"},"409":{"description":"That member is the last owner"},"410":{"description":"This org was deleted"},"422":{"description":"Role is not `owner` or `member`"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/memory":{"get":{"tags":["org"],"summary":"The memory an org's services hold.","description":"Accounted bytes of its services' retained code and bytes of linear memory\nits calls running now hold, summed over the nodes running them, beside its\nplan's limit. Idle cached code is reclaimed first; active calls can still\noccupy the allowance. Growth past it fails, and an image larger than the\nallowance is refused.","operationId":"org_memory","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"What its services hold now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Memory"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the org, or a key bound to another account"},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/services":{"get":{"tags":["org"],"summary":"List an org's services.","description":"Each service the caller sees, the public ones and the private ones too for\nthe org's members: its IDL as `GET /services/{owner}/{name}/idl` answers it,\n`private`, and `served` as `GET /services/{owner}/{name}` answers it.","operationId":"org_services","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Each service","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/orgs/{org}/services/deploys":{"post":{"tags":["org"],"summary":"Deploy an org's services together.","description":"Checks every candidate before switching, in dependency order. By default\none refusal prevents the set, and a switch failure rolls it back. With\n`partial`, each successful service stays live and each failure is reported\nby name. Migrations already applied remain applied after rollback.","operationId":"org_deploy","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploySetRequest"}}},"required":true},"responses":{"200":{"description":"Each service's deployed version or failure, by name","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"A bad name, or one service's image, seed or prices refused"},"401":{"description":"Missing or invalid bearer token"},"402":{"description":"The org holds no paid plan, or one service sets prices with no payout account that can receive payouts"},"403":{"description":"Not an owner of the org, or a key bound to another account"},"404":{"description":"No such org"},"409":{"description":"One service's deploy breaks what callers used in the last 30 days, undoes a period its owners set, names a seed for a service with a database, names a service in another project, or reserves past the plan's storage"},"422":{"description":"One service needs a syscall this host does not serve, or its `size` is refused"},"502":{"description":"A registry, the upload bucket or a node did not serve an image"},"503":{"description":"The fleet has no room for a service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/services/disk":{"get":{"tags":["org"],"summary":"What an org's services hold on disk.","description":"Each placed service's database: the bytes it reserves on its node and the\nbytes it keeps, as last sampled.","operationId":"org_services_disk","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Each service's disk, by name","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Disk"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the org, or a key bound to another account"},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/services/usage":{"get":{"tags":["org"],"summary":"What an org's services used.","description":"Each service's calls, failures, resources and cost over the last 30 days, a\nday each, oldest first, as last pushed by the nodes running it, each minute.","operationId":"org_services_usage","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Each service's days, by name","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/CostedDay"}},"propertyNames":{"type":"string"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the org, or a key bound to another account"},"404":{"description":"No such org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/sponsor/{member_id}":{"put":{"tags":["org"],"summary":"Transfer a Hobby organization's sponsorship to an eligible owner.","operationId":"sponsor","parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"member_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sponsorship transferred"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/teams":{"get":{"tags":["org"],"summary":"List an org's teams. Caller must be a member.","operationId":"list_teams","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Teams, by slug","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Team"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not a member of this org"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["org"],"summary":"Create a team. Owner only.","operationId":"create_team","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Created team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"400":{"description":"Invalid slug"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can create a team"},"409":{"description":"A team with that slug already exists"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/teams/{team}":{"get":{"tags":["org"],"summary":"One team. Caller must be a member of the org.","operationId":"get_team","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"team","in":"path","description":"Team slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not a member of this org"},"404":{"description":"No such team"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["org"],"summary":"Delete a team. Owner only.","description":"Its memberships go with it.","operationId":"delete_team","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"team","in":"path","description":"Team slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can delete a team"},"404":{"description":"No such team"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"patch":{"tags":["org"],"summary":"Update a team. Owner only; absent fields are left alone.","description":"A new `slug` renames the team everywhere at once, its memberships included.","operationId":"update_team","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"team","in":"path","description":"Team slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"400":{"description":"Invalid slug"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can update a team"},"404":{"description":"No such team"},"409":{"description":"Another team already holds that slug"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/teams/{team}/members":{"get":{"tags":["org"],"summary":"List a team's members. Caller must be a member of the org.","operationId":"list_team_members","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"team","in":"path","description":"Team slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The team's members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMember"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not a member of this org"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/teams/{team}/members/{member_id}":{"put":{"tags":["org"],"summary":"Add a member to a team. Owner only.","description":"Idempotent: re-adding someone already in the team changes nothing and\nreturns the membership they already had.","operationId":"add_team_member","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"team","in":"path","description":"Team slug","required":true,"schema":{"type":"string"}},{"name":"member_id","in":"path","description":"Member id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMember"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage a team, or the target is not in the org"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["org"],"summary":"Remove a member from a team. Owner only.","operationId":"remove_team_member","parameters":[{"name":"org","in":"path","description":"Org handle or id","required":true,"schema":{"type":"string"}},{"name":"team","in":"path","description":"Team slug","required":true,"schema":{"type":"string"}},{"name":"member_id","in":"path","description":"Member id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Only owners can manage a team"},"404":{"description":"Not a member of that team"},"410":{"description":"This org was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/orgs/{org}/templates":{"get":{"tags":["orgs"],"operationId":"org_templates","parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string"}},{"name":"all","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Published templates, or all templates for an authorized owner with all=true","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/requests":{"post":{"tags":["requests"],"summary":"Ask a person to pay for a purchase, to set secrets of a service, to approve\na deploy, to verify on GitHub, or to let an API key spend.","description":"Answers a code and the page it opens, which lasts 30 minutes, or 15 for a\ndeploy. The caller is the account or an owner of the org, through a session\nor an API key; a grant request is asked by any API key, for\nitself and its account, and is answered as the key's pending one when\nthat asks all of it already. What is asked is\nrefused here as doing it would be refused, and again when it is done. A\nsecret request asks for the credential it names, set or not, or else for\nevery required credential the service's runtime declares with a secret\nunset and each unset secret in none. Each image a deploy request names is read for what\nit says it is, and refused when it is not a service. A verify request is\nfor a person on Hobby who is not verified, and completes once they are.","operationId":"create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"400":{"description":"An unknown plan, a plan the account cannot have, a malformed secret name, a copy key no credential asked for declares, a deploy of no service, a grant asking nothing, a budget below zero or asked through a session, or `context` or a copy value too long"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not the account or an owner of it, a key bound to another account"},"404":{"description":"No such account, service or credential"},"409":{"description":"Already on the plan, every required secret set, or a verify request for an account that is not a person's on Hobby unverified"},"502":{"description":"The service's node did not answer"},"503":{"description":"This deployment keeps no secrets"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/requests/login":{"post":{"tags":["requests"],"summary":"Ask a person to sign a device in.","description":"RFC 8628's device authorization: the device shows the person `user_code`\nto enter at `verification_uri`, or `verification_uri_complete`, and polls\n`POST /requests/login/token` with `device_code` every `interval` seconds.\nA body naming `client_name` requests a dedicated agent key; no body\nrequests a personal session. The codes last 30 minutes.","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentLoginRequest"}]}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceAuthorization"}}}},"400":{"description":"Client name is empty or exceeds 100 characters"},"429":{"description":"Too many requests from this address"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/requests/login/token":{"post":{"tags":["requests"],"summary":"Poll a device's sign-in.","description":"RFC 8628's device access token request. Answers the approved credential\nonce: the poll after that, like one past the\nrequest's expiry, is refused `expired_token`. Until a person acts it is\nrefused `authorization_pending`, or `slow_down` sooner than `interval`\nafter the last poll; a declined sign-in is refused `access_denied`.","operationId":"login_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceToken"}}}},"400":{"description":"`authorization_pending`, `slow_down`, `access_denied` or `expired_token`, in `code`"},"429":{"description":"Too many requests from this address"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/requests/{code}":{"get":{"tags":["requests"],"summary":"One request.","description":"What the page a code opens shows, and what an agent waits on: with `wait`,\na pending request is answered once its status changes, or as it stands\nonce `wait` seconds pass. The code is the only credential; it is taken in\nany case, with or without its dash. Stored credential values are never returned.","operationId":"get_request","parameters":[{"name":"code","in":"path","description":"The request's code, as `WDJB-MJHT`","required":true,"schema":{"type":"string"}},{"name":"wait","in":"query","description":"Seconds to hold a pending request until its status changes, at most\n60. Without it the request is answered as it stands.","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"404":{"description":"No request has that code"},"429":{"description":"Too many requests from this address"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/requests/{code}/approve":{"post":{"tags":["requests"],"summary":"Approve a sign-in, a deploy or a grant.","description":"Signs the device or client that made the login request in as the caller,\na person signed in: an agent gets a dedicated key with the approved\nsettings; a personal device login gets a session. A client's answer carries\n`redirect`, back to the client with its code. A deploy request runs as the caller, an owner of the account, as\n`POST /orgs/{org}/services/deploys` deploys, and completes with each\nservice it put live, or why it did not go live. A grant request, approved\nby an owner of the key's account, lets the key call the services it asks\nfor, of those still public, and sets the budget it asks for.","operationId":"approve","parameters":[{"name":"code","in":"path","description":"The request's code, as `WDJB-MJHT`","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"401":{"description":"Missing or invalid bearer token, or an API key"},"403":{"description":"A deploy or grant request, and the caller is not an owner of its account"},"404":{"description":"No request has that code"},"409":{"description":"Not a login, deploy or grant request, or not pending, a deploy approved already, or a grant for a key since revoked"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/requests/{code}/checkout":{"post":{"tags":["requests"],"summary":"Pay a payment request.","description":"Answers Stripe Checkout, returning to the request's page. When the account's\nactive subscription moves onto the requested plan in place, it answers no\nURL. The request completes when Stripe\nreports the session done.","operationId":"pay","parameters":[{"name":"code","in":"path","description":"The request's code, as `WDJB-MJHT`","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayResponse"}}}},"400":{"description":"Not a payment request"},"404":{"description":"No request has that code"},"409":{"description":"The request is not pending, or the purchase is no longer possible"},"429":{"description":"Too many requests from this address"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/requests/{code}/decline":{"post":{"tags":["requests"],"summary":"Decline a request.","operationId":"decline","parameters":[{"name":"code","in":"path","description":"The request's code, as `WDJB-MJHT`","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Declined"},"404":{"description":"No request has that code"},"409":{"description":"The request is not pending"},"429":{"description":"Too many requests from this address"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/requests/{code}/expire":{"post":{"tags":["requests"],"summary":"Expire a request.","description":"Ends a pending request now, for the account it is for or an owner of it:\nits code stops working and it reads `expired`. Secrets a secret request\nalready saved stay set. A Stripe Checkout opened from a payment request\nbefore this stays payable until Stripe expires it.","operationId":"expire","parameters":[{"name":"code","in":"path","description":"The request's code, as `WDJB-MJHT`","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Request"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not the account or an owner of it"},"404":{"description":"No request has that code"},"409":{"description":"The request is not pending"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/requests/{code}/secrets":{"put":{"tags":["requests"],"summary":"Set one credential of a secret request.","description":"Values for the credential's secrets, set all at once or none, replacing\nany set; one already set may be left out. The caller must manage the service, as setting a secret\ndirectly requires; the code says which secrets. The request completes once\nevery credential it asks for is set through it.","operationId":"set_secrets","parameters":[{"name":"code","in":"path","description":"The request's code, as `WDJB-MJHT`","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretValues"}}},"required":true},"responses":{"204":{"description":"Set"},"400":{"description":"Not a secret request, values not of one credential, an unset secret of it left out, an empty, oversized or multi-line value, or one its credential's pattern refuses"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account"},"404":{"description":"No request has that code, or its service is gone"},"409":{"description":"The request is not pending"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/secrets/{owner}":{"get":{"tags":["secrets"],"operationId":"list","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SecretResource"}}}}}},"security":[{"bearer":[]}]},"post":{"tags":["secrets"],"operationId":"create","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSecretResource"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResource"}}}}},"security":[{"bearer":[]}]}},"/secrets/{owner}/{id}":{"put":{"tags":["secrets"],"operationId":"rotate","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSecret"}}},"required":true},"responses":{"204":{"description":""}},"security":[{"bearer":[]}]},"delete":{"tags":["secrets"],"operationId":"remove","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]}]}},"/secrets/{owner}/{id}/grants":{"put":{"tags":["secrets"],"operationId":"grant","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResourceGrant"}}},"required":true},"responses":{"204":{"description":""}},"security":[{"bearer":[]}]}},"/secrets/{owner}/{id}/grants/{service}":{"delete":{"tags":["secrets"],"operationId":"revoke","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"service","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]}]}},"/services/{owner}":{"post":{"tags":["services"],"operationId":"account_deploy","parameters":[{"name":"owner","in":"path","description":"Account handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploySetRequest"}}},"required":true},"responses":{"200":{"description":"Each service's deployed version or failure, by name","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Not an account owner, a key bound to another account, or missing deployment permission"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}":{"get":{"tags":["services"],"summary":"A service.","description":"The service as anyone it is visible to sees it: its IDL under `service`,\nand under `served` the calls of its tools that ended done from accounts,\napps and anonymous callers, per day over the last 30 days and in total.","operationId":"service","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The service","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"No such service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"tags":["services"],"summary":"Deploy a service.","description":"Runs the image `reference` names as `{owner}/{name}`: a registry reference,\nor `sha256:` and the SHA-256 of an image uploaded through\n`POST /services/{owner}/{name}/image`. Creates the service on its first deploy, private unless `public` is true, while the account's plan lets it deploy. Only its public tools, those its `crab.toml` gives `access`, can be called, by\nany account Cloud authenticates while it is public and any service of the same owner that\ndeclares it, with arguments of the caller's choosing. The service keeps its name and\nstorage across deploys. A deploy that breaks a tool or event of the version\nit replaces is refused while a caller used it in the last 30 days, naming\neach caller and its last call; `force` deploys anyway. `crons` sets each\ncron tool's expression, and is refused, unless `force`, when it undoes one\nits owners set since the last deploy that set them. One needing\na syscall this host does not serve is refused. `size` is what the service's\ndatabase may hold, reserved on its node, and refused when the account's\nservices would reserve past its plan's storage; a write past it fails. `seed` names a seed\nuploaded through `POST /services/{owner}/{name}/seed` that the service's\ndatabase starts as, held to the image's migrations; it is refused when the\nservice has a database. `stopped` installs it stopped, to serve once\nstarted; any other deploy installs it running. `project` labels it with the\nworkspace it came from, refused, unless `force`, when it is in another\nproject. `prices` sets each public tool's price a call, in USD micros, in\nplace of the prices the service had, and is refused naming a tool that is\nnot a public tool of the image, or while the account has no Stripe Connect\naccount that can receive payouts, a US one. Answers with `service`, the\nservice's IDL.","operationId":"deploy","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployRequest"}}},"required":true},"responses":{"200":{"description":"`service`, the service's IDL","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Bad name, a registry Cloud does not deploy from, an image Cloud cannot pull anonymously or that is not a service, an image that will not load, an image or a seed not uploaded, one the image's migrations do not hold to, or a price for a tool that is not a public tool of the image"},"401":{"description":"Missing or invalid bearer token"},"402":{"description":"The account holds no paid plan, or is unverified on Hobby, or sets prices with no payout account that can receive payouts"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account"},"409":{"description":"The deploy breaks what callers of the deployed version used in the last 30 days, undoes a period its owners set, names a seed for a service with a database, names a service in another project, or reserves past the plan's storage"},"422":{"description":"The service needs a syscall this host does not serve or keeps no database to seed, or `size` is past 10 GiB or below what the database holds"},"502":{"description":"The registry or the upload bucket did not serve the image"},"503":{"description":"The fleet has no node to run it on, or its node has no room for `size`"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["services"],"summary":"Remove a service.","description":"Stops running it and drops what it committed, its wake and its usage. Its\nname is free for a deploy.","operationId":"remove","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/billing":{"get":{"tags":["services"],"summary":"A service's billing.","description":"In one UTC calendar month, a day each: its meters and what they cost its\nowner, the current month read from the node running it as asked, an\nearlier one as the nodes last pushed it. Each charged resource over the\nmonth with its rate and cost at the rates, what its owner owes, and the\nservice's first metered day.","operationId":"billing","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"month","in":"query","description":"The UTC calendar month, `YYYY-MM`; the current one by default","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The service's billing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Billing"}}}},"400":{"description":"`month` is not `YYYY-MM`"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/calls":{"get":{"tags":["services"],"summary":"A service's calls.","description":"Each run of the service retained for one year, newest first, `limit` a\npage: a call from outside or a wake, with its caller (an account by its\nhandle, an app by its id, a service as `owner/name`), outcome,\nduration, meter summed over every service it reached, what that meter costs\nthe owner, and how many logs it emitted, as last pulled from the nodes\nrunning it every 30 seconds. `Link` names the `next` page, the calls below\nthe last one's `id` as `before`, while there may be more.","operationId":"calls","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"tool","in":"query","description":"Only calls of this tool","required":false,"schema":{"type":"string"}},{"name":"event","in":"query","description":"Only calls that emitted a log carrying this topic","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","description":"Only calls that emitted a log whose data or a topic holds this text, in either case","required":false,"schema":{"type":"string"}},{"name":"outcome","in":"query","description":"Only calls that ended so: `done`, `failed`, `denied` or `refused`","required":false,"schema":{"type":"string"}},{"name":"since","in":"query","description":"Only calls begun at or after this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"until","in":"query","description":"Only calls begun before this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"before","in":"query","description":"Only calls below the call of this id, newest first","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"limit","in":"query","description":"At most this many, up to 1000; 100 by default","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"The calls","headers":{"Link":{"schema":{"type":"string"},"description":"The `next` page, relative to the request"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Costed"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/calls/stats":{"get":{"tags":["services"],"summary":"A service's calls, counted.","description":"What its calls on the page the query asks for count to, the same filters\nas its calls take but `before` and `limit`: by `bucket` milliseconds of\ntheir start, as many as cut the range into at most 60, and by each tool and\noutcome, every filter but that one's applied. The range is the last 30 days\nthrough now without `since` and `until`.","operationId":"call_stats","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"tool","in":"query","description":"Only calls of this tool","required":false,"schema":{"type":"string"}},{"name":"event","in":"query","description":"Only calls that emitted a log carrying this topic","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","description":"Only calls that emitted a log whose data or a topic holds this text, in either case","required":false,"schema":{"type":"string"}},{"name":"outcome","in":"query","description":"Only calls that ended so: `done`, `failed`, `denied` or `refused`","required":false,"schema":{"type":"string"}},{"name":"since","in":"query","description":"Only calls begun at or after this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"until","in":"query","description":"Only calls begun before this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"The counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Counted"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/calls/tools":{"get":{"tags":["services"],"summary":"A service's tools, by what their calls used.","description":"Each tool's meters over the last 30 days, as last pushed by the node\nrunning it, each minute: what the tool's own invocations used, services it\ncalled left out, with the days it ran and what that use costs the owner at\nthe rates, the median and 99th percentile of what its runs that ended\n`done` used and cost to run, from the call log, and the `budget` for its\n`crab.toml` they fit. The empty tool holds what was metered before meters\nwere kept per tool. A tool not called is left out.","operationId":"call_tools","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Its tools' use, by tool","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ToolCosted"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/calls/{id}/image":{"get":{"tags":["services"],"summary":"The image a call that failed ran.","description":"The service's image at the digest its input names: `crab replay` runs the\ncall again in it. Only a call that failed names one.","operationId":"call_image","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","description":"The call's id","required":true,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"The image the call ran","content":{"application/wasm":{}}},"307":{"description":"A short-lived R2 download URL","headers":{"Location":{"schema":{"type":"string"},"description":"Signed artifact URL"}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account, service or call, or a call that kept no input"},"502":{"description":"The image could not be pulled"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/calls/{id}/input":{"get":{"tags":["services"],"summary":"What a call that failed ran with.","description":"Its tool, arguments as sent, caller and the digest of the image it ran,\nfor running it again elsewhere. Only a call that failed keeps them, for\n30 days.","operationId":"call_input","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","description":"The call's id","required":true,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"What the call ran with","content":{"application/json":{"schema":{"type":"object"}}}},"307":{"description":"A short-lived R2 download URL","headers":{"Location":{"schema":{"type":"string"},"description":"Signed artifact URL"}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account, service or call, or a call that kept no input"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/calls/{id}/nested":{"get":{"tags":["services"],"summary":"The calls a call made.","description":"Each call it made to one of the account's services past its first, in the\norder they began, numbered from 1 with `parent` the call that made it, the\nfirst being 0. Kept as long as calls are; a call to a service on another\nnode is left out.","operationId":"call_nested","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","description":"The call's id","required":true,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"The calls it made","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NestedCall"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account, service or call"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/calls/{id}/tape":{"get":{"tags":["services"],"summary":"A call that failed, as berm recorded its answers from outside the guest.","description":"Every syscall it made, in order, with a sha256 of what it asked and the\nanswer it got, encoded as berm encodes a tape: `crab replay` runs the call\nagain against it. Only a call that failed keeps one.","operationId":"call_tape","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","description":"The call's id","required":true,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"The call's tape","content":{"application/octet-stream":{}}},"307":{"description":"A short-lived R2 download URL","headers":{"Location":{"schema":{"type":"string"},"description":"Signed artifact URL"}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account, service or call, or a call that kept no tape"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/check":{"post":{"tags":["services"],"summary":"Check a deploy.","description":"What deploying `reference` as `{owner}/{name}` would do, without\ndeploying: the version it would go live on, the migrations it would apply,\ntried on the service's database and rolled back, and what it would break of\nwhat callers used in the last 30 days. Refused as the deploy would be but\nfor its breaks, which it answers with. The service must exist.","operationId":"check","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployRequest"}}},"required":true},"responses":{"200":{"description":"What the deploy would do","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"A registry Cloud does not deploy from, an image Cloud cannot pull or that is not a service, or migrations that do not apply"},"401":{"description":"Missing or invalid bearer token"},"402":{"description":"Sets prices with no payout account that can receive payouts"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"409":{"description":"The deploy undoes a period its owners set, or names a service in another project"},"422":{"description":"The service needs a syscall this host does not serve, or `size` is refused"},"502":{"description":"The registry or the node did not serve the image"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/context":{"get":{"tags":["services"],"operationId":"context","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","required":false,"schema":{"type":"string"}},{"name":"template","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Visible service, published template and management access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceContext"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/services/{owner}/{name}/crons":{"get":{"tags":["services"],"summary":"A service's cron tools.","description":"Each tool its manifest marks `#[cron]`, by name: its expression, five\nfields in UTC, when it next runs, how many times in a row it failed, and\nits last run. `held` while the account is refused: none runs until it is\nlet go.","operationId":"crons","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The cron tools","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Crons"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/deploys":{"get":{"tags":["services"],"summary":"A service's deploys.","description":"Its last 100 deploys, newest first, refused and failed ones included: how\neach ended and why, its version and image, what it was deployed from, the\nmigrations it applied, whether it was seeded, the node it was placed on,\nwhether it can be redeployed, who deployed it and when. A deploy refused\nbefore the service existed is not recorded.","operationId":"deploys","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Its deploys, newest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Deployment"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/deploys/status":{"get":{"tags":["services"],"summary":"Pending approvals and deployment attempts, including before the first deployment.","operationId":"deployment_status","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Pending approvals and recorded attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStatus"}}}},"403":{"description":"Not an account owner or missing deployments:read"},"404":{"description":"No such account, service or deployment request"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/deploys/{deploy_id}/redeploy":{"post":{"tags":["services"],"summary":"Redeploy a past deploy.","description":"Deploys the image deploy `{deploy_id}` of `{owner}/{name}` ran from again,\nat the size its database holds now, refused as `PUT /services/{owner}/{name}`\nrefuses a deploy. Its crons and prices stay as they are, and it is installed\nrunning.\nOnly a deploy whose image is still kept can be redeployed: one from a\nregistry, or an upload retained in account storage.","operationId":"redeploy","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"deploy_id","in":"path","description":"The deploy's id","required":true,"schema":{"type":"integer","format":"int64"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeployRequest"}}},"required":true},"responses":{"200":{"description":"`service`, the service's IDL","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"An image that will not load, or one the service's migrations do not hold to"},"401":{"description":"Missing or invalid bearer token"},"402":{"description":"The account holds no paid plan, or is unverified on Hobby"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account, service or deploy"},"409":{"description":"Its image is not kept, or the deploy breaks what callers of the deployed version used in the last 30 days or undoes a period its owners set"},"422":{"description":"The service needs a syscall this host does not serve"},"502":{"description":"The registry or the node did not serve the image"},"503":{"description":"The service's node is not in the fleet"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/idl":{"get":{"tags":["services"],"summary":"A service's IDL.","description":"The JSON `crab idl` writes, which `declare_service!` reads.","operationId":"idl","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The service's IDL","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"No such service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/services/{owner}/{name}/image":{"post":{"tags":["services"],"summary":"Upload an image.","description":"Where to `PUT` a service's image, with its `Content-Length`, that a deploy\nof `{owner}/{name}` names by its digest, `sha256:` and the `sha256` here:\nusable for an hour, and none when Cloud holds that image already. An image\nholds at most 64 MiB. Cloud retains it after deployment; only a\ndeploy of `{owner}/{name}` can name it.","operationId":"image","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadRequest"}}},"required":true},"responses":{"200":{"description":"Where to upload the image","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}}},"400":{"description":"Bad name, `sha256` not a SHA-256 in lowercase hex, or `size` past 64 MiB"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account"},"501":{"description":"This Cloud takes no uploads"},"502":{"description":"The upload bucket did not answer"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/logs":{"get":{"tags":["services"],"summary":"List a service's logs.","description":"What its runs emitted, for its owners to debug them: oldest first, `limit`\na page, each beside the call it was emitted in, kept one year. `Link` names\nthe `next` page, the logs after the last one's `seq` as `after`, while there\nmay be more.","operationId":"logs","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"topic","in":"query","description":"Only logs carrying this topic","required":false,"schema":{"type":"string"}},{"name":"call","in":"query","description":"Only logs emitted in this call, as `/calls` numbers it","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"after","in":"query","description":"Only logs after this sequence number","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"At most this many, up to 1000; 100 by default","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"`[{seq, call, at, topics, data}]`","headers":{"Link":{"schema":{"type":"string"},"description":"The `next` page, relative to the request"}},"content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/meters":{"get":{"tags":["services"],"summary":"What a service used.","description":"Its meters over the last 30 days, a day each: invocations, CPU time spent\nin microseconds, the largest linear memory one reached, rows read\nand written in its database and state, and the bytes it stored when the\nday was sampled. Calls whose callers paid the tool's price are left out. A\ntool's answer carries the call's own meter in `Berm-Meter`.","operationId":"metered","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"A day each, oldest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MeteredDay"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/origin":{"get":{"tags":["services"],"summary":"Where a service was deployed from.","description":"The public service of another account it was deployed from, as that one\nruns now: one running an image of the registry repository it runs. `null`\nfor a service running an uploaded image, or one no other account\npublishes.","operationId":"origin","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The service it was deployed from, or null","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Origin"}]}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/overview":{"get":{"tags":["services"],"operationId":"overview","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Terms and authorized owner overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOverview"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/services/{owner}/{name}/runtime":{"get":{"tags":["services"],"summary":"How a service runs.","description":"What its IDL leaves out, for its owners: its tools that are not public,\nwhat it reaches (`deps`), and the events it logs.","operationId":"runtime","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The service's runtime","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/schedule":{"get":{"tags":["services"],"operationId":"schedule","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Terms, cron tools and armed wakes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceSchedule"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/secrets":{"get":{"tags":["services"],"summary":"List a service's secrets.","description":"Names and the hosts each is sent to, by name; a value is never read back.","operationId":"secrets","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The service's secrets, by name","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Secret"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/secrets/{secret}":{"put":{"tags":["services"],"summary":"Provision or replace one declared secret for its manifest destinations.\nValues are never returned. Requires a signed-in owner.","operationId":"set_secret","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"secret","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSecret"}}},"required":true},"responses":{"204":{"description":"Set"},"400":{"description":"A malformed name or host, an empty, oversized or multi-line value, or one its credential's pattern refuses"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"503":{"description":"This deployment keeps no secrets"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["services"],"summary":"Revoke one of a service's secrets.","description":"The service stops being able to use it from the next push to its node.","operationId":"revoke_secret","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"secret","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service, or no secret of that name"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/seed":{"post":{"tags":["services"],"summary":"Upload a seed.","description":"Where to `PUT` a SQLite file, with its `Content-Length`, that a deploy of\n`{owner}/{name}` names by its SHA-256 in `seed`: usable for an hour, and\nnone when Cloud holds that seed already. A seed holds at most 5 GiB. Cloud\ndeletes it once a deploy installs it.","operationId":"seed","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadRequest"}}},"required":true},"responses":{"200":{"description":"Where to upload the seed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}}},"400":{"description":"Bad name, `sha256` not a SHA-256 in lowercase hex, or `size` past 5 GiB"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account"},"501":{"description":"This Cloud takes no uploads"},"502":{"description":"The upload bucket did not answer"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/start":{"post":{"tags":["services"],"summary":"Start a service.","description":"Serves a service stopped, or deployed stopped, again. Wakes that came due\nwhile it was stopped fire. On Hobby, a service stopped after 7 days with no\ncalls counts its next 7 from here.","operationId":"start","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Started"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/stop":{"post":{"tags":["services"],"summary":"Stop a service.","description":"It takes no calls and fires no wakes until started, and calls in flight\nfinish. What it stored stays, and so does the storage it reserves.","operationId":"stop","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Stopped"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/template":{"get":{"tags":["services"],"operationId":"template","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"version","in":"query","description":"Exact retained version or digest; omitted selects the latest non-yanked stable release, falling back to prereleases; if all retained releases are yanked, returns their latest metadata","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Published image and setup declarations","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"No such template"},"410":{"description":"Release image pruned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["services"],"summary":"Running services and existing copies remain.","operationId":"delete_template","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Template deleted"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Requires an owner session"},"404":{"description":"No such account or template"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/template/releases":{"get":{"tags":["services"],"operationId":"list","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Release history, including pruned images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TemplateRelease"}}}}}}}},"/services/{owner}/{name}/template/yank":{"put":{"tags":["services"],"operationId":"yank","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Yank"}}},"required":true},"responses":{"204":{"description":"Release yank state changed"}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/terms":{"get":{"tags":["services"],"summary":"What calling a service is held to and costs.","description":"Each public tool's terms, live, and the node's deadline for a chain of\ncalls: the most one call may use, as its owner set it; its price a call in\nUSD micros, as the service's last deploy set it; and from its first run in\nthe last 30 days that ended `done`, the median and 99th percentile of what\none used and cost to run at the rates, the 99th percentile being the\nlargest below 100 runs.","operationId":"terms","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The service's terms","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Terms"}}}},"404":{"description":"No such service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/services/{owner}/{name}/tools/{tool}":{"get":{"tags":["services"],"summary":"Call a query tool.","description":"For a tool the IDL marks `query`; any other answers `405`. The argument\nobject is URL-encoded JSON in `args`. The `ETag` is the service's commit\ncount, and `If-None-Match` with it answers `304` without running the tool.\nCommits to services the tool calls do not change it.\n\nA deprecated tool's answer carries `Deprecation` (RFC 9745), and `Sunset`\n(RFC 8594) once its owner sets one. A tool with a price charges it as a\n`POST` does; a `304` returns it.","operationId":"query","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"tool","in":"path","description":"Tool name","required":true,"schema":{"type":"string"}},{"name":"args","in":"query","description":"The tool's arguments, as JSON","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"`{\"done\": result}` or `{\"failed\": message}`","content":{"application/json":{"schema":{"type":"object"}}}},"304":{"description":"No commit since the `ETag` in `If-None-Match`"},"401":{"description":"Missing or invalid bearer token"},"402":{"description":"The service's owner is out of credit, or the caller's credit is short of the tool's price"},"404":{"description":"No such service or tool"},"405":{"description":"The tool is not a query"},"429":{"description":"Account rate, concurrency, or memory limit exceeded; admission limits include Retry-After"},"503":{"description":"Every call slot is taken"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["services"],"summary":"Call a tool.","description":"The body is the tool's argument object, as the service reads it. A tool's\nown failure answers `200` with `failed`. A tool with a price charges it to\nthe calling account's credit, the org a key is bound to or the person,\nunless that account owns the service or is a member of it: held before the\ncall, kept when it answers `done`, and returned otherwise.","operationId":"call","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"tool","in":"path","description":"Tool name","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The tool's arguments","content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"description":"`{\"done\": result}` or `{\"failed\": message}`","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid bearer token"},"402":{"description":"The service's owner is out of credit, or the caller's credit is short of the tool's price"},"404":{"description":"No such service or tool"},"429":{"description":"Account rate, concurrency, or memory limit exceeded; admission limits include Retry-After"},"503":{"description":"Every call slot is taken"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"patch":{"tags":["services"],"summary":"Set a deprecated tool's sunset.","description":"Calls to the tool then carry `Sunset` with it. `null` clears it. A tool not\ndeprecated in the deployed version takes none.","operationId":"update","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"tool","in":"path","description":"Tool name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolUpdate"}}},"required":true},"responses":{"204":{"description":"Set"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"409":{"description":"The tool is not deprecated"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/upgrades":{"get":{"tags":["services"],"operationId":"upgrades","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Automatic patch upgrade setting and last attempt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradePolicy"}}}}},"security":[{"bearer":[]}]},"put":{"tags":["services"],"operationId":"set_upgrades","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeSetting"}}},"required":true},"responses":{"204":{"description":"Automatic patch upgrade setting changed"}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/usage":{"get":{"tags":["services"],"summary":"What a service is using now.","description":"Read from the current node: calls running, their linear memory, committed\ndatabase allocation and its enforced capacity, and execution counters.","operationId":"usage","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"What it is using now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Live"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/uses":{"get":{"tags":["services"],"summary":"A service's uses.","description":"Each caller of each of its tools and events in a UTC calendar month, the\ncurrent one by default, by outcome: how many calls it made and when its\nlast one was. An account caller is named by its handle, a service by its\nname. A tool says whether the deployed version makes it public.","operationId":"uses","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"month","in":"query","description":"`YYYY-MM`; the current month when absent","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Its uses","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Usage"}}}}},"400":{"description":"`month` is not `YYYY-MM`"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/vars":{"get":{"tags":["services"],"summary":"A service's vars.","description":"Each var its `[vars]` declares, by name: its description, its default, and\nthe value this service holds, `null` while it reads the default.","operationId":"vars","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The vars","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Setting"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/vars/{var}":{"put":{"tags":["services"],"summary":"Set a var.","description":"The value the service reads for a var its `[vars]` declares, from its next\ncall; `null` returns it to its default. Kept until a deploy's `vars` sets\nanother or its `[vars]` drops the var.","operationId":"var","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"var","in":"path","description":"Var name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VarValue"}}},"required":true},"responses":{"204":{"description":"Set"},"400":{"description":"A value past 4096 bytes: `E0011`"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service, or no such var: `E0011`"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/visibility":{"get":{"tags":["services"],"summary":"Who a service answers.","operationId":"visibility","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The service's visibility","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Visibility"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"put":{"tags":["services"],"summary":"Set who a service answers.","description":"A private service answers only its owning account and that account's\nmembers, from the next request; everyone else is answered `404`.","operationId":"set_visibility","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Visibility"}}},"required":true},"responses":{"204":{"description":"Set"},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/services/{owner}/{name}/wakes":{"get":{"tags":["services"],"summary":"A service's armed wakes.","description":"The wakes armed with `berm.call.after` to call one of its tools that have\nnot run, soonest first: each one's tool, when it fires, the service that\narmed it, and how many times in a row it failed since it was armed. `held`\nwhile the account is refused: none runs until it is let go.","operationId":"wakes","parameters":[{"name":"owner","in":"path","description":"Owning account's handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Service name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The wakes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Wakes"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not an owner of the account, or a key bound to another one"},"404":{"description":"No such account or service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user":{"get":{"tags":["user"],"summary":"Return the caller's own account, and the orgs they belong to.","description":"The account a person owns by being it. `/orgs/{org}` answers for orgs and\n`404`s a person, so what an org gets there — its plan, its subscription — is\nhere for this one. `orgs` holds the shared orgs and not\nthis account, which is the same split GitHub makes between `/user` and\n`/user/orgs`.","operationId":"user_me","responses":{"200":{"description":"The caller's account with their orgs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthMe"}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["user"],"summary":"Delete the caller's account.","description":"Tombstone and scrub: the row and its id stay so every byline, `invited_by`\nand `created_by` goes on resolving to a specific deleted account rather than\nto nothing, while the address, name, avatar and handle go. Sessions and\nkeys are revoked, and the linked OAuth identities are dropped — so\nsigning in with the same provider afterwards creates a new account rather\nthan landing back on this one, which nothing can un-delete.\n\nThis touches nothing but the caller's own account. Orgs they solely own are\nthe one thing in the way: an org with no owner cannot be administered at all,\nso they are refused by name until each has been handed to another owner or\ndeleted.","operationId":"delete_user","responses":{"204":{"description":"Deleted"},"401":{"description":"Missing or invalid bearer token"},"409":{"description":"A subscription still bills this account, or it is the last owner of an org"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"patch":{"tags":["user"],"summary":"Update the caller's profile. Absent fields are left alone.","description":"The same columns `PATCH /orgs/{org}` writes for an org, through the\nsame validation — the token names the account, so there is nothing to\nresolve and no role to check.","operationId":"update_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"Updated user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"400":{"description":"Empty or too-long name, an invalid or reserved handle, a non-https avatar, a bio past 160 characters, or links past 4 or not https"},"401":{"description":"Missing or invalid bearer token"},"409":{"description":"Handle already taken"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/alerts":{"get":{"tags":["user"],"summary":"Which alerts email the caller.","operationId":"user_alerts","responses":{"200":{"description":"The caller's alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alerts"}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"put":{"tags":["user"],"summary":"Set which alerts email the caller.","operationId":"set_user_alerts","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alerts"}}},"required":true},"responses":{"200":{"description":"The caller's alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alerts"}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/apps":{"get":{"tags":["user"],"summary":"List the caller's own apps.","operationId":"list_user_apps","responses":{"200":{"description":"The caller's apps","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/App"}}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["user"],"summary":"Create an app on the caller's own account.","description":"A browser on one of its origins calls the services it lists, sending its\nid as `X-App` and, for a signed-in user, an ID token from one of its issuers\nas the bearer.","operationId":"create_user_app","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppRequest"}}},"required":true},"responses":{"200":{"description":"The app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/App"}}}},"400":{"description":"A bad origin, issuer or service"},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/apps/{app_id}":{"put":{"tags":["user"],"summary":"Replace one of the caller's own apps.","operationId":"replace_user_app","parameters":[{"name":"app_id","in":"path","description":"App id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppRequest"}}},"required":true},"responses":{"200":{"description":"The app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/App"}}}},"400":{"description":"A bad origin, issuer or service"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No such app"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["user"],"summary":"Delete one of the caller's own apps.","operationId":"delete_user_app","parameters":[{"name":"app_id","in":"path","description":"App id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No such app"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/avatar":{"put":{"tags":["user"],"summary":"Upload the caller's picture.","description":"The body is the image itself — PNG, JPEG or WebP, at most 1024 px on its\nlongest edge and under 1 MiB, read by its magic bytes rather than by\n`Content-Type`. Cloud stores it and points\n`avatar` at the result, which is what closes the gap a person had: their\npicture was whatever their OAuth provider handed over, and there was nowhere\nto put a different one. `PATCH /user` still takes a URL for an image hosted\nelsewhere.","operationId":"upload_user_avatar","requestBody":{"description":"PNG, JPEG or WebP bytes","content":{"application/octet-stream":{}},"required":true},"responses":{"200":{"description":"Stored; the URL `avatar` now holds","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvatarResponse"}}}},"400":{"description":"Not a PNG, JPEG or WebP"},"401":{"description":"Missing or invalid bearer token"},"413":{"description":"Image is over 1 MiB, or over 1024 px on an edge"},"501":{"description":"This deployment has no image storage configured"},"502":{"description":"The object store refused it"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/billing/checkout":{"post":{"tags":["user"],"summary":"Create a Stripe Checkout Session for the caller's own account.","description":"The person's half of checkout. Same session, same plans minus the ones a\nplan reserves for orgs. The token names the account, so there is\nnothing to resolve and nobody else to be refused.","operationId":"user_checkout","parameters":[{"name":"client","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Client"}},{"name":"plan","in":"query","description":"Plan slug from `[plans.*]`. Must be a paid plan (one with a\n`stripe_price_id`).","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Checkout session URL, or none when the subscription moved onto the plan in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeResponse"}}}},"400":{"description":"Unknown plan, plan is not purchasable, or the plan does not sell to a person"},"401":{"description":"Missing or invalid bearer token"},"409":{"description":"Already on the requested plan, with no change scheduled away from it"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/billing/credit":{"get":{"tags":["user"],"summary":"The caller's own credit balance.","operationId":"user_credit","responses":{"200":{"description":"The credit balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Credit"}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["user"],"summary":"Buy credit for the caller's own account.","description":"Returns a Checkout URL where the amount is entered, $20 or more. The\ncredit is deposited when Stripe reports the session paid.","operationId":"user_buy","parameters":[{"name":"client","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Client"}}],"responses":{"200":{"description":"Checkout session URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeLink"}}}},"401":{"description":"Missing or invalid bearer token"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/billing/credit/history":{"get":{"tags":["user"],"summary":"Where the caller's own credit came from and went.","operationId":"user_history","responses":{"200":{"description":"Each month's credit and what is left of each purchase","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditHistory"}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/billing/invoices":{"get":{"tags":["user"],"summary":"List the caller's own invoices, newest first.","description":"The person's half of the invoice list. An account with no billing account\nyet gets an empty list, not an error.","operationId":"user_invoices","responses":{"200":{"description":"Invoices, newest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}}}}},"401":{"description":"Missing or invalid bearer token"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/billing/payment-method":{"get":{"tags":["user"],"summary":"The card the caller's own subscription charges.","description":"`null` for an account with no card on file.","operationId":"user_payment_method","responses":{"200":{"description":"The card on file, or null","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaymentMethod"}]}}}},"401":{"description":"Missing or invalid bearer token"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/billing/portal":{"post":{"tags":["user"],"summary":"Open the Stripe Customer Portal for the caller's own account.","description":"The person's half of the portal — the same hosted Stripe page, reached\nthrough the namespace that names the caller.","operationId":"user_portal","parameters":[{"name":"client","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Client"}},{"name":"flow","in":"query","description":"Open the portal on one action. Omit for the full portal.","required":false,"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PortalFlow"}]}}],"responses":{"200":{"description":"Portal session URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeLink"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No billing account linked"},"409":{"description":"`flow=subscription_cancel` with no active subscription"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/billing/refill":{"put":{"tags":["user"],"summary":"Set the caller's own monthly auto-refill cap and what one refill buys.","description":"While the account holds a paid plan and its credit is below $5, the amount\nis charged to its card, as long as this month's refills stay within the\ncap. A cap of `0` turns refill off.","operationId":"user_refill","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefillRequest"}}},"required":true},"responses":{"204":{"description":"Cap set"},"400":{"description":"A negative cap, or an amount under $20 or over the cap"},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/billing/verification":{"get":{"tags":["user"],"summary":"The caller's verification.","description":"When the account was verified, or why verifying it now fails. It verifies\nwhen the person signs in with GitHub, the GitHub account is a year old or\nmore, its own public repositories hold 10 stars or more, and it verified no\nother account.","operationId":"user_verification","responses":{"200":{"description":"The verification","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"401":{"description":"Missing or invalid bearer token"},"502":{"description":"GitHub did not answer"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["user"],"summary":"Verify the caller.","description":"Runs the check `GET` describes and records the account verified, once,\ncompleting each of its pending verify requests. Verifying an account\nalready verified answers it as it is.","operationId":"user_verify","responses":{"200":{"description":"The account, verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verification"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"The GitHub verification check fails"},"409":{"description":"The GitHub account verified another account"},"502":{"description":"GitHub did not answer"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/connections":{"get":{"tags":["user"],"summary":"List the providers the caller signs in with.","description":"A second provider is added by running the link flow for it —\n`GET /auth/google/link` or `GET /auth/github/link` — with this token.","operationId":"list_connections","responses":{"200":{"description":"Login connections, oldest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Connection"}}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/connections/{provider}":{"delete":{"tags":["user"],"summary":"Detach a provider from the caller's account.","description":"Every other session is revoked, since one opened through this provider\nwould otherwise outlive it. The last remaining connection cannot be\nremoved — connect another provider first.","operationId":"unlink_connection","parameters":[{"name":"provider","in":"path","description":"`google` or `github`","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Detached"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"That provider is not connected"},"409":{"description":"The only connection left"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/earnings":{"get":{"tags":["user"],"summary":"What the caller's priced tools earned.","description":"A UTC calendar month each, newest first: the calls charged, their prices,\nthe platform's cut of them, the compute every priced call used at the\npublished rates, and what is left; each by service and tool. Beside them,\nwhether the account has a Stripe Connect account and can receive payouts,\nwhat closed months owe it, a month below zero counted as zero, and its\npayouts, newest first. Payout accounts are US only.","operationId":"user_earnings","responses":{"200":{"description":"The caller's earnings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Earnings"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"A key bound to another account"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/earnings/connect":{"post":{"tags":["user"],"summary":"Open Stripe's onboarding for the caller's payout account.","description":"Creates the caller's Stripe Express account the first time, a US one that\nreceives transfers, and answers a link to Stripe's hosted onboarding,\nwhich returns to the Earnings page. An unfinished onboarding asks for a\nfresh link.","operationId":"user_connect","responses":{"200":{"description":"Onboarding URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeLink"}}}},"401":{"description":"Missing or invalid bearer token"},"501":{"description":"Payouts are not offered"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/earnings/dashboard":{"post":{"tags":["user"],"summary":"Open the caller's payout account's Stripe dashboard.","description":"A login link to the Express dashboard, for bank details, payouts and tax\nforms.","operationId":"user_dashboard","responses":{"200":{"description":"Login URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeLink"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No payout account"},"501":{"description":"Payouts are not offered"},"502":{"description":"Stripe API error"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/feedback":{"post":{"tags":["user"],"summary":"Send feedback about the app.","description":"Reaches staff and nobody else — it is not published, not visible to the\nsender's org, and carries no reply. A session only: this is a person\nspeaking, and an API key is not one.","operationId":"send_feedback","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackRequest"}}},"required":true},"responses":{"204":{"description":"Recorded"},"400":{"description":"Empty message, or one longer than the accepted maximum"},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/invites":{"get":{"tags":["user"],"summary":"Accounts the caller has been invited to but not yet joined.","description":"Matched on the caller's verified email. This is how someone who already had\nan account learns they were invited — a first login takes its invitations\nautomatically, but an existing user is never joined to an org without\nasking.","operationId":"my_invites","responses":{"200":{"description":"Live invitations addressed to the caller","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Invite"}}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/invites/{token}/accept":{"post":{"tags":["user"],"summary":"Accept an invitation and join the org.","description":"The token alone is not enough: the caller's verified email must equal the\ninvited address, so a leaked link admits nobody. Spent once — the\ninvitation is deleted in the same transaction that adds the member.","operationId":"accept_invite","parameters":[{"name":"token","in":"path","description":"Invitation token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Joined; the new membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No live invitation matches that token and the caller's address"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/keys":{"get":{"tags":["user"],"summary":"List the caller's own keys, active and revoked.","description":"Each with what it spent on tool prices today, UTC, the other accounts'\npriced services it may call and its pending grant request.","operationId":"list_user_keys","responses":{"200":{"description":"The caller's keys, newest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Key"}}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["user"],"summary":"Mint an API key on the caller's own account.","operationId":"create_user_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}},"required":true},"responses":{"200":{"description":"New key + raw token (shown once)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"400":{"description":"A name outside 1–100 characters or a budget below zero"},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/keys/{key_id}":{"delete":{"tags":["user"],"summary":"Revoke one of the caller's own keys.","operationId":"revoke_user_key","parameters":[{"name":"key_id","in":"path","description":"Key id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No active key with that id"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"patch":{"tags":["user"],"summary":"Change one of the caller's own keys.","description":"Apply budget, scope and service access atomically. Omitted fields stay unchanged.","operationId":"update_user_key","parameters":[{"name":"key_id","in":"path","description":"Key id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKeyRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Key"}}}},"400":{"description":"A budget below zero"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No active key with that id"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/keys/{key_id}/services/{owner}/{name}":{"put":{"tags":["user"],"summary":"Let one of the caller's own keys call a priced service.","description":"Another account's public service, which the key may call from now on\nwithout a grant request. Granting one already granted changes nothing.","operationId":"grant_user_key","parameters":[{"name":"key_id","in":"path","description":"Key id","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"The service's account, by handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"The service's name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Granted"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No active key with that id, or no such public service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["user"],"summary":"Stop one of the caller's own keys calling a priced service.","operationId":"ungrant_user_key","parameters":[{"name":"key_id","in":"path","description":"Key id","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"The service's account, by handle or id","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"The service's name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No longer granted"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No active key with that id, or the key may not call that service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/orgs":{"get":{"tags":["user"],"summary":"List the authenticated user's orgs.","operationId":"list_orgs","responses":{"200":{"description":"User's orgs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Org"}}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/orgs/creation":{"get":{"tags":["user"],"summary":"Read organization creation eligibility and pending checkout.","operationId":"creation","responses":{"200":{"description":"Creation eligibility","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgCreation"}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/sessions":{"get":{"tags":["user"],"summary":"List the caller's active sessions.","operationId":"list_sessions","responses":{"200":{"description":"Active sessions, newest first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Session"}}}}},"401":{"description":"Missing or invalid bearer token"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/user/sessions/{id}":{"delete":{"tags":["user"],"summary":"Revoke one of the caller's sessions.","description":"The revoked session's JWT becomes invalid immediately.","operationId":"revoke_session","parameters":[{"name":"id","in":"path","description":"Session id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"No active session with that id"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/users/{user}":{"get":{"tags":["users"],"summary":"One person's profile. Requires a session.","description":"Takes a handle or an id, and answers only for a person — an org reached here\nis `404`, the way a person reached under `/orgs/{org}` is, so no account has\ntwo URLs.\n\nA tombstoned account answers `410`: its id is never reissued, so the\ntruthful answer is that it existed and stopped.","operationId":"get_user","parameters":[{"name":"user","in":"path","description":"Account handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicAccount"}}}},"401":{"description":"Missing or invalid session"},"403":{"description":"An API key cannot read account profiles"},"404":{"description":"No such person"},"410":{"description":"This account was deleted"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/users/{user}/billing/usage":{"get":{"tags":["users"],"summary":"What a person used of their plan this period.","description":"What the plan includes over the billing period, what the person's services\nused of it, as last pushed by their nodes, the credit drawn, the warnings\nthey were given, and what they paid other accounts' tools' prices.","operationId":"user_usage","parameters":[{"name":"user","in":"path","description":"Person's handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The current period","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Period"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not that person, or a key bound to another account"},"404":{"description":"No such person"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/users/{user}/calls":{"get":{"tags":["users"],"summary":"A person's calls.","description":"Each run of the person's services retained for one year, newest first,\n`limit` a page: as a service's calls are, each also naming its service, as\nlast pulled from the nodes running them every 30 seconds. `Link` names the\n`next` page, the calls below the last one's `id` as `before`, while there\nmay be more.","operationId":"user_calls","parameters":[{"name":"user","in":"path","description":"Person's handle or id","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Only calls of this service","required":false,"schema":{"type":"string"}},{"name":"project","in":"query","description":"Only calls of the services deployed in this project","required":false,"schema":{"type":"string"}},{"name":"tool","in":"query","description":"Only calls of this tool","required":false,"schema":{"type":"string"}},{"name":"event","in":"query","description":"Only calls that emitted a log carrying this topic","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","description":"Only calls that emitted a log whose data or a topic holds this text, in either case","required":false,"schema":{"type":"string"}},{"name":"outcome","in":"query","description":"Only calls that ended so: `done`, `failed`, `denied` or `refused`","required":false,"schema":{"type":"string"}},{"name":"since","in":"query","description":"Only calls begun at or after this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"until","in":"query","description":"Only calls begun before this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"before","in":"query","description":"Only calls below the call of this id, newest first","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"limit","in":"query","description":"At most this many, up to 1000; 100 by default","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"The calls","headers":{"Link":{"schema":{"type":"string"},"description":"The `next` page, relative to the request"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AccountCall"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not that person, or a key bound to another account"},"404":{"description":"No such person"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/users/{user}/calls/stats":{"get":{"tags":["users"],"summary":"A person's calls, counted.","description":"What the calls of its services on the page the query asks for count to,\nthe same filters as its calls take but `before` and `limit`: by `bucket`\nmilliseconds of their start, as many as cut the range into at most 60, and\nby each service, tool and outcome, every filter but that one's applied.\nThe range is the last 30 days through now without `since` and `until`.\n`synced` is when the calls counted were last pulled.","operationId":"user_call_stats","parameters":[{"name":"user","in":"path","description":"Person's handle or id","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Only calls of this service","required":false,"schema":{"type":"string"}},{"name":"project","in":"query","description":"Only calls of the services deployed in this project","required":false,"schema":{"type":"string"}},{"name":"tool","in":"query","description":"Only calls of this tool","required":false,"schema":{"type":"string"}},{"name":"event","in":"query","description":"Only calls that emitted a log carrying this topic","required":false,"schema":{"type":"string"}},{"name":"q","in":"query","description":"Only calls that emitted a log whose data or a topic holds this text, in either case","required":false,"schema":{"type":"string"}},{"name":"outcome","in":"query","description":"Only calls that ended so: `done`, `failed`, `denied` or `refused`","required":false,"schema":{"type":"string"}},{"name":"since","in":"query","description":"Only calls begun at or after this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"until","in":"query","description":"Only calls begun before this, in epoch milliseconds","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"The counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Counted"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not that person, or a key bound to another account"},"404":{"description":"No such person"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/users/{user}/memory":{"get":{"tags":["users"],"summary":"The memory a person's services hold.","description":"Accounted bytes of their services' retained code and bytes of linear\nmemory their calls running now hold, summed over the nodes running them,\nbeside their plan's limit. Idle cached code is reclaimed first; active calls\ncan still occupy the allowance. Growth past it fails, and an image larger\nthan the allowance is refused.","operationId":"user_memory","parameters":[{"name":"user","in":"path","description":"Person's handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"What their services hold now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Memory"}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not that person, or a key bound to another account"},"404":{"description":"No such person"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/users/{user}/services":{"get":{"tags":["users"],"summary":"List a person's services.","description":"Each service the caller sees, the public ones and the private ones too for\nthe person: its IDL as `GET /services/{owner}/{name}/idl` answers it,\n`private`, and `served` as `GET /services/{owner}/{name}` answers it.","operationId":"user_services","parameters":[{"name":"user","in":"path","description":"Person's handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Each service","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}},"404":{"description":"No such person"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/users/{user}/services/deploys":{"post":{"tags":["users"],"summary":"Deploy a person's services together.","description":"As `POST /orgs/{org}/services/deploys` deploys an org's.","operationId":"user_deploy","parameters":[{"name":"user","in":"path","description":"Person's handle or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploySetRequest"}}},"required":true},"responses":{"200":{"description":"Each service's deployed version or failure, by name","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"A bad name, or one service's image, seed or prices refused"},"401":{"description":"Missing or invalid bearer token"},"402":{"description":"The person holds no paid plan and is unverified on Hobby, or one service sets prices with no payout account that can receive payouts"},"403":{"description":"Not that person, or a key bound to another account"},"404":{"description":"No such person"},"409":{"description":"One service's deploy breaks what callers used in the last 30 days, undoes a period its owners set, names a seed for a service with a database, names a service in another project, or reserves past the plan's storage"},"422":{"description":"One service needs a syscall this host does not serve, or its `size` is refused"},"502":{"description":"A registry, the upload bucket or a node did not serve an image"},"503":{"description":"The fleet has no room for a service"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/users/{user}/services/disk":{"get":{"tags":["users"],"summary":"What a person's services hold on disk.","description":"Each placed service's database: the bytes it reserves on its node and the\nbytes it keeps, as last sampled.","operationId":"user_services_disk","parameters":[{"name":"user","in":"path","description":"Person's handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Each service's disk, by name","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Disk"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not that person, or a key bound to another account"},"404":{"description":"No such person"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/users/{user}/services/usage":{"get":{"tags":["users"],"summary":"What a person's services used.","description":"Each service's calls, failures, resources and cost over the last 30 days, a\nday each, oldest first, as last pushed by the nodes running it, each minute.","operationId":"user_services_usage","parameters":[{"name":"user","in":"path","description":"Person's handle or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Each service's days, by name","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/CostedDay"}},"propertyNames":{"type":"string"}}}}},"401":{"description":"Missing or invalid bearer token"},"403":{"description":"Not that person, or a key bound to another account"},"404":{"description":"No such person"},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer":[]}]}},"/users/{user}/templates":{"get":{"tags":["users"],"operationId":"user_templates","parameters":[{"name":"user","in":"path","required":true,"schema":{"type":"string"}},{"name":"all","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Published templates, or all templates for an authorized owner with all=true","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"components":{"schemas":{"Access":{"type":"object","description":"What a grant request asks for one API key, beside what the key holds now.","required":["label","hint","services","current","spent"],"properties":{"budget":{"type":["integer","null"],"format":"int64","description":"The daily budget it asks for, in USD micros."},"current":{"type":"integer","format":"int64","description":"Its daily budget now, in USD micros."},"hint":{"type":"string"},"label":{"type":"string","description":"The key's label."},"services":{"type":"array","items":{"$ref":"#/components/schemas/KeyService"},"description":"The priced services it asks to call."},"spent":{"type":"integer","format":"int64","description":"What it spent on tool prices today, UTC, in USD micros."}}},"AccountCall":{"allOf":[{"$ref":"#/components/schemas/Costed"},{"type":"object","required":["service"],"properties":{"service":{"type":"string","description":"The service's name in the account."}}}],"description":"A call of one of an account's services, with what its meter costs."},"AccountOverview":{"allOf":[{"$ref":"#/components/schemas/Metrics"},{"type":"object","required":["profile","services","templates"],"properties":{"profile":{"$ref":"#/components/schemas/PublicAccount"},"services":{"type":"array","items":{"type":"object"}},"templates":{"type":"array","items":{"type":"object"}}}}]},"AddMemberRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string"},"role":{"$ref":"#/components/schemas/Role"}}},"AgentLoginRequest":{"type":"object","description":"Ask for a dedicated agent key at `POST /requests/login`.","required":["client_name"],"properties":{"client_name":{"type":"string"}}},"Alerts":{"type":"object","description":"The alerts an account's owners can turn off. Running out of credit and\nreaching a share of what the plan includes always email them.","required":["failures"],"properties":{"failures":{"type":"boolean","description":"Whether a service starting to fail emails them: its first failed run,\nthen none until one of its runs is done again."}}},"ApiError":{"type":"object","description":"Structured envelope for typed conditions the client must branch on (e.g.\n`orgs_closed`). Distinguished from\n[`ErrorResponse`] by the nested object: clients switch on `error.code`, not\non the HTTP status, when surfacing UX.","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/ApiErrorBody"}}},"ApiErrorBody":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable identifier the client matches on. Snake-case, never renamed."},"explain":{"type":["string","null"],"description":"The error code explaining it, as [`ErrorResponse::explain`]."},"message":{"type":"string","description":"Human-readable explanation. Safe to display; never leaks internals."},"reset_at":{"type":["integer","null"],"format":"int64","description":"Unix timestamp (seconds, UTC) when the condition self-resolves. Omitted\nwhen the condition is not time-bounded — funding arrives on purchase,\nnot on a clock."}}},"App":{"type":"object","description":"An app: the origins a browser may call from, the identity providers whose\ntokens name its users, and the services it may call.","required":["id","owner_id","name","origins","issuers","services","anonymous","created_at"],"properties":{"anonymous":{"type":"boolean","description":"Calls with no token reach the services' `access = \"anonymous\"` tools."},"created_at":{"type":"integer","format":"int64"},"id":{"type":"string"},"issuers":{"type":"array","items":{"$ref":"#/components/schemas/Issuer"}},"name":{"type":"string"},"origins":{"type":"array","items":{"type":"string"},"description":"`scheme://host[:port]`, as a browser sends `Origin`, or [`ANY_ORIGIN`]."},"owner_id":{"type":"string"},"services":{"type":"array","items":{"type":"string"},"description":"Services it may call, as `{owner}/{name}`, the owner by its handle, or its\nid when it has none."}}},"AppRequest":{"type":"object","description":"What an app is created or replaced with.","required":["name","origins","services"],"properties":{"anonymous":{"type":"boolean"},"issuers":{"type":"array","items":{"$ref":"#/components/schemas/Issuer"}},"name":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"services":{"type":"array","items":{"type":"string"},"description":"Services it may call, as `{owner}/{name}`, the owner by handle or id."}}},"ApproveRequest":{"type":"object","description":"Settings submitted when approving a deployment or an agent connection.","properties":{"authorization":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CreateKeyRequest"}]},"auto_upgrade":{"type":"object","additionalProperties":{"type":"boolean"},"propertyNames":{"type":"string"}},"secrets":{"type":"object","description":"Each secret's value, by service, then by name.","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"string"}}}},"AskedCredential":{"type":"object","description":"A credential a secret request asks for, as its service declared it when\nthe request was made.","required":["id","secrets"],"properties":{"copy":{"type":"array","items":{"$ref":"#/components/schemas/CopyValue"},"description":"What the person enters at the provider, from the request's `copy`."},"guide":{"type":"string","description":"How to get its secrets, in Markdown."},"hosts":{"type":"array","items":{"type":"string"},"description":"Manifest destinations; provisioning cannot change them."},"id":{"type":"string"},"saved":{"type":"boolean","description":"Set through this request. The request completes once every one is."},"secret_id":{"type":["string","null"]},"secrets":{"type":"array","items":{"$ref":"#/components/schemas/AskedSecret"}},"title":{"type":"string"}}},"AskedSecret":{"type":"object","description":"A secret a request asks for.","required":["name","masked","set"],"properties":{"label":{"type":"string","description":"What the provider calls it; the name when empty."},"masked":{"type":"boolean","description":"Whether the entry field hides the value while it is typed."},"name":{"type":"string"},"pattern":{"type":["string","null"],"description":"A regular expression a value must match."},"set":{"type":"boolean"}}},"AuthMe":{"allOf":[{"$ref":"#/components/schemas/User"},{"type":"object","required":["plan","orgs"],"properties":{"orgs":{"type":"array","items":{"$ref":"#/components/schemas/Org"}},"plan":{"type":"string","description":"Active plan slug, as `GET /meta/plans` names it: the subscription's when\none is live, the granted rung otherwise."},"subscription":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Subscription","description":"The account's latest subscription regardless of status, read the same\nway as an org's: `past_due` means access is already paused, `canceled`\nand `unpaid` mean it ended. `plan` is the entitlement."}]}}}],"description":"The caller's own account, in full, and the orgs they belong to.\n\nA person's account is not an org, so this is the only place it is answered:\n`/orgs/{org}` resolves orgs and `404`s a person. Everything an org gets from\n`GET /orgs/{org}` is here for the account the token names — what funds it —\nso a client builds its account switcher from this one response and never\nreconciles two shapes."},"AvatarResponse":{"type":"object","description":"Where an uploaded picture landed. The same value `avatar` now holds, so a\nclient can render it without re-reading the account.","required":["avatar"],"properties":{"avatar":{"type":"string"}}},"Billing":{"type":"object","description":"A service's billing in one UTC calendar month.","required":["month","days","resources","owed_micros"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/CostedDay"},"description":"Each day of the month it used anything, oldest first."},"month":{"type":"string","description":"The month, `YYYY-MM`."},"owed_micros":{"type":"integer","format":"int64","description":"What its owner owes past what its credit covered, in USD micros, over\nevery period: drawn once the owner's credit covers it."},"resources":{"type":"array","items":{"$ref":"#/components/schemas/Resource"},"description":"Each charged resource over the month."},"since":{"type":["integer","null"],"format":"int32","description":"Its first metered day, counted from the Unix epoch; `null` before the\nfirst read."},"updated_at":{"type":["integer","null"],"format":"int64","description":"When its meters were last read, in epoch seconds; `null` before the\nfirst read. Each day's `cost_micros` is as of then."}}},"Bucket":{"type":"object","description":"The calls begun in one bucket of time, by how they ended.","required":["at","outcomes"],"properties":{"at":{"type":"integer","format":"int64","description":"Its start, in epoch milliseconds.","minimum":0},"outcomes":{"type":"object","additionalProperties":{"type":"integer","format":"int64","minimum":0},"propertyNames":{"type":"string","description":"How a use ended.","enum":["done","failed","denied","refused"]}}}},"Budget":{"type":"object","description":"The most one invocation may use: CPU time in microseconds, nested calls\nexcluded, rows read, rows written, and bytes of linear memory.","required":["cpu","read","written","memory"],"properties":{"cpu":{"type":"integer","format":"int64","minimum":0},"memory":{"type":"integer","format":"int64","description":"Held from the invocation's start to its return, and reserved from the\nhost's memory for that long.","minimum":0},"read":{"type":"integer","format":"int64","minimum":0},"written":{"type":"integer","format":"int64","minimum":0}}},"Call":{"type":"object","description":"One run of a service: a call from outside or a wake.","required":["id","at","tool","source","caller","outcome","ms","logs"],"properties":{"at":{"type":"integer","format":"int64","description":"When it began, in epoch milliseconds.","minimum":0},"caller":{"type":"string","description":"As [`Usage::caller`] names it."},"id":{"type":"integer","format":"int64","description":"Its position among the service's calls; newer calls have larger ids.","minimum":0},"logs":{"type":"integer","format":"int64","description":"How many logs it emitted.","minimum":0},"meter":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Meter","description":"What it used, summed over every service it reached. `None` for a call\nthe host refused."}]},"ms":{"type":"integer","format":"int64","description":"How long it ran, in milliseconds.","minimum":0},"outcome":{"$ref":"#/components/schemas/Outcome"},"source":{"$ref":"#/components/schemas/Source"},"tool":{"type":"string"}}},"CallStats":{"type":"object","description":"What a page of calls matches, counted: by time and by what it can be\nnarrowed to.","required":["bucket","buckets","tools","outcomes","services"],"properties":{"bucket":{"type":"integer","format":"int64","description":"Each bucket's length, in milliseconds.","minimum":0},"buckets":{"type":"array","items":{"$ref":"#/components/schemas/Bucket"},"description":"Each bucket with a call, oldest first."},"outcomes":{"type":"object","description":"The calls that ended each way, every filter but `outcome` applied.","additionalProperties":{"type":"integer","format":"int64","minimum":0},"propertyNames":{"type":"string","description":"How a use ended.","enum":["done","failed","denied","refused"]}},"services":{"type":"object","description":"The calls of each service, every filter but `service` applied; empty\nfor one service's calls.","additionalProperties":{"type":"integer","format":"int64","minimum":0},"propertyNames":{"type":"string"}},"tools":{"type":"object","description":"The calls of each tool, every filter but `tool` applied.","additionalProperties":{"type":"integer","format":"int64","minimum":0},"propertyNames":{"type":"string"}}}},"CategoryJobs":{"type":"object","description":"A category of `GET /catalog`: its platforms, each with its jobs.","required":["id","title","platforms"],"properties":{"id":{"type":"string"},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/PlatformJobs"}},"title":{"type":"string"}}},"Client":{"type":"string","description":"Which front-end surface started the sign-in: where the callback redirects,\nand what the session it mints reports as its `client`.","enum":["web","terminal"]},"Connection":{"type":"object","description":"One way the caller signs in — a provider account attached to this one.\n\nKeyed on the provider's own subject, which is stable across a rename there;\n`email` is what that provider reported when the connection was made, and is\ncarried for display.","required":["provider","created_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"email":{"type":["string","null"],"description":"Null when the provider shared no address."},"provider":{"type":"string","description":"`google`, `github`, or `email` for a code emailed to the address."}}},"CopyValue":{"type":"object","description":"A value the person enters at the provider, beside its label there.","required":["label","value"],"properties":{"label":{"type":"string"},"value":{"type":"string"}}},"Costed":{"allOf":[{"$ref":"#/components/schemas/Call"},{"type":"object","properties":{"cost_micros_decimal":{"type":["string","null"],"description":"What the call's meter costs at the fleet's rates, exactly, as a decimal\nof USD micros. Its day's storage is charged with the day. `None` for a\ncall the host refused."}}}],"description":"A call, with what its meter costs its service's owner."},"CostedDay":{"allOf":[{"$ref":"#/components/schemas/MeteredDay"},{"type":"object","required":["cost_micros"],"properties":{"cost_micros":{"type":"integer","format":"int64","description":"What the day's meters cost, in USD micros."}}}],"description":"One day of a service's meters, with what it cost."},"Count":{"type":"object","description":"One of a [`Live`]'s counts.","required":["total","per_second"],"properties":{"per_second":{"type":"number","format":"double","description":"Per second over the UTC day so far."},"total":{"type":"integer","format":"int64","description":"Since its first deploy.","minimum":0}}},"Counted":{"allOf":[{"$ref":"#/components/schemas/CallStats"},{"type":"object","properties":{"synced":{"type":["integer","null"],"format":"int64","minimum":0}}}]},"CreateKeyRequest":{"type":"object","required":["label"],"properties":{"budget":{"type":["integer","null"],"format":"int64","description":"Its daily budget, in USD micros; [`BUDGET`] when none is given."},"expires_at":{"type":["integer","null"],"format":"int64"},"label":{"type":"string"},"scope":{"type":"array","items":{"$ref":"#/components/schemas/Scope"}}}},"CreateKeyResponse":{"type":"object","required":["key","token"],"properties":{"key":{"$ref":"#/components/schemas/Key"},"token":{"type":"string"}}},"CreateOrgRequest":{"type":"object","required":["name","handle"],"properties":{"client":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Client","description":"Surface that will receive the post-checkout redirect. Required when\n`tier` is a paid plan; ignored otherwise."}]},"handle":{"type":"string","description":"URL handle, claimed with the org: 1–39 chars of `[a-z0-9-]`, not\nstarting or ending with `-`. One namespace covers people and orgs."},"name":{"type":"string"},"tier":{"type":["string","null"],"description":"Optional plan slug. When set to a paid plan, the response includes a\nStripe Checkout URL the frontend should redirect to. Omit and the org\nholds the granted rung every org starts on."}}},"CreateOrgResponse":{"allOf":[{"$ref":"#/components/schemas/Org"},{"type":"object","properties":{"checkout_url":{"type":["string","null"],"description":"Stripe Checkout URL when a paid tier was requested at creation.\nFrontend should navigate the user here to complete payment."}}}]},"CreateRequest":{"oneOf":[{"type":"object","description":"Pay for a purchase.","required":["account","purchase","kind"],"properties":{"account":{"type":"string"},"context":{"type":"string","description":"What it is for, in the asker's words, shown to the person."},"kind":{"type":"string","enum":["payment"]},"plan":{"type":["string","null"],"description":"The plan a `plan` purchase subscribes to."},"purchase":{"$ref":"#/components/schemas/Purchase"}}},{"type":"object","description":"Set secrets of one of the account's services: every credential its\nruntime declares with a secret unset, and each unset secret in no\ncredential, or the one `credential` names, set or not.","required":["account","service","kind"],"properties":{"account":{"type":"string"},"context":{"type":"string","description":"What it is for, in the asker's words, shown to the person."},"copy":{"type":"object","description":"The values its credentials' `copy` labels, by key; one fills\nevery credential declaring its key.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"credential":{"type":["string","null"]},"kind":{"type":"string","enum":["secret"]},"resource":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecretResourceSetup"}]},"service":{"type":"string"}}},{"type":"object","description":"Deploy the account's services together, by name, once a person\napproves; as `POST /orgs/{org}/services/deploys` deploys them.","required":["account","services","kind"],"properties":{"account":{"type":"string"},"context":{"type":"string","description":"One short sentence describing the change, at most 160 characters.\nShown to the person; keep setup instructions in credential guides."},"copy":{"type":"object","description":"Provider copy values, by service and key.","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"string"}},"kind":{"type":"string","enum":["deploy"]},"services":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/DeployRequest"},"propertyNames":{"type":"string"}}}},{"type":"object","description":"Verify the person `account` names on GitHub. It completes once they\nare verified, by its page or any other way.","required":["account","kind"],"properties":{"account":{"type":"string"},"context":{"type":"string","description":"What it is for, in the asker's words, shown to the person."},"kind":{"type":"string","enum":["verify"]}}},{"type":"object","description":"Let the key making the request call `services`, each as `owner/name`,\nor spend `budget` USD micros a UTC day, once an owner of its account\napproves.","required":["kind"],"properties":{"budget":{"type":["integer","null"],"format":"int64"},"context":{"type":"string","description":"What it is for, in the asker's words, shown to the person."},"kind":{"type":"string","enum":["grant"]},"services":{"type":"array","items":{"type":"string"}}}}],"description":"What to ask a person, at `POST /requests`, for the account `account` names\nby handle or id."},"CreateSecretResource":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}},"additionalProperties":false},"CreateTeamRequest":{"type":"object","required":["slug","name"],"properties":{"name":{"type":"string"},"slug":{"type":"string","description":"1–39 chars of `[a-z0-9-]`, not starting or ending with `-`."}}},"Credit":{"type":"object","description":"An account's credit, in USD micros.","required":["micros","refill_cap_micros","refill_micros"],"properties":{"micros":{"type":"integer","format":"int64","description":"Purchased credit, eligible for priced tools and paid-plan overage."},"recovery_until":{"type":["integer","null"],"format":"int64"},"refill_cap_micros":{"type":"integer","format":"int64","description":"The most refills may deposit in a UTC calendar month; `0` is off."},"refill_micros":{"type":"integer","format":"int64","description":"What one refill buys; `0` when never set."},"trial":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TrialCredit"}]}}},"CreditHistory":{"type":"object","description":"Where an account's credit came from and went.","required":["months","grants"],"properties":{"grants":{"type":"array","items":{"$ref":"#/components/schemas/Grant"},"description":"The purchases and refills still holding credit, soonest to expire\nfirst."},"months":{"type":"array","items":{"$ref":"#/components/schemas/CreditMonth"},"description":"A UTC calendar month each, newest first; only months credit moved in."},"trial_grants":{"type":"array","items":{"$ref":"#/components/schemas/Grant"}},"trial_months":{"type":"array","items":{"$ref":"#/components/schemas/CreditMonth"}}}},"CreditMonth":{"type":"object","description":"One month of [`CreditHistory`], in USD micros, each figure positive.","required":["month","added","overage","prices","expired","balance"],"properties":{"added":{"type":"integer","format":"int64","description":"Credit issued."},"balance":{"type":"integer","format":"int64","description":"The balance when the month ended, or now for the current month."},"expired":{"type":"integer","format":"int64"},"month":{"type":"string","description":"`YYYY-MM`."},"overage":{"type":"integer","format":"int64","description":"Metered execution."},"prices":{"type":"integer","format":"int64","description":"Other accounts' tools' prices, less what failed calls returned."}}},"CronJob":{"type":"object","description":"A cron tool: one its manifest marks `#[tool(cron)]`.","required":["tool","failures"],"properties":{"cron":{"type":["string","null"],"description":"Its expression, in UTC; `None` while it has none and is not called."},"due":{"type":["integer","null"],"format":"int64","description":"When it next runs, in epoch milliseconds; `None` while it has no\nexpression.","minimum":0},"failures":{"type":"integer","format":"int64","description":"Times it failed in a row.","minimum":0},"last":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Call","description":"Its last run, in the last 30 days."}]},"tool":{"type":"string"}}},"Crons":{"type":"object","description":"A service's cron tools.","required":["crons","held"],"properties":{"crons":{"type":"array","items":{"$ref":"#/components/schemas/CronJob"}},"held":{"type":"boolean","description":"Its scope is held: none runs until it is let go."}}},"DatabaseUsage":{"type":"object","description":"Committed SQLite allocation and the writer's enforced capacity, in bytes.","required":["used","limit","at"],"properties":{"at":{"type":"integer","format":"int64","description":"Epoch seconds when measured."},"limit":{"type":"integer","format":"int64","minimum":0},"used":{"type":"integer","format":"int64","minimum":0}}},"DeployOutcome":{"type":"string","description":"How a deploy ended.","enum":["live","replaced","refused","failed"]},"DeployRequest":{"type":"object","description":"What a service runs next: the image a registry reference names, or one\nuploaded through `POST /services/{owner}/{name}/image`, named by its digest,\n`sha256:` and its SHA-256 in hex.","required":["reference"],"properties":{"auto_upgrade":{"type":["boolean","null"]},"create":{"type":"boolean"},"force":{"type":"boolean","description":"Deploy even when it breaks a tool or event used in the last 30 days."},"prices":{"type":"object","description":"Each public tool's price a call, by name, in place of the prices the\nservice had: a deploy without them leaves it with none. Refused when\none names a tool that is not a public tool of the image.","additionalProperties":{"$ref":"#/components/schemas/Price"},"propertyNames":{"type":"string"}},"project":{"type":["string","null"],"description":"The project it is deployed in: the workspace it came from. Absent, it\nstays in the project it was in. Refused, unless `force`, when it is in\nanother project."},"public":{"type":["boolean","null"]},"publish_only":{"type":"boolean"},"reference":{"type":"string"},"release_notes":{"type":["string","null"]},"seed":{"type":["string","null"],"description":"The SHA-256, in hex, of a seed uploaded through\n`POST /services/{owner}/{name}/seed`: a SQLite file the service's\ndatabase starts as, held to the image's migrations. Refused when the\nservice has a database."},"size":{"type":["integer","null"],"format":"int64","description":"Bytes the service's database may hold, from\n[`MIN_DATABASE_SIZE`](berm_api::host::MIN_DATABASE_SIZE) to\n[`MAX_DATABASE_SIZE`](berm_api::host::MAX_DATABASE_SIZE). Absent, a\nservice keeps its reservation; a new deployment uses the image\ndefault, or [`DATABASE_SIZE`](berm_api::host::DATABASE_SIZE) for an\nimage built without one.","minimum":0},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TemplateSource"}]},"stopped":{"type":"boolean","description":"Install it stopped: it takes no calls and fires no wakes until\nstarted."},"template":{"type":["boolean","null"]},"vars":{"type":"object","description":"The value its copy holds for each var it names, by name; a var it\nleaves out keeps its value. Refused when one names a var its `[vars]`\ndoes not declare, or a value past 4096 bytes.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"DeploySetRequest":{"type":"object","description":"A project's services deployed together, each by its name in the account:\nevery one is checked before any switches, and one refused refuses them all.","required":["services"],"properties":{"partial":{"type":"boolean","description":"Keep successful services live when another fails."},"services":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/DeployRequest"},"propertyNames":{"type":"string"}}}},"Deployment":{"type":"object","description":"One deploy of a service, refused and failed ones included.","required":["id","name","outcome","reference","migrations","seeded","redeployable","by","at"],"properties":{"at":{"type":"integer","format":"int64","description":"When, in epoch seconds."},"by":{"type":"string","description":"Who deployed it, by handle, or by id when they have none."},"digest":{"type":["string","null"],"description":"`sha256:` and the hex SHA-256 of the image; none when the deploy ended\nbefore its reference was resolved."},"id":{"type":"integer","format":"int64"},"migrations":{"type":"array","items":{"type":"string"},"description":"The migrations it applied, a kit's as `{kit}/{name}`."},"name":{"type":"string","description":"The service it deployed, by its name in the account."},"node":{"type":["string","null"],"description":"The node it was placed on; none when it ended before placement."},"outcome":{"$ref":"#/components/schemas/DeployOutcome"},"project":{"type":["string","null"],"description":"The project it was deployed in."},"reason":{"type":["string","null"],"description":"Why it was refused or failed, as the deploy answered."},"redeployable":{"type":"boolean","description":"Its image can be deployed again: one from a registry, or an upload\nkept on the node the service is placed on now."},"reference":{"type":"string","description":"What it was deployed from: a registry reference, or `sha256:` and an\nupload's SHA-256."},"seeded":{"type":"boolean","description":"Its database started from a seed."},"version":{"type":["string","null"],"description":"The version it went live on; none for one that did not."}}},"DeploymentApproval":{"type":"object","required":["request","status","version","reference","at","expires_at"],"properties":{"at":{"type":"integer","format":"int64"},"expires_at":{"type":"integer","format":"int64"},"reference":{"type":"string"},"request":{"$ref":"#/components/schemas/RequestLink"},"status":{"$ref":"#/components/schemas/RequestStatus"},"version":{"type":"string"}}},"DeploymentStatus":{"type":"object","required":["approvals","deploys"],"properties":{"approvals":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentApproval"}},"deploys":{"type":"array","items":{"$ref":"#/components/schemas/Deployment"}}}},"DeviceAuthorization":{"type":"object","description":"A sign-in request a device made, at `POST /requests/login`: RFC 8628's\ndevice authorization response.","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","description":"What the device polls with. Never shown to the person."},"expires_in":{"type":"integer","format":"int64","description":"Seconds the codes last."},"interval":{"type":"integer","format":"int64","description":"Seconds to wait between polls.","minimum":0},"user_code":{"type":"string","description":"What the person enters at `verification_uri`, as `WDJB-MJHT`."},"verification_uri":{"type":"string"},"verification_uri_complete":{"type":"string","description":"The page that opens the request without typing its code."}}},"DeviceToken":{"type":"object","description":"The credential issued to the first poll after approval.","required":["token"],"properties":{"account":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PublicAccount","description":"The account an agent key acts for. Personal sessions omit it."}]},"token":{"type":"string"}}},"DeviceTokenRequest":{"type":"object","description":"A device's poll, at `POST /requests/login/token`.","required":["device_code"],"properties":{"device_code":{"type":"string"}}},"Discovery":{"type":"object","required":["entries","categories","page","limit","total"],"properties":{"categories":{"type":"array","items":{"$ref":"#/components/schemas/ExploreCategory"}},"entries":{"type":"array","items":{"$ref":"#/components/schemas/ExploreEntry"}},"limit":{"type":"integer","format":"int64"},"page":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"Disk":{"type":"object","description":"A placed service's database on its node's disk.","required":["reserved","stored"],"properties":{"database":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DatabaseUsage"}]},"reserved":{"type":"integer","format":"int64","description":"Bytes it reserves: its `size`.","minimum":0},"stored":{"type":"integer","format":"int64","description":"Bytes it keeps, as last sampled.","minimum":0}}},"Earned":{"type":"object","description":"What priced calls earned, in USD micros.","required":["calls","revenue","cut","compute","net"],"properties":{"calls":{"type":"integer","format":"int64","description":"Calls charged.","minimum":0},"compute":{"type":"integer","format":"int64","description":"What every priced call used, failed ones included, at the published\nrates."},"cut":{"type":"integer","format":"int64","description":"The platform's cut of `revenue`."},"net":{"type":"integer","format":"int64","description":"`revenue` less `cut` and `compute`; below zero when compute is larger."},"revenue":{"type":"integer","format":"int64","description":"Their prices, summed."}}},"EarnedMonth":{"allOf":[{"$ref":"#/components/schemas/Earned"},{"type":"object","required":["month","tools"],"properties":{"month":{"type":"string","description":"`YYYY-MM`."},"tools":{"type":"array","items":{"$ref":"#/components/schemas/EarnedTool"},"description":"By service then tool."}}}],"description":"One month of [`Earnings`]: the sum, and each tool's part of it."},"EarnedTool":{"allOf":[{"$ref":"#/components/schemas/Earned"},{"type":"object","required":["service","tool"],"properties":{"service":{"type":"string"},"tool":{"type":"string"}}}],"description":"One tool's part of an [`EarnedMonth`]."},"Earnings":{"type":"object","description":"What an account's priced tools earned, a UTC calendar month each, newest\nfirst, and what was paid out of it.","required":["months","connected","payouts_enabled","owed","payouts"],"properties":{"connected":{"type":"boolean","description":"Whether the account has a Stripe Connect account."},"months":{"type":"array","items":{"$ref":"#/components/schemas/EarnedMonth"}},"owed":{"type":"integer","format":"int64","description":"What closed months netted, each counted from `0`, less every payout\nand its fees, in USD micros."},"payouts":{"type":"array","items":{"$ref":"#/components/schemas/Payout"},"description":"Newest first."},"payouts_enabled":{"type":"boolean","description":"Whether Stripe lets that account receive payouts."}}},"ErrorResponse":{"type":"object","description":"Plain error envelope — `{\"error\": \"message\"}`.","required":["error"],"properties":{"error":{"type":"string"},"explain":{"type":["string","null"],"description":"The error code explaining it, as `E0001`: `crab explain E0001`, or\n`/docs/errors/E0001` on the web."},"request":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RequestLink","description":"The request a person completes to lift the refusal."}]}}},"Estimate":{"type":"object","description":"What a tool's runs that ended `done` in the last 30 days used, from the\ncall log: each run summed over every service it reached, and each measure's\nmedian and 99th percentile taken on its own.","required":["runs","typical","slow"],"properties":{"runs":{"type":"integer","format":"int64","description":"Runs measured.","minimum":0},"slow":{"$ref":"#/components/schemas/Measured","description":"Each measure's 99th percentile, which below [`Estimate::P99`] runs is\nits largest."},"typical":{"$ref":"#/components/schemas/Measured","description":"Each measure's median."}}},"Explanation":{"type":"object","description":"`GET /meta/errors/{code}`: what an error code means and what to do about\nit.","required":["code","text"],"properties":{"code":{"type":"string","description":"As `E0001`."},"text":{"type":"string","description":"Markdown: a summary line, then the rest."}}},"ExploreCategory":{"type":"object","required":["id","title"],"properties":{"id":{"type":"string"},"title":{"type":"string"}}},"ExploreEntry":{"type":"object","required":["owner","name","description","callable","tools","categories"],"properties":{"callable":{"type":"boolean"},"categories":{"type":"array","items":{"type":"string"},"uniqueItems":true},"description":{"type":"string"},"logo":{"type":["string","null"]},"name":{"type":"string"},"owner":{"type":"string"},"template":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ExploreTemplate"}]},"tools":{"type":"array","items":{"$ref":"#/components/schemas/ExploreTool"}}}},"ExploreTemplate":{"type":"object","required":["version","tools","credentials","secrets","required_secrets"],"properties":{"credentials":{"type":"array","items":{"type":"string"}},"required_secrets":{"type":"integer","minimum":0},"secrets":{"type":"integer","minimum":0},"tools":{"type":"array","items":{"type":"string"}},"version":{"type":"string"}}},"ExploreTool":{"type":"object","required":["name","description"],"properties":{"catalog":{"type":["string","null"]},"description":{"type":"string"},"name":{"type":"string"},"price":{"type":"integer","format":"int64"},"title":{"type":["string","null"]}}},"FeedbackRequest":{"type":"object","required":["body"],"properties":{"body":{"type":"string","description":"What the person wrote."},"version":{"type":["string","null"],"description":"The client build it was written from."}}},"Grant":{"type":"object","description":"One credit grant.","required":["id","remaining","created_at","expires_at"],"properties":{"created_at":{"type":"integer","format":"int64","description":"Unix seconds."},"expires_at":{"type":"integer","format":"int64","description":"Unix seconds."},"id":{"type":"integer","format":"int64"},"reference":{"type":["string","null"]},"remaining":{"type":"integer","format":"int64","description":"What is left of it, in USD micros."},"source":{"type":["string","null"]}}},"Held":{"type":"object","description":"The memory one service holds now.","required":["loaded","running"],"properties":{"loaded":{"type":"integer","format":"int64","description":"Accounted image and compiled-code bytes retained across its generations.\nZero when its code is cold; not process RSS.","minimum":0},"running":{"type":"integer","format":"int64","description":"Bytes of linear memory its invocations running now hold.","minimum":0}}},"Included":{"type":"object","description":"What a plan includes each billing period, summed over the account's\nservices.","properties":{"cpu":{"type":"integer","format":"int64","description":"CPU microseconds past each run's first\n[`INCLUDED_CPU`](crate::system::meta::INCLUDED_CPU).","default":0,"minimum":0},"held":{"type":"integer","format":"int64","description":"MiB-microseconds of memory budget the account's calls held, each from\nits start to its return, waiting included.","default":0,"minimum":0},"read":{"type":"integer","format":"int64","description":"Rows read.","default":0,"minimum":0},"runs":{"type":"integer","format":"int64","default":0,"minimum":0},"sent":{"type":"integer","format":"int64","description":"Bytes sent off the nodes: answers to outside callers and requests to\nother sites. Past it the account's services take no calls until the\nperiod ends; `0` is no cap.","default":0,"minimum":0},"stored":{"type":"integer","format":"int64","description":"Bytes the account's services reserve for their databases together. A\ndeploy that would reserve past it is refused.","default":0,"minimum":0},"written":{"type":"integer","format":"int64","description":"Rows written.","default":0,"minimum":0}}},"Invite":{"type":"object","description":"A pending invitation to join an org. Becomes a [`Member`] when the\ninvited address accepts.","required":["org_id","org_name","email","role","token","created_at","expires_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"email":{"type":"string"},"expires_at":{"type":"integer","format":"int64"},"org_id":{"type":"string"},"org_name":{"type":"string","description":"Org name, so a client listing the caller's own invitations can\nsay what they're being invited to without a second call."},"role":{"$ref":"#/components/schemas/Role"},"token":{"type":"string","description":"Unguessable acceptance credential. Cloud sends no mail, so the owner\ndelivers this themselves. It does not stand alone — accepting also\nrequires the caller's verified email to match `email`."}}},"InviteRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","description":"Address to invite. Matched against the verified email of whoever\naccepts, and against a new account's on first login."},"role":{"$ref":"#/components/schemas/Role"}}},"Invoice":{"type":"object","description":"One row of a customer's invoice history, a subset of the Stripe invoice\nobject. The document is Stripe's generated `invoice_pdf`.","required":["id","created","status","amount_paid","currency"],"properties":{"amount_paid":{"type":"integer","format":"int64","description":"Amount paid in the smallest currency unit (cents for USD)."},"created":{"type":"integer","format":"int64","description":"Unix epoch (seconds) the invoice was created."},"currency":{"type":"string"},"hosted_invoice_url":{"type":["string","null"],"description":"Stripe-hosted invoice page. `None` for drafts."},"id":{"type":"string"},"invoice_pdf":{"type":["string","null"],"description":"Direct PDF download link. `None` for drafts."},"number":{"type":["string","null"],"description":"Human-facing invoice number (e.g. `\"A1B2C3-0001\"`). `None` for drafts."},"status":{"$ref":"#/components/schemas/InvoiceStatus"}}},"InvoiceStatus":{"type":"string","description":"A Stripe invoice's status, as Stripe spells it.","enum":["draft","open","paid","uncollectible","void"]},"Issuer":{"type":"object","description":"An identity provider whose ID tokens an app's calls carry.","required":["issuer","audience"],"properties":{"audience":{"type":"string","description":"The token's `aud`."},"issuer":{"type":"string","description":"The token's `iss`. Its signing keys are read from its OpenID discovery\ndocument's `jwks_uri`."}}},"Job":{"type":"object","description":"One job: every tool whose `catalog` names it, most called first.","required":["id","title","providers"],"properties":{"id":{"type":"string","description":"The full catalog id, as `company.enrich`."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/Provider"}},"title":{"type":"string","description":"The most called provider's title, or its tool's name without one."}}},"Key":{"type":"object","required":["id","owner_id","created_by","label","hint","scope","created_at","budget"],"properties":{"budget":{"type":"integer","format":"int64","description":"What the key may spend on tool prices in a UTC day, in USD micros."},"created_at":{"type":"integer","format":"int64"},"created_by":{"type":"string"},"expires_at":{"type":["integer","null"],"format":"int64"},"hint":{"type":"string"},"id":{"type":"string"},"label":{"type":"string"},"owner_id":{"type":"string"},"request":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RequestLink","description":"Its pending grant request."}]},"revoked_at":{"type":["integer","null"],"format":"int64"},"scope":{"type":"array","items":{"$ref":"#/components/schemas/Scope"}},"services":{"type":"array","items":{"$ref":"#/components/schemas/KeyService"},"description":"The other accounts' priced services it may call."},"spent":{"type":"integer","format":"int64","description":"What it spent on tool prices today, UTC, in USD micros."},"used_at":{"type":["integer","null"],"format":"int64","description":"When it last authenticated a request, to the minute."}}},"KeyDefaults":{"type":"object","required":["scope","budget"],"properties":{"budget":{"type":"integer","format":"int64"},"scope":{"type":"array","items":{"$ref":"#/components/schemas/Scope"}}}},"KeyService":{"type":"object","description":"Another account's service, as a key's grant names it.","required":["service"],"properties":{"prices":{"type":"object","description":"Each priced tool's price a call, by tool.","additionalProperties":{"type":"integer","format":"int64","minimum":0},"propertyNames":{"type":"string"}},"service":{"type":"string","description":"As `owner/name`, under the account's handle, or its id when it has\nnone."}}},"Kind":{"type":"string","description":"Which kind of account: a person or a shared org.","enum":["user","org"]},"Limits":{"type":"object","description":"A tool's `budget` in its `crab.toml`: CPU time in microseconds, rows read,\nrows written, and memory in MiB. A key left out takes the host's.","properties":{"cpu":{"type":["integer","null"],"format":"int64","minimum":0},"memory":{"type":["integer","null"],"format":"int64","minimum":0},"read":{"type":["integer","null"],"format":"int64","minimum":0},"written":{"type":["integer","null"],"format":"int64","minimum":0}},"additionalProperties":false},"LinkResponse":{"type":"object","description":"Redirect URL handed back to a logged-in client that wants to link a\nprovider account to its current user.","required":["redirect_url"],"properties":{"redirect_url":{"type":"string","description":"Provider consent URL the FE should navigate the browser to."}}},"Live":{"type":"object","description":"What a service is using now.","required":["running","memory","stored","cpu","read","written","proxied","logged"],"properties":{"cpu":{"$ref":"#/components/schemas/Count","description":"CPU time spent, in microseconds."},"database":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DatabaseUsage"}]},"logged":{"$ref":"#/components/schemas/Count","description":"Bytes of the logs it emitted."},"memory":{"type":"integer","format":"int64","description":"Bytes of linear memory they hold.","minimum":0},"proxied":{"$ref":"#/components/schemas/Count","description":"Bytes sent and received through `berm.http.proxy`."},"read":{"$ref":"#/components/schemas/Count","description":"Rows read and written in its database and state."},"running":{"type":"integer","format":"int64","description":"Its invocations running now.","minimum":0},"stored":{"type":"integer","format":"int64","description":"Bytes it keeps: its database file, its write-ahead log, its state, its\nlogs kept, and its image and compiled code.","minimum":0},"written":{"$ref":"#/components/schemas/Count"}}},"LoginConfig":{"type":"object","required":["login_url"],"properties":{"login_url":{"type":"string"},"turnstile_site_key":{"type":["string","null"]}}},"Measured":{"type":"object","description":"One measure of a run: wall time in milliseconds, CPU time in microseconds,\nrows read and written, memory held in MiB-microseconds, and its cost at the\nfleet's rates as a decimal of USD micros.","required":["ms","cpu","read","written","cost_micros_decimal"],"properties":{"cost_micros_decimal":{"type":"string"},"cpu":{"type":"integer","format":"int64","minimum":0},"held":{"type":"integer","format":"int64","minimum":0},"ms":{"type":"integer","format":"int64","minimum":0},"read":{"type":"integer","format":"int64","minimum":0},"written":{"type":"integer","format":"int64","minimum":0}}},"Member":{"type":"object","description":"A membership, with the person holding it. The profile fields are the only\nway a client learns who `member_id` is: `GET /orgs/{member_id}` is member-gated, and nobody is a\nmember of someone else's account.","required":["org_id","user_id","role","created_at","name"],"properties":{"avatar":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64","description":"When they joined this org, not when their account was created."},"email":{"type":["string","null"],"description":"`None` only for a member that is itself an org; a person always has one."},"handle":{"type":["string","null"]},"name":{"type":"string"},"org_id":{"type":"string"},"role":{"$ref":"#/components/schemas/Role"},"user_id":{"type":"string"}}},"Memory":{"type":"object","description":"The memory a scope's services hold now, and the most they may.","required":["limit","loaded","running"],"properties":{"limit":{"type":"integer","format":"int64","description":"Bytes; `0` is no limit.","minimum":0},"loaded":{"type":"integer","format":"int64","description":"Accounted image and compiled-code bytes retained by cached or active\ngenerations, including calls finishing after removal. Not process RSS.","minimum":0},"running":{"type":"integer","format":"int64","description":"Bytes of linear memory its invocations running now hold.","minimum":0},"services":{"type":"object","description":"What each of its services holds, by its name within the scope.","additionalProperties":{"$ref":"#/components/schemas/Held"},"propertyNames":{"type":"string"}}}},"Meter":{"type":"object","description":"What a call used of one service: its runs, the chains it was the first link\nof; its invocations, the CPU time they spent in microseconds, nested calls\nexcluded, the largest linear memory one\nreached, in bytes, their budgets of memory held over their wall-clock time\nin MiB-microseconds, the rows they read and wrote, the CPU time their SQL\nstatements spent on the database's threads in microseconds, the bytes sent\nand received through the proxy, the bytes of the logs they emitted, and the\nbytes sent off the host.","required":["calls","cpu","memory","read","written","proxied"],"properties":{"calls":{"type":"integer","format":"int64","minimum":0},"cpu":{"type":"integer","format":"int64","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"held":{"type":"integer","format":"int64","minimum":0},"logged":{"type":"integer","format":"int64","minimum":0},"memory":{"type":"integer","format":"int64","minimum":0},"proxied":{"type":"integer","format":"int64","minimum":0},"read":{"type":"integer","format":"int64","minimum":0},"runs":{"type":"integer","format":"int64","minimum":0},"sent":{"type":"integer","format":"int64","minimum":0},"sql_cpu":{"type":"integer","format":"int64","minimum":0},"written":{"type":"integer","format":"int64","minimum":0}}},"Metered":{"type":"object","description":"One day of a service's meter, of one of its tools.","required":["day","calls","cpu","memory","read","written","proxied","stored"],"properties":{"calls":{"type":"integer","format":"int64","description":"Invocations of the service: from outside, from other services, and\nwakes.","minimum":0},"cpu":{"type":"integer","format":"int64","description":"CPU time those invocations spent, in microseconds.","minimum":0},"database":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DatabaseUsage"}]},"day":{"type":"integer","format":"int32","description":"Days since the Unix epoch."},"failed":{"type":"integer","format":"int64","description":"Of `calls`, those that trapped or failed, but not those the tool\nrefused through `berm.deny`.","minimum":0},"held":{"type":"integer","format":"int64","description":"Their budgets of memory, each held from its start to its return,\nwaiting included, in MiB-microseconds.","minimum":0},"logged":{"type":"integer","format":"int64","description":"Bytes of the logs those invocations emitted.","minimum":0},"memory":{"type":"integer","format":"int64","description":"The largest linear memory one of them reached, in bytes.","minimum":0},"proxied":{"type":"integer","format":"int64","description":"Bytes sent and received through `berm.http.proxy`.","minimum":0},"read":{"type":"integer","format":"int64","description":"Rows read and written in the service's database and state.","minimum":0},"runs":{"type":"integer","format":"int64","description":"Chains whose first link the service was: a call from outside, a wake\nor a Stripe event.","minimum":0},"sent":{"type":"integer","format":"int64","description":"Bytes sent off the host: the bodies of answers to outside callers, and\neach request `berm.http.fetch` and `berm.http.proxy` sent.","minimum":0},"sql_cpu":{"type":"integer","format":"int64","description":"CPU time the service's SQL statements spent on its database's threads,\nin microseconds; not part of `cpu`.","minimum":0},"stored":{"type":"integer","format":"int64","description":"Bytes the service kept when the day was sampled: its database file,\nits write-ahead log, its state, its logs kept, and its image and\ncompiled code.","minimum":0},"tool":{"type":"string","description":"The tool whose invocations these are. Empty for what the service\nholds itself, `stored`, and for a day summed over its tools."},"written":{"type":"integer","format":"int64","minimum":0}}},"MeteredDay":{"allOf":[{"$ref":"#/components/schemas/Metered"},{"type":"object","properties":{"overage":{"type":"integer","format":"int64","description":"The CPU microseconds each run spent in the service past the run's first\n[`INCLUDED_CPU`](crate::system::meta::INCLUDED_CPU), summed.","minimum":0}}}],"description":"One day of a service's meter, with what Cloud charges past each run's\nincluded CPU time."},"Metering":{"type":"object","description":"`GET /meta/rates`: what metering costs a service's owner.","required":["rates","included_cpu","max_log"],"properties":{"included_cpu":{"type":"integer","format":"int64","description":"CPU microseconds of each run `overage` does not count.","minimum":0},"max_log":{"type":"integer","description":"Bytes one log holds at most.","minimum":0},"rates":{"$ref":"#/components/schemas/Rates"}}},"Metrics":{"type":"object","properties":{"credit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Credit"}]},"disks":{"type":["object","null"],"additionalProperties":{"$ref":"#/components/schemas/Disk"},"propertyNames":{"type":"string"}},"earnings":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Earnings"}]},"memory":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Memory"}]},"period":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Period"}]},"usage":{"type":["object","null"],"additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/CostedDay"}},"propertyNames":{"type":"string"}}}},"NestedCall":{"type":"object","description":"One nested invocation on the host the run ran on.","required":["id","parent","service","tool","at","ms","outcome","cpu","read","written"],"properties":{"at":{"type":"integer","format":"int64","description":"When it began, in epoch milliseconds.","minimum":0},"cpu":{"type":"integer","format":"int64","description":"CPU microseconds it spent itself, the calls it made excluded.","minimum":0},"id":{"type":"integer","format":"int32","description":"Its number in the run, in the order the run's calls began; the run's\nfirst call is 0.","minimum":0},"ms":{"type":"integer","format":"int64","minimum":0},"outcome":{"$ref":"#/components/schemas/Outcome"},"parent":{"type":"integer","format":"int32","description":"The number of the call that made it.","minimum":0},"read":{"type":"integer","format":"int64","minimum":0},"service":{"type":"string","description":"The service's deployment address."},"tool":{"type":"string"},"written":{"type":"integer","format":"int64","minimum":0}}},"Next":{"type":"object","required":["tool","due"],"properties":{"due":{"type":"integer","format":"int64","minimum":0},"tool":{"type":"string"}}},"Org":{"type":"object","required":["id","type","name","role","created_at","updated_at"],"properties":{"avatar":{"type":["string","null"],"description":"Image URL for the switcher and any list that names this account. Set\nfrom the OAuth provider for a person and by `PATCH /orgs/{org}` for a\nshared org, so it is `None` until someone picks one."},"created_at":{"type":"integer","format":"int64"},"handle":{"type":["string","null"],"description":"URL handle, unique across every account — people and shared orgs share\none namespace, so `/<handle>` is never ambiguous.\n`None` until one is picked."},"id":{"type":"string"},"name":{"type":"string"},"role":{"$ref":"#/components/schemas/Role","description":"What the caller may do here."},"type":{"$ref":"#/components/schemas/Kind","description":"Whether this account is a person or a shared org. Mirrors GitHub's\n`\"type\": \"User\" | \"Organization\"`, and like theirs it is what a client\nbranches on to pick an avatar over an org glyph."},"updated_at":{"type":"integer","format":"int64"}}},"OrgCreation":{"type":"object","required":["hobby_available"],"properties":{"hobby_available":{"type":"boolean"},"pending":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PendingOrg"}]},"reserved_until":{"type":["integer","null"],"format":"int64"}}},"OrgPrivate":{"type":"object","description":"What membership buys: the org's plan and its timestamps. Absent for everyone else.","required":["role","updated_at","plan"],"properties":{"paused_until":{"type":["integer","null"],"format":"int64"},"plan":{"type":"string","description":"Active plan slug, as `GET /meta/plans` names it. Every account holds one:\na subscription buys its own, and the rung an account's kind is granted\nanswers for the rest. Being a member of a paying org does not upgrade\nyour own."},"role":{"$ref":"#/components/schemas/Role","description":"What the caller may do here. Present exactly when they are a member,\nsince that is when `private` is present at all."},"sponsor_id":{"type":["string","null"]},"subscription":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Subscription","description":"The account's latest subscription regardless of status, so a client\ncan branch on `status`: `past_due` → access is already paused (no\ngrace); show a \"payment failed, update card to restore\" banner.\n`canceled`/`unpaid` → the sub ended, prompt resubscribe. `plan` is the\nreal entitlement (the granted rung once non-`active`). `null` means never\nsubscribed."}]},"updated_at":{"type":"integer","format":"int64"}}},"OrgView":{"allOf":[{"$ref":"#/components/schemas/PublicAccount"},{"type":"object","properties":{"private":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OrgPrivate"}]}}}],"description":"One account, as much of it as the caller may see. `GET /orgs/{org}`.\n\nIdentity is always there. `private` is present exactly when the caller is a\nmember, so its absence is the answer to \"am I in this org\", and a client\nneeds no second call to find out."},"Origin":{"type":"object","description":"The public service of another account a service was deployed from: one\nrunning an image of the same registry repository.","required":["owner","name","reference","version"],"properties":{"name":{"type":"string"},"owner":{"type":"string","description":"Its owner, by handle, or by id when they have none."},"reference":{"type":"string","description":"The registry reference it runs now."},"version":{"type":"string","description":"The version it runs now."}}},"Outcome":{"type":"string","description":"How a use ended.","enum":["done","failed","denied","refused"]},"Owned":{"type":"object","required":["usage","held","tools"],"properties":{"deployed":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Deployment"}]},"held":{"type":"boolean"},"next":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Next"}]},"origin":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Origin"}]},"tools":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ToolCosted"},"propertyNames":{"type":"string"}},"usage":{"$ref":"#/components/schemas/Live"}}},"PayResponse":{"type":"object","description":"Where paying a request goes next.","properties":{"url":{"type":["string","null"],"description":"Stripe Checkout, or none when an active subscription moved onto the\nplan in place."}}},"PaymentMethod":{"type":"object","description":"The card a customer's subscription charges.\n\nRead to render \"Visa •••• 4242, expires 04/29\" beside the button that\nchanges it. `null` in place of this object is an account with nothing on\nfile.","required":["brand","last4","exp_month","exp_year"],"properties":{"brand":{"type":"string","description":"Card network, lowercase as Stripe spells it: `visa`, `mastercard`,\n`amex`, …"},"exp_month":{"type":"integer","format":"int64","description":"Expiry month, 1–12."},"exp_year":{"type":"integer","format":"int64"},"last4":{"type":"string","description":"Last four digits, the only part of the number that ever leaves Stripe."}}},"Payout":{"type":"object","description":"One transfer of earnings to the account's Stripe Connect account.","required":["month","amount","fees","status","created_at"],"properties":{"amount":{"type":"integer","format":"int64","description":"What was transferred, in USD micros."},"created_at":{"type":"integer","format":"int64","description":"Unix seconds."},"fees":{"type":"integer","format":"int64","description":"Connect's fees, taken from what was owed, in USD micros."},"month":{"type":"string","description":"`YYYY-MM`, the closed month it was made for."},"status":{"$ref":"#/components/schemas/PayoutStatus"}}},"PayoutStatus":{"type":"string","description":"Where a [`Payout`] stands.","enum":["pending","paid"]},"PendingOrg":{"type":"object","required":["id","name","handle","expires_at"],"properties":{"checkout_url":{"type":["string","null"]},"expires_at":{"type":"integer","format":"int64"},"handle":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"Period":{"type":"object","description":"An account's billing period: what its plan includes, what it used, and\nwhat it was warned of.","required":["plan","since","until","included","used","stored","warnings"],"properties":{"charge":{"type":"integer","format":"int64","description":"What its services used since `since` past the included amounts costs\nat the rates: what credit pays, in USD micros."},"costs":{"type":"object","description":"What `charge` is made of, by unit past its included amount, in USD\nmicros, each rounded down; a unit within it is left out.","additionalProperties":{"type":"integer","format":"int64"},"propertyNames":{"type":"string","description":"What a warning is about: a field of [`Included`], or `credit` when credit\nran out.","enum":["runs","cpu","read","written","held","stored","sent","credit"]}},"drawn":{"type":"integer","format":"int64","description":"Credit drawn since `since`, in USD micros."},"included":{"$ref":"#/components/schemas/Included"},"plan":{"type":"string","description":"The plan's slug: comped, else bought, else Hobby."},"since":{"type":"integer","format":"int32","description":"Days since the Unix epoch, `until` excluded."},"spent":{"type":"array","items":{"$ref":"#/components/schemas/Spent"},"description":"What the account paid other accounts' tools' prices since `since`, by\ntool, the most first."},"storage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StorageAllocation"}]},"stored":{"type":"integer","format":"int64","description":"Legacy storage aggregate; not database allocation.","minimum":0},"until":{"type":"integer","format":"int32"},"used":{"$ref":"#/components/schemas/Included","description":"In the units of `included`; `stored` includes database reservations, images and pending uploads."},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/Warning"},"description":"Each share of an included amount reached, and running out of credit."}}},"PlatformJobs":{"type":"object","description":"A platform and the jobs its services' tools do, most called first.","required":["id","jobs"],"properties":{"id":{"type":"string"},"jobs":{"type":"array","items":{"$ref":"#/components/schemas/Job"}}}},"PortalFlow":{"type":"string","description":"Which single action the portal opens on.\n\nOmitted, the portal opens on its home page and the customer navigates. Named,\nit opens on that one form with the rest of the portal hidden and returns as\nsoon as the action is done. These are the flows the deployment's portal\nconfiguration enables.","enum":["payment_method_update","subscription_cancel"]},"Price":{"type":"integer","format":"int64","description":"USD micros a call of a tool costs its caller, at least [`Price::MIN`].","minimum":0},"Provider":{"type":"object","description":"A service's tool that does a job.","required":["service","tool","description","calls"],"properties":{"calls":{"type":"integer","format":"int64","description":"Its calls over the last 30 days.","minimum":0},"description":{"type":"string"},"price":{"type":["integer","null"],"format":"int64","description":"What a call costs the caller, in USD micros; absent when it is free.","minimum":0},"service":{"type":"string","description":"`owner/name`, the owner by its handle, or its id when it has none."},"title":{"type":["string","null"]},"tool":{"type":"string"}}},"PublicAccount":{"type":"object","description":"Account profile fields, without billing or membership details.","required":["id","type","name","links","created_at"],"properties":{"avatar":{"type":["string","null"]},"bio":{"type":["string","null"],"description":"A line about the account, set by its owners."},"created_at":{"type":"integer","format":"int64"},"handle":{"type":["string","null"]},"id":{"type":"string"},"links":{"type":"array","items":{"type":"string"},"description":"`https://` URLs its owners list, in their order."},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/Kind"}}},"PublicPlan":{"type":"object","description":"A public plan catalog entry.","required":["slug","accounts","credit_micros","included","memory"],"properties":{"accounts":{"type":"array","items":{"$ref":"#/components/schemas/Kind"}},"credit_micros":{"type":"integer","format":"int64","minimum":0},"included":{"$ref":"#/components/schemas/Included","description":"What the plan includes each billing period."},"memory":{"type":"integer","format":"int64","description":"Bytes of memory the account's services may hold at once, their images\nand their calls running; `0` is no limit.","minimum":0},"price_micros":{"type":["integer","null"],"format":"int64","description":"Monthly gross price in microdollars — what the customer is charged.\n`null` is a plan that is not sold: a granted rung."},"slug":{"type":"string","description":"Identifier used in `POST /orgs/{org}/billing/checkout?plan=<slug>`."},"trial":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TrialOffer"}]}}},"Purchase":{"type":"string","description":"What a payment request buys.","enum":["plan","credit"]},"Rates":{"type":"object","description":"What an owner is charged for its services' meters, each in USD micros per\nbillion units. Cloud's `[fleet.rates]` config table, and what it serves.","properties":{"held":{"type":"integer","format":"int64","description":"MiB-microseconds of a call's memory budget held, waiting included.","default":12,"minimum":0},"overage":{"type":"integer","format":"int64","description":"CPU microseconds past each run's first [`INCLUDED_CPU`].","default":20000,"minimum":0},"proxied":{"type":["integer","null"],"format":"int64","description":"Bytes through `berm.http.proxy`; unset is free.","default":null,"minimum":0},"read":{"type":"integer","format":"int64","default":1000000,"minimum":0},"runs":{"type":"integer","format":"int64","default":150000000,"minimum":0},"written":{"type":"integer","format":"int64","default":1000000000,"minimum":0}}},"RedeployRequest":{"type":"object","description":"Deploy a past deploy's image again.","properties":{"force":{"type":"boolean","description":"Deploy even when it breaks a tool or event used in the last 30 days."}}},"RefillRequest":{"type":"object","description":"The body of `PUT …/billing/refill`.","required":["cap_micros"],"properties":{"amount_micros":{"type":"integer","format":"int64","description":"What one refill buys, $20 or more. Ignored when\n`cap_micros` is `0`."},"cap_micros":{"type":"integer","format":"int64","description":"The most refills may deposit in a UTC calendar month; `0` turns refill\noff."}}},"Request":{"type":"object","description":"A request, as the person who opens its code sees it.","required":["code","url","kind","status","context","created_at","expires_at"],"properties":{"access":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Access","description":"What a grant request asks for its key."}]},"account":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PublicAccount","description":"The account it is for; none for a sign-in until a person approves it."}]},"approved_at":{"type":["integer","null"],"format":"int64","description":"When a deploy was approved; absent before approval or for other kinds."},"asks":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/AskedCredential"}},"propertyNames":{"type":"string"}},"authorization":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CreateKeyRequest","description":"The dedicated key's settings, reviewed when authorizing a client."}]},"client":{"type":["string","null"],"description":"The registered client a sign-in is for, by its name; none for a\ndevice's."},"code":{"type":"string","description":"What a person types at `/pay`, `/secrets`, `/device`, `/deploy` or\n`/verify`, as `WDJB-MJHT`."},"context":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"credentials":{"type":"array","items":{"$ref":"#/components/schemas/AskedCredential"},"description":"What a secret request asks for, each set on its own. A secret in no\ncredential is one of its own, by the secret's name, with no title."},"deployed":{"type":"object","description":"Each service an approved deploy put live, by name."},"deploys":{"type":"object","description":"What a deploy request deploys, by service.","additionalProperties":{"$ref":"#/components/schemas/DeployRequest"},"propertyNames":{"type":"string"}},"expires_at":{"type":"integer","format":"int64"},"explain":{"type":["string","null"],"description":"The error code explaining `failure`, as `E0020`."},"failure":{"type":["string","null"],"description":"Why an approved deploy did not go live."},"key_id":{"type":["string","null"],"description":"The issued key, absent until the client exchanges its code."},"kind":{"$ref":"#/components/schemas/RequestKind"},"manifests":{"type":"object","description":"What each image a deploy request deploys says it is, by service, read\nfrom the image when it was asked."},"plan":{"type":["string","null"],"description":"The plan a `plan` purchase subscribes to."},"price_micros":{"type":["integer","null"],"format":"int64","description":"The plan's monthly price in microdollars; none for credit, whose\namount is chosen at checkout."},"purchase":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Purchase","description":"What a payment request buys."}]},"redirect":{"type":["string","null"],"description":"Where a client's sign-in sends the person back to once approved or\ndeclined, its code or error on it."},"results":{"type":"object"},"service":{"type":["string","null"],"description":"The service a secret request sets secrets of."},"status":{"$ref":"#/components/schemas/RequestStatus"},"unverified":{"type":"boolean","description":"The account is a person's on Hobby, not verified: a deploy request is\nrefused when approved until they verify."},"url":{"type":"string","description":"The page that opens it."}}},"RequestKind":{"type":"string","description":"What a request asks of the person.","enum":["payment","secret","login","deploy","verify","grant"]},"RequestLink":{"type":"object","description":"A request handed to a person: its code, as `WDJB-MJHT`, and the page that\nopens it.","required":["code","url"],"properties":{"code":{"type":"string"},"url":{"type":"string"}}},"RequestStatus":{"type":"string","description":"Where a request stands.","enum":["pending","deploying","completed","declined","expired"]},"Resource":{"type":"object","description":"One charged resource of a service over a month.","required":["resource","units","rate","cost_micros_decimal"],"properties":{"cost_micros_decimal":{"type":"string","description":"What the units cost at the rate, exactly, as a decimal of USD micros."},"rate":{"type":"integer","format":"int64","description":"USD micros per billion units.","minimum":0},"resource":{"type":"string","description":"As its rate is named in `GET /meta/rates`."},"units":{"type":"integer","format":"int64","minimum":0}}},"Role":{"type":"string","description":"What a member may do in an org. An owner administers it — members, teams,\nkeys, billing, and publishing; everything else is `member`.","enum":["owner","member"]},"Scope":{"type":"string","enum":["services:read","services:write","secrets:read","deployments:read","deployments:write","calls:read","logs:read","usage:read","billing:read","earnings:read","apps:read","apps:write","orgs:read","orgs:write","members:read","members:write","invites:read","invites:write","teams:read","teams:write","keys:read","alerts:read","alerts:write"]},"Secret":{"type":"object","description":"One of a service's secrets, by name. Its value is never read back.","required":["name","created_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"hosts":{"type":"array","items":{"type":"string"},"description":"The hosts its value is sent to, each named in full. A secret with none\nis never sent."},"name":{"type":"string"}}},"SecretResource":{"type":"object","required":["id","name","created_at","grants"],"properties":{"created_at":{"type":"integer","format":"int64"},"grants":{"type":"array","items":{"$ref":"#/components/schemas/SecretResourceGrant"}},"id":{"type":"string"},"name":{"type":"string"}}},"SecretResourceGrant":{"type":"object","required":["service","hosts"],"properties":{"hosts":{"type":"array","items":{"type":"string"}},"service":{"type":"string"}},"additionalProperties":false},"SecretResourceSetup":{"type":"object","required":["name","hosts"],"properties":{"hosts":{"type":"array","items":{"type":"string"}},"id":{"type":["string","null"]},"name":{"type":"string"}},"additionalProperties":false},"SecretValues":{"type":"object","description":"One credential's values by secret name, at `PUT /requests/{code}/secrets`.\nA secret already provisioned for these manifest destinations may be left out.","required":["values"],"properties":{"values":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"ServedDay":{"type":"object","description":"One day of [`Served`], counted as [`Metered`] counts it.","required":["day","runs","calls","failed"],"properties":{"calls":{"type":"integer","format":"int64","minimum":0},"day":{"type":"integer","format":"int32","description":"Days since the Unix epoch."},"failed":{"type":"integer","format":"int64","minimum":0},"runs":{"type":"integer","format":"int64","minimum":0}}},"ServiceContext":{"type":"object","required":["managed"],"properties":{"listing":{"type":["object","null"]},"managed":{"type":"boolean"},"private":{"type":["boolean","null"]},"template":{"type":["object","null"]}}},"ServiceOverview":{"type":"object","required":["terms"],"properties":{"owned":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Owned"}]},"runtime":{"type":["object","null"]},"terms":{"$ref":"#/components/schemas/Terms"},"upgrades":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UpgradePolicy"}]}}},"ServiceSchedule":{"type":"object","required":["terms","crons","wakes"],"properties":{"crons":{"$ref":"#/components/schemas/Crons"},"terms":{"$ref":"#/components/schemas/Terms"},"wakes":{"$ref":"#/components/schemas/Wakes"}}},"Session":{"type":"object","required":["id","user_id","client","ip","agent","created_at","expires_at"],"properties":{"agent":{"type":"string"},"client":{"$ref":"#/components/schemas/Client"},"created_at":{"type":"integer","format":"int64"},"expires_at":{"type":"integer","format":"int64","description":"Unix seconds when the session lapses *if left idle*. Every\nauthenticated request pushes it forward to `now + 7d`."},"id":{"type":"string"},"ip":{"type":"string"},"last_used_at":{"type":["integer","null"],"format":"int64","description":"Unix seconds of the most recent authenticated request, or null if the\nsession has not been used since creation. Drives the sliding\n`expires_at` and the \"last active\" display."},"revoked_at":{"type":["integer","null"],"format":"int64","description":"Unix seconds the session was explicitly revoked (logout / \"sign out\nthis device\"), or null if still live. A revoked session's token is\nrejected immediately, regardless of `expires_at`."},"user_id":{"type":"string"}}},"SetSecret":{"type":"object","description":"The body of `PUT …/secrets/{name}`.","required":["value"],"properties":{"value":{"type":"string"}},"additionalProperties":false},"Setting":{"type":"object","description":"One var of a service's `[vars]`, as its owners read it.","required":["name","description","default"],"properties":{"default":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"},"value":{"type":["string","null"],"description":"What this copy holds; `None` reads `default`."}}},"Source":{"type":"string","description":"Who used it.","enum":["service","account","app","anonymous","stripe","webhook"]},"Spent":{"type":"object","description":"What an account paid one tool's price.","required":["owner","service","tool","calls","micros"],"properties":{"calls":{"type":"integer","format":"int64","description":"Calls charged; a call is charged from its start and returned when it\nfails.","minimum":0},"micros":{"type":"integer","format":"int64","description":"In USD micros."},"owner":{"type":"string","description":"The service's owner, by handle, else by id."},"service":{"type":"string"},"tool":{"type":"string"}}},"StartBody":{"type":"object","properties":{"turnstile_token":{"type":["string","null"]}}},"Status":{"type":"object","required":["period","credit","memory"],"properties":{"credit":{"$ref":"#/components/schemas/Credit"},"memory":{"type":"object"},"period":{"$ref":"#/components/schemas/Period"}}},"StorageAllocation":{"type":"object","description":"Bytes allocated against the account's storage allowance.","required":["databases","objects"],"properties":{"databases":{"type":"integer","format":"int64","minimum":0},"objects":{"type":"integer","format":"int64","minimum":0}}},"StripeLink":{"type":"object","description":"A Stripe-hosted page to open.","required":["url"],"properties":{"url":{"type":"string"}}},"SubscribeResponse":{"type":"object","description":"A plan subscribed: the Checkout URL to pay at, or `None` when an active\nsubscription moved onto the plan in place.","properties":{"url":{"type":["string","null"]}}},"Subscription":{"type":"object","required":["status"],"properties":{"cancel_at":{"type":["integer","null"],"format":"int64","description":"When a cancelled subscription stops, or `null` while it renews.\n\nCancelling leaves `status` on `active` for the rest of the period already\npaid for, so this is what says whether the account is renewing or running\nout. Access is unchanged until it passes."},"current_period_end":{"type":["integer","null"],"format":"int64"},"next_plan":{"type":["string","null"],"description":"The plan slug it changes to at `current_period_end`, or `null` when no\nchange is scheduled."},"plan":{"type":["string","null"],"description":"The plan slug this subscription buys; `None` for a plan the deployment\nno longer sells."},"status":{"$ref":"#/components/schemas/SubscriptionStatus","description":"Stripe subscription status the client branches on: `active`/`trialing`\nentitle the paid plan, and `trialing` is held only by a trial started\nbefore trials were removed; `past_due` means a renewal failed and access is\npaused (no grace) — prompt the user to update their card; `canceled`/\n`unpaid` mean the subscription ended — prompt resubscribe."}}},"SubscriptionStatus":{"type":"string","description":"A Stripe subscription's status, as Stripe spells it.","enum":["incomplete","incomplete_expired","trialing","active","past_due","canceled","unpaid","paused"]},"Team":{"type":"object","description":"A group of an org's members that gates access. Membership overlaps: a\nperson can hold several teams.","required":["org_id","slug","name","member_count","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"member_count":{"type":"integer","format":"int64","description":"How many of the org's members hold this team."},"name":{"type":"string"},"org_id":{"type":"string"},"slug":{"type":"string","description":"URL segment, unique within the org: 1–39 chars of `[a-z0-9-]`."},"updated_at":{"type":"integer","format":"int64"}}},"TeamMember":{"type":"object","required":["org_id","team","user_id","created_at","name"],"properties":{"avatar":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64","description":"When they joined this team, not when their account was created."},"email":{"type":["string","null"],"description":"`None` only for a member that is itself an org; a person always has one."},"handle":{"type":["string","null"]},"name":{"type":"string"},"org_id":{"type":"string"},"team":{"type":"string"},"user_id":{"type":"string"}}},"TemplateRelease":{"type":"object","description":"A published version's identity remains after its image is pruned.","required":["version","digest","created_at","available","yanked"],"properties":{"available":{"type":"boolean"},"created_at":{"type":"integer","format":"int64"},"digest":{"type":"string"},"notes":{"type":["string","null"]},"version":{"type":"string"},"yanked":{"type":"boolean"}}},"TemplateSource":{"type":"object","required":["owner","name"],"properties":{"name":{"type":"string"},"owner":{"type":"string"}}},"Terms":{"type":"object","description":"What calling a service is held to and costs: each public tool's terms, by\nname.","required":["tools","deadline"],"properties":{"deadline":{"type":"integer","format":"int64","description":"Milliseconds a chain of calls runs before the host stops it.","minimum":0},"tools":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ToolTerms"},"propertyNames":{"type":"string"}}}},"ToolCosted":{"type":"object","description":"What one tool's invocations used over the last 30 days, as its service's\nmeters count them, with what that use costs its service's owner.","required":["meter","days","cost_micros"],"properties":{"cost_micros":{"type":"integer","format":"int64","description":"What its meters cost at the fleet's rates, in USD micros: each day's\n[`CostedDay::cost_micros`], summed."},"days":{"type":"array","items":{"$ref":"#/components/schemas/ServedDay"},"description":"Each day it ran, oldest first."},"estimate":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Estimate","description":"What its runs use; none before one ended `done`."}]},"fits":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Limits","description":"Suggested budget: 1.5× each CPU and row measure in `estimate.slow`\n(nested calls included), and 1.5× its own peak linear memory in MiB,\nrounded up. Host ceilings are not checked; none before memory was\nrecorded."}]},"meter":{"$ref":"#/components/schemas/Meter","description":"Its meters summed."}}},"ToolTerms":{"type":"object","description":"What one call of a tool is held to.","required":["budget"],"properties":{"budget":{"$ref":"#/components/schemas/Budget"}}},"ToolUpdate":{"type":"object","description":"A change to one of a service's tools.","properties":{"sunset":{"type":["integer","null"],"format":"int64","description":"When a deprecated tool stops being served, in epoch seconds; `null`\nclears it."}}},"TrialCredit":{"type":"object","description":"Trial funds pay execution, excluding priced tools and subscriptions.","required":["micros","granted_micros","reserved_micros","expires_at"],"properties":{"expires_at":{"type":"integer","format":"int64","description":"Next grant expiration, or the last expiration when all grants expired."},"granted_micros":{"type":"integer","format":"int64"},"micros":{"type":"integer","format":"int64"},"reserved_micros":{"type":"integer","format":"int64"}}},"TrialOffer":{"type":"object","description":"Verification offer terms.","required":["amount_micros","lifetime_days","retention_days"],"properties":{"amount_micros":{"type":"integer","format":"int64"},"lifetime_days":{"type":"integer","format":"int32","minimum":0},"retention_days":{"type":"integer","format":"int32","minimum":0}}},"Unit":{"type":"string","description":"What a warning is about: a field of [`Included`], or `credit` when credit\nran out.","enum":["runs","cpu","read","written","held","stored","sent","credit"]},"UpdateKeyRequest":{"type":"object","description":"What changes of a key, at `PATCH …/keys/{key_id}`; what is left out\nstays.","properties":{"budget":{"type":["integer","null"],"format":"int64","description":"Its daily budget, in USD micros."},"scope":{"type":["array","null"],"items":{"$ref":"#/components/schemas/Scope"}},"services":{"type":["array","null"],"items":{"type":"string"},"description":"Replace priced service access; an empty list removes every grant."}}},"UpdateMemberRequest":{"type":"object","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/Role"}}},"UpdateOrgRequest":{"type":"object","description":"Partial update of an org. Every field is optional; an absent one is left\nalone.","properties":{"avatar":{"type":["string","null"],"description":"`https://` URL of an image to show wherever this account is named.\nAbsent and `null` both leave it alone, as `handle` does."},"bio":{"type":["string","null"],"description":"At most 160 characters after trimming whitespace; empty clears it."},"handle":{"type":["string","null"],"description":"URL handle: 1–39 chars, `[a-z0-9-]`, can't start or end with `-`.\nA handle is never unset once picked, so `null` reads the same as\nabsent — no change — and this field needs no nesting."},"links":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces every link: at most 4 `https://` URLs under 512 characters."},"name":{"type":["string","null"],"description":"Display name. 1–100 characters after trimming whitespace."}}},"UpdateTeamRequest":{"type":"object","description":"Partial update of a team. Absent fields are left alone.","properties":{"name":{"type":["string","null"]},"slug":{"type":["string","null"],"description":"A new slug: the segment in the team's URL. Its memberships follow it."}}},"UpdateUserRequest":{"type":"object","description":"Partial update of the authenticated user. Every field is optional; an\nabsent one is left alone.","properties":{"avatar":{"type":["string","null"],"description":"`https://` URL of an image to show wherever this account is named.\nAbsent and `null` both leave it alone, as `handle` does."},"bio":{"type":["string","null"],"description":"At most 160 characters after trimming whitespace; empty clears it."},"handle":{"type":["string","null"],"description":"URL handle: 1–39 chars, `[a-z0-9-]`, can't start or end with `-`.\nOne namespace covers people and orgs alike, so this can collide with an\norg's. A handle is never unset once picked, so `null` reads the same as\nabsent."},"links":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces every link: at most 4 `https://` URLs under 512 characters."},"name":{"type":["string","null"],"description":"Display name. 1–100 characters after trimming whitespace."}}},"UpgradePolicy":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"},"explain":{"type":["string","null"]},"last_attempt":{"type":["integer","null"],"format":"int64"},"last_error":{"type":["string","null"]},"target":{"type":["string","null"]}}},"UpgradeSetting":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}},"additionalProperties":false},"Upload":{"type":"object","description":"Where a file's bytes go.","properties":{"upload":{"type":["string","null"],"description":"A URL to `PUT` the bytes to, with their `Content-Length`, within an\nhour; none when Cloud holds that file already."}}},"UploadRequest":{"type":"object","description":"A file to upload, a seed or an image: its SHA-256 in hex, and its size in\nbytes.","required":["sha256","size"],"properties":{"sha256":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"Usage":{"type":"object","description":"One caller of one of a service's tools or events over the last 30 days.","required":["kind","item","source","caller","outcome","calls","last"],"properties":{"caller":{"type":"string","description":"The service's deployment address, or the account or app."},"calls":{"type":"integer","format":"int64"},"item":{"type":"string"},"kind":{"$ref":"#/components/schemas/Kind"},"last":{"type":"integer","format":"int64","description":"The last call, in epoch seconds."},"outcome":{"$ref":"#/components/schemas/Outcome"},"public":{"type":["boolean","null"],"description":"For a tool, whether the deployed version makes it public."},"source":{"$ref":"#/components/schemas/Source"}}},"User":{"type":"object","required":["id","name","links","email","created_at","updated_at"],"properties":{"avatar":{"type":["string","null"]},"bio":{"type":["string","null"],"description":"A line about the person, shown on their profile."},"created_at":{"type":"integer","format":"int64"},"email":{"type":"string"},"handle":{"type":["string","null"],"description":"GitHub-style URL handle, unique across every account. `None` until one\nis picked on first login."},"id":{"type":"string"},"links":{"type":"array","items":{"type":"string"},"description":"`https://` URLs shown on their profile, in their order."},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"VarValue":{"type":"object","description":"A var's value, as its owners set it.","properties":{"value":{"type":["string","null"],"description":"`None` returns it to its default."}}},"Verification":{"type":"object","description":"A person's verification, which lets an account on Hobby deploy.","properties":{"github":{"type":"boolean","description":"The person signs in with GitHub."},"reason":{"type":["string","null"],"description":"Why verifying it now fails; `None` when verified or when it would pass."},"trial":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TrialOffer"}]},"verified_at":{"type":["integer","null"],"format":"int64","description":"When it was verified, in Unix seconds; `None` until it is."}}},"VersionInfo":{"type":"object","description":"What is deployed, served unauthenticated at `GET /meta/version`.","required":["version","commit","schema"],"properties":{"commit":{"type":"string","description":"The commit this binary was built from — the full 40-character SHA, e.g.\n`9bb4d4f11e60a4da6c8ca91a9dba2c5e874d2035`; truncate for display.\n`unknown` outside a git tree."},"schema":{"type":"integer","format":"int64","description":"The database schema this deployment is on — the highest migration\napplied, matching the number a migration filename starts with. What the\ndatabase holds, not merely what the binary ships."},"version":{"type":"string","description":"The running build's crate version, e.g. `0.1.1`, plain semver. It moves\nonly when someone bumps it, not every deploy; `commit` identifies a\nbuild."}}},"Visibility":{"type":"object","description":"Who a service answers.","required":["private"],"properties":{"private":{"type":"boolean","description":"Only the owning account and its members see and call it; anyone else\nis answered `404`."}}},"Wake":{"type":"object","description":"A wake armed with `berm.call.after`.","required":["tool","args","due","by","failures"],"properties":{"args":{"type":"string","description":"The arguments it calls the tool with, as JSON text."},"by":{"type":"string","description":"The service that armed it, by its name."},"due":{"type":"integer","format":"int64","description":"When it fires, in epoch milliseconds.","minimum":0},"failures":{"type":"integer","format":"int64","description":"Times it failed in a row since it was last armed.","minimum":0},"last":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Call","description":"The last time a wake armed by the same service ran this tool, in the\nlast 30 days."}]},"tool":{"type":"string","description":"The tool it calls."}}},"Wakes":{"type":"object","description":"The wakes armed to call a service's tools that have not run.","required":["wakes","held"],"properties":{"held":{"type":"boolean","description":"Its scope is held: none runs until it is let go."},"wakes":{"type":"array","items":{"$ref":"#/components/schemas/Wake"},"description":"Soonest first."}}},"Warning":{"type":"object","description":"A share of an included amount an account reached in a period.","required":["unit","threshold"],"properties":{"threshold":{"type":"integer","format":"int32","description":"In percent.","minimum":0},"unit":{"$ref":"#/components/schemas/Unit"}}},"Yank":{"type":"object","required":["version","yanked"],"properties":{"version":{"type":"string"},"yanked":{"type":"boolean"}},"additionalProperties":false}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"tags":[{"name":"auth","description":"User identity and session tokens."},{"name":"user","description":"The caller's own account, in full. A person's account is not an org — `/orgs/{org}` resolves orgs and `404`s a person — so everything an org gets under `/orgs/{org}` is here for the account the token names: profile, sessions, billing and keys. `GET /user` carries what funds it, which is what a client builds its account switcher from; `/user/orgs` is the shared orgs beside it, and `/user/invites` the invitations addressed to it.\n\nNothing here takes an id: the token names the only account these routes can reach, so there is nothing to resolve and no membership to check. That is the whole difference from `/users/{user}`, which names a person somebody else may be asking about."},{"name":"users","description":"A named person: their profile at `GET /users/{user}` (session required), and the services they deploy at `/users/{user}/services`. `/users/{user}` names a person the way `/orgs/{org}` names an org, and the segment takes a handle or an id in both. Each namespace answers only for its own kind — an org reached here is `404`, and a person reached under `/orgs/{org}` is too — so no account has two URLs."},{"name":"org","description":"Orgs — `GET /orgs/{org}` requires a session; settings, membership, the invitations an org issues, teams, keys, billing, and the services it deploys. Every route names its org in the path, and only an org: a person's own account is answered under `/user`, and reaching one here is a `404`. A *team* is a group inside one org that gates access; membership overlaps."},{"name":"meta","description":"Facts about the deployment, naming no org: the plan catalog, the meter rates, the liveness probe, and the minimum client version. Everything here answers the same for every caller, which is what keeps it out of `/orgs/{org}` — and what puts them under one segment rather than leaving them as strays at the root."},{"name":"requests","description":"What is asked of a person, handed to them as a code that lasts 30 minutes, or 15 for a deploy: pay for a purchase, which anyone holding the code may do; set a secret of a service, which takes someone signed in who manages it; sign a device in as them, which takes them signed in; or approve a deploy of an account's services, which takes an owner of it signed in and runs as them. A secret's value is never read back."},{"name":"catalog","description":"The jobs services' tools do, grouped by category and platform. A tool names its job in `catalog` in its `crab.toml`, as `company.enrich`: a platform the list in crab's SDK names, then the job. `GET /catalog` answers every category with its platforms and their jobs, `?category=` one category; `/catalog/{platform}` and `/catalog/{platform}/{job}` answer the category holding that platform or job alone. Each job lists every tool of a service the caller sees that does it, with its price and its calls over the last 30 days."},{"name":"services","description":"Services an account deploys under a name, at `/services/{owner}/{name}`. `GET` answers the service as anyone it is visible to sees it: its IDL under `service`, and under `served` its runs, calls and failed calls as its meters count them, per day over the last 30 days, and its runs in total. `/services/{owner}/{name}/idl` answers the IDL alone, the JSON `crab idl` writes: its public tools and package fields; `/services/{owner}/{name}/runtime` answers its owners the rest — its other tools, `deps` and `events`. `PUT` deploys the image a registry reference names, which Cloud pulls anonymously; the service keeps its name and storage across deploys, and a deploy that breaks a tool or event a caller used in the last 30 days is refused unless forced. `DELETE` removes it with what it committed. A service is private from its first deploy: every route of it answers `404` to anyone outside its owning account and that account's members, until its owners make it public at `/services/{owner}/{name}/visibility`. An account's services are listed at `/orgs/{org}/services` or `/users/{user}/services`, each one answering who it is visible to and what it served. A deprecated tool answers with `Deprecation`, and `Sunset` once its owner sets one. Only a service's public tools, those its `crab.toml` gives `access`, can be called, by any account Cloud authenticates and any service allowed by the deployment's visibility and the tool's access, with arguments of the caller's choosing; a deploy that makes a tool public is refused until it lists that tool in `public`, and a tool reads who called it from `berm_lang::caller()`. A tool is called at `/services/{owner}/{name}/tools/{tool}`: `POST` with the arguments as the body, or `GET` with `?args=` for a tool the IDL marks `query`, whose `ETag` is the service's commit count. Each service a call reaches commits what it wrote and emitted when its own part returns ok, whatever the parts around it do; a part that fails commits nothing of its own. `/services/{owner}/{name}/logs` lists to its owners what a service emitted to debug its runs, oldest first: each log names the call it was emitted in, holds at most 4 KiB, and is kept 30 days, whatever the call ended as. A service's data lives in its database and is read through its query tools. `berm.call.after` holds one wake per service, fired when due. `/services/{owner}/{name}/crons` shows its owners each `#[tool(cron)]` tool with its expression and next run, and `/services/{owner}/{name}/wakes` the wakes armed to call one of its tools that have not run, each with whether the account is held. A cron tool is called each time its cron expression fires, five fields read in UTC, whatever its last call ended as: a deploy's `crons` sets the expressions, its owners set one at `PUT /services/{owner}/{name}/tools/{tool}/cron` until the next such deploy, and that deploy is refused, unless forced, while it would undo theirs. A service's secrets are its own, at `/services/{owner}/{name}/secrets[/{secret}]`: set, listed by name and revoked by its owners, never read back, and substituted into its fetches where its manifest declares them. A service whose manifest keeps a database gets its own SQLite file, migrated on deploy, reached through `berm.sql`; a call into it runs in one transaction of that file. A service calls a running deployment by `owner/service`; cross-account calls require public visibility and charge the calling service's account for priced tools. A website calls from its users' browsers through an app (`/user/apps`, `/orgs/{org}/apps`): `X-App` names it, the request comes from one of its origins, and the bearer is an ID token from one of its issuers, whose user the tool reads from `berm_lang::user()`; with no token an anonymous app reaches only tools with `access = \"anonymous\"`, which read no caller, and an anonymous app with no issuers may list `*` as its origin to admit any site. Every caller is limited per minute. An account's services hold at most its plan's memory at once, their retained code and active calls, shown at `/orgs/{org}/memory` or `/users/{user}/memory`: idle cached code is reclaimed first, a call is refused with `429` while active work holds the allowance, a call growing past it fails, and an image larger than the allowance is refused. Idle code reloads automatically on the next call without stopping its deployment. `/services/{owner}/{name}/calls` lists each run of a service over the last 30 days to its owners, newest first: a call from outside or a wake, with its outcome, duration, meter, and what that meter costs the owner; an account's calls together, each naming its service, at `/orgs/{org}/calls` or `/users/{user}/calls`. `/services/{owner}/{name}/calls/stats`, `/orgs/{org}/calls/stats` and `/users/{user}/calls/stats` count the calls the same filters name, by time and by each tool, outcome and service. `/services/{owner}/{name}/uses` answers its owners each caller of each of its tools and events in a month, by outcome. `/services/{owner}/{name}/history` lists to its owners its last 100 deploys that went live, newest first, each with its version, image, what it was deployed from, who and when. `/services/{owner}/{name}/meters` is what a service used, a day each: invocations, CPU time spent, peak linear memory, rows read and written, bytes logged, and bytes stored; a tool's answer carries the call's own meter in `Berm-Meter`, the same on bermd for the same call, and each invocation stops at its CPU budget and refuses rows past its budget of rows read or of rows written. A tool's budget is set by `budget` in its `crab.toml`, built into its image, up to the node's; a tool that sets none takes the node's default. `/services/{owner}/{name}/usage` shows its owners what it is using now, read as asked: invocations running and the memory they hold, bytes stored, and CPU time, rows read and written, and bytes proxied and logged, each in total since its first deploy and per second over the UTC day so far. `/services/{owner}/{name}/billing` shows its owners, for a UTC calendar month, what those meters cost, each charged resource with its rate, and what is owed. `/services/{owner}/{name}/terms` is public and answers each public tool's terms, live, with the node's deadline for a chain of calls: its budget, the most one call of it can use, its price a call, as the service's last deploy set it, and from its first run in the last 30 days that ended done, what a typical and a 99th-percentile run used and cost to run, the 99th percentile being the slowest below 100 runs."}]}