{"openapi":"3.1.0","info":{"title":"FastAPI","version":"0.1.0"},"paths":{"/v1/bootstrap":{"get":{"tags":["v1-auth"],"summary":"Bootstrap","description":"Bootstrap endpoint - ONE request for complete app initialization.\n\n**REQUIRES X-Org-Id header** - users must explicitly choose their org context.\n\nThis endpoint returns everything the frontend needs to load:\n- User identity\n- List of all user's organizations (lightweight)\n- Active organization details with full permissions\n\nHeaders:\n    X-Org-Id: REQUIRED - Organization ID to load context for\n\nReturns:\n    user: Full user profile\n    orgs: Array of lightweight org info (for org switcher)\n    active_org: Full details of active org with permissions\n\nExample response:\n{\n    \"user\": {\n        \"user_id\": \"...\",\n        \"email\": \"john@example.com\",\n        \"full_name\": \"John Doe\",\n        \"created_at\": \"2025-01-01T00:00:00Z\",\n        \"updated_at\": \"2025-01-01T00:00:00Z\"\n    },\n    \"orgs\": [\n        {\n            \"org_id\": \"abc-123\",\n            \"name\": \"Acme Corp\",\n            \"role\": \"owner\",\n            \"joined_at\": \"2025-01-01T00:00:00Z\"\n        }\n    ],\n    \"active_org\": {\n        \"org_id\": \"abc-123\",\n        \"name\": \"Acme Corp\",\n        \"created_at\": \"2025-01-01T00:00:00Z\",\n        \"my_role\": \"owner\",\n        \"my_permissions\": [\"org.read\", \"org.update\", \"org.delete\", ...],\n        \"member_count\": 5\n    }\n}","operationId":"bootstrap_v1_bootstrap_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Bootstrap V1 Bootstrap Get"}}}}}}},"/v1/my-orgs":{"get":{"tags":["v1-auth"],"summary":"Get My Orgs","description":"Get list of user's organizations (lightweight).\n\nUsed for initial org selection before bootstrap.\nDoes not require X-Org-Id header.\n\nReturns:\n    orgs: Array of lightweight org info\n\nExample response:\n{\n    \"orgs\": [\n        {\n            \"org_id\": \"abc-123\",\n            \"name\": \"Acme Corp\",\n            \"role\": \"owner\",\n            \"joined_at\": \"2025-01-01T00:00:00Z\"\n        },\n        {\n            \"org_id\": \"def-456\",\n            \"name\": \"Beta Inc\",\n            \"role\": \"member\",\n            \"joined_at\": \"2025-01-02T00:00:00Z\"\n        }\n    ]\n}","operationId":"get_my_orgs_v1_my_orgs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get My Orgs V1 My Orgs Get"}}}}}}},"/v1/me":{"get":{"tags":["v1-auth"],"summary":"Get Me","description":"Get current user profile and lightweight org check.\n\nThis is the bootstrap endpoint - call this after login for initial load.\nReturns user profile and whether they have orgs. Frontend should then\ncall GET /v1/orgs for org list and GET /v1/orgs/{id} for active org details.\n\nReturns:\n    user: Full user profile from public.users\n    has_orgs: Boolean indicating if user has any organizations\n    default_org_id: First org ID (or null if no orgs)\n\nExample response:\n{\n    \"user\": {\n        \"user_id\": \"...\",\n        \"email\": \"john@example.com\",\n        \"full_name\": \"John Doe\",\n        \"created_at\": \"2025-01-01T00:00:00Z\"\n    },\n    \"has_orgs\": true,\n    \"default_org_id\": \"abc-123\"\n}","operationId":"get_me_v1_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Me V1 Me Get"}}}}}},"delete":{"tags":["v1-auth"],"summary":"Delete My Account","description":"Delete the current user's account.\n\nSole owners must transfer ownership or contact support before account\ndeletion can proceed. This prevents orphaning organizations; org\nauto-delete is intentionally not part of this endpoint.\n\nWhat gets deleted:\n- User's memberships in all orgs\n- User's role grants\n- User's API keys\n- Audit trail references (nullified, not deleted)\n- User profile (public.users)\n- Auth account (auth.users)\n\nWhat gets preserved (nullified):\n- Invites sent by user (invited_by_user_id → NULL)\n- Role grants created by user (granted_by → NULL)\n- API keys created by user (created_by → NULL)\n\nReturns:\n    204 No Content on success\n\nRaises:\n    400: User is sole owner of one or more orgs\n\nExample error response:\n{\n    \"detail\": \"Cannot delete account while you are the sole owner of these organizations. Transfer ownership or contact support: Acme Corp (org_abc)\"\n}","operationId":"delete_my_account_v1_me_delete","responses":{"204":{"description":"Successful Response"}}},"patch":{"tags":["v1-auth"],"summary":"Update My Profile","description":"Update the current user's profile.\n\nCurrently supports updating:\n- full_name: User's display name\n\nReturns:\n    Updated user profile\n\nExample request body:\n{\n    \"full_name\": \"John Doe\"\n}\n\nExample response:\n{\n    \"user_id\": \"...\",\n    \"email\": \"john@example.com\",\n    \"full_name\": \"John Doe\",\n    \"created_at\": \"2025-01-01T00:00:00Z\",\n    \"updated_at\": \"2025-01-06T12:00:00Z\"\n}","operationId":"update_my_profile_v1_me_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Update My Profile V1 Me Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs":{"get":{"tags":["v1-orgs"],"summary":"List Orgs","description":"List all organizations the current user is a member of.\n\nLightweight endpoint for org switcher - returns basic info without permissions.\nCall GET /v1/orgs/{org_id} to get full details for a specific org.\n\nReturns:\n    List of organizations with basic info and user's role\n\nExample response:\n[\n    {\n        \"org_id\": \"...\",\n        \"name\": \"Acme Corp\",\n        \"role\": \"owner\",\n        \"joined_at\": \"2025-01-01T00:00:00Z\"\n    }\n]","operationId":"list_orgs_v1_orgs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["v1-orgs"],"summary":"Create Org","description":"Create a new organization with billing setup.\n\nUser becomes the owner with all permissions and gets free tier credits.\n\nRequest body:\n{\n    \"name\": \"My Organization\"\n}\n\nReturns:\n    Created organization details","operationId":"create_org_v1_orgs_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Org V1 Orgs Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}":{"get":{"tags":["v1-orgs"],"summary":"Get Org Details","description":"Get full details of a specific organization including user's permissions.\n\nThis is the \"active org context\" endpoint - call this when user selects an org\nto get their role, permissions, and org details.\n\nArgs:\n    org_id: Organization ID\n\nReturns:\n    Organization details with user's role and permissions\n\nExample response:\n{\n    \"org_id\": \"...\",\n    \"name\": \"Acme Corp\",\n    \"created_at\": \"2025-01-01T00:00:00Z\",\n    \"my_role\": \"owner\",\n    \"my_permissions\": [\"jobs.create\", \"orgs.delete\", ...],\n    \"member_count\": 12\n}\n\nRaises:\n    403 if user is not a member of the organization","operationId":"get_org_details_v1_orgs__org_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Org Details V1 Orgs  Org Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["v1-orgs"],"summary":"Update Org","description":"Update organization details.\n\nRequires 'org.update' permission (typically admin or owner).\n\nRequest body:\n{\n    \"name\": \"New Organization Name\"\n}\n\nReturns:\n    Updated organization","operationId":"update_org_v1_orgs__org_id__patch","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOrgRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["v1-orgs"],"summary":"Delete Org","description":"Delete an organization.\n\nRequires 'org.delete' permission (typically owner only).\n\n⚠️ SMART DELETION LOGIC:\n- Cannot delete your last organization\n- You must either:\n  1. Join/create another organization first, THEN delete this one\n  2. Delete your account (which will auto-delete this org)\n\nThis ensures users always have at least one organization.\nManually deletes all related data: memberships, role grants, API keys, invites, etc.\n\nWARNING: This is irreversible!\n\nReturns:\n    204 No Content on success\n\nRaises:\n    400: This is your last organization","operationId":"delete_org_v1_orgs__org_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/members":{"get":{"tags":["v1-orgs"],"summary":"List Org Members","description":"List all members of the organization.\n\nRequires org membership.\n\nReturns:\n    List of members with user info, role, and join date","operationId":"list_org_members_v1_orgs__org_id__members_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Org Members V1 Orgs  Org Id  Members Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/members/{target_user_id}":{"patch":{"tags":["v1-orgs"],"summary":"Update Member Role","description":"Update a member's role in the organization.\n\nRequires 'orgs.share' permission (typically admin or owner).\n\nArgs:\n    org_id: Organization ID\n    target_user_id: User ID of the member to update\n    body: New role details\n\nReturns:\n    Success message with updated role","operationId":"update_member_role_v1_orgs__org_id__members__target_user_id__patch","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"target_user_id","in":"path","required":true,"schema":{"type":"string","title":"Target User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Update Member Role V1 Orgs  Org Id  Members  Target User Id  Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["v1-orgs"],"summary":"Remove Org Member","description":"Remove a member from the organization.\n\nRequires 'org.remove_members' permission (typically admin or owner).\n\nArgs:\n    org_id: Organization ID\n    target_user_id: User ID of the member to remove\n\nReturns:\n    204 No Content on success","operationId":"remove_org_member_v1_orgs__org_id__members__target_user_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"target_user_id","in":"path","required":true,"schema":{"type":"string","title":"Target User Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/invite":{"post":{"tags":["v1-orgs"],"summary":"Invite User To Org","description":"Invite a user to join the organization.\n\nRequires 'orgs.invite_users' permission.\n\nArgs:\n    org_id: Organization ID\n    body: Invite details (email, role_key)\n\nReturns:\n    Invite details including invite_token","operationId":"invite_user_to_org_v1_orgs__org_id__invite_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteUserRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Invite User To Org V1 Orgs  Org Id  Invite Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/invites":{"get":{"tags":["v1-orgs"],"summary":"List Pending Invites","description":"List pending invites for the organization.\n\nRequires org membership.\n\nArgs:\n    org_id: Organization ID\n\nReturns:\n    List of pending invites","operationId":"list_pending_invites_v1_orgs__org_id__invites_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Pending Invites V1 Orgs  Org Id  Invites Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/invites/{invite_id}":{"delete":{"tags":["v1-orgs"],"summary":"Revoke Invite","description":"Revoke (cancel) a pending invite.\n\nRequires 'orgs.invite_users' permission.\n\nArgs:\n    org_id: Organization ID\n    invite_id: Invite ID to revoke","operationId":"revoke_invite_v1_orgs__org_id__invites__invite_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"invite_id","in":"path","required":true,"schema":{"type":"string","title":"Invite Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/invites/pending":{"get":{"tags":["v1-orgs"],"summary":"List My Pending Invites","description":"List pending invites addressed to the authenticated user's verified emails.\n\nThis is global because orgless invitees need it before they have an org\nmembership or active org header.","operationId":"list_my_pending_invites_v1_invites_pending_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"type":"object","title":"Response List My Pending Invites V1 Invites Pending Get"}}}}}}},"/v1/invites/{invite_token}/accept":{"post":{"tags":["v1-orgs"],"summary":"Accept Invite Token","description":"Accept an organization invite.\n\nThis is a global endpoint (not org-scoped) because the user\naccepting might not be in the org yet.\n\nArgs:\n    invite_token: The invite token from the email/link\n\nReturns:\n    Success message with org details","operationId":"accept_invite_token_v1_invites__invite_token__accept_post","parameters":[{"name":"invite_token","in":"path","required":true,"schema":{"type":"string","title":"Invite Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Accept Invite Token V1 Invites  Invite Token  Accept Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/roles":{"get":{"tags":["v1-orgs"],"summary":"List Org Roles","description":"List available roles for the organization.\n\nReturns all org-level roles (owner, admin, member, viewer) that can be\nassigned to users or API keys.\n\nRequires: User must be a member of the org (any role).\n\nReturns:\n    List of role objects with id, role_key, name, description, permissions","operationId":"list_org_roles_v1_orgs__org_id__roles_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Org Roles V1 Orgs  Org Id  Roles Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/api-keys":{"get":{"tags":["v1-api-keys"],"summary":"List Api Keys","description":"List all API keys for the organization, active and revoked.\n\nRequires 'api_keys.read' permission.\n\nReturns:\n    List of API keys (without secret keys)","operationId":"list_api_keys_v1_orgs__org_id__api_keys_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Active keys first (newest first), then revoked keys.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true,"$ref":"#/components/schemas/APIKeyListItem"},"title":"Response 200 List Api Keys V1 Orgs  Org Id  Api Keys Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["v1-api-keys"],"summary":"Create New Api Key","description":"Create a new API key for the organization.\n\nRequires 'api_keys.create' permission.\n\n⚠️ IMPORTANT: The secret key is only shown ONCE upon creation.\nStore it securely - you won't be able to retrieve it again!\n\nThe API key will be granted a role assignment with the specified role_id.\nThe role determines what permissions the API key has access to.\n\nCommon role IDs:\n- role_org_viewer: Read-only access\n- role_org_member: Create and modify resources\n- role_org_admin: Full administrative access (except deleting org)\n- role_org_owner: Full control over organization\n\nArgs:\n    org_id: Organization ID\n    body: API key details (name, role_id, scopes, expiration)\n\nReturns:\n    API key details INCLUDING the secret key (only time it's shown)","operationId":"create_new_api_key_v1_orgs__org_id__api_keys_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAPIKeyRequest"}}}},"responses":{"201":{"description":"The created key, including the secret — shown only this once.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create New Api Key V1 Orgs  Org Id  Api Keys Post","$ref":"#/components/schemas/APIKeyCreateResponse"}}}},"400":{"description":"Unknown role, non-org role, or a scope outside the role's permissions."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/api-keys/{api_key_id}":{"delete":{"tags":["v1-api-keys"],"summary":"Revoke Api Key Endpoint","description":"Revoke (delete) an API key.\n\nRequires 'api_keys.delete' permission.\n\nArgs:\n    org_id: Organization ID\n    api_key_id: API key ID to revoke\n\nReturns:\n    204 No Content on success","operationId":"revoke_api_key_endpoint_v1_orgs__org_id__api_keys__api_key_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"api_key_id","in":"path","required":true,"schema":{"type":"string","title":"Api Key Id"}}],"responses":{"204":{"description":"Successful Response"},"404":{"description":"API key not found or already revoked."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/billing/subscriptions":{"post":{"tags":["v1-billing"],"summary":"Create Subscription Endpoint","description":"Create a self-serve subscription via Autumn (Stripe Checkout when needed).\n\nOwner-only. Allowed plans are limited to SELF_SERVE_PLAN_IDS.","operationId":"create_subscription_endpoint_v1_orgs__org_id__billing_subscriptions_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/billing/subscription":{"get":{"tags":["v1-billing"],"summary":"Get Subscription Endpoint","description":"Return current subscription status for the org.","operationId":"get_subscription_endpoint_v1_orgs__org_id__billing_subscription_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["v1-billing"],"summary":"Delete Subscription Endpoint","description":"Cancel the org's subscription.\n\n- immediate=false (default): cancel at period end\n- immediate=true: cancel now","operationId":"delete_subscription_endpoint_v1_orgs__org_id__billing_subscription_delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"immediate","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Immediate"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/orgs/{org_id}/billing/subscriptions:update":{"post":{"tags":["v1-billing"],"summary":"Update Subscription Endpoint","description":"Update an org's subscription: upgrade/downgrade or cancel.\n\n- If `plan_id` is provided, changes the plan.\n- If `cancel_now` is true, cancels immediately.\n- If `cancel_at_period_end` is true, schedules cancel at period end.","operationId":"update_subscription_endpoint_v1_orgs__org_id__billing_subscriptions_update_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSubscriptionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors":{"post":{"tags":["v1-connectors"],"summary":"Create Connector Endpoint","description":"Create new connector after source prerequisite validation.\n\nFlow:\n1. Validate connection_details schema for service_name\n2. Run the row-less PostgreSQL source prerequisite gate\n3. Store connection details in Key Vault\n4. Save connector to database\n5. Return connector (without schema_structure - call /discover next)\n\nResponse time: 500ms-1s (fast validation only)\n\nNote: After creating, call POST /connectors/{id}/discover to run schema discovery.\n\nPreflight gate scope: steps 1-2 run for every PostgreSQL create where\n``byoc`` is None — this deliberately includes BYOC-environment\n(``use_environment=True``, ARN-based) connectors as well as direct\n(no-environment) connectors. For the BYOC-environment path the gate\nprobes the source through the discovery tunnel (``private_link_id`` +\nresolved ``byoc_access_credentials`` are forwarded to\n``run_discovery_preflight``), so the source is validated before any row\nor secret is written. Only Neon-BYOC (``byoc='neon'``) and non-PostgreSQL\ncreates skip the gate.","operationId":"create_connector_endpoint_v1_connectors_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConnectorRequest"}}}},"responses":{"200":{"description":"The created connector row plus `can_update`/`can_delete`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorRow"}}}},"400":{"description":"Validation, placement, or private-network configuration error."},"422":{"description":"Preflight hasn't passed for this source; the body is the full preflight report. (A malformed request body also returns 422.)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreflightReport"}}}}}},"get":{"tags":["v1-connectors"],"summary":"List Connectors Endpoint","description":"List all connectors for an org with optional filters.\n\nRLS automatically filters to connectors user can access.","operationId":"list_connectors_endpoint_v1_connectors_get","parameters":[{"name":"org_id","in":"query","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"connector_category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Connector Category"}},{"name":"service_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Service Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}":{"get":{"tags":["v1-connectors"],"summary":"Get Connector Endpoint","description":"Get single connector with full schema_structure and computed status fields.\n\nComputed fields:\n- needs_reselection: True if schema_version > selection_schema_version\n- needs_reindex: True if selected_schema_version > last_indexed_version","operationId":"get_connector_endpoint_v1_connectors__connector_id__get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorRow"}}}},"404":{"description":"Connector not found (or not visible to the caller)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["v1-connectors"],"summary":"Update Connector Endpoint","description":"Update connector. If connection_details changed, re-tests connection and resets indexing_status.","operationId":"update_connector_endpoint_v1_connectors__connector_id__put","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConnectorRequest"}}}},"responses":{"200":{"description":"The updated connector row.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorRow"}}}},"400":{"description":"Validation error."},"404":{"description":"Connector not found (or not visible to the caller)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["v1-connectors"],"summary":"Delete Connector Endpoint","description":"Delete connector and all associated resources.\n\nCleanup handled by the DBOS connector-delete workflow:\n- Branching engine infrastructure (replication pipeline, compute, slot)\n- Delayed stored credential purge after DB finalization\n- Database record\n\nArgs:\n    force: When true, bypass the in-flight WAL/Kafka drain wait\n        (ARD-870). Customer accepts that any un-replicated data is\n        abandoned; the un-drained delta is recorded in cleanup_failures\n        for operator triage.","operationId":"delete_connector_endpoint_v1_connectors__connector_id__delete","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}}],"responses":{"202":{"description":"Delete accepted (or already in progress). Poll `GET /v1/operations/{operation_id}`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationHandle"}}}},"403":{"description":"No delete permission on this connector."},"404":{"description":"Connector not found (or not visible to the caller)."},"409":{"description":"Deletion is locked, or a conflicting delete is active."},"503":{"description":"Ardent could not start the work — safe to retry."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/connection-details":{"get":{"tags":["v1-connectors"],"summary":"Get Connector Connection Details Endpoint","description":"Get decrypted connection details for a connector.\n\nThis endpoint is used by the Edit Connection Details modal to load\nthe current (decrypted) connection credentials for editing.\n\nReturns only the connection_details dict with decrypted values.\nDoes NOT include schema_structure or other connector fields.\n\nSecurity:\n- Requires authentication (JWT or API key)\n- RLS automatically enforces that user has access to this connector\n- Connection details are decrypted from Azure Key Vault","operationId":"get_connector_connection_details_endpoint_v1_connectors__connector_id__connection_details_get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/deletion-lock":{"post":{"tags":["v1-connectors"],"summary":"Lock Connector Deletion Endpoint","description":"Lock connector deletion until an authorized caller unlocks it.","operationId":"lock_connector_deletion_endpoint_v1_connectors__connector_id__deletion_lock_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorDeletionLockRequest"}}}},"responses":{"200":{"description":"The locked connector.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorEnvelope"}}}},"403":{"description":"No update permission on this connector."},"404":{"description":"Connector not found (or not visible to the caller)."},"409":{"description":"A delete is already in progress."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["v1-connectors"],"summary":"Unlock Connector Deletion Endpoint","description":"Clear the connector deletion lock.","operationId":"unlock_connector_deletion_endpoint_v1_connectors__connector_id__deletion_lock_delete","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"200":{"description":"The unlocked connector.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorEnvelope"}}}},"403":{"description":"No update permission on this connector."},"404":{"description":"Connector not found (or not visible to the caller)."},"409":{"description":"A delete is already in progress."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/quarantine":{"get":{"tags":["v1-connectors"],"summary":"List Connector Quarantines Endpoint","description":"List active quarantine rows for a connector.\n\nReturns rows where status='quarantined'. Released rows are transient\n(deleted by the monitor after scale-up) and are not listed here.","operationId":"list_connector_quarantines_endpoint_v1_connectors__connector_id__quarantine_get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"200":{"description":"Active (paused) replication deployments.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuarantineListResponse"}}}},"404":{"description":"Connector not found (or not visible to the caller)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/readiness-checks":{"get":{"tags":["v1-connectors"],"summary":"List Connector Readiness Checks Endpoint","description":"List ARD-720 post-snapshot validation evidence for this connector.\n\nReturns the append-only paper trail of per-table checks the engine-setup\ngate emitted on each attempt. The schema's\n``branch_readiness_checks_select_policy`` enforces RLS via\n``current_user_accessible_connectors`` — callers see only the rows for\nconnectors they have read access to.\n\nA connector that's stuck in ``failed_validation`` will surface its\nfailing rows here (combine with ``?only_failed=true``); customers use\nthis to understand why their branch isn't routing without needing\noperator intervention.","operationId":"list_connector_readiness_checks_endpoint_v1_connectors__connector_id__readiness_checks_get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"attempt_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Attempt Id"}},{"name":"check_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Check Name"}},{"name":"only_failed","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Only Failed"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":5000,"minimum":1,"default":500,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/readiness-attempts":{"get":{"tags":["v1-connectors"],"summary":"List Connector Readiness Attempts Endpoint","description":"Roll up branch_readiness_checks into one summary per engine-setup attempt.\n\nReturns ``{attempt_id, total_checks, passed_checks, failed_checks,\nlatest_checked_at, pod_name}`` per attempt, sorted with the most recent\nattempt first. Customers land here to find the right ``attempt_id`` to\ndrill into via ``/readiness-checks?attempt_id=...``.","operationId":"list_connector_readiness_attempts_endpoint_v1_connectors__connector_id__readiness_attempts_get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":5000,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/quarantine/{quarantine_id}/release":{"post":{"tags":["v1-connectors"],"summary":"Release Quarantine Endpoint","description":"Release a quarantined CDC pipeline for this connector.\n\nFlips the quarantine row to status='released'. The quarantine monitor\npicks this up on its next tick (up to QUARANTINE_POLL_SECONDS later) and\nrestores the pipeline. Idempotent.\n\nRequires connectors.update permission on the parent connector.","operationId":"release_quarantine_endpoint_v1_connectors__connector_id__quarantine__quarantine_id__release_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"quarantine_id","in":"path","required":true,"schema":{"type":"string","title":"Quarantine Id"}}],"responses":{"200":{"description":"The released quarantine entry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuarantineRow"}}}},"403":{"description":"No update permission on this connector."},"404":{"description":"Connector or quarantine entry not found."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/discover":{"post":{"tags":["v1-connectors"],"summary":"Discover Connector Endpoint","description":"Dispatch the connector's schema discovery (ARD-1098).\n\nThe connectivity + branching-prerequisites gate runs synchronously\n(fast after ARD-1095). On gate success the per-database catalog walk\nis dispatched as a ``connector_discovery`` async_operation and the\nendpoint returns **202** with the operation id plus the prerequisite\npayload — enough for the customer to know \"your connection works\"\nbefore the schema crawl finishes. On gate failure (network\nunreachable, auth, missing prereqs) the endpoint returns 422 with a\nstructured remediation message; no worker is dispatched.\n\nThe CLI polls ``GET /v1/operations/{operation_id}`` for the\nterminal status of the catalog walk. Concurrent /discover calls on\nthe same connector are deduped by the async_operations partial unique\nindex — the second call rejoins the in-flight operation rather than\nlaunching a second crawl.\n\nAlways reads credentials from Key Vault (single source of truth). To\nupdate credentials first, call PUT /connectors/{connector_id}.","operationId":"discover_connector_endpoint_v1_connectors__connector_id__discover_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"202":{"description":"Discovery started (or joined, if one is already running). Poll the operation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverAccepted"}}}},"400":{"description":"The connector isn't in a state that can be discovered."},"404":{"description":"Connector not found (or not visible to the caller)."},"422":{"description":"Discovery prerequisites failed."},"503":{"description":"Ardent could not start the work — safe to retry."}}}},"/v1/connectors/preflight":{"post":{"tags":["v1-connectors"],"summary":"Preflight Connector Endpoint","description":"Validate a source DB without persisting a connector row (ARD-1146).\n\nThe customer's pain this closes: today the only way to learn that\nyour source is misconfigured is to run ``ardent connector create``,\nwhich persists a row + writes credentials to Key Vault + runs the\nduplicate-source fingerprint check at row-create time. Hitting any\ndiscovery failure leaves the customer in a delete/retry loop.\n\nPreflight calls :func:`run_discovery_preflight` (the row-less sibling\nof :func:`run_discovery_gate`), which reuses\n``PostgresDiscoveryHandler.gate()`` against inline credentials —\n*exactly* the function ``/discover`` runs synchronously. No row, no\nAKV write, no replication slot side effects.\n\nHTTP semantics:\n  - 200 whenever the source DB was actually probed; per-check failure\n    detail lives in the response body. The customer is asking a\n    question, not asking us to commit state.\n  - 400 for request-shape errors (malformed ``connection_details``,\n    unknown ``service_name``, **active-private-link symmetry violation**:\n    an ``environment_id`` with an active private link cannot be probed\n    without ``private_link_id`` because the probe would hit the wrong\n    egress).\n  - 403 for missing ``connectors.create``.\n  - 500 for tunnel / AKV failures we cannot reduce to a check entry.\n\nCompare with ``/discover`` which returns 422 on gate-fail because\ndiscover writes state and the gate result drives that state.","operationId":"preflight_connector_endpoint_v1_connectors_preflight_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreflightConnectorRequest"}}},"required":true},"responses":{"200":{"description":"The full preflight report. A failed gate is still a 200 — read `preflight_pass`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreflightReport"}}}},"400":{"description":"Unsupported service, or the connection details failed validation."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/grant-script":{"post":{"tags":["v1-connectors"],"summary":"Grant Script Endpoint","description":"Return the minimal-privilege psql script the customer should run on their source\nPostgreSQL to grant the replication user the access pgstream needs.\n\nOutput shape (idempotent — same connector + same selection => same script):\n    {\n      \"sql\": \"...complete psql artifact...\",\n      \"source_provider\": \"rds\" | \"supabase\" | \"cloudsql\" | \"vanilla\" | ...,\n      \"replication_username\": \"<the username on the connector>\",\n      \"schemas_per_database\": {\"<db>\": [\"<schema>\", ...], ...}\n    }\n\nThe SQL covers (per ARD-1051):\n  - the replication role attribute (provider-specific line),\n  - GRANT CONNECT + GRANT CREATE per database (so pgstream can\n    CREATE PUBLICATION and its bookkeeping schema),\n  - GRANT USAGE + SELECT on tables and sequences per schema,\n  - ALTER DEFAULT PRIVILEGES for both TABLES and SEQUENCES so\n    objects added to source AFTER the grants run also replicate.\n\nErrors:\n  - 404 — connector not found / no RLS access.\n  - 422 — connector is not a PostgreSQL service, discovery has not\n    run, no schemas selected, or connection_details is missing the\n    username field. The detail string names the exact next step.\n  - 500 — Key Vault decryption failed.\n\nNote for RDS sources: this endpoint emits the GRANT line; the\nrds.logical_replication parameter still has to be set to 1 in the\ncluster's parameter group and the instance restarted before logical\nreplication will work. The grant-script comment header reminds the\ncustomer.","operationId":"grant_script_endpoint_v1_connectors__connector_id__grant_script_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/selection":{"post":{"tags":["v1-connectors"],"summary":"Set Selection Endpoint","description":"Set entity selection for indexing.\n\nThis determines which entities (databases, schemas, tables) from the discovered\nschema will be indexed and available for querying.\n\nSpecial Selection Mode:\n- Use \"*\" in selected_paths to select ALL entities (wildcard selection)\n- Example: {\"selected_paths\": [\"*\"]} will index the entire discovered schema\n\nFlow:\n1. Load current connector and schema_structure\n2. Prune schema tree to only include selected paths (or use full schema if \"*\")\n3. Update DB with:\n   - selected_entity_paths (user's input)\n   - selected_schema_structure (pruned tree or full schema)\n   - selection_schema_version (snapshot of current schema_version)\n   - selected_schema_version (incremented counter)\n4. Return pruned schema\n\nAfter selection, user must call POST /{connector_id}/index to apply changes.\n\nRequirements:\n- User must have admin access to connector's org\n- Connector must exist with schema_structure (discovery completed)\n\nWARNING: This does NOT auto-include FK targets! If you select tables with\nforeign key relationships, you must manually select the referenced tables\nor risk dangling references in the indexed schema.","operationId":"set_selection_endpoint_v1_connectors__connector_id__selection_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectionRequest"}}}},"responses":{"200":{"description":"The connector row with the applied selection fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorRow"}}}},"400":{"description":"No discovered schema to select from, or an invalid selection."},"404":{"description":"Connector not found (or not visible to the caller)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/{connector_id}/engine-setup":{"post":{"tags":["v1-connectors"],"summary":"Engine Setup Endpoint","description":"Dispatch a branching-engine setup as an async operation.\n\nThe actual provisioning (Neon project, pgstream, snapshot, RLS) runs\n5–10 minutes — far past the ALB 60s idle timeout — so this endpoint\nreturns 202 with an operation_id within ~1s. The CLI polls\nGET /v1/operations/{id} for stage transitions and the terminal\noutcome (ARD-741).\n\nFast paths preserved from the prior synchronous endpoint:\n  - Already-healthy connector → 200 with the existing connector row.\n  - Wrong starting status → 400 with the rejected status name.\n  - Service has no engine-setup handler → 400.\nAnything past that point goes to the worker.\n\nRequirements:\n  - Connector must exist\n  - branching_engine_status must be retryable for setup dispatch","operationId":"engine_setup_endpoint_v1_connectors__connector_id__engine_setup_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"202":{"description":"Setup started (or joined). Poll `GET /v1/operations/{operation_id}`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationHandle"}}}},"200":{"description":"Nothing to do: the engine is already set up. Returns the connector row with a `message`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorRow"}}}},"400":{"description":"The connector isn't in a state that can run setup."},"403":{"description":"No update permission on this connector."},"404":{"description":"Connector not found (or not visible to the caller)."},"409":{"description":"A conflicting setup operation exists."},"422":{"description":"Setup prerequisites failed (for example, unresolved replica identity decisions)."},"503":{"description":"Ardent could not start the work — safe to retry."}}}},"/v1/connectors/{connector_id}/replica-identity-decisions":{"put":{"tags":["v1-connectors"],"summary":"Set Replica Identity Decisions Endpoint","description":"Record the customer's per-table decisions for ARD-999 preflight.\n\nEvery entry in ``request_body.decisions`` must:\n  - have a key that matches a discovered no-replication-identity\n    table for this connector (``\"<database>.<schema>.<table>\"`` FQN), and\n  - have a value of ``\"exclude\"``, ``\"add_pk\"``, or\n    ``\"replica_identity_full\"``.\n\nValidation fails loud (400) on any mismatch — silent acceptance of\nkeys that don't match would let a typo persist as a dead entry that\nlooks correct in the connector record but has no effect at engine\nsetup time. Tables that exist in the discovered no-replication-\nidentity list but are absent from ``decisions`` revert to the\ndefault ``\"exclude\"`` (the pre-ARD-999 behavior). This endpoint is\na full replace: submit the complete decision set for every table\nthat should keep a non-default decision, because omitted FQNs revert\nto ``\"exclude\"`` even if a prior PUT recorded a different decision.\n\nResponse carries the updated connector with the refreshed\n``replica_identity_preflight`` block (same shape as GET) so the CLI\nand the web wizard can render the post-write state without a follow-\nup round-trip.","operationId":"set_replica_identity_decisions_endpoint_v1_connectors__connector_id__replica_identity_decisions_put","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplicaIdentityDecisionsRequest"}}}},"responses":{"200":{"description":"The refreshed connector row, including `replica_identity_preflight`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorRow"}}}},"400":{"description":"A decision is invalid, covers an unknown table, or the map is incomplete."},"403":{"description":"No update permission on this connector."},"404":{"description":"Connector not found (or not visible to the caller)."},"409":{"description":"The decisions could not be applied — state changed underneath; retry."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/validate-github-repo":{"post":{"tags":["v1-connectors"],"summary":"Validate Github Repo Endpoint","description":"Validate if a GitHub repository exists and is accessible.\n\nThis endpoint proxies the GitHub API check to avoid CORS issues from the frontend.\nValidates repository format and checks accessibility via GitHub API.\n\nArgs:\n    repo: Repository in format \"username/repo\"\n    github_token: Optional GitHub personal access token for private repos\n\nReturns:\n    {\n        \"valid\": bool,\n        \"status\": \"valid\" | \"private\" | \"invalid\" | \"error\",\n        \"message\": str\n    }","operationId":"validate_github_repo_endpoint_v1_connectors_validate_github_repo_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateGitHubRepoRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubRepoValidationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/connectors/validate-github-auth":{"post":{"tags":["v1-connectors"],"summary":"Validate Github Auth Endpoint","description":"Validate GitHub authentication credentials.\n\nFor PAT auth, this verifies the token is valid and retrieves the authenticated user.\nFor OAuth/GitHub App auth, this validates the app credentials.\n\nArgs:\n    auth_type: \"pat\" or \"oauth\"\n    access_token: GitHub Personal Access Token (for PAT auth)\n    app_id, installation_id, private_key: GitHub App credentials (for OAuth)\n\nReturns:\n    {\n        \"valid\": bool,\n        \"status\": \"valid\" | \"invalid\" | \"error\",\n        \"message\": str,\n        \"username\": str | None  # The authenticated user/app name\n    }","operationId":"validate_github_auth_endpoint_v1_connectors_validate_github_auth_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateGitHubAuthRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubAuthValidationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/projects":{"post":{"tags":["v1-projects"],"summary":"Create Project Endpoint","description":"Create a new project.","operationId":"create_project_endpoint_v1_projects_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}}},"responses":{"201":{"description":"The created project row.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectRow"}}}},"409":{"description":"A project with this name already exists."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["v1-projects"],"summary":"List Projects Endpoint","description":"List all projects for an org. RLS automatically filters by access.","operationId":"list_projects_endpoint_v1_projects_get","parameters":[{"name":"org_id","in":"query","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/projects/{project_id}":{"get":{"tags":["v1-projects"],"summary":"Get Project Endpoint","description":"Get a single project.","operationId":"get_project_endpoint_v1_projects__project_id__get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectRow"}}}},"404":{"description":"Project not found (or not visible to the caller)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["v1-projects"],"summary":"Update Project Endpoint","description":"Update mutable project fields. Only provided fields are changed.","operationId":"update_project_endpoint_v1_projects__project_id__patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectRequest"}}}},"responses":{"200":{"description":"The updated project row.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectRow"}}}},"400":{"description":"No fields to update."},"404":{"description":"Project not found (or not visible to the caller)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["v1-projects"],"summary":"Delete Project Endpoint","description":"Delete a project. Cascades to child resources via ON DELETE CASCADE.","operationId":"delete_project_endpoint_v1_projects__project_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Deleted. Body is `{\"message\": \"Project deleted\"}`.","content":{"application/json":{"schema":{}}}},"403":{"description":"Not authorized to delete this project."},"404":{"description":"Project not found (or not visible to the caller)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/environments/aws-setup-link":{"post":{"tags":["v1-environments"],"summary":"Create Aws Setup Link Endpoint","operationId":"create_aws_setup_link_endpoint_v1_environments_aws_setup_link_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAwsSetupLinkRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/environments/aws-account-connections/{aws_account_connection_id}":{"patch":{"tags":["v1-environments"],"summary":"Confirm Aws Account Connection Endpoint","operationId":"confirm_aws_account_connection_endpoint_v1_environments_aws_account_connections__aws_account_connection_id__patch","parameters":[{"name":"aws_account_connection_id","in":"path","required":true,"schema":{"type":"string","title":"Aws Account Connection Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmAwsAccountConnectionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/environments":{"get":{"tags":["v1-environments"],"summary":"List Environments Endpoint","operationId":"list_environments_endpoint_v1_environments_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["v1-environments"],"summary":"Create Environment Endpoint","operationId":"create_environment_endpoint_v1_environments_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/environments/{environment_id}/neon-api-key":{"post":{"tags":["v1-environments"],"summary":"Rotate Environment Neon Api Key Endpoint","operationId":"rotate_environment_neon_api_key_endpoint_v1_environments__environment_id__neon_api_key_post","parameters":[{"name":"environment_id","in":"path","required":true,"schema":{"type":"string","title":"Environment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotateNeonApiKeyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/environments/aws-account-connections":{"get":{"tags":["v1-environments"],"summary":"List Aws Account Connections Endpoint","operationId":"list_aws_account_connections_endpoint_v1_environments_aws_account_connections_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/environments/{environment_id}/redeploy":{"post":{"tags":["v1-environments"],"summary":"Redeploy Environment Endpoint","operationId":"redeploy_environment_endpoint_v1_environments__environment_id__redeploy_post","parameters":[{"name":"environment_id","in":"path","required":true,"schema":{"type":"string","title":"Environment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/environments/{environment_id}":{"get":{"tags":["v1-environments"],"summary":"Get Environment Endpoint","operationId":"get_environment_endpoint_v1_environments__environment_id__get","parameters":[{"name":"environment_id","in":"path","required":true,"schema":{"type":"string","title":"Environment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["v1-environments"],"summary":"Delete Environment Endpoint","operationId":"delete_environment_endpoint_v1_environments__environment_id__delete","parameters":[{"name":"environment_id","in":"path","required":true,"schema":{"type":"string","title":"Environment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/environments/{environment_id}/private-link-template":{"get":{"tags":["v1-environments"],"summary":"Get Private Link Template Endpoint","operationId":"get_private_link_template_endpoint_v1_environments__environment_id__private_link_template_get","parameters":[{"name":"environment_id","in":"path","required":true,"schema":{"type":"string","title":"Environment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/environments/{environment_id}/private-links":{"get":{"tags":["v1-environments"],"summary":"List Private Links Endpoint","operationId":"list_private_links_endpoint_v1_environments__environment_id__private_links_get","parameters":[{"name":"environment_id","in":"path","required":true,"schema":{"type":"string","title":"Environment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["v1-environments"],"summary":"Create Private Link Endpoint","operationId":"create_private_link_endpoint_v1_environments__environment_id__private_links_post","parameters":[{"name":"environment_id","in":"path","required":true,"schema":{"type":"string","title":"Environment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrivateLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/environments/{environment_id}/private-links/{private_link_id}":{"delete":{"tags":["v1-environments"],"summary":"Delete Private Link Endpoint","operationId":"delete_private_link_endpoint_v1_environments__environment_id__private_links__private_link_id__delete","parameters":[{"name":"environment_id","in":"path","required":true,"schema":{"type":"string","title":"Environment Id"}},{"name":"private_link_id","in":"path","required":true,"schema":{"type":"string","title":"Private Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/user/github/status":{"get":{"tags":["v1-github"],"summary":"Get Github Status","description":"Check if the current user has GitHub connected.\n\nReturns connection status, username, granted scopes, and whether unlink is allowed.","operationId":"get_github_status_v1_user_github_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubStatusResponse"}}}}}}},"/v1/user/github/connect":{"post":{"tags":["v1-github"],"summary":"Connect Github","description":"Store GitHub credentials after successful OAuth flow.\n\nCalled by frontend after Supabase linkIdentity() or initial OAuth login.\nThe access_token is received from Supabase's session as provider_token.\n\nBody:\n    access_token: GitHub OAuth access token (from provider_token)\n    scopes: List of OAuth scopes granted (e.g., ['repo', 'user:email'])","operationId":"connect_github_v1_user_github_connect_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubConnectRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubConnectResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/user/github/unlink":{"post":{"tags":["v1-github"],"summary":"Unlink Github","description":"Disconnect GitHub from the current user's account.\n\nNote: This removes our stored token but does NOT revoke it on GitHub's side.\nThe user should also unlink in Supabase if they want full disconnection.\n\nWill refuse to unlink if GitHub is the user's only login method.","operationId":"unlink_github_v1_user_github_unlink_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubUnlinkResponse"}}}}}}},"/v1/github/repos/search":{"get":{"tags":["v1-github"],"summary":"Search Repos","description":"Search GitHub repositories.\n\nWorks without GitHub connection (public repos only, lower rate limit).\nIf user has GitHub connected, uses their token for higher rate limit\nand to include their private repos in results.\n\nQuery params:\n    q: Search query (required)\n    per_page: Number of results (default 10, max 100)","operationId":"search_repos_v1_github_repos_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","title":"Q"}},{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","default":10,"title":"Per Page"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubRepoSearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/github/repos/mine":{"get":{"tags":["v1-github"],"summary":"Get My Repos","description":"Get the current user's GitHub repositories.\n\nRequires GitHub connection. Returns both public and private repos\nif the 'repo' scope was granted.\n\nQuery params:\n    per_page: Number of results (default 30, max 100)","operationId":"get_my_repos_v1_github_repos_mine_get","parameters":[{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Per Page"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubUserReposResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/github-app/status":{"get":{"tags":["v1-github-app"],"summary":"Get Github App Status","description":"Check if the current user has GitHub App installed.\n\nReturns installation status and summary.","operationId":"get_github_app_status_v1_github_app_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstallationStatusResponse"}}}}}}},"/v1/github-app/installations":{"get":{"tags":["v1-github-app"],"summary":"List Installations","description":"List all active GitHub App installations for the current user.","operationId":"list_installations_v1_github_app_installations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListInstallationsResponse"}}}}}},"post":{"tags":["v1-github-app"],"summary":"Register Installation","description":"Register a new GitHub App installation.\n\nCalled by frontend after user completes installation on GitHub.\nFetches installation details from GitHub API and stores in database.","operationId":"register_installation_v1_github_app_installations_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterInstallationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterInstallationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/github-app/repos":{"get":{"tags":["v1-github-app"],"summary":"List Repos","description":"List all repositories accessible via user's GitHub App installations.\n\nFetches repos from GitHub API for each active installation.","operationId":"list_repos_v1_github_app_repos_get","parameters":[{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Per Page"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListReposResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/github-app/webhook":{"post":{"tags":["v1-github-app"],"summary":"Handle Webhook","description":"Handle GitHub App webhook events.\n\nEvents:\n- installation: created, deleted, suspend, unsuspend\n- installation_repositories: added, removed\n\nSecurity: Webhook signature is ALWAYS verified. If GITHUB_APP_WEBHOOK_SECRET\nis not configured, all requests are rejected.","operationId":"handle_webhook_v1_github_app_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Handle Webhook V1 Github App Webhook Post"}}}}}}},"/v1/posthog/event":{"post":{"tags":["v1-posthog"],"summary":"Add User Action","description":"Accept a list of telemetry events and forward each to PostHog.","operationId":"add_user_action_v1_posthog_event_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/system/git-info":{"get":{"tags":["v1-system"],"summary":"Get Git Branch","description":"Get the current git branch name for the repository.\n\nReturns:\n    JSONResponse containing:\n    - branch: Current git branch name\n    - error: Any error that occurred (if any)","operationId":"get_git_branch_v1_system_git_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/internal/neon/orphan-projects":{"get":{"tags":["v1-internal"],"summary":"List Orphan Neon Projects Route","description":"Admin-only: list currently classified orphan Ardent-managed Neon projects.","operationId":"list_orphan_neon_projects_route_v1_internal_neon_orphan_projects_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Orphan Neon Projects Route V1 Internal Neon Orphan Projects Get"}}}}}}},"/v1/internal/neon/orphan-projects/reclaim":{"post":{"tags":["v1-internal"],"summary":"Reclaim Orphan Neon Projects Route","description":"Admin-only: delete explicitly requested orphan Neon projects with audit.","operationId":"reclaim_orphan_neon_projects_route_v1_internal_neon_orphan_projects_reclaim_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrphanNeonProjectReclaimRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Reclaim Orphan Neon Projects Route V1 Internal Neon Orphan Projects Reclaim Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/recover-engine-setup":{"post":{"tags":["v1-internal"],"summary":"Recover Engine Setup Route","description":"Admin-only: replace a stale active connector engine-setup operation.\n\nThis is the audited manual lever for strands where the customer retry\nendpoint must keep reusing the active async_operation, but DBOS no longer\nhas a worker-executing workflow for that operation.","operationId":"recover_engine_setup_route_v1_internal_connectors__connector_id__recover_engine_setup_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecoverEngineSetupRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/reset":{"post":{"tags":["v1-internal"],"summary":"Reset Connector Route","description":"Admin-only: dispatch a connector reset as an async operation.\n\nReturns 202 with an operation_id; the actual reset (drop pgstream,\nre-snapshot Neon main, re-deploy CDC) routinely runs several\nminutes and would otherwise blow the ALB 60s idle timeout. The\ncaller polls GET /v1/operations/{id} for stage transitions and the\nterminal outcome (ARD-741).\n\nBranches and Neon project survive the reset by design — see\nreset_connector for the safety contract.\n\nArgs:\n    force: When true, bypass the in-flight WAL/Kafka drain wait\n        inside the pgstream teardown step (ARD-870). Operator accepts\n        that any un-replicated data is abandoned.","operationId":"reset_connector_route_v1_internal_connectors__connector_id__reset_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/reconcile-pgstream-deployments":{"post":{"tags":["v1-internal"],"summary":"Reconcile Pgstream Deployments Route","description":"Admin-only: reconcile connector pgstream state from live Kubernetes.","operationId":"reconcile_pgstream_deployments_route_v1_internal_connectors__connector_id__reconcile_pgstream_deployments_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Reconcile Pgstream Deployments Route V1 Internal Connectors  Connector Id  Reconcile Pgstream Deployments Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/reconcile-pgstream-relax-fk-env":{"post":{"tags":["v1-internal"],"summary":"Reconcile Pgstream Relax Fk Env Route","description":"Admin-only: reconcile live pgstream writer FK-relaxation env from config.","operationId":"reconcile_pgstream_relax_fk_env_route_v1_internal_connectors__connector_id__reconcile_pgstream_relax_fk_env_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"allow_active_restart","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Allow Active Restart"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Reconcile Pgstream Relax Fk Env Route V1 Internal Connectors  Connector Id  Reconcile Pgstream Relax Fk Env Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/branches/{branch_id}/mark-masked-ready":{"post":{"tags":["v1-internal"],"summary":"Mark Branch Masked Ready Route","description":"Admin-only: release a branch hook-readiness gate with durable audit.","operationId":"mark_branch_masked_ready_route_v1_internal_branches__branch_id__mark_masked_ready_post","parameters":[{"name":"branch_id","in":"path","required":true,"schema":{"type":"string","title":"Branch Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkBranchMaskedReadyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Mark Branch Masked Ready Route V1 Internal Branches  Branch Id  Mark Masked Ready Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/deep-reset":{"post":{"tags":["v1-internal"],"summary":"Deep Reset Connector Route","description":"Admin-only: dispatch a per-source-DB connector deep reset (ARD-1273).\n\nRebuilds ONE source DB's pgstream pipeline (delete pgstream -> wipe its\nbranch target schemas -> redeploy -> validate) without disturbing the\nconnector's other source DBs. Returns 202 with an operation_id; the caller\npolls GET /v1/operations/{id}. The destructive work runs on the DBOS byoc\nqueue, not on this request-serving pod.\n\nRefuses with 400 when ``source_db`` is unknown (not a deployed, selected\ndatabase). Coalescing is connector-scoped: the operation resource_id is the\nconnector id and the requested ``source_db`` is stored in ``result``. A\nsecond deep reset of the same source DB reuses the in-flight operation; a\ndifferent source DB on the same connector returns 409 because connector\nstatus and engine_config are connector-level state.","operationId":"deep_reset_connector_route_v1_internal_connectors__connector_id__deep_reset_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"source_db","in":"query","required":true,"schema":{"type":"string","title":"Source Db"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/debezium-shadow-compare":{"post":{"tags":["v1-internal"],"summary":"Debezium Shadow Compare Connector Route","description":"Admin-only: dispatch shadow parity compare and isolated-target apply.","operationId":"debezium_shadow_compare_connector_route_v1_internal_connectors__connector_id__debezium_shadow_compare_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DebeziumShadowCompareRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/debezium-shadow-cleanup":{"post":{"tags":["v1-internal"],"summary":"Debezium Shadow Cleanup Connector Route","description":"Admin-only: dispatch Debezium shadow cleanup without touching pgstream.","operationId":"debezium_shadow_cleanup_connector_route_v1_internal_connectors__connector_id__debezium_shadow_cleanup_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DebeziumShadowCleanupRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/debezium-cutover":{"post":{"tags":["v1-internal"],"summary":"Debezium Cutover Connector Route","description":"Admin-only: dispatch a DBOS-backed replication cutover operation.","operationId":"debezium_cutover_connector_route_v1_internal_connectors__connector_id__debezium_cutover_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DebeziumCutoverRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/debezium-rollback":{"post":{"tags":["v1-internal"],"summary":"Debezium Rollback Connector Route","description":"Admin-only: dispatch a DBOS-backed replication rollback operation.","operationId":"debezium_rollback_connector_route_v1_internal_connectors__connector_id__debezium_rollback_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DebeziumRollbackRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/debezium-post-cutover-reconciliation":{"post":{"tags":["v1-internal"],"summary":"Debezium Post Cutover Reconciliation Route","description":"Admin-only: run exact source/target reconciliation after cutover.","operationId":"debezium_post_cutover_reconciliation_route_v1_internal_connectors__connector_id__debezium_post_cutover_reconciliation_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DebeziumPostCutoverReconciliationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/debezium-repair":{"post":{"tags":["v1-internal"],"summary":"Debezium Repair Route","description":"Admin-only: run a synchronous Debezium repair action with audit.","operationId":"debezium_repair_route_v1_internal_connectors__connector_id__debezium_repair_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DebeziumRepairRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/debezium-migration/timeline":{"get":{"tags":["v1-internal"],"summary":"Debezium Migration Timeline Route","description":"Admin-only: return a connector's Debezium migration event timeline.","operationId":"debezium_migration_timeline_route_v1_internal_connectors__connector_id__debezium_migration_timeline_get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"source_database","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Database"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Debezium Migration Timeline Route V1 Internal Connectors  Connector Id  Debezium Migration Timeline Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/debezium-migration/open-intents":{"get":{"tags":["v1-internal"],"summary":"Debezium Migration Open Intents Route","description":"Admin-only: inspect currently open Debezium migration intents.","operationId":"debezium_migration_open_intents_route_v1_internal_connectors__connector_id__debezium_migration_open_intents_get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"source_database","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Database"}},{"name":"expired_only","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Expired Only"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Debezium Migration Open Intents Route V1 Internal Connectors  Connector Id  Debezium Migration Open Intents Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/debezium-migration/reconcile":{"post":{"tags":["v1-internal"],"summary":"Debezium Migration Reconcile Route","description":"Admin-only: reconcile expired open Debezium migration intents.","operationId":"debezium_migration_reconcile_route_v1_internal_connectors__connector_id__debezium_migration_reconcile_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DebeziumMigrationReconcileRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Debezium Migration Reconcile Route V1 Internal Connectors  Connector Id  Debezium Migration Reconcile Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/rollout":{"post":{"tags":["v1-internal"],"summary":"Rollout Connector Route","description":"Admin-only: dispatch a DBOS-backed connector rollout operation.","operationId":"rollout_connector_route_v1_internal_connectors__connector_id__rollout_post","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorRolloutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/environments/{environment_id}/redeploy":{"post":{"tags":["v1-internal"],"summary":"Redeploy Environment Route","description":"Admin-only: re-drive a BYOC environment deploy.\n\n`environment_deploy` now runs as a DBOS durable workflow\n(`run_environment_deploy`, `environment_deploy.v1`). A backend rollout or\nworker crash mid-deploy no longer fails the deploy — DBOS resumes it from\nthe last completed step on the next worker — and the legacy reaper no\nlonger governs deploy operations (it skips `runtime='dbos'` rows). So this\nroute is a manual re-drive for the residual cases the automatic path does\nnot cover: a genuinely terminal failure, or a deploy whose workflow died\nafter reaching a terminal error (e.g. the success write exhausted its\nretries, leaving the environment stuck `provisioning` with a terminal\noperation that nothing else re-drives). Because every deploy step is\nidempotent, customer-triggered retries are now safe too.\n\nEverything the workflow needs is already persisted: the `environments`\nrow, its `environment_resources` rows, and the AKV-referenced\n`external_id` / `neon_api_key`. It re-reads all of it from `environment_id`\nalone, so an operator can re-drive a stuck deploy with no customer\ninvolvement.\n\nBehavior by current status:\n  * `failed` — claim a fresh deploy (flip to `provisioning`, enqueue).\n  * `pending` / `provisioning` — if a deploy workflow is genuinely live,\n    return its operation unchanged; otherwise the prior operation stranded,\n    so terminalize it and enqueue a fresh one (the environment is already\n    `provisioning`).\n  * anything else — 409.\n\nReturns 202 with an operation_id; an EKS environment deploy routinely runs\n~25 minutes and would otherwise blow the ALB 60s idle timeout. The caller\npolls GET /v1/operations/{id} for stage transitions and the terminal\noutcome.","operationId":"redeploy_environment_route_v1_internal_environments__environment_id__redeploy_post","parameters":[{"name":"environment_id","in":"path","required":true,"schema":{"type":"string","title":"Environment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/health":{"get":{"tags":["v1-internal-health"],"summary":"List Connectors Health Endpoint","description":"List connector health state rows with filters.\n\nEach query parameter that accepts multiple values (status, cluster_name,\norg_id) AND-combines across distinct keys but OR-combines (IN) within\none key. Example query string:\n\n    ?status=crashing&status=wal_slot_held_by_stale_walsender&cluster_name=ardent-aws-prod-eks\n\nreturns rows where status ∈ {crashing, wal_slot_held_by_stale_walsender}\nAND cluster_name = ardent-aws-prod-eks.","operationId":"list_connectors_health_endpoint_v1_internal_connectors_health_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Status"}},{"name":"cluster_name","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Cluster Name"}},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Org Id"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Search"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Connectors Health Endpoint V1 Internal Connectors Health Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/health/coverage":{"get":{"tags":["v1-internal-health"],"summary":"List Connector Health Coverage Endpoint","description":"Fleet view of streaming connectors with absent or stale health rows.\n\nThe inverse of the list view above: instead of the health rows that exist,\nthis returns the connectors in a live apply state whose declared pgstream\ndeployments have no fresh ``connector_health_state`` row — the silent gap\nwhere a connector reads healthy by absence of evidence (ARD-1247). ``missing``\ngaps sort ahead of ``stale`` ones. Same verdict the Honeycomb coverage\ntriggers page on, served on demand for the operator console.","operationId":"list_connector_health_coverage_endpoint_v1_internal_connectors_health_coverage_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Connector Health Coverage Endpoint V1 Internal Connectors Health Coverage Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/health/unreconciled-pgstream":{"get":{"tags":["v1-internal-health"],"summary":"List Unreconciled Pgstream Deployments Endpoint","description":"List setup-state connectors that have live K8s pgstream deployments\nbut no persisted ``engine_config.pgstream_deployments`` entry.\n\nThis is the ARD-1430 operator view: health-row coverage cannot see a\nDeployment whose name was never stored on the connector, so this endpoint\nasks Kubernetes directly for bounded pages of setup-state connectors.\nPagination is over the connector page; ``unreconciled_count`` is the\nfiltered row count within that page.","operationId":"list_unreconciled_pgstream_deployments_endpoint_v1_internal_connectors_health_unreconciled_pgstream_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Unreconciled Pgstream Deployments Endpoint V1 Internal Connectors Health Unreconciled Pgstream Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/health/{connector_id}":{"get":{"tags":["v1-internal-health"],"summary":"Get Connector Health Endpoint","description":"Drill-down view: every deployment for one connector + recent events.\n\nWhen the connector has health rows, returns them plus the current coverage\nverdict so stale/superseded rows cannot mask a missing current deployment.\nWhen it has none, we no longer collapse straight to 404 (ARD-1247): if the\nconnector exists AND is in a live apply state, it is EXPECTED to be observed,\nso we return an explicit ``not_observed`` payload (200) instead. Only a\nconnector that does not exist, or is not in a streaming state (no coverage\nstory to tell), still 404s.","operationId":"get_connector_health_endpoint_v1_internal_connectors_health__connector_id__get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Connector Health Endpoint V1 Internal Connectors Health  Connector Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/quarantine/{quarantine_id}/release":{"post":{"tags":["v1-internal-health"],"summary":"Release Connector Quarantine Endpoint","description":"Staff-gated release for a quarantined pgstream Deployment.\n\nMirrors POST /v1/connectors/{cid}/quarantine/{qid}/release but lives under\n/internal/* so the connectors-health drilldown UI can release a quarantine\nwithout requiring its operator to also hold ``connectors.update`` on the\ncustomer's connector. Staff don't carry org membership for customer orgs;\nthe per-connector check on the public endpoint would 403 them on every\ncustomer they're paged for.\n\nAuthorization: ``verify_staff_auth`` (is_ardent_staff = TRUE) only.\nAudit: ``released_by`` is set to the staff user_id, identical to the\npublic endpoint, so the quarantine row's audit trail is preserved.\nIdempotent — already-released rows return the current state via\n``mark_quarantine_released``'s fallback path.","operationId":"release_connector_quarantine_endpoint_v1_internal_connectors_quarantine__quarantine_id__release_post","parameters":[{"name":"quarantine_id","in":"path","required":true,"schema":{"type":"string","title":"Quarantine Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Release Connector Quarantine Endpoint V1 Internal Connectors Quarantine  Quarantine Id  Release Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/readiness-checks":{"get":{"tags":["v1-internal-health"],"summary":"List Internal Readiness Checks Endpoint","description":"Operator drill-down on the ARD-720 post-snapshot validation paper trail.\n\nReturns one row per (attempt_id, check_name, subject) — the\nappend-only evidence written by the engine-setup gate. Operators use\nthis to answer \"why is this connector in failed_validation\" without\nneeding SQL access.\n\nFilters:\n- ``attempt_id`` narrows to one engine-setup attempt (latest first by\n  default — combine with the rollup view below to find the right id).\n- ``check_name`` narrows to a single validator family, such as\n  ``row_count``, ``snapshot_completion``, ``domain_presence``,\n  ``table_presence``, ``column_shape``, ``pk_presence``,\n  ``unique_identity_presence``, ``fk_validity``, ``fk_presence``,\n  ``policy_presence``, ``infra_signal``, or ``unlogged_table_skipped``.\n- ``only_failed`` shows just the rows that drove the\n  ``failed_validation`` verdict — the operator's primary view when\n  paged.\n\nNote: ``policy_presence`` rows with ``observed.present=false`` are\ninformational by default and can appear on a ``healthy`` connector, so\ndo not combine that drill-down with ``only_failed=true`` unless the\nconnector opted into strict replicated-policy gating.","operationId":"list_internal_readiness_checks_endpoint_v1_internal_connectors__connector_id__readiness_checks_get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"attempt_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Attempt Id"}},{"name":"check_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Check Name"}},{"name":"only_failed","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Only Failed"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":5000,"minimum":1,"default":500,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Internal Readiness Checks Endpoint V1 Internal Connectors  Connector Id  Readiness Checks Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/internal/connectors/{connector_id}/readiness-attempts":{"get":{"tags":["v1-internal-health"],"summary":"List Internal Readiness Attempts Endpoint","description":"Roll up branch_readiness_checks into one summary per attempt.\n\nOperators land here first to see \"this connector has run engine-setup\nN times, here's the pass/fail count for each\", then drill into the\nper-row evidence via the readiness-checks endpoint above.","operationId":"list_internal_readiness_attempts_endpoint_v1_internal_connectors__connector_id__readiness_attempts_get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":5000,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Internal Readiness Attempts Endpoint V1 Internal Connectors  Connector Id  Readiness Attempts Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/operations/{operation_id}":{"get":{"tags":["v1-operations"],"summary":"Get Operation Endpoint","description":"Return the current state of an async operation.\n\nPolled or long-polled by clients to drive operation progress.\nRLS scopes visibility to operations whose resource (connector) the\ncaller can read; an operation belonging to another tenant looks\nlike a 404 to a non-member rather than leaking existence.\n\nReturns the AsyncOperationResponse shape — see models.py.","operationId":"get_operation_endpoint_v1_operations__operation_id__get","parameters":[{"name":"operation_id","in":"path","required":true,"schema":{"type":"string","title":"Operation Id"}},{"name":"wait","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":10.0,"minimum":0},{"type":"null"}],"description":"Optionally wait up to this many seconds for a terminal operation state. Omit for the existing immediate poll response.","title":"Wait"},"description":"Optionally wait up to this many seconds for a terminal operation state. Omit for the existing immediate poll response."}],"responses":{"200":{"description":"Current operation state. On `completed`, `result` holds the outcome — for `branch_create`, the full branch details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncOperationResponse"}}}},"404":{"description":"Operation not found (or not visible to the caller)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/branch/create":{"post":{"tags":["v1-branching"],"summary":"Create Service Branch","description":"CLI endpoint to create a new branch for a connector.","operationId":"create_service_branch_v1_branch_create_post","responses":{"202":{"description":"Create accepted. Poll `GET /v1/operations/{operation_id}` for the branch details. Idempotent replays carry an `X-Idempotency-Replay: true` response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationHandle"}}}},"400":{"description":"A required field is missing, or the branch name or idempotency key is invalid."},"409":{"description":"A branch with this name already exists on the connector, this create is already in flight, or the idempotency key was reused for a different request."},"422":{"description":"The connector's engine isn't ready to branch."},"503":{"description":"Ardent could not start the work — safe to retry."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"description":"Body of POST /v1/branch/create.\n\nSpec-only today: the handler parses the raw body by hand so a missing\nfield keeps returning the documented 400, not Pydantic's 422. Keep the\nfields in sync with the hand parsing below.","properties":{"connector_id":{"description":"Connector to branch from.","title":"Connector Id","type":"string"},"service_type":{"description":"Service to branch; `postgres`, not the connector type `postgresql`.","title":"Service Type","type":"string"},"name":{"description":"Branch name, unique per connector.","title":"Name","type":"string"}},"required":["connector_id","service_type","name"],"title":"BranchCreateRequest","type":"object"}}}},"parameters":[{"in":"header","name":"X-Idempotency-Key","required":false,"schema":{"type":"string"},"description":"Makes retries safe: re-sending the same connector, service type, and name resumes the original request instead of creating a duplicate."}]}},"/v1/branch/route":{"post":{"tags":["v1-branching"],"summary":"Route Proxy Connection","description":"Internal endpoint for the proxy to route a connection to the correct branch.","operationId":"route_proxy_connection_v1_branch_route_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/branches/{connector_id}":{"get":{"tags":["v1-branching"],"summary":"Get Branches","description":"Get branch metadata for a connector.\n\nAuthorization: User must be authenticated and the connector must belong to\nan org the user has access to. RLS on branches checks\ncurrent_user_accessible_connectors.","operationId":"get_branches_v1_branches__connector_id__get","parameters":[{"name":"connector_id","in":"path","required":true,"schema":{"type":"string","title":"Connector Id"}}],"responses":{"200":{"description":"Up to 100 branch rows for the connector. Rows may carry additional columns beyond the documented core.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BranchRow"},"title":"Response 200 Get Branches V1 Branches  Connector Id  Get"}}}},"404":{"description":"Connector not found (or not visible to the caller)."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/policies":{"post":{"tags":["v1-policies"],"summary":"Create Policy Endpoint","description":"Create a new policy for an org. If assign_to_scope is provided, also\ncreate the assignment in the same request and roll the policy back if\nassignment fails — CLI settings set uses this to avoid orphan policies.\n\nassign_to_scope shape: {\"scope_type\": \"connectors\"|\"orgs\"|\"branches\",\n\"scope_id\": \"...\", \"priority\": 100 (optional)}. Omit priority on\nbranch_create_hook assignments to auto-append after existing hooks in the\nsame scope using HOOK_PRIORITY_GAP.","operationId":"create_policy_endpoint_v1_policies_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"get":{"tags":["v1-policies"],"summary":"List Policies Endpoint","description":"List policies for an org. If connector_id is given, return only policies\nthat have a connector-scoped assignment to that connector — used by the\nCLI settings commands to avoid an N+1 walk over every policy.","operationId":"list_policies_endpoint_v1_policies_get","parameters":[{"name":"org_id","in":"query","required":true,"schema":{"type":"string","title":"Org Id"}},{"name":"connector_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Connector Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/policies/{policy_id}":{"get":{"tags":["v1-policies"],"summary":"Get Policy Endpoint","description":"Get a single policy by ID.","operationId":"get_policy_endpoint_v1_policies__policy_id__get","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","title":"Policy Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["v1-policies"],"summary":"Update Policy Endpoint","description":"Update a policy's name/config and optionally one assignment's run order.","operationId":"update_policy_endpoint_v1_policies__policy_id__patch","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","title":"Policy Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["v1-policies"],"summary":"Delete Policy Endpoint","description":"Delete a policy. Cascades to all its assignments.","operationId":"delete_policy_endpoint_v1_policies__policy_id__delete","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","title":"Policy Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/policies/{policy_id}/assignments":{"post":{"tags":["v1-policies"],"summary":"Create Assignment Endpoint","description":"Assign a policy to a scope (org, connector, or branch).","operationId":"create_assignment_endpoint_v1_policies__policy_id__assignments_post","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","title":"Policy Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["v1-policies"],"summary":"List Assignments Endpoint","description":"List all scope assignments for a policy.","operationId":"list_assignments_endpoint_v1_policies__policy_id__assignments_get","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","title":"Policy Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["v1-policies"],"summary":"Update Assignment Endpoint","description":"Update an existing assignment's run-order priority for one scope.\n\nThe CLI calls this when ``settings set branch_sql --order`` changes the run\norder of a hook that already exists (the policy PATCH only touches config).\nScope is named in the body via (scope_type, scope_id) so a policy assigned\nto several scopes stays individually addressable.","operationId":"update_assignment_endpoint_v1_policies__policy_id__assignments_patch","parameters":[{"name":"policy_id","in":"path","required":true,"schema":{"type":"string","title":"Policy Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/policy_assignments/{assignment_id}":{"delete":{"tags":["v1-policies"],"summary":"Delete Assignment Endpoint","description":"Remove a policy assignment.","operationId":"delete_assignment_endpoint_v1_policy_assignments__assignment_id__delete","parameters":[{"name":"assignment_id","in":"path","required":true,"schema":{"type":"string","title":"Assignment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/branches/{branch_id}/policy_log":{"get":{"tags":["v1-policies"],"summary":"Get Branch Policy Log Endpoint","description":"Get policy execution log for a branch.","operationId":"get_branch_policy_log_endpoint_v1_branches__branch_id__policy_log_get","parameters":[{"name":"branch_id","in":"path","required":true,"schema":{"type":"string","title":"Branch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cli/auth/init":{"post":{"tags":["v1-cli"],"summary":"Cli Auth Init","description":"Initialize a CLI auth session.\n\nCalled by CLI before opening browser. Creates a pending session\nthat will be completed after OAuth.\n\nReturns:\n    session_id: Unique session identifier for polling\n    auth_url: URL to open in browser (goes directly to OAuth)","operationId":"cli_auth_init_v1_cli_auth_init_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/cli/auth/poll":{"get":{"tags":["v1-cli"],"summary":"Cli Auth Poll","description":"Poll for CLI auth completion.\n\nCalled by CLI repeatedly until status is 'completed'.\n\nArgs:\n    session: Session ID from /init\n\nReturns:\n    status: 'pending' | 'completed' | 'expired'\n    token: API key (only when completed)","operationId":"cli_auth_poll_v1_cli_auth_poll_get","parameters":[{"name":"session","in":"query","required":true,"schema":{"type":"string","title":"Session"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cli/auth/complete":{"post":{"tags":["v1-cli"],"summary":"Cli Auth Complete","description":"Complete CLI auth after OAuth.\n\nCalled by frontend after successful OAuth. Creates an API key\nand updates the session so CLI can retrieve it.\n\nHandles new users by auto-creating a personal org.\n\nRequires: Authenticated user (Supabase JWT)\n\nBody:\n    session_id: Session ID from CLI","operationId":"cli_auth_complete_v1_cli_auth_complete_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/cli/auth/select-org":{"post":{"tags":["v1-cli"],"summary":"Cli Auth Select Org","description":"Complete CLI auth with a selected org (for multi-org users).\n\nCalled after cli_auth_complete returns needs_org_selection.\n\nBody:\n    session_id: The CLI auth session ID\n    org_id: The selected organization ID\n\nReturns:\n    status: \"completed\"","operationId":"cli_auth_select_org_v1_cli_auth_select_org_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CLIAuthSelectOrgRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cli/me":{"get":{"tags":["v1-cli"],"summary":"Cli Get Me","description":"Get current user profile for CLI status display.\n\nReturns user info (name, email) and org info for the authenticated API key.","operationId":"cli_get_me_v1_cli_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/cli/connectors":{"get":{"tags":["v1-cli"],"summary":"Cli List Connectors","description":"List connectors for CLI user.\n\nReturns connectors for the authenticated user's org.\nIf project_id is provided, filters to connectors in that project.","operationId":"cli_list_connectors_v1_cli_connectors_get","parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cli/branches":{"get":{"tags":["v1-cli"],"summary":"Cli List Branches","description":"List branches for CLI user's current connector.\n\nconnector_id is required — scopes branches to a specific connector.","operationId":"cli_list_branches_v1_cli_branches_get","parameters":[{"name":"connector_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Connector Id"}},{"name":"branch_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Branch Id"}},{"name":"branch_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Branch Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cli/branches/{branch_id}":{"delete":{"tags":["v1-cli"],"summary":"Cli Delete Branch","description":"Delete a branch asynchronously (ARD-1453), in parity with branch create.\n\nReturns 202 + an operation handle; the CLI polls\n``GET /v1/operations/{operation_id}`` for staged progress and the terminal\noutcome. The teardown runs in the ``branch_delete.v1`` DBOS durable workflow\n(mark deleting -> external cleanup -> finalize), so a crash mid-teardown is\nrecovered by DBOS rather than stranding the row in ``deleting`` with no\nretry driver. Audit ordering and the partial-cleanup terminal-failed\nsemantics are preserved inside the workflow.\n\nIdempotency:\n  * A concurrent or retried delete of the same branch coalesces onto the\n    active operation via the ``(type, resource_id)`` partial unique index —\n    no second workflow is enqueued.\n  * A re-delete of an already-gone branch polls the prior delete operation\n    to completion (clean no-op) instead of 404ing.","operationId":"cli_delete_branch_v1_cli_branches__branch_id__delete","parameters":[{"name":"branch_id","in":"path","required":true,"schema":{"type":"string","title":"Branch Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cli/invite":{"post":{"tags":["v1-cli"],"summary":"Cli Invite User","description":"Invite a user to the organization via CLI.\n\nUses API key auth to determine org_id.\nSends invite email via Supabase.\n\nBody:\n    email: Email address to invite\n    role: Role to assign (owner/admin/member/viewer), defaults to \"member\"\n\nReturns:\n    success: True if invite sent\n    email: The invited email\n    role: The role they'll receive","operationId":"cli_invite_user_v1_cli_invite_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/cli/invites":{"get":{"tags":["v1-cli"],"summary":"Cli List Invites","description":"List pending invites for the organization.","operationId":"cli_list_invites_v1_cli_invites_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"delete":{"tags":["v1-cli"],"summary":"Cli Delete Invite","description":"Delete/revoke a pending invite by email.\n\nBody:\n    email: Email address of the invite to delete","operationId":"cli_delete_invite_v1_cli_invites_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/cli/members":{"get":{"tags":["v1-cli"],"summary":"Cli List Members","description":"List organization members.\n\nUses API key auth to determine org_id.\n\nReturns:\n    members: List of members with email, role, joined_at","operationId":"cli_list_members_v1_cli_members_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"delete":{"tags":["v1-cli"],"summary":"Cli Remove Member","description":"Remove a member from the organization by email.\n\nUses API key auth to determine org_id.\nRequires orgs.share permission.\n\nBody:\n    email: Email of member to remove\n\nReturns:\n    success, email","operationId":"cli_remove_member_v1_cli_members_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/cli/members/role":{"patch":{"tags":["v1-cli"],"summary":"Cli Update Member Role","description":"Update a member's role by email.\n\nUses API key auth to determine org_id.\nRequires orgs.share permission.\n\nBody:\n    email: Email of member to update\n    role: New role (owner/admin/member/viewer)\n\nReturns:\n    success, email, new_role","operationId":"cli_update_member_role_v1_cli_members_role_patch","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/":{"get":{"summary":"Read Root","operationId":"read_root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/healthz":{"get":{"summary":"Healthz","description":"Process liveness — wired to k8s livenessProbe.\n\nReturns 200 while the Python process is alive. Has no dependency check by\ndesign: restarting a pod can't fix a Supabase outage, and the thrashing\nonly deepens an incident. See ARD-728 and `app/health.py` for context.","operationId":"healthz_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Healthz Healthz Get"}}}}}}},"/readyz":{"get":{"summary":"Readyz","description":"Dependency readiness — wired to k8s readinessProbe.\n\nRuns the checks in `gather_readiness_checks` concurrently. Any failing\ncheck returns 503 with a JSON body listing which checks failed; K8s pulls\nthe pod out of the load balancer so callers see 503 immediately rather\nthan waiting on a backend that can't actually serve them.","operationId":"readyz_readyz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health Check","description":"Backward-compatible alias to /readyz.\n\nExisting callers (load balancers, monitoring, the deploy workflow's\nsanity check) keep working through the rollout. New consumers should\naddress /healthz for liveness or /readyz for readiness explicitly.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"APIKeyCreateResponse":{"properties":{"api_key_id":{"type":"string","title":"Api Key Id","description":"ID of the created key."},"api_key":{"type":"string","title":"Api Key","description":"The full secret key; shown only this once — store it now."},"name":{"type":"string","title":"Name","description":"Human-readable key name."},"key_prefix":{"type":"string","title":"Key Prefix","description":"First characters of the key, for identifying it in lists."},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","description":"Permission scopes granted to the key."},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"When the key expires. Null when it does not expire."},"created_at":{"type":"string","title":"Created At","description":"When the key was created."},"warning":{"type":"string","title":"Warning","description":"Reminder that the secret cannot be retrieved again."},"role_id":{"type":"string","title":"Role Id","description":"ID of the role granted to the key."},"role_key":{"type":"string","title":"Role Key","description":"The role's stable key, for example `role_org_member`."}},"additionalProperties":true,"type":"object","required":["api_key_id","api_key","name","key_prefix","scopes","created_at","warning","role_id","role_key"],"title":"APIKeyCreateResponse","description":"Response of POST /v1/orgs/{org_id}/api-keys.\n\n`api_key` is the full secret (sk-ard_live_… / sk-ard_test_…) and is\nreturned only here, once. Spec-only; see APIKeyListItem."},"APIKeyListItem":{"properties":{"id":{"type":"string","title":"Id","description":"API key ID."},"name":{"type":"string","title":"Name","description":"Human-readable key name."},"key_prefix":{"type":"string","title":"Key Prefix","description":"First characters of the key; the secret itself is never returned."},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","description":"Permission scopes granted to the key."},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"When the key expires. Null when it does not expire."},"revoked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revoked At","description":"When the key was revoked. Null for active keys."},"revoked_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revoked Reason","description":"Why the key was revoked: `admin_revoked`, `member_removed`, or `unknown_legacy` for keys revoked before the reason was recorded. Null for active keys."},"revoked_by":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Revoked By","description":"Who revoked the key: `{email, full_name}`. Null for active keys and for revocations with no attributable user."},"created_at":{"type":"string","title":"Created At","description":"When the key was created."},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At","description":"When the key last authenticated a request. Null when never used."},"users":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Users","description":"Who created the key: `{email, full_name}`."}},"additionalProperties":true,"type":"object","required":["id","name","key_prefix","scopes","created_at"],"title":"APIKeyListItem","description":"One row of GET /v1/orgs/{org_id}/api-keys. Never includes the secret.\n\nSpec-only: the handler returns plain dicts, so this model documents the\nshape without filtering (do not attach it as response_model)."},"AsyncOperationResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Operation ID."},"org_id":{"type":"string","title":"Org Id","description":"Organization the operation belongs to."},"type":{"$ref":"#/components/schemas/OperationType","description":"The kind of work this operation tracks, for example `branch_create`."},"resource_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Id","description":"ID of the resource the operation acts on (the branch ID for branch create)."},"status":{"$ref":"#/components/schemas/OperationStatus","description":"Current status. `completed` and `failed` are terminal."},"stage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stage","description":"Raw progress token, kept for released CLIs. Read `stage_label` instead."},"stage_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stage Label","description":"Human-readable stage; null means the operation has not started yet."},"progress":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Progress","description":"Best-effort completion percentage. Null when no estimate is available."},"setup_status":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Setup Status","description":"Connector setup progress detail. Present only for connector engine setup."},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result","description":"Result payload on completion; for branch create, includes `branch_url`."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message when the operation failed."},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At","description":"When work started. Null until then."},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At","description":"When the operation finished. Null until then."},"created_at":{"type":"string","title":"Created At","description":"When the operation was created."},"updated_at":{"type":"string","title":"Updated At","description":"When the operation was last updated."}},"type":"object","required":["id","org_id","type","resource_id","status","created_at","updated_at"],"title":"AsyncOperationResponse","description":"Response shape for GET /v1/operations/{id}.\n\nField set is intentionally narrow: the CLI polls this endpoint and\nwe only expose what the CLI / future UI needs. Audit fields stay\nout of the response."},"AttachRequest":{"properties":{"plan_id":{"type":"string","title":"Plan Id"},"success_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Success Url"}},"type":"object","required":["plan_id"],"title":"AttachRequest"},"BYOCAccessCredentialsInput":{"properties":{"role_arn":{"type":"string","title":"Role Arn","description":"arn:aws:iam::<account-id>:role/ArdentDeployer — provisioned by customer-template CFN."},"external_id":{"type":"string","maxLength":256,"minLength":1,"title":"External Id","description":"Per-customer UUID from generate-onboarding.sh; stored in AKV and replaced with a ref."},"region":{"type":"string","title":"Region","description":"AWS region the customer data plane runs in, e.g. 'us-east-1'."},"cluster_name":{"type":"string","maxLength":100,"minLength":1,"title":"Cluster Name","description":"EKS cluster name in the customer account where pgstream pods will run. Per-deployment (set by customer's terraform 'cluster_name' variable); backend needs it to call eks:DescribeCluster during branch create."}},"type":"object","required":["role_arn","external_id","region","cluster_name"],"title":"BYOCAccessCredentialsInput","description":"Customer-cloud access block supplied at connector-create time.\n\n``external_id`` is plaintext on the wire; the backend stores it in AKV as\npart of create_connector and persists only the resulting ``kv://akv/...``\nref on the connector row."},"BranchRow":{"properties":{"id":{"type":"string","title":"Id","description":"Branch ID."},"name":{"type":"string","title":"Name","description":"Branch name, as given at create."},"connector_id":{"type":"string","title":"Connector Id","description":"Connector this branch was created from."},"service_type":{"type":"string","title":"Service Type","description":"Branched service. `postgres` for Postgres branches."},"status":{"type":"string","title":"Status","description":"Current branch status."},"created_at":{"type":"string","title":"Created At","description":"When the branch was created."},"last_branch_activity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Branch Activity","description":"Most recent activity on the branch. Null when none has been recorded."},"read_ready_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Read Ready At","description":"When the branch became ready for reads. Null until then."},"write_ready_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Write Ready At","description":"When the branch became ready for writes. Null until then."},"masked_ready_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Masked Ready At","description":"When masked data became ready. Null until then."},"branch_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Branch Url","description":"Direct connection URL for the branch; sensitive — use exactly as returned."},"pooled_branch_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pooled Branch Url","description":"Pooled connection URL. Null when the provider has no pooled endpoint."},"pooled_branch_prisma_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pooled Branch Prisma Url","description":"Prisma-formatted pooled URL; null when the provider has no pooled endpoint."}},"additionalProperties":true,"type":"object","required":["id","name","connector_id","service_type","status","created_at"],"title":"BranchRow","description":"One row of GET /v1/branches/{connector_id}.\n\nSpec-only: the handler returns raw table rows (select *) enriched with\nURL fields, so this model documents the stable core without filtering.\nextra=\"allow\" is the contract — rows carry additional columns, and\nclients must tolerate fields not listed here."},"CLIAuthSelectOrgRequest":{"properties":{"session_id":{"type":"string","title":"Session Id"},"org_id":{"type":"string","title":"Org Id"}},"type":"object","required":["session_id","org_id"],"title":"CLIAuthSelectOrgRequest"},"ConfirmAwsAccountConnectionRequest":{"properties":{"org_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id"},"role_arn":{"type":"string","minLength":1,"title":"Role Arn"},"region":{"type":"string","minLength":1,"title":"Region","default":"us-east-1"}},"type":"object","required":["role_arn"],"title":"ConfirmAwsAccountConnectionRequest"},"ConnectorDeletionLockRequest":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Reason","description":"Why the connector is locked, up to 500 characters."}},"type":"object","title":"ConnectorDeletionLockRequest"},"ConnectorEnvelope":{"properties":{"connector":{"$ref":"#/components/schemas/ConnectorRow","description":"The connector's current row."}},"type":"object","required":["connector"],"title":"ConnectorEnvelope","description":"Spec-only wrapper used by the deletion-lock endpoints."},"ConnectorListResponse":{"properties":{"connectors":{"items":{"$ref":"#/components/schemas/ConnectorRow"},"type":"array","title":"Connectors","description":"Connectors in the organization, visible to the caller."}},"type":"object","required":["connectors"],"title":"ConnectorListResponse","description":"Spec-only wrapper for GET /v1/connectors."},"ConnectorRolloutRequest":{"properties":{"rollout_unit":{"type":"string","enum":["pgstream_image","data_plane_chart"],"title":"Rollout Unit"},"pgstream_source_image":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Pgstream Source Image"},"pgstream_target_digest":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Pgstream Target Digest"},"data_plane_chart_sha256":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Data Plane Chart Sha256"},"requires_drain":{"type":"boolean","title":"Requires Drain","default":true}},"type":"object","required":["rollout_unit"],"title":"ConnectorRolloutRequest","description":"Request body for staff-triggered connector rollouts."},"ConnectorRow":{"properties":{"id":{"type":"string","title":"Id","description":"Connector ID."},"org_id":{"type":"string","title":"Org Id","description":"Organization the connector belongs to."},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"Project the connector belongs to."},"name":{"type":"string","title":"Name","description":"Connector name."},"service_name":{"type":"string","title":"Service Name","description":"Service type. `postgresql` today."},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Current connector status."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the connector was created."},"can_update":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Can Update","description":"Whether the caller may update this connector."},"can_delete":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Can Delete","description":"Whether the caller may delete this connector."}},"additionalProperties":true,"type":"object","required":["id","org_id","name","service_name"],"title":"ConnectorRow","description":"Loose core of a connector response.\n\nThe connector row is the most dynamic shape in the system; extra=\"allow\"\nis the contract — responses carry many more columns and clients must\ntolerate fields not listed here. can_update/can_delete are added by the\npermission projection on create/get/update/list responses."},"CreateAPIKeyRequest":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name","description":"Descriptive name for the key"},"role_id":{"type":"string","title":"Role Id","description":"Role ID to grant to this API key (e.g., role_org_member)"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","description":"Permission keys like `connectors.read`, a subset of the role's; empty uses all.","default":[]},"expires_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires Days","description":"Days until expiration (null = never expires)"}},"type":"object","required":["name","role_id"],"title":"CreateAPIKeyRequest","description":"Request body for creating an API key"},"CreateAwsSetupLinkRequest":{"properties":{"org_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id"}},"type":"object","title":"CreateAwsSetupLinkRequest"},"CreateConnectorRequest":{"properties":{"org_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id","description":"Organization to create the connector in. Inferred from your auth when omitted."},"project_id":{"type":"string","title":"Project Id","description":"Project to create the connector in."},"name":{"type":"string","title":"Name","description":"Connector name."},"service_name":{"type":"string","title":"Service Name","description":"Service type. `postgresql` is the only supported value today."},"connection_details":{"additionalProperties":true,"type":"object","title":"Connection Details","description":"Connection details for the source database."},"byoc":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Byoc"},"neon_api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Neon Api Key"},"neon_project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Neon Project Id"},"deployment_model":{"type":"string","enum":["ardent-cloud","customer-cloud"],"title":"Deployment Model","default":"ardent-cloud"},"byoc_access_credentials":{"anyOf":[{"$ref":"#/components/schemas/BYOCAccessCredentialsInput"},{"type":"null"}]},"use_environment":{"type":"boolean","title":"Use Environment","description":"Create the connector in a customer-cloud environment.","default":false},"environment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Environment Id","description":"Customer-cloud environment; required when your org has more than one."},"private_link_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Private Link Id","description":"Private connection for the source database; needs `use_environment`."},"allow_high_rtt_placement":{"type":"boolean","title":"Allow High Rtt Placement","description":"Allow customer-cloud placement far from the worker region.","default":false},"drop_extensions":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Drop Extensions","description":"Source extensions to drop on branches instead of installing."}},"type":"object","required":["project_id","name","service_name","connection_details"],"title":"CreateConnectorRequest"},"CreateEnvironmentRequest":{"properties":{"org_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id"},"ownership_type":{"type":"string","pattern":"^(customer_owned)$","title":"Ownership Type"},"provider":{"type":"string","pattern":"^(aws|gcp|azure)$","title":"Provider"},"region":{"type":"string","title":"Region"},"credentials":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Credentials"},"neon_api_key":{"type":"string","minLength":1,"title":"Neon Api Key"},"aws_account_connection_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Account Connection Id"},"tier":{"type":"string","pattern":"^(small|medium|large)$","title":"Tier","default":"small"}},"type":"object","required":["ownership_type","provider","region","neon_api_key"],"title":"CreateEnvironmentRequest"},"CreateOrgRequest":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name","description":"Organization name"}},"type":"object","required":["name"],"title":"CreateOrgRequest","description":"Request body for creating a new organization"},"CreatePrivateLinkRequest":{"properties":{"name":{"type":"string","maxLength":64,"minLength":3,"pattern":"^[a-z0-9][a-z0-9-]*[a-z0-9]$","title":"Name"},"resource_configuration_arn":{"type":"string","pattern":"^arn:aws:vpc-lattice:[a-z0-9-]+:[0-9]{12}:resourceconfiguration/rcfg-[0-9a-z]+$","title":"Resource Configuration Arn"},"resource_share_arn":{"type":"string","pattern":"^arn:aws:ram:[a-z0-9-]+:[0-9]{12}:resource-share/[0-9a-f-]+$","title":"Resource Share Arn"},"database_port":{"type":"integer","maximum":65535.0,"minimum":1.0,"title":"Database Port","default":5432}},"type":"object","required":["name","resource_configuration_arn","resource_share_arn"],"title":"CreatePrivateLinkRequest"},"CreateProjectRequest":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name","description":"Project name (1-100 characters)."},"org_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id","description":"Organization to create the project in. Inferred from your auth when omitted."}},"type":"object","required":["name"],"title":"CreateProjectRequest"},"DebeziumCutoverRequest":{"properties":{"source_database":{"type":"string","maxLength":128,"minLength":1,"title":"Source Database"}},"type":"object","required":["source_database"],"title":"DebeziumCutoverRequest","description":"Request body for staff-triggered replication cutover."},"DebeziumMigrationReconcileRequest":{"properties":{"source_database":{"anyOf":[{"type":"string","maxLength":128,"minLength":1},{"type":"null"}],"title":"Source Database"},"limit":{"type":"integer","maximum":500.0,"minimum":1.0,"title":"Limit","default":50}},"type":"object","title":"DebeziumMigrationReconcileRequest","description":"Request body for staff-triggered migration-intent reconciliation."},"DebeziumPostCutoverReconciliationRequest":{"properties":{"source_database":{"type":"string","maxLength":128,"minLength":1,"title":"Source Database"},"run_id":{"anyOf":[{"type":"string","maxLength":128,"minLength":1},{"type":"null"}],"title":"Run Id"},"timeout_seconds":{"type":"number","maximum":1800.0,"minimum":30.0,"title":"Timeout Seconds","default":300.0},"tables":{"anyOf":[{"items":{"$ref":"#/components/schemas/DebeziumTableRequest"},"type":"array","maxItems":500,"minItems":1},{"type":"null"}],"title":"Tables"}},"type":"object","required":["source_database"],"title":"DebeziumPostCutoverReconciliationRequest","description":"Request body for exact post-cutover source/target reconciliation."},"DebeziumRepairRequest":{"properties":{"source_database":{"type":"string","maxLength":128,"minLength":1,"title":"Source Database"},"repair_action":{"type":"string","enum":["restart_connector","resnapshot_table","repair_slot_publication"],"title":"Repair Action"},"table":{"anyOf":[{"$ref":"#/components/schemas/DebeziumTableRequest"},{"type":"null"}]},"snapshot_type":{"type":"string","enum":["incremental","blocking"],"title":"Snapshot Type","default":"incremental"},"signal_id":{"anyOf":[{"type":"string","maxLength":42,"minLength":1},{"type":"null"}],"title":"Signal Id"}},"type":"object","required":["source_database","repair_action"],"title":"DebeziumRepairRequest","description":"Request body for synchronous Debezium operator repair actions."},"DebeziumRollbackRequest":{"properties":{"source_database":{"type":"string","maxLength":128,"minLength":1,"title":"Source Database"},"reason":{"type":"string","maxLength":64,"minLength":1,"title":"Reason"},"evidence_source":{"type":"string","maxLength":128,"minLength":1,"title":"Evidence Source"},"evidence_reference_id":{"type":"string","maxLength":256,"minLength":1,"title":"Evidence Reference Id"},"evidence_observed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Evidence Observed At"},"evidence":{"additionalProperties":true,"type":"object","title":"Evidence"},"intent_ttl_seconds":{"type":"integer","maximum":3600.0,"minimum":60.0,"title":"Intent Ttl Seconds","default":900}},"type":"object","required":["source_database","reason","evidence_source","evidence_reference_id"],"title":"DebeziumRollbackRequest","description":"Request body for staff-triggered replication rollback."},"DebeziumShadowCleanupRequest":{"properties":{"reason":{"type":"string","maxLength":256,"minLength":1,"title":"Reason"},"source_databases":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":100,"minItems":1},{"type":"null"}],"title":"Source Databases"}},"type":"object","required":["reason"],"title":"DebeziumShadowCleanupRequest","description":"Request body for staff-triggered Debezium-only shadow cleanup."},"DebeziumShadowCompareRequest":{"properties":{"source_database":{"type":"string","maxLength":128,"minLength":1,"title":"Source Database"},"run_id":{"type":"string","maxLength":128,"minLength":1,"title":"Run Id"},"selected_entities_fingerprint":{"type":"string","maxLength":256,"minLength":1,"title":"Selected Entities Fingerprint"},"window_start_lsn":{"type":"string","maxLength":32,"minLength":3,"title":"Window Start Lsn"},"window_end_lsn":{"type":"string","maxLength":32,"minLength":3,"title":"Window End Lsn"}},"type":"object","required":["source_database","run_id","selected_entities_fingerprint","window_start_lsn","window_end_lsn"],"title":"DebeziumShadowCompareRequest","description":"Request body for staff-triggered shadow compare reservation."},"DebeziumTableRequest":{"properties":{"schema":{"type":"string","maxLength":128,"minLength":1,"title":"Schema"},"table":{"type":"string","maxLength":128,"minLength":1,"title":"Table"}},"type":"object","required":["schema","table"],"title":"DebeziumTableRequest","description":"One source table identifier for staff Debezium tools."},"DiscoverAccepted":{"properties":{"operation_id":{"type":"string","title":"Operation Id","description":"Operation to poll at `GET /v1/operations/{operation_id}`."},"status":{"$ref":"#/components/schemas/OperationStatus","description":"Status at acceptance time."},"type":{"$ref":"#/components/schemas/OperationType","description":"The kind of work this operation tracks, for example `branch_create`."},"resource_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Id","description":"ID of the resource being created or acted on (the branch ID for branch create)."},"prerequisites":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Prerequisites","description":"Pre-discovery prerequisite check results."},"source_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Source Metadata","description":"Metadata gathered from the source."}},"type":"object","required":["operation_id","status","type","resource_id"],"title":"DiscoverAccepted","description":"202 body of POST /{connector_id}/discover: an operation handle plus\ndiscovery context."},"GitHubAuthValidationResponse":{"properties":{"valid":{"type":"boolean","title":"Valid"},"status":{"type":"string","enum":["valid","invalid","error"],"title":"Status"},"message":{"type":"string","title":"Message"},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"}},"type":"object","required":["valid","status","message","username"],"title":"GitHubAuthValidationResponse"},"GitHubConnectRequest":{"properties":{"access_token":{"type":"string","title":"Access Token"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","default":[]}},"type":"object","required":["access_token"],"title":"GitHubConnectRequest","description":"Request body for POST /v1/user/github/connect."},"GitHubConnectResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"github_username":{"type":"string","title":"Github Username"},"github_user_id":{"type":"string","title":"Github User Id"},"message":{"type":"string","title":"Message"}},"type":"object","required":["success","github_username","github_user_id","message"],"title":"GitHubConnectResponse","description":"Response for POST /v1/user/github/connect."},"GitHubRepoSearchResponse":{"properties":{"repos":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Repos"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["repos","count"],"title":"GitHubRepoSearchResponse","description":"Response for GET /v1/github/repos/search."},"GitHubRepoValidationResponse":{"properties":{"valid":{"type":"boolean","title":"Valid"},"status":{"type":"string","enum":["valid","private","invalid","error"],"title":"Status"},"message":{"type":"string","title":"Message"}},"type":"object","required":["valid","status","message"],"title":"GitHubRepoValidationResponse"},"GitHubStatusResponse":{"properties":{"connected":{"type":"boolean","title":"Connected"},"github_username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Github Username"},"github_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Github User Id"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"is_valid":{"type":"boolean","title":"Is Valid"},"can_unlink":{"type":"boolean","title":"Can Unlink"}},"type":"object","required":["connected","github_username","github_user_id","scopes","is_valid","can_unlink"],"title":"GitHubStatusResponse","description":"Response for GET /v1/user/github/status."},"GitHubUnlinkResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"}},"type":"object","required":["success","message"],"title":"GitHubUnlinkResponse","description":"Response for POST /v1/user/github/unlink."},"GitHubUserReposResponse":{"properties":{"repos":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Repos"},"count":{"type":"integer","title":"Count"},"github_username":{"type":"string","title":"Github Username"}},"type":"object","required":["repos","count","github_username"],"title":"GitHubUserReposResponse","description":"Response for GET /v1/github/repos/mine."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InstallationStatusResponse":{"properties":{"has_installation":{"type":"boolean","title":"Has Installation"},"total_count":{"type":"integer","title":"Total Count"},"installations":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Installations"}},"type":"object","required":["has_installation","total_count","installations"],"title":"InstallationStatusResponse","description":"Response for GET /v1/github-app/status."},"InviteUserRequest":{"properties":{"email":{"type":"string","title":"Email","description":"Email address to invite"},"role_key":{"type":"string","title":"Role Key","description":"Role to assign (owner/admin/member/viewer)","default":"member"}},"type":"object","required":["email"],"title":"InviteUserRequest","description":"Request body for inviting a user to an organization"},"ListInstallationsResponse":{"properties":{"installations":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Installations"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["installations","count"],"title":"ListInstallationsResponse","description":"Response for GET /v1/github-app/installations."},"ListReposResponse":{"properties":{"repos":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Repos"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["repos","count"],"title":"ListReposResponse","description":"Response for GET /v1/github-app/repos."},"MarkBranchMaskedReadyRequest":{"properties":{"reason":{"type":"string","maxLength":500,"minLength":1,"title":"Reason"},"confirm_safe_to_route":{"type":"boolean","title":"Confirm Safe To Route"}},"type":"object","required":["reason","confirm_safe_to_route"],"title":"MarkBranchMaskedReadyRequest","description":"Request body for staff-triggered hook-readiness recovery."},"OperationHandle":{"properties":{"operation_id":{"type":"string","title":"Operation Id","description":"Operation to poll at `GET /v1/operations/{operation_id}`."},"status":{"$ref":"#/components/schemas/OperationStatus","description":"Status at acceptance time."},"type":{"$ref":"#/components/schemas/OperationType","description":"The kind of work this operation tracks, for example `branch_create`."},"resource_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Id","description":"ID of the resource being created or acted on (the branch ID for branch create)."}},"type":"object","required":["operation_id","status","type","resource_id"],"title":"OperationHandle","description":"202 acceptance body for async endpoints (branch create today).\n\nDeclared on routes so the OpenAPI spec documents the handle shape.\nHandlers keep building the dict by hand; declaring this model on a\nroute is spec-only and never changes a live response."},"OperationStatus":{"type":"string","enum":["pending","running","completed","failed"],"title":"OperationStatus","description":"Lifecycle status of an async operation. Mirrors the\nasync_operations_status_valid CHECK constraint."},"OperationType":{"type":"string","enum":["connector_engine_setup","connector_reset","connector_deep_reset","connector_discovery","connector_delete","connector_secret_purge","connector_rollout","connector_replication_rollback","connector_debezium_cutover","connector_debezium_shadow_cleanup","environment_deploy","environment_destroy","branch_create","branch_delete"],"title":"OperationType","description":"Discriminator for an async operation. Must match the\nasync_operations_type_valid CHECK constraint in the migration —\nextending the set requires a migration to widen the constraint\nAND a worker registered in the dispatcher."},"OrphanNeonProjectReclaimRequest":{"properties":{"project_ids":{"items":{"type":"string"},"type":"array","maxItems":10,"minItems":1,"title":"Project Ids"},"confirm":{"type":"string","title":"Confirm"}},"type":"object","required":["project_ids","confirm"],"title":"OrphanNeonProjectReclaimRequest","description":"Request body for staff-triggered orphan Neon project reclaim."},"PreflightConnectorRequest":{"properties":{"org_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id","description":"Organization to preflight for. Inferred from your auth when omitted."},"service_name":{"type":"string","title":"Service Name","description":"Service type. `postgresql` is the only supported value today."},"connection_details":{"additionalProperties":true,"type":"object","title":"Connection Details","description":"Connection details for the source database. Nothing is stored."},"byoc":{"anyOf":[{"type":"string","const":"neon"},{"type":"null"}],"title":"Byoc"},"selected_schemas":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Selected Schemas","description":"Schemas to render in the grant script. Affects only `grant_script`."},"database":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Database","description":"Database to render in the grant script. Affects only `grant_script`."},"use_environment":{"type":"boolean","title":"Use Environment","description":"Route preflight through a customer-cloud environment.","default":false},"environment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Environment Id","description":"Customer-cloud environment; required when your org has more than one."},"private_link_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Private Link Id","description":"Private connection for the source database; needs `use_environment`."},"allow_high_rtt_placement":{"type":"boolean","title":"Allow High Rtt Placement","description":"Allow customer-cloud placement far from the worker region.","default":false}},"type":"object","required":["service_name","connection_details"],"title":"PreflightConnectorRequest","description":"Inline-credentialed prerequisite check before any connector row exists (ARD-1146).\n\nMirrors the CreateConnectorRequest connection surface so the CLI and\nwizard can call preflight with the exact same form values they would\nPOST to /v1/connectors. No row is persisted, no credentials reach\nKey Vault — the asyncpg connection lives only for the request lifetime.\n\n``selected_schemas`` and ``database`` are optional and affect only the\ngrant_script block in the response. When either is omitted, the\ngrant_script renders the replication-role-attribute line plus an\neditable per-database / per-schema template."},"PreflightReport":{"properties":{"checks":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Checks","description":"Individual check results, keyed by check name."},"source_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Provider","description":"Detected source provider, for example `supabase` or `vanilla`."},"source_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Source Metadata","description":"Metadata gathered from the source during preflight."},"source_preflight":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Source Preflight"},"source_placement":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Source Placement"},"branching_prerequisites_pass":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Branching Prerequisites Pass","description":"True when the checks required for branching pass."},"preflight_pass":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Preflight Pass","description":"True when every preflight check passes."},"grant_script":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grant Script","description":"Ready-to-run SQL grant script for the source database."}},"additionalProperties":true,"type":"object","title":"PreflightReport","description":"Preflight result: POST /preflight's 200 body, and the 422 body when\nconnector create is gated on failed preflight."},"ProjectListResponse":{"properties":{"projects":{"items":{"$ref":"#/components/schemas/ProjectRow"},"type":"array","title":"Projects","description":"Projects visible to the caller."}},"type":"object","required":["projects"],"title":"ProjectListResponse","description":"Spec-only wrapper for GET /v1/projects."},"ProjectRow":{"properties":{"id":{"type":"string","title":"Id","description":"Project ID."},"org_id":{"type":"string","title":"Org Id","description":"Organization the project belongs to."},"name":{"type":"string","title":"Name","description":"Project name."},"created_at":{"type":"string","title":"Created At","description":"When the project was created."}},"additionalProperties":true,"type":"object","required":["id","org_id","name","created_at"],"title":"ProjectRow","description":"One projects-table row, as returned by these endpoints.\n\nSpec-only: handlers return raw rows (select *) via JSONResponse, so\nthis documents the stable core without filtering. extra=\"allow\" —\nrows may carry additional audit columns."},"QuarantineListResponse":{"properties":{"quarantines":{"items":{"$ref":"#/components/schemas/QuarantineRow"},"type":"array","title":"Quarantines","description":"Active (still paused) quarantines for the connector."}},"type":"object","required":["quarantines"],"title":"QuarantineListResponse","description":"Spec-only wrapper for GET /{connector_id}/quarantine."},"QuarantineRow":{"properties":{"id":{"type":"string","title":"Id","description":"Quarantine ID."},"connector_id":{"type":"string","title":"Connector Id","description":"Connector the quarantine belongs to."},"deployment_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deployment Name","description":"Replication deployment that was paused."},"status":{"type":"string","title":"Status","description":"`quarantined` while paused, `released` after release."},"released_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Released At","description":"When the quarantine was released. Null while paused."},"released_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Released By","description":"Who released the quarantine. Null while paused."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"Human-readable status message."}},"additionalProperties":true,"type":"object","required":["id","connector_id","status"],"title":"QuarantineRow","description":"One paused replication deployment."},"RecoverEngineSetupRequest":{"properties":{"reason":{"type":"string","maxLength":256,"minLength":1,"title":"Reason"}},"type":"object","required":["reason"],"title":"RecoverEngineSetupRequest","description":"Request body for staff-triggered stale engine-setup recovery."},"RegisterInstallationRequest":{"properties":{"installation_id":{"type":"integer","title":"Installation Id"},"setup_action":{"type":"string","title":"Setup Action","default":"install"}},"type":"object","required":["installation_id"],"title":"RegisterInstallationRequest","description":"Request body for POST /v1/github-app/installations."},"RegisterInstallationResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"installation_id":{"type":"integer","title":"Installation Id"},"github_account_login":{"type":"string","title":"Github Account Login"},"repository_selection":{"type":"string","title":"Repository Selection"},"message":{"type":"string","title":"Message"}},"type":"object","required":["success","installation_id","github_account_login","repository_selection","message"],"title":"RegisterInstallationResponse","description":"Response for POST /v1/github-app/installations."},"ReplicaIdentityDecisionsRequest":{"properties":{"decisions":{"additionalProperties":{"type":"string"},"type":"object","title":"Decisions","description":"Per-table decision: `exclude`, `add_pk`, or `replica_identity_full`."}},"type":"object","required":["decisions"],"title":"ReplicaIdentityDecisionsRequest","description":"Body for PUT /v1/connectors/{id}/replica-identity-decisions (ARD-999).\n\n``decisions`` is the FULL set of per-table decisions for the\nconnector's currently-discovered no-replication-identity tables. The\nendpoint replaces (not merges) the persisted dict — customers\nsubmit a complete view of their choices, and re-discovery\ndeliberately invalidates stale decisions so the customer re-confirms\nafter a schema change.\n\nPydantic-side validation only verifies the dict shape (str -> str);\nsemantic validation (key matches a discovered table, value is one of\nthe allowed decisions) runs inside the route handler via the policy\nmodule so error messages can reference the discovered list."},"RotateNeonApiKeyRequest":{"properties":{"neon_api_key":{"type":"string","minLength":1,"title":"Neon Api Key"}},"type":"object","required":["neon_api_key"],"title":"RotateNeonApiKeyRequest"},"SelectionRequest":{"properties":{"selected_paths":{"items":{"type":"string"},"type":"array","title":"Selected Paths","description":"Discovered paths to replicate. Use `[\"*\"]` to select everything."}},"type":"object","required":["selected_paths"],"title":"SelectionRequest"},"UpdateConnectorRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"New connector name."},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"Move the connector to this project."},"connection_details":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Connection Details","description":"Replacement connection details for the source database."},"drop_extensions":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Drop Extensions","description":"Extensions to drop on branches; omit to leave unchanged, `[]` clears."}},"type":"object","title":"UpdateConnectorRequest"},"UpdateMemberRoleRequest":{"properties":{"role_key":{"type":"string","title":"Role Key","description":"New role to assign (owner/admin/member/viewer)"}},"type":"object","required":["role_key"],"title":"UpdateMemberRoleRequest","description":"Request body for updating a member's role"},"UpdateOrgRequest":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name","description":"New organization name"}},"type":"object","required":["name"],"title":"UpdateOrgRequest","description":"Request body for updating an organization"},"UpdateProfileRequest":{"properties":{"full_name":{"type":"string","maxLength":200,"minLength":1,"title":"Full Name","description":"User's full name"}},"type":"object","required":["full_name"],"title":"UpdateProfileRequest","description":"Request body for updating user profile"},"UpdateProjectRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"Name","description":"New project name (1-100 characters)."}},"type":"object","title":"UpdateProjectRequest"},"UpdateSubscriptionRequest":{"properties":{"plan_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan Id"},"cancel_at_period_end":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cancel At Period End"},"cancel_now":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cancel Now"}},"type":"object","title":"UpdateSubscriptionRequest"},"ValidateGitHubAuthRequest":{"properties":{"auth_type":{"type":"string","enum":["pat","oauth"],"title":"Auth Type","default":"pat"},"access_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"},"app_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"App Id"},"installation_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Installation Id"},"private_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Private Key"}},"type":"object","title":"ValidateGitHubAuthRequest"},"ValidateGitHubRepoRequest":{"properties":{"repo":{"type":"string","title":"Repo"},"github_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Github Token"}},"type":"object","required":["repo"],"title":"ValidateGitHubRepoRequest"},"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"}}}}