openapi: 3.1.0

info:
    title: 1Claw API
    version: 0.58.0
    description: |
        Secure secret management for AI agents. Provides vaults, secrets,
        policy-based access control, agent identity, Intents API,
        sharing, billing, and audit logging. Automations (workflow_spec,
        webhook tokens, event triggers, Assist), cloud runtimes with
        interactive shell sessions, agent memory, and discovery.

        All endpoints require JWT Bearer authentication unless marked with
        `security: []`.
    contact:
        email: ops@1claw.xyz

servers:
    - url: http://localhost:8443
      description: Development
    - url: https://api.1claw.xyz
      description: Production
    - url: https://shroud.1claw.xyz
      description: Shroud TEE Proxy (Intents API + LLM proxy)

x-agentcash-guidance:
    llmsTxtUrl: https://1claw.xyz/llms.txt

security:
    - BearerAuth: []

tags:
    - name: Authentication
      description: Credential exchange, MFA, device auth, token management
    - name: API Keys
      description: Personal API key management
    - name: Vaults
      description: Vault lifecycle operations
    - name: Secrets
      description: Secret CRUD within vaults
    - name: Policies
      description: Access policy management
    - name: Agents
      description: Agent identity and key management
    - name: Transactions
      description: Intents API (signing, simulation)
    - name: Chains
      description: Blockchain chain registry
    - name: Sharing
      description: Secret sharing links
    - name: Organization
      description: Org membership and roles
    - name: Billing
      description: Subscriptions, credits, and usage
    - name: Audit
      description: Immutable audit event log
    - name: Security
      description: IP rules and security configuration
    - name: Treasury
      description: Multi-sig treasury wallets (Safe) and agent access requests
    - name: Treasury Wallets
      description: Multi-chain wallet generation for human users (replaces CDP embedded wallets)
    - name: Admin
      description: Platform administration
    - name: Health
      description: Service health checks
    - name: Approvals
      description: Human-in-the-loop approval workflow for agent actions
    - name: Signing Keys
      description: Per-agent multi-chain signing key management
    - name: Webhooks
      description: Event webhook registration and management
    - name: Platform
      description: Platform API for developers building on 1Claw (plt_ keys, user provisioning, bootstrap templates)
    - name: OAuth
      description: OAuth 2.0 authorization server (PKCE, consent, token exchange, OIDC UserInfo)
    - name: Risk Engine
      description: Risk events, verdicts, and honeytoken management
    - name: Tokens
      description: Known token registry for guardrail enforcement
    - name: Execution Intents
      description: Execute HTTP calls, queries, and more through pre-configured bindings
    - name: Payment Cards
      description: Order prepaid/gift cards via x402, then reveal, refresh, and void them
    - name: Automations
      description: Scheduled, webhook-triggered, and on-demand automation workflows
    - name: Runtimes
      description: Cloud runtime containers for hosting AI agents
    - name: Agent Memory
      description: Agent memory storage (scratch, durable, semantic)
    - name: Discovery
      description: Agent directory and platform marketplace
    - name: Agent Chat
      description: Chat with agents via Shroud LLM proxy
    - name: Agent Channels
      description: External messaging channels (Telegram, WhatsApp, Discord)
    - name: OAuth Connect
      description: OAuth connected accounts for agents (provider registry, connect flows, app credentials)
    - name: Delegations
      description: Agent-to-agent delegation management (human-controlled authorization)
    - name: Cedar Policies
      description: Cedar policy engine (Team+ tier)
    - name: OPA Policies
      description: OPA policy engine (Business+ tier)
    - name: Contract ABIs
      description: Org-scoped contract ABI registry for transaction decoding
    - name: Pending Approvals
      description: Consensus-based multi-party approval workflow for signing
    - name: Sub-Organizations
      description: Sub-organization management
    - name: Portfolio
      description: Unified balance aggregator
    - name: Environment Variables
      description: Per-vault and org-shared environment variable management
    - name: Wallet Access
      description: Role-based wallet access policies for agents and users
    - name: Credential Recovery
      description: MFA/passkey/password recovery escape hatch with admin approval
    - name: Shamir KEK
      description: Shamir secret-sharing for org-level Key Encryption Keys

# =============================================================================
# PATHS
# =============================================================================

paths:
    # ---------------------------------------------------------------------------
    # Authentication
    # ---------------------------------------------------------------------------

    /v1/auth/token:
        post:
            tags: [Authentication]
            summary: Login with email and password
            operationId: login
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/LoginRequest"
            responses:
                "200":
                    description: Authenticated (or MFA required)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/LoginResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
        delete:
            tags: [Authentication]
            summary: Revoke current token
            operationId: revokeToken
            responses:
                "204":
                    description: Token revoked
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/auth/agent-token:
        post:
            tags: [Authentication]
            summary: Exchange agent credentials for JWT
            description: |
                Returns a short-lived EdDSA-signed JWT (`access_token`). Standard claims include `sub`
                (`agent:<uuid>`), `org`, `scopes`, `vault_ids`, optional `intents_api_enabled`, optional
                `shroud_enabled`, optional `llm_token_billing` / `stripe_customer_id` when org LLM billing is on.

                When **`shroud_enabled`** is true, the JWT payload may include **`shroud_config`**: a JSON object
                mirroring the agent row in Vault (same shape as `ShroudConfig` on `GET /v1/agents/{id}`).
                **Shroud** (TEE proxy) decodes this on each LLM request and runs **PolicyEngine** after the
                global inspection pipeline so per-agent limits and threat **block** actions apply without a
                separate policy fetch. Re-exchange the agent token after changing `shroud_config` so the JWT
                is fresh.

                User JWTs from password, API key, or device flow do **not** include `shroud_config`.
            operationId: agentToken
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/AgentTokenRequest"
            responses:
                "200":
                    description: Agent JWT issued
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TokenResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/auth/api-key-token:
        post:
            tags: [Authentication]
            summary: Exchange user API key for JWT
            operationId: apiKeyToken
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UserApiKeyTokenRequest"
            responses:
                "200":
                    description: JWT issued
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TokenResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/auth/refresh:
        post:
            tags: [Authentication]
            summary: Refresh an expiring JWT
            operationId: refreshToken
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [refresh_token]
                            properties:
                                refresh_token:
                                    type: string
            responses:
                "200":
                    description: Token refreshed
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TokenResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/auth/jwt-public-key:
        get:
            tags: [Authentication]
            summary: Get JWT verification public key
            description: |
                Returns the Ed25519 public key used to sign JWTs.
                Use this to verify tokens independently (e.g. in a TEE proxy or
                gateway). No authentication required.

                For OIDC-compliant relying parties (Anthropic Workload Identity
                Federation, etc.) prefer the JWKS endpoint at
                `/.well-known/jwks.json` together with the discovery document
                at `/.well-known/openid-configuration` — those advertise both
                Ed25519 and RS256 keys keyed by `kid` and survive key rotation.
            operationId: getJwtPublicKey
            security: []
            responses:
                "200":
                    description: JWT public key
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [alg, public_key_base64]
                                properties:
                                    alg:
                                        type: string
                                        example: EdDSA
                                    public_key_base64:
                                        type: string
                                        description: Base64-encoded Ed25519 public key

    /v1/auth/federated-token:
        post:
            tags: [Authentication]
            summary: Exchange a 1claw token for an OIDC federation token (RFC 8693)
            description: |
                Mints a short-lived RS256-signed JWT targeted at an external
                relying party (e.g. Anthropic Workload Identity Federation).
                The relying party validates the token via this issuer's JWKS
                URL (`/.well-known/jwks.json`) and exchanges it for its own
                short-lived service credentials.

                Requirements:
                - The agent that owns the `subject_token` must have
                  `federation_enabled = true` and the requested `audience`
                  must appear in `federation_audiences`.
                - The `subject_token` must be a valid 1claw agent JWT or
                  `ocv_` API key.
                - Optional `scope` narrows the agent's existing scopes — it
                  cannot escalate.

                Returns 503 when `ONECLAW_JWT_RS256_SIGNING_KEY_ID` is not
                configured on the server.
            operationId: exchangeFederatedToken
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/TokenExchangeRequest"
                    application/x-www-form-urlencoded:
                        schema:
                            $ref: "#/components/schemas/TokenExchangeRequest"
            responses:
                "200":
                    description: Federation token issued
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TokenExchangeResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "503":
                    description: RS256 signing key not configured

    /.well-known/openid-configuration:
        get:
            tags: [Authentication]
            summary: OIDC discovery document
            description: |
                Standard OpenID Connect discovery document advertising the
                issuer URL, JWKS URL, supported algorithms (`EdDSA`, `RS256`),
                and the RFC 8693 token-exchange endpoint. External IdPs
                (Anthropic WIF, Okta, Auth0, etc.) read this URL to learn
                where 1claw publishes its JWKS.
            operationId: openidConfiguration
            security: []
            responses:
                "200":
                    description: Discovery document
                    content:
                        application/json:
                            schema:
                                type: object

    /.well-known/jwks.json:
        get:
            tags: [Authentication]
            summary: JSON Web Key Set
            description: |
                Public keys for every active version of every JWT signing
                key (Ed25519 + RSA-2048). Each entry includes a `kid` so
                consumers can validate tokens issued before the most recent
                key rotation. Cached for 5 minutes via `Cache-Control` and
                CORS-permissive for browser-based IdP consoles.
            operationId: jwks
            security: []
            responses:
                "200":
                    description: JWK Set
                    content:
                        application/jwk-set+json:
                            schema:
                                type: object
                                properties:
                                    keys:
                                        type: array
                                        items:
                                            type: object

    /v1/auth/signup:
        post:
            tags: [Authentication]
            summary: Create a new account
            operationId: signup
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SignupRequest"
            responses:
                "200":
                    description: Account created (pending verification or auto-login)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SignupResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/auth/verify-email:
        post:
            tags: [Authentication]
            summary: Verify email address
            operationId: verifyEmail
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [token]
                            properties:
                                token:
                                    type: string
            responses:
                "200":
                    description: Email verified
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TokenResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/auth/forgot-password:
        post:
            tags: [Authentication]
            summary: Request password reset email
            description: |
                Always returns the same message whether or not the email exists (no account enumeration).
                Only password-based accounts receive mail.
            operationId: forgotPassword
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ForgotPasswordRequest"
            responses:
                "200":
                    description: Acknowledgement (check email if account exists)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ForgotPasswordResponse"

    /v1/auth/reset-password:
        post:
            tags: [Authentication]
            summary: Set a new password using reset token from email
            operationId: resetPassword
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ResetPasswordRequest"
            responses:
                "200":
                    description: Password updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ResetPasswordResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/auth/google:
        post:
            tags: [Authentication]
            summary: Authenticate with Google OAuth
            operationId: googleAuth
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/GoogleAuthRequest"
            responses:
                "200":
                    description: Authenticated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TokenResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/auth/change-password:
        post:
            tags: [Authentication]
            summary: Change current user's password
            operationId: changePassword
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ChangePasswordRequest"
            responses:
                "204":
                    description: Password changed
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/auth/set-password:
        post:
            tags: [Authentication]
            summary: Set initial password for platform users
            description: Only allowed when the user has no password set (platform_oidc users after claiming).
            operationId: setPassword
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [password, password_confirm]
                            properties:
                                password:
                                    type: string
                                    minLength: 12
                                password_confirm:
                                    type: string
            responses:
                "200":
                    description: Password set successfully
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    message:
                                        type: string
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/auth/change-email:
        post:
            tags: [Authentication]
            summary: Request email change
            description: Sends a 6-digit verification code to the new email address. Code expires in 10 minutes.
            operationId: changeEmail
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [new_email]
                            properties:
                                new_email:
                                    type: string
                                    format: email
            responses:
                "200":
                    description: Verification code sent
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    message:
                                        type: string
                                    new_email:
                                        type: string
                                    expires_in_seconds:
                                        type: integer
                "400":
                    $ref: "#/components/responses/BadRequest"
                "409":
                    description: Email already in use

    /v1/auth/verify-email-change:
        post:
            tags: [Authentication]
            summary: Verify email change with code
            operationId: verifyEmailChange
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [code]
                            properties:
                                code:
                                    type: string
            responses:
                "200":
                    description: Email updated
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    message:
                                        type: string
                                    email:
                                        type: string
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/auth/passkeys/register/begin:
        post:
            tags: [Authentication]
            summary: Begin passkey registration
            description: Returns a WebAuthn challenge for creating a new passkey credential.
            operationId: passkeyRegisterBegin
            responses:
                "200":
                    description: Registration options
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    challenge:
                                        type: string
                                    rp_id:
                                        type: string
                                    rp_name:
                                        type: string
                                    user_id:
                                        type: string
                                    user_name:
                                        type: string
                                    user_display_name:
                                        type: string
                                    attestation:
                                        type: string
                                    authenticator_selection:
                                        type: object

    /v1/auth/passkeys/register/complete:
        post:
            tags: [Authentication]
            summary: Complete passkey registration
            description: |
                When the account already has a password, passkey, or TOTP,
                `X-Auth-Confirm` is required (purpose `security.passkey.register`).
            operationId: passkeyRegisterComplete
            parameters:
                - name: X-Auth-Confirm
                  in: header
                  required: false
                  description: Re-auth token (`rat_`) or account password
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [credential_id, attestation_object, client_data_json]
                            properties:
                                credential_id:
                                    type: string
                                attestation_object:
                                    type: string
                                client_data_json:
                                    type: string
                                transports:
                                    type: array
                                    items:
                                        type: string
                                name:
                                    type: string
            responses:
                "201":
                    description: Passkey registered
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    passkey_id:
                                        type: string
                                        format: uuid
                                    credential_id:
                                        type: string

    /v1/auth/passkeys/assert/begin:
        post:
            tags: [Authentication]
            summary: Begin passkey authentication
            operationId: passkeyAssertBegin
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                email:
                                    type: string
                                    format: email
            responses:
                "200":
                    description: Assertion options
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    challenge:
                                        type: string
                                    rp_id:
                                        type: string
                                    timeout:
                                        type: integer
                                    user_verification:
                                        type: string
                                    allow_credentials:
                                        type: array
                                        items:
                                            type: object

    /v1/auth/passkeys/assert/complete:
        post:
            tags: [Authentication]
            summary: Complete passkey authentication
            operationId: passkeyAssertComplete
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [credential_id, authenticator_data, client_data_json, signature]
                            properties:
                                credential_id:
                                    type: string
                                authenticator_data:
                                    type: string
                                client_data_json:
                                    type: string
                                signature:
                                    type: string
            responses:
                "200":
                    description: Authentication successful
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    token:
                                        type: string
                                    refresh_token:
                                        type: string
                                    user:
                                        type: object

    /v1/auth/passkeys:
        get:
            tags: [Authentication]
            summary: List registered passkeys
            operationId: listPasskeys
            responses:
                "200":
                    description: List of passkeys
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    passkeys:
                                        type: array
                                        items:
                                            type: object
                                            properties:
                                                id:
                                                    type: string
                                                    format: uuid
                                                credential_id:
                                                    type: string
                                                name:
                                                    type: string
                                                last_used_at:
                                                    type: string
                                                created_at:
                                                    type: string

    /v1/auth/passkeys/{passkey_id}:
        delete:
            tags: [Authentication]
            summary: Delete a passkey
            description: |
                Removes a registered passkey. Requires recent re-authentication
                (`X-Auth-Confirm` with a `rat_` token from `POST /v1/auth/reauth`
                using purpose `security.passkey.delete`). Passkey or TOTP is
                required when either is enrolled. Deleting the last passkey is
                refused while vault passkey unlock is enabled.
            operationId: deletePasskey
            parameters:
                - name: passkey_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: X-Auth-Confirm
                  in: header
                  required: true
                  description: Re-auth token (`rat_`) or account password
                  schema:
                      type: string
            responses:
                "200":
                    description: Passkey deleted
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/approvals/request:
        post:
            tags: [Approvals]
            summary: Request human approval (agent-only)
            description: Agents can request policy changes or other sensitive actions that require human approval.
            operationId: requestApproval
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [action, target_type, target_id, summary]
                            properties:
                                action:
                                    type: string
                                    description: "Type of action (e.g. policy_change)"
                                target_type:
                                    type: string
                                target_id:
                                    type: string
                                summary:
                                    type: object
                                    description: "JSON payload describing the request"
                                reason:
                                    type: string
                                risk_tier:
                                    type: integer
                                    minimum: 1
                                    maximum: 5
            responses:
                "202":
                    description: Approval request created
                    headers:
                        Location:
                            description: URL to poll for approval status
                            schema:
                                type: string
                                example: /v1/approvals/{id}
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApprovalResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/auth/me:
        get:
            tags: [Authentication]
            summary: Get current user profile
            operationId: getMe
            responses:
                "200":
                    description: User profile
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/UserProfileResponse"
        patch:
            tags: [Authentication]
            summary: Update user profile
            operationId: updateMe
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateProfileRequest"
            responses:
                "200":
                    description: Profile updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/UserProfileResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
        delete:
            tags: [Authentication]
            summary: Delete current user account
            operationId: deleteMe
            parameters:
                - name: X-Auth-Confirm
                  in: header
                  required: true
                  description: Re-auth token (`rat_`, purpose `account.delete`) or password
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [confirmation]
                            properties:
                                confirmation:
                                    type: string
                                    description: Must be "DELETE MY ACCOUNT"
            responses:
                "204":
                    description: Account deleted
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/auth/settings:
        get:
            tags: [Authentication]
            summary: Get user security settings
            operationId: getSecuritySettings
            responses:
                "200":
                    description: Security settings
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    require_passkey_for_vaults:
                                        type: boolean
                                    require_passkey_for_mfa:
                                        type: boolean
                                    passkey_count:
                                        type: integer
        patch:
            tags: [Authentication]
            summary: Update user security settings
            description: |
                Disabling `require_passkey_for_vaults` requires `X-Auth-Confirm`
                (purpose `security.vault_passkey.disable`) with a passkey or TOTP
                when either is enrolled.

                Disabling `require_passkey_for_mfa` requires `X-Auth-Confirm`
                (purpose `security.mfa_passkey.disable`) with a passkey or TOTP
                when either is enrolled.
            operationId: updateSecuritySettings
            parameters:
                - name: X-Auth-Confirm
                  in: header
                  required: false
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                require_passkey_for_vaults:
                                    type: boolean
                                require_passkey_for_mfa:
                                    type: boolean
            responses:
                "200":
                    description: Updated settings
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/auth/human-factor-auth:
        get:
            tags: [Authentication]
            summary: Get effective human factor auth policy
            description: |
                Returns the resolved HFA policy for treasury wallet send, swap, and export.
                Precedence: user override → spend policy → platform defaults.
            operationId: getHumanFactorAuth
            responses:
                "200":
                    description: Effective HFA policy
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/HumanFactorAuthResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"
        put:
            tags: [Authentication]
            summary: Set user human factor auth policy
            operationId: upsertHumanFactorAuth
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpsertHumanFactorAuthRequest"
            responses:
                "200":
                    description: Updated policy
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/HumanFactorAuthResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"

    # MFA

    /v1/auth/mfa/status:
        get:
            tags: [Authentication]
            summary: Check MFA enrollment status
            operationId: mfaStatus
            responses:
                "200":
                    description: MFA status
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MfaStatusResponse"

    /v1/auth/mfa/setup:
        post:
            tags: [Authentication]
            summary: Begin MFA enrollment
            operationId: mfaSetup
            responses:
                "200":
                    description: TOTP setup details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MfaSetupResponse"

    /v1/auth/mfa/verify-setup:
        post:
            tags: [Authentication]
            summary: Confirm MFA enrollment with a TOTP code
            operationId: mfaVerifySetup
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/MfaVerifySetupRequest"
            responses:
                "200":
                    description: MFA enabled, recovery codes returned
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MfaVerifySetupResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/auth/mfa/verify:
        post:
            tags: [Authentication]
            summary: Verify MFA code during login
            operationId: mfaVerify
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/MfaVerifyRequest"
            responses:
                "200":
                    description: MFA verified, JWT issued
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TokenResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/auth/mfa/passkey/begin:
        post:
            tags: [Authentication]
            summary: Begin passkey MFA verification during login
            operationId: mfaPasskeyBegin
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [mfa_token]
                            properties:
                                mfa_token:
                                    type: string
            responses:
                "200":
                    description: WebAuthn challenge
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PasskeyAssertBeginResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/auth/mfa/passkey/complete:
        post:
            tags: [Authentication]
            summary: Complete passkey MFA verification during login
            operationId: mfaPasskeyComplete
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/MfaPasskeyCompleteRequest"
            responses:
                "200":
                    description: MFA verified, JWT issued
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TokenResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/auth/mfa:
        delete:
            tags: [Authentication]
            summary: Disable MFA
            description: |
                Requires a valid TOTP or recovery code in the body, or a passkey
                re-auth token in `X-Auth-Confirm` (purpose `security.mfa.disable`).
                Account password alone is not accepted while TOTP is enabled.
            operationId: mfaDisable
            parameters:
                - name: X-Auth-Confirm
                  in: header
                  required: false
                  description: Passkey or TOTP re-auth token (`rat_`)
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/MfaDisableRequest"
            responses:
                "204":
                    description: MFA disabled
                "400":
                    $ref: "#/components/responses/BadRequest"

    # Device Auth (CLI)

    /v1/auth/device/code:
        post:
            tags: [Authentication]
            summary: Request a device authorization code
            operationId: deviceCode
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/DeviceCodeRequest"
            responses:
                "200":
                    description: Device code issued
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DeviceCodeResponse"

    /v1/auth/device/token:
        post:
            tags: [Authentication]
            summary: Poll for device authorization token
            operationId: deviceToken
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/DeviceTokenRequest"
            responses:
                "200":
                    description: Token issued or authorization pending
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DeviceTokenResponse"

    /v1/auth/device/code/{user_code}:
        get:
            tags: [Authentication]
            summary: Check device code status
            operationId: deviceCodeStatus
            security: []
            parameters:
                - name: user_code
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Device code details
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/auth/device/approve:
        post:
            tags: [Authentication]
            summary: Approve a CLI device login
            operationId: deviceApprove
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/DeviceApproveRequest"
            responses:
                "200":
                    description: Device approved

    /v1/auth/device/deny:
        post:
            tags: [Authentication]
            summary: Deny a CLI device login
            operationId: deviceDeny
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/DeviceApproveRequest"
            responses:
                "200":
                    description: Device denied

    # ---------------------------------------------------------------------------
    # Personal API Keys
    # ---------------------------------------------------------------------------

    /v1/auth/api-keys:
        post:
            tags: [API Keys]
            summary: Create a personal API key
            operationId: createApiKey
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateApiKeyRequest"
            responses:
                "201":
                    description: API key created (full key shown once)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiKeyCreatedResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
        get:
            tags: [API Keys]
            summary: List personal API keys
            operationId: listApiKeys
            responses:
                "200":
                    description: List of API keys (masked)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiKeyListResponse"

    /v1/auth/api-keys/{key_id}:
        delete:
            tags: [API Keys]
            summary: Revoke an API key
            operationId: revokeApiKey
            parameters:
                - name: key_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Key revoked
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/auth/export-data:
        post:
            tags: [Authentication]
            summary: Export user data (GDPR)
            description: |
                Returns a full export of the authenticated user's data including
                profile, vaults, agents, secrets metadata, and policies. Intended
                for GDPR data-portability requests. Only available to human users
                (not agents). Requires `X-Auth-Confirm` (purpose `account.export`);
                passkey or TOTP when either is enrolled.
            operationId: exportUserData
            parameters:
                - name: X-Auth-Confirm
                  in: header
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: User data export
                    content:
                        application/json:
                            schema:
                                type: object
                                required:
                                    - export_version
                                    - exported_at
                                    - user
                                    - vaults
                                    - agents
                                    - secrets_metadata
                                    - policies
                                properties:
                                    export_version:
                                        type: string
                                        example: "1.0"
                                    exported_at:
                                        type: string
                                        format: date-time
                                    user:
                                        type: object
                                        required:
                                            - id
                                            - email
                                            - display_name
                                            - auth_method
                                            - created_at
                                        properties:
                                            id:
                                                type: string
                                                format: uuid
                                            email:
                                                type: string
                                                format: email
                                            display_name:
                                                type: string
                                            auth_method:
                                                type: string
                                            created_at:
                                                type: string
                                                format: date-time
                                    vaults:
                                        type: array
                                        items:
                                            type: object
                                            required: [id, name, created_at]
                                            properties:
                                                id:
                                                    type: string
                                                    format: uuid
                                                name:
                                                    type: string
                                                created_at:
                                                    type: string
                                                    format: date-time
                                    agents:
                                        type: array
                                        items:
                                            type: object
                                            required: [id, name, created_at]
                                            properties:
                                                id:
                                                    type: string
                                                    format: uuid
                                                name:
                                                    type: string
                                                created_at:
                                                    type: string
                                                    format: date-time
                                    secrets_metadata:
                                        type: array
                                        items:
                                            type: object
                                            required:
                                                - vault_id
                                                - path
                                                - type
                                                - version
                                                - created_at
                                            properties:
                                                vault_id:
                                                    type: string
                                                    format: uuid
                                                path:
                                                    type: string
                                                type:
                                                    type: string
                                                version:
                                                    type: integer
                                                created_at:
                                                    type: string
                                                    format: date-time
                                    policies:
                                        type: array
                                        items:
                                            type: object
                                            required:
                                                - id
                                                - vault_id
                                                - principal_type
                                                - principal_id
                                                - secret_path_pattern
                                                - permissions
                                                - created_at
                                            properties:
                                                id:
                                                    type: string
                                                    format: uuid
                                                vault_id:
                                                    type: string
                                                    format: uuid
                                                principal_type:
                                                    type: string
                                                principal_id:
                                                    type: string
                                                    format: uuid
                                                secret_path_pattern:
                                                    type: string
                                                permissions:
                                                    type: array
                                                    items:
                                                        type: string
                                                created_at:
                                                    type: string
                                                    format: date-time
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/auth/devices:
        post:
            tags: [Authentication]
            summary: Register a mobile device
            description: |
                Register a new mobile device for the authenticated user. Human-only.
                The device public key is used for step-up authentication challenges.
            operationId: registerDevice
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/RegisterDeviceRequest"
            responses:
                "201":
                    description: Device registered
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RegisterDeviceResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [Authentication]
            summary: List devices for current user
            description: Returns all registered mobile devices for the authenticated user.
            operationId: listDevices
            responses:
                "200":
                    description: Device list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DeviceListResponse"

    /v1/auth/devices/{device_id}:
        delete:
            tags: [Authentication]
            summary: Revoke a device
            description: Removes a registered device, invalidating its keys and push tokens.
            operationId: revokeDevice
            parameters:
                - name: device_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Device revoked
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/auth/devices/{device_id}/challenge:
        post:
            tags: [Authentication]
            summary: Create step-up auth challenge
            description: |
                Creates a cryptographic challenge bound to a specific action (e.g. approving
                a high-risk transaction). The device signs the challenge nonce to prove
                possession of the private key.
            operationId: createDeviceChallenge
            parameters:
                - name: device_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateDeviceChallengeRequest"
            responses:
                "200":
                    description: Challenge created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DeviceChallengeResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/auth/devices/{device_id}/attest:
        post:
            tags: [Authentication]
            summary: Attest device challenge
            description: |
                Submit a signed challenge nonce to complete step-up authentication.
                Returns a short-lived step-up token that can be used for the bound action.
            operationId: attestDeviceChallenge
            parameters:
                - name: device_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/AttestDeviceChallengeRequest"
            responses:
                "200":
                    description: Attestation successful
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AttestDeviceChallengeResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/auth/devices/{device_id}/push-token:
        post:
            tags: [Authentication]
            summary: Register push notification token
            description: |
                Associates a push notification token (APNs or FCM) with a registered device
                so the server can send approval requests and alerts.
            operationId: registerPushToken
            parameters:
                - name: device_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/RegisterPushTokenRequest"
            responses:
                "204":
                    description: Push token registered
                "400":
                    $ref: "#/components/responses/BadRequest"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Vaults
    # ---------------------------------------------------------------------------

    /v1/vaults:
        post:
            tags: [Vaults]
            summary: Create a vault
            operationId: createVault
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateVaultRequest"
            responses:
                "201":
                    description: Vault created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/VaultResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
        get:
            tags: [Vaults]
            summary: List vaults
            operationId: listVaults
            responses:
                "200":
                    description: List of vaults
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/VaultListResponse"

    /v1/vaults/{vault_id}:
        get:
            tags: [Vaults]
            summary: Get vault details
            operationId: getVault
            parameters:
                - $ref: "#/components/parameters/VaultId"
            responses:
                "200":
                    description: Vault details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/VaultResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Vaults]
            summary: Delete a vault
            operationId: deleteVault
            parameters:
                - $ref: "#/components/parameters/VaultId"
            responses:
                "204":
                    description: Vault deleted
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # CMEK (Customer-Managed Encryption Keys)
    # ---------------------------------------------------------------------------

    /v1/vaults/{vault_id}/cmek:
        post:
            tags: [CMEK]
            summary: Enable CMEK on a vault
            operationId: enableCmek
            description: |
                Enable client-side encryption on a vault. Requires Business or Enterprise plan.
                Only the key's SHA-256 fingerprint is stored — the key never touches the server.
            parameters:
                - $ref: "#/components/parameters/VaultId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/EnableCmekRequest"
            responses:
                "200":
                    description: CMEK enabled
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/VaultResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
        delete:
            tags: [CMEK]
            summary: Disable CMEK on a vault
            operationId: disableCmek
            description: |
                Disable client-side encryption. Existing CMEK-encrypted secrets still require
                the key to decrypt. New secrets will use HSM-only encryption.
            parameters:
                - $ref: "#/components/parameters/VaultId"
            responses:
                "200":
                    description: CMEK disabled
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/VaultResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/vaults/{vault_id}/cmek-rotate:
        post:
            tags: [CMEK]
            summary: Start server-assisted CMEK key rotation
            operationId: rotateCmek
            description: |
                Re-encrypts all secrets from the old CMEK key to the new one.
                Keys are passed in headers (TLS-only) and exist in server memory
                only during the rotation. Batched in groups of 100 secrets.
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - name: x-cmek-old-key
                  in: header
                  required: true
                  schema:
                      type: string
                  description: Base64-encoded old CMEK key (32 bytes)
                - name: x-cmek-new-key
                  in: header
                  required: true
                  schema:
                      type: string
                  description: Base64-encoded new CMEK key (32 bytes)
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CmekRotateRequest"
            responses:
                "202":
                    description: Rotation job started
                    headers:
                        Location:
                            description: URL to poll for rotation job status
                            schema:
                                type: string
                                example: /v1/vaults/{vault_id}/cmek-rotate/{job_id}
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CmekRotationJobResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/vaults/{vault_id}/cmek-rotate/{job_id}:
        get:
            tags: [CMEK]
            summary: Get CMEK rotation job status
            operationId: getCmekRotationJob
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - name: job_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Rotation job status
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CmekRotationJobResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # MPC
    # ---------------------------------------------------------------------------

    /v1/vaults/{vault_id}/mpc:
        post:
            tags: [Vaults]
            summary: Enable MPC custody on a vault
            operationId: enableMpc
            description: |
                Enable MPC custody on an existing vault. Requires Business or Enterprise plan.
                Splits secret encryption keys across multiple providers using the specified
                custody mode (e.g. 2-of-2, 2-of-3).
            parameters:
                - $ref: "#/components/parameters/VaultId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/EnableMpcRequest"
            responses:
                "200":
                    description: MPC custody enabled
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/VaultResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Secrets
    # ---------------------------------------------------------------------------

    /v1/vaults/{vault_id}/secrets:
        get:
            tags: [Secrets]
            summary: List secrets in a vault
            operationId: listSecrets
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - name: prefix
                  in: query
                  schema:
                      type: string
                  description: Filter by path prefix
            responses:
                "200":
                    description: Secret metadata list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SecretListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/vaults/{vault_id}/secrets/{path}:
        put:
            tags: [Secrets]
            summary: Store or update a secret
            operationId: putSecret
            x-agentcash-auth:
                mode: paid
            x-payment-info:
                protocols: [x402]
                pricingMode: fixed
                price: "0.0075"
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - $ref: "#/components/parameters/SecretPath"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/PutSecretRequest"
            responses:
                "201":
                    description: Secret created or updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SecretCreatedResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "402":
                    $ref: "#/components/responses/PaymentRequired"
        get:
            tags: [Secrets]
            summary: Retrieve a decrypted secret
            operationId: getSecret
            x-agentcash-auth:
                mode: paid
            x-payment-info:
                protocols: [x402]
                pricingMode: fixed
                price: "0.0015"
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - $ref: "#/components/parameters/SecretPath"
                - name: x-client-share
                  in: header
                  required: false
                  schema:
                      type: string
                  description: Base64-encoded client key share for MPC 2-of-2 vaults. Required when the vault uses 2-of-2 MPC custody.
            responses:
                "200":
                    description: Decrypted secret value
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SecretResponse"
                "402":
                    $ref: "#/components/responses/PaymentRequired"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Secrets]
            summary: Delete a secret
            operationId: deleteSecret
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - $ref: "#/components/parameters/SecretPath"
            responses:
                "204":
                    description: Secret deleted
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/vaults/{vault_id}/secret-versions/{path}:
        get:
            tags: [Secrets]
            summary: List all versions of a secret
            operationId: listSecretVersions
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - $ref: "#/components/parameters/SecretPath"
            responses:
                "200":
                    description: Version list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SecretVersionListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/vaults/{vault_id}/secret-version/{path}/{version}:
        get:
            tags: [Secrets]
            summary: Retrieve a specific version of a secret
            operationId: getSecretVersion
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - $ref: "#/components/parameters/SecretPath"
                - name: version
                  in: path
                  required: true
                  schema:
                      type: integer
            responses:
                "200":
                    description: Decrypted secret value at the specified version
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SecretResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
                "410":
                    description: Version has been disabled or expired

    /v1/vaults/{vault_id}/secret-version-disable/{path}/{version}:
        post:
            tags: [Secrets]
            summary: Disable a specific secret version
            operationId: disableSecretVersion
            description: |
                Disables a version so it can no longer be read. The version is
                retained for audit purposes but returns 410 on read attempts.
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - $ref: "#/components/parameters/SecretPath"
                - name: version
                  in: path
                  required: true
                  schema:
                      type: integer
            responses:
                "204":
                    description: Version disabled
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/vaults/{vault_id}/secret-rotate/{path}:
        post:
            tags: [Secrets]
            summary: Server-side secret rotation
            operationId: rotateSecret
            description: |
                Generates a cryptographically random value and stores it as a new
                version of the secret. The previous version is preserved in history.
                Requires rotate or write permission.
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - $ref: "#/components/parameters/SecretPath"
            requestBody:
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/RotateSecretRequest"
            responses:
                "201":
                    description: New version created with server-generated value
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SecretCreatedResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Policies
    # ---------------------------------------------------------------------------

    /v1/vaults/{vault_id}/policies:
        post:
            tags: [Policies]
            summary: Create an access policy
            operationId: createPolicy
            parameters:
                - $ref: "#/components/parameters/VaultId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreatePolicyRequest"
            responses:
                "201":
                    description: Policy created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PolicyResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
        get:
            tags: [Policies]
            summary: List policies on a vault
            operationId: listPolicies
            parameters:
                - $ref: "#/components/parameters/VaultId"
            responses:
                "200":
                    description: Policy list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PolicyListResponse"

    /v1/vaults/{vault_id}/policies/{policy_id}:
        put:
            tags: [Policies]
            summary: Update a policy
            operationId: updatePolicy
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - $ref: "#/components/parameters/PolicyId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdatePolicyRequest"
            responses:
                "200":
                    description: Policy updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PolicyResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Policies]
            summary: Revoke a policy
            operationId: deletePolicy
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - $ref: "#/components/parameters/PolicyId"
            responses:
                "204":
                    description: Policy revoked
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Environment Variables (per-vault)
    # ---------------------------------------------------------------------------

    /v1/vaults/{vault_id}/env-vars:
        get:
            tags: [Environment Variables]
            summary: List environment variables
            description: List all environment variables for a vault, optionally filtered by environment.
            operationId: listEnvVars
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - name: environment
                  in: query
                  schema:
                      type: string
                  description: Filter by environment (production, preview, development, or custom)
            responses:
                "200":
                    description: Environment variable list
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    env_vars:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/EnvVar"
        post:
            tags: [Environment Variables]
            summary: Create environment variable
            operationId: createEnvVar
            parameters:
                - $ref: "#/components/parameters/VaultId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateEnvVarRequest"
            responses:
                "201":
                    description: Environment variable created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/EnvVar"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/vaults/{vault_id}/env-vars/resolve:
        get:
            tags: [Environment Variables]
            summary: Resolve environment variables
            description: |
                Resolve the final KEY=VALUE set for an environment with full precedence (shared < vault < branch override).
                When the caller is an agent with `env_auto_resolve: true`, the `environment` query parameter may be omitted —
                the server uses the agent's tagged environment from the JWT. Org setting `env.enforce_agent_environment_scope`
                blocks agents from resolving vars outside their tagged environment.
            operationId: resolveEnvVars
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - name: environment
                  in: query
                  required: false
                  schema:
                      type: string
                  description: Target environment (production, preview, development, or custom). Required for human callers; optional for agents with env_auto_resolve when the agent has an environment tag.
                - name: git_branch
                  in: query
                  schema:
                      type: string
                  description: Optional git branch for preview branch overrides
            responses:
                "200":
                    description: Resolved environment variables
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ResolveEnvVarsResponse"

    /v1/vaults/{vault_id}/env-vars/{key}:
        get:
            tags: [Environment Variables]
            summary: Get environment variable
            operationId: getEnvVar
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - name: key
                  in: path
                  required: true
                  schema:
                      type: string
                - name: environment
                  in: query
                  schema:
                      type: string
            responses:
                "200":
                    description: Environment variable
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/EnvVar"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Environment Variables]
            summary: Update environment variable
            operationId: updateEnvVar
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - name: key
                  in: path
                  required: true
                  schema:
                      type: string
                - name: environment
                  in: query
                  schema:
                      type: string
            requestBody:
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateEnvVarRequest"
            responses:
                "200":
                    description: Environment variable updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/EnvVar"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Environment Variables]
            summary: Delete environment variable
            operationId: deleteEnvVar
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - name: key
                  in: path
                  required: true
                  schema:
                      type: string
                - name: environment
                  in: query
                  schema:
                      type: string
            responses:
                "204":
                    description: Deleted

    # ---------------------------------------------------------------------------
    # Vault Environments
    # ---------------------------------------------------------------------------

    /v1/vaults/{vault_id}/environments:
        get:
            tags: [Environment Variables]
            summary: List vault environments
            operationId: listVaultEnvironments
            parameters:
                - $ref: "#/components/parameters/VaultId"
            responses:
                "200":
                    description: Vault environment list
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    environments:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/VaultEnvironment"
        post:
            tags: [Environment Variables]
            summary: Create custom environment
            operationId: createVaultEnvironment
            parameters:
                - $ref: "#/components/parameters/VaultId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateEnvironmentRequest"
            responses:
                "201":
                    description: Environment created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/VaultEnvironment"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/vaults/{vault_id}/environments/{slug}:
        delete:
            tags: [Environment Variables]
            summary: Delete custom environment
            operationId: deleteVaultEnvironment
            parameters:
                - $ref: "#/components/parameters/VaultId"
                - name: slug
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "204":
                    description: Deleted

    # ---------------------------------------------------------------------------
    # Agent Self-Enrollment (public)
    # ---------------------------------------------------------------------------

    /v1/agents/enroll:
        post:
            tags: [Agents]
            summary: Self-enroll an agent
            operationId: enrollAgent
            description: |
                Public endpoint (no auth required).

                **With `human_email`:** Creates a pending enrollment for that account's org,
                emails Allow/Deny links, and returns `approval_url` in the JSON body (use if email
                is delayed). The API key is NOT returned until the human approves.

                **Name only (omit `human_email`):** Creates a link-only pending enrollment.
                The response includes `approval_url`; the human opens it while signed in to
                approve the agent into their org.

                Anti-spam: IP rate limiting, per-email cooldown, caps on pending rows.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/EnrollAgentRequest"
            responses:
                "201":
                    description: Enrollment processed (uniform response to prevent email enumeration)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/EnrollAgentResponse"
                "429":
                    description: Rate limit exceeded

    # ---------------------------------------------------------------------------
    # Agents
    # ---------------------------------------------------------------------------

    /v1/agents:
        post:
            tags: [Agents]
            summary: Register a new agent
            operationId: createAgent
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateAgentRequest"
            responses:
                "201":
                    description: Agent created with one-time API key
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentCreatedResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
        get:
            tags: [Agents]
            summary: List agents
            operationId: listAgents
            responses:
                "200":
                    description: Agent list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentListResponse"

    /v1/agents/me:
        get:
            tags: [Agents]
            summary: Get the calling agent's own profile
            operationId: getAgentSelf
            responses:
                "200":
                    description: Agent self profile
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentSelfResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/agents/{agent_id}:
        get:
            tags: [Agents]
            summary: Get agent details
            operationId: getAgent
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Agent details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Agents]
            summary: Update an agent
            operationId: updateAgent
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateAgentRequest"
            responses:
                "200":
                    description: Agent updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentResponse"
                "202":
                    description: |
                        Guardrail widening queued for human approval. The change is not
                        applied until approved via POST /v1/approvals/{approval_id}/decide.
                        Resubmit this PATCH with `approval_id` set to the returned value
                        after approval to apply the widening.
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/GuardrailWideningQueuedResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Agents]
            summary: Delete an agent
            operationId: deleteAgent
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "204":
                    description: Agent deleted
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/rotate-key:
        post:
            tags: [Agents]
            summary: Rotate agent API key
            operationId: rotateAgentKey
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: New API key returned
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentKeyRotatedResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/rotate-identity-keys:
        post:
            tags: [Agents]
            summary: Rotate agent identity keys (SSH + ECDH)
            description: |
                Rotates the agent's Ed25519 SSH keypair and P-256 ECDH keypair.
                New private keys are stored in the __agent-keys vault; old keys are overwritten.
                User-only endpoint — agents cannot rotate their own identity keys.
            operationId: rotateAgentIdentityKeys
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Agent with updated public keys
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/smart-accounts:
        post:
            tags: [Agents]
            summary: Add a smart account (Safe) for this agent on a chain
            description: |
                Use after deploying a Safe on a new chain. Multi-chain; one Safe per chain.
                Replaces any existing entry for the same chain_id.
            operationId: addAgentSmartAccount
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/AddSmartAccountRequest"
            responses:
                "200":
                    description: Agent with updated smart_accounts list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Transactions (Intents API)
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/transactions:
        post:
            tags: [Transactions]
            summary: Submit a transaction for signing
            x-agentcash-auth:
                mode: paid
            x-payment-info:
                protocols: [x402]
                pricingMode: quote
            description: |
                Replay protection: send an optional **Idempotency-Key** header (e.g. UUID or opaque string).
                Duplicate requests with the same key within 24 hours return the cached transaction response
                (no second sign/broadcast). Omit the header for non-idempotent submissions.
            operationId: submitTransaction
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: Idempotency-Key
                  in: header
                  required: false
                  description: Optional key for replay protection; duplicate requests return cached response.
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SubmitTransactionRequest"
            responses:
                "201":
                    description: Transaction signed (and optionally broadcast)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TransactionResponse"
                "200":
                    description: Transaction previously created with same Idempotency-Key (replay-safe response)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TransactionResponse"
                "402":
                    $ref: "#/components/responses/PaymentRequired"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "409":
                    description: Idempotency-Key in use by another in-flight request; retry later.
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ProblemDetails"
                "422":
                    description: Simulation reverted (when simulate_first is true)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TransactionResponse"
                "202":
                    description: Transaction held for human approval (graduated tx_approval_policy)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TxAwaitingApproval"
        get:
            tags: [Transactions]
            summary: List agent transactions
            operationId: listTransactions
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - $ref: "#/components/parameters/IncludeSignedTx"
            responses:
                "200":
                    description: Transaction list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TransactionListResponse"

    /v1/agents/{agent_id}/transactions/{tx_id}:
        get:
            tags: [Transactions]
            summary: Get a transaction by ID
            operationId: getTransaction
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: tx_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - $ref: "#/components/parameters/IncludeSignedTx"
            responses:
                "200":
                    description: Transaction details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TransactionResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/transactions/sign:
        post:
            tags: [Transactions]
            summary: Sign a transaction without broadcasting
            description: |
                Signs a transaction inside the server (or TEE when using Shroud) but does
                **not** broadcast it. The caller receives the raw `signed_tx` hex and
                `tx_hash` so it can submit to any RPC of its choosing.

                All agent guardrails (allowlists, value caps, daily limits) are enforced
                exactly as for the submit endpoint. The signed transaction is recorded for
                audit and daily-limit tracking with `status: "sign_only"`.
            operationId: signTransaction
            x-agentcash-auth:
                mode: paid
            x-payment-info:
                protocols: [x402]
                pricingMode: quote
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SignTransactionRequest"
            responses:
                "200":
                    description: Transaction signed successfully (not broadcast)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SignTransactionResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "402":
                    $ref: "#/components/responses/PaymentRequired"

    /v1/agents/{agent_id}/transactions/simulate:
        post:
            tags: [Transactions]
            summary: Simulate a transaction via Tenderly
            operationId: simulateTransaction
            x-agentcash-auth:
                mode: paid
            x-payment-info:
                protocols: [x402]
                pricingMode: fixed
                price: "0.075"
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SimulateTransactionRequest"
            responses:
                "200":
                    description: Simulation result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SimulationResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "402":
                    $ref: "#/components/responses/PaymentRequired"

    /v1/agents/{agent_id}/transactions/simulate-bundle:
        post:
            tags: [Transactions]
            summary: Simulate a bundle of transactions
            operationId: simulateBundle
            x-agentcash-auth:
                mode: paid
            x-payment-info:
                protocols: [x402]
                pricingMode: fixed
                price: "0.075"
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SimulateBundleRequest"
            responses:
                "200":
                    description: Bundle simulation results
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/BundleSimulationResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "402":
                    $ref: "#/components/responses/PaymentRequired"

    # ---------------------------------------------------------------------------
    # Agent Signing Keys (Multi-Chain)
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/signing-keys:
        post:
            tags: [Signing Keys]
            summary: Provision a signing key for a chain
            operationId: createSigningKey
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateSigningKeyRequest"
            responses:
                "201":
                    description: Signing key created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SigningKeyResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "409":
                    $ref: "#/components/responses/Conflict"
        get:
            tags: [Signing Keys]
            summary: List signing keys for an agent
            operationId: listSigningKeys
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Signing keys list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SigningKeyListResponse"

    /v1/agents/{agent_id}/signing-keys/{chain}/rotate:
        post:
            tags: [Signing Keys]
            summary: Rotate a signing key for a chain
            operationId: rotateSigningKey
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Rotated signing key
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SigningKeyResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/signing-keys/{chain}:
        delete:
            tags: [Signing Keys]
            summary: Deactivate a signing key for a chain
            operationId: deactivateSigningKey
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "204":
                    description: Key deactivated
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/signing-keys/{chain}/export:
        post:
            tags: [Signing Keys]
            summary: Export a signing key (private key included)
            description: |
                Export the private key for an agent's signing key. Requires re-authentication
                via the X-Auth-Confirm header containing the user's account password.
                Human users only — agents cannot export keys.
            operationId: exportSigningKey
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
                - name: X-Auth-Confirm
                  in: header
                  required: true
                  description: Account password for re-authentication
                  schema:
                      type: string
                      format: password
            responses:
                "200":
                    description: Signing key exported successfully
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [chain, curve, public_key, private_key, key_version, agent_id]
                                properties:
                                    chain:
                                        type: string
                                    curve:
                                        type: string
                                    public_key:
                                        type: string
                                    address:
                                        type: string
                                    private_key:
                                        type: string
                                    key_version:
                                        type: integer
                                    agent_id:
                                        type: string
                                        format: uuid
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/signing-keys/{chain}/balance:
        get:
            tags: [Signing Keys]
            summary: Get signing key balance
            description: |
                Returns the native token balance for the agent's signing key address
                on the specified chain.
            operationId: getSigningKeyBalance
            security:
                - BearerAuth: []
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Signing key balance
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SigningKeyBalanceResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/signing-keys/{chain}/import:
        post:
            tags: [Signing Keys]
            summary: Import a signing key for a chain
            description: |
                Import an existing private key for a specific chain. Human-only,
                requires password re-authentication.
            operationId: importSigningKey
            security:
                - BearerAuth: []
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ImportKeyRequest"
            responses:
                "201":
                    description: Signing key imported
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SigningKeyResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    # ---------------------------------------------------------------------------
    # Bankr Dynamic Key Vending
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/bankr-keys/lease:
        post:
            tags: [Bankr Keys]
            summary: Lease a short-lived Bankr wallet API key
            description: |
                Provision a scoped, time-limited Bankr wallet API key for an agent.
                **Privileged, deny-by-default:** agent callers need an explicit access policy
                on `agents/{agent_id}/bankr/*` in the `__agent-keys` vault (JWT scope
                `agents/{agent_id}/bankr/lease`). Agents may only lease for their own ID.
                The `bk_usr_` key is **omitted** from the JSON response for agent JWTs —
                stored server-side for Shroud resolution. Human callers receive `api_key` once.
                Requires `BANKR_PARTNER_KEY` on Vault. Agent default TTL 15 min when omitted;
                human/org default 1 hour (`BANKR_DEFAULT_LEASE_TTL_SECS`). Recommend 5–15 min
                for autonomous agents. Max TTL 24 hours. Max 5 concurrent leases per agent.
            operationId: leaseBankrKey
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: false
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/LeaseBankrKeyRequest"
            responses:
                "201":
                    description: Bankr key leased
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/LeaseBankrKeyResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/agents/{agent_id}/bankr-keys:
        get:
            tags: [Bankr Keys]
            summary: List active Bankr key leases for an agent
            operationId: listBankrKeys
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Active leases (no secret values)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/BankrKeyLeaseListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/bankr-keys/{lease_id}:
        delete:
            tags: [Bankr Keys]
            summary: Revoke an active Bankr key lease
            operationId: revokeBankrKey
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: lease_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Lease revoked
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Agent Delegations
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/accounts:
        get:
            tags: [Agents]
            summary: List agent on-chain accounts
            operationId: listAgentAccounts
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Agent accounts
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentAccountListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"
        post:
            tags: [Agents]
            summary: Provision an agent account record
            description: Human-only. Creates a DB record for an EOA or Safe account (Safe onchain sync is stubbed).
            operationId: provisionAgentAccount
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ProvisionAgentAccountRequest"
            responses:
                "201":
                    description: Account provisioned
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentAccountResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/accounts/migrate:
        post:
            tags: [Agents]
            summary: EOA to Safe migration wizard
            description: Human-only. Provisions counterfactual Safe and returns sweep plan. Onchain module broadcast stubbed pre-audit.
            operationId: migrateAgentToSafe
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [chain]
                            properties:
                                chain:
                                    type: string
                                deprecate_eoa:
                                    type: boolean
            responses:
                "200":
                    description: Migration plan
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MigrationPlanResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/accounts/{chain}/deprecate-eoa:
        post:
            tags: [Agents]
            summary: Mark agent EOA account deprecated
            operationId: deprecateAgentEoa
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Updated account
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentAccountResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/accounts/{chain}/deploy:
        post:
            tags: [Agents]
            summary: Lazy-deploy counterfactual Safe (stub)
            description: Human-only. Broadcasts Safe deployment when Guard audit completes. Returns 501 pre-audit.
            operationId: deployAgentSafeAccount
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "501":
                    description: Not implemented (Phase 5.1)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/NotImplementedResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/org/safe/sync-allowances:
        post:
            tags: [Organization]
            summary: Reconcile Safe allowance targets (org admin)
            description: Compiles tx_daily_limit targets for Safe agents. Onchain read/write stubbed pre-audit.
            operationId: syncOrgSafeAllowances
            responses:
                "200":
                    description: Reconciliation report
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AllowanceReconcileReport"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/treasury/{treasury_id}/safe/roles-sync:
        post:
            tags: [Treasury]
            summary: Sync treasury Safe Roles module (stub)
            description: Human-only. Reconciles on-chain Roles config with agent guardrails. Returns 501 pre-audit.
            operationId: treasurySafeRolesSync
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "501":
                    description: Not implemented (Phase 5.9)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/NotImplementedResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/safe/cosign:
        post:
            tags: [Agents]
            summary: Enable Vault co-signer (stub)
            operationId: enableSafeCosign
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "501":
                    description: Not implemented (Phase 5.2)

    /v1/agents/{agent_id}/safe/passkey-enroll:
        post:
            tags: [Agents]
            summary: Enroll passkey Safe owner (stub)
            operationId: enrollSafePasskeyOwner
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "501":
                    description: Not implemented (Phase 5.5)

    /v1/agents/{agent_id}/safe/timelock:
        post:
            tags: [Agents]
            summary: Configure Zodiac timelock (stub)
            operationId: configureSafeTimelock
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "501":
                    description: Not implemented (Phase 5.6)

    /v1/agents/{agent_id}/safe/erc4337:
        post:
            tags: [Agents]
            summary: Enable ERC-4337 Safe lane (stub)
            operationId: enableSafeErc4337
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "501":
                    description: Not implemented (Phase 5.8)

    /v1/agents/{agent_id}/guardrails/replay:
        post:
            tags: [Agents]
            summary: Dry-run guardrail changes against recent transactions
            description: Human-only. Compares draft guardrails against recent agent transactions.
            operationId: replayAgentGuardrails
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/GuardrailReplayRequest"
            responses:
                "200":
                    description: Replay report
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/GuardrailReplayResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/safe/module-registry/{chain}:
        get:
            tags: [Agents]
            summary: List Safe module registry entries for a chain
            operationId: getSafeModuleRegistry
            security: []
            parameters:
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Module registry
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SafeModuleRegistryResponse"

    /v1/agents/{agent_id}/delegations:
        post:
            tags: [Delegations]
            summary: Create a delegation
            description: |
                Grant an agent (delegator) permission to delegate tasks to another agent (delegate).
                Human-only — agents cannot create their own delegations.
            operationId: createDelegation
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateDelegationRequest"
            responses:
                "201":
                    description: Delegation created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DelegationResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "409":
                    description: Delegation already exists for this delegator/delegate pair
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ProblemDetails"
        get:
            tags: [Delegations]
            summary: List delegations for an agent
            description: |
                List all delegations where this agent is the delegator.
            operationId: listDelegations
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: List of delegations
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DelegationListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/delegations/effective:
        get:
            tags: [Delegations]
            summary: Get effective delegations
            description: |
                Get the effective delegations for an agent, including daily usage statistics.
                Agents can call this on their own ID to discover what they are authorized to delegate to.
            operationId: getEffectiveDelegations
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Effective delegations with usage stats
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DelegationListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/delegations/{delegation_id}:
        get:
            tags: [Delegations]
            summary: Get a specific delegation
            operationId: getDelegation
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: delegation_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Delegation details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DelegationResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Delegations]
            summary: Update a delegation
            description: |
                Update delegation tools, limits, mode, or active status. Human-only.
            operationId: updateDelegation
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: delegation_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateDelegationRequest"
            responses:
                "200":
                    description: Delegation updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DelegationResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Delegations]
            summary: Revoke a delegation
            operationId: revokeDelegation
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: delegation_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Delegation revoked
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Unified Signing Intent
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/sign:
        post:
            tags: [Signing]
            summary: Unified signing intent (EIP-191, EIP-712, EIP-2718 types 0-4)
            operationId: signIntent
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SignIntentRequest"
            responses:
                "200":
                    description: Signed result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SignIntentResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"

    # ---------------------------------------------------------------------------
    # Execution Intents
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/bindings:
        post:
            tags: [Execution Intents]
            summary: Create a binding
            operationId: createBinding
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateBindingRequest"
            responses:
                "201":
                    description: Binding created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/BindingResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [Execution Intents]
            summary: List bindings
            operationId: listBindings
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Binding list
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [bindings]
                                properties:
                                    bindings:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/BindingResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/agents/{agent_id}/bindings/{binding_id}:
        get:
            tags: [Execution Intents]
            summary: Get binding
            operationId: getBinding
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: binding_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Binding details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/BindingResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Execution Intents]
            summary: Update binding
            operationId: updateBinding
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: binding_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateBindingRequest"
            responses:
                "200":
                    description: Binding updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/BindingResponse"
                "202":
                    description: |
                        Binding guardrail widening queued for human approval. Resubmit
                        PATCH with `approval_id` after approval via
                        POST /v1/approvals/{approval_id}/decide.
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/GuardrailWideningQueuedResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Execution Intents]
            summary: Delete binding
            operationId: deleteBinding
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: binding_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Binding deleted
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/bindings/{binding_id}/test:
        post:
            tags: [Execution Intents]
            summary: Test binding connectivity
            operationId: testBinding
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: binding_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: false
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                timeout_ms:
                                    type: integer
                                    description: Connection test timeout in milliseconds
            responses:
                "200":
                    description: Test result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TestBindingResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/bindings/{binding_id}/rotate-credential:
        post:
            tags: [Execution Intents]
            summary: Rotate a binding credential
            description: Overwrite the stored credential for a binding without touching its config or guardrails. Human-only. The credential value is never returned.
            operationId: rotateBindingCredential
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: binding_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [credential]
                            properties:
                                credential:
                                    description: New credential material (object or string). Stored server-side.
            responses:
                "200":
                    description: Updated binding
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/BindingResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/execute:
        post:
            tags: [Execution Intents]
            summary: Execute an intent
            operationId: executeIntent
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ExecuteRequest"
            responses:
                "200":
                    description: Execution result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ExecuteResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    description: Guardrail violation or permission denied
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: "#/components/schemas/GuardrailViolation"
                                    - $ref: "#/components/schemas/ProblemDetails"
                "413":
                    description: Request params exceed binding max_request_bytes
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/GuardrailViolation"
                "429":
                    description: Binding or agent execution rate limit exceeded
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/GuardrailViolation"
                "202":
                    description: Execution requires human approval before running
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ExecutionApprovalRequired"

    /v1/agents/{agent_id}/executions:
        get:
            tags: [Execution Intents]
            summary: List execution events
            operationId: listExecutions
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: limit
                  in: query
                  required: false
                  schema:
                      type: integer
                      default: 50
                - name: offset
                  in: query
                  required: false
                  schema:
                      type: integer
                      default: 0
            responses:
                "200":
                    description: Execution event list
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [events]
                                properties:
                                    events:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/ExecutionEventResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"

    # ---------------------------------------------------------------------------
    # Chains
    # ---------------------------------------------------------------------------

    /v1/chains:
        get:
            tags: [Chains]
            summary: List enabled chains
            operationId: listChains
            security: []
            responses:
                "200":
                    description: Chain list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChainListResponse"

    /v1/chains/{identifier}:
        get:
            tags: [Chains]
            summary: Get chain by name or ID
            operationId: getChain
            security: []
            parameters:
                - name: identifier
                  in: path
                  required: true
                  schema:
                      type: string
                  description: Chain name (e.g. "ethereum") or numeric chain ID
            responses:
                "200":
                    description: Chain details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChainResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/admin/chains:
        get:
            tags: [Chains]
            summary: List all chains including disabled (admin)
            operationId: adminListChains
            responses:
                "200":
                    description: Full chain list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChainListResponse"
        post:
            tags: [Chains]
            summary: Add a chain (admin)
            operationId: createChain
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateChainRequest"
            responses:
                "201":
                    description: Chain added
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChainResponse"

    /v1/admin/chains/{chain_id}:
        put:
            tags: [Chains]
            summary: Update a chain (admin)
            operationId: updateChain
            parameters:
                - name: chain_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateChainRequest"
            responses:
                "200":
                    description: Chain updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChainResponse"
        delete:
            tags: [Chains]
            summary: Remove a chain (admin)
            operationId: deleteChain
            parameters:
                - name: chain_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Chain removed

    # ---------------------------------------------------------------------------
    # Sharing
    # ---------------------------------------------------------------------------

    /v1/secrets/{secret_id}/share:
        post:
            tags: [Sharing]
            summary: Create a share link for a secret
            operationId: createShare
            x-agentcash-auth:
                mode: paid
            x-payment-info:
                protocols: [x402]
                pricingMode: fixed
                price: "0.003"
            parameters:
                - name: secret_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateShareRequest"
            responses:
                "201":
                    description: Share created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShareResponse"
                "402":
                    $ref: "#/components/responses/PaymentRequired"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/share/{share_id}:
        get:
            tags: [Sharing]
            summary: Access a shared secret
            operationId: accessShare
            security: []
            x-agentcash-auth:
                mode: paid
            x-payment-info:
                protocols: [x402]
                pricingMode: fixed
                price: "0.0015"
            parameters:
                - name: share_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Shared secret value
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SharedSecretResponse"
                "402":
                    $ref: "#/components/responses/PaymentRequired"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Sharing]
            summary: Revoke a share link
            operationId: revokeShare
            parameters:
                - name: share_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Share revoked

    /v1/shares/outbound:
        get:
            tags: [Sharing]
            summary: List shares you have sent
            operationId: listOutboundShares
            responses:
                "200":
                    description: Outbound share list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShareListResponse"

    /v1/shares/inbound:
        get:
            tags: [Sharing]
            summary: List shares sent to you
            operationId: listInboundShares
            responses:
                "200":
                    description: Inbound share list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShareListResponse"

    /v1/shares/{share_id}/accept:
        post:
            tags: [Sharing]
            summary: Accept an inbound share
            operationId: acceptShare
            parameters:
                - name: share_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Share accepted

    /v1/shares/{share_id}/decline:
        post:
            tags: [Sharing]
            summary: Decline an inbound share
            operationId: declineShare
            parameters:
                - name: share_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Share declined

    # ---------------------------------------------------------------------------
    # Organization
    # ---------------------------------------------------------------------------

    /v1/org/members:
        get:
            tags: [Organization]
            summary: List organization members
            operationId: listOrgMembers
            responses:
                "200":
                    description: Member list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OrgMemberListResponse"

    /v1/org/agent-keys-vault:
        get:
            tags: [Organization]
            summary: Get the org's __agent-keys vault id
            description: Returns the vault id for the caller's org agent-keys vault (used for revealing agent identity keys). Users only; 404 if the vault does not exist.
            operationId: getAgentKeysVault
            responses:
                "200":
                    description: Agent-keys vault id
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentKeysVaultResponse"
                "404":
                    description: Agent-keys vault not found

    /v1/org/status:
        get:
            tags: [Organization]
            summary: Organization operational status
            description: Returns whether the org is emergency-frozen (blocks agent tx/execution).
            operationId: getOrgStatus
            responses:
                "200":
                    description: Current org status
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [org_id, status]
                                properties:
                                    org_id:
                                        type: string
                                        format: uuid
                                    status:
                                        type: string
                                        enum: [active, frozen]
                                    frozen_at:
                                        type: string
                                        format: date-time
                                        nullable: true
                "403":
                    description: Forbidden

    /v1/org/freeze:
        post:
            tags: [Organization]
            summary: Emergency org-wide freeze
            description: Sets organizations.frozen_at — blocks agent tx/execution until unfreeze. Owner/admin only.
            operationId: freezeOrg
            responses:
                "200":
                    description: Organization frozen
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    status:
                                        type: string
                                        enum: [frozen]
                                    org_id:
                                        type: string
                                        format: uuid
                "403":
                    description: Forbidden

    /v1/org/unfreeze:
        post:
            tags: [Organization]
            summary: Clear org-wide freeze
            description: Clears organizations.frozen_at. Owner/admin only.
            operationId: unfreezeOrg
            responses:
                "200":
                    description: Organization unfrozen
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    status:
                                        type: string
                                        enum: [unfrozen]
                                    org_id:
                                        type: string
                                        format: uuid
                "403":
                    description: Forbidden

    /v1/org/bankr-config:
        get:
            tags: [Organization]
            summary: Get org Bankr partner configuration
            description: Returns whether the org has configured Bankr BYOK (partner key prefix and default wallet only — never the secret). Users only.
            operationId: getOrgBankrConfig
            responses:
                "200":
                    description: Bankr configuration status
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OrgBankrConfigResponse"
        put:
            tags: [Organization]
            summary: Set org Bankr partner configuration
            description: Store or replace the org's Bankr partner key (`bk_ptr_...`) and optional default wallet (`wlt_...`). Owner/admin only. Partner key encrypted at rest.
            operationId: upsertOrgBankrConfig
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpsertOrgBankrConfigRequest"
            responses:
                "200":
                    description: Configuration saved
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OrgBankrConfigResponse"
        delete:
            tags: [Organization]
            summary: Remove org Bankr partner configuration
            description: Delete BYOK credentials for the org. Owner/admin only.
            operationId: deleteOrgBankrConfig
            responses:
                "204":
                    description: Configuration removed
                "404":
                    description: Configuration not found

    /v1/org/invite:
        post:
            tags: [Organization]
            summary: Invite a member by email
            operationId: inviteMember
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/InviteMemberRequest"
            responses:
                "200":
                    description: Invitation sent
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/InviteMemberResponse"

    /v1/org/members/{user_id}:
        patch:
            tags: [Organization]
            summary: Update a member's role
            operationId: updateMemberRole
            parameters:
                - name: user_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateMemberRoleRequest"
            responses:
                "200":
                    description: Role updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OrgMemberResponse"
        delete:
            tags: [Organization]
            summary: Remove a member from the organization
            operationId: removeMember
            parameters:
                - name: user_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Member removed

    # ---------------------------------------------------------------------------
    # Org Shared Environment Variables
    # ---------------------------------------------------------------------------

    /v1/org/env-vars:
        get:
            tags: [Organization]
            summary: List org shared environment variables
            operationId: listOrgEnvVars
            responses:
                "200":
                    description: Org shared environment variable list
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    env_vars:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/OrgEnvVar"
        post:
            tags: [Organization]
            summary: Create org shared environment variable
            operationId: createOrgEnvVar
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateOrgEnvVarRequest"
            responses:
                "201":
                    description: Org shared env var created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OrgEnvVar"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/org/env-vars/{key}:
        patch:
            tags: [Organization]
            summary: Update org shared environment variable
            operationId: updateOrgEnvVar
            parameters:
                - name: key
                  in: path
                  required: true
                  schema:
                      type: string
            requestBody:
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateOrgEnvVarRequest"
            responses:
                "200":
                    description: Org shared env var updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OrgEnvVar"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/org/env-vars/{id}:
        delete:
            tags: [Organization]
            summary: Delete org shared environment variable
            operationId: deleteOrgEnvVar
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Deleted

    /v1/org/env-vars/{id}/link:
        post:
            tags: [Organization]
            summary: Link org shared env var to a vault
            operationId: linkOrgEnvVar
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [vault_id]
                            properties:
                                vault_id:
                                    type: string
                                    format: uuid
            responses:
                "201":
                    description: Linked

    /v1/org/env-vars/{id}/links/{vault_id}:
        delete:
            tags: [Organization]
            summary: Unlink org shared env var from a vault
            operationId: unlinkOrgEnvVar
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: vault_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Unlinked

    # ---------------------------------------------------------------------------
    # Billing
    # ---------------------------------------------------------------------------

    /v1/billing/usage:
        get:
            tags: [Billing]
            summary: Get usage summary (legacy)
            operationId: billingUsage
            responses:
                "200":
                    description: Usage summary
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/UsageSummaryResponse"

    /v1/billing/history:
        get:
            tags: [Billing]
            summary: Get usage event history (legacy)
            operationId: billingHistory
            parameters:
                - name: limit
                  in: query
                  schema:
                      type: integer
                      default: 50
            responses:
                "200":
                    description: Usage event list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/UsageHistoryResponse"

    /v1/billing/subscribe:
        post:
            tags: [Billing]
            summary: Start a subscription via Stripe Checkout
            operationId: billingSubscribe
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SubscribeRequest"
            responses:
                "200":
                    description: Checkout URL
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CheckoutUrlResponse"

    /v1/billing/portal:
        post:
            tags: [Billing]
            summary: Open Stripe Customer Portal
            operationId: billingPortal
            responses:
                "200":
                    description: Portal URL
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PortalUrlResponse"

    /v1/billing/subscription:
        get:
            tags: [Billing]
            summary: Get subscription, usage, and credit summary
            operationId: billingSubscription
            responses:
                "200":
                    description: Full billing summary
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SubscriptionResponse"

    /v1/billing/credits/topup:
        post:
            tags: [Billing]
            summary: Top up prepaid credits via Stripe
            operationId: billingCreditTopup
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/TopupRequest"
            responses:
                "200":
                    description: Checkout URL for top-up
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CheckoutUrlResponse"

    /v1/billing/credits/balance:
        get:
            tags: [Billing]
            summary: Get credit balance
            operationId: billingCreditBalance
            responses:
                "200":
                    description: Credit balance
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CreditBalanceResponse"

    /v1/billing/credits/transactions:
        get:
            tags: [Billing]
            summary: Get credit transaction ledger
            operationId: billingCreditTransactions
            parameters:
                - name: page
                  in: query
                  schema:
                      type: integer
                      default: 1
                - name: limit
                  in: query
                  schema:
                      type: integer
                      default: 50
            responses:
                "200":
                    description: Credit ledger
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CreditTransactionsListResponse"

    # ---------------------------------------------------------------------------
    # LLM Token Billing
    # ---------------------------------------------------------------------------

    /v1/billing/llm-token-billing:
        get:
            tags: [Billing]
            summary: Get LLM token billing status
            operationId: getLlmTokenBilling
            description: >
                Returns whether LLM token billing is enabled, optional Stripe billing credit balance
                (metered scope), and estimated cycle usage from the upcoming invoice—including per-line
                metered rows when Stripe returns them (amounts; quantities such as tokens when present).
            responses:
                "200":
                    description: LLM token billing status
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/LlmTokenBillingStatus"

    /v1/billing/llm-token-billing/subscribe:
        post:
            tags: [Billing]
            summary: Subscribe to LLM token billing
            operationId: subscribeLlmTokenBilling
            description: >
                Creates a Stripe Checkout session for the LLM token billing pricing plan.
                Returns a checkout URL to redirect the user. After the user completes checkout,
                a webhook activates LLM billing for the org.
            responses:
                "200":
                    description: Stripe Checkout URL
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/LlmCheckoutResponse"

    /v1/billing/llm-token-billing/disable:
        post:
            tags: [Billing]
            summary: Disable LLM token billing
            operationId: disableLlmTokenBilling
            description: >
                Disables LLM token billing for the org and cancels all active
                Stripe subscriptions for the LLM pricing plan. Agents will fall
                back to direct provider routing. You can re-enable it at any time.
            responses:
                "200":
                    description: LLM billing disabled
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/LlmDisableResponse"

    /v1/billing/llm-token-billing/cancel-duplicates:
        post:
            tags: [Billing]
            summary: Cancel duplicate LLM billing subscriptions
            operationId: cancelLlmDuplicateSubscriptions
            description: >
                Cancels extra Stripe LLM billing subscriptions for the org,
                keeping a single primary subscription (active preferred over trialing).
                Does not change the org LLM billing enabled setting.
            responses:
                "200":
                    description: Duplicate subscriptions cancelled
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/LlmCancelDuplicatesResponse"

    /v1/billing/overage-method:
        patch:
            tags: [Billing]
            summary: Set overage payment method
            operationId: billingOverageMethod
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/OverageMethodRequest"
            responses:
                "200":
                    description: Overage method updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OverageMethodResponse"

    /v1/billing/webhooks:
        post:
            tags: [Billing]
            summary: Stripe webhook receiver
            operationId: billingWebhook
            security: []
            responses:
                "200":
                    description: Webhook processed

    # ---------------------------------------------------------------------------
    # Audit
    # ---------------------------------------------------------------------------

    /v1/audit/events:
        get:
            tags: [Audit]
            summary: Query audit events
            operationId: queryAuditEvents
            x-agentcash-auth:
                mode: paid
            x-payment-info:
                protocols: [x402]
                pricingMode: fixed
                price: "0.0008"
            parameters:
                - name: resource_id
                  in: query
                  schema:
                      type: string
                - name: actor_id
                  in: query
                  schema:
                      type: string
                - name: action
                  in: query
                  schema:
                      type: string
                - name: from
                  in: query
                  schema:
                      type: string
                      format: date-time
                - name: to
                  in: query
                  schema:
                      type: string
                      format: date-time
                - name: limit
                  in: query
                  schema:
                      type: integer
                      default: 100
                - name: offset
                  in: query
                  schema:
                      type: integer
                      default: 0
            responses:
                "200":
                    description: Audit events
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AuditEventsResponse"
                "402":
                    $ref: "#/components/responses/PaymentRequired"

    /v1/audit/verify:
        get:
            tags: [Audit]
            summary: Verify audit hash chain integrity
            operationId: verifyAuditChain
            description: |
                Verifies the HMAC-SHA256 integrity hash chain for audit events in the
                calling organization. Returns whether the chain is valid, how many
                events were verified, and the point of first break (if any).
            parameters:
                - name: from
                  in: query
                  schema:
                      type: string
                      format: date-time
                - name: to
                  in: query
                  schema:
                      type: string
                      format: date-time
                - name: limit
                  in: query
                  schema:
                      type: integer
                      default: 1000
                      maximum: 10000
            responses:
                "200":
                    description: Chain verification result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AuditVerifyResponse"

    # ---------------------------------------------------------------------------
    # Security (IP Rules)
    # ---------------------------------------------------------------------------

    /v1/security/ip-rules:
        get:
            tags: [Security]
            summary: List IP rules
            operationId: listIpRules
            responses:
                "200":
                    description: IP rule list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/IpRulesListResponse"
        post:
            tags: [Security]
            summary: Create an IP rule
            operationId: createIpRule
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateIpRuleRequest"
            responses:
                "201":
                    description: Rule created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/IpRuleResponse"

    /v1/security/ip-rules/{rule_id}:
        delete:
            tags: [Security]
            summary: Delete an IP rule
            operationId: deleteIpRule
            parameters:
                - name: rule_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Rule deleted

    # ---------------------------------------------------------------------------
    # Treasury
    # ---------------------------------------------------------------------------

    /v1/treasury:
        post:
            tags: [Treasury]
            summary: Create a treasury (Safe multisig)
            operationId: createTreasury
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateTreasuryRequest"
            responses:
                "201":
                    description: Treasury created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
        get:
            tags: [Treasury]
            summary: List treasuries
            operationId: listTreasuries
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: List of treasuries
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    treasuries:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/TreasuryResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/treasury/{treasury_id}:
        get:
            tags: [Treasury]
            summary: Get treasury details
            operationId: getTreasury
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Treasury details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Treasury]
            summary: Update treasury name and/or threshold
            operationId: updateTreasury
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateTreasuryRequest"
            responses:
                "200":
                    description: Treasury updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Treasury]
            summary: Delete a treasury and its signers
            operationId: deleteTreasury
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Treasury deleted
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/{treasury_id}/signers:
        post:
            tags: [Treasury]
            summary: Add a signer to a treasury
            operationId: addTreasurySigner
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/AddSignerRequest"
            responses:
                "201":
                    description: Signer added
                "400":
                    $ref: "#/components/responses/BadRequest"

    /v1/treasury/{treasury_id}/signers/{signer_id}:
        delete:
            tags: [Treasury]
            summary: Remove a signer from a treasury
            operationId: removeTreasurySigner
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: signer_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Signer removed
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/{treasury_id}/access-requests:
        post:
            tags: [Treasury]
            summary: Request access to a treasury (agent-only)
            operationId: requestTreasuryAccess
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "201":
                    description: Access request created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AccessRequestResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [Treasury]
            summary: List access requests for a treasury
            operationId: listTreasuryAccessRequests
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: List of access requests
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    requests:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/AccessRequestResponse"

    /v1/treasury/{treasury_id}/access-requests/{request_id}/approve:
        post:
            tags: [Treasury]
            summary: Approve an access request
            operationId: approveTreasuryAccess
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: request_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Access request approved
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/{treasury_id}/access-requests/{request_id}/deny:
        post:
            tags: [Treasury]
            summary: Deny an access request
            operationId: denyTreasuryAccess
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: request_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Access request denied
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Treasury Proposals (multisig propose / sign / execute)
    # ---------------------------------------------------------------------------

    /v1/treasury/{treasury_id}/proposals:
        post:
            tags: [Treasury Proposals]
            summary: Create a multisig proposal
            description: |
                Create a new Safe multisig transaction proposal. The proposer must be a
                treasury signer or an agent with an active delegation for the treasury.
                If auto-approve rules match, the agent's signature is auto-inserted and
                auto-execute fires if threshold is met.
            operationId: createTreasuryProposal
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateTreasuryProposalRequest"
            responses:
                "201":
                    description: Proposal created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryProposalResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [Treasury Proposals]
            summary: List proposals for a treasury
            operationId: listTreasuryProposals
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: status
                  in: query
                  required: false
                  schema:
                      type: string
                      enum: [pending, approved, executing, executed, rejected, expired]
            responses:
                "200":
                    description: Proposal list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryProposalListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/treasury/{treasury_id}/proposals/{proposal_id}:
        get:
            tags: [Treasury Proposals]
            summary: Get a proposal with collected signatures
            operationId: getTreasuryProposal
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: proposal_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Proposal details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryProposalResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Treasury Proposals]
            summary: Cancel a pending proposal (proposer only)
            operationId: cancelTreasuryProposal
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: proposal_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Proposal cancelled
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/{treasury_id}/proposals/{proposal_id}/sign:
        post:
            tags: [Treasury Proposals]
            summary: Sign a proposal (approve or reject)
            description: |
                Submit an EIP-712 signature for a pending proposal. When approve signatures
                reach the Safe threshold, auto-execute fires: signatures are collected in
                address-sorted order, `execTransaction` calldata is built, and the transaction
                is broadcast via RPC.
            operationId: signTreasuryProposal
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: proposal_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SignTreasuryProposalRequest"
            responses:
                "200":
                    description: Signature recorded (may include executed_tx_hash if auto-executed)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryProposalResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/{treasury_id}/proposals/{proposal_id}/execute:
        post:
            tags: [Treasury Proposals]
            summary: Force-execute a proposal if threshold is met (user-only)
            operationId: executeTreasuryProposal
            security:
                - BearerAuth: []
            parameters:
                - name: treasury_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: proposal_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Proposal executed
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryProposalResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Treasury Wallets (multi-chain key generation for human users)
    # ---------------------------------------------------------------------------

    /v1/treasury/wallets/generate:
        post:
            tags: [Treasury Wallets]
            summary: Generate multi-chain wallets for the authenticated user
            description: |
                Generates keypairs for the requested chains (or all supported chains if omitted).
                Private keys are stored in a per-org `__treasury-keys` vault with tier-appropriate
                MPC custody. Skips chains where the user already has an active wallet. Available
                on all tiers (counts toward wallet quota). Human users only — agents get 403.
            operationId: generateTreasuryWallets
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/GenerateTreasuryWalletsRequest"
            responses:
                "201":
                    description: Wallets generated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryWalletListResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/treasury/wallets:
        get:
            tags: [Treasury Wallets]
            summary: List the authenticated user's treasury wallets
            operationId: listTreasuryWallets
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Wallet list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryWalletListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/treasury/wallets/{chain}:
        get:
            tags: [Treasury Wallets]
            summary: Get the user's active wallet for a specific chain
            operationId: getTreasuryWallet
            security:
                - BearerAuth: []
            parameters:
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
                  description: "Chain name (e.g. ethereum, solana, bitcoin)"
            responses:
                "200":
                    description: Wallet details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryWalletResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Treasury Wallets]
            summary: Deactivate the user's wallet for a specific chain
            operationId: deactivateTreasuryWallet
            security:
                - BearerAuth: []
            parameters:
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "204":
                    description: Wallet deactivated
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/treasury/wallets/{chain}/export:
        post:
            tags: [Treasury Wallets]
            summary: Export the private key for a treasury wallet
            description: |
                Returns the raw private key hex for the user's active wallet on
                the given chain. Requires re-authentication via the `X-Auth-Confirm`
                header (account password). Audit-logged as `treasury_wallet.export`.
                Human users only.
            operationId: exportTreasuryWallet
            security:
                - BearerAuth: []
            parameters:
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
                - name: X-Auth-Confirm
                  in: header
                  required: true
                  description: Account password for re-authentication
                  schema:
                      type: string
                      format: password
            responses:
                "200":
                    description: Private key exported
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryWalletExportResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/wallets/{chain}/rotate:
        post:
            tags: [Treasury Wallets]
            summary: Rotate the user's wallet key for a chain
            description: |
                Generates a new keypair, deactivates the old wallet, and creates a
                new active wallet. The old private key version is retained in the
                vault for audit. Counts toward wallet quota (does not require a paid plan).
            operationId: rotateTreasuryWallet
            security:
                - BearerAuth: []
            parameters:
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Wallet rotated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryWalletResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/wallets/{chain}/balance:
        get:
            tags: [Treasury Wallets]
            summary: Get wallet balance
            description: |
                Returns the native and token balances for the user's active wallet
                on the specified chain.
            operationId: getTreasuryWalletBalance
            security:
                - BearerAuth: []
            parameters:
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
                - name: tokens
                  in: query
                  required: false
                  description: Optional list of ERC-20 contract addresses to query balances for
                  schema:
                      type: array
                      items:
                          type: string
            responses:
                "200":
                    description: Wallet balance
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryWalletBalanceResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/wallets/{chain}/send:
        post:
            tags: [Treasury Wallets]
            summary: Send from treasury wallet
            description: |
                Signs and broadcasts a transaction from the user's active wallet on
                the specified chain. Requires re-authentication via `X-Auth-Confirm`
                header (account password). Human users only.
            operationId: sendFromTreasuryWallet
            security:
                - BearerAuth: []
            parameters:
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
                - name: X-Auth-Confirm
                  in: header
                  required: true
                  description: Account password for re-authentication
                  schema:
                      type: string
                      format: password
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/TreasuryWalletSendRequest"
            responses:
                "200":
                    description: Transaction sent
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryWalletSendResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/wallets/{chain}/swap:
        post:
            tags: [Treasury Wallets]
            summary: Swap tokens via DEX aggregator
            description: |
                Executes a token swap through a DEX aggregator from the user's active
                wallet on the specified chain. Requires re-authentication via
                `X-Auth-Confirm` header (account password). Human users only.
            operationId: swapFromTreasuryWallet
            security:
                - BearerAuth: []
            parameters:
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
                - name: X-Auth-Confirm
                  in: header
                  required: true
                  description: Account password for re-authentication
                  schema:
                      type: string
                      format: password
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/TreasuryWalletSwapRequest"
            responses:
                "200":
                    description: Swap executed
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryWalletSwapResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/treasury/wallets/{chain}/import:
        post:
            tags: [Treasury Wallets]
            summary: Import a treasury wallet
            description: |
                Import an existing private key as a treasury wallet. Human-only,
                requires password re-authentication via X-Auth-Confirm header.
            operationId: importTreasuryWallet
            security:
                - BearerAuth: []
            parameters:
                - name: chain
                  in: path
                  required: true
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ImportKeyRequest"
            responses:
                "201":
                    description: Treasury wallet imported
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryWalletResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/treasury/wallets/auth-policy:
        get:
            tags: [Treasury Wallets]
            summary: Get effective human factor auth policy for embedded clients
            description: |
                Returns the resolved human factor auth (HFA) policy governing treasury
                wallet send, swap, and export, plus the number of passkeys registered
                for the calling user. Intended for embedded wallet clients; equivalent
                to GET /v1/auth/human-factor-auth with an additional passkey count.
                Precedence: user override → platform app → spend policy → defaults.
            operationId: getTreasuryAuthPolicy
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Effective HFA policy with passkey registration count
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TreasuryAuthPolicyResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/treasury/wallets/spend-policy:
        get:
            tags: [Treasury Wallets]
            summary: Get effective spend policy for current user
            description: |
                Returns the effective spend policy governing the authenticated user's
                wallet transactions. Resolves from per-user override (if set) or the
                app-wide default. Returns null if no policy is configured.
            operationId: getEffectiveSpendPolicy
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Effective spend policy
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    policy:
                                        nullable: true
                                        allOf:
                                            - $ref: "#/components/schemas/SpendPolicyResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/treasury/wallets/inference-budget:
        get:
            tags: [Treasury Wallets]
            summary: Get inference budget for current user
            description: |
                Returns the user's remaining LLM inference allowance when connected via a platform app.
                Includes allowance, spent, remaining USD, per-request cap, and billing period end.
            operationId: getUserInferenceBudget
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Inference budget (or unconfigured message)
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: "#/components/schemas/InferenceBudgetResponse"
                                    - $ref: "#/components/schemas/InferenceBudgetUnconfiguredResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"

    # ---------------------------------------------------------------------------
    # Webhooks
    # ---------------------------------------------------------------------------

    /v1/webhooks:
        post:
            tags: [Webhooks]
            summary: Register a webhook
            operationId: createWebhook
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateWebhookRequest"
            responses:
                "201":
                    description: Webhook registered
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/WebhookCreatedResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
        get:
            tags: [Webhooks]
            summary: List webhooks
            operationId: listWebhooks
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Webhook list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/WebhookListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/webhooks/{id}:
        get:
            tags: [Webhooks]
            summary: Get webhook
            operationId: getWebhook
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Webhook details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/WebhookResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Webhooks]
            summary: Update webhook
            operationId: updateWebhook
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateWebhookRequest"
            responses:
                "200":
                    description: Webhook updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/WebhookResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Webhooks]
            summary: Delete webhook
            operationId: deleteWebhook
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Webhook deleted
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Admin
    # ---------------------------------------------------------------------------

    /v1/admin/settings:
        get:
            tags: [Admin]
            summary: List platform settings
            operationId: adminListSettings
            responses:
                "200":
                    description: Settings list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SettingsListResponse"

    /v1/admin/settings/{key}:
        put:
            tags: [Admin]
            summary: Update a platform setting
            operationId: adminUpdateSetting
            parameters:
                - name: key
                  in: path
                  required: true
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateSettingRequest"
            responses:
                "200":
                    description: Setting updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SettingResponse"
        delete:
            tags: [Admin]
            summary: Delete a platform setting
            operationId: adminDeleteSetting
            parameters:
                - name: key
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "204":
                    description: Setting deleted

    /v1/admin/x402:
        get:
            tags: [Admin]
            summary: Get x402 payment config
            operationId: adminGetX402Config
            responses:
                "200":
                    description: x402 config
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/X402ConfigResponse"
        put:
            tags: [Admin]
            summary: Update x402 payment config
            operationId: adminUpdateX402Config
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/X402ConfigResponse"
            responses:
                "200":
                    description: Config updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/X402ConfigResponse"

    /v1/admin/users:
        get:
            tags: [Admin]
            summary: List all platform users
            operationId: adminListUsers
            responses:
                "200":
                    description: User list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AdminUsersListResponse"

    /v1/admin/users/{user_id}:
        delete:
            tags: [Admin]
            summary: Delete a user (cascade)
            operationId: adminDeleteUser
            parameters:
                - name: user_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: User deleted

    /v1/admin/orgs/{org_id}/limits:
        get:
            tags: [Admin]
            summary: Get org limits
            operationId: adminGetOrgLimits
            parameters:
                - name: org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Org limits
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OrgLimitsResponse"
        put:
            tags: [Admin]
            summary: Update org limits
            operationId: adminUpdateOrgLimits
            parameters:
                - name: org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateOrgLimitsRequest"
            responses:
                "200":
                    description: Limits updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OrgLimitsResponse"

    /v1/admin/orgs/{org_id}/billing-tier:
        put:
            tags: [Admin]
            summary: Set org billing tier (without Stripe)
            operationId: adminSetBillingTier
            description: |
                Manually set an organization's billing tier to free, pro, business, or enterprise.
                For testing, manual upgrades, and trial grants — does not create a Stripe subscription.
                Setting to "pro", "business", or "enterprise" sets period_end to now + duration_days (default 365).
                Setting to "free" clears subscription data. Use duration_days: 90 for a 3-month trial.
            parameters:
                - name: org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SetBillingTierRequest"
            responses:
                "200":
                    description: Billing tier updated
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/admin/usage/reset:
        post:
            tags: [Admin]
            summary: Reset all API usage events (testing)
            operationId: adminResetUsageEvents
            description: |
                Deletes every row in `usage_events` for all organizations. Resets monthly
                request counts used for free-tier / x402 quota. Does not change prepaid credit
                balances or Stripe. **Platform admin only** (same guard as other `/v1/admin/*` routes).
            responses:
                "200":
                    description: Usage table cleared; returns number of deleted rows
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ResetUsageEventsResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/admin/usage/reset-for-user:
        post:
            tags: [Admin]
            summary: Reset API usage for a user's organization
            operationId: adminResetUsageForUserByEmail
            description: |
                Looks up a registered user by email and deletes all `usage_events` rows for that
                user's `org_id`. Resets free-tier / monthly quota for the whole org (not other orgs).
                **Platform admin only.**
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ResetUsageForUserEmailRequest"
            responses:
                "200":
                    description: Usage cleared for the user's org
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ResetUsageForUserEmailResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Health
    # ---------------------------------------------------------------------------

    /v1/health:
        get:
            tags: [Health]
            summary: Service health check
            operationId: healthCheck
            security: []
            responses:
                "200":
                    description: Healthy
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/HealthResponse"

    /v1/health/hsm:
        get:
            tags: [Health]
            summary: HSM connectivity check
            operationId: healthHsm
            security: []
            responses:
                "200":
                    description: HSM status
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    status:
                                        type: string
                                        enum: [ok, degraded, unavailable]

    # --- Shroud Activity ---

    /v1/shroud/attestation:
        get:
            tags: [Shroud]
            summary: TEE attestation proof (public)
            operationId: getShroudAttestation
            security: []
            description: |
                Public endpoint returning the TEE attestation proof for Shroud.
                Returns the GCE Confidential VM identity token and image hash so
                customers can verify Shroud is running inside a Confidential VM
                before signing contracts. Served from shroud.1claw.xyz.
            servers:
                - url: https://shroud.1claw.xyz
            responses:
                "200":
                    description: Attestation proof
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShroudAttestationResponse"

    /v1/shroud/activity:
        get:
            tags: [Shroud]
            summary: List Shroud activity events
            description: Returns recent Shroud proxy activity for the organization (LLM requests, inspections, policy actions).
            security:
                - BearerAuth: []
            parameters:
                - in: query
                  name: agent_id
                  schema:
                      type: string
                  description: Filter by agent ID
                - in: query
                  name: action
                  schema:
                      type: string
                  description: Filter by action (allowed, blocked, warned)
                - in: query
                  name: limit
                  schema:
                      type: integer
                      default: 50
                  description: Maximum events to return
                - in: query
                  name: offset
                  schema:
                      type: integer
                      default: 0
                  description: Pagination offset
            responses:
                "200":
                    description: Activity events
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    events:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/ShroudActivityEvent"
                                    total:
                                        type: integer
                "401":
                    description: Unauthorized
        post:
            tags: [Shroud]
            summary: Ingest Shroud activity event (internal)
            description: Called by the Shroud proxy to record activity events. Not intended for external use.
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/IngestShroudActivityRequest"
            responses:
                "201":
                    description: Event recorded
                "401":
                    description: Unauthorized

    /v1/shroud/threat-summary:
        get:
            tags: [Shroud]
            summary: Shroud threat analytics summary
            description: >
                Aggregated threat metrics for the organization from `shroud_activity`
                (detectors, blocked counts, recent flagged requests). Query `period` selects
                the window; the previous window of equal length is used for request volume trend.
            security:
                - BearerAuth: []
            parameters:
                - in: query
                  name: period
                  schema:
                      type: string
                      enum: [1h, 24h, 7d, 30d]
                      default: 24h
                  description: Rolling window ending now
            responses:
                "200":
                    description: Threat summary
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShroudThreatSummary"
                "400":
                    description: Invalid period
                "401":
                    description: Unauthorized

    # --- Platform API ---

    /v1/platform/apps:
        post:
            tags: [Platform]
            summary: Register a platform app
            description: Register a new platform app for building on top of 1Claw. Returns an API key (plt_ prefix) that must be saved immediately.
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreatePlatformAppRequest"
            responses:
                "201":
                    description: Platform app created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformAppCreatedResponse"
                "400":
                    description: Invalid request
                "403":
                    description: Only human users can register platform apps
        get:
            tags: [Platform]
            summary: List platform apps
            description: List all platform apps in the organization.
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: List of platform apps
                    content:
                        application/json:
                            schema:
                                type: array
                                items:
                                    $ref: "#/components/schemas/PlatformAppResponse"

    /v1/platform/apps/{appId}:
        get:
            tags: [Platform]
            summary: Get platform app details
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Platform app details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformAppResponse"
                "404":
                    description: Not found
        patch:
            tags: [Platform]
            summary: Update platform app
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdatePlatformAppRequest"
            responses:
                "200":
                    description: Updated platform app
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformAppResponse"
        delete:
            tags: [Platform]
            summary: Delete platform app
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Soft-deleted; slug released for reuse within the org
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformAppDeleteResponse"
                "403":
                    description: Only human users can delete platform apps

    /v1/platform/apps/{appId}/transfer-ownership:
        post:
            tags: [Platform]
            summary: Transfer platform app to another organization
            description: |
                Moves the platform app record to another organization. Requires org
                owner/admin in the source org and step-up auth (`X-Auth-Confirm`,
                purpose `platform.app.transfer`). End-user connections and provisioned
                resources remain in their original organizations.
            operationId: transferPlatformAppOwnership
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: header
                  name: X-Auth-Confirm
                  required: true
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/TransferPlatformAppOwnershipRequest"
            responses:
                "200":
                    description: Ownership transferred
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TransferPlatformAppOwnershipResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/apps/{appId}/rotate-key:
        post:
            tags: [Platform]
            summary: Rotate platform API key
            description: Generate a new API key for the platform app. The old key is immediately invalidated. Returns the new key (one-time).
            security:
                - BearerAuth: []
            parameters:
                - name: appId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                api_key_expires_at:
                                    type: string
                                    format: date-time
                                    nullable: true
                                    description: Optional expiration for the new key.
            responses:
                "200":
                    description: New key generated
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    api_key:
                                        type: string
                                        description: The new API key (shown once)
                                    api_key_prefix:
                                        type: string
                                    api_key_expires_at:
                                        type: string
                                        format: date-time
                                        nullable: true
                "403":
                    description: Only human users can rotate platform keys

    /v1/platform/apps/{appId}/stats:
        get:
            tags: [Platform]
            summary: Get platform app statistics
            description: Returns aggregate statistics about a platform app's connected users, bootstraps, and grants.
            operationId: getPlatformAppStats
            security:
                - BearerAuth: []
            parameters:
                - name: appId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: App statistics
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformAppStatsResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/apps/{appId}/rotate-webhook-secret:
        post:
            tags: [Platform]
            summary: Rotate webhook secret
            description: Generate a new webhook signing secret for the platform app. The old secret is immediately invalidated. Returns the new secret (one-time).
            operationId: rotatePlatformWebhookSecret
            security:
                - BearerAuth: []
            parameters:
                - name: appId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: New webhook secret generated
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [webhook_secret]
                                properties:
                                    webhook_secret:
                                        type: string
                                        description: The new webhook signing secret (shown once)
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    description: Only human users can rotate webhook secrets
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/apps/{appId}/templates:
        post:
            tags: [Platform]
            summary: Create bootstrap template
            description: Create a template that defines what vault, agents, and policies to bootstrap for each connected user.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateTemplateRequest"
            responses:
                "201":
                    description: Template created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformTemplateResponse"
        get:
            tags: [Platform]
            summary: List templates
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: List of templates
                    content:
                        application/json:
                            schema:
                                type: array
                                items:
                                    $ref: "#/components/schemas/PlatformTemplateResponse"

    /v1/platform/apps/{appId}/templates/{template_id}:
        patch:
            tags: [Platform]
            summary: Update a bootstrap template
            description: Update an existing template's name, description, spec, or active status.
            operationId: updatePlatformTemplate
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: path
                  name: template_id
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                name:
                                    type: string
                                description:
                                    type: string
                                    nullable: true
                                spec:
                                    type: object
                                    additionalProperties: true
                                is_active:
                                    type: boolean
            responses:
                "200":
                    description: Template updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformTemplateResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Platform]
            summary: Delete a bootstrap template
            operationId: deletePlatformTemplate
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: path
                  name: template_id
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Template deleted
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/apps/{appId}/templates/{template_id}/preview:
        post:
            tags: [Platform]
            summary: Preview resolved template spec
            description: |
                Resolves `{{params.*}}` and `{{subject.*}}` placeholders in a template spec
                without provisioning resources. Useful for validating parameterized bootstrap templates.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: path
                  name: template_id
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: false
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/TemplatePreviewRequest"
            responses:
                "200":
                    description: Resolved template spec
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/TemplatePreviewResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/users/upsert:
        post:
            tags: [Platform]
            summary: Provision or look up a platform user
            description: Upserts a user using either an OIDC subject_token (verified against the platform app's JWKS) or an email address. Returns the user handle and connection ID.
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpsertPlatformUserRequest"
            responses:
                "200":
                    description: Existing user found
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformUserResponse"
                "201":
                    description: New user created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformUserResponse"
                "409":
                    description: User exists in a different organization. Contains a link_required payload with an OAuth authorize URL for cross-org consent.
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PlatformUserLinkRequiredResponse"

    /v1/platform/siwe/challenge:
        post:
            tags: [Platform]
            summary: Issue SIWE nonce
            description: |
                Creates a one-time nonce for Sign-In With Ethereum user provisioning.
                Requires platform (`plt_`) authentication. The nonce expires in 5 minutes.
            security:
                - BearerAuth: []
            requestBody:
                required: false
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SiweChallengeRequest"
            responses:
                "200":
                    description: Nonce issued
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SiweChallengeResponse"
                "400":
                    description: SIWE domain not configured

    /v1/platform/apps/{appId}/users:
        get:
            tags: [Platform]
            summary: List connected users
            description: List all users connected to this platform app.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Connected users
                    content:
                        application/json:
                            schema:
                                type: array
                                items:
                                    $ref: "#/components/schemas/PlatformConnectedUserResponse"

    /v1/platform/connections/{connectionId}/bootstrap:
        post:
            tags: [Platform]
            summary: Bootstrap resources for a connected user
            description: Executes a template to create vault, agent, and policies for the connected user. Returns a claim URL and token for the user to claim their resources.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/BootstrapRequest"
            responses:
                "201":
                    description: Resources bootstrapped
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/BootstrapResponse"

    /v1/platform/connections/{connectionId}/reissue-claim:
        post:
            tags: [Platform]
            summary: Reissue a claim URL
            description: Mints a fresh 10-minute claim token for an already-bootstrapped connection without re-provisioning resources. Use when the original claim URL has expired.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: false
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                return_to:
                                    type: string
                                    description: Optional redirect URL after claim
            responses:
                "200":
                    description: New claim URL issued
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    claim_url:
                                        type: string
                                    claim_token:
                                        type: string
                                    expires_in:
                                        type: integer
                                        description: Seconds until expiry (600 = 10 min)
                                    connection_id:
                                        type: string
                                        format: uuid
                "400":
                    description: Connection not yet bootstrapped
                "404":
                    description: Connection not found

    /v1/platform/connections/{connectionId}:
        get:
            tags: [Platform]
            summary: Get connection details
            description: |
                Returns connection status, claim state, wallet address, and provisioned resource IDs.
                Use for polling the claim loop after bootstrap.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Connection details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ConnectionDetailResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/connections/{connectionId}/usage:
        get:
            tags: [Platform]
            summary: Get per-connection usage
            description: Returns inference spend for the current UTC month for this connection.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Usage summary
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ConnectionUsageResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/connections/{connectionId}/entitlements:
        get:
            tags: [Platform]
            summary: List entitlement evaluations
            description: Returns on-chain entitlement watch status for the connection.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Entitlement watches
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/EntitlementsListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/connections/{connectionId}/entitlements/refresh:
        post:
            tags: [Platform]
            summary: Refresh entitlement evaluations
            description: Triggers an immediate entitlement monitor cycle for this connection's org.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "202":
                    description: Refresh accepted
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/apps/{appId}/audit:
        get:
            tags: [Platform]
            summary: Platform audit log
            description: Returns audit events related to this platform app.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: query
                  name: limit
                  schema:
                      type: integer
                      default: 50
                - in: query
                  name: offset
                  schema:
                      type: integer
                      default: 0
            responses:
                "200":
                    description: Audit events
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    events:
                                        type: array
                                        items:
                                            type: object

    /v1/platform/connected-apps:
        get:
            tags: [Platform]
            summary: List connected apps (user side)
            description: Returns platform apps connected to the calling user's account.
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Connected apps
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    connected_apps:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/ConnectedAppResponse"

    /v1/platform/connected-apps/{connectionId}:
        patch:
            tags: [Platform]
            summary: Update connection delegation
            description: Toggle delegation and update delegation scopes for a connected platform app. User-only.
            operationId: updateConnectionDelegation
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                delegation_enabled:
                                    type: boolean
                                delegation_scopes:
                                    type: array
                                    items:
                                        type: string
                                    description: "Scopes: vaults:read, vaults:write, agents:read, agents:write, secrets:read, secrets:write, automations:*, runtimes:*"
            responses:
                "200":
                    description: Delegation settings updated
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    connection_id:
                                        type: string
                                        format: uuid
                                    delegation_enabled:
                                        type: boolean
                                    delegation_scopes:
                                        type: array
                                        items:
                                            type: string
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Platform]
            summary: Disconnect a platform app
            description: Disconnect the calling user from a platform app.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Disconnected
                "404":
                    description: Connection not found

    /v1/platform/connections/{connectionId}/delegation-log:
        get:
            tags: [Platform]
            summary: Delegation audit log
            description: List delegated actions performed by a platform app on behalf of this user.
            operationId: getDelegationLog
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Delegation log entries
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    entries:
                                        type: array
                                        items:
                                            type: object
                                            properties:
                                                action:
                                                    type: string
                                                scope:
                                                    type: string
                                                resource_type:
                                                    type: string
                                                resource_id:
                                                    type: string
                                                    format: uuid
                                                timestamp:
                                                    type: string
                                                    format: date-time
                                                details:
                                                    type: object
                                                    additionalProperties: true
                                                    nullable: true
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/connections/{connectionId}/grant:
        post:
            tags: [Platform]
            summary: Grant platform app access to vaults/agents
            description: |
                User-authenticated. Grant the platform app access to selected vaults and agents.
                Validates user ownership of all requested resources. Creates platform_user_grants
                entries and merges resource IDs into the connection record.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/GrantResourcesRequest"
            responses:
                "201":
                    description: Grants created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/GrantResourcesResponse"
                "400":
                    description: No vault_ids or agent_ids provided
                "403":
                    description: Resource not owned by caller
                "404":
                    description: Connection not found

    /v1/platform/connections/{connectionId}/grants:
        get:
            tags: [Platform]
            summary: List active resource grants for a connection
            description: User-authenticated. Returns active (non-revoked) grants for the connection.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Grant list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/GrantListResponse"
                "404":
                    description: Connection not found

    /v1/platform/connections/{connectionId}/grants/{grantId}:
        delete:
            tags: [Platform]
            summary: Revoke a resource grant
            description: User-authenticated. Revoke a specific resource grant by ID.
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: path
                  name: grantId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Grant revoked
                "404":
                    description: Grant not found or already revoked

    /v1/platform/claim/{token}:
        get:
            tags: [Platform]
            summary: Preview a claim token
            description: |
                Verify a claim token and preview what was provisioned (app name, vaults, agents, policies).
                Public endpoint — the token itself is the authentication.
            parameters:
                - in: path
                  name: token
                  required: true
                  schema:
                      type: string
                  description: The `ct_` prefixed claim token from the bootstrap response
            responses:
                "200":
                    description: Claim preview
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ClaimPreviewResponse"
                "404":
                    description: Invalid or expired claim token
        post:
            tags: [Platform]
            summary: Redeem a claim token
            description: |
                Redeem a one-time claim token, marking the connection as claimed.
                Public endpoint — the token itself is the authentication. Returns 409 if already claimed, 410 if expired.
            parameters:
                - in: path
                  name: token
                  required: true
                  schema:
                      type: string
                  description: The `ct_` prefixed claim token from the bootstrap response
            responses:
                "200":
                    description: Claim redeemed
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ClaimRedeemResponse"
                "404":
                    description: Invalid claim token
                "409":
                    description: Claim token already used
                "410":
                    description: Claim token has expired

    # --- Spend Policies ---

    /v1/platform/apps/{appId}/spend-policies:
        post:
            tags: [Platform]
            summary: Create wallet spend policy
            description: |
                Create an app-wide spend policy that governs what embedded wallet users
                can do with their wallets. Policies apply to all connected users by default
                and can be overridden per-user via connection-level policies.
            operationId: createSpendPolicy
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateSpendPolicyRequest"
            responses:
                "201":
                    description: Spend policy created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SpendPolicyResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [Platform]
            summary: List spend policies for app
            description: Returns all spend policies configured for the platform app.
            operationId: listSpendPolicies
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Spend policies
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    policies:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/SpendPolicyResponse"

    /v1/platform/apps/{appId}/spend-policies/{policyId}:
        get:
            tags: [Platform]
            summary: Get a spend policy by ID
            operationId: getSpendPolicy
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: path
                  name: policyId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Spend policy
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SpendPolicyResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Platform]
            summary: Delete a spend policy
            operationId: deleteSpendPolicy
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: appId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: path
                  name: policyId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Deleted
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/connections/{connectionId}/spend-policy:
        get:
            tags: [Platform]
            summary: Get effective spend policy for a connection
            description: |
                Returns the effective spend policy for the connected user, resolving
                per-user overrides before app-level defaults. Requires plt_ platform auth.
            operationId: getConnectionSpendPolicy
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Effective spend policy (or null)
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    policy:
                                        oneOf:
                                            - $ref: "#/components/schemas/SpendPolicyResponse"
                                            - type: "null"
                "404":
                    $ref: "#/components/responses/NotFound"
        put:
            tags: [Platform]
            summary: Set per-user spend policy override
            description: |
                Override the app-wide spend policy for a specific connected user. This
                policy takes precedence over the app default. Remove by deleting the
                connection-level policy.
            operationId: setUserSpendPolicy
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: header
                  name: Idempotency-Key
                  required: false
                  schema:
                      type: string
                  description: Optional replay protection; same key + body returns cached response (409 on body mismatch).
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateSpendPolicyRequest"
            responses:
                "200":
                    description: Spend policy set (or idempotent replay)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SpendPolicyResponse"
                "201":
                    description: Spend policy created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SpendPolicyResponse"
                "409":
                    description: Idempotency-Key reused with different body
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"

                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/connections/{connectionId}/approvals:
        get:
            tags: [Platform]
            summary: List approvals for a platform connection
            description: |
                Returns approvals assigned to the connection's user, filtered to agents
                provisioned on the connection. Requires plt_ platform auth.
            operationId: listConnectionApprovals
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: status
                  in: query
                  required: false
                  schema:
                      type: string
                - name: risk_tier
                  in: query
                  required: false
                  schema:
                      type: integer
                - name: limit
                  in: query
                  required: false
                  schema:
                      type: integer
                      default: 50
                - name: offset
                  in: query
                  required: false
                  schema:
                      type: integer
                      default: 0
            responses:
                "200":
                    description: Connection-scoped approvals
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApprovalListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/connections/{connectionId}/approvals/{approvalId}:
        get:
            tags: [Platform]
            summary: Get a connection-scoped approval
            operationId: getConnectionApproval
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - in: path
                  name: approvalId
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Approval detail
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApprovalResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/connections/{connectionId}/pending-approvals:
        get:
            tags: [Platform]
            summary: List pending consensus approvals for a connection
            description: |
                Returns pending approvals for agents provisioned on the connection,
                including `action_payload` and `payload_hash` for consensus UX.
                Requires plt_ platform auth.
            operationId: listConnectionPendingApprovals
            security:
                - BearerAuth: []
            parameters:
                - in: path
                  name: connectionId
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: status
                  in: query
                  schema:
                      type: string
                      default: pending
                - name: limit
                  in: query
                  schema:
                      type: integer
                      default: 50
                - name: offset
                  in: query
                  schema:
                      type: integer
                      default: 0
            responses:
                "200":
                    description: Pending approvals list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PendingApprovalListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    # --- Approvals ---

    /v1/approvals:
        get:
            tags: [Approvals]
            summary: List pending approvals
            description: |
                Returns approvals for the authenticated user's organization.
                Human-only. Supports filtering by status and pagination.
            operationId: listApprovals
            parameters:
                - name: status
                  in: query
                  required: false
                  schema:
                      type: string
                      enum: [pending, approved, rejected, expired]
                  description: Filter by approval status
                - name: limit
                  in: query
                  required: false
                  schema:
                      type: integer
                      default: 50
                - name: offset
                  in: query
                  required: false
                  schema:
                      type: integer
                      default: 0
            responses:
                "200":
                    description: Approval list
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [approvals]
                                properties:
                                    approvals:
                                        type: array
                                        items:
                                            $ref: "#/components/schemas/ApprovalResponse"

    /v1/approvals/{approval_id}:
        get:
            tags: [Approvals]
            summary: Get approval details
            description: Returns details for a single approval by ID.
            operationId: getApproval
            parameters:
                - name: approval_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Approval details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApprovalResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/approvals/{approval_id}/status:
        get:
            tags: [Approvals]
            summary: Poll approval status (agent-only)
            description: |
                Lightweight status poll for agents waiting on human approval.
                Returns `status` and `expires_at` only. Agents may only poll
                approvals they created (`agent_id` must match the caller).
            operationId: getApprovalStatus
            parameters:
                - name: approval_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Approval status
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApprovalStatusResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/approvals/{approval_id}/decide:
        post:
            tags: [Approvals]
            summary: Approve or reject
            description: |
                Submit a decision (approve or reject) for a pending approval.
                Human-only. The approval must be in `pending` status.
                For `card_order` approvals, approving auto-executes the x402 payment;
                rejecting marks the card as `rejected`.
                Risk tier 2+ approvals require step-up authentication via
                `X-Auth-Confirm` (account password or `rat_` re-auth token from
                `POST /v1/auth/reauth/begin` + `complete`). Risk tier 3 requires
                passkey or TOTP re-auth token.
            operationId: decideApproval
            parameters:
                - name: approval_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/DecideApprovalRequest"
            responses:
                "200":
                    description: Decision recorded
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApprovalResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "404":
                    $ref: "#/components/responses/NotFound"
                "409":
                    $ref: "#/components/responses/Conflict"

    /v1/approvals/quick-decide:
        get:
            tags: [Approvals]
            summary: One-click approve or deny (email link)
            description: |
                Public endpoint (no Bearer auth). The `token` query param is the
                authenticator — SHA-256 hashed, single-use, 7-day TTL. On success
                redirects to `{public_url}/approvals/{id}?decided=true`.
                Auto-executes approved `card_order` and `policy_change` actions.
            operationId: quickDecideApproval
            parameters:
                - name: token
                  in: query
                  required: true
                  schema:
                      type: string
                - name: decision
                  in: query
                  required: true
                  schema:
                      type: string
                      enum: [approved, rejected]
            responses:
                "302":
                    description: Redirect to dashboard confirmation page
                "400":
                    $ref: "#/components/responses/BadRequest"
                "404":
                    $ref: "#/components/responses/NotFound"
                "409":
                    $ref: "#/components/responses/Conflict"

    /v1/deposit-destinations:
        post:
            tags: [Treasury]
            summary: Create deposit destination
            operationId: createDepositDestination
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [chain]
                            properties:
                                chain: { type: string }
                                label: { type: string }
                                treasury_wallet_id: { type: string, format: uuid }
            responses:
                "201":
                    description: Destination created
                "401":
                    $ref: "#/components/responses/Unauthorized"
        get:
            tags: [Treasury]
            summary: List deposit destinations
            operationId: listDepositDestinations
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: List of destinations

    /v1/deposit-destinations/{id}:
        get:
            tags: [Treasury]
            summary: Get deposit destination
            operationId: getDepositDestination
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema: { type: string, format: uuid }
            responses:
                "200":
                    description: Destination detail with events
        patch:
            tags: [Treasury]
            summary: Update deposit destination status
            operationId: updateDepositDestination
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema: { type: string, format: uuid }
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                status: { type: string, enum: [active, paused, archived] }
            responses:
                "200":
                    description: Updated destination

    /v1/internal-accounts:
        post:
            tags: [Treasury]
            summary: Create internal account
            operationId: createInternalAccount
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [name]
                            properties:
                                name: { type: string }
                                description: { type: string }
            responses:
                "201":
                    description: Account created
        get:
            tags: [Treasury]
            summary: List internal accounts
            operationId: listInternalAccounts
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Account list with balances

    /v1/internal-accounts/{id}:
        get:
            tags: [Treasury]
            summary: Get internal account
            operationId: getInternalAccount
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema: { type: string, format: uuid }
            responses:
                "200":
                    description: Account detail

    /v1/internal-accounts/{id}/ledger:
        get:
            tags: [Treasury]
            summary: Get account ledger
            operationId: getInternalAccountLedger
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema: { type: string, format: uuid }
            responses:
                "200":
                    description: Ledger entries

    /v1/internal-transfers:
        post:
            tags: [Treasury]
            summary: Transfer between internal accounts
            operationId: createInternalTransfer
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [from_account_id, to_account_id, asset, amount]
                            properties:
                                from_account_id: { type: string, format: uuid }
                                to_account_id: { type: string, format: uuid }
                                asset: { type: string }
                                amount: { type: string }
                                memo: { type: string }
            responses:
                "201":
                    description: Transfer completed

    /v1/fiat/onramp/session:
        post:
            tags: [Billing]
            summary: Create fiat onramp session
            operationId: createFiatOnrampSession
            security:
                - BearerAuth: []
            responses:
                "201":
                    description: Onramp widget URL

    /v1/fiat/offramp/initiate:
        post:
            tags: [Billing]
            summary: Initiate fiat offramp
            operationId: initiateFiatOfframp
            security:
                - BearerAuth: []
            responses:
                "201":
                    description: Offramp widget URL

    /v1/auth/social-login:
        post:
            tags: [Authentication]
            summary: Social login (Google, Apple, Discord)
            operationId: socialLogin
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [provider, id_token]
                            properties:
                                provider: { type: string, enum: [google, apple, discord] }
                                id_token:
                                    type: string
                                    description: Google/Apple ID token, or Discord OAuth authorization code
                                oauth_redirect_uri:
                                    type: string
                                    description: Required for Discord — must match the redirect URI used in the OAuth flow
                                auto_provision_chains:
                                    type: array
                                    items: { type: string }
            responses:
                "200":
                    description: Login successful
                "201":
                    description: New user created
                "409":
                    description: Email already registered (no auto-linking)
                "401":
                    description: Invalid or unverified token

    /v1/auth/passkeys/tx-assert/begin:
        post:
            tags: [Authentication]
            summary: Begin passkey transaction authorization
            description: |
                Requires `tx_digest` — SHA-256 hex of the canonical digest for the
                treasury action being authorized (`send` or `swap`). The server
                recomputes this digest on send/swap and rejects passkey tokens that
                do not match.
            operationId: passkeyTxAssertBegin
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/PasskeyTxAssertBeginRequest"
            responses:
                "200":
                    description: WebAuthn challenge
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PasskeyAssertBeginResponse"
                "400":
                    description: Missing or invalid tx_digest, or invalid action
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    description: No passkeys registered for the user

    /v1/auth/passkeys/tx-assert/complete:
        post:
            tags: [Authentication]
            summary: Complete passkey transaction authorization
            operationId: passkeyTxAssertComplete
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Passkey token for X-Passkey-Token header

    # ---------------------------------------------------------------------------
    # Email OTP
    # ---------------------------------------------------------------------------

    /v1/auth/email-otp/send:
        post:
            tags: [Authentication]
            summary: Send email OTP code
            description: |
                Sends a 6-digit one-time code to the specified email address.
                No authentication required. Rate-limited per IP and per email.
            operationId: sendEmailOtp
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [email]
                            properties:
                                email:
                                    type: string
                                    format: email
                                platform_app_id:
                                    type: string
                                    format: uuid
                                    description: Optional platform app context for embedded wallet flows
            responses:
                "200":
                    description: OTP sent
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    status:
                                        type: string
                                        enum: [sent]
                "429":
                    description: Rate limited

    /v1/auth/email-otp/verify:
        post:
            tags: [Authentication]
            summary: Verify email OTP and get JWT
            description: |
                Verifies the 6-digit code sent to the user's email. If the user does not
                exist, a new account is created. Optionally auto-provisions treasury wallets
                for the specified chains. Returns a JWT for subsequent API calls.
            operationId: verifyEmailOtp
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [email, code]
                            properties:
                                email:
                                    type: string
                                    format: email
                                code:
                                    type: string
                                    description: 6-digit OTP code
                                platform_app_id:
                                    type: string
                                    format: uuid
                                auto_provision_chains:
                                    type: array
                                    items: { type: string }
                                    description: Chains to auto-generate wallets for (e.g. ["ethereum", "base"])
            responses:
                "200":
                    description: Existing user authenticated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/EmailOtpVerifyResponse"
                "201":
                    description: New user created and authenticated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/EmailOtpVerifyResponse"
                "400":
                    description: Invalid or expired code
                "429":
                    description: Rate limited

    # ---------------------------------------------------------------------------
    # OAuth
    # ---------------------------------------------------------------------------

    /v1/oauth/authorize:
        get:
            tags: [OAuth]
            summary: Get OAuth consent info
            description: |
                Returns information about the platform app requesting authorization so the
                UI can display a consent screen. Used by the 1Claw-hosted consent page.
            operationId: getOAuthConsent
            security:
                - BearerAuth: []
            parameters:
                - name: client_id
                  in: query
                  required: true
                  schema: { type: string }
                  description: Platform app slug
                - name: redirect_uri
                  in: query
                  required: true
                  schema: { type: string, format: uri }
                - name: response_type
                  in: query
                  required: true
                  schema: { type: string, enum: [code] }
                - name: scope
                  in: query
                  schema: { type: string }
                  description: Space-delimited scopes (e.g. "openid email wallet")
                - name: state
                  in: query
                  schema: { type: string }
                - name: code_challenge
                  in: query
                  schema: { type: string }
                  description: PKCE code challenge
                - name: code_challenge_method
                  in: query
                  schema: { type: string, enum: [S256] }
                  description: Only S256 is supported (PKCE is mandatory for code grants)
                - name: nonce
                  in: query
                  schema: { type: string }
                  description: OIDC nonce for ID token replay protection
                - name: login_hint
                  in: query
                  schema: { type: string }
                  description: Pre-fill the email field on the consent page
            responses:
                "200":
                    description: Consent screen data
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OAuthConsentResponse"
                "400":
                    description: Invalid client_id, redirect_uri, or response_type
        post:
            tags: [OAuth]
            summary: Submit OAuth consent decision
            description: |
                The user approves or denies the authorization request. On approval, returns
                a redirect URL containing the authorization code. On denial, returns a
                redirect URL with an error parameter.
            operationId: submitOAuthConsent
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [approve, client_id, redirect_uri]
                            properties:
                                approve: { type: boolean }
                                client_id: { type: string }
                                redirect_uri: { type: string, format: uri }
                                scope: { type: string }
                                state: { type: string }
                                code_challenge: { type: string }
                                code_challenge_method: { type: string, enum: [S256] }
                                nonce: { type: string }
            responses:
                "200":
                    description: Redirect URL with authorization code or error
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [redirect_url]
                                properties:
                                    redirect_url:
                                        type: string
                                        format: uri
                "400":
                    description: Invalid request

    /v1/oauth/token:
        post:
            tags: [OAuth]
            summary: Exchange authorization code for tokens
            description: |
                Standard OAuth 2.0 token endpoint. Exchanges an authorization code for an
                access token and optional OIDC ID token. Supports PKCE via `code_verifier`.
            operationId: exchangeOAuthToken
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [grant_type, code, client_id, redirect_uri]
                            properties:
                                grant_type:
                                    type: string
                                    enum: [authorization_code]
                                code: { type: string }
                                client_id: { type: string }
                                redirect_uri: { type: string, format: uri }
                                code_verifier:
                                    type: string
                                    description: PKCE code verifier (required — PKCE S256 is mandatory for all code grants)
            responses:
                "200":
                    description: Token response
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OAuthTokenResponse"
                "400":
                    description: Invalid grant, code, or verifier
                "401":
                    description: Invalid client credentials

    /v1/oauth/userinfo:
        get:
            tags: [OAuth]
            summary: Get authenticated user info (OIDC UserInfo)
            description: |
                Standard OIDC UserInfo endpoint. Returns claims about the authenticated user
                based on the granted scopes.
            operationId: getOAuthUserInfo
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: User info
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OAuthUserInfoResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/oauth/revoke:
        post:
            tags: [OAuth]
            summary: Revoke an OAuth token (RFC 7009)
            description: |
                Revokes an access token or refresh token. The authorization server
                invalidates the token so it can no longer be used. Follows RFC 7009.
            operationId: revokeOAuthToken
            security: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [token]
                            properties:
                                token:
                                    type: string
                                    description: The token to revoke (access_token or refresh_token)
                                token_type_hint:
                                    type: string
                                    enum: [access_token, refresh_token]
                                    description: Hint about the type of token being revoked
            responses:
                "200":
                    description: Token revoked successfully (or was already invalid)
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    revoked:
                                        type: boolean
                                        example: true

    /v1/oauth/consents/{app_id}:
        delete:
            tags: [OAuth]
            summary: Revoke consent for a platform app
            description: |
                Revokes the user's previously granted OAuth consent for a specific platform app.
                All active tokens issued to the app are invalidated and the consent record is deleted.
            operationId: revokeOAuthConsent
            security:
                - BearerAuth: []
            parameters:
                - name: app_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                  description: The platform app ID whose consent to revoke
            responses:
                "200":
                    description: Consent revoked
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    revoked:
                                        type: boolean
                                        example: true
                                    app_id:
                                        type: string
                                        format: uuid
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Risk Engine
    # ---------------------------------------------------------------------------

    /v1/risk/events:
        get:
            tags: [Risk Engine]
            summary: List risk events
            description: |
                Returns risk events detected by the risk engine, ordered by most recent first.
                Filter by severity or principal type.
            operationId: listRiskEvents
            parameters:
                - name: severity
                  in: query
                  schema:
                      type: string
                      enum: [low, medium, high, critical]
                  description: Filter events by severity level
                - name: principal_type
                  in: query
                  schema:
                      type: string
                      enum: [user, agent]
                  description: Filter events by principal type
                - name: limit
                  in: query
                  schema:
                      type: integer
                      default: 50
                - name: offset
                  in: query
                  schema:
                      type: integer
                      default: 0
            responses:
                "200":
                    description: Risk event list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RiskEventListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/risk/verdicts:
        get:
            tags: [Risk Engine]
            summary: List risk verdicts
            description: Returns all active risk verdicts for the caller's organization.
            operationId: listRiskVerdicts
            responses:
                "200":
                    description: Verdict list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RiskVerdictListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/risk/verdicts/{principal_type}/{principal_id}:
        get:
            tags: [Risk Engine]
            summary: Get risk verdict for a principal
            description: Returns the current risk verdict for a specific user or agent.
            operationId: getRiskVerdict
            parameters:
                - name: principal_type
                  in: path
                  required: true
                  schema:
                      type: string
                      enum: [user, agent]
                - name: principal_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Risk verdict (null if no verdict exists)
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    verdict:
                                        $ref: "#/components/schemas/RiskVerdict"
                                        nullable: true
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/risk/honeytokens:
        get:
            tags: [Risk Engine]
            summary: List honeytokens
            description: Returns all honeytokens (canary secrets) configured for the caller's organization.
            operationId: listHoneytokens
            responses:
                "200":
                    description: Honeytoken list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/HoneytokenListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
        post:
            tags: [Risk Engine]
            summary: Create a honeytoken
            description: |
                Register a secret path as a honeytoken (canary). Any access to this secret
                triggers a risk event and increments the trigger counter.
            operationId: createHoneytoken
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateHoneytokenRequest"
            responses:
                "201":
                    description: Honeytoken created
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    honeytoken:
                                        $ref: "#/components/schemas/Honeytoken"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/risk/honeytokens/{id}:
        delete:
            tags: [Risk Engine]
            summary: Delete a honeytoken
            description: Remove a honeytoken registration. The underlying secret is not affected.
            operationId: deleteHoneytoken
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Honeytoken deleted
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    deleted:
                                        type: boolean
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/tokens:
        get:
            tags: [Tokens]
            summary: List known tokens
            operationId: listKnownTokens
            parameters:
                - name: chain
                  in: query
                  schema:
                      type: string
                  description: Filter by chain name
            responses:
                "200":
                    description: Token list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/KnownTokenListResponse"

    /v1/chains/{chain_name}/tokens:
        get:
            tags: [Tokens]
            summary: List tokens for a specific chain
            operationId: listTokensByChain
            parameters:
                - name: chain_name
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Token list for chain
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/KnownTokenListResponse"

    /v1/admin/tokens:
        post:
            tags: [Admin, Tokens]
            summary: Create a known token (admin only)
            operationId: createKnownToken
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateKnownTokenRequest"
            responses:
                "201":
                    description: Token created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/KnownToken"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/admin/tokens/{token_id}:
        delete:
            tags: [Admin, Tokens]
            summary: Delete a known token (admin only)
            operationId: deleteKnownToken
            security:
                - BearerAuth: []
            parameters:
                - name: token_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Token deleted
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/agents/{agent_id}/cards/order:
        post:
            tags: [Payment Cards]
            summary: Order a payment card (x402)
            description: >
                Order a prepaid or gift card for an agent. Drives the x402
                payment flow server-side using the agent's Ethereum signing key
                (funded with USDC on Base). Requires `cards_enabled` on the agent
                and a Pro or higher plan. An `Idempotency-Key` header is required.
                When `card_require_approval` is true (default), the order is held
                in `awaiting_approval` until a human approves via the dashboard,
                mobile app, or email one-click link; payment runs only after approval.
            operationId: orderCard
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: Idempotency-Key
                  in: header
                  required: true
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/OrderCardRequest"
            responses:
                "202":
                    description: Card order queued for human approval (status awaiting_approval)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardResponse"
                "201":
                    description: Card order accepted and payment submitted (status pending)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardResponse"
                "200":
                    description: Idempotent replay of a prior order
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "409":
                    $ref: "#/components/responses/Conflict"

    /v1/cards:
        get:
            tags: [Payment Cards]
            summary: List payment cards
            description: List cards for the caller (agents see only their own). Always masked (last4 only).
            operationId: listCards
            responses:
                "200":
                    description: Card list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardListResponse"

    /v1/cards/import:
        post:
            tags: [Payment Cards]
            summary: Import a card (human-only)
            description: Manually import an existing card. Full storage mode — PAN stored encrypted, CVV as a one-time-read secret. Human-only.
            operationId: importCard
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ImportCardRequest"
            responses:
                "201":
                    description: Card imported
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/cards/gift-cards/search:
        post:
            tags: [Payment Cards]
            summary: Search gift-card brands
            description: Search available Laso gift-card brands/servers for the org's Laso account.
            operationId: searchGiftCards
            requestBody:
                required: false
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SearchGiftCardsRequest"
            responses:
                "200":
                    description: Available gift-card brands (provider-shaped payload)
                    content:
                        application/json:
                            schema:
                                type: object
                                additionalProperties: true

    /v1/cards/{card_id}:
        get:
            tags: [Payment Cards]
            summary: Get a payment card
            description: Get a single card (masked — last4 only).
            operationId: getCard
            parameters:
                - $ref: "#/components/parameters/CardId"
            responses:
                "200":
                    description: Card details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardResponse"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Payment Cards]
            summary: Update a card's reveal policy (human-only)
            operationId: updateCard
            parameters:
                - $ref: "#/components/parameters/CardId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateCardRequest"
            responses:
                "200":
                    description: Card updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/cards/{card_id}/reveal:
        post:
            tags: [Payment Cards]
            summary: Reveal card details
            description: >
                Reveal full card details (PAN/CVV or gift-card redemption).
                Humans must re-authenticate with their account password via the
                `X-Auth-Confirm` header. Agents may reveal only when a human has
                enabled a per-card reveal policy. Once revealed, the card can be
                used anywhere up to its balance — 1Claw has no further control.
            operationId: revealCard
            parameters:
                - $ref: "#/components/parameters/CardId"
                - name: X-Auth-Confirm
                  in: header
                  required: false
                  description: Account password (humans) for re-authentication.
                  schema:
                      type: string
            responses:
                "200":
                    description: Revealed card details (sensitive)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardRevealResponse"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/cards/{card_id}/void:
        post:
            tags: [Payment Cards]
            summary: Void a card
            description: 1Claw-level lock that blocks all further reveals/refreshes. Forward-looking only — a card revealed before void remains live.
            operationId: voidCard
            parameters:
                - $ref: "#/components/parameters/CardId"
            responses:
                "200":
                    description: Card voided
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/cards/{card_id}/refresh:
        post:
            tags: [Payment Cards]
            summary: Refresh a card's balance
            description: Proxy Laso refresh to update balance/status. Rate-limited to once per 5 minutes per card (429 on exceed).
            operationId: refreshCard
            parameters:
                - $ref: "#/components/parameters/CardId"
            responses:
                "200":
                    description: Card refreshed
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CardResponse"
                "429":
                    description: Refreshed too recently
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Automations
    # ---------------------------------------------------------------------------

    /v1/automations:
        post:
            tags: [Automations]
            summary: Create automation
            operationId: createAutomation
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateAutomationRequest"
            responses:
                "201":
                    description: Automation created (includes one-time webhook credentials when trigger_type is webhook)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationCreatedResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
        get:
            tags: [Automations]
            summary: List automations
            operationId: listAutomations
            responses:
                "200":
                    description: Automation list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/automations/{automationId}:
        get:
            tags: [Automations]
            summary: Get automation
            operationId: getAutomation
            parameters:
                - name: automationId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Automation details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Automations]
            summary: Update automation
            operationId: updateAutomation
            parameters:
                - name: automationId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateAutomationRequest"
            responses:
                "200":
                    description: Automation updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Automations]
            summary: Delete automation
            operationId: deleteAutomation
            parameters:
                - name: automationId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Automation deleted
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/automations/{automationId}/trigger:
        post:
            tags: [Automations]
            summary: Trigger automation
            operationId: triggerAutomation
            parameters:
                - name: automationId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Automation triggered
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationRunResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/automations/{automationId}/runs:
        get:
            tags: [Automations]
            summary: List automation runs
            operationId: listAutomationRuns
            parameters:
                - name: automationId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: limit
                  in: query
                  schema:
                      type: integer
                      default: 50
                - name: offset
                  in: query
                  schema:
                      type: integer
                      default: 0
            responses:
                "200":
                    description: Automation run list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationRunListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/automations/{automationId}/runs/{runId}:
        get:
            tags: [Automations]
            summary: Get automation run
            operationId: getAutomationRun
            description: Get details of a single automation run including step results and context.
            parameters:
                - name: automationId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: runId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Automation run detail
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationRunResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/automations/assist/draft:
        post:
            tags: [Automations]
            summary: Draft automation from natural language
            operationId: assistDraftAutomation
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [message]
                            properties:
                                message:
                                    type: string
                                agent_id:
                                    type: string
                                    format: uuid
                                timezone:
                                    type: string
            responses:
                "200":
                    description: Reviewable automation draft
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AssistDraftResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/automations/assist/session:
        post:
            tags: [Automations]
            summary: Mint short-lived Assist session token
            operationId: assistAutomationSession
            requestBody:
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                runtime_id:
                                    type: string
                                    format: uuid
            responses:
                "200":
                    description: Assist session token
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AssistSessionResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/automations/webhook/{automationId}/{token}:
        post:
            tags: [Automations]
            summary: Public webhook trigger
            operationId: webhookTriggerAutomation
            security: []
            parameters:
                - name: automationId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: token
                  in: path
                  required: true
                  schema:
                      type: string
                      description: whk_ prefixed webhook token (SHA-256 verified server-side)
            responses:
                "201":
                    description: Automation run queued
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationRunResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/automations/{automationId}/rotate-webhook-token:
        post:
            tags: [Automations]
            summary: Rotate webhook token
            operationId: rotateAutomationWebhookToken
            parameters:
                - name: automationId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: New one-time webhook URL and token
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/WebhookTokenRotatedResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/automations/{automationId}/runs/{runId}/cancel:
        post:
            tags: [Automations]
            summary: Cancel a running automation run
            operationId: cancelAutomationRun
            description: |
                Cancel a run that is currently in `running` or `awaiting_approval` status.
                Returns the updated run with status `cancelled`.
            parameters:
                - name: automationId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: runId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Run cancelled
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationRunResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/automations/presets:
        get:
            tags: [Automations]
            summary: List automation presets
            operationId: listAutomationPresets
            security: []
            description: Public preset gallery of ready-to-use automation templates.
            responses:
                "200":
                    description: Automation preset list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AutomationPresetsResponse"

    # ---------------------------------------------------------------------------
    # Runtimes
    # ---------------------------------------------------------------------------

    /v1/runtimes:
        post:
            tags: [Runtimes]
            summary: Create runtime
            operationId: createRuntime
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateRuntimeRequest"
            responses:
                "201":
                    description: Runtime created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RuntimeResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
        get:
            tags: [Runtimes]
            summary: List runtimes
            operationId: listRuntimes
            responses:
                "200":
                    description: Runtime list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RuntimeListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/runtimes/{runtimeId}:
        get:
            tags: [Runtimes]
            summary: Get runtime
            operationId: getRuntime
            parameters:
                - name: runtimeId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Runtime details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RuntimeResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Runtimes]
            summary: Update runtime
            operationId: updateRuntime
            parameters:
                - name: runtimeId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateRuntimeRequest"
            responses:
                "200":
                    description: Runtime updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RuntimeResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Runtimes]
            summary: Delete runtime
            operationId: deleteRuntime
            parameters:
                - name: runtimeId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Runtime deleted
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/runtimes/{runtimeId}/start:
        post:
            tags: [Runtimes]
            summary: Start runtime
            operationId: startRuntime
            parameters:
                - name: runtimeId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Runtime started
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RuntimeResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/runtimes/{runtimeId}/stop:
        post:
            tags: [Runtimes]
            summary: Stop runtime
            operationId: stopRuntime
            parameters:
                - name: runtimeId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Runtime stopped
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RuntimeResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/runtimes/{runtimeId}/logs:
        get:
            tags: [Runtimes]
            summary: Get runtime logs
            operationId: getRuntimeLogs
            parameters:
                - name: runtimeId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: tail
                  in: query
                  schema:
                      type: integer
                      default: 100
                  description: Number of recent log lines to return
            responses:
                "200":
                    description: Runtime logs
                    content:
                        application/json:
                            schema:
                                type: object
                                required: [entries]
                                properties:
                                    entries:
                                        type: array
                                        items:
                                            type: object
                                            required: [message]
                                            properties:
                                                timestamp:
                                                    type: string
                                                    format: date-time
                                                message:
                                                    type: string
                                                level:
                                                    type: string
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/runtimes/slug-check/{slug}:
        get:
            tags: [Runtimes]
            summary: Check slug availability
            operationId: checkSlugAvailability
            parameters:
                - name: slug
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Slug availability result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SlugCheckResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/runtimes/{runtimeId}/shell/session:
        post:
            tags: [Runtimes]
            summary: Create interactive shell session
            description: |
                Human-only. Creates a short-lived WebSocket session token for the
                runtime's PTY terminal. Requires step-up auth via `password`,
                `totp_code`, `passkey_credential`, or `reauth_token` (from
                `POST /v1/auth/reauth` with purpose `runtime_shell`).
                Runtime must have `shell_access_enabled` and be running.
                Enabling shell on a running runtime may require stop/start, or
                the server may auto-reconcile the sidecar on connect.
            operationId: createShellSession
            parameters:
                - name: runtimeId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ShellSessionRequest"
            responses:
                "200":
                    description: Shell session created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShellSessionResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/runtimes/{runtimeId}/shell/passkey/begin:
        post:
            tags: [Runtimes]
            summary: Begin shell passkey assertion
            description: |
                Human-only. Starts a WebAuthn assertion ceremony for shell
                step-up auth (social/Google users without a password).
            operationId: beginShellPasskey
            parameters:
                - name: runtimeId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Passkey challenge for shell session
                    content:
                        application/json:
                            schema:
                                type: object
                                additionalProperties: true
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/runtimes/{runtimeId}/chat:
        post:
            tags: [Runtimes]
            summary: Chat with a running runtime agent
            description: |
                Human-only. Proxies to the runtime container's OpenAI-compatible
                `POST /v1/chat/completions` (hermes / openclaw / openclaude / opencode chat bridge).
                Starts the runtime if stopped. Streams SSE when `Accept: text/event-stream`
                or `stream: true`. Conversation history is ephemeral (pass `messages`).
                Requires a public URL (shell access, Shroud sidecar, or HTTP hosting).
            operationId: runtimeChat
            parameters:
                - name: runtimeId
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/RuntimeChatRequest"
            responses:
                "200":
                    description: Chat completion (JSON) or SSE stream
                    content:
                        application/json:
                            schema:
                                type: object
                                additionalProperties: true
                        text/event-stream:
                            schema:
                                type: string
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Agent Memory
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/memory:
        get:
            tags: [Agent Memory]
            summary: List memory namespaces
            operationId: listMemoryNamespaces
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Namespace list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MemoryNamespaceListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/memory/{namespace}:
        get:
            tags: [Agent Memory]
            summary: List entries in namespace
            operationId: listMemoryEntries
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: namespace
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Memory entries
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MemoryEntryListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/memory/{namespace}/{key}:
        put:
            tags: [Agent Memory]
            summary: Put memory entry
            operationId: putMemoryEntry
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: namespace
                  in: path
                  required: true
                  schema:
                      type: string
                - name: key
                  in: path
                  required: true
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/PutMemoryRequest"
            responses:
                "200":
                    description: Memory entry stored
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MemoryEntry"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        get:
            tags: [Agent Memory]
            summary: Get memory entry
            operationId: getMemoryEntry
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: namespace
                  in: path
                  required: true
                  schema:
                      type: string
                - name: key
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "200":
                    description: Memory entry
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MemoryEntry"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Agent Memory]
            summary: Delete memory entry
            operationId: deleteMemoryEntry
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: namespace
                  in: path
                  required: true
                  schema:
                      type: string
                - name: key
                  in: path
                  required: true
                  schema:
                      type: string
            responses:
                "204":
                    description: Memory entry deleted
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/memory/search:
        post:
            tags: [Agent Memory]
            summary: Semantic search
            operationId: searchMemory
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/MemorySearchRequest"
            responses:
                "200":
                    description: Search results
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MemorySearchResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Discovery
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/card:
        get:
            tags: [Discovery]
            summary: Get agent card
            description: Public endpoint returning the agent's discovery card metadata.
            operationId: getAgentCard
            security: []
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Agent card
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentCardResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/directory:
        get:
            tags: [Discovery]
            summary: Public agent directory
            description: Browse the public directory of discoverable agents.
            operationId: listDirectory
            security: []
            parameters:
                - name: page
                  in: query
                  schema:
                      type: integer
                      default: 1
                - name: per_page
                  in: query
                  schema:
                      type: integer
                      default: 20
                - name: tags
                  in: query
                  schema:
                      type: string
                  description: Comma-separated tag filter
                - name: q
                  in: query
                  schema:
                      type: string
                  description: Search query
            responses:
                "200":
                    description: Directory listing
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/DirectoryResponse"

    /v1/agents/org-directory:
        get:
            tags: [agents, discovery]
            summary: List org agents
            description: |
                List agents within the caller's organization for sub-agent discovery.
                Returns agents with their capabilities, enabling agent-to-agent
                coordination and discovery within an org. Requires authentication.
            operationId: listOrgDirectory
            parameters:
                - name: q
                  in: query
                  schema:
                      type: string
                  description: Search query to filter agents by name or description
                - name: tags
                  in: query
                  schema:
                      type: string
                  description: Comma-separated tag filter
                - name: page
                  in: query
                  schema:
                      type: integer
                      default: 1
                - name: page_size
                  in: query
                  schema:
                      type: integer
                      default: 20
            responses:
                "200":
                    description: Org agent directory listing
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OrgDirectoryResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/agents/{agent_id}/discovery:
        patch:
            tags: [Discovery]
            summary: Update discovery settings
            operationId: updateDiscoverySettings
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateDiscoveryRequest"
            responses:
                "200":
                    description: Discovery settings updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/AgentCardResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/platform/marketplace:
        get:
            tags: [Platform, Discovery]
            summary: Public marketplace
            description: Browse the public platform marketplace of listed apps and agents. Returns approved platform apps with category, tags, pricing summaries, and screenshots.
            operationId: listMarketplace
            security: []
            parameters:
                - name: page
                  in: query
                  schema:
                      type: integer
                      default: 1
                - name: per_page
                  in: query
                  schema:
                      type: integer
                      default: 20
                - name: q
                  in: query
                  schema:
                      type: string
                  description: Search query
                - name: category
                  in: query
                  schema:
                      type: string
                  description: Filter by app category
            responses:
                "200":
                    description: Marketplace listing
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/MarketplaceResponse"

    # ---------------------------------------------------------------------------
    # Agent Chat
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/chat:
        post:
            tags: [Agent Chat]
            summary: Send chat message
            description: |
                Send a message to an agent and receive a response via Shroud LLM.
                Supports SSE streaming when Accept: text/event-stream is set.

                Agents can call this endpoint on other agents within the same
                organization for inter-agent communication (agent-to-agent chat).
                The caller must be authenticated and belong to the same org as
                the target agent.
            operationId: sendChatMessage
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SendChatMessageRequest"
            responses:
                "200":
                    description: Chat response
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SendChatMessageResponse"
                        text/event-stream:
                            schema:
                                type: string
                                description: SSE stream of response chunks
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/agents/{agent_id}/chat/conversations:
        get:
            tags: [Agent Chat]
            summary: List conversations
            description: List all chat conversations for an agent.
            operationId: listChatConversations
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Conversation list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChatConversationListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/agents/{agent_id}/chat/conversations/{conversation_id}:
        get:
            tags: [Agent Chat]
            summary: Get conversation
            description: Get a conversation with its full message history.
            operationId: getChatConversation
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: conversation_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Conversation detail
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ConversationDetailResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Agent Chat]
            summary: Archive conversation
            description: Archive (soft-delete) a chat conversation.
            operationId: deleteChatConversation
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: conversation_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Conversation archived
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Agent Channels
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/channels:
        post:
            tags: [Agent Channels]
            summary: Register channel
            description: |
                Register a new external messaging channel (Telegram, WhatsApp, Discord)
                for an agent. Human-only. Returns the channel with its webhook URL.
            operationId: createChannel
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateChannelRequest"
            responses:
                "201":
                    description: Channel created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChannelResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [Agent Channels]
            summary: List channels
            description: List all messaging channels for an agent.
            operationId: listChannels
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Channel list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChannelListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/agents/{agent_id}/channels/{channel_id}:
        patch:
            tags: [Agent Channels]
            summary: Update channel
            description: Update a channel's name, active status, or config. Human-only.
            operationId: updateChannel
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: channel_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdateChannelRequest"
            responses:
                "200":
                    description: Channel updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChannelResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Agent Channels]
            summary: Delete channel
            description: Delete a messaging channel. Human-only.
            operationId: deleteChannel
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: channel_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Channel deleted
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/channels/{channel_id}/send:
        post:
            tags: [Agent Channels]
            summary: Send outbound message
            description: Send an outbound message via a registered channel.
            operationId: sendChannelMessage
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: channel_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SendChannelMessageRequest"
            responses:
                "200":
                    description: Message sent
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChannelMessageResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/channels/{channel_id}/messages:
        get:
            tags: [Agent Channels]
            summary: Channel message history
            description: List inbound and outbound messages for a channel.
            operationId: listChannelMessages
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: channel_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: limit
                  in: query
                  schema:
                      type: integer
                      default: 50
            responses:
                "200":
                    description: Message list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ChannelMessageListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/agents/{agent_id}/channels/{channel_id}/test:
        post:
            tags: [Agent Channels]
            summary: Test channel connectivity
            description: Send a test message through the channel to verify connectivity and credentials.
            operationId: testChannel
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: channel_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                external_chat_id:
                                    type: string
                                    description: Optional chat ID to send the test message to
                                content:
                                    type: string
                                    description: Optional custom test message content
            responses:
                "200":
                    description: Test result
                    content:
                        application/json:
                            schema:
                                type: object
                                properties:
                                    success:
                                        type: boolean
                                    message:
                                        type: string
                                        nullable: true
                                    error:
                                        type: string
                                        nullable: true
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Channel Webhooks (Public)
    # ---------------------------------------------------------------------------

    /v1/webhooks/telegram/{webhook_path}:
        post:
            tags: [Agent Channels]
            summary: Telegram webhook
            description: Public webhook endpoint for receiving Telegram bot updates.
            operationId: telegramWebhook
            security: []
            parameters:
                - name: webhook_path
                  in: path
                  required: true
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
            responses:
                "200":
                    description: Webhook processed

    /v1/webhooks/whatsapp/{webhook_path}:
        get:
            tags: [Agent Channels]
            summary: WhatsApp webhook verification
            description: Verification endpoint for WhatsApp Cloud API webhook setup.
            operationId: whatsappWebhookVerify
            security: []
            parameters:
                - name: webhook_path
                  in: path
                  required: true
                  schema:
                      type: string
                - name: hub.mode
                  in: query
                  schema:
                      type: string
                - name: hub.verify_token
                  in: query
                  schema:
                      type: string
                - name: hub.challenge
                  in: query
                  schema:
                      type: string
            responses:
                "200":
                    description: Challenge response
        post:
            tags: [Agent Channels]
            summary: WhatsApp webhook
            description: Public webhook endpoint for receiving WhatsApp Cloud API events.
            operationId: whatsappWebhook
            security: []
            parameters:
                - name: webhook_path
                  in: path
                  required: true
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
            responses:
                "200":
                    description: Webhook processed

    /v1/webhooks/discord/{webhook_path}:
        post:
            tags: [Agent Channels]
            summary: Discord webhook
            description: Public webhook endpoint for receiving Discord bot interactions.
            operationId: discordWebhook
            security: []
            parameters:
                - name: webhook_path
                  in: path
                  required: true
                  schema:
                      type: string
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
            responses:
                "200":
                    description: Webhook processed

    # ---------------------------------------------------------------------------
    # OAuth Connect
    # ---------------------------------------------------------------------------

    /v1/oauth/providers:
        get:
            tags: [OAuth Connect]
            summary: List OAuth providers
            description: |
                Returns the list of supported OAuth providers with their metadata,
                available scopes, and authorization URLs. No authentication required.
            operationId: listOAuthProviders
            security: []
            responses:
                "200":
                    description: Provider list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OAuthProviderListResponse"

    /v1/agents/{agent_id}/oauth/connect:
        post:
            tags: [OAuth Connect]
            summary: Initiate OAuth connection
            description: |
                Start an OAuth authorization flow for the specified agent and provider.
                Returns the authorization URL to redirect the user to. Human-only.
            operationId: connectOAuth
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ConnectOAuthRequest"
            responses:
                "200":
                    description: Authorization URL generated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ConnectOAuthResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/oauth/connections:
        get:
            tags: [OAuth Connect]
            summary: List OAuth connections
            description: List all active OAuth connections for the specified agent.
            operationId: listOAuthConnections
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Connection list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OAuthConnectionListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/oauth/disconnect/{binding_id}:
        post:
            tags: [OAuth Connect]
            summary: Disconnect OAuth connection
            description: |
                Disconnect an OAuth connection by revoking tokens and removing the binding.
                Human-only.
            operationId: disconnectOAuth
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: binding_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Connection disconnected
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/oauth/app-credentials:
        post:
            tags: [OAuth Connect]
            summary: Save OAuth app credentials
            description: |
                Store custom OAuth app credentials (client ID/secret) for a provider.
                Allows the agent to use a BYOA (Bring Your Own App) OAuth application
                instead of 1Claw's shared credentials. Human-only.
            operationId: saveOAuthAppCredentials
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SaveOAuthAppCredentialsRequest"
            responses:
                "201":
                    description: Credentials saved
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OAuthAppCredentialResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"
        get:
            tags: [OAuth Connect]
            summary: List OAuth app credentials
            description: |
                List stored OAuth app credentials for the agent. Client secrets
                are never returned in the response.
            operationId: listOAuthAppCredentials
            parameters:
                - $ref: "#/components/parameters/AgentId"
            responses:
                "200":
                    description: Credential list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OAuthAppCredentialListResponse"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/agents/{agent_id}/oauth/app-credentials/{provider_slug}:
        delete:
            tags: [OAuth Connect]
            summary: Delete OAuth app credentials
            description: |
                Remove stored OAuth app credentials for a specific provider. Human-only.
            operationId: deleteOAuthAppCredentials
            parameters:
                - $ref: "#/components/parameters/AgentId"
                - name: provider_slug
                  in: path
                  required: true
                  schema:
                      type: string
                  description: Provider identifier (e.g. "github", "google", "slack")
            responses:
                "204":
                    description: Credentials deleted
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/oauth/callback:
        get:
            tags: [OAuth Connect]
            summary: OAuth callback
            description: |
                Public callback URL that OAuth providers redirect to after user authorization.
                Exchanges the authorization code for tokens and redirects to the dashboard.
            operationId: oauthConnectCallback
            security: []
            parameters:
                - name: code
                  in: query
                  schema:
                      type: string
                  description: Authorization code from the OAuth provider
                - name: state
                  in: query
                  schema:
                      type: string
                  description: Opaque state parameter for CSRF protection and session binding
                - name: error
                  in: query
                  schema:
                      type: string
                  description: Error code if the authorization was denied or failed
            responses:
                "302":
                    description: Redirect to dashboard with success or error status

    # ---------------------------------------------------------------------------
    # Cedar Policies
    # ---------------------------------------------------------------------------

    /v1/org/cedar-policies:
        post:
            tags: [Cedar Policies]
            summary: Create a Cedar policy
            description: Create a new Cedar policy for the organization. Team+ tier required.
            operationId: createCedarPolicy
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateCedarPolicyRequest"
            responses:
                "201":
                    description: Cedar policy created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CedarPolicyResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [Cedar Policies]
            summary: List Cedar policies
            description: List all Cedar policies for the organization.
            operationId: listCedarPolicies
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Cedar policies list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CedarPolicyListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/org/cedar-policies/{id}:
        get:
            tags: [Cedar Policies]
            summary: Get a Cedar policy
            description: Retrieve a specific Cedar policy by ID.
            operationId: getCedarPolicy
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Cedar policy details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CedarPolicyResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Cedar Policies]
            summary: Delete a Cedar policy
            description: Delete a Cedar policy by ID.
            operationId: deleteCedarPolicy
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Cedar policy deleted
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/org/cedar-policies/test:
        post:
            tags: [Cedar Policies]
            summary: Test Cedar policy evaluation
            description: Evaluate the organization's Cedar policies against a test request.
            operationId: testCedarPolicy
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CedarPolicyTestRequest"
            responses:
                "200":
                    description: Policy evaluation result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CedarPolicyTestResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    # ---------------------------------------------------------------------------
    # OPA Policies
    # ---------------------------------------------------------------------------

    /v1/org/opa-policies:
        post:
            tags: [OPA Policies]
            summary: Create an OPA policy
            description: Create a new OPA Rego policy for the organization. Business+ tier required.
            operationId: createOpaPolicy
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateOpaPolicyRequest"
            responses:
                "201":
                    description: OPA policy created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OpaPolicyResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [OPA Policies]
            summary: List OPA policies
            description: List all OPA policies for the organization.
            operationId: listOpaPolicies
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: OPA policies list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OpaPolicyListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/org/opa-policies/{id}:
        get:
            tags: [OPA Policies]
            summary: Get an OPA policy
            description: Retrieve a specific OPA policy by ID.
            operationId: getOpaPolicy
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: OPA policy details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OpaPolicyResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [OPA Policies]
            summary: Delete an OPA policy
            description: Delete an OPA policy by ID.
            operationId: deleteOpaPolicy
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: OPA policy deleted
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/org/opa-policies/test:
        post:
            tags: [OPA Policies]
            summary: Test OPA policy evaluation
            description: Evaluate the organization's OPA policies against a test input.
            operationId: testOpaPolicy
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/OpaPolicyTestRequest"
            responses:
                "200":
                    description: Policy evaluation result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/OpaPolicyTestResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    # ---------------------------------------------------------------------------
    # Policy Backend Settings (Cedar/OPA enforcement)
    # ---------------------------------------------------------------------------

    /v1/org/settings/policy-backend:
        get:
            tags: [Organization]
            summary: Get policy backend settings
            description: |
                Returns the org's Cedar/OPA enforcement configuration. Default mode is shadow.
                Owner/admin only.
            operationId: getPolicyBackendSettings
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Policy backend settings
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PolicyBackendSettingsResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
        patch:
            tags: [Organization]
            summary: Update policy backend settings
            description: |
                Configure backend (builtin, cedar, opa, builtin+cedar, builtin+opa), mode (shadow/enforce),
                scope actions, and circuit breaker behavior. Owner/admin only.
            operationId: updatePolicyBackendSettings
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/UpdatePolicyBackendSettingsRequest"
            responses:
                "200":
                    description: Updated settings
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PolicyBackendSettingsResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/org/policy-shadow-report:
        get:
            tags: [Organization]
            summary: Get policy shadow divergence report
            description: |
                Returns divergence statistics when running Cedar/OPA in shadow mode.
                Owner/admin only.
            operationId: getPolicyShadowReport
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Shadow divergence report
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PolicyShadowReportResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/org/guardrail-shadow-report:
        get:
            tags: [Organization]
            summary: Get guardrail shadow divergence report
            description: |
                Returns Convention 6 shadow-mode violations (`guardrail_shadow.would_deny` audit events)
                grouped by reason code. Owner/admin only.
            operationId: getGuardrailShadowReport
            security:
                - BearerAuth: []
            parameters:
                - name: since
                  in: query
                  schema:
                      type: string
                      format: date-time
                - name: until
                  in: query
                  schema:
                      type: string
                      format: date-time
            responses:
                "200":
                    description: Guardrail shadow report
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/GuardrailShadowReportResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/org/guardrail-revisions:
        get:
            tags: [Organization]
            summary: List guardrail revision history
            description: Audit trail of agent and binding guardrail changes. Owner/admin only.
            operationId: listGuardrailRevisions
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Guardrail revisions
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/GuardrailRevisionListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    # ---------------------------------------------------------------------------
    # Contract ABI Registry
    # ---------------------------------------------------------------------------

    /v1/org/contract-abis:
        post:
            tags: [Contract ABIs]
            summary: Register a contract ABI
            description: Upload an org-scoped ABI for transaction decoding. Owner/admin only.
            operationId: createContractAbi
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateContractAbiRequest"
            responses:
                "201":
                    description: ABI registered
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ContractAbiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "409":
                    $ref: "#/components/responses/Conflict"
        get:
            tags: [Contract ABIs]
            summary: List contract ABIs
            description: List org contract ABIs, optionally filtered by chain. Owner/admin only.
            operationId: listContractAbis
            security:
                - BearerAuth: []
            parameters:
                - name: chain
                  in: query
                  schema:
                      type: string
                  description: Filter by chain name
            responses:
                "200":
                    description: ABI list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ContractAbiListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/org/contract-abis/{id}:
        get:
            tags: [Contract ABIs]
            summary: Get a contract ABI
            operationId: getContractAbi
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: ABI details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ContractAbiResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Contract ABIs]
            summary: Delete a contract ABI
            operationId: deleteContractAbi
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: ABI deleted
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Pending Approvals (consensus policies)
    # ---------------------------------------------------------------------------

    /v1/pending-approvals:
        post:
            tags: [Pending Approvals]
            summary: Submit action for approval
            description: Submit a signing or transaction action that matches a consensus policy trigger.
            operationId: submitPendingApproval
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SubmitPendingApprovalRequest"
            responses:
                "202":
                    description: Approval required
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SubmitPendingApprovalResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        get:
            tags: [Pending Approvals]
            summary: List pending approvals
            operationId: listPendingApprovals
            security:
                - BearerAuth: []
            parameters:
                - name: status
                  in: query
                  schema:
                      type: string
                - name: agent_id
                  in: query
                  schema:
                      type: string
                      format: uuid
                - name: limit
                  in: query
                  schema:
                      type: integer
                      maximum: 100
                - name: offset
                  in: query
                  schema:
                      type: integer
            responses:
                "200":
                    description: Pending approvals list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PendingApprovalListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/pending-approvals/{id}:
        get:
            tags: [Pending Approvals]
            summary: Get pending approval details
            operationId: getPendingApproval
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Pending approval with signatures
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PendingApprovalResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/pending-approvals/{id}/approve:
        post:
            tags: [Pending Approvals]
            summary: Approve or reject a pending approval
            operationId: approvePendingApproval
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ApprovePendingApprovalRequest"
            responses:
                "200":
                    description: Updated pending approval
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PendingApprovalResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"
                "409":
                    $ref: "#/components/responses/Conflict"

    /v1/pending-approvals/{id}/execute:
        post:
            tags: [Pending Approvals]
            summary: Execute an approved action
            description: Human-only. Marks the approval as executed after verifying signatures.
            operationId: executePendingApproval
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Action executed
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ExecutePendingApprovalResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/pending-approvals/{id}/cancel:
        post:
            tags: [Pending Approvals]
            summary: Cancel a pending approval
            operationId: cancelPendingApproval
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Cancelled pending approval
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PendingApprovalResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Sub-Organizations
    # ---------------------------------------------------------------------------

    /v1/org/sub-orgs:
        post:
            tags: [Sub-Organizations]
            summary: Create a sub-organization
            description: Create a new sub-organization under the current org.
            operationId: createSubOrg
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateSubOrgRequest"
            responses:
                "201":
                    description: Sub-organization created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SubOrgResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [Sub-Organizations]
            summary: List sub-organizations
            description: List all sub-organizations under the current org.
            operationId: listSubOrgs
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Sub-organizations list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SubOrgListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/org/sub-orgs/{sub_org_id}:
        get:
            tags: [Sub-Organizations]
            summary: Get a sub-organization
            description: Retrieve a specific sub-organization by ID.
            operationId: getSubOrg
            security:
                - BearerAuth: []
            parameters:
                - name: sub_org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Sub-organization details
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SubOrgResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        patch:
            tags: [Sub-Organizations]
            summary: Update a sub-organization
            description: Update sub-organization name, description, or billing model.
            operationId: updateSubOrg
            security:
                - BearerAuth: []
            parameters:
                - name: sub_org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateSubOrgRequest"
            responses:
                "200":
                    description: Sub-organization updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/SubOrgResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"
        delete:
            tags: [Sub-Organizations]
            summary: Archive a sub-organization
            description: Archive (soft-delete) a sub-organization.
            operationId: deleteSubOrg
            security:
                - BearerAuth: []
            parameters:
                - name: sub_org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Sub-organization archived
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/org/sub-orgs/{sub_org_id}/users:
        post:
            tags: [Sub-Organizations]
            summary: Add a user to a sub-organization
            description: Add a user to a sub-organization with a specified role.
            operationId: addSubOrgUser
            security:
                - BearerAuth: []
            parameters:
                - name: sub_org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SubOrgAddUserRequest"
            responses:
                "201":
                    description: User added to sub-organization
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/org/sub-orgs/{sub_org_id}/permissions:
        post:
            tags: [Sub-Organizations]
            summary: Grant permissions to a sub-organization
            description: Grant a permission scope to the sub-organization.
            operationId: grantSubOrgPermission
            security:
                - BearerAuth: []
            parameters:
                - name: sub_org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SubOrgPermissionRequest"
            responses:
                "201":
                    description: Permission granted
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/org/sub-orgs/{sub_org_id}/permissions/{permission}:
        delete:
            tags: [Sub-Organizations]
            summary: Revoke a sub-organization permission
            description: Revoke a specific permission scope from the sub-organization.
            operationId: revokeSubOrgPermission
            security:
                - BearerAuth: []
            parameters:
                - name: sub_org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
                - name: permission
                  in: path
                  required: true
                  schema:
                      type: string
                  description: The permission scope to revoke
            responses:
                "204":
                    description: Permission revoked
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/org/sub-orgs/{sub_org_id}/wallets/generate:
        post:
            tags: [Sub-Organizations]
            summary: Generate wallets for a sub-organization
            description: Generate treasury wallets for specified chains within the sub-org.
            operationId: generateSubOrgWallets
            security:
                - BearerAuth: []
            parameters:
                - name: sub_org_id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            requestBody:
                required: false
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/SubOrgGenerateWalletsRequest"
            responses:
                "201":
                    description: Wallets generated
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Portfolio
    # ---------------------------------------------------------------------------

    /v1/portfolio:
        get:
            tags: [Portfolio]
            summary: Get unified portfolio
            description: |
                Returns an aggregated view of all wallet balances (treasury wallets,
                signing keys, smart accounts) with USD estimates.
            operationId: getPortfolio
            security:
                - BearerAuth: []
            parameters:
                - name: chains
                  in: query
                  required: false
                  schema:
                      type: string
                  description: Comma-separated list of chain names to filter by (e.g. "ethereum,solana")
                - name: include_tokens
                  in: query
                  required: false
                  schema:
                      type: boolean
                      default: false
                  description: Whether to include token balances alongside native balances
            responses:
                "200":
                    description: Portfolio summary
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/PortfolioResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    # ---------------------------------------------------------------------------
    # Smart Account Import
    # ---------------------------------------------------------------------------

    /v1/agents/{agent_id}/smart-accounts/import:
        post:
            tags: [Agents]
            summary: Import an existing Safe smart account
            description: |
                Import an existing Safe smart account for an agent. Optionally verifies
                on-chain that the agent's EOA is a signer on the Safe.
            operationId: importSmartAccount
            security:
                - BearerAuth: []
            parameters:
                - $ref: "#/components/parameters/AgentId"
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ImportSmartAccountRequest"
            responses:
                "201":
                    description: Smart account imported
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ImportSmartAccountResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    # ---------------------------------------------------------------------------
    # Wallet Access Policies
    # ---------------------------------------------------------------------------

    /v1/treasury/wallets/access-policies:
        post:
            tags: [Wallet Access]
            summary: Create a wallet access policy
            description: |
                Create a role-based wallet access policy granting an agent, user, role,
                or platform app specific permissions on treasury wallets within a scope
                (org-wide, platform app, or single wallet). Requires Pro+ tier.
            operationId: createWalletAccessPolicy
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CreateWalletAccessPolicyRequest"
            responses:
                "201":
                    description: Policy created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/WalletAccessPolicyResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
        get:
            tags: [Wallet Access]
            summary: List wallet access policies for the org
            operationId: listWalletAccessPolicies
            security:
                - BearerAuth: []
            parameters:
                - name: scope_type
                  in: query
                  schema:
                      type: string
                      enum: [wallet, platform_app, org]
                  description: Filter by scope type
                - name: scope_id
                  in: query
                  schema:
                      type: string
                      format: uuid
                  description: Filter by scope ID (wallet or platform app UUID)
            responses:
                "200":
                    description: Policy list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/WalletAccessPolicyListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/treasury/wallets/access-policies/{id}:
        delete:
            tags: [Wallet Access]
            summary: Delete a wallet access policy
            operationId: deleteWalletAccessPolicy
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Policy deleted
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Credential Recovery
    # ---------------------------------------------------------------------------

    /v1/auth/credential-recovery/request:
        post:
            tags: [Credential Recovery]
            summary: Initiate credential recovery
            description: |
                Start a credential recovery request for MFA reset, passkey reset,
                or password reset. Requires admin approval per org policy.
            operationId: requestCredentialRecovery
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CredentialRecoveryRequest"
            responses:
                "201":
                    description: Recovery request created
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CredentialRecoveryResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/auth/credential-recovery/requests:
        get:
            tags: [Credential Recovery]
            summary: List recovery requests for the org
            description: Admin/owner only. Returns pending, approved, and rejected recovery requests.
            operationId: listCredentialRecoveryRequests
            security:
                - BearerAuth: []
            parameters:
                - name: status
                  in: query
                  schema:
                      type: string
                      enum: [pending_approval, approved, rejected, expired]
                  description: Filter by status
            responses:
                "200":
                    description: Recovery request list
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CredentialRecoveryListResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/auth/credential-recovery/requests/{id}/approve:
        post:
            tags: [Credential Recovery]
            summary: Approve a recovery request
            description: Admin/owner approves a pending recovery request. May return a one-time recovery code.
            operationId: approveCredentialRecovery
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Request approved
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CredentialRecoveryApproveResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/auth/credential-recovery/requests/{id}/execute:
        post:
            tags: [Credential Recovery]
            summary: Execute an approved credential recovery request
            description: >-
                Execute an approved credential recovery request after the delay
                window has elapsed. Only org owners or admins can execute.
            operationId: executeCredentialRecovery
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "200":
                    description: Recovery executed
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CredentialRecoveryExecuteResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    /v1/auth/credential-recovery/requests/{id}:
        delete:
            tags: [Credential Recovery]
            summary: Cancel or reject a recovery request
            operationId: cancelCredentialRecovery
            security:
                - BearerAuth: []
            parameters:
                - name: id
                  in: path
                  required: true
                  schema:
                      type: string
                      format: uuid
            responses:
                "204":
                    description: Request cancelled
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "404":
                    $ref: "#/components/responses/NotFound"

    # ---------------------------------------------------------------------------
    # Org Credential Recovery Policy
    # ---------------------------------------------------------------------------

    /v1/org/credential-recovery-policy:
        get:
            tags: [Credential Recovery]
            summary: Get org credential recovery policy
            operationId: getCredentialRecoveryPolicy
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Recovery policy
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CredentialRecoveryPolicyResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
        patch:
            tags: [Credential Recovery]
            summary: Update org credential recovery policy
            operationId: updateCredentialRecoveryPolicy
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/CredentialRecoveryPolicyRequest"
            responses:
                "200":
                    description: Policy updated
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/CredentialRecoveryPolicyResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    # ---------------------------------------------------------------------------
    # Shamir KEK
    # ---------------------------------------------------------------------------

    /v1/org/shamir-kek/setup:
        post:
            tags: [Shamir KEK]
            summary: Set up Shamir KEK for the org
            description: |
                Initialize a Shamir secret-sharing KEK for the org. Splits the master
                key into shares distributed to custodians. Shares are returned one-time
                only and must be stored securely by each custodian.
            operationId: setupShamirKek
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ShamirKekSetupRequest"
            responses:
                "201":
                    description: Shamir KEK configured (shares returned one-time)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShamirKekSetupResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/org/shamir-kek:
        get:
            tags: [Shamir KEK]
            summary: Get Shamir KEK status
            description: Returns the current Shamir KEK configuration status for the org.
            operationId: getShamirKekStatus
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Shamir KEK status
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShamirKekStatusResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /v1/org/shamir-kek/reconstruct:
        post:
            tags: [Shamir KEK]
            summary: Reconstruct KEK from shares
            description: |
                Submit Shamir shares to reconstruct the org KEK. Requires at least
                `threshold` valid shares. Used during disaster recovery.
            operationId: reconstructShamirKek
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ShamirKekReconstructRequest"
            responses:
                "200":
                    description: Reconstruction result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShamirKekReconstructResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"

    /v1/org/shamir-kek/recovery-codes:
        get:
            tags: [Shamir KEK]
            summary: Get Shamir recovery codes (one-time)
            description: |
                Returns the one-time recovery codes for the Shamir KEK. These codes
                can be used as an emergency fallback if custodian shares are lost.
                Codes are only returned once — subsequent calls return 410.
            operationId: getShamirKekRecoveryCodes
            security:
                - BearerAuth: []
            responses:
                "200":
                    description: Recovery codes (one-time)
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShamirKekRecoveryCodesResponse"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "403":
                    $ref: "#/components/responses/Forbidden"
                "410":
                    description: Codes already retrieved

    /v1/org/shamir-kek/verify-recovery-code:
        post:
            tags: [Shamir KEK]
            summary: Verify a Shamir recovery code
            description: Check whether a recovery code is valid without consuming it.
            operationId: verifyShamirKekRecoveryCode
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ShamirKekVerifyCodeRequest"
            responses:
                "200":
                    description: Verification result
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ShamirKekVerifyCodeResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

# =============================================================================
# COMPONENTS
# =============================================================================

components:
    securitySchemes:
        BearerAuth:
            type: http
            scheme: bearer
            bearerFormat: JWT
        ApiKeyAuth:
            type: http
            scheme: bearer
            description: 1ck_ prefixed API key used as Bearer token

    parameters:
        VaultId:
            name: vault_id
            in: path
            required: true
            schema:
                type: string
                format: uuid
        SecretPath:
            name: path
            in: path
            required: true
            schema:
                type: string
            description: Secret path (e.g. "db/credentials")
        AgentId:
            name: agent_id
            in: path
            required: true
            schema:
                type: string
                format: uuid
        PolicyId:
            name: policy_id
            in: path
            required: true
            schema:
                type: string
                format: uuid
        CardId:
            name: card_id
            in: path
            required: true
            schema:
                type: string
                format: uuid
        IncludeSignedTx:
            name: include_signed_tx
            in: query
            required: false
            description: >
                Set to `true` or `1` to include the raw signed transaction hex in the response.
                Omitted by default to reduce key exfiltration risk. Only the literal values "true" or "1" enable inclusion; any other value or omission returns responses without signed_tx.
                Applies to GET /v1/agents/{agent_id}/transactions and GET /v1/agents/{agent_id}/transactions/{tx_id}.
            schema:
                type: boolean
                default: false
                example: false

    responses:
        BadRequest:
            description: Invalid request
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ProblemDetails"
        Unauthorized:
            description: Authentication required or invalid
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ProblemDetails"
        Forbidden:
            description: Insufficient permissions
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ProblemDetails"
        NotFound:
            description: Resource not found
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ProblemDetails"
        PaymentRequired:
            description: x402 payment required
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/PaymentRequirement"
        Conflict:
            description: Resource already exists or conflict
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ProblemDetails"

    schemas:
        OrderCardRequest:
            type: object
            required: [kind, amount_usd]
            properties:
                kind:
                    type: string
                    enum: [prepaid, gift_card]
                amount_usd:
                    type: string
                    description: USD amount to load onto the card.
                    example: "25.00"
                laso_server_id:
                    type: string
                    description: Optional Laso gift-card server/brand id (gift cards only).
                country:
                    type: string
                    description: Optional country (prepaid cards; defaults to US).
        CardResponse:
            type: object
            description: Masked card view — never contains PAN/CVV.
            required: [id, issuer, kind, currency, status, storage_mode, reveal_policy, created_at, updated_at]
            properties:
                id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                    nullable: true
                issuer:
                    type: string
                    enum: [laso, manual]
                kind:
                    type: string
                    enum: [prepaid, gift_card]
                brand:
                    type: string
                last4:
                    type: string
                exp_month:
                    type: integer
                exp_year:
                    type: integer
                currency:
                    type: string
                order_amount_usd:
                    type: string
                balance:
                    type: string
                status:
                    type: string
                    enum: [ordering, pending, ready, depleted, expired, voided, orphaned_payment, awaiting_approval, rejected]
                storage_mode:
                    type: string
                    enum: [reference, full]
                reveal_policy:
                    type: object
                    additionalProperties: true
                approval_id:
                    type: string
                    format: uuid
                    description: Linked approval when status is awaiting_approval
                void_after:
                    type: string
                    format: date-time
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time
        CardListResponse:
            type: object
            required: [cards]
            properties:
                cards:
                    type: array
                    items:
                        $ref: "#/components/schemas/CardResponse"
        CardRevealResponse:
            type: object
            description: Revealed card details — sensitive. Returned only by the reveal endpoint.
            required: [id, disclaimer]
            properties:
                id:
                    type: string
                    format: uuid
                pan:
                    type: string
                cvv:
                    type: string
                exp_month:
                    type: integer
                exp_year:
                    type: integer
                brand:
                    type: string
                redemption:
                    type: object
                    additionalProperties: true
                    description: Gift-card redemption payload (URL/code/PIN) when applicable.
                disclaimer:
                    type: string
        UpdateCardRequest:
            type: object
            description: Human-settable per-card reveal policy + lifecycle controls.
            properties:
                agent_reveal:
                    type: boolean
                max_reveals:
                    type: integer
                reveal_expires_at:
                    type: string
                    format: date-time
                    nullable: true
                void_after:
                    type: string
                    format: date-time
                    nullable: true
        ImportCardRequest:
            type: object
            required: [pan, cvv, exp_month, exp_year]
            properties:
                pan:
                    type: string
                cvv:
                    type: string
                exp_month:
                    type: integer
                exp_year:
                    type: integer
                brand:
                    type: string
                currency:
                    type: string
                balance:
                    type: string
                agent_id:
                    type: string
                    format: uuid
        SearchGiftCardsRequest:
            type: object
            properties:
                query:
                    type: string
                country:
                    type: string
        ProblemDetails:
            type: object
            description: RFC 7807 error envelope
            properties:
                type:
                    type: string
                title:
                    type: string
                status:
                    type: integer
                detail:
                    type: string

        ResetUsageEventsResponse:
            type: object
            required: [deleted_events]
            properties:
                deleted_events:
                    type: integer
                    format: int64
                    description: Number of usage_events rows removed

        ResetUsageForUserEmailRequest:
            type: object
            required: [email]
            properties:
                email:
                    type: string
                    format: email

        ResetUsageForUserEmailResponse:
            type: object
            required:
                [deleted_events, org_id, user_id, email, display_name]
            properties:
                deleted_events:
                    type: integer
                    format: int64
                org_id:
                    type: string
                    format: uuid
                user_id:
                    type: string
                    format: uuid
                email:
                    type: string
                display_name:
                    type: string

        # --- Auth ---

        LoginRequest:
            type: object
            required: [email, password]
            properties:
                email:
                    type: string
                    format: email
                password:
                    type: string
                    format: password

        LoginResponse:
            type: object
            properties:
                access_token:
                    type: string
                token_type:
                    type: string
                expires_in:
                    type: integer
                refresh_token:
                    type: string
                mfa_required:
                    type: boolean
                mfa_token:
                    type: string
                mfa_method:
                    type: string
                    enum: [totp, passkey]
                    description: When MFA is required, which second factor to collect

        TokenResponse:
            type: object
            required: [access_token, token_type]
            properties:
                access_token:
                    type: string
                token_type:
                    type: string
                expires_in:
                    type: integer
                refresh_token:
                    type: string
                mfa_required:
                    type: boolean
                mfa_token:
                    type: string
                mfa_method:
                    type: string
                    enum: [totp, passkey]

        AgentTokenRequest:
            type: object
            required: [api_key]
            properties:
                agent_id:
                    type: string
                    format: uuid
                    description: Optional when using key-only auth (ocv_ keys auto-resolve agent)
                api_key:
                    type: string

        UserApiKeyTokenRequest:
            type: object
            required: [api_key]
            properties:
                api_key:
                    type: string

        TokenExchangeRequest:
            type: object
            required: [grant_type, subject_token, subject_token_type, audience]
            description: |
                RFC 8693 token-exchange request body. `subject_token_type`
                accepts the standard JWT URI or 1claw's API-key URI:
                  - `urn:ietf:params:oauth:token-type:jwt`
                  - `urn:1claw:params:oauth:token-type:api-key`
            properties:
                grant_type:
                    type: string
                    enum:
                        - "urn:ietf:params:oauth:grant-type:token-exchange"
                subject_token:
                    type: string
                    description: 1claw JWT or `ocv_` API key authorising the exchange.
                subject_token_type:
                    type: string
                    enum:
                        - "urn:ietf:params:oauth:token-type:jwt"
                        - "urn:1claw:params:oauth:token-type:api-key"
                audience:
                    type: string
                    format: uri
                    description: Required `aud` claim for the issued federation token (must be in agent's allowlist).
                    example: "https://api.anthropic.com"
                scope:
                    type: string
                    description: Optional space-separated subset of the agent's existing scopes.
                requested_token_type:
                    type: string
                    description: Optional. Defaults to `urn:ietf:params:oauth:token-type:jwt`.

        TokenExchangeResponse:
            type: object
            required: [access_token, issued_token_type, token_type, expires_in]
            properties:
                access_token:
                    type: string
                    description: RS256-signed federation JWT.
                issued_token_type:
                    type: string
                token_type:
                    type: string
                expires_in:
                    type: integer
                scope:
                    type: string

        SignupRequest:
            type: object
            required: [email, password]
            properties:
                email:
                    type: string
                    format: email
                password:
                    type: string
                    format: password
                display_name:
                    type: string

        SignupResponse:
            type: object
            properties:
                message:
                    type: string
                email:
                    type: string
                access_token:
                    type: string
                token_type:
                    type: string

        GoogleAuthRequest:
            type: object
            required: [id_token]
            properties:
                id_token:
                    type: string

        ChangePasswordRequest:
            type: object
            required: [current_password, new_password]
            properties:
                current_password:
                    type: string
                new_password:
                    type: string

        ForgotPasswordRequest:
            type: object
            required: [email]
            properties:
                email:
                    type: string
                    format: email

        ForgotPasswordResponse:
            type: object
            required: [message, status]
            properties:
                message:
                    type: string
                status:
                    type: string
                    enum: [email_sent, no_account, social_account, invalid]
                    description: |
                        Outcome of the reset request:
                        - email_sent: password reset email dispatched
                        - no_account: no account found for the email
                        - social_account: account uses Google/SSO sign-in
                        - invalid: request was malformed

        ResetPasswordRequest:
            type: object
            required: [token, new_password]
            properties:
                token:
                    type: string
                new_password:
                    type: string

        ResetPasswordResponse:
            type: object
            properties:
                message:
                    type: string

        # --- MFA ---

        MfaStatusResponse:
            type: object
            properties:
                enabled:
                    type: boolean
                eligible:
                    type: boolean
                totp_enabled:
                    type: boolean
                passkey_mfa_enabled:
                    type: boolean

        MfaSetupResponse:
            type: object
            properties:
                otpauth_uri:
                    type: string
                secret:
                    type: string

        MfaVerifySetupRequest:
            type: object
            required: [code]
            properties:
                code:
                    type: string

        MfaVerifySetupResponse:
            type: object
            properties:
                recovery_codes:
                    type: array
                    items:
                        type: string

        MfaVerifyRequest:
            type: object
            required: [code, mfa_token]
            properties:
                code:
                    type: string
                mfa_token:
                    type: string

        MfaDisableRequest:
            type: object
            properties:
                code:
                    type: string
                    description: TOTP or recovery code
                password:
                    type: string
                    description: Deprecated. Password is no longer sufficient to disable MFA.
                    deprecated: true

        # --- Device Auth ---

        DeviceCodeRequest:
            type: object
            required: [client_id, email]
            properties:
                client_id:
                    type: string
                email:
                    type: string
                    format: email
                    description: Account email; only that user may approve the code in the dashboard.

        DeviceCodeResponse:
            type: object
            properties:
                device_code:
                    type: string
                user_code:
                    type: string
                verification_uri:
                    type: string
                    format: uri
                expires_in:
                    type: integer
                interval:
                    type: integer

        DeviceTokenRequest:
            type: object
            required: [device_code, grant_type]
            properties:
                device_code:
                    type: string
                grant_type:
                    type: string

        DeviceTokenResponse:
            type: object
            properties:
                access_token:
                    type: string
                token_type:
                    type: string
                expires_in:
                    type: integer
                error:
                    type: string
                email:
                    type: string
                user_id:
                    type: string
                org_id:
                    type: string

        DeviceApproveRequest:
            type: object
            required: [user_code]
            properties:
                user_code:
                    type: string

        UserProfileResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                email:
                    type: string
                display_name:
                    type: string
                auth_method:
                    type: string
                role:
                    type: string
                email_verified:
                    type: boolean
                marketing_emails:
                    type: boolean
                totp_enabled:
                    type: boolean
                created_at:
                    type: string
                    format: date-time

        UpdateProfileRequest:
            type: object
            properties:
                display_name:
                    type: string
                marketing_emails:
                    type: boolean

        # --- API Keys ---

        CreateApiKeyRequest:
            type: object
            required: [name]
            properties:
                name:
                    type: string
                scopes:
                    type: array
                    items:
                        type: string
                expires_at:
                    type: string
                    format: date-time

        ApiKeyResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                key_prefix:
                    type: string
                scopes:
                    type: array
                    items:
                        type: string
                is_active:
                    type: boolean
                created_at:
                    type: string
                    format: date-time
                expires_at:
                    type: string
                    format: date-time
                last_used_at:
                    type: string
                    format: date-time

        ApiKeyCreatedResponse:
            type: object
            properties:
                key:
                    $ref: "#/components/schemas/ApiKeyResponse"
                api_key:
                    type: string
                    description: Full key (shown once)

        ApiKeyListResponse:
            type: object
            properties:
                keys:
                    type: array
                    items:
                        $ref: "#/components/schemas/ApiKeyResponse"

        # --- Vaults ---

        CreateVaultRequest:
            type: object
            required: [name]
            properties:
                name:
                    type: string
                description:
                    type: string
                mpc_custody:
                    type: string
                    description: MPC custody mode to enable at creation (e.g. "2-of-2", "2-of-3")

        VaultResponse:
            type: object
            required: [id, name, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                description:
                    type: string
                created_by:
                    type: string
                created_by_type:
                    type: string
                created_at:
                    type: string
                    format: date-time
                cmek_enabled:
                    type: boolean
                    description: Whether client-managed encryption is enabled
                cmek_fingerprint:
                    type: string
                    description: SHA-256 fingerprint of the CMEK key (64 hex chars)
                mpc_custody:
                    type: string
                    description: MPC custody mode (e.g. "2-of-2", "2-of-3"), absent when MPC is not enabled
                mpc_threshold:
                    type: integer
                    description: Number of shares required to reconstruct the key
                mpc_providers:
                    type: array
                    items:
                        type: string
                    description: List of MPC share providers (e.g. ["server", "client"])

        VaultListResponse:
            type: object
            properties:
                vaults:
                    type: array
                    items:
                        $ref: "#/components/schemas/VaultResponse"

        # --- CMEK ---

        EnableCmekRequest:
            type: object
            required: [fingerprint]
            properties:
                fingerprint:
                    type: string
                    description: SHA-256 hex fingerprint of the CMEK key (64 chars)

        CmekRotateRequest:
            type: object
            required: [new_fingerprint]
            properties:
                new_fingerprint:
                    type: string
                    description: SHA-256 hex fingerprint of the new CMEK key

        CmekRotationJobResponse:
            type: object
            required:
                [id, vault_id, status, total_secrets, processed, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                vault_id:
                    type: string
                    format: uuid
                old_fingerprint:
                    type: string
                new_fingerprint:
                    type: string
                status:
                    type: string
                    enum: [pending, running, completed, failed]
                total_secrets:
                    type: integer
                processed:
                    type: integer
                error:
                    type: string
                started_at:
                    type: string
                    format: date-time
                completed_at:
                    type: string
                    format: date-time
                created_at:
                    type: string
                    format: date-time

        # --- MPC ---

        EnableMpcRequest:
            type: object
            required: [mpc_custody]
            properties:
                mpc_custody:
                    type: string
                    description: MPC custody mode (e.g. "2-of-2", "2-of-3")

        # --- Secrets ---

        PutSecretRequest:
            type: object
            required: [value]
            properties:
                type:
                    type: string
                    description: Secret type (generic, password, api_key, certificate, private_key, ssh_key, env)
                    default: generic
                value:
                    type: string
                metadata:
                    type: object
                    additionalProperties: true
                expires_at:
                    type: string
                    format: date-time
                rotation_policy:
                    type: object
                    additionalProperties: true
                max_access_count:
                    type: integer

        SecretMetadataResponse:
            type: object
            required: [id, path, type, version, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                path:
                    type: string
                type:
                    type: string
                version:
                    type: integer
                metadata:
                    type: object
                    additionalProperties: true
                created_at:
                    type: string
                    format: date-time
                expires_at:
                    type: string
                    format: date-time
                is_disabled:
                    type: boolean
                    description: Whether this version has been disabled (retained for audit but unreadable)

        SecretCreatedResponse:
            description: Returned when a secret is created or updated. Extends SecretMetadataResponse with an optional client_share for MPC vaults.
            type: object
            required: [id, path, type, version, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                path:
                    type: string
                type:
                    type: string
                version:
                    type: integer
                metadata:
                    type: object
                    additionalProperties: true
                created_at:
                    type: string
                    format: date-time
                expires_at:
                    type: string
                    format: date-time
                client_share:
                    type: string
                    description: Base64-encoded client key share. Returned only for MPC 2-of-2 vaults. The client must store this share securely — it is not persisted server-side.

        SecretResponse:
            type: object
            required: [id, path, type, value, version, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                path:
                    type: string
                type:
                    type: string
                value:
                    type: string
                version:
                    type: integer
                metadata:
                    type: object
                    additionalProperties: true
                created_by:
                    type: string
                created_at:
                    type: string
                    format: date-time
                expires_at:
                    type: string
                    format: date-time
                cmek_encrypted:
                    type: boolean
                    description: Whether this secret value is CMEK-encrypted (requires client-side decryption)

        SecretListResponse:
            type: object
            properties:
                secrets:
                    type: array
                    items:
                        $ref: "#/components/schemas/SecretMetadataResponse"

        SecretVersionListResponse:
            type: object
            properties:
                versions:
                    type: array
                    items:
                        $ref: "#/components/schemas/SecretMetadataResponse"

        RotateSecretRequest:
            type: object
            properties:
                length:
                    type: integer
                    minimum: 8
                    maximum: 1024
                    description: Length of the generated value (default 32)
                charset:
                    type: string
                    enum: [hex, base64, alphanumeric, ascii]
                    description: Character set for the generated value (default hex)
                type:
                    type: string
                    description: Override the secret type (defaults to existing secret's type)

        # --- Policies ---

        CreatePolicyRequest:
            type: object
            required:
                [secret_path_pattern, principal_type, principal_id, permissions]
            properties:
                secret_path_pattern:
                    type: string
                principal_type:
                    type: string
                    enum: [user, agent]
                principal_id:
                    type: string
                permissions:
                    type: array
                    items:
                        type: string
                conditions:
                    type: object
                    additionalProperties: true
                expires_at:
                    type: string
                    format: date-time
                effect:
                    type: string
                    enum: [allow, deny]
                    default: allow
                priority:
                    type: integer
                    minimum: 0
                    default: 0
                attribute_conditions:
                    type: object
                    additionalProperties: true
                consensus_trigger:
                    $ref: "#/components/schemas/ConsensusTrigger"
                tx_conditions:
                    $ref: "#/components/schemas/TxConditions"
                approval_id:
                    type: string
                    format: uuid
                    description: >
                        Optional completed approval ID for control-plane consensus bypass.
                        When control-plane consensus policies match, resubmit with this
                        field after the approval has been executed.
                policy_schema_version:
                    type: integer
                    default: 2
                    description: |
                        Policy schema version. Version 1 = legacy field-matching only.
                        Version 2 = expression engine support in tx_conditions.

        UpdatePolicyRequest:
            type: object
            properties:
                permissions:
                    type: array
                    items:
                        type: string
                conditions:
                    type: object
                    additionalProperties: true
                expires_at:
                    type: string
                    format: date-time
                effect:
                    type: string
                    enum: [allow, deny]
                    default: allow
                priority:
                    type: integer
                    minimum: 0
                    default: 0
                attribute_conditions:
                    type: object
                    additionalProperties: true
                consensus_trigger:
                    $ref: "#/components/schemas/ConsensusTrigger"
                tx_conditions:
                    $ref: "#/components/schemas/TxConditions"
                approval_id:
                    type: string
                    format: uuid
                    description: >
                        Optional completed approval ID for control-plane consensus bypass.

        PolicyResponse:
            type: object
            required:
                [
                    id,
                    vault_id,
                    secret_path_pattern,
                    principal_type,
                    principal_id,
                    permissions,
                    created_at,
                ]
            properties:
                id:
                    type: string
                    format: uuid
                vault_id:
                    type: string
                    format: uuid
                secret_path_pattern:
                    type: string
                principal_type:
                    type: string
                principal_id:
                    type: string
                permissions:
                    type: array
                    items:
                        type: string
                conditions:
                    type: object
                    additionalProperties: true
                expires_at:
                    type: string
                    format: date-time
                created_by:
                    type: string
                created_by_type:
                    type: string
                created_at:
                    type: string
                    format: date-time
                effect:
                    type: string
                    enum: [allow, deny]
                    default: allow
                priority:
                    type: integer
                    minimum: 0
                    default: 0
                attribute_conditions:
                    type: object
                    additionalProperties: true
                consensus_trigger:
                    $ref: "#/components/schemas/ConsensusTrigger"
                tx_conditions:
                    $ref: "#/components/schemas/TxConditions"
                policy_schema_version:
                    type: integer
                    description: Policy schema version (1 = legacy, 2 = expression engine)

        PolicyListResponse:
            type: object
            properties:
                policies:
                    type: array
                    items:
                        $ref: "#/components/schemas/PolicyResponse"

        # --- Agent Enrollment ---

        EnrollAgentRequest:
            type: object
            required: [name]
            properties:
                name:
                    type: string
                    description: Display name for the new agent
                human_email:
                    type: string
                    format: email
                    description: |
                        Optional. If set, pending enrollment is bound to that 1Claw account email
                        and Allow/Deny links are emailed. If omitted, only `approval_url` is used
                        (link-only enrollment; human must open the URL while signed in).
                description:
                    type: string
                    description: Optional agent description

        EnrollAgentResponse:
            type: object
            properties:
                agent_id:
                    type: string
                    format: uuid
                    description: UUID of the created agent (nil UUID until approved — uniform response)
                message:
                    type: string
                    description: Status message (worded to limit email enumeration where applicable)
                approval_url:
                    type: string
                    format: uri
                    description: |
                        Present when a pending enrollment was created and the client should show
                        this link (email flow includes it as a fallback; name-only flow requires it).

        # --- Agents ---

        CreateAgentRequest:
            type: object
            required: [name]
            properties:
                name:
                    type: string
                description:
                    type: string
                auth_method:
                    type: string
                    enum: [api_key, mtls, oidc_client_credentials]
                    default: api_key
                    description: Authentication method. api_key generates a one-time key; mtls requires client_cert_fingerprint; oidc_client_credentials requires oidc_issuer and oidc_client_id.
                scopes:
                    type: array
                    items:
                        type: string
                expires_at:
                    type: string
                    format: date-time
                intents_api_enabled:
                    type: boolean
                    default: false
                tx_to_allowlist:
                    type: array
                    items:
                        type: string
                tx_max_value:
                    type: string
                    description: Maximum value per transaction in native major units for the transacting chain family (ETH on EVM, BTC on Bitcoin, SOL on Solana, XRP, ADA, TRX).
                tx_daily_limit:
                    type: string
                    description: Rolling daily spend cap in native major units, enforced per chain family at signing time.
                tx_max_value_eth:
                    type: string
                    deprecated: true
                    description: Deprecated alias for tx_max_value. Same unit semantics (native major units, not ETH-only).
                tx_daily_limit_eth:
                    type: string
                    deprecated: true
                    description: Deprecated alias for tx_daily_limit.
                tx_allowed_chains:
                    type: array
                    items:
                        type: string
                token_ttl_seconds:
                    type: integer
                    nullable: true
                    description: Per-agent token TTL in seconds (overrides global default)
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                    description: Restrict agent to specific vault UUIDs (empty = all vaults in org)
                client_cert_fingerprint:
                    type: string
                    description: SHA-256 fingerprint of the client certificate (required for mTLS auth)
                oidc_issuer:
                    type: string
                    description: OIDC issuer URL (required for oidc_client_credentials auth)
                oidc_client_id:
                    type: string
                    description: OIDC client ID (required for oidc_client_credentials auth)
                shroud_enabled:
                    type: boolean
                    default: false
                    description: Enable Shroud LLM Proxy for this agent
                shroud_config:
                    $ref: "#/components/schemas/ShroudConfig"
                execution_intents_enabled:
                    type: boolean
                    default: false
                    description: Enable Execution Intents (bindings and execute endpoint) for this agent
                execution_guardrails:
                    type: object
                    additionalProperties: true
                    description: Guardrails applied to all execution intents for this agent
                intents_require_tee:
                    type: boolean
                    default: false
                    description: When true, transaction/sign requests must arrive via a TEE host (Pro+ only)
                execution_require_tee:
                    type: boolean
                    default: false
                    description: When true, execute requests must arrive via TEE and all direct secret reads are blocked (Pro+ only)
                tx_token_allowlist:
                    type: array
                    items:
                        type: string
                    description: Token contract/mint addresses this agent may interact with. Empty = unrestricted.
                tx_known_tokens_only:
                    type: boolean
                    default: false
                    description: When true, only tokens in the known_tokens registry may be used.
                xrpl_allowed_tx_types:
                    type: array
                    items:
                        type: string
                    description: Allowed XRP Ledger transaction types (Payment, TrustSet, etc.). Empty = all allowed.
                per_chain_guardrails:
                    type: object
                    additionalProperties: true
                    description: |
                        Per-chain guardrail overrides. Keys are signing chains (ethereum, bitcoin, solana, xrp, cardano, tron).
                        Each value may include max_value, daily_limit, to_allowlist, token_allowlist, max_per_day,
                        overhead_budget, max_ata_creates_per_day, max_fee_per_gas_gwei, max_gas_limit,
                        gas_daily_budget_native (UTC-day cumulative EVM gas estimate in native units).
                        Strictest of global and per-chain limits wins. Daily limits apply per chain family spend, not cross-chain totals.
                tx_max_per_day:
                    type: integer
                    nullable: true
                    description: Max transactions per UTC calendar day. Null = unlimited.
                tx_overhead_budget:
                    type: object
                    nullable: true
                    additionalProperties:
                        type: string
                    description: Per-chain daily overhead budget in native units (e.g. {"solana":"0.5","xrp":"100"}).
                solana_ata_allowlist:
                    type: array
                    items:
                        type: string
                    description: Solana wallet addresses whose ATAs may be created. Empty = unrestricted.
                cards_enabled:
                    type: boolean
                    description: Whether this agent may order payment cards (x402 card ordering). Pro+ tier.
                card_max_order_usd:
                    type: string
                    description: Maximum USD amount for a single card order.
                card_daily_limit_usd:
                    type: string
                    description: Maximum cumulative USD spent ordering cards per rolling 24h window.
                card_payto_allowlist:
                    type: array
                    items:
                        type: string
                    description: Allowed x402 payTo recipients for card orders (empty = built-in Laso recipients).
                card_reveal_enabled:
                    type: boolean
                    description: Whether agents may reveal card details subject to per-card reveal policy.
                card_require_approval:
                    type: boolean
                    default: true
                    description: When true, card orders route through the human approval queue before x402 payment.
                tx_approval_policy:
                    type: object
                    additionalProperties: true
                    nullable: true
                    description: Graduated transaction approval policy (HITL thresholds). Separate from hard guardrails.
                typed_data_policy:
                    type: string
                    enum: [deny, approve]
                    description: EIP-712 escalation when typed_data matches no allowlist — deny (403) or route to HITL (approve).
                simulation_failure_policy:
                    type: string
                    enum: [deny, approve]
                    description: Simulation failure escalation — deny (422) or route to HITL (approve).
                tx_block_unlimited_approvals:
                    type: boolean
                    default: false
                    description: Block unlimited ERC-20 approvals (max uint256 / setApprovalForAll).
                tx_per_recipient_max_per_day:
                    type: integer
                    nullable: true
                    description: Max transactions to the same recipient address per UTC day.
                tx_per_recipient_daily_limit:
                    type: string
                    nullable: true
                    description: Max native-unit spend to the same recipient per UTC day.
                new_recipient_cap_native:
                    type: string
                    nullable: true
                    description: Cap on first-time recipient spend in native units.
                tx_max_value_usd:
                    type: string
                    nullable: true
                    description: Per-transaction USD cap (requires price oracle).
                tx_daily_limit_usd:
                    type: string
                    nullable: true
                    description: Rolling 24h USD spend cap (requires price oracle).
                raw_signing_policy:
                    type: string
                    enum: [allow, deny, approve]
                    default: allow
                    description: Raw digest signing policy — allow, deny, or route to HITL (approve).
                personal_sign_policy:
                    type: object
                    additionalProperties: true
                    description: personal_sign guardrails (message allowlist, max bytes, etc.).
                allow_erc4337:
                    type: boolean
                    default: false
                    description: Allow ERC-4337 gasless UserOperations.
                allow_eip7702:
                    type: boolean
                    default: false
                    description: Allow EIP-7702 (tx type 4) set-code transactions.
                api_key_expires_at:
                    type: string
                    format: date-time
                    nullable: true
                    description: Optional expiration time for the agent's API key.
                environment:
                    type: string
                    description: Named environment for this agent (production, preview, development, or custom).
                environment_locked:
                    type: boolean
                    default: false
                    description: When true, the environment tag cannot be changed after creation.
                env_auto_resolve:
                    type: boolean
                    default: false
                    description: When true, env var resolve endpoints auto-fill environment from this agent's tag.
                approval_id:
                    type: string
                    format: uuid
                    description: >
                        Optional completed approval ID for control-plane consensus bypass
                        when creating an agent under a control-plane governance policy.

        UpdateAgentRequest:
            type: object
            properties:
                name:
                    type: string
                scopes:
                    type: array
                    items:
                        type: string
                is_active:
                    type: boolean
                expires_at:
                    type: string
                    format: date-time
                intents_api_enabled:
                    type: boolean
                tx_to_allowlist:
                    type: array
                    items:
                        type: string
                tx_max_value:
                    type: string
                    description: Maximum value per transaction in native major units for the transacting chain family (ETH on EVM, BTC on Bitcoin, SOL on Solana, XRP, ADA, TRX).
                tx_daily_limit:
                    type: string
                    description: Rolling daily spend cap in native major units, enforced per chain family at signing time.
                tx_max_value_eth:
                    type: string
                    deprecated: true
                    description: Deprecated alias for tx_max_value. Same unit semantics (native major units, not ETH-only).
                tx_daily_limit_eth:
                    type: string
                    deprecated: true
                    description: Deprecated alias for tx_daily_limit.
                tx_allowed_chains:
                    type: array
                    items:
                        type: string
                token_ttl_seconds:
                    type: integer
                    nullable: true
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                shroud_enabled:
                    type: boolean
                    description: Enable/disable Shroud LLM Proxy
                shroud_config:
                    $ref: "#/components/schemas/ShroudConfig"
                execution_intents_enabled:
                    type: boolean
                    description: Enable/disable Execution Intents for this agent
                execution_guardrails:
                    type: object
                    additionalProperties: true
                    description: Guardrails applied to all execution intents for this agent
                intents_require_tee:
                    type: boolean
                    description: When true, transaction/sign requests must arrive via a TEE host (Pro+ only)
                execution_require_tee:
                    type: boolean
                    description: When true, execute requests must arrive via TEE and all direct secret reads are blocked (Pro+ only)
                tx_max_per_day:
                    type: integer
                    nullable: true
                    description: Max transactions per UTC calendar day. Null = unlimited.
                tx_overhead_budget:
                    type: object
                    nullable: true
                    additionalProperties:
                        type: string
                    description: Per-chain daily overhead budget in native units.
                solana_ata_allowlist:
                    type: array
                    items:
                        type: string
                    description: Solana wallet addresses whose ATAs may be created.
                cards_enabled:
                    type: boolean
                    description: Whether this agent may order payment cards (x402 card ordering). Pro+ tier.
                card_max_order_usd:
                    type: string
                    nullable: true
                    description: Maximum USD amount for a single card order. null clears.
                card_daily_limit_usd:
                    type: string
                    nullable: true
                    description: Maximum cumulative USD spent ordering cards per rolling 24h window. null clears.
                card_payto_allowlist:
                    type: array
                    items:
                        type: string
                    description: Allowed x402 payTo recipients for card orders (empty = built-in Laso recipients).
                card_reveal_enabled:
                    type: boolean
                    description: Whether agents may reveal card details subject to per-card reveal policy.
                card_require_approval:
                    type: boolean
                    description: When true, card orders route through the human approval queue before x402 payment.
                tx_approval_policy:
                    type: object
                    additionalProperties: true
                    nullable: true
                    description: Graduated transaction approval policy (HITL thresholds).
                typed_data_policy:
                    type: string
                    enum: [deny, approve]
                    nullable: true
                    description: EIP-712 escalation policy.
                simulation_failure_policy:
                    type: string
                    enum: [deny, approve]
                    nullable: true
                    description: Simulation failure escalation policy.
                tx_block_unlimited_approvals:
                    type: boolean
                    description: Block unlimited ERC-20 approvals (max uint256 / setApprovalForAll).
                tx_per_recipient_max_per_day:
                    type: integer
                    nullable: true
                    description: Max transactions to the same recipient per UTC day. Null clears.
                tx_per_recipient_daily_limit:
                    type: string
                    nullable: true
                    description: Max native spend to same recipient per UTC day. Null clears.
                new_recipient_cap_native:
                    type: string
                    nullable: true
                    description: First-time recipient native cap. Null clears.
                tx_max_value_usd:
                    type: string
                    nullable: true
                    description: Per-tx USD cap. Null clears.
                tx_daily_limit_usd:
                    type: string
                    nullable: true
                    description: Rolling 24h USD spend cap. Null clears.
                raw_signing_policy:
                    type: string
                    enum: [allow, deny, approve]
                    description: Raw digest signing policy.
                personal_sign_policy:
                    type: object
                    additionalProperties: true
                    description: personal_sign guardrails JSON.
                allow_erc4337:
                    type: boolean
                    description: Allow ERC-4337 gasless UserOperations.
                allow_eip7702:
                    type: boolean
                    description: Allow EIP-7702 (tx type 4).
                clear_auto_suspended:
                    type: boolean
                    description: When true, clears circuit-breaker auto-suspension (human owner/admin only).
                federation_enabled:
                    type: boolean
                    description: |
                        Enable OIDC federation (RFC 8693 token-exchange) for this agent.
                        When true, the agent may call POST /v1/auth/federated-token to mint
                        federation tokens for the audiences listed in `federation_audiences`.
                federation_audiences:
                    type: array
                    items:
                        type: string
                        format: uri
                    description: |
                        Allowlist of `aud` values the federation token-exchange may issue
                        tokens for (e.g. `["https://api.anthropic.com"]`). Empty array
                        blocks all federation requests (zero-trust default).
                federated_token_ttl_seconds:
                    type: integer
                    minimum: 60
                    maximum: 3600
                    nullable: true
                    description: |
                        Per-agent TTL override for federation tokens (seconds). NULL falls
                        back to the global default (`ONECLAW_JWT_FEDERATED_TOKEN_EXPIRY_SECS`).
                        Hard-capped at 3600 seconds.
                tx_token_allowlist:
                    type: array
                    items:
                        type: string
                    description: Token contract/mint addresses this agent may interact with. Empty = unrestricted.
                tx_known_tokens_only:
                    type: boolean
                    default: false
                    description: When true, only tokens in the known_tokens registry may be used.
                xrpl_allowed_tx_types:
                    type: array
                    items:
                        type: string
                    description: Allowed XRP Ledger transaction types (Payment, TrustSet, etc.). Empty = all allowed.
                per_chain_guardrails:
                    type: object
                    additionalProperties: true
                    description: |
                        Per-chain guardrail overrides. Keys are signing chains (ethereum, bitcoin, solana, xrp, cardano, tron).
                        Each value may include max_value, daily_limit, to_allowlist, token_allowlist (legacy *_eth keys accepted),
                        max_fee_per_gas_gwei, max_gas_limit, gas_daily_budget_native (UTC-day cumulative EVM gas in native units).
                        Strictest of global and per-chain limits wins. Daily limits apply per chain family spend, not cross-chain totals.
                api_key_expires_at:
                    type: string
                    format: date-time
                    nullable: true
                    description: Optional expiration time for the agent's API key. Set to null to clear.
                environment:
                    type: string
                    nullable: true
                    description: Named environment for this agent (production, preview, development, or custom).
                environment_locked:
                    type: boolean
                    description: When true, the environment tag cannot be changed after creation.
                env_auto_resolve:
                    type: boolean
                    description: When true, env var resolve endpoints auto-fill environment from this agent's tag.
                per_environment_guardrails:
                    type: object
                    additionalProperties: true
                    description: Per-environment guardrail overrides keyed by environment slug.
                address_screening_policy:
                    type: object
                    additionalProperties: true
                    description: Recipient address screening policy. `mode` may be `off`, `deny`, or `approve`.
                approval_id:
                    type: string
                    format: uuid
                    description: >
                        Approved policy_change id when applying a queued guardrail
                        widening. Resubmit PATCH with this field after the approval
                        has been approved via POST /v1/approvals/{approval_id}/decide.

        AgentResponse:
            type: object
            required:
                [
                    id,
                    name,
                    auth_method,
                    is_active,
                    intents_api_enabled,
                    shroud_enabled,
                    created_at,
                ]
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                description:
                    type: string
                auth_method:
                    type: string
                    enum: [api_key, mtls, oidc_client_credentials]
                scopes:
                    type: array
                    items:
                        type: string
                is_active:
                    type: boolean
                intents_api_enabled:
                    type: boolean
                tx_to_allowlist:
                    type: array
                    items:
                        type: string
                tx_max_value:
                    type: string
                    description: Maximum value per transaction in native major units for the transacting chain family (ETH on EVM, BTC on Bitcoin, SOL on Solana, XRP, ADA, TRX).
                tx_daily_limit:
                    type: string
                    description: Rolling daily spend cap in native major units, enforced per chain family at signing time.
                tx_max_value_eth:
                    type: string
                    deprecated: true
                    description: Deprecated alias for tx_max_value. Same unit semantics (native major units, not ETH-only).
                tx_daily_limit_eth:
                    type: string
                    deprecated: true
                    description: Deprecated alias for tx_daily_limit.
                tx_spent_today:
                    type: string
                    description: Sum of today's spend across all chain families in major units. Prefer tx_spent_today_by_chain.
                tx_spent_today_eth:
                    type: string
                    deprecated: true
                    description: Deprecated alias for tx_spent_today.
                tx_allowed_chains:
                    type: array
                    items:
                        type: string
                token_ttl_seconds:
                    type: integer
                    nullable: true
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                client_cert_fingerprint:
                    type: string
                    description: SHA-256 fingerprint of the client certificate (mTLS agents)
                oidc_issuer:
                    type: string
                    description: OIDC issuer URL (oidc_client_credentials agents)
                oidc_client_id:
                    type: string
                    description: OIDC client ID (oidc_client_credentials agents)
                ssh_public_key:
                    type: string
                    description: Ed25519 SSH public key (base64-encoded, auto-generated at creation)
                ecdh_public_key:
                    type: string
                    description: P-256 ECDH public key (base64 SEC1 uncompressed point, auto-generated at creation)
                shroud_enabled:
                    type: boolean
                    description: Whether this agent routes LLM traffic through the Shroud TEE proxy
                shroud_config:
                    $ref: "#/components/schemas/ShroudConfig"
                execution_intents_enabled:
                    type: boolean
                    description: Whether Execution Intents (bindings and execute endpoint) are enabled for this agent
                execution_guardrails:
                    type: object
                    additionalProperties: true
                    description: Guardrails applied to all execution intents for this agent
                intents_require_tee:
                    type: boolean
                    description: When true, transaction/sign requests must arrive via a TEE host (Pro+ only)
                execution_require_tee:
                    type: boolean
                    description: When true, execute requests must arrive via TEE and all direct secret reads are blocked (Pro+ only)
                tx_max_per_day:
                    type: integer
                    nullable: true
                    description: Max transactions per UTC calendar day. Null = unlimited.
                tx_overhead_budget:
                    type: object
                    nullable: true
                    additionalProperties:
                        type: string
                    description: Per-chain daily overhead budget in native units.
                solana_ata_allowlist:
                    type: array
                    items:
                        type: string
                    description: Solana wallet addresses whose ATAs may be created.
                cards_enabled:
                    type: boolean
                    description: Whether this agent may order payment cards (x402 card ordering).
                card_max_order_usd:
                    type: string
                    description: Maximum USD amount for a single card order.
                card_daily_limit_usd:
                    type: string
                    description: Maximum cumulative USD spent ordering cards per rolling 24h window.
                card_payto_allowlist:
                    type: array
                    items:
                        type: string
                    description: Allowed x402 payTo recipients for card orders (empty = built-in Laso recipients).
                card_reveal_enabled:
                    type: boolean
                    description: Whether agents may reveal card details subject to per-card reveal policy.
                card_require_approval:
                    type: boolean
                    description: When true, card orders route through the human approval queue before x402 payment.
                tx_approval_policy:
                    type: object
                    additionalProperties: true
                    nullable: true
                    description: Graduated transaction approval policy (HITL thresholds).
                typed_data_policy:
                    type: string
                    enum: [deny, approve]
                    nullable: true
                simulation_failure_policy:
                    type: string
                    enum: [deny, approve]
                    nullable: true
                tx_block_unlimited_approvals:
                    type: boolean
                    description: Block unlimited ERC-20 approvals.
                tx_per_recipient_max_per_day:
                    type: integer
                    nullable: true
                tx_per_recipient_daily_limit:
                    type: string
                    nullable: true
                new_recipient_cap_native:
                    type: string
                    nullable: true
                tx_max_value_usd:
                    type: string
                    nullable: true
                tx_daily_limit_usd:
                    type: string
                    nullable: true
                raw_signing_policy:
                    type: string
                    enum: [allow, deny, approve]
                personal_sign_policy:
                    type: object
                    additionalProperties: true
                    nullable: true
                allow_erc4337:
                    type: boolean
                allow_eip7702:
                    type: boolean
                auto_suspended:
                    type: boolean
                    description: True when circuit breaker auto-suspended the agent after repeated guardrail denials.
                tx_count_today:
                    type: integer
                    description: Today's transaction count (UTC calendar day). Present when intents_api_enabled.
                tx_overhead_today_by_chain:
                    type: object
                    additionalProperties:
                        type: string
                    description: Today's overhead spend by chain in native units.
                federation_enabled:
                    type: boolean
                    description: |
                        Whether this agent may mint OIDC federation tokens via
                        POST /v1/auth/federated-token. False by default.
                federation_audiences:
                    type: array
                    items:
                        type: string
                        format: uri
                    description: Allowlist of audience URIs the agent may federate to.
                federated_token_ttl_seconds:
                    type: integer
                    nullable: true
                    description: Per-agent TTL override for federation tokens (60..=3600).
                signing_chains:
                    type: array
                    items:
                        type: string
                    description: Chains for which this agent has provisioned signing keys.
                eip712_domain_allowlist:
                    type: array
                    items:
                        type: object
                    description: JSON array of allowed EIP-712 domain entries.
                eip712_default_policy:
                    type: string
                    enum: [deny, allow]
                    description: Default EIP-712 policy (deny blocks all unless allowlisted).
                message_signing_enabled:
                    type: boolean
                    description: Whether EIP-191 personal_sign is enabled.
                raw_signing_enabled:
                    type: boolean
                    description: >
                        Whether the raw/precomputed-digest signing intent (eip712_digest) is
                        enabled. Blind signing — bypasses transaction guardrails; OFF by default
                        and human-set. Required for ERC-1271/ERC-7739 flows (e.g. Polymarket).
                tx_token_allowlist:
                    type: array
                    items:
                        type: string
                    description: Token contract/mint addresses this agent may interact with.
                tx_known_tokens_only:
                    type: boolean
                    description: When true, only tokens in the known_tokens registry may be used.
                xrpl_allowed_tx_types:
                    type: array
                    items:
                        type: string
                    description: Allowed XRP Ledger transaction types.
                per_chain_guardrails:
                    type: object
                    additionalProperties: true
                    description: Per-chain guardrail overrides.
                tx_spent_today_by_chain:
                    type: object
                    additionalProperties:
                        type: string
                    description: 'Per-chain-family daily spend in native major units (keys: evm, bitcoin, solana, xrp, cardano, tron).'
                api_key_expires_at:
                    type: string
                    format: date-time
                    nullable: true
                    description: Optional expiration time for the agent's API key.
                evm_address:
                    type: string
                    nullable: true
                    description: Agent's Ethereum EOA address (used as Safe signer for smart accounts and Intents API).
                created_at:
                    type: string
                    format: date-time
                expires_at:
                    type: string
                    format: date-time
                last_active_at:
                    type: string
                    format: date-time
                smart_accounts:
                    type: array
                    description: Multi-chain; one Safe per chain
                    items:
                        $ref: "#/components/schemas/AgentSmartAccountResponse"
                environment:
                    type: string
                    nullable: true
                    description: Named environment this agent belongs to (production, preview, development, or custom).
                environment_locked:
                    type: boolean
                    description: When true, the environment tag is locked and cannot be changed.
                env_auto_resolve:
                    type: boolean
                    description: When true, env var resolve endpoints auto-fill environment from this agent's tag.
                per_environment_guardrails:
                    type: object
                    additionalProperties: true
                    description: Per-environment guardrail overrides keyed by environment slug.
                address_screening_policy:
                    type: object
                    additionalProperties: true
                    description: Recipient address screening policy. `mode` may be `off`, `deny`, or `approve`.

        KnownToken:
            type: object
            required: [id, chain, symbol, name, contract_address, decimals, is_testnet, is_verified]
            properties:
                id:
                    type: string
                    format: uuid
                chain:
                    type: string
                symbol:
                    type: string
                name:
                    type: string
                contract_address:
                    type: string
                decimals:
                    type: integer
                is_testnet:
                    type: boolean
                is_verified:
                    type: boolean
                logo_url:
                    type: string
                    nullable: true
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        KnownTokenListResponse:
            type: object
            required: [tokens]
            properties:
                tokens:
                    type: array
                    items:
                        $ref: "#/components/schemas/KnownToken"

        CreateKnownTokenRequest:
            type: object
            required: [chain, symbol, name, contract_address, decimals]
            properties:
                chain:
                    type: string
                symbol:
                    type: string
                name:
                    type: string
                contract_address:
                    type: string
                decimals:
                    type: integer
                is_testnet:
                    type: boolean
                    default: false
                is_verified:
                    type: boolean
                    default: true
                logo_url:
                    type: string
                    nullable: true

        AgentSmartAccountResponse:
            type: object
            description: One Safe smart account per chain for an agent
            properties:
                id:
                    type: string
                    format: uuid
                chain:
                    type: string
                chain_id:
                    type: integer
                safe_address:
                    type: string
                nonce:
                    type: string
                init_data:
                    type: object
                created_at:
                    type: string
                    format: date-time

        AddSmartAccountRequest:
            type: object
            required: [chain, chain_id, safe_address]
            properties:
                chain:
                    type: string
                chain_id:
                    type: integer
                safe_address:
                    type: string
                nonce:
                    type: string
                init_data:
                    type: object

        AgentSelfResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                description:
                    type: string
                org_id:
                    type: string
                    format: uuid
                scopes:
                    type: array
                    items:
                        type: string
                is_active:
                    type: boolean
                intents_api_enabled:
                    type: boolean
                created_by:
                    type: string
                    format: uuid
                created_at:
                    type: string
                    format: date-time
                expires_at:
                    type: string
                    format: date-time
                last_active_at:
                    type: string
                    format: date-time
                ssh_public_key:
                    type: string
                    description: Ed25519 SSH public key (base64-encoded)
                ecdh_public_key:
                    type: string
                    description: P-256 ECDH public key (base64 SEC1 uncompressed point)
                shroud_enabled:
                    type: boolean
                    description: Whether this agent routes LLM traffic through the Shroud TEE proxy
                shroud_config:
                    $ref: "#/components/schemas/ShroudConfig"

        ShroudConfig:
            type: object
            description: Per-agent Shroud LLM Proxy configuration
            properties:
                pii_policy:
                    type: string
                    enum: [block, redact, warn, allow]
                    default: redact
                    description: How PII detections are handled
                injection_threshold:
                    type: number
                    minimum: 0
                    maximum: 1
                    default: 0.7
                    description: Prompt injection score threshold (0.0–1.0). Requests above are blocked
                context_injection_threshold:
                    type: number
                    minimum: 0
                    maximum: 1
                    default: 0.7
                    description: Context injection score threshold (0.0–1.0)
                allowed_providers:
                    type: array
                    items:
                        type: string
                    description: LLM providers this agent may use (empty = all)
                allowed_models:
                    type: array
                    items:
                        type: string
                    description: Specific models allowed (empty = all)
                denied_models:
                    type: array
                    items:
                        type: string
                    description: Models explicitly blocked
                max_tokens_per_request:
                    type: integer
                    description: Maximum input tokens per request
                max_requests_per_minute:
                    type: integer
                    description: Rate limit (requests per minute)
                max_requests_per_day:
                    type: integer
                    description: Rate limit (requests per day)
                daily_budget_usd:
                    type: number
                    description: Daily LLM spend cap in USD (0 = unlimited)
                enable_secret_redaction:
                    type: boolean
                    default: true
                    description: Whether vault secrets are redacted from prompts/responses
                enable_response_filtering:
                    type: boolean
                    default: true
                    description: Whether response credential scanning is active
                unicode_normalization:
                    $ref: "#/components/schemas/UnicodeNormalizationConfig"
                command_injection_detection:
                    $ref: "#/components/schemas/CommandInjectionConfig"
                social_engineering_detection:
                    $ref: "#/components/schemas/SocialEngineeringConfig"
                encoding_detection:
                    $ref: "#/components/schemas/EncodingDetectionConfig"
                network_detection:
                    $ref: "#/components/schemas/NetworkDetectionConfig"
                filesystem_detection:
                    $ref: "#/components/schemas/FilesystemDetectionConfig"
                sanitization_mode:
                    type: string
                    enum: [block, surgical, log_only]
                    default: block
                    description: Global behavior when threats are detected (block=reject, surgical=remove only malicious parts, log_only=audit without action)
                threat_logging:
                    type: boolean
                    default: true
                    description: Whether to log all detected threats to audit (even when action is allow/warn)
                tool_call_inspection:
                    $ref: "#/components/schemas/ToolCallPolicy"
                output_policy:
                    $ref: "#/components/schemas/OutputPolicy"
                secret_injection_detection:
                    $ref: "#/components/schemas/SecretInjectionConfig"
                advanced_redaction:
                    $ref: "#/components/schemas/AdvancedRedactionConfig"
                semantic_policy:
                    $ref: "#/components/schemas/SemanticPolicy"
                flagged_request_retention_days:
                    type: integer
                    minimum: 0
                    maximum: 365
                    description: Number of days to retain flagged request bodies for replay/investigation

        UnicodeNormalizationConfig:
            type: object
            description: Unicode normalization and homoglyph detection settings
            properties:
                enabled:
                    type: boolean
                    default: true
                    description: Enable Unicode normalization
                strip_zero_width:
                    type: boolean
                    default: true
                    description: Remove zero-width and invisible Unicode characters
                normalize_homoglyphs:
                    type: boolean
                    default: true
                    description: Replace look-alike characters (e.g., Cyrillic а → Latin a)
                normalization_form:
                    type: string
                    enum: [NFC, NFKC, NFD, NFKD]
                    default: NFKC
                    description: Unicode normalization form to apply

        CommandInjectionConfig:
            type: object
            description: Shell/command injection detection settings
            properties:
                enabled:
                    type: boolean
                    default: true
                    description: Enable command injection detection
                action:
                    type: string
                    enum: [block, sanitize, warn, log]
                    default: block
                    description: Action when command injection is detected
                patterns:
                    type: string
                    enum: [default, strict, custom]
                    default: default
                    description: Pattern strictness level
                custom_patterns:
                    type: array
                    items:
                        type: string
                    description: Custom regex patterns for detection (only used when patterns=custom)

        SocialEngineeringConfig:
            type: object
            description: Social engineering and manipulation detection settings
            properties:
                enabled:
                    type: boolean
                    default: true
                    description: Enable social engineering detection
                action:
                    type: string
                    enum: [block, warn, log]
                    default: warn
                    description: Action when manipulation attempts are detected
                sensitivity:
                    type: string
                    enum: [low, medium, high]
                    default: medium
                    description: Detection sensitivity level

        EncodingDetectionConfig:
            type: object
            description: Encoding/obfuscation detection settings
            properties:
                enabled:
                    type: boolean
                    default: true
                    description: Enable encoding detection
                action:
                    type: string
                    enum: [block, decode, warn, log]
                    default: warn
                    description: Action when obfuscated content is detected
                detect_base64:
                    type: boolean
                    default: true
                    description: Detect Base64-encoded content
                detect_hex:
                    type: boolean
                    default: true
                    description: Detect hex-encoded content (\\x41, 0x41)
                detect_unicode_escape:
                    type: boolean
                    default: true
                    description: Detect Unicode escape sequences (\\u0041)

        NetworkDetectionConfig:
            type: object
            description: Suspicious URL/domain detection settings
            properties:
                enabled:
                    type: boolean
                    default: true
                    description: Enable network/URL detection
                action:
                    type: string
                    enum: [block, warn, log]
                    default: warn
                    description: Action when suspicious URLs are detected
                blocked_domains:
                    type: array
                    items:
                        type: string
                    description: Domains to always block (e.g., pastebin.com, ngrok.io)
                allowed_domains:
                    type: array
                    items:
                        type: string
                    description: Domains to always allow (allowlist mode when non-empty)

        FilesystemDetectionConfig:
            type: object
            description: Filesystem path detection settings
            properties:
                enabled:
                    type: boolean
                    default: false
                    description: Enable filesystem path detection (disabled by default as it can be noisy)
                action:
                    type: string
                    enum: [block, sanitize, warn, log]
                    default: log
                    description: Action when filesystem paths are detected
                blocked_paths:
                    type: array
                    items:
                        type: string
                    description: Path patterns to block (e.g., /etc/passwd, ~/.ssh)

        ToolCallPolicy:
            type: object
            description: Tool/function call inspection settings
            properties:
                enabled:
                    type: boolean
                    default: false
                    description: Enable tool call inspection
                allowed_tool_names:
                    type: array
                    items:
                        type: string
                    description: Allowed tool/function names (empty = all allowed)
                denied_tool_names:
                    type: array
                    items:
                        type: string
                    description: Denied tool/function names
                scan_arguments:
                    type: boolean
                    default: true
                    description: Scan tool call arguments for credential exfiltration
                block_credential_exfil:
                    type: boolean
                    default: true
                    description: Block tool calls that appear to exfiltrate credentials
                action:
                    type: string
                    enum: [block, sanitize, warn, log]
                    default: block
                    description: Action when a tool call violation is detected

        OutputPolicy:
            type: object
            description: Output content policy settings for LLM responses
            properties:
                enabled:
                    type: boolean
                    default: false
                    description: Enable output content policies
                blocked_patterns:
                    type: array
                    items:
                        type: string
                    description: Custom regex patterns to block in responses
                blocked_entities:
                    type: array
                    items:
                        type: string
                    description: Named entities to block (e.g., competitor names)
                block_harmful_content:
                    type: boolean
                    default: false
                    description: Block responses containing harmful content categories
                harmful_categories:
                    type: array
                    items:
                        type: string
                        enum: [violence, self_harm, illegal, hate, sexual, malware]
                    description: Harm categories to block
                action:
                    type: string
                    enum: [block, sanitize, warn, log]
                    default: warn
                    description: Action when output policy is violated

        SecretInjectionConfig:
            type: object
            description: Detects credentials injected into prompts that are not from the vault
            properties:
                enabled:
                    type: boolean
                    default: false
                    description: Enable secret injection detection
                action:
                    type: string
                    enum: [block, sanitize, warn, log]
                    default: block
                    description: Action when injected credentials are detected
                sensitivity:
                    type: string
                    enum: [low, medium, high]
                    default: medium
                    description: Detection sensitivity level

        AdvancedRedactionConfig:
            type: object
            description: Advanced secret redaction settings (base64-encoded, split, prefix leaks)
            properties:
                enabled:
                    type: boolean
                    default: false
                    description: Enable advanced redaction checks
                detect_base64_encoded:
                    type: boolean
                    default: false
                    description: Detect base64-encoded vault secrets
                detect_split_secrets:
                    type: boolean
                    default: false
                    description: Detect secrets split across tokens or messages
                detect_prefix_leak:
                    type: boolean
                    default: false
                    description: Detect partial/prefix leaks of vault secrets
                min_secret_length:
                    type: integer
                    default: 16
                    description: Minimum secret length to consider for advanced matching

        SemanticPolicy:
            type: object
            description: Semantic/intent-level policy enforcement
            properties:
                enabled:
                    type: boolean
                    default: false
                    description: Enable semantic policy enforcement
                allowed_topics:
                    type: array
                    items:
                        type: string
                    description: Topics the agent is allowed to discuss (empty = all)
                denied_topics:
                    type: array
                    items:
                        type: string
                    description: Topics to block
                allowed_tasks:
                    type: array
                    items:
                        type: string
                    description: Tasks the agent is allowed to perform (empty = all)
                denied_tasks:
                    type: array
                    items:
                        type: string
                    description: Tasks to block (e.g., code_generation, data_export)
                action:
                    type: string
                    enum: [block, sanitize, warn, log]
                    default: warn
                    description: Action when semantic policy is violated

        AgentCreatedResponse:
            type: object
            required: [agent]
            properties:
                agent:
                    $ref: "#/components/schemas/AgentResponse"
                api_key:
                    type: string
                    description: One-time API key (only present for api_key auth method)

        AgentListResponse:
            type: object
            properties:
                agents:
                    type: array
                    items:
                        $ref: "#/components/schemas/AgentResponse"

        AgentKeyRotatedResponse:
            type: object
            properties:
                api_key:
                    type: string

        # --- Transactions ---

        SubmitTransactionRequest:
            type: object
            required: [to, value, chain]
            properties:
                to:
                    type: string
                    description: Destination address (0x-prefixed)
                value:
                    type: string
                    description: Value in ETH
                chain:
                    type: string
                    description: Chain name or numeric ID
                data:
                    type: string
                    description: Hex-encoded calldata
                signing_key_path:
                    type: string
                    description: Vault path to signing key. Auto-resolves per-chain signing key if provisioned, otherwise keys/{chain}-signer.
                nonce:
                    type: integer
                gas_price:
                    type: string
                gas_limit:
                    type: integer
                max_fee_per_gas:
                    type: string
                max_priority_fee_per_gas:
                    type: string
                simulate_first:
                    type: boolean
                    default: false
                mode:
                    type: string
                    description: Transaction mode
                    enum: [eoa, smart_account]
                    default: eoa
                gasless:
                    type: boolean
                    description: Whether to submit as a gasless (sponsored) transaction
                    default: false
                destination_tag:
                    type: integer
                    description: "Non-EVM (XRP): destination tag for exchange deposits"
                memo:
                    type: string
                    description: "Non-EVM (XRP, Solana): optional memo"
                fee_rate_sat_per_vbyte:
                    type: integer
                    description: "Non-EVM (Bitcoin): override the fetched fee rate (sat/vByte)"
                fee_limit_sun:
                    type: integer
                    description: "Non-EVM (Tron): TRC-20 energy fee limit in sun"
                token_mint:
                    type: string
                    description: "Non-EVM (Solana SPL / Tron TRC-20): token mint or contract address; omit for native transfer"
                token_decimals:
                    type: integer
                    description: "Non-EVM (Solana, Tron): token decimals (default 6)"
                ttl:
                    type: integer
                    description: "Non-EVM (Cardano): transaction time-to-live (absolute slot)"
                xrpl_tx_json:
                    type: object
                    additionalProperties: true
                    description: >
                        Raw XRPL transaction JSON for full transaction type coverage.
                        When present (and chain is XRP), the handler uses the xrpl-rust
                        binary codec to encode and sign the transaction as-is. Supports
                        all XRPL transaction types: Payment, TrustSet, OfferCreate,
                        OfferCancel, AccountSet, EscrowCreate, NFTokenMint, AMMCreate,
                        and 20+ more. Account, Sequence, Fee, LastLedgerSequence, and
                        SigningPubKey are auto-filled when absent.
                approval_id:
                    type: string
                    format: uuid
                    description: >
                        Optional pending approval ID. When consensus policies match,
                        clients resubmit with this field set to bypass the 202 gate
                        after the approval has been executed.
                raw_transaction:
                    type: string
                    description: >
                        Pre-built raw transaction as a base64-encoded byte string.
                        When provided, the handler decodes and deep-inspects the
                        transaction for policy evaluation before signing. Supported
                        for non-EVM chains where the client constructs the
                        transaction payload.
                tron_transaction:
                    type: object
                    additionalProperties: true
                    description: >
                        Pre-built Tron transaction JSON object. When provided,
                        the handler signs the transaction as-is using the Tron
                        protobuf format. Enables full Tron transaction type
                        coverage beyond simple TRX/TRC-20 transfers.

        SignTransactionRequest:
            type: object
            required: [to, value, chain]
            properties:
                to:
                    type: string
                    description: Destination address (0x-prefixed)
                value:
                    type: string
                    description: Value in ETH
                chain:
                    type: string
                    description: Chain name or numeric ID
                data:
                    type: string
                    description: Hex-encoded calldata
                signing_key_path:
                    type: string
                    description: Vault path to signing key. Auto-resolves per-chain signing key if provisioned, otherwise keys/{chain}-signer.
                nonce:
                    type: integer
                gas_price:
                    type: string
                gas_limit:
                    type: integer
                max_fee_per_gas:
                    type: string
                max_priority_fee_per_gas:
                    type: string
                simulate_first:
                    type: boolean
                    default: false
                destination_tag:
                    type: integer
                    description: "Non-EVM (XRP): destination tag for exchange deposits"
                memo:
                    type: string
                    description: "Non-EVM (XRP, Solana): optional memo"
                fee_rate_sat_per_vbyte:
                    type: integer
                    description: "Non-EVM (Bitcoin): override the fetched fee rate (sat/vByte)"
                fee_limit_sun:
                    type: integer
                    description: "Non-EVM (Tron): TRC-20 energy fee limit in sun"
                token_mint:
                    type: string
                    description: "Non-EVM (Solana SPL / Tron TRC-20): token mint or contract address; omit for native transfer"
                token_decimals:
                    type: integer
                    description: "Non-EVM (Solana, Tron): token decimals (default 6)"
                ttl:
                    type: integer
                    description: "Non-EVM (Cardano): transaction time-to-live (absolute slot)"
                xrpl_tx_json:
                    type: object
                    additionalProperties: true
                    description: >
                        Raw XRPL transaction JSON for full transaction type coverage.
                        When present (and chain is XRP), the handler uses the xrpl-rust
                        binary codec to encode and sign the transaction as-is. Supports
                        all XRPL transaction types: Payment, TrustSet, OfferCreate,
                        OfferCancel, AccountSet, EscrowCreate, NFTokenMint, AMMCreate,
                        and 20+ more. Account, Sequence, Fee, LastLedgerSequence, and
                        SigningPubKey are auto-filled when absent.

        SignTransactionResponse:
            type: object
            properties:
                signed_tx:
                    type: string
                    description: Raw signed transaction hex (always included)
                tx_hash:
                    type: string
                from:
                    type: string
                    description: Derived sender address
                to:
                    type: string
                chain:
                    type: string
                chain_id:
                    type: integer
                nonce:
                    type: integer
                value_wei:
                    type: string
                status:
                    type: string
                    enum: [sign_only]
                simulation_id:
                    type: string
                simulation_status:
                    type: string
                max_fee_per_gas:
                    type: string
                max_priority_fee_per_gas:
                    type: string

        SimulateTransactionRequest:
            type: object
            required: [to, value, chain]
            properties:
                to:
                    type: string
                value:
                    type: string
                chain:
                    type: string
                data:
                    type: string
                signing_key_path:
                    type: string
                    description: Vault path to signing key. Auto-resolves per-chain signing key if provisioned, otherwise keys/{chain}-signer.
                gas_limit:
                    type: integer

        SimulateBundleRequest:
            type: object
            required: [transactions]
            properties:
                transactions:
                    type: array
                    items:
                        $ref: "#/components/schemas/SimulateTransactionRequest"

        # Signing Keys (Multi-Chain)
        CreateSigningKeyRequest:
            type: object
            required: [chain]
            properties:
                chain:
                    type: string
                    enum: [ethereum, bitcoin, solana, xrp, cardano, tron]

        SigningKeyResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                chain:
                    type: string
                curve:
                    type: string
                public_key:
                    type: string
                address:
                    type: string
                    nullable: true
                key_version:
                    type: integer
                is_active:
                    type: boolean
                created_at:
                    type: string
                    format: date-time
                rotated_at:
                    type: string
                    format: date-time
                    nullable: true

        SigningKeyListResponse:
            type: object
            properties:
                keys:
                    type: array
                    items:
                        $ref: "#/components/schemas/SigningKeyResponse"

        # Bankr Dynamic Key Vending
        LeaseBankrKeyRequest:
            type: object
            properties:
                wallet_id:
                    type: string
                    description: Bankr wallet ID (wlt_...). Uses org default if omitted.
                ttl_seconds:
                    type: integer
                    description: Lease TTL in seconds (default 3600, max 86400).
                    minimum: 60
                    maximum: 86400
                permissions:
                    $ref: "#/components/schemas/LeaseBankrPermissions"

        LeaseBankrPermissions:
            type: object
            properties:
                llm_gateway_enabled:
                    type: boolean
                    default: true
                agent_api_enabled:
                    type: boolean
                    default: false
                read_only:
                    type: boolean
                    default: true

        LeaseBankrKeyResponse:
            type: object
            properties:
                lease_id:
                    type: string
                    format: uuid
                api_key:
                    type: string
                    description: Ephemeral bk_usr_ key. Present for human callers only; omitted for agent JWTs.
                wallet_id:
                    type: string
                expires_at:
                    type: string
                    format: date-time

        BankrKeyLeaseResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                wallet_id:
                    type: string
                bankr_key_id:
                    type: string
                permissions:
                    type: object
                expires_at:
                    type: string
                    format: date-time
                created_at:
                    type: string
                    format: date-time

        BankrKeyLeaseListResponse:
            type: object
            properties:
                leases:
                    type: array
                    items:
                        $ref: "#/components/schemas/BankrKeyLeaseResponse"

        # Agent Delegations
        CreateDelegationRequest:
            type: object
            required: [delegate_id]
            properties:
                delegate_id:
                    type: string
                    format: uuid
                    description: The agent ID to delegate to.
                allowed_tools:
                    type: array
                    items:
                        type: string
                    description: Tool names the delegate may use. Empty means all tools allowed.
                blocked_tools:
                    type: array
                    items:
                        type: string
                    description: Tool names the delegate may NOT use.
                max_daily_delegations:
                    type: integer
                    description: Maximum delegation calls per UTC day. NULL means unlimited.
                max_depth:
                    type: integer
                    description: Maximum delegation chain depth (default 3).
                    default: 3
                guardrails:
                    type: object
                    description: Additional guardrail constraints for this delegation.
                delegation_mode:
                    type: string
                    enum: [caller, target, both]
                    description: "Execution mode: caller (use delegator's creds), target (use delegate's config), or both."
                    default: caller
                expires_at:
                    type: string
                    format: date-time
                    description: Optional expiration timestamp.

        UpdateDelegationRequest:
            type: object
            properties:
                allowed_tools:
                    type: array
                    items:
                        type: string
                blocked_tools:
                    type: array
                    items:
                        type: string
                max_daily_delegations:
                    type: integer
                max_depth:
                    type: integer
                guardrails:
                    type: object
                delegation_mode:
                    type: string
                    enum: [caller, target, both]
                is_active:
                    type: boolean
                expires_at:
                    type: string
                    format: date-time
                    nullable: true

        DelegationResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                delegator_id:
                    type: string
                    format: uuid
                delegate_id:
                    type: string
                    format: uuid
                delegator_name:
                    type: string
                delegate_name:
                    type: string
                allowed_tools:
                    type: array
                    items:
                        type: string
                blocked_tools:
                    type: array
                    items:
                        type: string
                max_daily_delegations:
                    type: integer
                    nullable: true
                max_depth:
                    type: integer
                guardrails:
                    type: object
                delegation_mode:
                    type: string
                    enum: [caller, target, both]
                is_active:
                    type: boolean
                created_by:
                    type: string
                    format: uuid
                expires_at:
                    type: string
                    format: date-time
                    nullable: true
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time
                delegations_today:
                    type: integer
                    description: Number of delegations used today (present in effective endpoint).

        DelegationListResponse:
            type: object
            properties:
                delegations:
                    type: array
                    items:
                        $ref: "#/components/schemas/DelegationResponse"

        # Unified Signing Intent
        SignIntentRequest:
            type: object
            required: [intent_type, chain]
            properties:
                intent_type:
                    type: string
                    enum: [personal_sign, typed_data, eip712_digest, transaction]
                chain:
                    type: string
                signing_key_path:
                    type: string
                    description: Vault path to signing key. Auto-resolves per-chain signing key if provisioned, otherwise keys/{chain}-signer.
                message:
                    type: string
                    description: Hex-encoded message bytes (for personal_sign)
                typed_data:
                    type: object
                    description: EIP-712 typed data JSON (for typed_data)
                hash:
                    type: string
                    description: >
                        Client-computed 32-byte digest (0x-prefixed) for the eip712_digest
                        intent. Signed directly (blind signing); requires the agent's
                        raw_signing_enabled flag. Use for ERC-1271/ERC-7739 nested EIP-712
                        flows (e.g. Polymarket) where the canonical hash is computed client-side.
                tx_type:
                    type: integer
                    description: "EIP-2718 type: 0=legacy, 1=2930, 2=1559, 3=4844, 4=7702"
                to:
                    type: string
                value:
                    type: string
                data:
                    type: string
                nonce:
                    type: integer
                gas_limit:
                    type: integer
                gas_price:
                    type: string
                max_fee_per_gas:
                    type: string
                max_priority_fee_per_gas:
                    type: string
                access_list:
                    type: array
                    items:
                        type: object
                max_fee_per_blob_gas:
                    type: string
                blob_versioned_hashes:
                    type: array
                    items:
                        type: string
                authorization_list:
                    type: array
                    items:
                        type: object
                sign_only:
                    type: boolean
                    description: "When true, sign only (do not broadcast). Non-EVM transaction intents only."
                destination_tag:
                    type: integer
                    description: "Non-EVM (XRP): destination tag for exchange deposits"
                memo:
                    type: string
                    description: "Non-EVM (XRP, Solana): optional memo"
                fee_rate_sat_per_vbyte:
                    type: integer
                    description: "Non-EVM (Bitcoin): override the fetched fee rate (sat/vByte)"
                fee_limit_sun:
                    type: integer
                    description: "Non-EVM (Tron): TRC-20 energy fee limit in sun"
                token_mint:
                    type: string
                    description: "Non-EVM (Solana SPL / Tron TRC-20): token mint or contract address; omit for native transfer"
                token_decimals:
                    type: integer
                    description: "Non-EVM (Solana, Tron): token decimals (default 6)"
                ttl:
                    type: integer
                    description: "Non-EVM (Cardano): transaction time-to-live (absolute slot)"
                xrpl_tx_json:
                    type: object
                    additionalProperties: true
                    description: >
                        Raw XRPL transaction JSON for full transaction type coverage.
                        When present (and chain is XRP), the handler uses the xrpl-rust
                        binary codec to encode and sign the transaction as-is. Supports
                        all XRPL transaction types: Payment, TrustSet, OfferCreate,
                        OfferCancel, AccountSet, EscrowCreate, NFTokenMint, AMMCreate,
                        and 20+ more. Account, Sequence, Fee, LastLedgerSequence, and
                        SigningPubKey are auto-filled when absent.
                approval_id:
                    type: string
                    format: uuid
                    description: >
                        Optional pending approval ID. When consensus policies match,
                        clients resubmit with this field set to bypass the 202 gate
                        after the approval has been executed.
                raw_transaction:
                    type: string
                    description: >
                        Pre-built raw transaction as a base64-encoded byte string.
                        When provided, the handler decodes and deep-inspects the
                        transaction for policy evaluation before signing. Supported
                        for non-EVM chains where the client constructs the
                        transaction payload.
                tron_transaction:
                    type: object
                    additionalProperties: true
                    description: >
                        Pre-built Tron transaction JSON object. When provided,
                        the handler signs the transaction as-is using the Tron
                        protobuf format. Enables full Tron transaction type
                        coverage beyond simple TRX/TRC-20 transfers.

        SignIntentResponse:
            type: object
            properties:
                intent_type:
                    type: string
                chain:
                    type: string
                from:
                    type: string
                signature:
                    type: string
                    nullable: true
                signed_tx:
                    type: string
                    nullable: true
                tx_hash:
                    type: string
                    nullable: true
                message_hash:
                    type: string
                    nullable: true
                typed_data_hash:
                    type: string
                    nullable: true
                tx_type:
                    type: integer
                    nullable: true

        TransactionResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                chain:
                    type: string
                chain_id:
                    type: integer
                to:
                    type: string
                value_wei:
                    type: string
                status:
                    type: string
                    enum:
                        [pending, signed, sign_only, broadcast, failed, simulation_failed]
                signed_tx:
                    type: string
                    nullable: true
                    description: >
                        Raw signed transaction hex. On GET list and GET by id, this property is omitted by default (absent from the response). Pass `include_signed_tx=true` on those endpoints to include it. Always present on the initial POST submit response.
                tx_hash:
                    type: string
                error_message:
                    type: string
                created_at:
                    type: string
                    format: date-time
                signed_at:
                    type: string
                    format: date-time
                simulation_id:
                    type: string
                simulation_status:
                    type: string
                tenderly_dashboard_url:
                    type: string
                    format: uri
                max_fee_per_gas:
                    type: string
                max_priority_fee_per_gas:
                    type: string

        TransactionListResponse:
            type: object
            properties:
                transactions:
                    type: array
                    items:
                        $ref: "#/components/schemas/TransactionResponse"

        BalanceChange:
            type: object
            properties:
                address:
                    type: string
                token:
                    type: string
                token_symbol:
                    type: string
                before:
                    type: string
                after:
                    type: string
                change:
                    type: string

        SimulationResponse:
            type: object
            properties:
                simulation_id:
                    type: string
                status:
                    type: string
                    enum: [success, reverted, error]
                gas_used:
                    type: integer
                gas_estimate_usd:
                    type: string
                balance_changes:
                    type: array
                    items:
                        $ref: "#/components/schemas/BalanceChange"
                error:
                    type: string
                error_code:
                    type: string
                error_human_readable:
                    type: string
                revert_reason:
                    type: string
                tenderly_dashboard_url:
                    type: string
                    format: uri
                simulated_at:
                    type: string
                    format: date-time

        BundleSimulationResponse:
            type: object
            properties:
                simulations:
                    type: array
                    items:
                        $ref: "#/components/schemas/SimulationResponse"

        # --- Chains ---

        ChainResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                display_name:
                    type: string
                chain_id:
                    type: integer
                rpc_url:
                    type: string
                ws_url:
                    type: string
                explorer_url:
                    type: string
                native_currency:
                    type: string
                is_testnet:
                    type: boolean
                is_enabled:
                    type: boolean
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        ChainListResponse:
            type: object
            properties:
                chains:
                    type: array
                    items:
                        $ref: "#/components/schemas/ChainResponse"

        CreateChainRequest:
            type: object
            required: [name, display_name, chain_id]
            properties:
                name:
                    type: string
                display_name:
                    type: string
                chain_id:
                    type: integer
                rpc_url:
                    type: string
                ws_url:
                    type: string
                explorer_url:
                    type: string
                native_currency:
                    type: string
                    default: ETH
                is_testnet:
                    type: boolean
                    default: false
                is_enabled:
                    type: boolean
                    default: true

        UpdateChainRequest:
            type: object
            properties:
                display_name:
                    type: string
                rpc_url:
                    type: string
                ws_url:
                    type: string
                explorer_url:
                    type: string
                native_currency:
                    type: string
                is_testnet:
                    type: boolean
                is_enabled:
                    type: boolean

        # --- Sharing ---

        CreateShareRequest:
            type: object
            required: [recipient_type, expires_at]
            properties:
                recipient_type:
                    type: string
                    enum:
                        [user, agent, external_email, anyone_with_link, creator]
                recipient_id:
                    type: string
                    format: uuid
                email:
                    type: string
                    format: email
                permissions:
                    type: array
                    items:
                        type: string
                max_access_count:
                    type: integer
                expires_at:
                    type: string
                    format: date-time
                passphrase:
                    type: string
                ip_allowlist:
                    type: array
                    items:
                        type: string

        ShareResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                share_url:
                    type: string
                    format: uri
                recipient_type:
                    type: string
                recipient_email:
                    type: string
                expires_at:
                    type: string
                    format: date-time
                max_access_count:
                    type: integer

        SharedSecretResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                path:
                    type: string
                type:
                    type: string
                value:
                    type: string
                access_count:
                    type: integer
                max_access_count:
                    type: integer

        ShareListItem:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                secret_path:
                    type: string
                recipient_type:
                    type: string
                recipient_email:
                    type: string
                access_count:
                    type: integer
                max_access_count:
                    type: integer
                expires_at:
                    type: string
                    format: date-time
                created_at:
                    type: string
                    format: date-time
                is_expired:
                    type: boolean
                is_accepted:
                    type: boolean

        ShareListResponse:
            type: object
            properties:
                shares:
                    type: array
                    items:
                        $ref: "#/components/schemas/ShareListItem"

        # --- Organization ---

        OrgMemberResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                email:
                    type: string
                display_name:
                    type: string
                role:
                    type: string
                auth_method:
                    type: string
                created_at:
                    type: string
                    format: date-time

        OrgMemberListResponse:
            type: object
            properties:
                members:
                    type: array
                    items:
                        $ref: "#/components/schemas/OrgMemberResponse"

        UpdateMemberRoleRequest:
            type: object
            required: [role]
            properties:
                role:
                    type: string
                    enum: [owner, admin, member]

        InviteMemberRequest:
            type: object
            required: [email]
            properties:
                email:
                    type: string
                    format: email
                role:
                    type: string

        InviteMemberResponse:
            type: object
            properties:
                message:
                    type: string
                email:
                    type: string

        AgentKeysVaultResponse:
            type: object
            properties:
                vault_id:
                    type: string
                    format: uuid

        OrgBankrConfigResponse:
            type: object
            properties:
                configured:
                    type: boolean
                partner_key_prefix:
                    type: string
                default_wallet_id:
                    type: string
                updated_at:
                    type: string
                    format: date-time
                using_platform_fallback:
                    type: boolean

        UpsertOrgBankrConfigRequest:
            type: object
            required: [partner_key]
            properties:
                partner_key:
                    type: string
                    description: Bankr partner API key (bk_ptr_...)
                default_wallet_id:
                    type: string
                    description: Default provisioned wallet (wlt_...)

        # --- Billing ---

        UsageSummaryResponse:
            type: object
            properties:
                billing_tier:
                    type: string
                free_tier_limit:
                    type: integer
                current_month:
                    type: object
                    properties:
                        total_requests:
                            type: integer
                        paid_requests:
                            type: integer
                        free_requests:
                            type: integer
                        total_cost_usd:
                            type: string

        UsageHistoryResponse:
            type: object
            properties:
                events:
                    type: array
                    items:
                        type: object
                        properties:
                            id:
                                type: string
                                format: uuid
                            principal_type:
                                type: string
                            principal_id:
                                type: string
                            method:
                                type: string
                            endpoint:
                                type: string
                            status_code:
                                type: integer
                            price_usd:
                                type: string
                            is_paid:
                                type: boolean
                            created_at:
                                type: string
                                format: date-time

        SubscribeRequest:
            type: object
            required: [tier, interval]
            properties:
                tier:
                    type: string
                    enum: [pro, business]
                interval:
                    type: string
                    enum: [monthly, yearly]
                trial:
                    type: boolean
                    default: true

        TopupRequest:
            type: object
            required: [amount_usd]
            properties:
                amount_usd:
                    type: integer
                    minimum: 5
                    maximum: 1000

        OverageMethodRequest:
            type: object
            required: [method]
            properties:
                method:
                    type: string
                    enum: [credits, x402]

        CheckoutUrlResponse:
            type: object
            properties:
                checkout_url:
                    type: string
                    format: uri

        PortalUrlResponse:
            type: object
            properties:
                portal_url:
                    type: string
                    format: uri

        SubscriptionResponse:
            type: object
            properties:
                tier:
                    type: string
                interval:
                    type: string
                period_end:
                    type: string
                    format: date-time
                status:
                    type: string
                credit_balance_cents:
                    type: integer
                credit_balance_usd:
                    type: string
                overage_method:
                    type: string
                usage:
                    type: object
                    properties:
                        requests:
                            $ref: "#/components/schemas/UsageMeter"
                        secrets:
                            $ref: "#/components/schemas/UsageMeter"
                        agents:
                            $ref: "#/components/schemas/UsageMeter"
                        vaults:
                            $ref: "#/components/schemas/UsageMeter"
                        team_members:
                            $ref: "#/components/schemas/UsageMeter"
                        intent_transactions:
                            $ref: "#/components/schemas/UsageMeter"
                        wallets:
                            $ref: "#/components/schemas/UsageMeter"
                        shares:
                            $ref: "#/components/schemas/UsageMeter"

        UsageMeter:
            type: object
            properties:
                used:
                    type: integer
                limit:
                    type: integer

        LlmMeteredInvoiceLine:
            type: object
            description: Metered line from Stripe upcoming invoice (usage detail when available).
            properties:
                description:
                    type: string
                    nullable: true
                amount_cents:
                    type: integer
                    format: int64
                quantity:
                    type: number
                    nullable: true
                    description: Billed usage units when Stripe returns quantity (e.g. tokens).
                price_nickname:
                    type: string
                    nullable: true

        LlmBillingCycleUsage:
            type: object
            description: Accrued LLM charges for the current Stripe subscription period (upcoming invoice).
            properties:
                period_start:
                    type: string
                    format: date-time
                    nullable: true
                period_end:
                    type: string
                    format: date-time
                    nullable: true
                accrued_usage_cents:
                    type: integer
                    format: int64
                currency:
                    type: string
                metered_lines:
                    type: array
                    items:
                        $ref: "#/components/schemas/LlmMeteredInvoiceLine"

        LlmCreditBalance:
            type: object
            properties:
                available_cents:
                    type: integer
                    format: int64
                ledger_cents:
                    type: integer
                    format: int64
                used_cents:
                    type: integer
                    format: int64
                currency:
                    type: string

        LlmTokenBillingStatus:
            type: object
            required: [enabled]
            properties:
                enabled:
                    type: boolean
                subscription_status:
                    type: string
                    enum: [active, inactive]
                credit_balance:
                    $ref: "#/components/schemas/LlmCreditBalance"
                billing_cycle_usage:
                    $ref: "#/components/schemas/LlmBillingCycleUsage"
                active_subscription_count:
                    type: integer
                subscription_ids:
                    type: array
                    items:
                        type: string
                warning:
                    type: string

        LlmCheckoutResponse:
            type: object
            properties:
                checkout_url:
                    type: string
                    format: uri
                already_subscribed:
                    type: boolean
                subscription_id:
                    type: string

        LlmCancelDuplicatesResponse:
            type: object
            required: [cancelled_count, cancelled_subscription_ids, remaining_subscription_ids]
            properties:
                cancelled_count:
                    type: integer
                cancelled_subscription_ids:
                    type: array
                    items:
                        type: string
                remaining_subscription_ids:
                    type: array
                    items:
                        type: string

        LlmDisableResponse:
            type: object
            properties:
                enabled:
                    type: boolean

        CreditBalanceResponse:
            type: object
            properties:
                balance_cents:
                    type: integer
                balance_usd:
                    type: string
                expiring_within_90_days:
                    type: object
                    properties:
                        amount_cents:
                            type: integer
                        earliest_expiry:
                            type: string
                            format: date-time

        CreditTransactionsListResponse:
            type: object
            properties:
                transactions:
                    type: array
                    items:
                        type: object
                        properties:
                            id:
                                type: string
                                format: uuid
                            type:
                                type: string
                            amount_cents:
                                type: integer
                            balance_after_cents:
                                type: integer
                            description:
                                type: string
                            created_at:
                                type: string
                                format: date-time
                page:
                    type: integer
                limit:
                    type: integer

        OverageMethodResponse:
            type: object
            properties:
                overage_method:
                    type: string

        # --- Audit ---

        AuditEventsResponse:
            type: object
            properties:
                events:
                    type: array
                    items:
                        $ref: "#/components/schemas/AuditEvent"
                count:
                    type: integer

        AuditVerifyResponse:
            type: object
            required: [chain_valid, events_verified, events_checked, scheme]
            properties:
                chain_valid:
                    type: boolean
                    description: Whether the integrity hash chain is unbroken
                events_verified:
                    type: integer
                    format: int64
                    description: Number of events with valid integrity hashes
                events_checked:
                    type: integer
                    description: Total events examined
                broken_at_event_id:
                    type: string
                    format: uuid
                    nullable: true
                    description: First event where chain integrity broke (null if valid)
                scheme:
                    type: object
                    properties:
                        algorithm:
                            type: string
                            example: HMAC-SHA256
                        chain_structure:
                            type: string
                        hash_field:
                            type: string
                        link_field:
                            type: string
                        documentation:
                            type: string
                            format: uri

        ShroudAttestationResponse:
            type: object
            required: [attested, attestation_level, image_hash, identity_token, verification]
            properties:
                attested:
                    type: boolean
                    description: |
                        Whether at least an identity token was obtained (true for identity,
                        confidential, or sev_snp levels). Backward-compatible boolean; prefer
                        attestation_level for granularity.
                attestation_level:
                    type: string
                    enum: [none, identity, confidential, sev_snp]
                    description: |
                        Granularity of TEE attestation achieved. `none` = dev/non-GCE;
                        `identity` = GCE metadata JWT only; `confidential` = CC claims present;
                        `sev_snp` = full SEV-SNP measurement verified against image digest.
                image_hash:
                    type: string
                    description: Confidential VM image hash (compare against published Docker digest)
                identity_token:
                    type: string
                    description: GCE metadata identity JWT (verify against Google public keys)
                confidential_claims:
                    nullable: true
                    description: Confidential Computing claims extracted from the identity JWT
                    $ref: "#/components/schemas/ConfidentialClaims"
                verification:
                    type: object
                    properties:
                        steps:
                            type: array
                            items:
                                type: string
                        google_certs_url:
                            type: string
                            format: uri
                        expected_audience:
                            type: string

        ConfidentialClaims:
            type: object
            nullable: true
            properties:
                secboot:
                    type: boolean
                    description: Whether secure boot was enabled
                hwmodel:
                    type: string
                    description: Hardware model string (e.g. GCP_AMD_SEV)
                instance_confidentiality:
                    type: string
                    description: Instance confidentiality level from google.compute_engine
                sw_name:
                    type: string
                    description: Software name claim (swname or sw_name)

        AuditEvent:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                action:
                    type: string
                actor_id:
                    type: string
                actor_type:
                    type: string
                resource_type:
                    type: string
                resource_id:
                    type: string
                org_id:
                    type: string
                    format: uuid
                details:
                    type: object
                    additionalProperties: true
                ip_address:
                    type: string
                created_at:
                    type: string
                    format: date-time

        # --- Security ---

        CreateIpRuleRequest:
            type: object
            required: [rule_type, cidr]
            properties:
                rule_type:
                    type: string
                    enum: [allow, deny]
                cidr:
                    type: string
                label:
                    type: string
                applies_to:
                    type: string

        IpRuleResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                rule_type:
                    type: string
                cidr:
                    type: string
                label:
                    type: string
                applies_to:
                    type: string
                created_by:
                    type: string
                created_at:
                    type: string
                    format: date-time

        IpRulesListResponse:
            type: object
            properties:
                rules:
                    type: array
                    items:
                        $ref: "#/components/schemas/IpRuleResponse"

        # --- Admin ---

        SettingResponse:
            type: object
            properties:
                key:
                    type: string
                value:
                    type: string
                updated_by:
                    type: string
                updated_at:
                    type: string
                    format: date-time

        SettingsListResponse:
            type: object
            properties:
                settings:
                    type: array
                    items:
                        $ref: "#/components/schemas/SettingResponse"

        UpdateSettingRequest:
            type: object
            required: [value]
            properties:
                value:
                    type: string

        X402ConfigResponse:
            type: object
            properties:
                pay_to:
                    type: string
                network:
                    type: string
                scheme:
                    type: string
                free_tier_limit:
                    type: integer
                facilitator_url:
                    type: string

        AdminUsersListResponse:
            type: object
            properties:
                users:
                    type: array
                    items:
                        type: object
                        properties:
                            id:
                                type: string
                                format: uuid
                            email:
                                type: string
                            display_name:
                                type: string
                            role:
                                type: string
                            auth_method:
                                type: string
                            org_id:
                                type: string
                                format: uuid
                            org_name:
                                type: string
                            billing_tier:
                                type: string
                            created_at:
                                type: string
                                format: date-time
                            free_tier_override:
                                type: integer
                            is_sponsored:
                                type: boolean
                            current_month_requests:
                                type: integer
                total:
                    type: integer

        UpdateOrgLimitsRequest:
            type: object
            properties:
                free_tier_override:
                    type: integer
                is_sponsored:
                    type: boolean

        OrgLimitsResponse:
            type: object
            properties:
                org_id:
                    type: string
                    format: uuid
                free_tier_override:
                    type: integer
                is_sponsored:
                    type: boolean

        SetBillingTierRequest:
            type: object
            required: [tier]
            properties:
                tier:
                    type: string
                    enum: [free, pro, business, enterprise]
                duration_days:
                    type: integer
                    description: How many days the tier lasts (default 365). Use 90 for a 3-month trial.
                    minimum: 1
                    maximum: 3650

        # --- Treasury ---

        CreateTreasuryRequest:
            type: object
            required: [name, safe_address]
            properties:
                name:
                    type: string
                    description: Display name (1–128 characters)
                safe_address:
                    type: string
                    description: Deployed Safe contract address (0x-prefixed, 42 characters)
                chain:
                    type: string
                    description: Chain name (default base)
                chain_id:
                    type: integer
                    description: EVM chain ID (default 8453 for Base)
                threshold:
                    type: integer
                    minimum: 1
                    description: Safe threshold (default 1)
                signers:
                    type: array
                    items:
                        $ref: "#/components/schemas/CreateTreasurySignerEntry"

        CreateTreasurySignerEntry:
            type: object
            required: [signer_type, signer_id, signer_address]
            properties:
                signer_type:
                    type: string
                    enum: [user, agent]
                signer_id:
                    type: string
                    format: uuid
                signer_address:
                    type: string
                    description: EVM address (0x-prefixed)

        UpdateTreasuryRequest:
            type: object
            properties:
                name:
                    type: string
                threshold:
                    type: integer
                    minimum: 1

        TreasuryResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                safe_address:
                    type: string
                chain:
                    type: string
                chain_id:
                    type: integer
                threshold:
                    type: integer
                created_by:
                    type: string
                    format: uuid
                signers:
                    type: array
                    items:
                        $ref: "#/components/schemas/TreasurySignerResponse"
                created_at:
                    type: string
                    format: date-time

        TreasurySignerResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                signer_type:
                    type: string
                    enum: [user, agent]
                signer_id:
                    type: string
                    format: uuid
                signer_address:
                    type: string
                added_at:
                    type: string
                    format: date-time

        AddSignerRequest:
            type: object
            required: [signer_type, signer_id, signer_address]
            properties:
                signer_type:
                    type: string
                    enum: [user, agent]
                signer_id:
                    type: string
                    format: uuid
                signer_address:
                    type: string

        AccessRequestResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                treasury_id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                status:
                    type: string
                    enum: [pending, approved, denied]
                reason:
                    type: string
                requested_at:
                    type: string
                    format: date-time
                resolved_by:
                    type: string
                    format: uuid
                resolved_at:
                    type: string
                    format: date-time

        # --- Treasury Proposals ---

        CreateTreasuryProposalRequest:
            type: object
            required: [to_address, value_wei, chain]
            properties:
                to_address:
                    type: string
                    description: Destination address (0x-prefixed)
                value_wei:
                    type: string
                    description: Transaction value in wei
                chain:
                    type: string
                    description: Chain name (e.g. ethereum, base)
                chain_id:
                    type: integer
                    description: Numeric chain ID (alternative to chain name)
                data_hex:
                    type: string
                    description: Hex-encoded calldata (optional)
                operation:
                    type: integer
                    description: Safe operation type (0 = Call, 1 = DelegateCall)
                    default: 0

        SignTreasuryProposalRequest:
            type: object
            required: [decision]
            properties:
                decision:
                    type: string
                    enum: [approve, reject]
                    description: Whether to approve or reject the proposal
                signature:
                    type: string
                    description: EIP-712 signature (hex). If omitted, server signs with caller's key.

        TreasuryProposalResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                treasury_id:
                    type: string
                    format: uuid
                proposed_by:
                    type: string
                    format: uuid
                proposed_by_type:
                    type: string
                    enum: [user, agent]
                chain:
                    type: string
                chain_id:
                    type: integer
                safe_address:
                    type: string
                to_address:
                    type: string
                value_wei:
                    type: string
                data_hex:
                    type: string
                    nullable: true
                operation:
                    type: integer
                safe_tx_hash:
                    type: string
                    nullable: true
                nonce:
                    type: integer
                    nullable: true
                status:
                    type: string
                    enum: [pending, approved, executing, executed, rejected, expired]
                threshold:
                    type: integer
                expires_at:
                    type: string
                    format: date-time
                    nullable: true
                executed_tx_hash:
                    type: string
                    nullable: true
                executed_at:
                    type: string
                    format: date-time
                    nullable: true
                signatures:
                    type: array
                    items:
                        $ref: "#/components/schemas/ProposalSignatureResponse"
                created_at:
                    type: string
                    format: date-time

        ProposalSignatureResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                signer_id:
                    type: string
                    format: uuid
                signer_type:
                    type: string
                    enum: [user, agent]
                signer_address:
                    type: string
                signature:
                    type: string
                decision:
                    type: string
                    enum: [approve, reject]
                created_at:
                    type: string
                    format: date-time

        TreasuryProposalListResponse:
            type: object
            properties:
                proposals:
                    type: array
                    items:
                        $ref: "#/components/schemas/TreasuryProposalResponse"

        # --- Treasury Wallets ---

        GenerateTreasuryWalletsRequest:
            type: object
            properties:
                chains:
                    type: array
                    items:
                        type: string
                    description: "Chains to generate wallets for (e.g. [\"ethereum\", \"solana\"]). Omit for all supported chains."

        TreasuryWalletResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                chain:
                    type: string
                curve:
                    type: string
                    description: "Cryptographic curve (e.g. secp256k1, ed25519)"
                public_key_hex:
                    type: string
                address:
                    type: string
                is_active:
                    type: boolean
                created_at:
                    type: string
                    format: date-time

        TreasuryWalletListResponse:
            type: object
            properties:
                wallets:
                    type: array
                    items:
                        $ref: "#/components/schemas/TreasuryWalletResponse"

        TreasuryWalletExportResponse:
            type: object
            properties:
                chain:
                    type: string
                address:
                    type: string
                private_key_hex:
                    type: string
                    description: Raw private key in hex encoding. Handle with extreme care.

        TreasuryWalletBalanceResponse:
            type: object
            required: [chain, address, native]
            properties:
                chain:
                    type: string
                address:
                    type: string
                native:
                    type: object
                    required: [symbol, balance_wei, balance_display]
                    properties:
                        symbol:
                            type: string
                        balance_wei:
                            type: string
                        balance_display:
                            type: string
                tokens:
                    type: array
                    items:
                        type: object
                        required: [contract_address, balance_raw]
                        properties:
                            contract_address:
                                type: string
                            balance_raw:
                                type: string

        TreasuryWalletSendRequest:
            type: object
            required: [to, value_wei]
            properties:
                to:
                    type: string
                    description: Destination address (0x-prefixed)
                value_wei:
                    type: string
                    description: Value in wei (or major-unit decimal string for non-EVM)
                data:
                    type: string
                    description: Hex-encoded calldata (optional)
                gas_limit:
                    type: integer
                    description: Gas limit override
                gasless:
                    type: boolean
                    description: When true, submits as a gasless (ERC-4337) transaction via Pimlico paymaster. The paymaster sponsors the gas cost.
                    default: false
                token_mint:
                    type: string
                    description: Token contract address / mint (ERC-20, SPL, TRC-20, Cardano policy_id.asset_name)
                memo:
                    type: string
                    description: Transaction memo (Solana Memo Program, XRP Memos, Tron extra_data)
                destination_tag:
                    type: integer
                    description: XRP destination tag
                fee_rate_sat_per_vbyte:
                    type: integer
                    description: Bitcoin fee rate in sat/vbyte
                xrpl_tx_json:
                    type: object
                    description: Raw XRPL transaction JSON for advanced XRP transaction types
                fee_limit_sun:
                    type: integer
                    description: Tron fee limit in sun
                token_decimals:
                    type: integer
                    description: Token decimals (required for non-EVM token transfers when not in known_tokens)
                ttl:
                    type: integer
                    description: Cardano transaction TTL (slot number)

        TreasuryWalletSendResponse:
            type: object
            required: [tx_hash, from, to, value_wei, chain, status]
            properties:
                tx_hash:
                    type: string
                from:
                    type: string
                to:
                    type: string
                value_wei:
                    type: string
                chain:
                    type: string
                status:
                    type: string
                user_op_hash:
                    type: string
                    description: UserOperation hash (only present for gasless sends via paymaster)

        TreasuryWalletSwapRequest:
            type: object
            required: [sell_token, buy_token, sell_amount]
            properties:
                sell_token:
                    type: string
                    description: Address of the token to sell (or "native" for ETH)
                buy_token:
                    type: string
                    description: Address of the token to buy (or "native" for ETH)
                sell_amount:
                    type: string
                    description: Amount to sell in token's smallest unit

        TreasuryWalletSwapResponse:
            type: object
            required: [tx_hash, sell_token, buy_token, sell_amount, buy_amount, chain, status]
            properties:
                tx_hash:
                    type: string
                sell_token:
                    type: string
                buy_token:
                    type: string
                sell_amount:
                    type: string
                buy_amount:
                    type: string
                chain:
                    type: string
                status:
                    type: string

        # --- Webhooks ---

        CreateWebhookRequest:
            type: object
            required: [url, events]
            properties:
                url:
                    type: string
                    format: uri
                    description: HTTPS URL to deliver webhook events to
                events:
                    type: array
                    items:
                        type: string
                    description: Event types to subscribe to
                description:
                    type: string

        UpdateWebhookRequest:
            type: object
            properties:
                url:
                    type: string
                    format: uri
                events:
                    type: array
                    items:
                        type: string
                is_active:
                    type: boolean
                description:
                    type: string

        WebhookCreatedResponse:
            type: object
            required: [id, url, events, secret, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                url:
                    type: string
                    format: uri
                events:
                    type: array
                    items:
                        type: string
                secret:
                    type: string
                    description: HMAC signing secret for verifying payloads (shown only once)
                created_at:
                    type: string
                    format: date-time

        WebhookResponse:
            type: object
            required: [id, url, events, is_active, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                url:
                    type: string
                    format: uri
                events:
                    type: array
                    items:
                        type: string
                is_active:
                    type: boolean
                description:
                    type: string
                created_at:
                    type: string
                    format: date-time

        WebhookListResponse:
            type: object
            required: [webhooks]
            properties:
                webhooks:
                    type: array
                    items:
                        $ref: "#/components/schemas/WebhookResponse"

        # --- Signing Key Balance ---

        SigningKeyBalanceResponse:
            type: object
            required: [chain, address, balance_wei, balance_display]
            properties:
                chain:
                    type: string
                address:
                    type: string
                balance_wei:
                    type: string
                balance_display:
                    type: string
                tokens:
                    type: array
                    description: Token balances when ?tokens= query param is provided
                    items:
                        type: object
                        properties:
                            contract_address:
                                type: string
                            symbol:
                                type: string
                                nullable: true
                            balance:
                                type: string
                            decimals:
                                type: integer
                                nullable: true

        # --- x402 ---

        PaymentRequirement:
            type: object
            properties:
                x402Version:
                    type: integer
                accepts:
                    type: array
                    items:
                        type: object
                        properties:
                            scheme:
                                type: string
                            network:
                                type: string
                            payTo:
                                type: string
                            price:
                                type: string
                            requiredDeadlineSeconds:
                                type: integer
                description:
                    type: string

        # --- Shroud Activity ---

        ShroudActivityEvent:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                provider:
                    type: string
                model:
                    type: string
                action:
                    type: string
                    description: Action taken (allowed, blocked, warned)
                request_tokens:
                    type: integer
                response_tokens:
                    type: integer
                latency_ms:
                    type: integer
                had_secrets_redacted:
                    type: boolean
                had_pii_detected:
                    type: boolean
                injection_score:
                    type: number
                policy_violations:
                    type: array
                    items:
                        type: string
                # Response-side inspection signals (Shroud v0.5.0+,
                # H-RESP-INSPECT). Optional — pre-v0.5.0 events have them
                # unset; treat as zero / empty.
                response_injection_score:
                    type: number
                    description: Response-side prompt-injection score (0.0–1.0).
                response_context_injection_score:
                    type: number
                    description: Response-side context-injection score (0.0–1.0).
                response_injection_categories:
                    type: array
                    items:
                        type: string
                    description: Category tags emitted by the response-side filters (e.g. `markdown_image_exfil`, `data_uri_blob`, `echoed_instruction`).
                external_urls_flagged:
                    type: array
                    items:
                        type: string
                    description: URLs emitted by the model that were flagged as potential exfil / callback targets.
                unexpected_code_blocks:
                    type: integer
                    description: Number of code fences in the response that were not expected for the agent's allowed task set.
                content_filtered:
                    type: boolean
                    description: True when Shroud rewrote or blocked response content before returning it to the agent.
                metadata:
                    type: object
                timestamp:
                    type: string
                    format: date-time

        IngestShroudActivityRequest:
            type: object
            required: [agent_id, action]
            properties:
                agent_id:
                    type: string
                provider:
                    type: string
                model:
                    type: string
                action:
                    type: string
                request_tokens:
                    type: integer
                    default: 0
                response_tokens:
                    type: integer
                    default: 0
                latency_ms:
                    type: integer
                had_secrets_redacted:
                    type: boolean
                    default: false
                had_pii_detected:
                    type: boolean
                    default: false
                injection_score:
                    type: number
                    default: 0
                policy_violations:
                    type: array
                    items:
                        type: string
                metadata:
                    type: object
                # Response-side inspection signals (Shroud v0.5.0+,
                # H-RESP-INSPECT). Optional for backward compatibility.
                response_injection_score:
                    type: number
                    default: 0
                response_context_injection_score:
                    type: number
                    default: 0
                response_injection_categories:
                    type: array
                    items:
                        type: string
                external_urls_flagged:
                    type: array
                    items:
                        type: string
                unexpected_code_blocks:
                    type: integer
                    default: 0
                content_filtered:
                    type: boolean
                    default: false

        ShroudThreatSummary:
            type: object
            properties:
                total_requests:
                    type: integer
                    format: int64
                total_requests_prev:
                    type: integer
                    format: int64
                blocked_requests:
                    type: integer
                    format: int64
                detectors_triggered:
                    type: integer
                    format: int64
                active_agents:
                    type: integer
                    format: int64
                detectors:
                    type: array
                    items:
                        $ref: "#/components/schemas/ShroudDetectorStats"
                flagged_requests:
                    type: array
                    items:
                        $ref: "#/components/schemas/ShroudFlaggedRequest"

        ShroudDetectorStats:
            type: object
            properties:
                detector:
                    type: string
                detections:
                    type: integer
                    format: int64
                blocks:
                    type: integer
                    format: int64
                actions:
                    type: object
                    properties:
                        blocked:
                            type: integer
                            format: int64
                        warned:
                            type: integer
                            format: int64
                        logged:
                            type: integer
                            format: int64

        ShroudFlaggedRequest:
            type: object
            properties:
                id:
                    type: string
                timestamp:
                    type: string
                    format: date-time
                agent_id:
                    type: string
                agent_name:
                    type: string
                score:
                    type: number
                reason:
                    type: string
                action:
                    type: string
                    enum: [blocked, warned, logged]

        # --- Health ---

        HealthResponse:
            type: object
            properties:
                status:
                    type: string
                    enum: [healthy, degraded]
                version:
                    type: string

        # --- Platform API Schemas ---

        CreatePlatformAppRequest:
            type: object
            required: [name, slug]
            properties:
                name:
                    type: string
                slug:
                    type: string
                    minLength: 3
                    maxLength: 64
                    pattern: "^[a-zA-Z0-9_-]+$"
                description:
                    type: string
                oidc_jwks_url:
                    type: string
                    format: uri
                oidc_issuer:
                    type: string
                    format: uri
                oidc_audience:
                    type: string
                    description: Expected audience claim for OIDC token validation
                redirect_uris:
                    type: array
                    items:
                        type: string
                        format: uri
                billing_model:
                    type: string
                    enum: [platform_pays, user_pays, hybrid]
                    default: platform_pays
                auth_mode:
                    type: string
                    enum: [silent, user_signin, configurable]
                    default: silent
                max_connected_users:
                    type: integer
                    nullable: true
                api_key_expires_at:
                    type: string
                    format: date-time
                    nullable: true
                    description: Optional expiration time for the platform API key.

        UpdatePlatformAppRequest:
            type: object
            properties:
                name:
                    type: string
                description:
                    type: string
                logo_url:
                    type: string
                oidc_jwks_url:
                    type: string
                oidc_issuer:
                    type: string
                oidc_audience:
                    type: string
                    description: Expected audience claim for OIDC token validation
                redirect_uris:
                    type: array
                    items:
                        type: string
                webhook_url:
                    type: string
                billing_model:
                    type: string
                    enum: [platform_pays, user_pays, hybrid]
                auth_mode:
                    type: string
                    enum: [silent, user_signin, configurable]
                max_connected_users:
                    type: integer
                    nullable: true
                is_active:
                    type: boolean
                api_key_expires_at:
                    type: string
                    format: date-time
                    nullable: true
                    description: Optional expiration time for the platform API key. Set to null to clear.

        PlatformAppDeleteResponse:
            type: object
            required: [deleted, soft_delete, slug_released, former_slug]
            properties:
                deleted:
                    type: boolean
                soft_delete:
                    type: boolean
                slug_released:
                    type: boolean
                former_slug:
                    type: string

        TransferPlatformAppOwnershipRequest:
            type: object
            properties:
                target_org_id:
                    type: string
                    format: uuid
                target_user_email:
                    type: string
                    format: email
            description: Provide `target_org_id` or `target_user_email` (owner/admin in destination org).

        TransferPlatformAppOwnershipResponse:
            type: object
            required: [app_id, former_org_id, new_org_id, message]
            properties:
                app_id:
                    type: string
                    format: uuid
                former_org_id:
                    type: string
                    format: uuid
                new_org_id:
                    type: string
                    format: uuid
                message:
                    type: string

        PlatformAppResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                slug:
                    type: string
                description:
                    type: string
                logo_url:
                    type: string
                    nullable: true
                api_key_prefix:
                    type: string
                oidc_jwks_url:
                    type: string
                    nullable: true
                oidc_issuer:
                    type: string
                    nullable: true
                oidc_audience:
                    type: string
                    nullable: true
                    description: Expected audience claim for OIDC token validation
                redirect_uris:
                    type: array
                    items:
                        type: string
                webhook_url:
                    type: string
                    nullable: true
                is_active:
                    type: boolean
                billing_model:
                    type: string
                auth_mode:
                    type: string
                max_connected_users:
                    type: integer
                    nullable: true
                connected_users:
                    type: integer
                api_key_expires_at:
                    type: string
                    format: date-time
                    nullable: true
                    description: When the platform API key expires.
                api_key_rotated_at:
                    type: string
                    format: date-time
                    nullable: true
                    description: When the platform API key was last rotated.
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        PlatformAppCreatedResponse:
            allOf:
                - $ref: "#/components/schemas/PlatformAppResponse"
                - type: object
                  required: [api_key]
                  properties:
                      api_key:
                          type: string
                          description: The platform API key. Save immediately - it cannot be retrieved again.

        CreateTemplateRequest:
            type: object
            required: [name, spec]
            properties:
                name:
                    type: string
                description:
                    type: string
                spec:
                    type: object
                    description: |
                        Template specification defining vault, agents, policies, and signing keys to bootstrap.
                        Top-level fields: `vault` (object with name, description), `agents` (array of agent specs
                        with name, description, shroud_enabled, intents, shroud_config), `policies` (array with
                        vault_ref, principal_ref, paths, permissions, conditions), and `signing_keys` (array of
                        `{ chain }` objects — supported chains: ethereum, bitcoin, solana, xrp, cardano, tron).
                        When `signing_keys` is present, HSM-backed signing keys are auto-provisioned for the
                        bootstrapped agent.

        PlatformTemplateResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                platform_app_id:
                    type: string
                    format: uuid
                name:
                    type: string
                description:
                    type: string
                version:
                    type: integer
                spec:
                    type: object
                is_active:
                    type: boolean
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        UpsertPlatformUserRequest:
            type: object
            properties:
                subject_token:
                    type: string
                    description: OIDC JWT from the platform's IdP (verified against JWKS)
                subject_token_type:
                    type: string
                    default: "urn:ietf:params:oauth:token-type:jwt"
                    description: |
                        Token type for subject_token. Use `urn:1claw:params:oauth:token-type:siwe`
                        with `siwe_message` and `siwe_signature` for wallet-based provisioning.
                email:
                    type: string
                    format: email
                    description: Fallback when subject_token is not provided
                display_name:
                    type: string
                siwe_message:
                    type: string
                    description: EIP-4361 Sign-In With Ethereum message (required for SIWE upsert)
                siwe_signature:
                    type: string
                    description: Hex-encoded SIWE signature (required for SIWE upsert)
                return_to:
                    type: string
                    format: uri
                    description: Redirect URL after cross-org link consent
                create_sub_org:
                    type: boolean
                    default: false
                    description: When true, creates a sub-org under the platform app's org

        PlatformUserResponse:
            type: object
            properties:
                user_handle:
                    type: string
                    format: uuid
                is_new:
                    type: boolean
                connection_id:
                    type: string
                    format: uuid
                email:
                    type: string
                link_required:
                    $ref: "#/components/schemas/LinkRequiredInfo"

        PlatformUserLinkRequiredResponse:
            type: object
            required: [is_new, email, link_required]
            properties:
                is_new:
                    type: boolean
                    example: false
                email:
                    type: string
                link_required:
                    $ref: "#/components/schemas/LinkRequiredInfo"

        LinkRequiredInfo:
            type: object
            required: [status, reason, authorize_url, app_slug]
            properties:
                status:
                    type: string
                    enum: [link_required]
                reason:
                    type: string
                    example: user_exists_in_other_org
                authorize_url:
                    type: string
                    format: uri
                    description: OAuth authorize URL the platform app should redirect the user to for consent.
                app_slug:
                    type: string

        PlatformConnectedUserResponse:
            type: object
            properties:
                connection_id:
                    type: string
                    format: uuid
                user_id:
                    type: string
                    format: uuid
                external_subject:
                    type: string
                status:
                    type: string
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                agent_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                created_at:
                    type: string
                    format: date-time
                claimed_at:
                    type: string
                    format: date-time
                    nullable: true

        BootstrapRequest:
            type: object
            properties:
                template_id:
                    type: string
                    format: uuid
                    description: Template to use. Falls back to the app's default template.
                return_to:
                    type: string
                    format: uri
                    description: URL to redirect the user to after claiming resources.
                parameters:
                    type: object
                    additionalProperties: true
                    description: |
                        Template parameters substituted as `{{params.*}}` during bootstrap.
                        Combined with `Idempotency-Key` header for params-aware idempotent replay.

        BootstrapResponse:
            type: object
            properties:
                claim_url:
                    type: string
                    format: uri
                claim_token:
                    type: string
                expires_in:
                    type: integer
                    description: Seconds until the claim token expires
                connection_id:
                    type: string
                    format: uuid
                summary:
                    type: object
                    properties:
                        vault_id:
                            type: string
                            format: uuid
                            nullable: true
                        agent_id:
                            type: string
                            format: uuid
                            nullable: true
                        agent_ids:
                            type: array
                            items:
                                type: string
                                format: uuid
                            description: All agent IDs provisioned by the template (when multiple agents are defined)
                        policy_ids:
                            type: array
                            items:
                                type: string
                                format: uuid
                        signing_key_chains:
                            type: array
                            items:
                                type: string
                            description: Chains with provisioned signing keys
                        agent_api_key:
                            type: string
                            nullable: true
                            description: One-time agent API key (ocv_ prefix). Store securely — not retrievable later.
                        agent_evm_address:
                            type: string
                            nullable: true
                            description: EOA address when provision_eoa is true in the template
                        signing_keys:
                            type: array
                            description: Provisioned signing key details (chain, address, public key)
                            items:
                                type: object
                                properties:
                                    chain:
                                        type: string
                                    curve:
                                        type: string
                                    public_key:
                                        type: string
                                    address:
                                        type: string
                        runtime_ids:
                            type: array
                            items:
                                type: string
                                format: uuid
                            description: IDs of runtimes provisioned by the template
                        automation_ids:
                            type: array
                            items:
                                type: string
                                format: uuid
                            description: IDs of automations provisioned by the template

        PlatformAppStatsResponse:
            type: object
            required: [total_connections, active_connections, claimed_connections, total_bootstraps, total_grants]
            properties:
                total_connections:
                    type: integer
                    description: Total number of user connections (all statuses)
                active_connections:
                    type: integer
                    description: Number of active connections
                claimed_connections:
                    type: integer
                    description: Number of claimed connections
                total_bootstraps:
                    type: integer
                    description: Total bootstrap operations performed
                total_grants:
                    type: integer
                    description: Total resource grants issued

        MarketplaceResponse:
            type: object
            properties:
                apps:
                    type: array
                    items:
                        type: object
                        properties:
                            id:
                                type: string
                                format: uuid
                            name:
                                type: string
                            slug:
                                type: string
                            description:
                                type: string
                            logo_url:
                                type: string
                                nullable: true
                            category:
                                type: string
                                nullable: true
                            listing_tags:
                                type: array
                                items:
                                    type: string
                            listing_screenshots:
                                type: array
                                items:
                                    type: string
                            pricing_summary:
                                type: string
                                nullable: true

        ConnectedAppResponse:
            type: object
            properties:
                connection_id:
                    type: string
                    format: uuid
                app_name:
                    type: string
                app_slug:
                    type: string
                status:
                    type: string
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                agent_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                created_at:
                    type: string
                    format: date-time

        GrantResourcesRequest:
            type: object
            properties:
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                    description: Vault IDs to grant access to
                agent_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                    description: Agent IDs to grant access to
                allowed_paths:
                    type: array
                    items:
                        type: string
                    default: ["**"]
                    description: Secret path patterns the app can access
                permissions:
                    type: array
                    items:
                        type: string
                    default: ["read"]
                    description: Permissions granted (read, write, rotate)
                expires_at:
                    type: string
                    format: date-time
                    description: Optional grant expiration

        GrantResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                vault_id:
                    type: string
                    format: uuid
                allowed_paths:
                    type: array
                    items:
                        type: string
                permissions:
                    type: array
                    items:
                        type: string
                expires_at:
                    type: string
                    format: date-time
                    nullable: true
                created_at:
                    type: string
                    format: date-time

        GrantResourcesResponse:
            type: object
            properties:
                connection_id:
                    type: string
                    format: uuid
                grants:
                    type: array
                    items:
                        $ref: "#/components/schemas/GrantResponse"
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                agent_ids:
                    type: array
                    items:
                        type: string
                        format: uuid

        GrantListResponse:
            type: object
            properties:
                grants:
                    type: array
                    items:
                        $ref: "#/components/schemas/GrantResponse"

        ClaimPreviewResponse:
            type: object
            properties:
                app_name:
                    type: string
                app_slug:
                    type: string
                app_logo_url:
                    type: string
                    nullable: true
                auth_mode:
                    type: string
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                agent_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                policy_count:
                    type: integer
                status:
                    type: string
                already_claimed:
                    type: boolean
                expired:
                    type: boolean
                return_to:
                    type: string
                    nullable: true

        ClaimRedeemResponse:
            type: object
            properties:
                status:
                    type: string
                connection_id:
                    type: string
                    format: uuid
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                agent_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                return_to:
                    type: string
                    nullable: true
                dashboard_url:
                    type: string

        # --- Mobile Companion App schemas ---

        RegisterDeviceRequest:
            type: object
            required: [name, platform, public_key_pem]
            properties:
                name:
                    type: string
                    description: Human-readable device name (e.g. "Kevin's iPhone")
                    example: My iPhone
                platform:
                    type: string
                    enum: [ios, android]
                public_key_pem:
                    type: string
                    description: PEM-encoded public key for step-up challenge signing
                attestation_blob:
                    type: string
                    description: Optional platform attestation (Apple DeviceCheck / Android SafetyNet)

        RegisterDeviceResponse:
            type: object
            required: [device_id, attestation_verified]
            properties:
                device_id:
                    type: string
                    format: uuid
                attestation_verified:
                    type: boolean

        DeviceListResponse:
            type: object
            required: [devices]
            properties:
                devices:
                    type: array
                    items:
                        $ref: "#/components/schemas/DeviceResponse"

        DeviceResponse:
            type: object
            required: [id, name, platform, attestation_verified, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                platform:
                    type: string
                attestation_verified:
                    type: boolean
                last_used_at:
                    type: string
                    format: date-time
                    nullable: true
                created_at:
                    type: string
                    format: date-time

        CreateDeviceChallengeRequest:
            type: object
            required: [action, target_id]
            properties:
                action:
                    type: string
                    description: The action this challenge authorizes (e.g. "approve_transaction")
                target_id:
                    type: string
                    description: ID of the resource the action targets

        DeviceChallengeResponse:
            type: object
            required: [challenge_nonce, expires_at, action_bound_hash]
            properties:
                challenge_nonce:
                    type: string
                expires_at:
                    type: string
                    format: date-time
                action_bound_hash:
                    type: string
                    description: SHA-256 binding the challenge to the requested action and target

        AttestDeviceChallengeRequest:
            type: object
            required: [challenge_nonce, signature]
            properties:
                challenge_nonce:
                    type: string
                signature:
                    type: string
                    description: Signature over the challenge nonce using the device's private key

        AttestDeviceChallengeResponse:
            type: object
            required: [step_up_token, expires_at]
            properties:
                step_up_token:
                    type: string
                    description: Short-lived token authorizing the bound action
                expires_at:
                    type: string
                    format: date-time

        RegisterPushTokenRequest:
            type: object
            required: [token, platform]
            properties:
                token:
                    type: string
                    description: Push notification token from APNs or FCM
                platform:
                    type: string
                    enum: [apns, fcm]

        DecideApprovalRequest:
            type: object
            required: [decision]
            properties:
                decision:
                    type: string
                    enum: [approve, reject]
                reason:
                    type: string
                    description: Optional human-readable reason for the decision

        ApprovalResponse:
            type: object
            required: [id, org_id, user_id, action, target_type, target_id, risk_tier, status, summary, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                user_id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                    nullable: true
                action:
                    type: string
                target_type:
                    type: string
                target_id:
                    type: string
                risk_tier:
                    type: integer
                    minimum: 1
                    maximum: 3
                status:
                    type: string
                    enum: [pending, approved, rejected, expired]
                summary:
                    type: object
                    description: Structured summary of the action requiring approval
                reason:
                    type: string
                    nullable: true
                decision_reason:
                    type: string
                    nullable: true
                decided_by:
                    type: string
                    format: uuid
                    nullable: true
                decided_at:
                    type: string
                    format: date-time
                    nullable: true
                expires_at:
                    type: string
                    format: date-time
                    nullable: true
                created_at:
                    type: string
                    format: date-time

        ApprovalListResponse:
            type: object
            required: [approvals, total]
            properties:
                approvals:
                    type: array
                    items:
                        $ref: "#/components/schemas/ApprovalResponse"
                total:
                    type: integer

        ApprovalStatusResponse:
            type: object
            required: [status]
            properties:
                status:
                    type: string
                    enum: [pending, approved, rejected, expired]
                expires_at:
                    type: string
                    format: date-time
                    nullable: true

        GuardrailReasonCode:
            type: string
            description: |
                Stable snake_case reason codes for guardrail violations (Convention 1).
                Shadow-mode `"log"` emits the same codes in `guardrail_shadow.would_deny`
                audit events with `enforced: false`. 202 HITL responses use
                `approval_available: true` instead of a deny reason_code.
            enum:
                - binding_rpm_exceeded
                - agent_rpm_exceeded
                - graphql_mutation_blocked
                - graphql_depth_exceeded
                - graphql_parse_failed
                - graphql_introspection_blocked
                - response_too_large
                - request_too_large
                - method_not_allowed
                - header_not_allowed
                - dns_private_ip_blocked
                - agent_suspended
                - outside_time_window
                - secret_in_request
                - concurrency_exceeded
                - org_frozen
                - price_unavailable
                - gas_fee_exceeded
                - unlimited_approval_blocked
                - tx_per_recipient_limit_exceeded
                - tx_max_value_exceeded
                - tx_daily_limit_exceeded
                - delegation_signing_blocked
                - recipient_screening_failed
                - screening_provider_unavailable
                - human_factor_auth_required
                - register_passkey_required

        GuardrailViolation:
            type: object
            description: Convention 1 machine-readable guardrail denial JSON body.
            required: [error, reason_code, approval_available]
            properties:
                error:
                    type: string
                    enum: [guardrail_violation]
                reason_code:
                    $ref: "#/components/schemas/GuardrailReasonCode"
                limit:
                    type: string
                    nullable: true
                current:
                    type: string
                    nullable: true
                attempted:
                    type: string
                    nullable: true
                approval_available:
                    type: boolean
                    default: false
                retry_after_seconds:
                    type: integer
                    nullable: true
                detail:
                    type: string
                    nullable: true

        GuardrailDenial:
            description: Alias of GuardrailViolation (Convention 1 JSON shape).
            allOf:
                - $ref: "#/components/schemas/GuardrailViolation"

        # --- Email OTP ---

        EmailOtpVerifyResponse:
            type: object
            required: [token, user_id, org_id, is_new_user, email]
            properties:
                token:
                    type: string
                    description: JWT access token
                user_id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                is_new_user:
                    type: boolean
                email:
                    type: string
                    format: email
                wallet_address:
                    type: string
                    nullable: true
                    description: Ethereum address if auto_provision_chains included an EVM chain

        # --- OAuth ---

        OAuthConsentResponse:
            type: object
            required: [app_name, app_slug, scopes, redirect_uri, already_consented]
            properties:
                app_name:
                    type: string
                app_slug:
                    type: string
                app_logo_url:
                    type: string
                    format: uri
                    nullable: true
                scopes:
                    type: array
                    items: { type: string }
                redirect_uri:
                    type: string
                    format: uri
                already_consented:
                    type: boolean

        OAuthTokenResponse:
            type: object
            required: [access_token, token_type, expires_in, scope]
            properties:
                access_token:
                    type: string
                token_type:
                    type: string
                    enum: [Bearer]
                expires_in:
                    type: integer
                    description: Token lifetime in seconds
                refresh_token:
                    type: string
                    nullable: true
                    description: Refresh token for obtaining new access tokens (when offline_access scope was granted)
                id_token:
                    type: string
                    nullable: true
                    description: OIDC ID token (when openid scope was granted)
                scope:
                    type: string

        OAuthUserInfoResponse:
            type: object
            required: [sub, email]
            properties:
                sub:
                    type: string
                    format: uuid
                email:
                    type: string
                    format: email
                name:
                    type: string
                    nullable: true
                wallet_address:
                    type: string
                    nullable: true

        # --- Spend Policies ---

        CreateSpendPolicyRequest:
            type: object
            properties:
                user_id:
                    type: string
                    format: uuid
                    description: Scope to a specific user (app-level policies only)
                to_allowlist:
                    type: array
                    items: { type: string }
                    description: Permitted destination addresses (empty = unrestricted)
                to_denylist:
                    type: array
                    items: { type: string }
                    description: Blocked destination addresses
                max_value_per_tx_eth:
                    type: string
                    description: Maximum value per transaction in ETH (decimal string)
                daily_limit_eth:
                    type: string
                    description: Rolling 24h spend cap in ETH (decimal string)
                allowed_chains:
                    type: array
                    items: { type: string }
                    description: Chains the user may transact on (empty = all enabled)
                allowed_tokens:
                    type: array
                    items: { type: string }
                    description: Permitted ERC-20 token contract addresses
                max_transactions_per_day:
                    type: integer
                    description: Maximum number of transactions per 24h window
                inference_allowance_usd:
                    type: string
                    description: Monthly LLM inference allowance in USD (decimal string)
                inference_reserved_pct:
                    type: integer
                    minimum: 0
                    maximum: 100
                    default: 25
                    description: Percent of allowance held in reserve (not spendable)
                inference_hard_stop:
                    type: boolean
                    default: true
                    description: When true, block inference when allowance is exhausted
                inference_allowance_mode:
                    type: string
                    enum: [policy, credits]
                    default: policy
                max_request_cost_usd:
                    type: string
                    description: Maximum estimated cost per LLM request in USD
                human_factor_auth:
                    type: object
                    additionalProperties: true
                    description: |
                        Human factor auth requirements for send/swap/export.
                        Fields: send, swap, export (password_or_passkey | passkey_only | passkey_required | password_only | reauth_token_only),
                        conditional.require_passkey_above_usd, conditional.require_passkey_for_new_recipient.

        SiweChallengeRequest:
            type: object
            properties:
                domain:
                    type: string
                    description: Optional SIWE domain override (defaults to platform app's siwe_domain)

        SiweChallengeResponse:
            type: object
            required: [nonce, expires_in, domain]
            properties:
                nonce:
                    type: string
                expires_in:
                    type: integer
                    description: Seconds until nonce expiry
                domain:
                    type: string

        ConnectionDetailResponse:
            type: object
            required: [connection_id, user_id, status, entitlement_status, vault_ids, agent_ids, claim]
            properties:
                connection_id:
                    type: string
                    format: uuid
                user_id:
                    type: string
                    format: uuid
                status:
                    type: string
                entitlement_status:
                    type: string
                wallet_address:
                    type: string
                    nullable: true
                vault_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                agent_ids:
                    type: array
                    items:
                        type: string
                        format: uuid
                claimed_at:
                    type: string
                    format: date-time
                    nullable: true
                claim:
                    $ref: "#/components/schemas/ClaimStatusResponse"

        ClaimStatusResponse:
            type: object
            required: [status]
            properties:
                status:
                    type: string
                    enum: [pending, active, claimed]
                redeemed_at:
                    type: string
                    format: date-time
                    nullable: true

        ConnectionUsageResponse:
            type: object
            required: [connection_id, period, inference_spent_usd]
            properties:
                connection_id:
                    type: string
                    format: uuid
                period:
                    type: string
                    description: UTC month (YYYY-MM)
                inference_spent_usd:
                    type: string

        EntitlementsListResponse:
            type: object
            required: [evaluations]
            properties:
                evaluations:
                    type: array
                    items:
                        $ref: "#/components/schemas/EntitlementEvaluationResponse"

        EntitlementEvaluationResponse:
            type: object
            required: [id, status, watch_kind, chain, holder_address]
            properties:
                id:
                    type: string
                status:
                    type: string
                watch_kind:
                    type: string
                chain:
                    type: string
                holder_address:
                    type: string
                last_value_raw:
                    type: string
                    nullable: true
                last_checked_at:
                    type: string
                    format: date-time
                    nullable: true

        TemplatePreviewRequest:
            type: object
            properties:
                parameters:
                    type: object
                    additionalProperties: true
                subject:
                    type: object
                    properties:
                        user_id:
                            type: string
                        external_subject:
                            type: string
                        wallet_address:
                            type: string
                        email:
                            type: string

        TemplatePreviewResponse:
            type: object
            required: [resolved_spec]
            properties:
                resolved_spec:
                    type: object
                    additionalProperties: true

        InferenceBudgetResponse:
            type: object
            required:
                - allowance_usd
                - spent_usd
                - remaining_usd
                - reserved_pct
                - max_request_cost_usd
                - period_end
            properties:
                allowance_usd:
                    type: string
                spent_usd:
                    type: string
                remaining_usd:
                    type: string
                reserved_pct:
                    type: integer
                max_request_cost_usd:
                    type: string
                period_end:
                    type: string
                    format: date-time
                connection_id:
                    type: string
                    format: uuid
                    nullable: true

        InferenceBudgetUnconfiguredResponse:
            type: object
            properties:
                allowance_usd:
                    type: string
                    nullable: true
                remaining_usd:
                    nullable: true
                message:
                    type: string

        SpendPolicyResponse:
            type: object
            required: [id, platform_app_id, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                platform_app_id:
                    type: string
                    format: uuid
                user_id:
                    type: string
                    format: uuid
                    nullable: true
                to_allowlist:
                    type: array
                    items: { type: string }
                to_denylist:
                    type: array
                    items: { type: string }
                max_value_per_tx_eth:
                    type: string
                    nullable: true
                daily_limit_eth:
                    type: string
                    nullable: true
                allowed_chains:
                    type: array
                    items: { type: string }
                allowed_tokens:
                    type: array
                    items: { type: string }
                max_transactions_per_day:
                    type: integer
                    nullable: true
                inference_allowance_usd:
                    type: string
                    nullable: true
                inference_reserved_pct:
                    type: integer
                    nullable: true
                inference_hard_stop:
                    type: boolean
                    nullable: true
                inference_allowance_mode:
                    type: string
                    nullable: true
                max_request_cost_usd:
                    type: string
                    nullable: true
                human_factor_auth:
                    type: object
                    additionalProperties: true
                    nullable: true
                created_at:
                    type: string
                    format: date-time

        # --- Risk Engine ---

        HumanFactorAuthPolicy:
            type: object
            properties:
                send:
                    type: string
                    enum: [password_or_passkey, passkey_only, passkey_required, password_only, reauth_token_only]
                swap:
                    type: string
                    enum: [password_or_passkey, passkey_only, passkey_required, password_only, reauth_token_only]
                export:
                    type: string
                    enum: [password_or_passkey, passkey_only, passkey_required, password_only, reauth_token_only]
                conditional:
                    type: object
                    properties:
                        require_passkey_above_usd:
                            type: string
                            nullable: true
                        require_passkey_for_new_recipient:
                            type: boolean

        UpsertHumanFactorAuthRequest:
            type: object
            required: [policy]
            properties:
                policy:
                    $ref: "#/components/schemas/HumanFactorAuthPolicy"

        HumanFactorAuthResponse:
            type: object
            required: [policy, source]
            properties:
                policy:
                    $ref: "#/components/schemas/HumanFactorAuthPolicy"
                source:
                    type: string
                    description: user | platform_app | spend_policy | default

        TreasuryAuthPolicyResponse:
            type: object
            required: [policy, source, registered_passkeys]
            properties:
                policy:
                    $ref: "#/components/schemas/HumanFactorAuthPolicy"
                source:
                    type: string
                    description: user | platform_app | spend_policy | default
                registered_passkeys:
                    type: integer
                    minimum: 0
                    description: Number of WebAuthn passkeys registered for the calling user.

        PasskeyTxAssertBeginRequest:
            type: object
            required: [tx_digest]
            properties:
                tx_digest:
                    type: string
                    description: 64-char hex SHA-256 of canonical send or swap params
                action:
                    type: string
                    enum: [send, swap]
                    default: send
                    description: Treasury action being authorized. Defaults to `send`.

        PasskeyAssertBeginResponse:
            type: object
            required: [challenge, rp_id, timeout, user_verification, allow_credentials]
            properties:
                challenge:
                    type: string
                rp_id:
                    type: string
                timeout:
                    type: integer
                user_verification:
                    type: string
                allow_credentials:
                    type: array
                    items:
                        $ref: "#/components/schemas/AllowCredential"

        AllowCredential:
            type: object
            required: [id, type]
            properties:
                id:
                    type: string
                type:
                    type: string
                    enum: [public-key]
                transports:
                    type: array
                    items:
                        type: string

        MfaPasskeyCompleteRequest:
            type: object
            required: [mfa_token, credential_id, authenticator_data, client_data_json, signature]
            properties:
                mfa_token:
                    type: string
                credential_id:
                    type: string
                authenticator_data:
                    type: string
                client_data_json:
                    type: string
                signature:
                    type: string

        GuardrailWideningQueuedResponse:
            type: object
            required: [status, approval_id, revision_id, message]
            properties:
                status:
                    type: string
                    enum: [awaiting_approval]
                approval_id:
                    type: string
                    format: uuid
                revision_id:
                    type: string
                    format: uuid
                message:
                    type: string
                    description: Human-readable explanation of the queued change.

        RiskEvent:
            type: object
            required: [id, occurred_at, principal_type, principal_id, org_id, event_type, payload, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                occurred_at:
                    type: string
                    format: date-time
                principal_type:
                    type: string
                    enum: [user, agent]
                principal_id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                event_type:
                    type: string
                    description: "Risk event type (e.g. first_seen, geo_velocity, honeytoken_access)"
                ip:
                    type: string
                    nullable: true
                asn:
                    type: integer
                    nullable: true
                asn_org:
                    type: string
                    nullable: true
                country_code:
                    type: string
                    nullable: true
                region:
                    type: string
                    nullable: true
                city:
                    type: string
                    nullable: true
                latitude:
                    type: number
                    nullable: true
                longitude:
                    type: number
                    nullable: true
                user_agent:
                    type: string
                    nullable: true
                severity:
                    type: string
                    nullable: true
                    description: "Computed severity at event time (low, medium, high, critical)"
                payload:
                    type: object
                    additionalProperties: true
                created_at:
                    type: string
                    format: date-time

        RiskEventListResponse:
            type: object
            required: [events]
            properties:
                events:
                    type: array
                    items:
                        $ref: "#/components/schemas/RiskEvent"

        RiskVerdictReason:
            type: object
            required: [detector, severity, description]
            properties:
                detector:
                    type: string
                severity:
                    type: string
                description:
                    type: string
                metadata:
                    type: object
                    additionalProperties: true

        RiskVerdict:
            type: object
            required: [principal_type, principal_id, org_id, score, severity, reasons, computed_at, expires_at]
            properties:
                principal_type:
                    type: string
                principal_id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                score:
                    type: number
                    description: Composite risk score (0.0 – 100.0)
                severity:
                    type: string
                    enum: [low, medium, high, critical]
                reasons:
                    type: array
                    items:
                        $ref: "#/components/schemas/RiskVerdictReason"
                computed_at:
                    type: string
                    format: date-time
                expires_at:
                    type: string
                    format: date-time

        RiskVerdictListResponse:
            type: object
            required: [verdicts]
            properties:
                verdicts:
                    type: array
                    items:
                        $ref: "#/components/schemas/RiskVerdict"

        Honeytoken:
            type: object
            required: [id, vault_id, org_id, secret_path, created_by, created_at, triggered_count]
            properties:
                id:
                    type: string
                    format: uuid
                vault_id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                secret_path:
                    type: string
                created_by:
                    type: string
                    format: uuid
                created_at:
                    type: string
                    format: date-time
                notes:
                    type: string
                    nullable: true
                triggered_count:
                    type: integer
                last_triggered_at:
                    type: string
                    format: date-time
                    nullable: true

        CreateHoneytokenRequest:
            type: object
            required: [vault_id, secret_path]
            properties:
                vault_id:
                    type: string
                    format: uuid
                secret_path:
                    type: string
                    description: Vault secret path to monitor as a canary
                notes:
                    type: string
                    description: Optional human-readable notes about this honeytoken

        HoneytokenListResponse:
            type: object
            required: [honeytokens]
            properties:
                honeytokens:
                    type: array
                    items:
                        $ref: "#/components/schemas/Honeytoken"

        # --- Execution Intents ---

        CredentialSource:
            type: object
            required: [type]
            description: Credential source — inline value (stored in __agent-keys) or live pointer to a vault secret (resolved at execution time).
            discriminator:
                propertyName: type
            properties:
                type:
                    type: string
                    enum: [inline, vault_ref]
                value:
                    type: object
                    additionalProperties: true
                    description: For inline — the credential value object.
                vault_id:
                    type: string
                    format: uuid
                    description: For vault_ref — the vault containing the referenced secret.
                path:
                    type: string
                    description: For vault_ref — the secret path in the vault.

        CreateBindingRequest:
            type: object
            required: [name, binding_type]
            properties:
                name:
                    type: string
                binding_type:
                    type: string
                    enum: [http, graphql, postgres, mysql, redis, grpc, smtp, cloud_sdk, s3, custom]
                config:
                    type: object
                    additionalProperties: true
                guardrails:
                    $ref: "#/components/schemas/BindingGuardrails"
                credential:
                    type: object
                    additionalProperties: true
                    description: "Legacy: inline credential value. Use credential_source for new integrations."
                credential_source:
                    $ref: "#/components/schemas/CredentialSource"

        UpdateBindingRequest:
            type: object
            properties:
                config:
                    type: object
                    additionalProperties: true
                guardrails:
                    $ref: "#/components/schemas/BindingGuardrails"
                is_active:
                    type: boolean
                credential:
                    type: object
                    additionalProperties: true
                    description: "Legacy: inline credential value."
                credential_source:
                    $ref: "#/components/schemas/CredentialSource"
                approval_id:
                    type: string
                    format: uuid
                    description: >
                        Approved policy_change id when applying a queued binding
                        guardrail widening. Resubmit PATCH with this field after
                        approval via POST /v1/approvals/{approval_id}/decide.

        BindingGuardrails:
            type: object
            description: Per-binding execution guardrails enforced at execute time.
            properties:
                allowed_hosts:
                    type: array
                    items: { type: string }
                    description: Host allowlist (trailing * wildcard supported). Empty = unrestricted at binding level.
                allowed_paths:
                    type: array
                    items: { type: string }
                    description: Path allowlist for HTTP/GraphQL bindings.
                max_requests_per_minute:
                    type: integer
                    minimum: 1
                    description: Per-binding RPM; strictest of binding and agent limits wins. Denied executions do not count.
                max_duration_ms:
                    type: integer
                    description: Upstream timeout cap for this binding.
                max_request_bytes:
                    type: integer
                    default: 262144
                    description: Max serialized execute `params` size in bytes (default 256 KiB).
                max_response_bytes:
                    type: integer
                    description: Max upstream response body bytes (default 1 MiB, hard cap 4 MiB).
                allowed_request_headers:
                    type: array
                    items: { type: string }
                    description: Agent-supplied headers permitted in execute params. Defaults to content-type, accept, user-agent, idempotency-key.
                allow_mutations:
                    type: boolean
                    default: true
                    description: GraphQL only — when false, mutation operations return 403 guardrail_violation.
                allow_introspection:
                    type: boolean
                    default: false
                    description: GraphQL only — when false, __schema/__type introspection is blocked.
                max_query_depth:
                    type: integer
                    default: 10
                    description: GraphQL max selection depth.
                max_aliases:
                    type: integer
                    default: 30
                    description: GraphQL max alias count.
                allowed_operations:
                    type: array
                    items: { type: string }
                    description: GraphQL operation kinds allowed (query, mutation, subscription).

        BindingResponse:
            type: object
            required: [id, agent_id, binding_type, name, is_active, created_at, updated_at]
            properties:
                id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                binding_type:
                    type: string
                    enum: [http, graphql, postgres, mysql, redis, grpc, smtp, cloud_sdk, s3, custom]
                name:
                    type: string
                config:
                    type: object
                    additionalProperties: true
                guardrails:
                    $ref: "#/components/schemas/BindingGuardrails"
                is_active:
                    type: boolean
                credential_set:
                    type: boolean
                    description: Whether a credential is stored for this binding. The value itself is never returned.
                credential_source_type:
                    type: string
                    enum: [inline, vault_ref]
                    nullable: true
                    description: How the credential is sourced — inline (HSM-encrypted copy) or vault_ref (live pointer).
                credential_vault_id:
                    type: string
                    format: uuid
                    nullable: true
                    description: For vault_ref credentials — the vault containing the referenced secret.
                credential_path:
                    type: string
                    nullable: true
                    description: For vault_ref credentials — the secret path in the referenced vault.
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        TestBindingResponse:
            type: object
            required: [success, latency_ms]
            properties:
                success:
                    type: boolean
                latency_ms:
                    type: integer
                error:
                    type: string
                    nullable: true

        ExecuteRequest:
            type: object
            required: [binding, intent_type, params]
            properties:
                binding:
                    type: string
                    description: Binding name or ID to execute against
                intent_type:
                    type: string
                    description: Type of execution intent (e.g. http_request, graphql_query)
                execution_mode:
                    type: string
                    enum: [vault, tee]
                    default: vault
                    description: Where execution runs (vault = server-side, tee = Shroud TEE)
                params:
                    type: object
                    additionalProperties: true
                    description: Intent-specific parameters
                dry_run:
                    type: boolean
                    default: false
                    description: When true, validate guardrails and approval policy without executing or persisting side effects.
                resume_after_approval_id:
                    type: string
                    format: uuid
                    description: Internal — resume execution after human approval (server-injected).

        ExecutionApprovalRequired:
            type: object
            required: [error, approval_id, status]
            properties:
                error:
                    type: string
                    enum: [approval_required]
                approval_id:
                    type: string
                    format: uuid
                status:
                    type: string
                    enum: [pending]
                expires_at:
                    type: string
                    format: date-time
                    nullable: true

        TxAwaitingApproval:
            type: object
            required: [status, approval_id]
            properties:
                status:
                    type: string
                    enum: [awaiting_approval]
                approval_id:
                    type: string
                    format: uuid
                tx_id:
                    type: string
                    format: uuid
                    nullable: true
                expires_at:
                    type: string
                    format: date-time
                    nullable: true

        ExecuteResponse:
            type: object
            required: [execution_id, status, duration_ms, redactions_applied]
            properties:
                execution_id:
                    type: string
                    format: uuid
                status:
                    type: string
                result:
                    type: object
                    additionalProperties: true
                    nullable: true
                error:
                    type: string
                    nullable: true
                duration_ms:
                    type: integer
                redactions_applied:
                    type: integer
                execution_surface:
                    type: string
                    enum: [vault, tee]
                    description: Where the intent actually ran. Reported truthfully — never claims TEE when it ran in the Vault.

        ExecutionEventResponse:
            type: object
            required: [id, agent_id, binding_id, intent_type, execution_mode, status, duration_ms, redactions_applied, created_at]
            properties:
                id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                binding_id:
                    type: string
                    format: uuid
                intent_type:
                    type: string
                execution_mode:
                    type: string
                status:
                    type: string
                request_summary:
                    type: object
                    additionalProperties: true
                    nullable: true
                result_summary:
                    type: object
                    additionalProperties: true
                    nullable: true
                error_message:
                    type: string
                    nullable: true
                duration_ms:
                    type: integer
                cost_cents:
                    type: integer
                    nullable: true
                redactions_applied:
                    type: integer
                created_at:
                    type: string
                    format: date-time

        # --- Automations ---

        CreateAutomationRequest:
            type: object
            required: [name, agent_id, trigger_type, workflow_spec]
            description: |
                Create an automation. `workflow_spec` is required and must be either
                a JSON array of steps or `{ "steps": [...] }`. Dashboard `schedule`
                trigger_type is accepted and normalized to `cron`. For cron triggers,
                `cron_expr` is required.
            properties:
                name:
                    type: string
                agent_id:
                    type: string
                    format: uuid
                trigger_type:
                    type: string
                    description: cron | event | webhook | manual (alias schedule → cron)
                    enum: [cron, event, webhook, manual, schedule]
                cron_expr:
                    type: string
                    description: Required when trigger_type is cron (or schedule)
                    example: "0 */6 * * *"
                timezone:
                    type: string
                    default: UTC
                    example: UTC
                event_filter:
                    type: object
                    additionalProperties: true
                    nullable: true
                workflow_spec:
                    description: |
                        Workflow steps. Accepts a bare array `[...]` or
                        `{ "steps": [...] }` (dashboard / preset shape).
                        Supported step types: get_secret, put_secret, http_request,
                        rotate_secret, notify_human, ai_generate, memory_get,
                        memory_put, memory_search, notify, approval_request,
                        condition, execute_binding.
                    oneOf:
                        - type: array
                          items:
                              type: object
                              additionalProperties: true
                        - type: object
                          additionalProperties: true

        UpdateAutomationRequest:
            type: object
            properties:
                name:
                    type: string
                cron_expr:
                    type: string
                    nullable: true
                timezone:
                    type: string
                event_filter:
                    type: object
                    additionalProperties: true
                    nullable: true
                workflow_spec:
                    oneOf:
                        - type: array
                          items:
                              type: object
                              additionalProperties: true
                        - type: object
                          additionalProperties: true
                is_active:
                    type: boolean

        AutomationResponse:
            type: object
            required: [id, agent_id, name, trigger_type, timezone, workflow_spec, is_active, created_at, updated_at]
            properties:
                id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                name:
                    type: string
                trigger_type:
                    type: string
                    enum: [cron, event, webhook, manual]
                cron_expr:
                    type: string
                    nullable: true
                timezone:
                    type: string
                event_filter:
                    type: object
                    additionalProperties: true
                    nullable: true
                workflow_spec:
                    oneOf:
                        - type: array
                          items:
                              type: object
                              additionalProperties: true
                        - type: object
                          additionalProperties: true
                is_active:
                    type: boolean
                last_run_at:
                    type: string
                    format: date-time
                    nullable: true
                next_run_at:
                    type: string
                    format: date-time
                    nullable: true
                last_run_status:
                    type: string
                    nullable: true
                    description: Status of the most recent run (enriched list field)
                total_runs:
                    type: integer
                    nullable: true
                    description: Total runs in the last 30 days (enriched list field)
                success_rate:
                    type: number
                    nullable: true
                    description: Success rate percentage (enriched list field)
                agent_name:
                    type: string
                    nullable: true
                    description: Resolved agent display name (enriched list field)
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        AutomationCreatedResponse:
            allOf:
                - $ref: "#/components/schemas/AutomationResponse"
                - type: object
                  properties:
                      webhook_url:
                          type: string
                          description: Full POST URL including token (one-time on create)
                      webhook_token:
                          type: string
                          description: whk_ token segment (one-time on create)

        WebhookTokenRotatedResponse:
            type: object
            required: [webhook_url, webhook_token]
            properties:
                webhook_url:
                    type: string
                webhook_token:
                    type: string

        AssistDraftResponse:
            type: object
            required: [draft, reply]
            properties:
                draft:
                    type: object
                    additionalProperties: true
                reply:
                    type: string

        AssistSessionResponse:
            type: object
            required: [access_token, expires_in, scopes, cli_hint]
            properties:
                access_token:
                    type: string
                expires_in:
                    type: integer
                scopes:
                    type: array
                    items:
                        type: string
                runtime_id:
                    type: string
                    format: uuid
                    nullable: true
                runtime_status:
                    type: string
                    nullable: true
                cli_hint:
                    type: string

        AutomationListResponse:
            type: object
            required: [automations]
            properties:
                automations:
                    type: array
                    items:
                        $ref: "#/components/schemas/AutomationResponse"

        AutomationRunResponse:
            type: object
            required: [id, automation_id, agent_id, status, started_at, tokens_used, cost_cents]
            properties:
                id:
                    type: string
                    format: uuid
                automation_id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                status:
                    type: string
                    enum: [running, success, failed, timed_out, cancelled, awaiting_approval]
                step_results:
                    nullable: true
                error:
                    type: string
                    nullable: true
                trigger_source:
                    type: string
                    nullable: true
                context:
                    type: object
                    additionalProperties: true
                    nullable: true
                    description: JSONB context passed between workflow steps
                started_at:
                    type: string
                    format: date-time
                finished_at:
                    type: string
                    format: date-time
                    nullable: true
                tokens_used:
                    type: integer
                cost_cents:
                    type: integer

        AutomationRunListResponse:
            type: object
            required: [runs]
            properties:
                runs:
                    type: array
                    items:
                        $ref: "#/components/schemas/AutomationRunResponse"

        AutomationPresetsResponse:
            type: object
            required: [presets]
            properties:
                presets:
                    type: array
                    items:
                        type: object
                        properties:
                            id:
                                type: string
                            name:
                                type: string
                            description:
                                type: string
                            trigger_type:
                                type: string
                            cron_expr:
                                type: string
                                nullable: true
                            workflow_spec:
                                type: object
                                additionalProperties: true

        # --- Runtimes ---

        CreateRuntimeRequest:
            type: object
            required: [name, agent_id]
            properties:
                name:
                    type: string
                agent_id:
                    type: string
                    format: uuid
                template:
                    type: string
                preset:
                    type: string
                image:
                    type: string
                environment:
                    type: string
                    description: Vault environment to resolve env vars from (e.g. production, preview, development)
                env_public:
                    type: object
                    additionalProperties:
                        type: string
                idle_timeout_secs:
                    type: integer
                expose_http:
                    type: boolean
                    default: false
                http_port:
                    type: integer
                slug:
                    type: string
                inbound_auth:
                    type: string
                    enum: [api_key, jwt, public]
                shell_access_enabled:
                    type: boolean
                    default: false
                shell_auth_policy:
                    type: string
                    description: Step-up auth policy for shell (e.g. password, passkey, totp)
                shell_max_session_minutes:
                    type: integer

        UpdateRuntimeRequest:
            type: object
            properties:
                name:
                    type: string
                template:
                    type: string
                preset:
                    type: string
                image:
                    type: string
                environment:
                    type: string
                    description: Vault environment to resolve env vars from
                env_public:
                    type: object
                    additionalProperties:
                        type: string
                idle_timeout_secs:
                    type: integer
                expose_http:
                    type: boolean
                http_port:
                    type: integer
                slug:
                    type: string
                inbound_auth:
                    type: string
                    enum: [api_key, jwt, public]
                shell_access_enabled:
                    type: boolean
                shell_auth_policy:
                    type: string
                shell_max_session_minutes:
                    type: integer

        RuntimeResponse:
            type: object
            required: [id, name, agent_id, status, created_at, updated_at]
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                agent_id:
                    type: string
                    format: uuid
                template:
                    type: string
                    nullable: true
                preset:
                    type: string
                    nullable: true
                provider:
                    type: string
                    nullable: true
                status:
                    type: string
                    enum: [creating, running, stopping, stopped, failed, deleting]
                image:
                    type: string
                    nullable: true
                environment:
                    type: string
                    nullable: true
                    description: Vault environment for env var resolution
                env_public:
                    type: object
                    additionalProperties:
                        type: string
                    nullable: true
                idle_timeout_secs:
                    type: integer
                    nullable: true
                expose_http:
                    type: boolean
                    nullable: true
                slug:
                    type: string
                    nullable: true
                public_url:
                    type: string
                    nullable: true
                http_port:
                    type: integer
                    nullable: true
                inbound_auth:
                    type: string
                    enum: [api_key, jwt, public]
                    nullable: true
                shell_access_enabled:
                    type: boolean
                shell_auth_policy:
                    type: string
                shell_max_session_minutes:
                    type: integer
                monthly_hours_used:
                    type: number
                    nullable: true
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        RuntimeListResponse:
            type: object
            required: [runtimes]
            properties:
                runtimes:
                    type: array
                    items:
                        $ref: "#/components/schemas/RuntimeResponse"

        SlugCheckResponse:
            type: object
            required: [available, slug]
            properties:
                available:
                    type: boolean
                slug:
                    type: string
                reason:
                    type: string
                    nullable: true

        ShellSessionRequest:
            type: object
            description: |
                Step-up credentials for an interactive shell session.
                Provide one of password, totp_code, passkey_credential, or reauth_token.
            properties:
                password:
                    type: string
                totp_code:
                    type: string
                passkey_credential:
                    type: object
                    additionalProperties: true
                reauth_token:
                    type: string
                    description: Single-use `rat_` token from POST /v1/auth/reauth (purpose runtime_shell)

        ShellSessionResponse:
            type: object
            required: [session_token, ws_url, expires_in, runtime_id, max_session_minutes]
            properties:
                session_token:
                    type: string
                ws_url:
                    type: string
                    description: WebSocket URL for the PTY terminal
                expires_in:
                    type: integer
                    format: int64
                runtime_id:
                    type: string
                    format: uuid
                max_session_minutes:
                    type: integer

        RuntimeChatRequest:
            type: object
            description: |
                Chat with the agent inside a runtime. Provide `message` and/or
                a full OpenAI-style `messages` array (ephemeral history).
            properties:
                message:
                    type: string
                    description: Latest user message
                messages:
                    type: array
                    items:
                        type: object
                        additionalProperties: true
                    description: OpenAI chat messages (optional history)
                model:
                    type: string
                provider:
                    type: string
                stream:
                    type: boolean
                    description: Request SSE streaming (default true when Accept is text/event-stream)

        # --- Agent Memory ---

        MemoryEntry:
            type: object
            required: [id, agent_id, namespace, key, value, created_at, updated_at]
            properties:
                id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                namespace:
                    type: string
                key:
                    type: string
                value:
                    type: string
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time
                ttl_expires_at:
                    type: string
                    format: date-time
                    nullable: true

        PutMemoryRequest:
            type: object
            required: [value]
            properties:
                value:
                    type: string
                ttl_seconds:
                    type: integer
                    nullable: true

        MemorySearchRequest:
            type: object
            required: [namespace, query]
            properties:
                namespace:
                    type: string
                query:
                    type: string
                top_k:
                    type: integer
                    default: 5

        MemorySearchResponse:
            type: object
            required: [results]
            properties:
                results:
                    type: array
                    items:
                        type: object
                        properties:
                            key:
                                type: string
                            value:
                                type: string
                            score:
                                type: number
                            namespace:
                                type: string

        MemoryNamespaceListResponse:
            type: object
            required: [namespaces]
            properties:
                namespaces:
                    type: array
                    items:
                        type: string

        MemoryEntryListResponse:
            type: object
            required: [entries]
            properties:
                entries:
                    type: array
                    items:
                        $ref: "#/components/schemas/MemoryEntry"

        # --- Discovery ---

        AgentCardResponse:
            type: object
            required: [id, name]
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                description:
                    type: string
                    nullable: true
                capabilities:
                    type: array
                    items:
                        type: string
                a2a_url:
                    type: string
                    nullable: true
                mcp_url:
                    type: string
                    nullable: true
                tags:
                    type: array
                    items:
                        type: string

        DirectoryEntry:
            type: object
            required: [id, name]
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                description:
                    type: string
                    nullable: true
                tags:
                    type: array
                    items:
                        type: string
                capabilities:
                    type: array
                    items:
                        type: string
                a2a_url:
                    type: string
                    nullable: true
                mcp_url:
                    type: string
                    nullable: true
                org_name:
                    type: string
                    nullable: true

        DirectoryResponse:
            type: object
            required: [agents, total, page, per_page]
            properties:
                agents:
                    type: array
                    items:
                        $ref: "#/components/schemas/DirectoryEntry"
                total:
                    type: integer
                page:
                    type: integer
                per_page:
                    type: integer

        OrgDirectoryAgent:
            type: object
            required: [id, name, intents_api_enabled, execution_intents_enabled, memory_enabled, shroud_enabled]
            properties:
                id:
                    type: string
                    format: uuid
                name:
                    type: string
                public_description:
                    type: string
                    nullable: true
                public_tags:
                    type: array
                    items:
                        type: string
                a2a_url:
                    type: string
                    nullable: true
                mcp_url:
                    type: string
                    nullable: true
                intents_api_enabled:
                    type: boolean
                execution_intents_enabled:
                    type: boolean
                memory_enabled:
                    type: boolean
                shroud_enabled:
                    type: boolean

        OrgDirectoryResponse:
            type: object
            required: [agents, total, page, page_size]
            properties:
                agents:
                    type: array
                    items:
                        $ref: "#/components/schemas/OrgDirectoryAgent"
                total:
                    type: integer
                page:
                    type: integer
                page_size:
                    type: integer

        UpdateDiscoveryRequest:
            type: object
            properties:
                discoverable:
                    type: boolean
                public_description:
                    type: string
                public_tags:
                    type: array
                    items:
                        type: string

        # ── Agent Chat ────────────────────────────────────────────────

        SendChatMessageRequest:
            type: object
            required: [message]
            properties:
                message:
                    type: string
                conversation_id:
                    type: string
                    format: uuid
                mode:
                    type: string
                model:
                    type: string
                provider:
                    type: string
                system_prompt:
                    type: string

        ChatMessageResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                conversation_id:
                    type: string
                    format: uuid
                role:
                    type: string
                content:
                    type: string
                tool_calls: {}
                tool_results: {}
                tokens_prompt:
                    type: integer
                tokens_completion:
                    type: integer
                model:
                    type: string
                created_at:
                    type: string
                    format: date-time

        ChatConversationResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                title:
                    type: string
                mode:
                    type: string
                model:
                    type: string
                provider:
                    type: string
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        ChatConversationListResponse:
            type: object
            properties:
                conversations:
                    type: array
                    items:
                        $ref: "#/components/schemas/ChatConversationResponse"

        ConversationDetailResponse:
            type: object
            properties:
                conversation:
                    $ref: "#/components/schemas/ChatConversationResponse"
                messages:
                    type: array
                    items:
                        $ref: "#/components/schemas/ChatMessageResponse"

        SendChatMessageResponse:
            type: object
            properties:
                conversation_id:
                    type: string
                    format: uuid
                message:
                    $ref: "#/components/schemas/ChatMessageResponse"

        # ── Agent Channels ────────────────────────────────────────────

        CreateChannelRequest:
            type: object
            required: [channel_type, config]
            properties:
                channel_type:
                    type: string
                    enum: [telegram, whatsapp, discord]
                channel_name:
                    type: string
                config:
                    type: object
                    additionalProperties:
                        type: string
                    description: |
                        Platform-specific config.
                        Telegram: { bot_token }.
                        WhatsApp: { phone_number_id, access_token, verify_token }.
                        Discord: { bot_token, application_id }.
                slash_commands_enabled:
                    type: boolean
                    description: |
                        Enable Hermes-compatible slash commands on this channel. When true,
                        messages starting with `/` are handled before the LLM. Commands:
                        /help, /new, /reset, /clear, /model, /mode, /personality, /retry,
                        /undo, /compress, /summarize, /stop, /status, /skills, /usage, /sethome.
                voice_transcription_enabled:
                    type: boolean
                    description: Enable voice message transcription
                sender_allowlist:
                    type: array
                    items:
                        type: string
                    description: List of allowed sender IDs
                auto_respond_enabled:
                    type: boolean
                    description: Enable auto-respond

        UpdateChannelRequest:
            type: object
            properties:
                channel_name:
                    type: string
                is_active:
                    type: boolean
                config:
                    type: object
                    additionalProperties:
                        type: string
                slash_commands_enabled:
                    type: boolean
                voice_transcription_enabled:
                    type: boolean
                sender_allowlist:
                    type: array
                    items:
                        type: string
                auto_respond_enabled:
                    type: boolean

        ChannelResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                channel_type:
                    type: string
                    enum: [telegram, whatsapp, discord]
                channel_name:
                    type: string
                webhook_path:
                    type: string
                webhook_url:
                    type: string
                is_active:
                    type: boolean
                config:
                    type: object
                    additionalProperties: true
                    nullable: true
                    description: |
                        Channel-specific configuration JSON. May include:
                        - sender_allowlist (array of strings): restrict which external senders can trigger the agent
                        - auto_respond_enabled (boolean): whether the agent auto-responds to inbound messages
                slash_commands_enabled:
                    type: boolean
                    description: |
                        Whether Hermes-compatible slash commands are enabled for this channel.
                        Commands: /help, /new, /reset, /clear, /model, /mode, /personality, /retry,
                        /undo, /compress, /summarize, /stop, /status, /skills, /usage, /sethome.
                voice_transcription_enabled:
                    type: boolean
                    description: Whether voice message transcription is enabled
                unified_conversation_id:
                    type: string
                    format: uuid
                    nullable: true
                    description: ID linking this channel to a unified cross-platform conversation
                is_home_platform:
                    type: boolean
                    description: Whether this is the agent's home platform channel
                sender_allowlist:
                    type: array
                    items:
                        type: string
                    nullable: true
                    description: List of allowed sender IDs for auto-respond
                auto_respond_enabled:
                    type: boolean
                    description: Whether auto-respond is enabled for this channel
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        ChannelListResponse:
            type: object
            properties:
                channels:
                    type: array
                    items:
                        $ref: "#/components/schemas/ChannelResponse"

        SendChannelMessageRequest:
            type: object
            required: [external_chat_id, content]
            properties:
                external_chat_id:
                    type: string
                    description: External platform chat/user ID
                content:
                    type: string
                reply_to:
                    type: string
                    description: External message ID to reply to

        ChannelMessageResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                channel_id:
                    type: string
                    format: uuid
                direction:
                    type: string
                    enum: [inbound, outbound]
                external_chat_id:
                    type: string
                external_message_id:
                    type: string
                sender_name:
                    type: string
                content:
                    type: string
                media_url:
                    type: string
                is_voice_message:
                    type: boolean
                    description: Whether this message was a voice message
                voice_file_id:
                    type: string
                    nullable: true
                    description: Telegram voice file ID
                voice_duration_secs:
                    type: integer
                    nullable: true
                    description: Duration of voice message in seconds
                transcription_status:
                    type: string
                    nullable: true
                    enum: [pending, completed, failed]
                    description: Status of voice transcription
                created_at:
                    type: string
                    format: date-time

        ChannelMessageListResponse:
            type: object
            properties:
                messages:
                    type: array
                    items:
                        $ref: "#/components/schemas/ChannelMessageResponse"

        # ── OAuth Connect ──────────────────────────────────────────────

        OAuthProviderScope:
            type: object
            properties:
                scope:
                    type: string
                label:
                    type: string
                description:
                    type: string
                default:
                    type: boolean

        OAuthProvider:
            type: object
            properties:
                slug:
                    type: string
                    description: Unique provider identifier (e.g. "github", "google", "slack")
                display_name:
                    type: string
                icon_url:
                    type: string
                    format: uri
                authorization_url:
                    type: string
                    format: uri
                token_url:
                    type: string
                    format: uri
                scopes_available:
                    type: array
                    items:
                        $ref: "#/components/schemas/OAuthProviderScope"
                default_scopes:
                    type: array
                    items:
                        type: string
                extra_auth_params:
                    type: object
                    additionalProperties:
                        type: string
                    nullable: true
                requires_app_credentials:
                    type: boolean
                    description: Whether custom app credentials are required (vs. shared 1Claw app)
                documentation_url:
                    type: string
                    format: uri
                    nullable: true

        OAuthProviderListResponse:
            type: object
            properties:
                providers:
                    type: array
                    items:
                        $ref: "#/components/schemas/OAuthProvider"

        ConnectOAuthRequest:
            type: object
            required: [provider_slug]
            properties:
                provider_slug:
                    type: string
                    description: Provider to connect (e.g. "github", "google", "slack")
                scopes:
                    type: array
                    items:
                        type: string
                    description: Override default scopes for this connection
                redirect_after:
                    type: string
                    description: URL to redirect to after the OAuth flow completes

        ConnectOAuthResponse:
            type: object
            properties:
                authorization_url:
                    type: string
                    format: uri
                    description: Redirect the user to this URL to authorize the connection

        OAuthConnectionResponse:
            type: object
            properties:
                binding_id:
                    type: string
                    format: uuid
                provider_slug:
                    type: string
                provider_name:
                    type: string
                scopes:
                    type: array
                    items:
                        type: string
                status:
                    type: string
                    enum: [active, expired, revoked]
                needs_reauth:
                    type: boolean
                created_at:
                    type: string
                    format: date-time

        OAuthConnectionListResponse:
            type: object
            properties:
                connections:
                    type: array
                    items:
                        $ref: "#/components/schemas/OAuthConnectionResponse"

        SaveOAuthAppCredentialsRequest:
            type: object
            required: [provider_slug, client_id, client_secret]
            properties:
                provider_slug:
                    type: string
                    description: Provider this credential is for
                client_id:
                    type: string
                client_secret:
                    type: string
                    description: Write-only; never returned in responses
                redirect_uri:
                    type: string
                    format: uri
                    description: Custom redirect URI override

        OAuthAppCredentialResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                provider_slug:
                    type: string
                client_id:
                    type: string
                redirect_uri:
                    type: string
                    format: uri
                    nullable: true
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        OAuthAppCredentialListResponse:
            type: object
            properties:
                credentials:
                    type: array
                    items:
                        $ref: "#/components/schemas/OAuthAppCredentialResponse"

        # -------------------------------------------------------------------
        # Key Import
        # -------------------------------------------------------------------

        ImportKeyRequest:
            type: object
            required: [private_key]
            properties:
                private_key:
                    type: string
                    description: The private key to import
                format:
                    type: string
                    enum: [hex, base64, wif]
                    description: Key format (default hex)

        # -------------------------------------------------------------------
        # Cedar Policies
        # -------------------------------------------------------------------

        CreateCedarPolicyRequest:
            type: object
            required: [name, cedar_text]
            properties:
                name:
                    type: string
                cedar_text:
                    type: string
                    description: Cedar policy text

        CedarPolicyResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                name:
                    type: string
                cedar_text:
                    type: string
                is_active:
                    type: boolean
                enforcement_status:
                    type: string
                    enum: [shadow, enforce, inactive]
                    description: Dynamic status from org policy backend config
                created_by:
                    type: string
                    format: uuid
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        CedarPolicyListResponse:
            type: object
            properties:
                policies:
                    type: array
                    items:
                        $ref: "#/components/schemas/CedarPolicyResponse"

        CedarPolicyTestRequest:
            type: object
            required: [principal_type, principal_id, action, resource_path, vault_id]
            properties:
                cedar_text:
                    type: string
                    description: Optional inline Cedar text to test
                principal_type:
                    type: string
                principal_id:
                    type: string
                    format: uuid
                action:
                    type: string
                resource_path:
                    type: string
                vault_id:
                    type: string
                    format: uuid
                context:
                    type: object

        CedarPolicyTestResponse:
            type: object
            properties:
                decision:
                    type: string
                    enum: [allow, deny]
                backend:
                    type: string
                enforcement_status:
                    type: string
                    enum: [shadow, enforce, inactive]
                note:
                    type: string

        # -------------------------------------------------------------------
        # OPA Policies
        # -------------------------------------------------------------------

        CreateOpaPolicyRequest:
            type: object
            required: [name]
            properties:
                name:
                    type: string
                rego_source:
                    type: string
                    description: OPA Rego module source
                wasm_bundle_base64:
                    type: string
                    description: Optional WASM bundle (base64)
                entrypoint:
                    type: string
                    default: oneclaw/allow

        OpaPolicyResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                name:
                    type: string
                rego_source:
                    type: string
                has_wasm_bundle:
                    type: boolean
                entrypoint:
                    type: string
                is_active:
                    type: boolean
                enforcement_status:
                    type: string
                    enum: [shadow, enforce, inactive]
                created_by:
                    type: string
                    format: uuid
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        OpaPolicyListResponse:
            type: object
            properties:
                policies:
                    type: array
                    items:
                        $ref: "#/components/schemas/OpaPolicyResponse"

        OpaPolicyTestRequest:
            type: object
            required: [principal_type, principal_id, action, resource_path, vault_id]
            properties:
                principal_type:
                    type: string
                principal_id:
                    type: string
                    format: uuid
                action:
                    type: string
                resource_path:
                    type: string
                vault_id:
                    type: string
                    format: uuid
                context:
                    type: object

        OpaPolicyTestResponse:
            type: object
            properties:
                decision:
                    type: string
                    enum: [allow, deny]
                backend:
                    type: string
                enforcement_status:
                    type: string
                    enum: [shadow, enforce, inactive]
                note:
                    type: string

        # -------------------------------------------------------------------
        # Policy Backend Settings
        # -------------------------------------------------------------------

        PolicyBackendSettingsResponse:
            type: object
            properties:
                backend:
                    type: string
                    enum: [builtin, cedar, opa, builtin+cedar, builtin+opa]
                mode:
                    type: string
                    enum: [shadow, enforce]
                scope:
                    type: array
                    items:
                        type: string
                breaker_behavior:
                    type: string
                    enum: [fail_closed, fail_open_builtin]
                policy_version:
                    type: integer
                    format: int64

        UpdatePolicyBackendSettingsRequest:
            type: object
            properties:
                backend:
                    type: string
                    enum: [builtin, cedar, opa, builtin+cedar, builtin+opa]
                mode:
                    type: string
                    enum: [shadow, enforce]
                scope:
                    type: array
                    items:
                        type: string
                breaker_behavior:
                    type: string
                    enum: [fail_closed, fail_open_builtin]

        PolicyShadowReportResponse:
            type: object
            properties:
                total_evaluated:
                    type: integer
                    format: int64
                total_divergences:
                    type: integer
                    format: int64
                total_errors:
                    type: integer
                    format: int64
                concordance_rate:
                    type: number
                    format: double
                sample_events:
                    type: array
                    items:
                        $ref: "#/components/schemas/PolicyShadowEvent"
                period_start:
                    type: string
                    format: date-time
                period_end:
                    type: string
                    format: date-time

        PolicyShadowEvent:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                backend:
                    type: string
                action:
                    type: string
                builtin_decision:
                    type: string
                backend_decision:
                    type: string
                divergent:
                    type: boolean
                sampled:
                    type: boolean
                eval_duration_ms:
                    type: integer
                error_text:
                    type: string
                caller_id:
                    type: string
                    format: uuid
                resource_path:
                    type: string
                created_at:
                    type: string
                    format: date-time

        GuardrailShadowReportResponse:
            type: object
            properties:
                org_id:
                    type: string
                    format: uuid
                since:
                    type: string
                    format: date-time
                until:
                    type: string
                    format: date-time
                total_would_deny:
                    type: integer
                    format: int64
                by_reason:
                    type: array
                    items:
                        $ref: "#/components/schemas/GuardrailShadowReasonRow"

        GuardrailShadowReasonRow:
            type: object
            properties:
                reason_code:
                    type: string
                would_deny_count:
                    type: integer
                    format: int64
                enforced_count:
                    type: integer
                    format: int64

        GuardrailRevisionListResponse:
            type: object
            properties:
                revisions:
                    type: array
                    items:
                        $ref: "#/components/schemas/GuardrailRevisionRow"

        GuardrailRevisionRow:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                resource_type:
                    type: string
                    enum: [agent, binding]
                resource_id:
                    type: string
                    format: uuid
                actor_id:
                    type: string
                    format: uuid
                before_json:
                    type: object
                    additionalProperties: true
                after_json:
                    type: object
                    additionalProperties: true
                change_kind:
                    type: string
                    enum: [narrowing, widening, neutral]
                approval_id:
                    type: string
                    format: uuid
                    nullable: true
                created_at:
                    type: string
                    format: date-time

        GuardrailReplayRequest:
            type: object
            properties:
                days:
                    type: integer
                    minimum: 1
                    maximum: 90
                draft_guardrails:
                    type: object
                    additionalProperties: true
                draft_approval_policy:
                    type: object
                    additionalProperties: true

        GuardrailReplayResponse:
            type: object
            properties:
                agent_id:
                    type: string
                    format: uuid
                window_days:
                    type: integer
                    format: int64
                allowed:
                    type: integer
                    format: int64
                denied:
                    type: integer
                    format: int64
                would_require_approval:
                    type: integer
                    format: int64
                samples:
                    type: array
                    items:
                        type: object
                        additionalProperties: true

        AgentAccountListResponse:
            type: object
            properties:
                accounts:
                    type: array
                    items:
                        $ref: "#/components/schemas/AgentAccountResponse"

        AgentAccountResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                chain:
                    type: string
                account_type:
                    type: string
                address:
                    type: string
                safe_version:
                    type: string
                modules_enabled:
                    type: array
                    items:
                        type: string
                deploy_status:
                    type: string
                cosign_enabled:
                    type: boolean
                metadata:
                    type: object
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        MigrationPlanResponse:
            type: object
            properties:
                agent_id:
                    type: string
                    format: uuid
                chain:
                    type: string
                safe_address:
                    type: string
                safe_version:
                    type: string
                modules:
                    type: array
                    items:
                        type: string
                eoa_address:
                    type: string
                sweep_instructions:
                    type: array
                    items:
                        type: object
                        properties:
                            asset:
                                type: string
                            action:
                                type: string
                            note:
                                type: string
                roles_config_hash:
                    type: string
                allowance_config_hash:
                    type: string
                warnings:
                    type: array
                    items:
                        type: string
                deploy_status:
                    type: string

        ProvisionAgentAccountRequest:
            type: object
            required: [chain]
            properties:
                chain:
                    type: string
                account_type:
                    type: string
                    default: eoa
                address:
                    type: string

        SafeModuleRegistryResponse:
            type: object
            properties:
                chain:
                    type: string
                modules:
                    type: array
                    items:
                        $ref: "#/components/schemas/SafeModuleInfo"

        SafeModuleInfo:
            type: object
            properties:
                name:
                    type: string
                address:
                    type: string
                version:
                    type: string

        AllowanceReconcileReport:
            type: object
            properties:
                org_id:
                    type: string
                    format: uuid
                agents_checked:
                    type: integer
                compiled:
                    type: array
                    items:
                        type: object
                        additionalProperties: true
                drift_detected:
                    type: array
                    items:
                        type: object
                        additionalProperties: true
                onchain_sync:
                    type: string
                    description: counterfactual when on-chain broadcast is stubbed pre-audit

        NotImplementedResponse:
            type: object
            required: [error, phase, message]
            properties:
                error:
                    type: string
                phase:
                    type: string
                message:
                    type: string

        # -------------------------------------------------------------------
        # Contract ABIs
        # -------------------------------------------------------------------

        CreateContractAbiRequest:
            type: object
            required: [chain, contract_address, abi_json]
            properties:
                chain:
                    type: string
                contract_address:
                    type: string
                    description: Contract address, or Solana program id when interface_kind is solana_idl
                abi_json:
                    description: EVM ABI JSON array, or Solana IDL object when interface_kind is solana_idl
                    oneOf:
                        - type: array
                          items:
                              type: object
                        - type: object
                name:
                    type: string
                description:
                    type: string
                token_decimals:
                    type: integer
                interface_kind:
                    type: string
                    enum: [evm_abi, solana_idl]
                    default: evm_abi

        ContractAbiResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                chain:
                    type: string
                contract_address:
                    type: string
                abi_json:
                    description: EVM ABI JSON array, or Solana IDL object
                    oneOf:
                        - type: array
                          items:
                              type: object
                        - type: object
                name:
                    type: string
                description:
                    type: string
                token_decimals:
                    type: integer
                interface_kind:
                    type: string
                    enum: [evm_abi, solana_idl]
                    default: evm_abi
                created_by:
                    type: string
                    format: uuid
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        ContractAbiListResponse:
            type: object
            properties:
                abis:
                    type: array
                    items:
                        $ref: "#/components/schemas/ContractAbiResponse"

        # -------------------------------------------------------------------
        # Consensus / Pending Approvals
        # -------------------------------------------------------------------

        TxConditions:
            type: object
            description: |
                Signing-time conditions on access policies (all tiers).
                Ignored on secret reads. Evaluated when a TransactionContext is present.
                Fields are combined according to `match_mode` (default AND).
            additionalProperties: true
            properties:
                match_mode:
                    type: string
                    enum: [all, any]
                    default: all
                    description: |
                        How individual condition fields are combined.
                        "all" (default): every present field must match (AND).
                        "any": at least one present field must match (OR).
                function_name_in:
                    type: array
                    items:
                        type: string
                function_selector_in:
                    type: array
                    items:
                        type: string
                erc20_amount_above:
                    type: string
                value_above:
                    type: string
                    description: Native value threshold in wei (arbitrary-precision string)
                eip712_primary_type_in:
                    type: array
                    items:
                        type: string
                    description: Match EIP-712 typed_data primaryType (case-sensitive)
                eip712_verifying_contract_in:
                    type: array
                    items:
                        type: string
                    description: Match EIP-712 domain.verifyingContract (case-insensitive)
                eip712_domain_name_in:
                    type: array
                    items:
                        type: string
                    description: Match EIP-712 domain.name
                eip712_domain_chain_id_in:
                    type: array
                    items:
                        type: integer
                        format: int64
                    description: Match EIP-712 domain.chainId
                eip7702_authorized_addresses_in:
                    type: array
                    items:
                        type: string
                    description: Match EIP-7702 authorization_list delegate addresses (case-insensitive)
                to_address_in:
                    type: array
                    items:
                        type: string
                chain_in:
                    type: array
                    items:
                        type: string
                intent_type_in:
                    type: array
                    items:
                        type: string
                decode_failed:
                    type: boolean
                program_id_in:
                    type: array
                    items:
                        type: string
                deep_inspect:
                    type: boolean
                    default: false
                    description: |
                        When true, conditions are also evaluated against inner calls
                        extracted from wrapper transactions (multicall, Safe execTransaction,
                        ERC-4337 handleOps). A match on any inner call counts as an overall match.
                expression:
                    type: string
                    maxLength: 1024
                    description: |
                        Mini expression DSL for policy conditions (schema version 2+).
                        References transaction context fields (chain, value_wei, to_address,
                        function_selector, etc.) with boolean operators. Fail-closed on parse
                        or evaluation errors. Example: `chain == 'ethereum' && value_wei > 1000000000000000000`

        ConsensusTrigger:
            type: object
            required: [conditions, approval]
            properties:
                conditions:
                    type: array
                    items:
                        $ref: "#/components/schemas/ConsensusCondition"
                approval:
                    $ref: "#/components/schemas/ApprovalRequirement"
                expiry_secs:
                    type: integer
                    format: int64
                    default: 86400
                self_approval_allowed:
                    type: boolean
                    default: false
                skip_when:
                    type: array
                    description: |
                        When ALL conditions in ANY entry match, consensus is bypassed.
                        Useful for exempting known-safe recipients or low-value transfers.
                    items:
                        $ref: "#/components/schemas/FlatConditionSet"
                require_when:
                    type: array
                    description: |
                        Consensus is ONLY required when at least one entry matches.
                        If set and none match, consensus is skipped entirely.
                    items:
                        $ref: "#/components/schemas/FlatConditionSet"
                deep_inspect:
                    type: boolean
                    default: false
                    description: |
                        When true, also evaluate conditions against inner calls extracted
                        from wrapper transactions (multicall, Safe execTransaction,
                        ERC-4337 handleOps).

        FlatConditionSet:
            type: object
            description: |
                Flat condition set used by consensus composability. Each present field
                is AND-combined within the set. At least one field must be specified
                (unless `always` is true).
            additionalProperties: false
            properties:
                value_above:
                    type: string
                    description: Native value threshold in gwei (numeric string)
                chain_in:
                    type: array
                    items:
                        type: string
                to_address_in:
                    type: array
                    items:
                        type: string
                function_selector_in:
                    type: array
                    items:
                        type: string
                erc20_amount_above:
                    type: string
                    description: ERC-20 raw token amount threshold (numeric string)
                intent_type_in:
                    type: array
                    items:
                        type: string
                always:
                    type: boolean
                    description: When true, this entry always matches regardless of other fields
                action_in:
                    type: array
                    items:
                        type: string
                    description: Control-plane actions to match (e.g. policy.create, signing_key.export)
                action_kind_in:
                    type: array
                    items:
                        type: string
                    description: |
                        Version-agnostic action kind groups (e.g. signing_key.*, policy.*, member.*)

        TimeWindow:
            type: object
            description: |
                Time window condition for policy evaluation. Used inside the policy
                `conditions` JSON to restrict when the policy is active.
            properties:
                start_hour:
                    type: integer
                    minimum: 0
                    maximum: 23
                end_hour:
                    type: integer
                    minimum: 0
                    maximum: 24
                days_of_week:
                    type: array
                    description: Days when policy is active (0=Sunday, 6=Saturday)
                    items:
                        type: integer
                        minimum: 0
                        maximum: 6
                timezone:
                    type: string
                    description: IANA timezone identifier (e.g. "America/New_York"). Defaults to UTC.
                cron_expr:
                    type: string
                    description: Cron expression (6-field with seconds) for fine-grained scheduling.

        ConsensusCondition:
            oneOf:
                - type: object
                  required: [type]
                  properties:
                      type:
                          type: string
                          enum: [value_above]
                      threshold_wei:
                          type: string
                          description: Value threshold in wei (arbitrary-precision string). Preferred over threshold_gwei.
                      threshold_gwei:
                          type: integer
                          format: int64
                          deprecated: true
                          description: Deprecated — use threshold_wei for arbitrary precision
                - type: object
                  required: [type, chains]
                  properties:
                      type:
                          type: string
                          enum: [chain_in]
                      chains:
                          type: array
                          items:
                              type: string
                - type: object
                  required: [type, addresses]
                  properties:
                      type:
                          type: string
                          enum: [to_address_in]
                      addresses:
                          type: array
                          items:
                              type: string
                - type: object
                  required: [type, selectors]
                  properties:
                      type:
                          type: string
                          enum: [function_selector_in]
                      selectors:
                          type: array
                          items:
                              type: string
                - type: object
                  required: [type, threshold_raw]
                  properties:
                      type:
                          type: string
                          enum: [erc20_amount_above]
                      threshold_raw:
                          type: string
                - type: object
                  required: [type, intent_types]
                  properties:
                      type:
                          type: string
                          enum: [intent_type_in]
                      intent_types:
                          type: array
                          items:
                              type: string
                - type: object
                  required: [type]
                  properties:
                      type:
                          type: string
                          enum: [always]
                - type: object
                  required: [type, actions]
                  properties:
                      type:
                          type: string
                          enum: [action_in]
                      actions:
                          type: array
                          items:
                              type: string
                          description: |
                              Control-plane actions to match, e.g. policy.create, policy.update,
                              policy.delete, signing_key.export, member.role_change, member.remove
                - type: object
                  required: [type, action_kinds]
                  properties:
                      type:
                          type: string
                          enum: [action_kind_in]
                      action_kinds:
                          type: array
                          items:
                              type: string
                          description: |
                              Version-agnostic action kind groups, e.g. signing_key.*, policy.*, member.*

        ApprovalRequirement:
            type: object
            required: [min_approvals]
            properties:
                min_approvals:
                    type: integer
                required_roles:
                    type: array
                    items:
                        type: string
                per_role_minimums:
                    type: object
                    additionalProperties:
                        type: integer
                require_credential_types:
                    type: array
                    items:
                        type: string
                        enum: [password, passkey, totp, biometric, api_key]
                    description: At least one approval must use one of these credential types

        SubmitPendingApprovalRequest:
            type: object
            required: [policy_id, action, action_payload]
            properties:
                policy_id:
                    type: string
                    format: uuid
                action:
                    type: string
                action_payload:
                    type: object

        SubmitPendingApprovalResponse:
            type: object
            properties:
                pending_approval_id:
                    type: string
                    format: uuid
                required_approvals:
                    type: integer
                current_approvals:
                    type: integer
                expires_at:
                    type: string
                    format: date-time
                status:
                    type: string
                message:
                    type: string

        ApprovePendingApprovalRequest:
            type: object
            required: [decision, payload_hash]
            properties:
                decision:
                    type: string
                    enum: [approve, reject]
                payload_hash:
                    type: string
                reason:
                    type: string
                credential_type:
                    type: string
                    enum: [password, passkey, totp, biometric, api_key]
                    description: Authentication method used for this approval vote

        PendingApprovalResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                policy_id:
                    type: string
                    format: uuid
                action:
                    type: string
                action_payload:
                    type: object
                payload_hash:
                    type: string
                submitted_by:
                    type: string
                    format: uuid
                submitted_by_type:
                    type: string
                status:
                    type: string
                required_approvals:
                    type: integer
                current_approvals:
                    type: integer
                expires_at:
                    type: string
                    format: date-time
                executed_at:
                    type: string
                    format: date-time
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time
                signatures:
                    type: array
                    items:
                        $ref: "#/components/schemas/ApprovalSignatureResponse"

        ApprovalSignatureResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                approver_id:
                    type: string
                    format: uuid
                approver_type:
                    type: string
                decision:
                    type: string
                reason:
                    type: string
                created_at:
                    type: string
                    format: date-time

        PendingApprovalListResponse:
            type: object
            properties:
                pending_approvals:
                    type: array
                    items:
                        $ref: "#/components/schemas/PendingApprovalResponse"
                total:
                    type: integer
                    format: int64

        ExecutePendingApprovalResponse:
            type: object
            properties:
                pending_approval_id:
                    type: string
                    format: uuid
                status:
                    type: string
                executed_at:
                    type: string
                    format: date-time
                result:
                    type: object

        # -------------------------------------------------------------------
        # Sub-Organizations
        # -------------------------------------------------------------------

        CreateSubOrgRequest:
            type: object
            required: [name]
            properties:
                name:
                    type: string
                    minLength: 1
                    maxLength: 128
                description:
                    type: string
                billing_model:
                    type: string
                    enum: [inherit, independent]
                    default: inherit

        SubOrgResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                parent_org_id:
                    type: string
                    format: uuid
                name:
                    type: string
                description:
                    type: string
                billing_model:
                    type: string
                status:
                    type: string
                    enum: [active, archived]
                created_at:
                    type: string
                    format: date-time

        SubOrgListResponse:
            type: object
            properties:
                sub_orgs:
                    type: array
                    items:
                        $ref: "#/components/schemas/SubOrgResponse"

        SubOrgPermissionRequest:
            type: object
            required: [permission]
            properties:
                permission:
                    type: string
                    description: "Permission to grant (e.g. vaults:read, agents:write)"
                resource_ids:
                    type: array
                    items:
                        type: string
                        format: uuid

        SubOrgAddUserRequest:
            type: object
            required: [user_id]
            properties:
                user_id:
                    type: string
                    format: uuid
                role:
                    type: string
                    enum: [admin, member, viewer]
                    default: member

        SubOrgGenerateWalletsRequest:
            type: object
            properties:
                chains:
                    type: array
                    items:
                        type: string

        # -------------------------------------------------------------------
        # Portfolio
        # -------------------------------------------------------------------

        PortfolioResponse:
            type: object
            properties:
                wallets:
                    type: array
                    items:
                        $ref: "#/components/schemas/PortfolioWalletEntry"
                total_usd_estimate:
                    type: string

        PortfolioWalletEntry:
            type: object
            properties:
                wallet_type:
                    type: string
                    enum: [treasury, signing_key, smart_account]
                chain:
                    type: string
                address:
                    type: string
                native_balance:
                    type: string
                native_balance_usd:
                    type: string
                tokens:
                    type: array
                    items:
                        $ref: "#/components/schemas/PortfolioTokenBalance"

        PortfolioTokenBalance:
            type: object
            properties:
                contract_address:
                    type: string
                symbol:
                    type: string
                name:
                    type: string
                balance:
                    type: string
                balance_usd:
                    type: string
                decimals:
                    type: integer

        # -------------------------------------------------------------------
        # Smart Account Import
        # -------------------------------------------------------------------

        ImportSmartAccountRequest:
            type: object
            required: [chain, chain_id, safe_address]
            properties:
                chain:
                    type: string
                chain_id:
                    type: integer
                safe_address:
                    type: string
                verify:
                    type: boolean
                    default: true
                    description: Verify on-chain Safe ownership

        ImportSmartAccountResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                agent_id:
                    type: string
                    format: uuid
                chain:
                    type: string
                chain_id:
                    type: integer
                safe_address:
                    type: string
                nonce:
                    type: integer
                    nullable: true
                created_at:
                    type: string
                    format: date-time

        # -------------------------------------------------------------------
        # Environment Variables
        # -------------------------------------------------------------------

        EnvVar:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                key:
                    type: string
                environments:
                    type: array
                    items:
                        type: string
                git_branch:
                    type: string
                    nullable: true
                sensitive:
                    type: boolean
                comment:
                    type: string
                    nullable: true
                value:
                    type: string
                    nullable: true
                    description: Null for sensitive vars in list responses
                version:
                    type: integer
                created_by:
                    type: string
                    nullable: true
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        CreateEnvVarRequest:
            type: object
            required: [key, value]
            properties:
                key:
                    type: string
                    description: Uppercase alphanumeric + underscore, 1-256 chars
                value:
                    type: string
                environments:
                    type: array
                    items:
                        type: string
                    default: [production, preview, development]
                git_branch:
                    type: string
                    description: Branch override (preview only)
                sensitive:
                    type: boolean
                    default: false
                comment:
                    type: string

        UpdateEnvVarRequest:
            type: object
            properties:
                value:
                    type: string
                environments:
                    type: array
                    items:
                        type: string
                sensitive:
                    type: boolean
                comment:
                    type: string

        ResolveEnvVarsResponse:
            type: object
            properties:
                vars:
                    type: object
                    additionalProperties:
                        type: string
                sources:
                    type: object
                    additionalProperties:
                        type: string
                        enum: [shared, vault, branch_override]
                environment:
                    type: string
                git_branch:
                    type: string
                    nullable: true
                resolved_at:
                    type: string
                    format: date-time

        VaultEnvironment:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                slug:
                    type: string
                description:
                    type: string
                    nullable: true
                is_builtin:
                    type: boolean
                copied_from:
                    type: string
                    nullable: true
                is_detached:
                    type: boolean
                created_at:
                    type: string
                    format: date-time

        CreateEnvironmentRequest:
            type: object
            required: [slug]
            properties:
                slug:
                    type: string
                    description: Lowercase alphanumeric + hyphens, 2-30 chars
                description:
                    type: string
                copy_from:
                    type: string
                    description: Copy env vars from this environment

        OrgEnvVar:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                key:
                    type: string
                environments:
                    type: array
                    items:
                        type: string
                sensitive:
                    type: boolean
                comment:
                    type: string
                    nullable: true
                value:
                    type: string
                    nullable: true
                version:
                    type: integer
                linked_vaults:
                    type: array
                    items:
                        type: string
                        format: uuid
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        CreateOrgEnvVarRequest:
            type: object
            required: [key, value]
            properties:
                key:
                    type: string
                value:
                    type: string
                environments:
                    type: array
                    items:
                        type: string
                    default: [production, preview, development]
                sensitive:
                    type: boolean
                    default: false
                comment:
                    type: string

        UpdateOrgEnvVarRequest:
            type: object
            properties:
                value:
                    type: string
                environments:
                    type: array
                    items:
                        type: string
                comment:
                    type: string

        # -----------------------------------------------------------------
        # Wallet Access Policy schemas
        # -----------------------------------------------------------------

        CreateWalletAccessPolicyRequest:
            type: object
            required: [scope_type, principal_type, principal_id]
            properties:
                scope_type:
                    type: string
                    enum: [wallet, platform_app, org]
                    description: Policy scope — org-wide, platform app, or single wallet
                scope_id:
                    type: string
                    format: uuid
                    nullable: true
                    description: Wallet or platform app UUID when scope_type is not org
                principal_type:
                    type: string
                    enum: [user, agent, role, platform_app]
                    description: Who receives the grant
                principal_id:
                    type: string
                    description: User/agent UUID, role name, or platform app UUID
                can_sign:
                    type: boolean
                    default: false
                can_view_balance:
                    type: boolean
                    default: true
                can_export:
                    type: boolean
                    default: false
                can_send:
                    type: boolean
                    default: false
                can_swap:
                    type: boolean
                    default: false
                allowed_chains:
                    type: array
                    items:
                        type: string
                    description: Chains this policy applies to (empty = all)
                max_value_per_tx_eth:
                    type: string
                    description: Max value per transaction in ETH
                daily_limit_eth:
                    type: string
                    description: Daily spend limit in ETH
                conditions:
                    type: object
                    description: Additional JSON conditions (reserved for future enforcement)
                expires_at:
                    type: string
                    format: date-time

        WalletAccessPolicyResponse:
            type: object
            properties:
                id:
                    type: string
                    format: uuid
                org_id:
                    type: string
                    format: uuid
                scope_type:
                    type: string
                scope_id:
                    type: string
                    format: uuid
                    nullable: true
                principal_type:
                    type: string
                principal_id:
                    type: string
                can_sign:
                    type: boolean
                can_view_balance:
                    type: boolean
                can_export:
                    type: boolean
                can_send:
                    type: boolean
                can_swap:
                    type: boolean
                allowed_chains:
                    type: array
                    items:
                        type: string
                max_value_per_tx_eth:
                    type: string
                    nullable: true
                daily_limit_eth:
                    type: string
                    nullable: true
                conditions:
                    type: object
                is_active:
                    type: boolean
                expires_at:
                    type: string
                    format: date-time
                    nullable: true
                created_by:
                    type: string
                    format: uuid
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        WalletAccessPolicyListResponse:
            type: object
            properties:
                policies:
                    type: array
                    items:
                        $ref: "#/components/schemas/WalletAccessPolicyResponse"

        # -----------------------------------------------------------------
        # Credential Recovery schemas
        # -----------------------------------------------------------------

        CredentialRecoveryRequest:
            type: object
            required: [recovery_type]
            properties:
                recovery_type:
                    type: string
                    enum: [mfa_reset, passkey_reset, password_reset]
                reason:
                    type: string
                    description: Optional justification for the recovery request

        CredentialRecoveryResponse:
            type: object
            properties:
                request_id:
                    type: string
                    format: uuid
                status:
                    type: string
                    enum: [pending_approval, approved, rejected, expired]
                recovery_type:
                    type: string
                    enum: [mfa_reset, passkey_reset, password_reset]
                created_at:
                    type: string
                    format: date-time

        CredentialRecoveryListResponse:
            type: object
            properties:
                requests:
                    type: array
                    items:
                        $ref: "#/components/schemas/CredentialRecoveryResponse"

        CredentialRecoveryApproveResponse:
            type: object
            properties:
                request_id:
                    type: string
                    format: uuid
                status:
                    type: string
                    enum: [approved]
                recovery_code:
                    type: string
                    nullable: true
                    description: One-time recovery code (only present for certain recovery types)

        CredentialRecoveryExecuteResponse:
            type: object
            properties:
                request_id:
                    type: string
                    format: uuid
                status:
                    type: string
                    enum: [executed]
                recovery_type:
                    type: string
                executed_at:
                    type: string
                    format: date-time

        CredentialRecoveryPolicyResponse:
            type: object
            properties:
                enabled:
                    type: boolean
                require_admin_approval:
                    type: boolean
                delay_hours:
                    type: integer
                    description: Waiting period before recovery takes effect
                allowed_types:
                    type: array
                    items:
                        type: string
                        enum: [mfa_reset, passkey_reset, password_reset]

        CredentialRecoveryPolicyRequest:
            type: object
            properties:
                enabled:
                    type: boolean
                require_admin_approval:
                    type: boolean
                delay_hours:
                    type: integer
                allowed_types:
                    type: array
                    items:
                        type: string
                        enum: [mfa_reset, passkey_reset, password_reset]

        # -----------------------------------------------------------------
        # Shamir KEK schemas
        # -----------------------------------------------------------------

        ShamirKekSetupRequest:
            type: object
            required: [threshold, total_shares, custodian_emails]
            properties:
                threshold:
                    type: integer
                    enum: [2, 3]
                    description: Minimum shares required to reconstruct the KEK
                total_shares:
                    type: integer
                    enum: [3, 5]
                    description: Total number of shares to generate
                custodian_emails:
                    type: array
                    items:
                        type: string
                        format: email
                    description: Email addresses of share custodians

        ShamirKekSetupResponse:
            type: object
            properties:
                kek_id:
                    type: string
                threshold:
                    type: integer
                total_shares:
                    type: integer
                shares:
                    type: array
                    description: One-time share distribution (never returned again)
                    items:
                        type: object
                        properties:
                            index:
                                type: integer
                            custodian_email:
                                type: string
                                format: email
                            share_b64:
                                type: string
                                description: Base64-encoded share
                custody_mode:
                    type: string
                created_at:
                    type: string
                    format: date-time

        ShamirKekStatusResponse:
            type: object
            properties:
                configured:
                    type: boolean
                kek_id:
                    type: string
                    nullable: true
                threshold:
                    type: integer
                    nullable: true
                total_shares:
                    type: integer
                    nullable: true
                custody_mode:
                    type: string
                    nullable: true
                custodians:
                    type: array
                    nullable: true
                    items:
                        type: object
                        properties:
                            email:
                                type: string
                                format: email
                            share_provided:
                                type: boolean
                created_at:
                    type: string
                    format: date-time
                    nullable: true

        ShamirKekReconstructRequest:
            type: object
            required: [shares]
            properties:
                shares:
                    type: array
                    items:
                        type: object
                        required: [index, share_b64]
                        properties:
                            index:
                                type: integer
                            share_b64:
                                type: string
                                description: Base64-encoded share

        ShamirKekReconstructResponse:
            type: object
            properties:
                status:
                    type: string
                    enum: [accepted, reconstructed]
                message:
                    type: string

        ShamirKekRecoveryCodesResponse:
            type: object
            properties:
                codes:
                    type: array
                    items:
                        type: string

        ShamirKekVerifyCodeRequest:
            type: object
            required: [code]
            properties:
                code:
                    type: string

        ShamirKekVerifyCodeResponse:
            type: object
            properties:
                valid:
                    type: boolean
