{"openapi":"3.1.0","info":{"title":"HeyMetra API","version":"0.1.0"},"paths":{"/health":{"get":{"tags":["health"],"summary":"Health","description":"Liveness only: the process is running and can answer. Asserts nothing\nabout the database, the schema or Redis — ``/health/ready`` does that.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Health Health Get"}}}}}}},"/health/ready":{"get":{"tags":["health"],"summary":"Readiness","description":"Readiness: reports each dependency separately *and* refuses with 503.\n\nThe per-dependency detail is kept because it is what turns a red probe into\na diagnosis. The status code is what an orchestrator acts on, so it is no\nlonger always 200.","operationId":"readiness_health_ready_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Readiness Health Ready Get"}}}}}}},"/health/integrations":{"get":{"tags":["health"],"summary":"Integrations","description":"Per-provider state, from what was last recorded — never from a live call.\n\nAlways 200 unless our own side is broken. A customer's expired token is\ntheir integration being red, not our service being down, and a monitor that\nwent red for it would be red permanently and therefore ignored.\n\nThat paragraph was true and the code did not honour it. The top-level\n``status`` carried the worst CUSTOMER-side state, so one connection needing\na reconnect reported the whole product as down — measured on 2026-09-23,\nwhen it did exactly that and the uptime monitor called HeyMetra DOWN over a\nsingle WooCommerce connection that was waiting to be re-entered.\n\nThe same promise had a second half it was not keeping: \"always 200 UNLESS\nour own side is broken\". A side that could not read its own state answered\n200 with the word ``unknown`` in the body, so an uptime check had to be\nconfigured to read the body to notice — and a check that needs the right\nkeyword configured is a check that is one edit away from watching nothing.\nIt refuses with 503 now, which is what ``/health/ready`` above already does\nand what its own test says out loud: an orchestrator reads the status code,\nnot the word in the body.\n\nSo the two are separate now. ``status`` is about US and takes one of two\nvalues: ``ok``, or ``unknown`` when this endpoint cannot read its own\nstate. ``connections`` is about the customers, in the same vocabulary as\nthe per-provider map below, so nothing is lost by the split.\n\nDeliberately carries no counts, no account ids, no names and no figures.\nThe endpoint is unauthenticated, like the probes above, and \"how many\nShopify stores are connected\" is nobody's business but ours.","operationId":"integrations_health_integrations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Integrations Health Integrations Get"}}}}}}},"/health/mcp":{"get":{"tags":["health"],"summary":"Mcp Surface","description":"Whether the tool surface actually built, and how wide it is.\n\nThe failure the owner suspected all day and nothing could confirm or deny:\na registry that came up empty after a deploy would serve an MCP endpoint\nwith no tools on it, and every client would report that its tools had\nvanished — which is exactly what he was seeing, for an unrelated reason.\nNothing reported the registry's size, so the suspicion could not be settled.\n\nIn-process and free: it counts what this container imported at startup.\nA count of zero is our fault and says so with a 503, because a surface with\nno tools is not a surface.","operationId":"mcp_surface_health_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Mcp Surface Health Mcp Get"}}}}}}},"/api/account":{"patch":{"tags":["account"],"summary":"Update Name","description":"Set this person's name. Keycloak first, the mirror only if that lands.\n\nWritten in that order on purpose: if the Admin API call fails, nothing is\never written to the user row, so the row and Keycloak cannot disagree about\nwhose name is current.","operationId":"update_name_api_account_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountNameIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountNameOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/resend-verification":{"post":{"tags":["auth"],"summary":"Resend Verification","operationId":"resend_verification_api_auth_resend_verification_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResendVerificationOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connections":{"get":{"tags":["connections"],"summary":"List All","operationId":"list_all_api_connections_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionStatusOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connections/{provider}/session":{"post":{"tags":["connections"],"summary":"Create Session","description":"Mint the token the browser uses to open the provider's own consent screen.\n\nOnly owners and admins may start this: connecting an account is what decides\nwhat the agent can see for everyone in the tenant.","operationId":"create_session_api_connections__provider__session_post","parameters":[{"name":"provider","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Provider"}},{"name":"write","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Write"}},{"name":"marketplace","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marketplace"}},{"name":"store_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Store Name"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectSessionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connections/ikas/callback":{"get":{"tags":["connections"],"summary":"Ikas Callback","description":"Where ikas returns the browser: verify, exchange, vault, record.\n\nPublic by necessity — the browser arrives from ikas, not from our app — so\neverything it trusts is checked: ikas's HMAC over the code, and a state we\nissued, once, for this store. Every outcome goes back to the Connections\nscreen with a word it can show.","operationId":"ikas_callback_api_connections_ikas_callback_get","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":"string","default":"","title":"Code"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","default":"","title":"State"}},{"name":"signature","in":"query","required":false,"schema":{"type":"string","default":"","title":"Signature"}},{"name":"storeName","in":"query","required":false,"schema":{"type":"string","default":"","title":"Storename"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connections/{provider}/api-key":{"post":{"tags":["connections"],"summary":"Connect Api Key","description":"Connect a custom (API-key) source, e.g. Adapty.\n\nThere is no OAuth popup: the customer pastes their secret key, the backend\nimports it into Nango's vault, then proves it works before saving anything.\nA key that Nango accepts but the provider rejects must not leave a live\nconnection behind, so a failed verification rolls the stored key back.","operationId":"connect_api_key_api_connections__provider__api_key_post","parameters":[{"name":"provider","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Provider"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyConnectIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connections/telegram/link":{"post":{"tags":["connections"],"summary":"Link Telegram","description":"Hand back a one-time deep link the customer taps in their own bot.\n\nTelegram has no OAuth, so ownership of a chat is proved by the customer\nsending the bot a code only this tenant could have been given. The webhook\nconsumes it and records the chat id on the connection.","operationId":"link_telegram_api_connections_telegram_link_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelegramInviteOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connections/{connection_id}/test":{"post":{"tags":["connections"],"summary":"Send Test Message","description":"Send a real message to a connected channel, and report what came back.\n\nA connection can look healthy and still reach nothing — a bot whose chat\nwas never linked, a Slack channel the app was removed from. Finding that out\nwhen it matters is the worst way to find out, so this pushes a real call and\nsurfaces the provider's own answer.\n\nGated, since ZEISO-248. It had no role check at all: a VIEWER could make\nHeyMetra post a real message into the customer's Slack channel, Telegram\nchat or mailbox — the one thing ``slack_send_message`` refuses them at\n``core/policy.py`` step 6, reachable by another door. Measured 2026-09-15\nby handing this endpoint a provider double that raises when touched, from a\nviewer's context; the double was touched.","operationId":"send_test_message_api_connections__connection_id__test_post","parameters":[{"name":"connection_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Connection Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelTestOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connections/{provider}/accounts":{"get":{"tags":["connections"],"summary":"Discover Accounts","description":"Ask the provider what this grant can actually reach.\n\nRun once, right after consent. The customer picks from this list; nothing\nlater in the product ever calls it again.","operationId":"discover_accounts_api_connections__provider__accounts_get","parameters":[{"name":"provider","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Provider"}},{"name":"nango_connection_id","in":"query","required":true,"schema":{"type":"string","title":"Nango Connection Id"}},{"name":"write","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Write"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoveredAccountsOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["connections"],"summary":"Select Accounts","description":"Persist the customer's choice.\n\nThe account ids are re-fetched from the provider rather than trusted from\nthe request: a browser could otherwise post an id this grant does not cover.","operationId":"select_accounts_api_connections__provider__accounts_post","parameters":[{"name":"provider","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Provider"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectAccountsIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionOut"},"title":"Response Select Accounts Api Connections  Provider  Accounts Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connections/{connection_id}":{"patch":{"tags":["connections"],"summary":"Update Connection","description":"Everything about a connection the customer can change without redoing it.\n\nIts name, its credentials, and who in the workspace may use it. One\nendpoint because they are one screen:\nthe pencil on a connection row opens an editor, and an editor that could\nonly rename was the complaint that opened ZEISO-426 — *\"emaili connector\nolarak bağlayınca bir daha hiçbir şeyi düzenleyemiyoruz\"*. Rotating a key\nmeant deleting the connection and building a new one, which loses the row\nand everything pointing at it.\n\nWho may: whoever holds ``read_write`` on THIS connection. See\n``_changeable_connection`` for why that is not the workspace-wide question\nit used to be.","operationId":"update_connection_api_connections__connection_id__patch","parameters":[{"name":"connection_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Connection Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConnectionIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["connections"],"summary":"Remove Connection","description":"Archive the connection and revoke the grant.\n\nThe row is kept — the audit trail refers to it, and \"undo\" has to remain\npossible (plan §2.5). What is destroyed is the token, at Nango.","operationId":"remove_connection_api_connections__connection_id__delete","parameters":[{"name":"connection_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Connection Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connections/{connection_id}/consent":{"post":{"tags":["connections"],"summary":"Record Consent","description":"Accept the widened ask, where the provider has nothing left to grant.\n\nThe other half of the offer ``core/reconsent.py`` makes. When a version bump\nwidened only what we do with scopes the customer already granted, the token\nneeds nothing and sending them round an OAuth trip would be asking them to\nclick for nothing — so this records the agreement and stops the offer.\n\nIt refuses, hard, when the bump widened the provider grant. No token we hold\ncarries a scope the customer never granted, and no row we write changes\nthat: stamping the version there would manufacture exactly the consent\nrecord that keeping ``consent_version`` NULL was refusing to manufacture.\nThe reconnect flow is what records that one, because the provider is what\ngrants it.\n\nOwner only: agreeing to a wider ask on the workspace's behalf is the same\nact as connecting the account in the first place.","operationId":"record_consent_api_connections__connection_id__consent_post","parameters":[{"name":"connection_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Connection Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/connectors":{"get":{"tags":["connectors"],"summary":"List Connectors","description":"The public connector catalog: categories in display order + every connector.\n\nUnauthenticated by design — the same list the app's Connections screen and\nthe marketing integrations pages render, from one backend source.\n\nThe catalog is the default and a superadmin override wins (ZEISO-286): a\nconnector switched off is omitted entirely rather than listed as closed,\nbecause this payload is the whole of what the dashboard and the marketing\nsite know about. The session is read for that one fact and for nothing else,\nwhich is why an endpoint with no login in front of it now touches the\ndatabase — one small query against a table that is empty in normal\noperation.\n\n**The marketing site fetches this at BUILD time**, so a deactivation reaches\nheymetra.com only on the next rebuild. The app fetches it at runtime and\nchanges immediately.","operationId":"list_connectors_api_connectors_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Connectors Api Connectors Get"}}}}}}},"/api/connectors/{connector_key}/consent":{"get":{"tags":["connectors"],"summary":"Connector Consent","description":"Everything this connector asks for, scopes included — for a member.\n\nAuthenticated, where the public catalog is not, and the scope list is the\nwhole reason for the difference. Showing a customer the exact strings they\nare about to grant is the point of this endpoint; publishing them to anyone\nwho asks would describe the shape of every token we hold, for every\ncustomer, from an endpoint with no login in front of it.\n\nThe workspace is not used to decide the answer — a connector asks the same\nthing of everyone — only to decide that there is one.","operationId":"connector_consent_api_connectors__connector_key__consent_get","parameters":[{"name":"connector_key","in":"path","required":true,"schema":{"type":"string","title":"Connector Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connector Consent Api Connectors  Connector Key  Consent Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp-clients":{"get":{"tags":["mcp-clients"],"summary":"List Clients","description":"Every MCP client the caller has let in.","operationId":"list_clients_api_mcp_clients_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/McpClientOut"},"title":"Response List Clients Api Mcp Clients Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mcp-clients/{client_id}":{"delete":{"tags":["mcp-clients"],"summary":"Revoke Client","description":"Cut this client off from the caller's account.\n\nAnyone may revoke their own grant; nobody may revoke somebody else's\n(ZEISO-545).","operationId":"revoke_client_api_mcp_clients__client_id__delete","parameters":[{"name":"client_id","in":"path","required":true,"schema":{"type":"string","title":"Client Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/usage":{"get":{"tags":["usage"],"summary":"Usage","operationId":"usage_api_usage_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/plans":{"get":{"tags":["usage"],"summary":"Plans","description":"The self-serve pricing catalogue (starter/pro/superior); enterprise is contact-us.","operationId":"plans_api_plans_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PlanOut"},"title":"Response Plans Api Plans Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/checkout":{"post":{"tags":["billing"],"summary":"Checkout","description":"Open a hosted checkout for the caller's workspace on the chosen plan.\n\n``tier=enterprise`` pays the offer an admin staged on this workspace; any\nother tier on an Enterprise workspace is refused.","operationId":"checkout_api_billing_checkout_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/change-plan":{"post":{"tags":["billing"],"summary":"Change Plan","description":"Switch plans. An active subscriber is moved in place (prorated) at the\nprovider; a workspace with no live subscription gets a checkout link.","operationId":"change_plan_api_billing_change_plan_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePlanIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePlanOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/checkout/{session_id}":{"get":{"tags":["billing"],"summary":"Checkout Status","description":"What became of a checkout this workspace opened.\n\nA failed first payment never reaches the workspace (no subscription is\nstored, so no event moves it), so the session is the only place it can be\nread. A session another workspace opened, or one older than a day, is not\nfound.","operationId":"checkout_status_api_billing_checkout__session_id__get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,128}$","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutStatusOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/portal":{"post":{"tags":["billing"],"summary":"Portal","description":"A link to the provider's customer portal, where the subscription is\ncancelled, resumed and its card and invoices managed.\n\nOpened for the billing customer stored on THIS workspace. One person paying\nfor several workspaces shares one customer, so the portal lists all of\nthem; a workspace that never paid has no customer and is refused rather\nthan handed the one its owner has elsewhere.","operationId":"portal_api_billing_portal_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/trial-eligibility":{"get":{"tags":["billing"],"summary":"Trial Eligibility","description":"Whether the dashboard may say \"Try free for N days\" to this person.\n\nAnswered by the same function checkout asks, per workspace and per person,\nso the button never offers a trial the checkout then does not carry. The\ntier does not change the answer for a self-serve plan; Starter stands in.","operationId":"trial_eligibility_api_billing_trial_eligibility_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrialEligibilityOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/pricing/plans":{"get":{"tags":["pricing"],"summary":"Pricing Plans","description":"The public plan catalogue: a month + annual row per tier.\n\nUnauthenticated by design — this is the same list the public pricing page\nprints, consumed by the marketing site's build-time fetch.","operationId":"pricing_plans_api_pricing_plans_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Pricing Plans Api Pricing Plans Get"}}}}}}},"/api/waitlist":{"post":{"tags":["waitlist"],"summary":"Join Waitlist","operationId":"join_waitlist_api_waitlist_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"boolean"},"type":"object","title":"Response Join Waitlist Api Waitlist Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/csp-report":{"post":{"tags":["csp"],"summary":"Csp Report","operationId":"csp_report_api_csp_report_post","responses":{"204":{"description":"Successful Response"}}}},"/api/approvals":{"get":{"tags":["approvals"],"summary":"Index","operationId":"index_api_approvals_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApprovalOut"},"title":"Response Index Api Approvals Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/approvals/{approval_id}":{"get":{"tags":["approvals"],"summary":"Show","operationId":"show_api_approvals__approval_id__get","parameters":[{"name":"approval_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Approval Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalStateOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/approvals/{approval_id}/approve":{"post":{"tags":["approvals"],"summary":"Approve","operationId":"approve_api_approvals__approval_id__approve_post","parameters":[{"name":"approval_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Approval Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecisionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/approvals/{approval_id}/reject":{"post":{"tags":["approvals"],"summary":"Reject","operationId":"reject_api_approvals__approval_id__reject_post","parameters":[{"name":"approval_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Approval Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecisionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/approvals/{approval_id}/undo":{"post":{"tags":["approvals"],"summary":"Undo","operationId":"undo_api_approvals__approval_id__undo_post","parameters":[{"name":"approval_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Approval Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DecisionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/team":{"get":{"tags":["team"],"summary":"Get Team","operationId":"get_team_api_team_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/team/invites":{"post":{"tags":["team"],"summary":"Create Invite","operationId":"create_invite_api_team_invites_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/team/invites/{invitation_id}":{"delete":{"tags":["team"],"summary":"Revoke Invite","operationId":"revoke_invite_api_team_invites__invitation_id__delete","parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/team/members/{user_id}":{"patch":{"tags":["team"],"summary":"Set Role","operationId":"set_role_api_team_members__user_id__patch","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["team"],"summary":"Remove Member","operationId":"remove_member_api_team_members__user_id__delete","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/team/invites/{token}/preview":{"get":{"tags":["team"],"summary":"Preview Invite","description":"Public: what this invitation is, and whether it can still be used.\n\nRate limited per IP because it is the only unauthenticated endpoint here\nthat reads a secret from the URL. The tokens are 32 random bytes, so\nguessing one is not a realistic attack — but an endpoint that answers\nunlimited guesses is worth throttling on principle rather than on\narithmetic, and the same limit stops it being used to hammer the database.","operationId":"preview_invite_api_team_invites__token__preview_get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitePreviewOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/team/invites/{token}/accept":{"post":{"tags":["team"],"summary":"Accept Invite","description":"Join the workspace this invitation names, as the person signed in now.\n\nTwo things have to agree and neither is enough alone. The **token** proves\nthe caller was sent this particular link. The **address** proves they are\nthe person it was sent to — checked against the address the identity\nprovider verified, never against anything in the request — so forwarding\nthe mail to somebody else does not hand them the workspace.\n\nUntil this existed the token was decoration: it travelled in the URL and\nthe sign-up screen read it only to prefill an email field. Joining depended\nentirely on an address matching at first sign-in, which is why an\ninvitation sent to somebody who already had an account could never be\napplied (measured in production, 2026-09-14).","operationId":"accept_invite_api_team_invites__token__accept_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptedOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/me/invitations":{"get":{"tags":["session"],"summary":"List Invitations","operationId":"list_invitations_api_me_invitations_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingInvitationOut"},"title":"Response List Invitations Api Me Invitations Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/me/invitations/{invitation_id}/accept":{"post":{"tags":["session"],"summary":"Accept Invitation","operationId":"accept_invitation_api_me_invitations__invitation_id__accept_post","parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptedOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/me/invitations/{invitation_id}/decline":{"post":{"tags":["session"],"summary":"Decline Invitation","operationId":"decline_invitation_api_me_invitations__invitation_id__decline_post","parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workspace":{"delete":{"tags":["workspace"],"summary":"Close This Workspace","description":"Close the workspace being acted for, permanently.\n\nThe workspace is the one the request is already scoped to — a caller\nswitches into a workspace to close it. That is not ceremony: the role that\ndecides whether they may is the role they hold *there*, and reading it from\nthe context is what makes it impossible to close a workspace using an\nadmin's rights somewhere else.","operationId":"close_this_workspace_api_workspace_delete","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloseWorkspaceIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClosureOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["workspace"],"summary":"Get Workspace","operationId":"get_workspace_api_workspace_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["workspace"],"summary":"Update Workspace","operationId":"update_workspace_api_workspace_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workspace/attribution":{"put":{"tags":["workspace"],"summary":"Record Attribution","description":"Store the ad click ids the workspace arrived with.\n\nCalled by the app once a session resolves, because the values live in\nfirst-party cookies the browser holds and the webhook that later confirms a\nsubscription has no browser to read them from.\n\nWritten once and never overwritten. Any member of the workspace may call it\n— this is not privileged data and the first user through the door is\nusually the one who clicked the ad. A call carrying nothing is a no-op\nrather than an error: most sessions have no click ids to report.\n\nBeside the click ids it keeps what an ad platform needs to match a\nconversion the server reports (ZEISO-526 §2.5): the browser's user agent\nand IP, read from the request itself and never from the body, so the\nbrowser cannot claim them; the consent the site recorded; and who\ncaptured it. A ``sign_up`` still waiting for these is completed and sent.","operationId":"record_attribution_api_workspace_attribution_put","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttributionIn"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workspaces":{"post":{"tags":["workspace"],"summary":"Create Workspace","description":"Open another workspace and move into it.\n\nANYBODY MAY, and that reverses the ruling of 2026-09-14 (\"sadece adminler\nworkspace ekleyebilmeli ve silebilmeli\") on the owner's instruction of\n2026-09-20. The reasoning: a role says what somebody may do INSIDE a\nworkspace, and opening a new one is not something that workspace has any\nstake in. Being invited to a customer's team as a member should not stop a\nperson using the product for their own work — which is what the old gate\ndid, silently, by hiding the control rather than refusing it.\n\nThey become the OWNER of what they create, whatever role they hold where\nthey are standing. Closing a workspace is a different question and keeps\nits own gate.\n\nSwitching into it is part of creating it: a new workspace you are not\nlooking at is indistinguishable from nothing having happened.","operationId":"create_workspace_api_workspaces_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewWorkspaceIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewWorkspaceOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workspace/activity":{"get":{"tags":["activity"],"summary":"Workspace Activity","description":"This workspace's tool calls, newest first, within a bounded window.\n\nThe workspace is the one the request is acting for — read from the context\nlike every other endpoint here, never from the path or the query string, so\nnaming somebody else's workspace is not a thing this route can be asked to\ndo.","operationId":"workspace_activity_api_workspace_activity_get","parameters":[{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Since"}},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Until"}},{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"}},{"name":"mcp_session_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mcp Session Id"}},{"name":"outcome","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ToolResultStatus"},{"type":"null"}],"title":"Outcome"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityPageOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/skills":{"get":{"tags":["admin"],"summary":"List Connector Skills","description":"Every connector and the instructions it ships, in catalogue order.","operationId":"list_connector_skills_api_admin_skills_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectorSkillOut"},"title":"Response List Connector Skills Api Admin Skills Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/workspaces":{"get":{"tags":["admin"],"summary":"List Workspaces","operationId":"list_workspaces_api_admin_workspaces_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WorkspaceRow"},"title":"Response List Workspaces Api Admin Workspaces Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/workspaces/{tenant_id}/grant-enterprise":{"post":{"tags":["admin"],"summary":"Grant Enterprise","description":"Move a workspace onto a custom enterprise plan with bespoke limits.\n\nPayment is handled outside self-serve: either a provider subscription created for\nthe deal (link it via billing_subscription_id so renewals sync) or an off-platform\ninvoice (leave it unset — a manual grant renewed by hand).","operationId":"grant_enterprise_api_admin_workspaces__tenant_id__grant_enterprise_post","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantEnterpriseIn"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/workspaces/{tenant_id}/enterprise":{"patch":{"tags":["admin"],"summary":"Edit Enterprise","description":"Change what an existing enterprise workspace gets (ZEISO-280).\n\nThe only enterprise action used to be \"set a NEW plan\", so changing one\nceiling on a workspace already on enterprise meant re-granting the whole\nthing — and ``grant_enterprise`` demands a period end, resets the billing\nperiod and clears a scheduled cancellation. A superadmin adding a seat was\nmoving a renewal date.\n\nThe body is the create path's own model (``EnterpriseLimitsIn``), so there\nis one place the bounds are written. Refused with 409 for a workspace on a\nself-serve tier: those limits come from the catalogue.\n\nRecorded in ``admin_audit_log`` with both sides of every ceiling it moved\n(ZEISO-302). The note that used to stand here said there was no admin audit\ntable and that a ``logger.info`` was the whole trail; there is one now, and\nthe log line is kept only as operator-visible noise beside it.","operationId":"edit_enterprise_api_admin_workspaces__tenant_id__enterprise_patch","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnterpriseLimitsIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceRow"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/workspaces/{tenant_id}/enterprise-checkout":{"post":{"tags":["admin"],"summary":"Enterprise Checkout","description":"Stage a bespoke enterprise offer and return a checkout link for the customer.\n\nCreates a bespoke price at the negotiated amount with the payment provider,\nstages the limits on the workspace (no access yet), and opens a checkout\nbilled to the workspace owner. The admin sends the returned URL to the\ncustomer; paying it fires the webhook that activates the plan.","operationId":"enterprise_checkout_api_admin_workspaces__tenant_id__enterprise_checkout_post","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnterpriseCheckoutIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnterpriseCheckoutOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/modules":{"get":{"tags":["admin"],"summary":"List Modules","description":"Every module HeyMetra ships, with what the catalog says and what is in force.","operationId":"list_modules_api_admin_modules_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModuleOut"},"title":"Response List Modules Api Admin Modules Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/modules/{connector_key}":{"put":{"tags":["admin"],"summary":"Set Module Availability","description":"Move one module to available, soon, or off.\n\nRecorded twice over: ``set_by`` on the override row says who holds the\ncurrent state, and ``admin_audit_log`` says who moved it and from what\n(ZEISO-302). The second is the one that answers \"who took Trendyol down on\nTuesday\", because the first is overwritten by whoever changes it next.","operationId":"set_module_availability_api_admin_modules__connector_key__put","parameters":[{"name":"connector_key","in":"path","required":true,"schema":{"type":"string","title":"Connector Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleAvailabilityIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin"],"summary":"Clear Module Availability","description":"Hand one module back to the catalog's own availability.","operationId":"clear_module_availability_api_admin_modules__connector_key__delete","parameters":[{"name":"connector_key","in":"path","required":true,"schema":{"type":"string","title":"Connector Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/audit":{"get":{"tags":["admin"],"summary":"List Audit","description":"What platform staff have done, newest first.\n\nTwo filters, because they are the two questions that follow \"what\nhappened\": what was done to this customer, and every time this kind of thing\nwas done. Filtering by actor is available in the library and not published\nhere — the screen has no picker for it, and an endpoint nothing calls is an\nendpoint nothing checks.","operationId":"list_audit_api_admin_audit_get","parameters":[{"name":"action","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/AdminAction"},{"type":"null"}],"title":"Action"}},{"name":"tenant_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Tenant Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditEntryOut"},"title":"Response List Audit Api Admin Audit Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/feedback":{"get":{"tags":["admin"],"summary":"List Feedback","description":"Every workspace's requests and reports, newest first.\n\n``state=new`` is the working queue; without a filter it is the whole\nhistory.","operationId":"list_feedback_api_admin_feedback_get","parameters":[{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/FeedbackState"},{"type":"null"}],"title":"State"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FeedbackOut"},"title":"Response List Feedback Api Admin Feedback Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/feedback/{note_id}":{"patch":{"tags":["admin"],"summary":"Update Feedback","operationId":"update_feedback_api_admin_feedback__note_id__patch","parameters":[{"name":"note_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Note Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackPatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/webhooks/dodo":{"post":{"tags":["webhooks"],"summary":"Payment Webhook","description":"The provider's delivery endpoint.\n\nThe path still says \"dodo\" because it is registered with the live provider\nand changing it would silently stop every subscription event until someone\nre-registered the endpoint. The handler behind it is provider-neutral.","operationId":"payment_webhook_api_webhooks_dodo_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/webhooks/telegram/{connection_id}/{signature}":{"post":{"tags":["webhooks"],"summary":"Telegram Update","description":"Receive one customer bot's updates.\n\nUnauthenticated by necessity — Telegram delivers to a URL, not a session.\nTwo independent checks stand in front: the signature in the path and the\nsecret token Telegram echoes back in a header. Both run before any database\nwork, and a failure never reveals whether the connection exists.\n\nAnything past verification answers 200, even when it is ignored: Telegram\nretries non-2xx, and retrying a delivery that can never succeed is noise.","operationId":"telegram_update_api_webhooks_telegram__connection_id___signature__post","parameters":[{"name":"connection_id","in":"path","required":true,"schema":{"type":"string","title":"Connection Id"}},{"name":"signature","in":"path","required":true,"schema":{"type":"string","title":"Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Telegram Update Api Webhooks Telegram  Connection Id   Signature  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/webhooks/ikas":{"post":{"tags":["webhooks"],"summary":"Ikas Webhook","description":"Everything ikas sends to the app's Webhook URL (ZEISO-951).\n\nTwo kinds matter. `store/app/deleted`: the store removed HeyMetra, so its\nconnections close and both halves of the grant are destroyed. And the\nrequest ikas sends 48 hours later to delete that store's customers'\npersonal data: HeyMetra keeps none — answers are read live and cached for\nat most a minute — so it is acknowledged and recorded. Any other signed\ndelivery is acknowledged too, because ikas retries a non-200 three times.\n\nThe body is `{id, createdAt, scope, merchantId, authorizedAppId, data,\nsignature}`; `signature` is HMAC-SHA256 of `data` with our client secret.\nUnsigned is unanswered: 401, nothing touched.","operationId":"ikas_webhook_api_webhooks_ikas_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/webhooks/meta/deauthorize":{"post":{"tags":["webhooks"],"summary":"Meta Deauthorize","description":"Somebody removed HeyMetra from their Facebook settings. Let the grant go.\n\nUntil this existed there was no path at all: `deauth_callback_url` was empty\non the Meta app, and nothing in the code base read a `signed_request`\n(ZEISO-481). A customer who revoked the app at Facebook left a live-looking\nconnection here and a credential in the vault, and nobody was told. Our own\n/data-protection/ page says disconnecting destroys the credential\nimmediately; this is the door that sentence did not cover, and Meta's\nPlatform Terms ask for the data to go when the access does.\n\nUNVERIFIED IS NOT ACKNOWLEDGED. The whole message is the signature, and\nnothing else in the request says who sent it — so an endpoint that answered\n200 to an unsigned body would be an endpoint anybody could use to disconnect\na stranger's accounts. A refusal is 401 and stores nothing.\n\nMeta wants 200 for a delivery it signed, including one that matches no\nconnection of ours: \"we have nothing for this person\" is a completed\ninstruction, not a failure, and an error would put the delivery back in\nMeta's retry queue forever.","operationId":"meta_deauthorize_api_webhooks_meta_deauthorize_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/me":{"get":{"tags":["session"],"summary":"Me","operationId":"me_api_me_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/me/workspace/{tenant_id}":{"post":{"tags":["session"],"summary":"Switch Workspace","description":"Act for a different workspace from now on.\n\n404 rather than 403 when the caller has no membership there: a\nworkspace they cannot reach and one that does not exist should be\nindistinguishable, or the endpoint answers \"that workspace exists\" to\nanyone who guesses an id.","operationId":"switch_workspace_api_me_workspace__tenant_id__post","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-workspace-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Workspace-Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/.well-known/oauth-authorization-server/mcp":{"get":{"tags":["oauth-discovery"],"summary":"Oauth Authorization Server","operationId":"oauth_authorization_server__well_known_oauth_authorization_server_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Oauth Authorization Server  Well Known Oauth Authorization Server Mcp Get"}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"tags":["oauth-discovery"],"summary":"Oauth Authorization Server","operationId":"oauth_authorization_server__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Oauth Authorization Server  Well Known Oauth Authorization Server Get"}}}}}}},"/.well-known/openid-configuration/mcp":{"get":{"tags":["oauth-discovery"],"summary":"Openid Configuration","operationId":"openid_configuration__well_known_openid_configuration_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Openid Configuration  Well Known Openid Configuration Mcp Get"}}}}}}},"/.well-known/openid-configuration":{"get":{"tags":["oauth-discovery"],"summary":"Openid Configuration","operationId":"openid_configuration__well_known_openid_configuration_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Openid Configuration  Well Known Openid Configuration Get"}}}}}}}},"components":{"schemas":{"AcceptedOut":{"properties":{"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"tenant_name":{"type":"string","title":"Tenant Name"},"role":{"$ref":"#/components/schemas/UserRole"}},"type":"object","required":["tenant_id","tenant_name","role"],"title":"AcceptedOut"},"AccountNameIn":{"properties":{"first_name":{"type":"string","maxLength":100,"minLength":1,"title":"First Name"},"last_name":{"type":"string","maxLength":100,"minLength":1,"title":"Last Name"}},"type":"object","required":["first_name","last_name"],"title":"AccountNameIn"},"AccountNameOut":{"properties":{"first_name":{"type":"string","title":"First Name"},"last_name":{"type":"string","title":"Last Name"}},"type":"object","required":["first_name","last_name"],"title":"AccountNameOut"},"ActivityPageOut":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/ActivityRowOut"},"type":"array","title":"Rows"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"},"window_start":{"type":"string","format":"date-time","title":"Window Start"},"window_end":{"type":"string","format":"date-time","title":"Window End"}},"type":"object","required":["rows","next_cursor","window_start","window_end"],"title":"ActivityPageOut"},"ActivityRowOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"at":{"type":"string","format":"date-time","title":"At"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"user_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Email"},"client":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client"},"mcp_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mcp Session Id"},"tool":{"type":"string","title":"Tool"},"is_write":{"type":"boolean","title":"Is Write"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"connection_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Connection Id"},"connection_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Connection Label"},"duration_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration Ms"},"outcome":{"$ref":"#/components/schemas/ToolResultStatus"},"failure_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Kind"},"error_status":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Error Status"},"error_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Type"}},"type":"object","required":["id","at","user_id","user_email","client","mcp_session_id","tool","is_write","provider","connection_id","connection_label","duration_ms","outcome","failure_kind","error_status","error_type"],"title":"ActivityRowOut","description":"One tool call: when, who, what, against which account, and how it ended.\n\nDeliberately no argument keys and no byte sizes. The stored row carries the\n*shape* of a call and never its contents, and the reader stays narrower\nstill — leaving no field here for a value to be added to later."},"AdminAction":{"type":"string","enum":["skill.create","skill.import","skill.update","skill.delete","enterprise.grant","enterprise.edit","enterprise.checkout","module.set","module.reset"],"title":"AdminAction","description":"What a superadmin did, as the audit trail names it (ZEISO-302).\n\nA closed vocabulary rather than free text. An audit table whose ``action``\ncolumn is whatever the last caller typed cannot be filtered, cannot be\ncounted, and cannot be read a year later by somebody who does not know which\nspellings were in use that month.\n\nThe rule for membership: **an action belongs here when it changes what a\ncustomer gets or sees.** That is why feedback triage is absent — moving a\nnote from new to triaged changes nothing on the customer's side, and it is\nalso the highest-volume thing staff do here, so logging it would bury the\nfour actions that matter. ``tests/test_admin_audit.py`` enumerates the\nrouter and fails if a new writing endpoint is neither audited nor\ndeliberately excluded.\n\nThe names are ``subject.verb`` so that filtering by prefix is filtering by\nsubject, and they are persisted as strings: adding one is a code change, not\na migration that rewrites a type."},"AdminSubject":{"type":"string","enum":["workspace","module","skill"],"title":"AdminSubject","description":"What an admin action was done to.\n\nThree, because the id in ``subject_id`` is three different kinds of thing: a\nworkspace uuid, a connector key, a skill uuid. Storing the kind beside it is\nwhat lets a reader (and a query) tell them apart without guessing from the\nshape of the string."},"ApiKeyConnectIn":{"properties":{"credentials":{"additionalProperties":{"type":"string"},"type":"object","minProperties":1,"title":"Credentials"},"account_name":{"type":"string","maxLength":100,"minLength":1,"title":"Account Name"},"write_enabled":{"type":"boolean","title":"Write Enabled"},"shared_with_workspace":{"type":"boolean","title":"Shared With Workspace","default":false}},"type":"object","required":["credentials","account_name","write_enabled"],"title":"ApiKeyConnectIn","description":"The values a customer typed for a custom (API-key) connector, plus a name\nthey give the connection.\n\nKeys match the connector's ``credential_fields``. Secret values are stored\nin Nango's vault and never returned; they exist in this request and nowhere\nelse in the application. Non-secret values (a seller id) stay on our side.\nThe name is required and must be unique among the tenant's connections for\nthe same provider."},"ApprovalOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"tool_name":{"type":"string","title":"Tool Name"},"details":{"additionalProperties":true,"type":"object","title":"Details"},"mcp_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mcp Session Id"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","tool_name","details","mcp_session_id","expires_at","created_at"],"title":"ApprovalOut"},"ApprovalStateOut":{"properties":{"status":{"$ref":"#/components/schemas/ApprovalStatus"},"executed":{"type":"boolean","title":"Executed"},"undo_available":{"type":"boolean","title":"Undo Available"},"undo_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Undo Until"},"details":{"additionalProperties":true,"type":"object","title":"Details"},"tool_name":{"type":"string","title":"Tool Name"},"summary":{"type":"string","title":"Summary"}},"type":"object","required":["status","executed","undo_available","undo_until","details","tool_name","summary"],"title":"ApprovalStateOut"},"ApprovalStatus":{"type":"string","enum":["not_required","pending","approved","rejected"],"title":"ApprovalStatus"},"AssignableRoleOut":{"properties":{"value":{"$ref":"#/components/schemas/UserRole"},"label":{"type":"string","title":"Label"},"description":{"type":"string","title":"Description"}},"type":"object","required":["value","label","description"],"title":"AssignableRoleOut","description":"One role the screen may offer, with the words to offer it in."},"AttributionIn":{"properties":{"client_id":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Client Id"},"click_ids":{"additionalProperties":{"type":"string","maxLength":4096},"propertyNames":{"maxLength":64},"type":"object","maxProperties":32,"title":"Click Ids"}},"type":"object","title":"AttributionIn","description":"How the workspace found us, read by the app from first-party cookies."},"AuditEntryOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"actor_user_id":{"type":"string","title":"Actor User Id"},"actor_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Email"},"action":{"$ref":"#/components/schemas/AdminAction"},"subject_type":{"$ref":"#/components/schemas/AdminSubject"},"subject_id":{"type":"string","title":"Subject Id"},"subject_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subject Label"},"tenant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Tenant Id"},"before":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Before"},"after":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"After"},"changed":{"items":{"$ref":"#/components/schemas/FieldChangeOut"},"type":"array","title":"Changed"}},"type":"object","required":["id","created_at","actor_user_id","actor_email","action","subject_type","subject_id","subject_label","tenant_id","before","after","changed"],"title":"AuditEntryOut"},"BillingInterval":{"type":"string","enum":["monthly","annual"],"title":"BillingInterval"},"ChangePlanIn":{"properties":{"tier":{"$ref":"#/components/schemas/PlanTier"},"interval":{"$ref":"#/components/schemas/BillingInterval","default":"monthly"}},"type":"object","required":["tier"],"title":"ChangePlanIn"},"ChangePlanOut":{"properties":{"changed":{"type":"boolean","title":"Changed","default":false},"checkout_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checkout Url"},"mode":{"type":"string","title":"Mode","default":"live"},"session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"}},"type":"object","title":"ChangePlanOut"},"ChannelTestOut":{"properties":{"status":{"type":"string","const":"sent","title":"Status"},"detail":{"type":"string","title":"Detail"}},"type":"object","required":["status","detail"],"title":"ChannelTestOut","description":"The result of sending a real message to a connected channel."},"CheckoutIn":{"properties":{"tier":{"$ref":"#/components/schemas/PlanTier"},"interval":{"$ref":"#/components/schemas/BillingInterval","default":"monthly"}},"type":"object","required":["tier"],"title":"CheckoutIn"},"CheckoutOut":{"properties":{"checkout_url":{"type":"string","title":"Checkout Url"},"mode":{"type":"string","title":"Mode"},"session_id":{"type":"string","title":"Session Id"}},"type":"object","required":["checkout_url","mode","session_id"],"title":"CheckoutOut"},"CheckoutStatusOut":{"properties":{"session_id":{"type":"string","title":"Session Id"},"payment_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Status"},"access_active":{"type":"boolean","title":"Access Active"},"subscription_status":{"type":"string","title":"Subscription Status"},"plan":{"type":"string","title":"Plan"},"trial_ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Trial Ends At"},"current_period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period End"}},"type":"object","required":["session_id","payment_status","access_active","subscription_status","plan","trial_ends_at","current_period_end"],"title":"CheckoutStatusOut"},"CloseWorkspaceIn":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"}},"type":"object","required":["name"],"title":"CloseWorkspaceIn","description":"The workspace's own name, typed back by the person closing it.\n\nA second confirmation in the request itself, not only in the dialog: this\nis the one call in the product that cannot be undone, and a DELETE that\ntakes no body is one mis-wired button away from firing. Checked\ncase-insensitively against the current name — the point is intent, not\ntyping accuracy."},"ClosureOut":{"properties":{"connections_archived":{"type":"integer","title":"Connections Archived"},"invitations_revoked":{"type":"integer","title":"Invitations Revoked"},"approvals_dropped":{"type":"integer","title":"Approvals Dropped"},"memberships_ended":{"type":"integer","title":"Memberships Ended"},"subscription_cancelled":{"type":"boolean","title":"Subscription Cancelled"},"grants_left_behind":{"type":"integer","title":"Grants Left Behind"}},"type":"object","required":["connections_archived","invitations_revoked","approvals_dropped","memberships_ended","subscription_cancelled","grants_left_behind"],"title":"ClosureOut","description":"What closing took with it, for the confirmation the customer is shown."},"ConnectSessionOut":{"properties":{"integration_id":{"type":"string","title":"Integration Id"},"session_token":{"type":"string","title":"Session Token"},"expires_at":{"type":"string","title":"Expires At"},"connection_config":{"additionalProperties":{"type":"string"},"type":"object","title":"Connection Config","default":{}},"authorize_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorize Url"}},"type":"object","required":["integration_id","session_token","expires_at"],"title":"ConnectSessionOut","description":"What the browser needs to open the provider's consent screen."},"ConnectionOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"provider":{"$ref":"#/components/schemas/Provider"},"account_id":{"type":"string","title":"Account Id"},"account_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Name"},"alias":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Alias"},"display_name":{"type":"string","title":"Display Name"},"is_active":{"type":"boolean","title":"Is Active"},"paused_for_plan":{"type":"boolean","title":"Paused For Plan"},"write_enabled":{"type":"boolean","title":"Write Enabled"},"ask_before_sending":{"type":"boolean","title":"Ask Before Sending","default":false},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"consent_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Consent Version"},"is_mine":{"type":"boolean","title":"Is Mine","default":false},"may_administer":{"type":"boolean","title":"May Administer","default":false},"shared_with_workspace":{"type":"boolean","title":"Shared With Workspace","default":false},"reconsent":{"anyOf":[{"$ref":"#/components/schemas/ReconsentOut"},{"type":"null"}]},"reference":{"type":"string","title":"Reference"},"identity":{"additionalProperties":{"type":"string"},"type":"object","title":"Identity"},"credentials":{"additionalProperties":{"type":"string"},"type":"object","title":"Credentials"},"last_error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Error"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"grant_shape":{"$ref":"#/components/schemas/GrantShape","description":"What a read-only choice buys at this provider.\n\nComputed rather than stored, and carried on the connection rather than\nlooked up from the provider list beside it: the editor is three\ncomponents deep and needs it to decide whether to offer the switch at\nall — a channel has nothing to switch off and a read-only grant has\nnothing to switch on. A stored field would need a default, and the\ndefault would make a provider nobody declared quietly `inseparable`.","readOnly":true}},"type":"object","required":["id","provider","account_id","account_name","alias","display_name","is_active","paused_for_plan","write_enabled","currency","reference","identity","last_error","created_at","grant_shape"],"title":"ConnectionOut"},"ConnectionStatusOut":{"properties":{"providers":{"items":{"$ref":"#/components/schemas/ProviderInfo"},"type":"array","title":"Providers"},"connections":{"items":{"$ref":"#/components/schemas/ConnectionOut"},"type":"array","title":"Connections"}},"type":"object","required":["providers","connections"],"title":"ConnectionStatusOut"},"ConnectorAvailability":{"type":"string","enum":["available","soon","disabled"],"title":"ConnectorAvailability","description":"What a superadmin may say about one module (= connector), overriding the\ncatalog's own ``availability``.\n\nThree values, and the third is the one this enum exists for. ``available``\nand ``soon`` mirror ``core.catalog.connectors.Availability`` so an override\ncan put a connector back exactly where the catalog would have had it;\n``disabled`` has no catalog equivalent because a connector nobody may see is\nnot a state source code should have to carry — it is an operational\ndecision, taken at 2am when a provider's API breaks, and it must not wait\nfor a deploy.\n\n``disabled`` means gone, not hidden: absent from the public catalog, from\nthe dashboard, from the MCP tool listing, and refused on call. Rows already\nin the database are untouched — see ``core.catalog.availability``."},"ConnectorSkillOut":{"properties":{"connector":{"type":"string","title":"Connector"},"label":{"type":"string","title":"Label"},"availability":{"type":"string","title":"Availability"},"body":{"type":"string","title":"Body"}},"type":"object","required":["connector","label","availability","body"],"title":"ConnectorSkillOut"},"DecisionOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"executed":{"type":"boolean","title":"Executed"},"summary":{"type":"string","title":"Summary"},"undo_available":{"type":"boolean","title":"Undo Available","default":false},"undo_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Undo Until"}},"type":"object","required":["id","executed","summary"],"title":"DecisionOut"},"DiscoveredAccount":{"properties":{"account_id":{"type":"string","title":"Account Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"is_manager":{"type":"boolean","title":"Is Manager","default":false},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"kind":{"$ref":"#/components/schemas/Provider"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"platform":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform"},"already_connected":{"type":"boolean","title":"Already Connected","default":false}},"type":"object","required":["account_id","kind"],"title":"DiscoveredAccount"},"DiscoveredAccountsOut":{"properties":{"provider":{"$ref":"#/components/schemas/Provider"},"nango_connection_id":{"type":"string","title":"Nango Connection Id"},"accounts":{"items":{"$ref":"#/components/schemas/DiscoveredAccount"},"type":"array","title":"Accounts"},"chosen_at_provider":{"type":"boolean","title":"Chosen At Provider","default":false}},"type":"object","required":["provider","nango_connection_id","accounts"],"title":"DiscoveredAccountsOut"},"EnterpriseCheckoutIn":{"properties":{"connector_limit":{"type":"integer","minimum":0.0,"title":"Connector Limit"},"account_limit":{"type":"integer","minimum":0.0,"title":"Account Limit"},"seat_limit":{"type":"integer","minimum":0.0,"title":"Seat Limit"},"monthly_price_usd":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Monthly Price Usd"},"interval":{"$ref":"#/components/schemas/BillingInterval","default":"monthly"}},"type":"object","required":["connector_limit","account_limit","seat_limit","monthly_price_usd"],"title":"EnterpriseCheckoutIn","description":"A superadmin stages a bespoke enterprise offer the customer pays for.\n\nUnlike a manual grant, this does not grant access: it creates a bespoke\nprice at the negotiated amount, stages the limits, and returns a checkout\nlink. The workspace activates only when the customer pays and the webhook\nfires."},"EnterpriseCheckoutOut":{"properties":{"checkout_url":{"type":"string","title":"Checkout Url"}},"type":"object","required":["checkout_url"],"title":"EnterpriseCheckoutOut"},"EnterpriseLimitsIn":{"properties":{"connector_limit":{"type":"integer","minimum":0.0,"title":"Connector Limit"},"account_limit":{"type":"integer","minimum":0.0,"title":"Account Limit"},"seat_limit":{"type":"integer","minimum":0.0,"title":"Seat Limit"},"monthly_price_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Monthly Price Usd"}},"type":"object","required":["connector_limit","account_limit","seat_limit","monthly_price_usd"],"title":"EnterpriseLimitsIn","description":"What a bespoke enterprise plan grants, and what it costs.\n\nThe one declaration of these four values and their bounds. ZEISO-280 added\nan edit path beside the create path, and a second copy of ``ge=0`` would\nhave been a rule that drifts — the create path would keep refusing a\nnegative seat count and the edit path would quietly stop. Both bodies below\ninherit it, and ``tests/test_enterprise_edit.py`` fails if either stops."},"FeedbackKind":{"type":"string","enum":["connector_request","data_dispute","other"],"title":"FeedbackKind","description":"What a customer is telling us (ZEISO-218).\n\nOne mechanism carries two moments, and the difference between them is who\nreads the row rather than how it is stored: a connector we do not have is a\nproduct decision, a number the customer does not believe is a bug hunt.\nCollapsing them into one bucket would lose that, and splitting them into two\ntables would duplicate every column to record it."},"FeedbackOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"workspace":{"type":"string","title":"Workspace"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"kind":{"$ref":"#/components/schemas/FeedbackKind"},"state":{"$ref":"#/components/schemas/FeedbackState"},"message":{"type":"string","title":"Message"},"about_tool":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"About Tool"},"client":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","workspace","email","kind","state","message","about_tool","client","created_at"],"title":"FeedbackOut"},"FeedbackPatch":{"properties":{"state":{"$ref":"#/components/schemas/FeedbackState"}},"type":"object","required":["state"],"title":"FeedbackPatch","description":"Triage, which is the only thing we may change about a note.\n\nThe message is deliberately not editable: it is a record of what somebody\nsaid."},"FeedbackState":{"type":"string","enum":["new","triaged","resolved"],"title":"FeedbackState","description":"Where a note is in our own triage.\n\nThree, because a fourth (\"declined\") would be a second way of saying the\nnote is finished with, and a state nobody can tell from its neighbour is a\nstate nobody sets."},"FieldChangeOut":{"properties":{"field":{"type":"string","title":"Field"},"before":{"anyOf":[{},{"type":"null"}],"title":"Before"},"after":{"anyOf":[{},{"type":"null"}],"title":"After"}},"type":"object","required":["field"],"title":"FieldChangeOut","description":"One field that moved, with both of its values."},"GrantEnterpriseIn":{"properties":{"connector_limit":{"type":"integer","minimum":0.0,"title":"Connector Limit"},"account_limit":{"type":"integer","minimum":0.0,"title":"Account Limit"},"seat_limit":{"type":"integer","minimum":0.0,"title":"Seat Limit"},"monthly_price_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}],"title":"Monthly Price Usd"},"interval":{"$ref":"#/components/schemas/BillingInterval","default":"monthly"},"period_start":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period Start"},"period_end":{"type":"string","format":"date-time","title":"Period End"},"billing_subscription_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Billing Subscription Id"}},"type":"object","required":["connector_limit","account_limit","seat_limit","monthly_price_usd","period_end"],"title":"GrantEnterpriseIn","description":"A superadmin puts one workspace on a custom enterprise plan."},"GrantShape":{"type":"string","enum":["separable","read_only","inseparable","channel"],"title":"GrantShape","description":"What a customer's read-or-write choice can actually buy at this provider.\n\nThe choice is offered on every connector, because a customer deciding\nwhether an assistant may change their account should not have to know which\nproviders happen to model that as a scope. What differs is what the choice\nBUYS, and saying so is this enum's whole job: a screen that offers the same\ntwo options everywhere while one of them is unenforceable at three\nproviders is worse than one that says which is which."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InvitationOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"role":{"$ref":"#/components/schemas/UserRole"},"invite_url":{"type":"string","title":"Invite Url"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"}},"type":"object","required":["id","email","role","invite_url","expires_at"],"title":"InvitationOut"},"InviteIn":{"properties":{"email":{"type":"string","title":"Email"},"role":{"$ref":"#/components/schemas/UserRole","default":"member"}},"type":"object","required":["email"],"title":"InviteIn"},"InvitePreviewOut":{"properties":{"state":{"type":"string","enum":["valid","expired","revoked","accepted","unknown"],"title":"State"},"tenant_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tenant Name"},"role":{"anyOf":[{"$ref":"#/components/schemas/UserRole"},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"has_account":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Account"}},"type":"object","required":["state"],"title":"InvitePreviewOut","description":"What the invite screen may say before anybody has signed in.\n\n``state`` is the whole point of this shape. It used to be 404 for every\nunusable invitation, which left the one person who most needs an answer —\nsomebody holding a link that no longer works — staring at a sign-up form\nwith no idea why it would not help them. The owner's ruling (2026-09-14):\n*\"workspace daveti expired olduysa kullanici bunu login olmadan gormeli.\"*\n\nThe workspace name and the invited address are only ever filled in for an\ninvitation that really exists; an unknown token is answered with the state\nalone, so this cannot be turned into a way to read a workspace's name or a\ncolleague's address by guessing."},"McpClientOut":{"properties":{"client_id":{"type":"string","title":"Client Id"},"name":{"type":"string","title":"Name"},"granted_by_email":{"type":"string","title":"Granted By Email"},"granted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Granted At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"active_sessions":{"type":"integer","title":"Active Sessions","default":0}},"type":"object","required":["client_id","name","granted_by_email"],"title":"McpClientOut","description":"One MCP client holding a grant on this workspace.\n\n``client_id`` is what the customer revokes by; it is Keycloak's own id for\nthe client the assistant registered, and it is the only stable handle —\n``name`` is whatever that client called itself and two of them may say the\nsame thing."},"MemberOut":{"properties":{"id":{"type":"string","title":"Id"},"email":{"type":"string","title":"Email"},"role":{"$ref":"#/components/schemas/UserRole"},"is_you":{"type":"boolean","title":"Is You"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"connections":{"type":"integer","title":"Connections","default":0},"paused":{"type":"boolean","title":"Paused","default":false}},"type":"object","required":["id","email","role","is_you","created_at"],"title":"MemberOut"},"ModuleAvailabilityIn":{"properties":{"availability":{"$ref":"#/components/schemas/ConnectorAvailability"}},"type":"object","required":["availability"],"title":"ModuleAvailabilityIn"},"ModuleOut":{"properties":{"key":{"type":"string","title":"Key"},"name":{"type":"string","title":"Name"},"category":{"type":"string","title":"Category"},"kind":{"type":"string","title":"Kind"},"catalog_availability":{"type":"string","title":"Catalog Availability"},"availability":{"$ref":"#/components/schemas/ConnectorAvailability"},"overridden":{"type":"boolean","title":"Overridden"},"live_connections":{"type":"integer","title":"Live Connections"}},"type":"object","required":["key","name","category","kind","catalog_availability","availability","overridden","live_connections"],"title":"ModuleOut","description":"One connector, as the admin screen needs to see it.\n\nBoth availabilities, not one: a reader has to be able to tell \"this is what\nthe catalog says\" from \"somebody overrode it\", or the screen cannot show\nwhat resetting would do."},"NewWorkspaceIn":{"properties":{"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"}},"type":"object","required":["name"],"title":"NewWorkspaceIn"},"NewWorkspaceOut":{"properties":{"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"name":{"type":"string","title":"Name"}},"type":"object","required":["tenant_id","name"],"title":"NewWorkspaceOut"},"PendingInvitationOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"tenant_name":{"type":"string","title":"Tenant Name"},"invited_by":{"type":"string","title":"Invited By"},"role":{"$ref":"#/components/schemas/UserRole"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"}},"type":"object","required":["id","tenant_name","invited_by","role","expires_at"],"title":"PendingInvitationOut"},"PlanOut":{"properties":{"tier":{"type":"string","title":"Tier"},"interval":{"type":"string","title":"Interval"},"display_price":{"type":"string","title":"Display Price"}},"type":"object","required":["tier","interval","display_price"],"title":"PlanOut","description":"A self-serve offer as shown on the pricing cards."},"PlanTier":{"type":"string","enum":["starter","pro","superior","enterprise"],"title":"PlanTier"},"PortalOut":{"properties":{"url":{"type":"string","title":"Url"}},"type":"object","required":["url"],"title":"PortalOut"},"Provider":{"type":"string","enum":["google_ads","meta_ads","meta_instagram","meta_page","ga4","gsc","zoho_crm","zoho_salesiq","zoho_marketing","telegram","slack","email","adapty","trendyol","revenuecat","appsflyer","app_store_connect","woocommerce","shopify","stripe","posthog","jira","google_calendar","hepsiburada","n11","ciceksepeti","amazon_seller","ikas"],"title":"Provider"},"ProviderInfo":{"properties":{"provider":{"$ref":"#/components/schemas/Provider"},"label":{"type":"string","title":"Label"},"available":{"type":"boolean","title":"Available"},"connected_count":{"type":"integer","title":"Connected Count"},"supports_write":{"type":"boolean","title":"Supports Write"},"grant_shape":{"$ref":"#/components/schemas/GrantShape"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["provider","label","available","connected_count","supports_write","grant_shape"],"title":"ProviderInfo","description":"A provider as offered on the connections screen."},"ReconsentOut":{"properties":{"connector":{"type":"string","title":"Connector"},"granted_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Granted Version"},"current_version":{"type":"integer","title":"Current Version"},"reconnect_required":{"type":"boolean","title":"Reconnect Required"},"what_changed":{"items":{"type":"string"},"type":"array","title":"What Changed"},"how_to_fix":{"type":"string","title":"How To Fix"}},"type":"object","required":["connector","granted_version","current_version","reconnect_required","what_changed","how_to_fix"],"title":"ReconsentOut","description":"What this connection has not agreed to yet, and how it is fixed.\n\nPresent only when there is something to offer, so a row without it is a row\nwith nothing to say — never a row whose state is unknown."},"ResendVerificationOut":{"properties":{"sent":{"type":"boolean","title":"Sent"}},"type":"object","required":["sent"],"title":"ResendVerificationOut"},"RoleIn":{"properties":{"role":{"$ref":"#/components/schemas/UserRole"}},"type":"object","required":["role"],"title":"RoleIn"},"SelectAccountsIn":{"properties":{"nango_connection_id":{"type":"string","maxLength":200,"minLength":1,"title":"Nango Connection Id"},"account_ids":{"items":{"type":"string"},"type":"array","maxItems":50,"minItems":1,"title":"Account Ids"},"write_enabled":{"type":"boolean","title":"Write Enabled"},"shared_with_workspace":{"type":"boolean","title":"Shared With Workspace","default":false}},"type":"object","required":["nango_connection_id","account_ids","write_enabled"],"title":"SelectAccountsIn"},"SessionInfo":{"properties":{"user_id":{"type":"string","title":"User Id"},"email":{"type":"string","title":"Email"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Name"},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Name"},"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"tenant_name":{"type":"string","title":"Tenant Name"},"role":{"$ref":"#/components/schemas/UserRole"},"plan":{"$ref":"#/components/schemas/PlanTier"},"has_plan":{"type":"boolean","title":"Has Plan","default":false},"paused":{"type":"boolean","title":"Paused","default":false},"industry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Industry"},"can_write":{"type":"boolean","title":"Can Write"},"can_administer":{"type":"boolean","title":"Can Administer"},"needs_onboarding":{"type":"boolean","title":"Needs Onboarding"},"is_superadmin":{"type":"boolean","title":"Is Superadmin"},"workspaces":{"items":{"$ref":"#/components/schemas/WorkspaceMembership"},"type":"array","title":"Workspaces","default":[]}},"type":"object","required":["user_id","email","first_name","last_name","tenant_id","tenant_name","role","plan","industry","can_write","can_administer","needs_onboarding","is_superadmin"],"title":"SessionInfo"},"SubscriptionStatus":{"type":"string","enum":["none","active","past_due","canceled","trialing","trial_ended"],"title":"SubscriptionStatus"},"TeamOut":{"properties":{"members":{"items":{"$ref":"#/components/schemas/MemberOut"},"type":"array","title":"Members"},"invitations":{"items":{"$ref":"#/components/schemas/InvitationOut"},"type":"array","title":"Invitations"},"can_manage":{"type":"boolean","title":"Can Manage"},"assignable_roles":{"items":{"$ref":"#/components/schemas/AssignableRoleOut"},"type":"array","title":"Assignable Roles"}},"type":"object","required":["members","invitations","can_manage","assignable_roles"],"title":"TeamOut"},"TelegramInviteOut":{"properties":{"deep_link":{"type":"string","title":"Deep Link"},"bot_username":{"type":"string","title":"Bot Username"},"command":{"type":"string","title":"Command"},"expires_in":{"type":"integer","title":"Expires In"}},"type":"object","required":["deep_link","bot_username","command","expires_in"],"title":"TelegramInviteOut","description":"A one-time invite the customer redeems in Telegram.\n\nThe deep link only helps someone who has Telegram on the machine they are\nreading this on. The bot name and the raw command cover everyone else:\nthey open Telegram on their phone and type it."},"ToolResultStatus":{"type":"string","enum":["ok","no_data","connection_required","connection_error","account_ambiguous","quota_exceeded","approval_required","denied","error"],"title":"ToolResultStatus","description":"The vocabulary a tool may return.\n\nEverything other than ``OK`` is a structured intermediate state the frontend\nturns into a UI affordance rather than an error toast (plan §7)."},"TrialEligibilityOut":{"properties":{"trial_days":{"type":"integer","title":"Trial Days"}},"type":"object","required":["trial_days"],"title":"TrialEligibilityOut"},"UpdateConnectionIn":{"properties":{"alias":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Alias"},"credentials":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Credentials"},"shared_with_workspace":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Shared With Workspace"},"write_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Write Enabled"},"ask_before_sending":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ask Before Sending"}},"type":"object","title":"UpdateConnectionIn"},"UsageOut":{"properties":{"connector_limit":{"type":"integer","title":"Connector Limit"},"connected_connectors":{"type":"integer","title":"Connected Connectors"},"account_limit":{"type":"integer","title":"Account Limit"},"connected_accounts":{"type":"integer","title":"Connected Accounts"},"seat_limit":{"type":"integer","title":"Seat Limit"},"seats_used":{"type":"integer","title":"Seats Used"},"period_start":{"type":"string","format":"date","title":"Period Start"},"plan":{"type":"string","title":"Plan"},"subscription_status":{"type":"string","title":"Subscription Status"},"billing_interval":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Billing Interval"},"monthly_price_usd":{"type":"number","title":"Monthly Price Usd"},"current_period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period End"},"trial_ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Trial Ends At"},"cancel_at_period_end":{"type":"boolean","title":"Cancel At Period End"},"access_active":{"type":"boolean","title":"Access Active"},"never_subscribed":{"type":"boolean","title":"Never Subscribed"},"enterprise_offer_pending":{"type":"boolean","title":"Enterprise Offer Pending"},"can_manage_billing":{"type":"boolean","title":"Can Manage Billing","default":false},"account_workspaces":{"type":"integer","title":"Account Workspaces","default":1}},"type":"object","required":["connector_limit","connected_connectors","account_limit","connected_accounts","seat_limit","seats_used","period_start","plan","subscription_status","billing_interval","monthly_price_usd","current_period_end","trial_ends_at","cancel_at_period_end","access_active","never_subscribed","enterprise_offer_pending"],"title":"UsageOut"},"UserRole":{"type":"string","enum":["owner","member"],"title":"UserRole","description":"Who somebody is in one workspace.\n\nTwo, by the owner's decision of 2026-09-18, and the argument is the one he\nmade: four roles that collapse to two predicates are not four roles. OWNER\nand ADMIN differed in two lines in the whole codebase; EDITOR and VIEWER in\none.\n\nWorse, four roles plus per-connection grants meant the same fact could be\nstated twice and disagree — a role saying VIEWER while a grant said writer,\nwith the winner decided across sixteen separate gates. One axis cannot\nexpress the contradiction.\n\n``OWNER`` does everything: billing, team, connecting accounts, approving\nchanges, and reading and writing on every connection.\n\n``MEMBER`` does exactly what it was given, per connection, in\n``connection_grants.level``. A member with no row anywhere can sign in and\nsee that nothing has been shared with them yet, and that is all.\n\nPersisted as a plain string: VARCHAR(32), no CHECK constraint, no native\nPostgres type, so this is a code change and not a migration."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WaitlistIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"referrer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Referrer"},"utm_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Source"},"utm_medium":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Medium"},"utm_campaign":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Campaign"},"utm_term":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Term"},"utm_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Content"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone"},"device":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device"},"screen":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screen"}},"type":"object","required":["email"],"title":"WaitlistIn"},"WorkspaceIn":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"},"timezone":{"type":"string","maxLength":64,"title":"Timezone","default":"Europe/Istanbul"},"industry":{"type":"string","maxLength":120,"title":"Industry","default":""},"custom_prompt":{"type":"string","maxLength":1000,"title":"Custom Prompt","default":""},"negative_prompt":{"type":"string","maxLength":1000,"title":"Negative Prompt","default":""}},"type":"object","required":["name"],"title":"WorkspaceIn"},"WorkspaceMembership":{"properties":{"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"name":{"type":"string","title":"Name"},"role":{"$ref":"#/components/schemas/UserRole"},"is_active":{"type":"boolean","title":"Is Active"},"paused":{"type":"boolean","title":"Paused","default":false}},"type":"object","required":["tenant_id","name","role","is_active"],"title":"WorkspaceMembership","description":"One workspace this person may act for, as the switcher shows it."},"WorkspaceOut":{"properties":{"name":{"type":"string","title":"Name"},"industry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Industry"},"timezone":{"type":"string","title":"Timezone"},"custom_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Prompt"},"negative_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Negative Prompt"},"can_edit":{"type":"boolean","title":"Can Edit"}},"type":"object","required":["name","industry","timezone","custom_prompt","negative_prompt","can_edit"],"title":"WorkspaceOut"},"WorkspaceRow":{"properties":{"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"name":{"type":"string","title":"Name"},"plan":{"$ref":"#/components/schemas/PlanTier"},"subscription_status":{"$ref":"#/components/schemas/SubscriptionStatus"},"billing_interval":{"anyOf":[{"$ref":"#/components/schemas/BillingInterval"},{"type":"null"}]},"current_period_start":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period Start"},"current_period_end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period End"},"members":{"type":"integer","title":"Members"},"connections":{"type":"integer","title":"Connections"},"monthly_price_usd":{"type":"number","title":"Monthly Price Usd"},"connector_limit":{"type":"integer","title":"Connector Limit"},"account_limit":{"type":"integer","title":"Account Limit"},"seat_limit":{"type":"integer","title":"Seat Limit"}},"type":"object","required":["tenant_id","name","plan","subscription_status","billing_interval","current_period_start","current_period_end","members","connections","monthly_price_usd","connector_limit","account_limit","seat_limit"],"title":"WorkspaceRow"}}}}