{"openapi":"3.1.0","info":{"title":"Cognee API","description":"Cognee API with API key and bearer token auth","version":"1.0.0"},"paths":{"/api/v1/billing/credits/overview":{"get":{"tags":["billing"],"summary":"Get Credits Overview Route","description":"Return the authenticated user's prepaid credit balance and per-tenant spend.","operationId":"get_credits_overview_route_api_v1_billing_credits_overview_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditsOverviewResponse"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/billing/tenants/{tenant_id}/costs/hourly":{"get":{"tags":["billing"],"summary":"Get Tenant Hourly Costs Route","description":"Hourly LLM cost (USD) for a tenant over a window (default: last 7 days).\n\nSourced live from Prometheus (LiteLLM's `litellm_spend_metric_total`).\nNote: Prometheus retention currently bounds how far back data actually\nexists (~3h today) — older hours come back absent until retention is\nraised or an hourly persistence job backfills them.","operationId":"get_tenant_hourly_costs_route_api_v1_billing_tenants__tenant_id__costs_hourly_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"start","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"UTC window start; defaults to 7 days before end.","title":"Start"},"description":"UTC window start; defaults to 7 days before end."},{"name":"end","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"UTC window end; defaults to now.","title":"End"},"description":"UTC window end; defaults to now."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantHourlyCostsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/billing/tenants/{tenant_id}/auto-recharge":{"get":{"tags":["billing"],"summary":"Get Auto Recharge Settings Route","description":"Return the tenant's auto-recharge configuration, or all-disabled\ndefaults if it has never been configured.","operationId":"get_auto_recharge_settings_route_api_v1_billing_tenants__tenant_id__auto_recharge_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoRechargeSettings"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["billing"],"summary":"Update Auto Recharge Settings Route","description":"Create or update the tenant's auto-recharge configuration.","operationId":"update_auto_recharge_settings_route_api_v1_billing_tenants__tenant_id__auto_recharge_put","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutoRechargeSettings"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoRechargeSettings"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api-keys":{"get":{"tags":["api-keys"],"summary":"Get Api Keys For User","operationId":"get_api_keys_for_user_api_v1_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"ApiKeyAuth":[]}]},"post":{"tags":["api-keys"],"summary":"Create Api Key For User","operationId":"create_api_key_for_user_api_v1_api_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreationPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]},"delete":{"tags":["api-keys"],"summary":"Delete Api Key For User","operationId":"delete_api_key_for_user_api_v1_api_keys_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyDeletionPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/api-keys/check":{"post":{"tags":["api-keys"],"summary":"Check Api Key For User","operationId":"check_api_key_for_user_api_v1_api_keys_check_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/api-keys/my-user-id":{"get":{"tags":["api-keys"],"summary":"Get My User Id","operationId":"get_my_user_id_api_v1_api_keys_my_user_id_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/tenants/users":{"post":{"tags":["tenants"],"summary":"Add User To Tenant","description":"Add a user to a tenant.\n\nThis endpoint assigns a user to a specific tenant. Either user_id or email must be provided.\nIf email is provided, it will be resolved to a user_id before proceeding.\n\n## Request Parameters\n- **tenant_id** (UUID): The UUID of the tenant to assign the user to\n- **user_id** (UUID, optional): The UUID of the user to add\n- **email** (str, optional): The email of the user to add; converted to user_id if provided.\n  If no account exists for the email, a stub user is created and added — they join\n  automatically when they sign up with that email.\n\nThe new member is always emailed (COG-6177) — a sign-up CTA if they have no account\nyet, a plain \"you were added\" notice if they do.\n\n## Response\n`200` — the member is in and the tenant pod knows them (`sync_status: \"ok\"`).\n`207` — the member is in, but the tenant pod does not know them yet:\n`sync_status` is `\"unreachable\"` (pod cold, suspended or restarting) or\n`\"rejected\"` (the pod answered with an error). Nothing was mailed. **POST the\nsame member again** once the workspace is up — re-adding an existing member\nre-runs the push and the notification (`already_member: true`); it is not a\nconflict.\n\nBody: `message`, `pending_invite` (an account had to be stubbed),\n`invite_email_sent`, `sync_status`, `already_member`.\n\n## Error Codes\n- **400 Bad Request**: Neither user_id nor email provided\n- **403 Forbidden**: Caller doesn't own this tenant\n- **404 Not Found**: User or tenant doesn't exist\n- **500 Internal Server Error**: Error adding user to tenant","operationId":"add_user_to_tenant_api_v1_tenants_users_post","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"}},{"name":"email","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["tenants"],"summary":"Remove User From Tenant","description":"Remove a user from a tenant.\n\nOnly the tenant owner can remove users. The owner cannot remove themselves.\n\n## Request Parameters\n- **tenant_id** (UUID): The UUID of the tenant\n- **user_id** (UUID): The UUID of the user to remove\n\nThe removed member is emailed, for the same reason the added one is\n(COG-6177): losing access silently is as confusing as gaining it silently.\n\nThe member's access is revoked on the tenant pod BEFORE the membership is\ndropped here, so a removal is never recorded while their keys still work.\n\n## Error Codes\n- **403 Forbidden**: User doesn't have permission or is trying to remove owner\n- **404 Not Found**: User-tenant association doesn't exist\n- **503 Service Unavailable**: The workspace could not be reached to revoke access;\n  nothing was removed — retry once it is running (a suspended workspace must be\n  restored first)\n- **500 Internal Server Error**: Error removing user from tenant","operationId":"remove_user_from_tenant_api_v1_tenants_users_delete","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"user_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tenants/users/resend-invite":{"post":{"tags":["tenants"],"summary":"Resend Invite","description":"Re-send the membership email to someone already on this tenant.\n\nMembership is never changed here — this only re-sends the mail, for when\nthe original send failed (`invite_email_sent: false`) or was lost. Which\nvariant goes out follows the member's current state, so someone who has\nsigned up since gets the \"you have access\" notice, not a sign-up CTA.\n\n## Request Parameters\n- **tenant_id** (UUID): The UUID of the tenant\n- **email** (str): Email of an existing member of that tenant\n\n## Error Codes\n- **403 Forbidden**: Caller doesn't own this tenant\n- **404 Not Found**: Tenant doesn't exist, or that address isn't a member of it","operationId":"resend_invite_api_v1_tenants_users_resend_invite_post","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"email","in":"query","required":true,"schema":{"type":"string","title":"Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tenants":{"post":{"tags":["tenants"],"summary":"Create Tenant","description":"Create a new tenant.\n\nThis endpoint creates a new tenant with the specified name. Tenants are used\nto organize users and resources in multi-tenant environments, providing\nisolation and access control between different groups or organizations.\n\n## Request Parameters\n- **tenant_name** (str): The name of the tenant to create\n\n## Response\nReturns a success message indicating the tenant was created.\n\n## Error Codes\n- **400 Bad Request**: Invalid tenant name or tenant already exists\n- **500 Internal Server Error**: Error creating the tenant","operationId":"create_tenant_api_v1_tenants_post","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_name","in":"query","required":true,"schema":{"type":"string","title":"Tenant Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["tenants"],"summary":"Delete Tenant","operationId":"delete_tenant_api_v1_tenants_delete","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tenants/current":{"get":{"tags":["tenants"],"summary":"Get Current Tenant","description":"Get the current tenant for the authenticated user.\n\nThis endpoint retrieves the tenant information associated with the authenticated user. It returns details about the tenant, such as its name and ID.\n\n## Response\nReturns the tenant information for the authenticated user.\n\n## Error Codes\n- **403 Forbidden**: User doesn't have permission to access tenant information\n- **404 Not Found**: Tenant doesn't exist for the user\n- **500 Internal Server Error**: Error retrieving tenant information","operationId":"get_current_tenant_api_v1_tenants_current_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/tenants/current/service-url":{"get":{"tags":["tenants"],"summary":"Get Current Tenant Service Url","description":"Get the service URL for the current tenant.\n\nThis endpoint retrieves the service URL associated with the authenticated user's tenant. The service URL is used to access tenant-specific resources and services.\n\n## Response\nReturns the service URL for the authenticated user's tenant.\n\n## Error Codes\n- **403 Forbidden**: User doesn't have permission to access tenant information\n- **404 Not Found**: Tenant doesn't exist for the user\n- **500 Internal Server Error**: Error retrieving tenant information","operationId":"get_current_tenant_service_url_api_v1_tenants_current_service_url_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/tenants/{tenant_id}/users":{"get":{"tags":["tenants"],"summary":"List Tenant Users","description":"List all users in a tenant. Any tenant member can call this.\n\n## Path Parameters\n- **tenant_id** (UUID): The UUID of the tenant\n\n## Response\nReturns a list of users with id and email.","operationId":"list_tenant_users_api_v1_tenants__tenant_id__users_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tenants/{tenant_id}/status":{"get":{"tags":["tenants"],"summary":"Get Tenant Status Endpoint","description":"Single-shot k8s status for a tenant, backed by the k8s control plane —\ncovers provisioning, readiness, and health, not just the initial\nprovisioning phase. Lets the frontend tell \"still provisioning\" apart\nfrom a genuine failure instead of guessing from how long a direct pod\nping has been failing (see wait_for_tenant_instance_provisioning for\nthe equivalent polling loop used synchronously during creation itself).\n\n## Response\n`{\"tenant_id\": str, \"status\": \"provisioning\" | \"healthy\" | \"suspended\" | \"failed\" | \"terminating\" | \"unknown\"}`\n\n`suspended` means the tenant is scaled to zero with its data intact. It\nwill not come up on its own — the client should offer a restore action\n(POST /{tenant_id}/restore) rather than keep polling.","operationId":"get_tenant_status_endpoint_api_v1_tenants__tenant_id__status_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tenants/{tenant_id}/restore":{"post":{"tags":["tenants"],"summary":"Restore Tenant","description":"Restore a suspended tenant: scale it back up from zero replicas.\n\nAny *member* of the tenant may restore it, not only the owner — unlike\ndeletion. Restoring is non-destructive and a suspended shared workspace\nis unusable for everyone in it, so requiring the owner would strand\nmembers whose owner is away.\n\nReturns as soon as the control plane accepts the request. Restoring is a\ncold start, so the client should poll `GET /{tenant_id}/status` until it\nreports `healthy` rather than assuming the tenant is ready on return.\n\n## Response\n`{\"tenant_id\": str, \"status\": \"restoring\"}`\n\n## Error Codes\n- **403 Forbidden**: user is not a member of this tenant\n- **404 Not Found**: no Tenant CR exists for this tenant\n- **502 Bad Gateway**: the control plane rejected or could not serve the request","operationId":"restore_tenant_api_v1_tenants__tenant_id__restore_post","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tenants/me/with-status":{"get":{"tags":["tenants"],"summary":"Get My Tenants With Status","description":"Get all tenants the user belongs to, with each tenant's owner info.\nUsed by the workspace picker.","operationId":"get_my_tenants_with_status_api_v1_tenants_me_with_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/users/me":{"get":{"tags":["users"],"summary":"Get Me","operationId":"get_me_api_v1_users_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMeDTO"}}}}},"security":[{"ApiKeyAuth":[]}]},"delete":{"tags":["users"],"summary":"Delete My Account","operationId":"delete_my_account_api_v1_users_me_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteAccountResponse"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/users/me/seen-welcome":{"patch":{"tags":["users"],"summary":"Mark Seen Welcome","operationId":"mark_seen_welcome_api_v1_users_me_seen_welcome_patch","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMeDTO"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/users/me/complete-onboarding":{"patch":{"tags":["users"],"summary":"Complete Onboarding","operationId":"complete_onboarding_api_v1_users_me_complete_onboarding_patch","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMeDTO"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/users/me/marketing-consent":{"patch":{"tags":["users"],"summary":"Set My Marketing Consent","operationId":"set_my_marketing_consent_api_v1_users_me_marketing_consent_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketingConsentInDTO"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMeDTO"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/users/me/session-recording-consent":{"patch":{"tags":["users"],"summary":"Set My Session Recording Consent","operationId":"set_my_session_recording_consent_api_v1_users_me_session_recording_consent_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionRecordingConsentInDTO"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMeDTO"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/users/me/feature-announcements/{feature_key}/dismiss":{"patch":{"tags":["users"],"summary":"Dismiss Feature Announcement Endpoint","operationId":"dismiss_feature_announcement_endpoint_api_v1_users_me_feature_announcements__feature_key__dismiss_patch","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"feature_key","in":"path","required":true,"schema":{"type":"string","title":"Feature Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserMeDTO"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/survey/eligibility":{"post":{"tags":["survey"],"summary":"Check Survey Eligibility","operationId":"check_survey_eligibility_api_v1_survey_eligibility_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EligibilityRequestInDTO"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EligibilityOutDTO"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/survey/response/{response_id}":{"patch":{"tags":["survey"],"summary":"Submit Response","operationId":"submit_response_api_v1_survey_response__response_id__patch","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"response_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Response Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitSurveyResponseInDTO"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurveyResponseOutDTO"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/slack/authorize":{"post":{"tags":["integrations"],"summary":"Slack Authorize","description":"Mint the Slack authorize URL for a workspace owner.","operationId":"slack_authorize_api_v1_integrations_slack_authorize_post","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/slack/channels":{"get":{"tags":["integrations"],"summary":"Get Slack Channels","description":"List the connected workspace's public channels (CLO-377 routing picker).\n\nMember-visible read, same as ``/slack/connection`` — picking a\nchannel to look at isn't sensitive; only *changing* its route is\nowner-gated (see ``PUT /slack/channel-routes``).","operationId":"get_slack_channels_api_v1_integrations_slack_channels_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["integrations"],"summary":"Set Allowed Channels","description":"Choose which channels this workspace ingests (CLO-387).\n\nOwner-only, unlike the member-visible read above: deciding what enters\nthe knowledge graph — and therefore what every workspace member can\nquery — is not a browsing action.\n\nNewly selected channels are backfilled immediately, since selecting a\nchannel is the moment the owner asked for its history. De-selecting\nonly stops future ingestion; already-ingested content stays searchable\n(deleting from a knowledge graph is destructive and entities may be\nreferenced elsewhere — see CLO-391).","operationId":"set_allowed_channels_api_v1_integrations_slack_channels_put","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllowedChannelsPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/slack/link":{"post":{"tags":["integrations"],"summary":"Confirm Slack Link","description":"Finish a ``/cognee-link`` started in Slack (CLO-390).\n\nMember-level, not owner-level: everyone links their *own* account, and\nrequiring an owner would make the escape hatch useless to the people\nwho need it.\n\nThe account linked is taken from the authenticated session, never from\nthe code. The code only says which Slack member is asking; letting it\nalso name the account would let anyone holding one link themselves to\nsomebody else.","operationId":"confirm_slack_link_api_v1_integrations_slack_link_post","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlackLinkPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/slack/connection":{"get":{"tags":["integrations"],"summary":"Slack Connection Status","description":"Connection state for the Integrations page — visible to any tenant member.\n\nOwn connection (Connect/Disconnect) and CLO-377 routing are\nindependent: a tenant with no Slack of its own can still receive\nchannels routed here from another workspace, and a tenant *with* its\nown Slack can *also* receive routed channels from a different\nworkspace's install. ``via_routing`` is reported alongside\n``connected``, never instead of it — a tenant that only receives\nrouted channels must still see a working \"Connect\" for its own,\nseparate workspace.","operationId":"slack_connection_status_api_v1_integrations_slack_connection_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["integrations"],"summary":"Slack Disconnect","description":"Disconnect the workspace — owner-only, mirroring tenant deletion.\n\nRevokes the bot token on Slack's side first (best-effort — see\n``revoke_remote_installation``), deletes the API key minted for\n``/cognee-recall`` (so it doesn't outlive the connection it was created\nfor), drops this account's channel routes, then marks the stored\ninstallation revoked locally. Order matters only in that the remote\ncall still needs the token, which local revoke doesn't erase.\n\nRoutes go here rather than being left dormant: they are keyed on the\naccount, not the tenant, so a leftover route re-arms the moment anyone\nreinstalls this workspace (see ``delete_routes_for_account``). A\nre-authorization for new scopes does *not* pass through this endpoint,\nso routing config survives that case as intended.","operationId":"slack_disconnect_api_v1_integrations_slack_connection_delete","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/{provider}/channel-routes":{"get":{"tags":["integrations"],"summary":"Get Channel Routes","description":"List this account's per-resource tenant routes (CLO-377).\n\n``tenant_id`` identifies the account by its primary (originally\nconnected) tenant — member-visible, mirroring ``/{provider}/connection``.","operationId":"get_channel_routes_api_v1_integrations__provider__channel_routes_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["integrations"],"summary":"Put Channel Route","description":"Route one resource (e.g. a Slack channel) to a different tenant the\nsame owner controls (CLO-377). Owner-only on both ends: the caller must\nown the account's primary tenant *and* the target tenant, or this\nbecomes a way to leak one user's traffic into a stranger's tenant.","operationId":"put_channel_route_api_v1_integrations__provider__channel_routes_put","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelRoutePayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/{provider}/channel-routes/{resource_id}":{"delete":{"tags":["integrations"],"summary":"Delete Channel Route","description":"Remove one tenant's route — a resource can be fanned out to several,\nso ``target_tenant_id`` says which subscriber to drop; the resource\nkeeps reaching the primary tenant and any other subscriber untouched.\n\n``target_tenant_id`` is optional for backward compatibility with\ncallers from before CLO-528 fan-out, when a resource had at most one\nroute: omitting it deletes that one route if exactly one exists,\nno-ops if none exists, and 409s asking for it explicitly if the\nresource has since fanned out to more than one tenant — there is no\nlonger a single unambiguous \"the route\" to guess at.\n\nGated on the *primary* tenant's owner only, deliberately — not on\n``target_tenant_id`` ownership too. This revokes access to the primary\nowner's own connected Slack data, including a route created via\nself-serve subscription (``unsubscribe_linked_workspace_channel``);\nthe primary owner controls what leaves their workspace, the same way\nthey control who's invited into a private channel. A subscribing\ntenant revoking its own access is the separate, narrower-scoped\n``DELETE /slack/linked-workspaces/{team_id}/channels/{channel_id}/subscription``.","operationId":"delete_channel_route_api_v1_integrations__provider__channel_routes__resource_id__delete","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"resource_id","in":"path","required":true,"schema":{"type":"string","title":"Resource Id"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"target_tenant_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/slack/linked-workspaces":{"get":{"tags":["integrations"],"summary":"List Linked Workspaces","description":"Slack workspaces the caller is personally linked into via\n``/cognee-link`` or an email match (CLO-390), regardless of which\ntenant originally connected them. The entry point for self-serve\nchannel subscription: a member doesn't need to own — or even be a\nmember of — the tenant that installed Slack, only to be a verified\nmember of that Slack workspace.","operationId":"list_linked_workspaces_api_v1_integrations_slack_linked_workspaces_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/integrations/slack/linked-workspaces/{team_id}/channels":{"get":{"tags":["integrations"],"summary":"List Linked Workspace Channels","description":"This workspace's channels, flagged with whether ``tenant_id`` (a\ntenant the caller owns) already subscribes each one — self-serve, so\nthe only two things checked are the caller's own Slack member-link\nfor this exact workspace and their ownership of ``tenant_id``, never\nownership of the workspace's primary tenant.","operationId":"list_linked_workspace_channels_api_v1_integrations_slack_linked_workspaces__team_id__channels_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"string","title":"Team Id"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/slack/linked-workspaces/{team_id}/channels/{channel_id}/subscription":{"put":{"tags":["integrations"],"summary":"Subscribe Linked Workspace Channel","description":"Self-serve subscribe ``tenant_id`` to one channel of a workspace the\ncaller is a verified member of (CLO-390 extended). No approval from\nthe workspace's primary tenant owner: being a linked member of that\nexact Slack workspace, plus owning the target tenant, is authorization\nenough — the same bar Slack itself uses for reading a public channel.","operationId":"subscribe_linked_workspace_channel_api_v1_integrations_slack_linked_workspaces__team_id__channels__channel_id__subscription_put","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"string","title":"Team Id"}},{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["integrations"],"summary":"Unsubscribe Linked Workspace Channel","description":"Drop a self-serve subscription — the channel stops reaching\n``tenant_id``; the primary tenant and any other subscriber are\nuntouched.","operationId":"unsubscribe_linked_workspace_channel_api_v1_integrations_slack_linked_workspaces__team_id__channels__channel_id__subscription_delete","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"string","title":"Team Id"}},{"name":"channel_id","in":"path","required":true,"schema":{"type":"string","title":"Channel Id"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/connectors":{"get":{"tags":["integrations"],"summary":"List Connectors","description":"The connector catalog, for the Integrations page.\n\nAuthenticated but not tenant-scoped: it describes what this deployment\nsupports, not what anyone has connected. Carries no secret values —\nonly whether secrets are present.","operationId":"list_connectors_api_v1_integrations_connectors_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/integrations/{provider}/authorize":{"post":{"tags":["integrations"],"summary":"Authorize","description":"Mint the provider's install URL for a tenant owner.\n\nAlso sets the nonce cookie the callback checks against the state's\n``nonce_hash`` (CLO-628's #373 bot review, module docstring on\n``flow.py``) — without it, a state minted here is valid for *any*\nbrowser that later presents it, not just this one.","operationId":"authorize_api_v1_integrations__provider__authorize_post","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/{provider}/connection":{"get":{"tags":["integrations"],"summary":"Connection","description":"This tenant's connection state. Never returns token material.\n\n``account_id`` picks one connection when the tenant holds several to\nthe same provider (CLO-528); omitted, this is the pre-existing\n\"most recently connected wins\" behavior.","operationId":"connection_api_v1_integrations__provider__connection_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"account_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["integrations"],"summary":"Disconnect","description":"Revoke this tenant's connection. Owner-only.\n\nLocal revocation is what actually cuts access off — it stops any token\nfrom being minted or decrypted for this account. The remote call is\nbest-effort on top, and a no-op for providers where the only remote\nequivalent is destructive (uninstalling an app from a whole\norganization is not one tenant's decision to make).\n\n``account_id`` picks one connection when the tenant holds several to\nthe same provider (CLO-528); omitted, this is the pre-existing\n\"most recently connected wins\" behavior.","operationId":"disconnect_api_v1_integrations__provider__connection_delete","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"account_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/integrations/{provider}/resources":{"get":{"tags":["integrations"],"summary":"List Resources","description":"What this connection could ingest, plus what it is narrowed to.\n\n``account_id`` picks one connection when the tenant holds several to\nthe same provider (CLO-528); omitted, this is the pre-existing\n\"most recently connected wins\" behavior.\n\nBoth halves in one response on purpose: a picker needs the available\nlist *and* the current selection to render, and fetching them\nseparately would let it draw a stale set of checkboxes against a fresh\nlist.\n\n``selected`` is ``null`` when the connection is not narrowed, which the\nUI must render as \"all of them\" rather than as \"none\" — the two are\ndifferent states and conflating them is how a picker silently turns\ningestion off.\n\nEach row also carries ``sync``: that resource's own last outcome, in the\nsame vocabulary ``GET /{provider}/connection`` returns, so a caller\nreading both does not learn two shapes for one fact. It is ``null`` when\nnothing is known — never dispatched, or connected before per-resource\noutcomes were recorded — which is **not** the same as ``pending``: one\nmeans \"we have never asked\", the other \"we asked and are waiting\". A\npicker that renders them alike reports a resource as in flight forever.\n\nKnown gap: a resource whose health was recorded and which the provider\nno longer lists (an installation dropped it) does not appear here at\nall, and its entry stays in the column. Pruning belongs to the write\npath that knows an id is gone for good, not to a read.","operationId":"list_resources_api_v1_integrations__provider__resources_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"account_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["integrations"],"summary":"Set Resources","description":"Narrow this connection to the given resources. Owner-only.\n\nOwner-only because it decides what the tenant pays to ingest and what\nbecomes readable to everyone in the workspace — the same reason\nconnecting and disconnecting are owner-only.\n\nAll three states are accepted, and they are three different answers:\n``null`` stops narrowing (everything, including what is added later),\n``[]`` narrows to nothing, a list narrows to exactly those. An empty\nlist is a valid, meaningful choice and is *not* the same as never\nhaving chosen.\n\n``account_id`` picks one connection when the tenant holds several to\nthe same provider (CLO-528); omitted, this is the pre-existing\n\"most recently connected wins\" behavior.","operationId":"set_resources_api_v1_integrations__provider__resources_put","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"tenant_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}},{"name":"account_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceSelection"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/permissions/tenants/select":{"post":{"tags":["permissions"],"summary":"Select Tenant","description":"Select current tenant.\n\nThis endpoint selects a tenant with the specified UUID. Tenants are used\nto organize users and resources in multi-tenant environments, providing\nisolation and access control between different groups or organizations.\n\nSending a null/None value as tenant_id selects his default single user tenant\n\n## Request Parameters\n- **tenant_id** (Union[UUID, None]): UUID of the tenant to select, If null/None is provided use the default single user tenant\n\n## Response\nReturns a success message along with selected tenant id.","operationId":"select_tenant_api_v1_permissions_tenants_select_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectTenantDTO"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/api/v1/permissions/tenants/{tenant_id}/users":{"get":{"tags":["permissions"],"summary":"Get Users In Tenant","description":"List all users in a tenant, with their roles.\n\nThe authenticated user must be the tenant owner or have user-management\npermission (e.g. Admin role) in the tenant.\n\n## Path Parameters\n- **tenant_id** (UUID): The UUID of the tenant (find yours via GET /api/v1/permissions/tenants/me)\n\n## Response\nReturns a JSON list of users: [{\"id\", \"email\", \"roles\": [{\"id\", \"name\"}]}].\n\n## Error Codes\n- **403 Forbidden**: Caller lacks user-management permission in the tenant","operationId":"get_users_in_tenant_api_v1_permissions_tenants__tenant_id__users_get","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/permissions/tenants/me":{"get":{"tags":["permissions"],"summary":"Get My Tenants","description":"List the tenants the authenticated user belongs to.\n\nUse the returned ids as the tenant_id path parameter for the other\n/permissions/tenants/... endpoints.\n\n## Response\nReturns a JSON list of tenants: [{\"id\", \"name\"}].","operationId":"get_my_tenants_api_v1_permissions_tenants_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"ApiKeyAuth":[]}]}}},"components":{"schemas":{"AllowedChannelsPayload":{"properties":{"channel_ids":{"items":{"type":"string"},"type":"array","title":"Channel Ids"}},"type":"object","required":["channel_ids"],"title":"AllowedChannelsPayload"},"ApiKeyCreationPayload":{"properties":{"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"ApiKeyCreationPayload"},"ApiKeyDeletionPayload":{"properties":{"apiKeyId":{"type":"string","format":"uuid","title":"Apikeyid"}},"type":"object","required":["apiKeyId"],"title":"ApiKeyDeletionPayload"},"AutoRechargeSettings":{"properties":{"autoRechargeEnabled":{"type":"boolean","title":"Autorechargeenabled","default":false},"rechargeThresholdUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rechargethresholdusd"},"rechargeAmountUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rechargeamountusd"},"monthlyRechargeLimitUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Monthlyrechargelimitusd"},"monthlyRechargedUsd":{"type":"number","title":"Monthlyrechargedusd","default":0},"notifyThresholdUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Notifythresholdusd"},"lastRechargeError":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastrechargeerror"},"paymentMethodMissing":{"type":"boolean","title":"Paymentmethodmissing","default":false}},"type":"object","title":"AutoRechargeSettings"},"ChannelRoutePayload":{"properties":{"resource_id":{"type":"string","title":"Resource Id"},"resource_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Name"},"target_tenant_id":{"type":"string","format":"uuid","title":"Target Tenant Id"}},"type":"object","required":["resource_id","target_tenant_id"],"title":"ChannelRoutePayload"},"CreditPurchase":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"tenantId":{"type":"string","format":"uuid","title":"Tenantid"},"tokensPurchased":{"type":"integer","title":"Tokenspurchased"},"amountPaidUsd":{"type":"number","title":"Amountpaidusd"},"currency":{"type":"string","title":"Currency"},"createdAt":{"type":"string","format":"date-time","title":"Createdat"},"invoiceUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoiceurl"}},"type":"object","required":["id","tenantId","tokensPurchased","amountPaidUsd","currency","createdAt"],"title":"CreditPurchase"},"CreditsBudget":{"properties":{"totalUsd":{"type":"number","title":"Totalusd"},"spentUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Spentusd"},"remainingUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Remainingusd"},"spentPct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Spentpct"},"tenantsUnreadable":{"type":"integer","title":"Tenantsunreadable"}},"type":"object","required":["totalUsd","tenantsUnreadable"],"title":"CreditsBudget"},"CreditsOverviewResponse":{"properties":{"budget":{"$ref":"#/components/schemas/CreditsBudget"},"tenants":{"items":{"$ref":"#/components/schemas/TenantSpend"},"type":"array","title":"Tenants"},"purchases":{"items":{"$ref":"#/components/schemas/CreditPurchase"},"type":"array","title":"Purchases"}},"type":"object","required":["budget","tenants","purchases"],"title":"CreditsOverviewResponse"},"DeleteAccountError":{"properties":{"scope":{"type":"string","title":"Scope"},"message":{"type":"string","title":"Message"},"tenantId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Tenantid"}},"type":"object","required":["scope","message"],"title":"DeleteAccountError"},"DeleteAccountResponse":{"properties":{"tenantsDeleted":{"type":"integer","title":"Tenantsdeleted"},"tenantsFailed":{"type":"integer","title":"Tenantsfailed"},"stripeCustomersDeleted":{"type":"integer","title":"Stripecustomersdeleted"},"auth0UsersDeleted":{"type":"integer","title":"Auth0Usersdeleted"},"userDeleted":{"type":"boolean","title":"Userdeleted"},"errors":{"items":{"$ref":"#/components/schemas/DeleteAccountError"},"type":"array","title":"Errors"},"ok":{"type":"boolean","title":"Ok"}},"type":"object","required":["tenantsDeleted","tenantsFailed","stripeCustomersDeleted","auth0UsersDeleted","userDeleted","errors","ok"],"title":"DeleteAccountResponse"},"EligibilityOutDTO":{"properties":{"eligible":{"type":"boolean","title":"Eligible"},"responseId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Responseid"}},"type":"object","required":["eligible"],"title":"EligibilityOutDTO"},"EligibilityRequestInDTO":{"properties":{"surveyKey":{"type":"string","title":"Surveykey"},"trigger":{"type":"string","maxLength":64,"title":"Trigger"},"page":{"type":"string","maxLength":255,"title":"Page"},"surveyVersion":{"type":"integer","maximum":1000.0,"minimum":1.0,"title":"Surveyversion","default":1}},"type":"object","required":["surveyKey","trigger","page"],"title":"EligibilityRequestInDTO"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HourlyCostPoint":{"properties":{"hour":{"type":"string","format":"date-time","title":"Hour"},"spendUsd":{"type":"number","title":"Spendusd"}},"type":"object","required":["hour","spendUsd"],"title":"HourlyCostPoint"},"MarketingConsentInDTO":{"properties":{"optedIn":{"type":"boolean","title":"Optedin"},"source":{"type":"string","enum":["signup","settings","announcement"],"title":"Source"}},"type":"object","required":["optedIn","source"],"title":"MarketingConsentInDTO"},"ResourceSelection":{"properties":{"resource_ids":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":5000},{"type":"null"}],"title":"Resource Ids"}},"type":"object","required":["resource_ids"],"title":"ResourceSelection","description":"The picker's payload: which resources this connection should ingest.\n\nA full selection, not a patch — the picker always submits everything, so a\nconcurrent edit from another tab loses cleanly rather than merging two\nhalf-intentions into a set nobody chose.\n\nThe three states the rest of the design is built on are all expressible\nhere, which is the point:\n\n* ``null`` — stop narrowing. Everything the connection covers, *including\n  resources added later*.\n* ``[]`` — narrowed to nothing.\n* ``[\"a\", \"b\"]`` — exactly these.\n\n``null`` matters more than it looks. Without it, narrowing is a one-way\ndoor: ticking every box stores an explicit list, and a repository added to\nthe installation next month is then silently never ingested. Re-ticking\neverything would not help — an exhaustive list is still a list."},"SelectTenantDTO":{"properties":{"tenantId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Tenantid"}},"type":"object","title":"SelectTenantDTO"},"SessionRecordingConsentInDTO":{"properties":{"optedIn":{"type":"boolean","title":"Optedin"},"source":{"type":"string","enum":["first_login","settings"],"title":"Source"}},"type":"object","required":["optedIn","source"],"title":"SessionRecordingConsentInDTO"},"SlackLinkPayload":{"properties":{"code":{"type":"string","title":"Code"}},"type":"object","required":["code"],"title":"SlackLinkPayload"},"SubmitSurveyResponseInDTO":{"properties":{"score":{"type":"integer","maximum":10.0,"minimum":0.0,"title":"Score"},"followupQuestionId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Followupquestionid"},"followupAnswer":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}],"title":"Followupanswer"},"consentToQuote":{"type":"boolean","title":"Consenttoquote","default":false}},"type":"object","required":["score"],"title":"SubmitSurveyResponseInDTO"},"SurveyResponseOutDTO":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"score":{"type":"integer","title":"Score"},"scoreBucket":{"type":"string","title":"Scorebucket"}},"type":"object","required":["id","score","scoreBucket"],"title":"SurveyResponseOutDTO"},"TenantHourlyCostsResponse":{"properties":{"tenantId":{"type":"string","format":"uuid","title":"Tenantid"},"start":{"type":"string","format":"date-time","title":"Start"},"end":{"type":"string","format":"date-time","title":"End"},"currency":{"type":"string","title":"Currency","default":"USD"},"points":{"items":{"$ref":"#/components/schemas/HourlyCostPoint"},"type":"array","title":"Points"}},"type":"object","required":["tenantId","start","end","points"],"title":"TenantHourlyCostsResponse"},"TenantSpend":{"properties":{"tenantId":{"type":"string","format":"uuid","title":"Tenantid"},"tenantName":{"type":"string","title":"Tenantname"},"spentUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Spentusd"},"maxBudgetUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Maxbudgetusd"},"remainingUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Remainingusd"},"purchasedUsd":{"type":"number","title":"Purchasedusd","default":0.0},"initialBudgetUsd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Initialbudgetusd"}},"type":"object","required":["tenantId","tenantName"],"title":"TenantSpend"},"UpdateAutoRechargeSettings":{"properties":{"autoRechargeEnabled":{"type":"boolean","title":"Autorechargeenabled"},"rechargeThresholdUsd":{"type":"number","maximum":10000.0,"minimum":0.0,"title":"Rechargethresholdusd"},"rechargeAmountUsd":{"type":"number","maximum":10000.0,"exclusiveMinimum":0.0,"title":"Rechargeamountusd"},"monthlyRechargeLimitUsd":{"type":"number","maximum":100000.0,"exclusiveMinimum":0.0,"title":"Monthlyrechargelimitusd"},"notifyThresholdUsd":{"anyOf":[{"type":"number","maximum":100000.0,"minimum":0.0},{"type":"null"}],"title":"Notifythresholdusd"}},"type":"object","required":["autoRechargeEnabled","rechargeThresholdUsd","rechargeAmountUsd","monthlyRechargeLimitUsd"],"title":"UpdateAutoRechargeSettings"},"UserMeDTO":{"properties":{"isSeenWelcome":{"type":"boolean","title":"Isseenwelcome"},"onboardingCompletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Onboardingcompletedat"},"activeWorkspaceId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Activeworkspaceid"},"pendingFeatureAnnouncements":{"items":{"type":"string"},"type":"array","title":"Pendingfeatureannouncements"},"accountCreatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Accountcreatedat"},"marketingOptIn":{"type":"boolean","title":"Marketingoptin"},"marketingConsentAnswered":{"type":"boolean","title":"Marketingconsentanswered"},"sessionRecordingOptIn":{"type":"boolean","title":"Sessionrecordingoptin"},"sessionRecordingConsentAnswered":{"type":"boolean","title":"Sessionrecordingconsentanswered"}},"type":"object","required":["isSeenWelcome","onboardingCompletedAt","activeWorkspaceId","pendingFeatureAnnouncements","accountCreatedAt","marketingOptIn","marketingConsentAnswered","sessionRecordingOptIn","sessionRecordingConsentAnswered"],"title":"UserMeDTO"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-Api-Key","description":"API Key authentication"}}}}