{"openapi":"3.1.0","info":{"title":"str.ing API","description":"Send a token in the `Authorization` header: `Authorization: Bearer <token>`. Sign in with `POST /auth/login` to get a session token, create a personal access token for tools like the CLI, or create an API key for automation. A missing, invalid, expired or revoked token gets `401 UNAUTHENTICATED` on every route.\nAuthentication for stored credentials is cached for up to five seconds.\n\nOrganizations are named by their slug, such as `acme`, in paths and requests.\n\nTimes are RFC 3339 date-times in UTC, such as `2026-10-27T16:00:00.000Z`.\n\nAn error returns a JSON body with `code` and `message`. Branch on `code`; each operation lists the codes it can return.","license":{"name":""},"version":"2"},"paths":{"/auth/device/approve":{"post":{"tags":["device-auth"],"summary":"Approve a device login","description":"The device gets a personal access token for you in the chosen organization,\nvalid for 90 days.","operationId":"approve_device_login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveDeviceRequest"}}},"required":true},"responses":{"200":{"description":"Approved. The device's next poll gets its token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceDecisionResponse"}}}},"403":{"description":"`SESSION_REQUIRED`: sign in first; a key or token can't approve devices.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`DEVICE_CODE_NOT_FOUND`: no pending request has this code. It may be mistyped, expired, or already approved or denied. `ORG_NOT_FOUND`: you are not a member of an organization with this slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/auth/device/authorization":{"get":{"tags":["device-auth"],"summary":"Look up a device login","description":"For the approval page: shows what the device is asking for before the user\napproves. Accepts the code as typed, ignoring case, spaces and dashes.","operationId":"get_device_login","parameters":[{"name":"user_code","in":"query","description":"The code the user typed, such as `bcdf ghjk`.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The pending request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceAuthorizationDetails"}}}},"403":{"description":"`SESSION_REQUIRED`: sign in first; a key or token can't approve devices.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`DEVICE_CODE_NOT_FOUND`: no pending request has this code. It may be mistyped, expired, or already approved or denied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/auth/device/code":{"post":{"tags":["device-auth"],"summary":"Start a device login","description":"For a tool that can't show a sign-in page, such as a CLI. The device shows the\nuser a short code and a link. The user opens the link in a browser where they\nare signed in and approves. Meanwhile the device polls\n`POST /auth/device/token` until it receives a personal access token.","operationId":"start_device_login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceCodeRequest"}}},"required":true},"responses":{"200":{"description":"Show `user_code` and `verification_uri` to the user, then poll with `device_code`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceCodeResponse"}}}},"400":{"description":"`CLIENT_NAME_REQUIRED`: `client_name` is empty.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"`DEVICE_LOGIN_UNAVAILABLE`: device login is turned off on this server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/auth/device/deny":{"post":{"tags":["device-auth"],"summary":"Deny a device login","operationId":"deny_device_login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DenyDeviceRequest"}}},"required":true},"responses":{"200":{"description":"Denied. The device's next poll gets `access_denied`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceDecisionResponse"}}}},"403":{"description":"`SESSION_REQUIRED`: sign in first; a key or token can't approve devices.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`DEVICE_CODE_NOT_FOUND`: no pending request has this code. It may be mistyped, expired, or already approved or denied.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/auth/device/token":{"post":{"tags":["device-auth"],"summary":"Collect a device login's token","description":"Poll every `interval` seconds until the response is `200` or an error says to\nstop.","operationId":"poll_device_login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenRequest"}}},"required":true},"responses":{"200":{"description":"Approved. The token is in this response only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenResponse"}}}},"400":{"description":"Not approved yet, or never will be. `error` says which.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenError"}}}},"503":{"description":"`unavailable`: a temporary failure. Keep polling.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceTokenError"}}}}}}},"/auth/exchange":{"post":{"tags":["auth"],"summary":"Exchange a token for a narrower one","description":"Trade the token you are using for one that can do less: it works in one\norganization, with no higher role, and expires no later than the original.\nHand the narrower token to a job or service that needs only that much access.\n\nA token of 300 seconds or less is a signed `request` token. A longer one\nis a stored `exchanged` token. Both stop working when the source is revoked.","operationId":"exchange","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeRequest"}}},"required":true},"responses":{"200":{"description":"The new token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeResponse"}}}},"400":{"description":"`ROLE_EXCEEDS_SOURCE`: a role in `roles` is higher than your current token's. `NO_ROLE_LEFT`: none of `roles` is available to you in this organization. `INVALID_TTL`: `ttl_seconds` is not between 1 and 2592000.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`EXCHANGE_NOT_ALLOWED`: only a session, personal access token or API key can be exchanged, not a token that was itself exchanged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: your current token does not reach an organization with this slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"`REQUEST_TOKEN_KEY_UNAVAILABLE`: short-lived tokens are temporarily unavailable. Retry, or ask for more than 300 seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/auth/login":{"post":{"tags":["auth"],"summary":"Sign in with email and password","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Signed in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}},"401":{"description":"`INVALID_CREDENTIALS`: the email or password is wrong.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/auth/logout":{"post":{"tags":["auth"],"summary":"Sign out","description":"Ends the session that made the request.","operationId":"logout","responses":{"204":{"description":"Signed out. The session token stops working within five seconds."},"401":{"description":"`UNAUTHENTICATED`: no token was sent, or it is invalid, expired or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`SESSION_REQUIRED`: this needs a signed-in session, not an API key or token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/auth/register":{"post":{"tags":["auth"],"summary":"Create an account","description":"Creates the user and a personal workspace they own, and signs them in.","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}},"required":true},"responses":{"200":{"description":"Registered and signed in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}},"400":{"description":"`INVALID_EMAIL`: `email` is not an email address. `WEAK_PASSWORD`: `password` is shorter than 8 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"`USER_EXISTS`: an account with this email already exists. Sign in instead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/auth/tokens":{"get":{"tags":["tokens"],"summary":"List your personal access tokens","operationId":"list_pats","responses":{"200":{"description":"Your tokens that have not been revoked, newest first. The tokens themselves are never shown again.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PatListItem"}}}}},"403":{"description":"`SESSION_REQUIRED`: sign in to manage keys and tokens; an API key or token can't do it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["tokens"],"summary":"Create a personal access token","description":"A personal access token (PAT) lets a tool such as the CLI or a script act as\nyou in one organization, with your role there. It stops working there if you\nleave the organization. Use an API key instead for automation that should not\ndepend on one person.","operationId":"create_pat","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePatRequest"}}},"required":true},"responses":{"201":{"description":"The new token. Store `raw_token` now; it is not shown again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePatResponse"}}}},"400":{"description":"`NAME_REQUIRED`: `name` is empty. `INVALID_EXPIRES_AT`: `expires_at` is not a date-time in the future.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`SESSION_REQUIRED`: sign in to manage keys and tokens; an API key or token can't do it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/auth/tokens/{pat_id}":{"delete":{"tags":["tokens"],"summary":"Revoke a personal access token","description":"Anything still using the token gets `401` within five seconds.","operationId":"revoke_pat","parameters":[{"name":"pat_id","in":"path","description":"The token's `id`","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked. The token stops working within five seconds."},"403":{"description":"`SESSION_REQUIRED`: sign in to manage keys and tokens; an API key or token can't do it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`NOT_FOUND`: you have no such token, or it is already revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/auth/verify":{"get":{"tags":["auth"],"summary":"Get the signed-in user","description":"Returns the user behind a session, with every organization they belong to.","operationId":"verify","responses":{"200":{"description":"The signed-in user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyResponse"}}}},"401":{"description":"`UNAUTHENTICATED`: no token was sent, or it is invalid, expired or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`SESSION_REQUIRED`: this needs a signed-in session, not an API key or token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/auth/whoami":{"get":{"tags":["auth"],"summary":"Describe the current token","description":"Works with any token. Use it to check what a key or token can do before you\nrely on it.","operationId":"whoami","responses":{"200":{"description":"What the token is and what it can reach","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhoamiResponse"}}}},"401":{"description":"`UNAUTHENTICATED`: no token was sent, or it is invalid, expired or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/health":{"get":{"tags":["health"],"summary":"Check that the API is up","description":"Answers without reading any data.","operationId":"live","responses":{"200":{"description":"The API is up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/health/db":{"get":{"tags":["health"],"summary":"Check that the API can read its data","operationId":"db","responses":{"200":{"description":"The API can read its data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"`DATABASE_UNAVAILABLE`: the API is up but can't read its data. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/health/functions":{"get":{"tags":["health"],"summary":"Check that functions are available","operationId":"functions","responses":{"200":{"description":"Functions are available","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"`FUNCTIONS_UNAVAILABLE`: the API is up but functions are not. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/health/store":{"get":{"tags":["health"],"summary":"Check that the API can reach its data store","operationId":"store","responses":{"200":{"description":"The API can reach its data store","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"`DATA_STORE_UNAVAILABLE`: the API is up but can't reach its data store. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/invitations/{token}":{"get":{"tags":["members"],"summary":"Look up an invitation","description":"Needs no sign-in, so an invitee can see which organization they are joining\nbefore they create an account.","operationId":"get_invitation","parameters":[{"name":"token","in":"path","description":"The `invite_token` from the invitation","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The invitation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationDetails"}}}},"404":{"description":"`INVITATION_NOT_FOUND`: the token is unknown, or the invitation expired, was revoked or was already accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/invitations/{token}/accept":{"post":{"tags":["members"],"summary":"Accept an invitation","description":"Sign in with the email address the invitation was sent to first.","operationId":"accept_invitation","parameters":[{"name":"token","in":"path","description":"The `invite_token` from the invitation","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Joined. The organization now appears in your sessions and tokens.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInvitationResponse"}}}},"403":{"description":"`SESSION_REQUIRED`: sign in to accept. `INVITATION_EMAIL_MISMATCH`: you are signed in with a different email than the invitation was sent to.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`INVITATION_NOT_FOUND`: the token is unknown, or the invitation expired, was revoked or was already accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"`ALREADY_MEMBER`: you are already a member of this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/orgs":{"post":{"tags":["orgs"],"summary":"Create an organization","description":"The slug is made from the name, such as `acme-inc` from \"Acme Inc\". If it is\ntaken, a number is added (`acme-inc-2`).","operationId":"create_org","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgRequest"}}},"required":true},"responses":{"201":{"description":"The new organization, with you as its owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgGrant"}}}},"400":{"description":"`INVALID_NAME`: `name` is empty or longer than 100 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`SESSION_REQUIRED`: sign in to create an organization; a key or token can't do it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"`SLUG_TAKEN`: the slug made from this name, and its numbered variants, are all taken. Try a more distinctive name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/api-keys":{"get":{"tags":["api-keys"],"summary":"List an organization's API keys","operationId":"list_api_keys","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The organization's keys that have not been revoked, newest first. The keys themselves are never shown again.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyListItem"}}}}},"403":{"description":"`SESSION_REQUIRED`: sign in to manage keys and tokens; an API key or token can't do it. `INSUFFICIENT_ROLE`: you need the admin or owner role in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["api-keys"],"summary":"Create an API key","description":"An API key lets a program call the API on behalf of an organization rather\nthan a person. It acts with one role in one organization and keeps working\nwhen the person who created it leaves. Use one for servers and automation.","operationId":"create_api_key","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"The new key. Store `raw_key` now; it is not shown again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"`ROLE_EXCEEDS_CREATOR`: `role` is higher than your own. `NAME_REQUIRED`: `name` is empty. `INVALID_EXPIRES_AT`: `expires_at` is not a date-time in the future.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`SESSION_REQUIRED`: sign in to manage keys and tokens; an API key or token can't do it. `INSUFFICIENT_ROLE`: you need the admin or owner role in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/api-keys/{key_id}":{"delete":{"tags":["api-keys"],"summary":"Revoke an API key","description":"Anything still using the key gets `401` within five seconds.","operationId":"revoke_api_key","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}},{"name":"key_id","in":"path","description":"The key's `id`","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked. The key stops working within five seconds."},"403":{"description":"`SESSION_REQUIRED`: sign in to manage keys and tokens; an API key or token can't do it. `INSUFFICIENT_ROLE`: you need the admin or owner role in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member. `NOT_FOUND`: no such key in this organization, or it is already revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions":{"get":{"tags":["functions"],"summary":"List functions","operationId":"list_functions","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Every function in the organization, most recently updated first","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Function"}}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["functions"],"summary":"Create a function","description":"Without a `slug`, one is made from the name: \"Classify Ticket\" becomes\n`classify-ticket`, or `classify-ticket-2` if that is taken.","operationId":"create_function","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunctionRequest"}}},"required":true},"responses":{"201":{"description":"The new function","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}}},"400":{"description":"`INVALID_NAME`: `name` is empty or longer than 100 characters. `INVALID_SLUG`: `slug` breaks the format or is reserved. `INVALID_DESCRIPTION`: `description` is longer than 2,000 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE`: you need the member role or above in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"`SLUG_TAKEN`: another function in this organization has this slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}":{"get":{"tags":["functions"],"summary":"Get a function","operationId":"get_function","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"The function's slug or id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The function","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member. `FUNCTION_NOT_FOUND`: no function with this slug or id in the organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]},"delete":{"tags":["functions"],"summary":"Delete a function","operationId":"delete_function","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"The function's slug or id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"403":{"description":"`INSUFFICIENT_ROLE`: you need the member role or above in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member. `FUNCTION_NOT_FOUND`: no function with this slug or id in the organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]},"patch":{"tags":["functions"],"summary":"Update a function","description":"Fields you leave out keep their value. The slug doesn't follow a new name;\nchange it with `PATCH /{org_slug}/functions/{function}/slug`.","operationId":"update_function","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"The function's slug or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFunctionRequest"}}},"required":true},"responses":{"200":{"description":"The function, updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}}},"400":{"description":"`INVALID_NAME`: `name` is empty or longer than 100 characters. `INVALID_DESCRIPTION`: `description` is longer than 2,000 characters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE`: you need the member role or above in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member. `FUNCTION_NOT_FOUND`: no function with this slug or id in the organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}/check":{"post":{"tags":["functions"],"summary":"Check a script","description":"Typechecks unsaved `main.ts` source. `Input` and `Output` are generated from\nthe two schemas, and the default export must take an `Input` and return an `Output`.","operationId":"check_script","parameters":[{"name":"org_slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"Function ID or slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckScript"}}},"required":true},"responses":{"200":{"description":"The script's diagnostics; an empty list when it typechecks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckResult"}}}},"400":{"description":"`INVALID_CHECK`: the body lacks `source`, `input_schema` or `output_schema`. `INVALID_SCHEMA`: a schema is not a JSON Schema object or is not a valid JSON Schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"`UNAUTHENTICATED`: no token was sent, or it is invalid, expired or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND` or `FUNCTION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"`REQUEST_TOO_LARGE`: the request exceeds the size limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"`FUNCTIONS_UNAVAILABLE`: scripts cannot be checked right now. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}/default-version":{"get":{"tags":["functions"],"summary":"Read the current and previous default versions.","operationId":"get_default","parameters":[{"name":"org_slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Current and previous default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultVersion"}}}},"404":{"description":"ORG_NOT_FOUND or FUNCTION_NOT_FOUND","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]},"put":{"tags":["functions"],"summary":"Set or clear the default; send the previous version to restore it.","operationId":"set_default","parameters":[{"name":"org_slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetDefault"}}},"required":true},"responses":{"200":{"description":"Current and previous default; unchanged selections preserve previous_version","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultVersion"}}}},"403":{"description":"INSUFFICIENT_ROLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"ORG_NOT_FOUND, FUNCTION_NOT_FOUND or VERSION_NOT_FOUND","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"Invalid version object"}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}/draft":{"get":{"tags":["functions"],"summary":"Read the function draft","operationId":"get_draft","parameters":[{"name":"org_slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"Function ID or slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Draft source; null commit and empty files before the first save","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Draft"}}}},"404":{"description":"ORG_NOT_FOUND or FUNCTION_NOT_FOUND","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"FUNCTIONS_UNAVAILABLE: function source cannot be read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]},"put":{"tags":["functions"],"summary":"Save the function draft","operationId":"put_draft","parameters":[{"name":"org_slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"Function ID or slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveDraft"}}},"required":true},"responses":{"200":{"description":"Saved source commit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedDraft"}}}},"400":{"description":"INVALID_DRAFT, INVALID_COMMIT, INVALID_FUNCTION, INVALID_MODEL, or INVALID_FILES","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"INSUFFICIENT_ROLE: saving requires member access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"ORG_NOT_FOUND or FUNCTION_NOT_FOUND","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"DRAFT_CONFLICT: reload the draft before saving again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"REQUEST_TOO_LARGE: source request exceeds the size limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"FUNCTIONS_UNAVAILABLE or MODELS_UNAVAILABLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}/exec":{"post":{"tags":["functions"],"summary":"Execute the default version","description":"Runs the version `PUT …/default-version` selected, with `input` checked\nagainst its `input_schema` and the output against its `output_schema`.\nThe script's `api.infer` calls reach the gateway as the organization, with\nthe caller's role, under the tag `$fn:{function_id}:{version}`.","operationId":"exec_default","parameters":[{"name":"org_slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"Function ID or slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecRequest"}}},"required":true},"responses":{"200":{"description":"The output and the calls the script made","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Execution"}}}},"400":{"description":"`INVALID_REQUEST`: the body is not JSON with an `input`. `INVALID_INPUT`: the input does not match the version's `input_schema`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"`UNAUTHENTICATED`: no token was sent, or it is invalid, expired or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE`: executing needs the member role or above.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`, `FUNCTION_NOT_FOUND`, or `NO_DEFAULT_VERSION`: no default version is selected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"`REQUEST_TOO_LARGE`: the request exceeds the size limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"`SCRIPT_ERROR`: the script threw. `INVALID_OUTPUT`: the output does not match the `output_schema`. `SCRIPT_HUNG`: the script awaited a promise that can never settle. `INVALID_SOURCE` or `INVALID_DEFINITION`: the version's source does not load.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"501":{"description":"`RUNTIME_UNSUPPORTED`: the version is not a script function.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"`FUNCTIONS_UNAVAILABLE`: scripts cannot be run right now. Retry later. `REQUEST_TOKEN_KEY_UNAVAILABLE`: the run's gateway credential cannot be minted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"504":{"description":"`SCRIPT_TIMEOUT`: the version's `timeout_seconds` elapsed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}/exec/{version}":{"post":{"tags":["functions"],"summary":"Execute a version","description":"`version` is `v1`, `v1.2` or `v1.2.3`: the highest published version\nwith that major, the highest patch of that line, or exactly that version.\nOtherwise as `POST …/exec`.","operationId":"exec_version","parameters":[{"name":"org_slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"Function ID or slug","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"`v1`, `v1.2` or `v1.2.3`","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecRequest"}}},"required":true},"responses":{"200":{"description":"The output and the calls the script made","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Execution"}}}},"400":{"description":"`INVALID_VERSION`: the version is not `v1`, `v1.2` or `v1.2.3`. `INVALID_REQUEST`: the body is not JSON with an `input`. `INVALID_INPUT`: the input does not match the version's `input_schema`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"`UNAUTHENTICATED`: no token was sent, or it is invalid, expired or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE`: executing needs the member role or above.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`, `FUNCTION_NOT_FOUND`, or `VERSION_NOT_FOUND`: no published version matches.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"413":{"description":"`REQUEST_TOO_LARGE`: the request exceeds the size limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"`SCRIPT_ERROR`: the script threw. `INVALID_OUTPUT`: the output does not match the `output_schema`. `SCRIPT_HUNG`: the script awaited a promise that can never settle. `INVALID_SOURCE` or `INVALID_DEFINITION`: the version's source does not load.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"501":{"description":"`RUNTIME_UNSUPPORTED`: the version is not a script function.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"`FUNCTIONS_UNAVAILABLE`: scripts cannot be run right now. Retry later. `REQUEST_TOKEN_KEY_UNAVAILABLE`: the run's gateway credential cannot be minted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"504":{"description":"`SCRIPT_TIMEOUT`: the version's `timeout_seconds` elapsed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}/files":{"get":{"tags":["functions"],"summary":"Read function files at a commit","operationId":"get_files","parameters":[{"name":"org_slug","in":"path","description":"Organization slug","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"Function ID or slug","required":true,"schema":{"type":"string"}},{"name":"commit","in":"query","description":"Full commit SHA returned by a save.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Files at the requested commit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Files"}}}},"400":{"description":"INVALID_COMMIT: expected a full commit SHA","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"ORG_NOT_FOUND, FUNCTION_NOT_FOUND, or COMMIT_NOT_FOUND","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"FUNCTIONS_UNAVAILABLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}/publish-preview":{"get":{"tags":["functions"],"summary":"Preview the required bump against the latest version on each major line.","operationId":"publish_preview","parameters":[{"name":"org_slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","required":true,"schema":{"type":"string"}},{"name":"commit","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Publish options; an exhausted version range has no suggestion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishPreview"}}}},"400":{"description":"INVALID_COMMIT, INVALID_FUNCTION or INVALID_MODEL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"ORG_NOT_FOUND, FUNCTION_NOT_FOUND or COMMIT_NOT_FOUND","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"FUNCTIONS_UNAVAILABLE or MODELS_UNAVAILABLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}/slug":{"patch":{"tags":["functions"],"summary":"Change a function's slug","description":"URLs that use the old slug stop working at once; the id never changes.","operationId":"change_function_slug","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","description":"The function's slug or id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeSlugRequest"}}},"required":true},"responses":{"200":{"description":"The function, with its new slug","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}}},"400":{"description":"`INVALID_SLUG`: `slug` breaks the format or is reserved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE`: you need the member role or above in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member. `FUNCTION_NOT_FOUND`: no function with this slug or id in the organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"`SLUG_TAKEN`: another function in this organization has this slug.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/functions/{function}/versions":{"get":{"tags":["functions"],"summary":"List published function versions, newest version first.","operationId":"list_versions","parameters":[{"name":"org_slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Published versions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublishedVersion"}}}}},"404":{"description":"ORG_NOT_FOUND or FUNCTION_NOT_FOUND","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["functions"],"summary":"Publish an immutable version of a source commit.","operationId":"publish_version","parameters":[{"name":"org_slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"function","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishRequest"}}},"required":true},"responses":{"201":{"description":"Published version; publishing does not change the default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishedVersion"}}}},"400":{"description":"INVALID_COMMIT, INVALID_FUNCTION or INVALID_MODEL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"INSUFFICIENT_ROLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"ORG_NOT_FOUND, FUNCTION_NOT_FOUND or COMMIT_NOT_FOUND","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"VERSION_EXISTS, VERSION_NOT_LATEST, VERSION_BUMP_TOO_SMALL or PUBLISH_CONFLICT; reload the publish preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"Invalid version object"},"503":{"description":"FUNCTIONS_UNAVAILABLE or MODELS_UNAVAILABLE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/invitations":{"get":{"tags":["members"],"summary":"List pending invitations","operationId":"list_invitations","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Invitations not yet accepted, revoked or expired","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InvitationListItem"}}}}},"403":{"description":"`INSUFFICIENT_ROLE`: you need the admin or owner role in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/invitations/{invitation_id}":{"delete":{"tags":["members"],"summary":"Revoke an invitation","operationId":"revoke_invitation","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}},{"name":"invitation_id","in":"path","description":"The invitation's `id`","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked. The invitation can no longer be accepted."},"403":{"description":"`INSUFFICIENT_ROLE`: you need the admin or owner role in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member. `NOT_FOUND`: no pending invitation with this id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/members":{"get":{"tags":["members"],"summary":"List members","description":"Any member can see who else is in the organization.","operationId":"list_members","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The organization's members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MemberResponse"}}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]},"post":{"tags":["members"],"summary":"Invite someone","description":"Creates an invitation for an email address. str.ing doesn't send email yet,\nso send the returned `invite_token` to the invitee yourself. It expires after\n7 days.","operationId":"invite","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteRequest"}}},"required":true},"responses":{"201":{"description":"The invitation. Send `invite_token` to the invitee now; it is not shown again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteResponse"}}}},"400":{"description":"`INVALID_EMAIL`: `email` is not an email address. `ROLE_EXCEEDS_CALLER`: `role` is higher than yours. `PERSONAL_ORG`: a personal workspace can't have other members.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE`: you need the admin or owner role in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"`ALREADY_MEMBER`: someone with this email is already a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/members/leave":{"post":{"tags":["members"],"summary":"Leave an organization","operationId":"leave","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"You are no longer a member"},"403":{"description":"`SESSION_REQUIRED`: sign in to leave; a key or token can't do it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"`LAST_OWNER`: this would leave the organization without an owner. Make someone else an owner first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/members/{user_id}":{"delete":{"tags":["members"],"summary":"Remove a member","operationId":"remove_member","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}},{"name":"user_id","in":"path","description":"The member's `user_id`","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Removed. Stored credentials lose access within five seconds; existing request tokens keep their grants until they expire."},"400":{"description":"`ROLE_EXCEEDS_CALLER`: the member's role is higher than yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE`: you need the admin or owner role in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member. `MEMBER_NOT_FOUND`: that user is not a member of this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"`LAST_OWNER`: this would leave the organization without an owner. Make someone else an owner first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org_slug}/members/{user_id}/role":{"patch":{"tags":["members"],"summary":"Change a member's role","operationId":"change_role","parameters":[{"name":"org_slug","in":"path","description":"The organization's slug, such as `acme`","required":true,"schema":{"type":"string"}},{"name":"user_id","in":"path","description":"The member's `user_id`","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeRoleRequest"}}},"required":true},"responses":{"200":{"description":"The member, with the new role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberResponse"}}}},"400":{"description":"`ROLE_EXCEEDS_CALLER`: the member's current or new role is higher than yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE`: you need the admin or owner role in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`: no organization with this slug, or you are not a member. `MEMBER_NOT_FOUND`: that user is not a member of this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"`LAST_OWNER`: this would leave the organization without an owner. Make someone else an owner first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org}/agent/threads/{thread}/chat":{"get":{"tags":["agent"],"summary":"Connect to a thread using the native Cloudflare Agents chat protocol","description":"Requires a session, PAT or API key with member access. The API mints an\norg-scoped JWT lasting at most one hour and no longer than its source.\nReconnect through this endpoint after expiry. Source revocation is checked\non each authenticated request.\nThread storage is scoped to organization ID, actor and thread ID.","operationId":"chat","parameters":[{"name":"org","in":"path","description":"Organization slug or ID","required":true,"schema":{"type":"string"}},{"name":"thread","in":"path","description":"1–128 ASCII letters, digits, underscores or hyphens","required":true,"schema":{"type":"string"}}],"responses":{"101":{"description":"Native SDK WebSocket; messages, cancellation and resume pass through unchanged"},"400":{"description":"`INVALID_THREAD`: invalid thread ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"`UNAUTHENTICATED`: missing, invalid, expired or revoked credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE` or `AGENT_CREDENTIAL_REQUIRED`: use a session, PAT or API key with member access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"426":{"description":"`WEBSOCKET_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"`AGENTS_UNAVAILABLE`: the agents service is not available","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}},"/{org}/agent/threads/{thread}/get-messages":{"get":{"tags":["agent"],"summary":"Read a thread's native SDK message history","operationId":"get_messages","parameters":[{"name":"org","in":"path","description":"Organization slug or ID","required":true,"schema":{"type":"string"}},{"name":"thread","in":"path","description":"1–128 ASCII letters, digits, underscores or hyphens","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Native SDK UIMessage history","content":{"application/json":{"schema":{"type":"array","items":{}}}}},"400":{"description":"`INVALID_THREAD`: invalid thread ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"`UNAUTHENTICATED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"description":"`INSUFFICIENT_ROLE` or `AGENT_CREDENTIAL_REQUIRED`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"404":{"description":"`ORG_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"description":"`AGENTS_UNAVAILABLE`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"bearer":[]}]}}},"components":{"schemas":{"AcceptInvitationResponse":{"type":"object","required":["organization_id","organization_slug","role"],"properties":{"organization_id":{"type":"string"},"organization_slug":{"type":"string"},"role":{"$ref":"#/components/schemas/OrgRole"}}},"ApiError":{"type":"object","description":"The body of every error response.\n\n```json\n{\"code\": \"ORG_NOT_FOUND\", \"message\": \"Organization not found\"}\n```","required":["code","message"],"properties":{"code":{"type":"string","description":"A stable, machine-readable identifier such as `ORG_NOT_FOUND`. Branch on\nthis; each operation lists the codes it can return."},"message":{"type":"string","description":"A human-readable explanation. Show it to people, but don't parse it:\nthe wording can change."}}},"ApiKeyListItem":{"type":"object","required":["id","key_prefix","name","role","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time","description":"When it stops working, if it has an expiry."},"id":{"type":"string"},"key_prefix":{"type":"string","description":"The start of the key, such as `str_sk_1a2b3c4d`, to help you recognize\nit in a list."},"name":{"type":"string"},"role":{"$ref":"#/components/schemas/OrgRole"}}},"ApproveDeviceRequest":{"type":"object","required":["user_code","organization_slug"],"properties":{"organization_slug":{"type":"string","description":"The organization the device's token will work in, such as `acme`."},"user_code":{"type":"string"}}},"Call":{"type":"object","description":"One `api.infer` call the script made, in the order the calls were made.","required":["index","kind","label","model","cache_status","input_tokens","output_tokens","cost_usd","latency_ms","finish_reason","error_code"],"properties":{"cache_status":{"type":["string","null"],"description":"The gateway's `x-string-cache-status`: `hit`, `miss` or `bypass`."},"cost_usd":{"type":["number","null"],"format":"double","description":"What the call cost. Null when the gateway did not price it."},"error_code":{"type":["string","null"],"description":"Why the call failed, such as `BUDGET_EXCEEDED` or `MODEL_NOT_FOUND`.\nNull when it succeeded."},"finish_reason":{"type":["string","null"]},"index":{"type":"integer","format":"int32","minimum":0},"input_tokens":{"type":["integer","null"],"format":"int64","minimum":0},"kind":{"type":"string","description":"Always `infer` for now."},"label":{"type":["string","null"],"description":"The `label` the script gave the call."},"latency_ms":{"type":"integer","format":"int64","minimum":0},"model":{"type":"string","description":"The model the gateway answered with, or the one asked for when the\ncall failed."},"output_tokens":{"type":["integer","null"],"format":"int64","minimum":0}}},"ChangeRoleRequest":{"type":"object","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/OrgRole","description":"The member's new role. It can't be higher than your own."}}},"ChangeSlugRequest":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string","description":"1 to 63 lowercase letters, digits and hyphens, not starting with a\nhyphen."}}},"CheckResult":{"type":"object","required":["diagnostics"],"properties":{"diagnostics":{"type":"array","items":{"$ref":"#/components/schemas/Diagnostic"},"description":"Problems found in the script, in source order. Empty when the script\nchecks cleanly."}}},"CheckScript":{"type":"object","required":["source","input_schema","output_schema"],"properties":{"input_schema":{"type":"object","description":"The JSON Schema the script's `Input` type is generated from."},"output_schema":{"type":"object","description":"The JSON Schema the script's `Output` type is generated from."},"source":{"type":"string","description":"The contents of `main.ts`."}}},"CreateApiKeyRequest":{"type":"object","required":["name"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","description":"When the key stops working. Leave it out for a key that works until it\nis revoked."},"name":{"type":"string","description":"A label for the key, such as \"ci-deploy\" or \"billing-sync\". It appears\nwhen you list keys, so name it after the system that uses it."},"role":{"$ref":"#/components/schemas/OrgRole","description":"The role the key acts with in this organization. Defaults to `member`.\nIt can't be higher than your own role."}}},"CreateApiKeyResponse":{"type":"object","required":["id","raw_key","key_prefix","name","role","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time","description":"When it stops working, if it has an expiry."},"id":{"type":"string"},"key_prefix":{"type":"string","description":"The start of the key, such as `str_sk_1a2b3c4d`, to help you recognize\nit in a list."},"name":{"type":"string"},"raw_key":{"type":"string","description":"The API key itself. Send it as `Authorization: Bearer <key>`. This is\nthe only response that contains it, so store it securely now; if it is\nlost, revoke the key and create a new one."},"role":{"$ref":"#/components/schemas/OrgRole"}}},"CreateFunctionRequest":{"type":"object","required":["name"],"properties":{"description":{"type":["string","null"],"description":"Up to 2,000 characters. Blank means none."},"name":{"type":"string","description":"The display name, 1 to 100 characters."},"slug":{"type":["string","null"],"description":"The slug, such as `classify-ticket`: 1 to 63 lowercase letters, digits\nand hyphens, not starting with a hyphen. Omit it to make one from the\nname."}}},"CreateOrgRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"The display name, 1 to 100 characters. The slug is made from it."}}},"CreatePatRequest":{"type":"object","required":["name","organization_slug"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","description":"When the token stops working. Leave it out for a token that works until\nit is revoked; setting one limits the damage if it leaks."},"name":{"type":"string","description":"A label for the token, such as \"laptop\" or \"ci-deploy\". It appears when\nyou list your tokens, so name it after where it is used."},"organization_slug":{"type":"string","description":"The organization the token works in, such as `acme`. It acts with your\nrole there."}}},"CreatePatResponse":{"type":"object","required":["id","raw_token","token_prefix","name","organization_slug","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time","description":"When it stops working, if it has an expiry."},"id":{"type":"string"},"name":{"type":"string"},"organization_slug":{"type":"string"},"raw_token":{"type":"string","description":"The token itself. Send it as `Authorization: Bearer <token>`. This is\nthe only response that contains it, so store it securely now; if it is\nlost, revoke the token and create a new one."},"token_prefix":{"type":"string","description":"The start of the token, such as `str_pat_1a2b3c4d`, to help you\nrecognize it in a list."}}},"DefaultVersion":{"type":"object","required":["version","previous_version"],"properties":{"previous_version":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Version"}]},"version":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Version"}]}}},"DenyDeviceRequest":{"type":"object","required":["user_code"],"properties":{"user_code":{"type":"string"}}},"DeviceAuthorizationDetails":{"type":"object","required":["user_code","client_name","scope","expires_at"],"properties":{"client_name":{"type":"string","description":"The name the device gave itself. Anyone can choose it, so check that it\nmatches what you are signing in to."},"expires_at":{"type":"string","format":"date-time"},"scope":{"$ref":"#/components/schemas/DeviceScope"},"user_code":{"type":"string"}}},"DeviceCodeRequest":{"type":"object","required":["client_name"],"properties":{"client_name":{"type":"string","description":"Names the device or tool, such as \"str CLI on laptop\". The approver\nsees it, and it becomes the name of the resulting token."},"scope":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeviceScope","description":"What to ask for. Defaults to `execute`; ask for `read_only` when the\ntool only reads."}]}}},"DeviceCodeResponse":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","interval","expires_in"],"properties":{"device_code":{"type":"string","description":"Keep this secret on the device and send it to `POST /auth/device/token`."},"expires_in":{"type":"integer","format":"int64","description":"Seconds until the codes expire."},"interval":{"type":"integer","format":"int64","description":"Seconds to wait between polls."},"user_code":{"type":"string","description":"Show this to the user, such as `BCDF-GHJK`. They type it at\n`verification_uri`."},"verification_uri":{"type":"string","description":"Where the user approves the request."},"verification_uri_complete":{"type":"string","description":"`verification_uri` with the code filled in. Open it in the user's\nbrowser, or show it as a link or QR code."}}},"DeviceDecisionResponse":{"type":"object","required":["user_code","client_name","approved"],"properties":{"approved":{"type":"boolean"},"client_name":{"type":"string"},"user_code":{"type":"string"}}},"DeviceScope":{"type":"string","description":"What the device may do once approved:\n\n- `read_only`: read, with the `viewer` role.\n- `execute`: act with the approver's own role.","enum":["read_only","execute"]},"DeviceTokenError":{"type":"object","description":"The error body of `POST /auth/device/token`. It follows the OAuth device\nflow (RFC 8628) rather than the `{code, message}` body other routes use, so\nstandard OAuth clients understand it.","required":["error","error_description"],"properties":{"error":{"$ref":"#/components/schemas/DeviceTokenErrorCode"},"error_description":{"type":"string","description":"A human-readable explanation."},"interval":{"type":["integer","null"],"format":"int64","description":"With `slow_down`: the seconds to wait between polls from now on."}}},"DeviceTokenErrorCode":{"type":"string","description":"Why the device has no token yet:\n\n- `authorization_pending`: the user hasn't decided yet. Poll again after\n  `interval` seconds.\n- `slow_down`: you polled too soon. Wait the returned `interval`, which is\n  longer, between polls from now on.\n- `expired_token`: the codes expired before approval. Start over.\n- `access_denied`: the user denied the request. Stop polling.\n- `invalid_grant`: the `device_code` is unknown or its token was already\n  collected. Stop polling.\n- `unavailable`: a temporary failure on our side. Keep polling.","enum":["authorization_pending","slow_down","expired_token","access_denied","invalid_grant","unavailable"]},"DeviceTokenRequest":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string","description":"The `device_code` from `POST /auth/device/code`."}}},"DeviceTokenResponse":{"type":"object","required":["access_token","token_type","token_id","organization_slug","organization_name","account_email","scope","expires_at"],"properties":{"access_token":{"type":"string","description":"A personal access token, such as `str_pat_…`. Send it as\n`Authorization: Bearer <token>`. Store it securely: this is the only\nresponse that contains it."},"account_email":{"type":"string","description":"The email of the user who approved, and whom the token acts as."},"expires_at":{"type":"string","format":"date-time","description":"When the token stops working, 90 days after approval."},"organization_name":{"type":"string"},"organization_slug":{"type":"string","description":"The organization the token works in."},"scope":{"$ref":"#/components/schemas/DeviceScope"},"token_id":{"type":"string","description":"The token's `id`, for revoking it with `DELETE /auth/tokens/{pat_id}`."},"token_type":{"type":"string","description":"Always `Bearer`."}}},"Diagnostic":{"type":"object","description":"One problem in the script. Lines and columns start at 1.\n\n```json\n{\"severity\": \"error\", \"code\": 2322, \"message\": \"Type 'number' is not assignable to type 'string'.\",\n \"line\": 3, \"column\": 10, \"end_line\": 3, \"end_column\": 14}\n```","required":["severity","message","line","column"],"properties":{"code":{"type":["integer","null"],"format":"int32","description":"The TypeScript error number, such as 2322. Null when the problem has none.","minimum":0},"column":{"type":"integer","format":"int32","description":"The column where the problem starts.","minimum":0},"end_column":{"type":["integer","null"],"format":"int32","description":"The column where the problem ends. Null when the problem has no range in the source.","minimum":0},"end_line":{"type":["integer","null"],"format":"int32","description":"The line where the problem ends. Null when the problem has no range in the source.","minimum":0},"line":{"type":"integer","format":"int32","description":"The line where the problem starts.","minimum":0},"message":{"type":"string"},"severity":{"$ref":"#/components/schemas/DiagnosticSeverity"}}},"DiagnosticSeverity":{"type":"string","description":"How serious a diagnostic is. Only `error` means the script will not\ntypecheck.","enum":["error","warning","suggestion","message"]},"Draft":{"type":"object","required":["files"],"properties":{"commit":{"type":["string","null"]},"files":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}},"ExchangeRequest":{"type":"object","required":["organization_slug","ttl_seconds"],"properties":{"name":{"type":["string","null"],"description":"A label for a long-lived token, such as \"nightly-export\". It appears\nwhen tokens are listed, so name it after the job that uses it."},"organization_slug":{"type":"string","description":"The one organization the new token works in, such as `acme`."},"roles":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OrgRole"},"description":"Limit the new token to these roles, for example `[\"viewer\"]` for a\nread-only token. It gets the highest listed role that your current\ntoken also has. Leave it out to keep your current role."},"ttl_seconds":{"type":"integer","format":"int64","description":"How long the new token lasts, from 1 second to 2592000 (30 days). It\nnever outlasts the token you exchange."}}},"ExchangeResponse":{"type":"object","required":["kind","token","expires_at","organization"],"properties":{"expires_at":{"type":"string","format":"date-time"},"kind":{"$ref":"#/components/schemas/TokenKind","description":"`request` for a token of 5 minutes or less, otherwise `exchanged`."},"organization":{"$ref":"#/components/schemas/OrgGrant","description":"The organization the token works in, with the role it acts with."},"token":{"type":"string","description":"The new token. Send it as `Authorization: Bearer <token>`."}}},"ExecRequest":{"type":"object","required":["input"],"properties":{"input":{"description":"The script's input. It must match the version's `input_schema`."}}},"Execution":{"type":"object","description":"```json\n{\"version\": {\"major\": 1, \"minor\": 2, \"patch\": 0}, \"commit\": \"3f2a…\",\n \"output\": {\"summary\": \"…\"}, \"llm_call_count\": 1,\n \"calls\": [{\"index\": 0, \"kind\": \"infer\", \"label\": \"first\", \"model\": \"gpt-6\", \"cache_status\": \"miss\",\n            \"input_tokens\": 410, \"output_tokens\": 37, \"cost_usd\": 0.0012, \"latency_ms\": 1840,\n            \"finish_reason\": \"stop\", \"error_code\": null}],\n \"metrics\": {\"total_time_ms\": 1902, \"llm_time_ms\": 1840,\n             \"token_usage\": {\"prompt_tokens\": 410, \"completion_tokens\": 37, \"total_tokens\": 447},\n             \"cost_usd\": 0.0012, \"unknown_charge_calls\": 0}}\n```","required":["version","commit","output","calls","llm_call_count","metrics"],"properties":{"calls":{"type":"array","items":{"$ref":"#/components/schemas/Call"}},"commit":{"type":"string","description":"The source commit of that version."},"llm_call_count":{"type":"integer","format":"int32","minimum":0},"metrics":{"$ref":"#/components/schemas/Metrics"},"output":{"description":"The script's return value. It matches the version's `output_schema`."},"version":{"$ref":"#/components/schemas/Version","description":"The published version that ran."}}},"Files":{"type":"object","required":["commit","files"],"properties":{"commit":{"type":"string"},"files":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}},"Function":{"type":"object","required":["id","slug","name","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"created_by":{"type":["string","null"],"description":"The user who created it. Absent when an API key did."},"description":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string","description":"Unique in the organization. It addresses the function in URLs, and\nchanges only through `PATCH /{org_slug}/functions/{function}/slug`."},"updated_at":{"type":"string","format":"date-time"}}},"HealthResponse":{"type":"object","required":["status"],"properties":{"status":{"type":"string","description":"Always `ok`."}}},"InternalRole":{"type":"string","description":"A role on the str.ing team, which grants access beyond any one\norganization. Customers never hold one.","enum":["superuser","customer_support","billing_admin","developer"]},"InvitationDetails":{"type":"object","required":["organization_name","organization_slug","email","role","expires_at"],"properties":{"email":{"type":"string","description":"The address the invitation was sent to. Only someone signed in with it\ncan accept."},"expires_at":{"type":"string","format":"date-time"},"organization_name":{"type":"string"},"organization_slug":{"type":"string"},"role":{"$ref":"#/components/schemas/OrgRole","description":"The role they get on joining."}}},"InvitationListItem":{"type":"object","required":["id","email","role","created_at","expires_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"email":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"id":{"type":"string"},"role":{"$ref":"#/components/schemas/OrgRole"}}},"InviteRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","description":"The address to invite. Only someone signed in with this email can\naccept."},"role":{"$ref":"#/components/schemas/OrgRole","description":"The role they get on joining. Defaults to `member`. It can't be higher\nthan your own."}}},"InviteResponse":{"type":"object","required":["id","email","role","expires_at","invite_token"],"properties":{"email":{"type":"string"},"expires_at":{"type":"string","format":"date-time","description":"The invitation can be accepted until this time, 7 days after it was\nsent."},"id":{"type":"string"},"invite_token":{"type":"string","description":"Send this to the invitee, for example as a link that passes it to\n`POST /invitations/{token}/accept`. This is the only response that\ncontains it; if it is lost, revoke the invitation and invite again."},"role":{"$ref":"#/components/schemas/OrgRole"}}},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"},"remember_me":{"type":"boolean","description":"Keep the session for 30 days instead of 1."}}},"MemberResponse":{"type":"object","required":["user_id","email","role","joined_at"],"properties":{"email":{"type":"string"},"full_name":{"type":["string","null"]},"joined_at":{"type":"string","format":"date-time"},"role":{"$ref":"#/components/schemas/OrgRole"},"user_id":{"type":"string"}}},"Metrics":{"type":"object","required":["total_time_ms","llm_time_ms","token_usage","cost_usd","unknown_charge_calls"],"properties":{"cost_usd":{"type":["number","null"],"format":"double","description":"Sum of the known charges in USD; zero when no call cost anything, null\nonly when every call's charge is unknown."},"llm_time_ms":{"type":"integer","format":"int64","description":"Time the script spent waiting on models, summed over calls.","minimum":0},"token_usage":{"$ref":"#/components/schemas/TokenUsage"},"total_time_ms":{"type":"integer","format":"int64","description":"From receiving the request to answering it.","minimum":0},"unknown_charge_calls":{"type":"integer","format":"int32","description":"Calls whose charge is unknown and so not in `cost_usd`.","minimum":0}}},"OrgGrant":{"type":"object","description":"An organization, with the role you have in it.","required":["id","name","slug","role","is_personal"],"properties":{"id":{"type":"string"},"is_personal":{"type":"boolean","description":"Whether this is the user's own workspace, created with their account.\nA personal workspace has no other members."},"name":{"type":"string","description":"The display name, such as \"Acme Inc\"."},"role":{"$ref":"#/components/schemas/OrgRole","description":"The role you, or this token, act with here."},"slug":{"type":"string","description":"The short name used in URLs and requests, such as `acme`."}}},"OrgRole":{"type":"string","description":"A role in an organization. From most to least access:\n\n- `owner`: full control. Every organization has at least one.\n- `admin`: manages members, invitations and API keys.\n- `member`: uses the organization's resources.\n- `viewer`: read-only.","enum":["owner","admin","member","viewer"]},"PatListItem":{"type":"object","required":["id","token_prefix","name","organization_slug","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time","description":"When it stops working, if it has an expiry."},"id":{"type":"string"},"name":{"type":"string"},"organization_slug":{"type":"string"},"token_prefix":{"type":"string","description":"The start of the token, such as `str_pat_1a2b3c4d`, to help you\nrecognize it in a list."}}},"PublishOption":{"type":"object","required":["predecessor","required_bump","reasons","suggested_version"],"properties":{"predecessor":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Version"}]},"reasons":{"type":"array","items":{"type":"string"}},"required_bump":{"type":"string"},"suggested_version":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Version"}]}}},"PublishPreview":{"type":"object","required":["commit","options"],"properties":{"commit":{"type":"string"},"options":{"type":"array","items":{"$ref":"#/components/schemas/PublishOption"}}}},"PublishRequest":{"type":"object","required":["commit","version"],"properties":{"commit":{"type":"string"},"version":{"$ref":"#/components/schemas/Version"}}},"PublishedVersion":{"type":"object","required":["version","commit","principal_id","principal_kind","published_at"],"properties":{"commit":{"type":"string"},"principal_id":{"type":"string"},"principal_kind":{"$ref":"#/components/schemas/TokenKind"},"published_at":{"type":"string","format":"date-time"},"version":{"$ref":"#/components/schemas/Version"}}},"RegisterRequest":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string","description":"Used to sign in. Case doesn't matter."},"name":{"type":"string","description":"The user's full name, as other members of their organizations see it."},"password":{"type":"string","description":"At least 8 characters."}}},"SaveDraft":{"type":"object","required":["files"],"properties":{"base_commit":{"type":["string","null"],"description":"The commit from the last draft read, or null for the first save."},"files":{"type":"object","description":"Complete source tree, including function.json and prompt.hbs or main.ts.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}},"SavedDraft":{"type":"object","required":["commit"],"properties":{"commit":{"type":"string"}}},"SessionResponse":{"type":"object","required":["session_token","expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"When the session ends and the user must sign in again."},"session_token":{"type":"string","description":"The session token, such as `str_sess_…`. Send it as\n`Authorization: Bearer <token>`. Keep it secret: it acts as the user."}}},"SetDefault":{"type":"object","required":["version"],"properties":{"version":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Version","description":"Exact published version, or null to clear the default. Restore by sending previous_version."}]}}},"TokenKind":{"type":"string","description":"The type of a token. Each type starts with its own prefix, so you can tell\nwhich one you have:\n\n- `session` (`str_sess_…`): a signed-in user, from `POST /auth/login`.\n- `pat` (`str_pat_…`): a personal access token, acting as one user in one\n  organization.\n- `api_key` (`str_sk_…`): acts for an organization, not a person.\n- `exchanged` (`str_xt_…`): a narrower token from `POST /auth/exchange`,\n  lasting up to 30 days.\n- `request` (`str_rt_…`): a short-lived token from `POST /auth/exchange`,\n  tied to its source credential's revocation and expiry. Agent ingress uses JWT encoding.","enum":["session","pat","api_key","exchanged","request"]},"TokenUsage":{"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"properties":{"completion_tokens":{"type":["integer","null"],"format":"int64","minimum":0},"prompt_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens sent to models, summed over the calls that reported usage.\nNull only when no call reported it.","minimum":0},"total_tokens":{"type":["integer","null"],"format":"int64","minimum":0}}},"UpdateFunctionRequest":{"type":"object","properties":{"description":{"type":["string","null"],"description":"The new description, up to 2,000 characters. Blank removes it."},"name":{"type":["string","null"],"description":"The new display name, 1 to 100 characters. The slug doesn't change."}}},"VerifyResponse":{"type":"object","required":["user_id","email","email_verified","organizations","internal_roles"],"properties":{"avatar_url":{"type":["string","null"]},"email":{"type":"string"},"email_verified":{"type":"boolean"},"full_name":{"type":["string","null"]},"internal_roles":{"type":"array","items":{"$ref":"#/components/schemas/InternalRole"},"description":"Staff roles the user holds. Empty for everyone outside the str.ing team."},"organizations":{"type":"array","items":{"$ref":"#/components/schemas/OrgGrant"},"description":"Every organization the user belongs to, with their role in each."},"user_id":{"type":"string"}}},"Version":{"type":"object","description":"An exact version. Ordering compares major, then minor, then patch:\n\n```text\n1.9.3 < 1.10.0 < 2.0.0\n```","required":["major","minor","patch"],"properties":{"major":{"type":"integer","format":"int32","minimum":0},"minor":{"type":"integer","format":"int32","minimum":0},"patch":{"type":"integer","format":"int32","minimum":0}}},"WhoamiResponse":{"type":"object","required":["kind","token_id","organizations","internal_roles"],"properties":{"internal_roles":{"type":"array","items":{"$ref":"#/components/schemas/InternalRole"},"description":"Staff roles the token carries. Empty for everyone outside the str.ing team."},"kind":{"$ref":"#/components/schemas/TokenKind","description":"The type of token the request used."},"organizations":{"type":"array","items":{"$ref":"#/components/schemas/OrgGrant"},"description":"Every organization the token can act in, with its role in each."},"token_id":{"type":"string","description":"The token's `id`, as listed by `GET /auth/tokens` or\n`GET /{org_slug}/api-keys`."},"user_id":{"type":["string","null"],"description":"The user the token acts for. Absent for an API key, which acts for its\norganization rather than a person."}}}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer"}}}}