openapi: 3.0.3
info:
  title: FINAUTON B2B REST API
  version: 1.0.0-mvp
  description: |
    REST_API_FIRST / embedded. O backend do parceiro integra por esta API; o cliente final
    (externalUserId) não tem login FINAUTON. Conexão de provider só pela página hospedada
    (connect-sessions). Escopo vem da credencial; fora do escopo = 404. Campos controlados pela
    plataforma no corpo = 403 SCOPE_FIELD_REJECTED. Ver B2B_INTEGRATION_GUIDE.md e ERROR_CATALOG.md.
servers:
  - url: https://api.finauton.example
security:
  - basicAuth: []
tags:
  - name: health
  - name: tenants
  - name: clients
  - name: strategies
  - name: risk
  - name: providers
  - name: automation
  - name: execution
  - name: performance
  - name: billing
  - name: events
paths:
  /v1/providers:
    get:
      tags:
        - providers
      summary: Catálogo permitido ao principal (grant não implica readiness REAL)
      responses:
        '200':
          description: Providers autorizados para MARKET_READ
          content:
            application/json:
              schema:
                type: object
                properties:
                  providers:
                    type: array
                    items:
                      type: object
                      required:
                        - providerId
                        - name
                        - kind
                        - capabilities
                      properties:
                        providerId:
                          type: string
                        name:
                          type: string
                        kind:
                          type: string
                        capabilities:
                          type: array
                          items:
                            type: string
                  requestId:
                    type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_providers
  /v1/markets:
    get:
      tags:
        - providers
      summary: Mercado do provider autorizado (consulta externa; não usar no smoke sem provider)
      parameters:
        - name: providerId
          in: query
          required: true
          schema:
            type: string
            minLength: 2
        - name: symbol
          in: query
          schema:
            type: string
            minLength: 3
      responses:
        '200':
          description: market quando symbol informado; markets ativos caso contrário
          content:
            application/json:
              schema:
                type: object
                properties:
                  market:
                    type: object
                    additionalProperties: true
                  markets:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                  requestId:
                    type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_markets
  /v1/usage:
    get:
      tags:
        - health
      summary: Consumo e limites do principal autenticado
      parameters:
        - name: minutes
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 1440
            default: 60
      responses:
        '200':
          description: Janelas de consumo do principal
          content:
            application/json:
              schema:
                type: object
                properties:
                  window:
                    type: object
                    properties:
                      from:
                        type: string
                        format: date-time
                      minutes:
                        type: integer
                  totals:
                    type: object
                    properties:
                      requests:
                        type: integer
                      orders:
                        type: integer
                  limits:
                    type: object
                    properties:
                      requestsPerMinute:
                        type: integer
                      ordersPerMinute:
                        type: integer
                  buckets:
                    type: array
                    items:
                      type: object
                      properties:
                        window:
                          type: string
                          format: date-time
                        kind:
                          type: string
                          enum:
                            - REQUEST
                            - ORDER
                        count:
                          type: integer
                  requestId:
                    type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_usage
  /v1/users/{externalUserId}/accounts:
    get:
      tags:
        - providers
      summary: Metadados das contas permitidas; nunca retorna material de credencial
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: Estado local das contas (ACCOUNT_READ)
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  requestId:
                    type: string
                  accounts:
                    type: array
                    items:
                      type: object
                      properties:
                        providerId:
                          type: string
                        scheme:
                          type: string
                        configured:
                          type: boolean
                        status:
                          type: string
                          enum:
                            - CONNECTED
                            - REVOKED
                            - NOT_CONNECTED
                        capabilities:
                          type: array
                          items:
                            type: string
                        permissions:
                          type: object
                          properties:
                            canRead:
                              type: boolean
                            canFutures:
                              type: boolean
                            canWithdraw:
                              type: boolean
                        accountHint:
                          type: string
                          nullable: true
                        updatedAt:
                          type: string
                          format: date-time
                          nullable: true
                        revokedAt:
                          type: string
                          format: date-time
                          nullable: true
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_accounts
  /v1/health:
    get:
      tags:
        - health
      summary: Saúde da API e dos providers do grant
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Health'
        '401':
          $ref: '#/components/responses/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_health
  /v1/tenants:
    get:
      tags:
        - tenants
      summary: Lista os tenants do parceiro
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  tenants:
                    type: array
                    items:
                      $ref: '#/components/schemas/Tenant'
                  requestId:
                    type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_tenants
  /v1/tenants/{tenantId}:
    get:
      tags:
        - tenants
      parameters:
        - $ref: '#/components/parameters/TenantId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  tenant:
                    $ref: '#/components/schemas/Tenant'
        '404':
          $ref: '#/components/responses/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_tenants_tenantId
  /v1/tenants/{tenantId}/restrictions:
    put:
      tags:
        - tenants
      summary: Restringe o próprio tenant dentro do grant (nunca amplia)
      parameters:
        - $ref: '#/components/parameters/TenantId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - reason
              properties:
                providers:
                  type: array
                  nullable: true
                  items:
                    type: string
                    enum:
                      - BINANCE
                      - HYPERLIQUID
                strategies:
                  type: array
                  nullable: true
                  items:
                    type: string
                envelope:
                  type: object
                  nullable: true
                  additionalProperties: false
                  properties:
                    maxLeverage:
                      type: number
                      minimum: 0
                    maxMarginPerTradeUsd:
                      type: number
                      minimum: 0
                    maxConcurrentTrades:
                      type: number
                      minimum: 0
                    maxDailyLossUsd:
                      type: number
                      minimum: 0
                reason:
                  type: string
                  minLength: 3
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  tenant:
                    $ref: '#/components/schemas/Tenant'
                  requestId:
                    type: string
        '403':
          description: GRANT_ESCALATION | RISK_ENVELOPE_EXCEEDED | SCOPE_FIELD_REJECTED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          $ref: '#/components/responses/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: put_v1_tenants_tenantId_restrictions
  /v1/strategies:
    get:
      tags:
        - strategies
      summary: Catálogo publicado concedido ao parceiro
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  strategies:
                    type: array
                    items:
                      type: object
                      properties:
                        strategyId:
                          type: string
                        version:
                          type: string
                        status:
                          type: string
                        displayName:
                          type: string
                        summary:
                          type: string
                        supportedProviders:
                          type: array
                          items:
                            type: string
                        supportedMarkets:
                          type: array
                          items:
                            type: string
                        configurableParameters:
                          type: array
                          items:
                            type: object
                            properties:
                              key:
                                type: string
                              type:
                                type: string
                              label:
                                type: string
                              min:
                                type: number
                              max:
                                type: number
                              options:
                                type: array
                                items:
                                  type: string
                              default:
                                oneOf:
                                  - type: string
                                  - type: number
                                  - type: boolean
                        riskRequirements:
                          type: object
                          additionalProperties: true
                  requestId:
                    type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_strategies
  /v1/users:
    get:
      tags:
        - clients
      parameters:
        - name: tenantId
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
            enum:
              - ACTIVE
              - SUSPENDED
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 100
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items:
                      $ref: '#/components/schemas/Client'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users
    post:
      tags:
        - clients
      summary: Cria/upsert cliente (idempotente pelo par parceiro+externalUserId)
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - externalUserId
              properties:
                externalUserId:
                  $ref: '#/components/schemas/ExternalUserId'
                tenantId:
                  type: string
                  description: Opcional. Sem ele, o cliente entra no contrato único do parceiro (tenant principal, id igual ao do parceiro). Só é obrigatório para parceiro antigo com vários tenants (400 TENANT_REQUIRED).
      responses:
        '201':
          description: Criado ou já existente
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Client'
                  - type: object
                    properties:
                      created:
                        type: boolean
        '400':
          description: TENANT_REQUIRED | IDEMPOTENCY_KEY_REQUIRED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          $ref: '#/components/responses/Error'
        '409':
          description: TENANT_MISMATCH | IDEMPOTENCY_CONFLICT
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_users
  /v1/users/{externalUserId}:
    get:
      tags:
        - clients
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  status:
                    type: string
                  automations:
                    type: array
                    items:
                      $ref: '#/components/schemas/AutomationSummary'
        '404':
          $ref: '#/components/responses/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId
  /v1/users/{externalUserId}/status:
    get:
      tags:
        - clients
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: Conexões, setup, comercial, automações e posições abertas
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  status:
                    type: string
                  access:
                    type: object
                    properties:
                      active:
                        type: boolean
                  strategies:
                    type: array
                    items:
                      type: string
                  providers:
                    type: array
                    items:
                      type: object
                      properties:
                        providerId:
                          type: string
                        connection:
                          type: string
                        setup:
                          type: object
                          additionalProperties: true
                          nullable: true
                        commercial:
                          $ref: '#/components/schemas/Commercial'
                  automations:
                    type: array
                    items:
                      type: object
                      properties:
                        providerId:
                          type: string
                        strategyId:
                          type: string
                        enabled:
                          type: boolean
                  openPositions:
                    type: number
        '404':
          $ref: '#/components/responses/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_status
  /v1/users/{externalUserId}/commercial:
    get:
      tags:
        - clients
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  clientStatus:
                    type: string
                  providers:
                    type: array
                    items:
                      $ref: '#/components/schemas/Commercial'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_commercial
  /v1/users/{externalUserId}/suspend:
    post:
      tags:
        - clients
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      requestBody:
        $ref: '#/components/requestBodies/Reason'
      responses:
        '200':
          description: Suspenso
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Client'
                  - type: object
                    properties:
                      requestId:
                        type: string
                      updatedAt:
                        type: string
        '404':
          $ref: '#/components/responses/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_users_externalUserId_suspend
  /v1/users/{externalUserId}/reactivate:
    post:
      tags:
        - clients
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      requestBody:
        $ref: '#/components/requestBodies/Reason'
      responses:
        '200':
          description: Reativado (todos os portões continuam valendo)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Client'
                  - type: object
                    properties:
                      requestId:
                        type: string
                      updatedAt:
                        type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_users_externalUserId_reactivate
  /v1/users/{externalUserId}/strategies:
    get:
      tags:
        - strategies
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  granted:
                    type: array
                    items:
                      type: string
                  selected:
                    type: array
                    items:
                      type: string
                  selectionMode:
                    type: string
                    enum:
                      - ALL_GRANTED
                      - EXPLICIT
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_strategies
    put:
      tags:
        - strategies
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - strategyIds
              properties:
                strategyIds:
                  type: array
                  nullable: true
                  items:
                    type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  selected:
                    type: array
                    items:
                      type: string
                    nullable: true
                  selectionMode:
                    type: string
        '403':
          description: GRANT_ESCALATION | STRATEGY_NOT_AVAILABLE | SCOPE_FIELD_REJECTED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: put_v1_users_externalUserId_strategies
  /v1/users/{externalUserId}/setup:
    get:
      tags:
        - risk
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: providerId
          in: query
          required: true
          schema:
            type: string
            enum:
              - BINANCE
              - HYPERLIQUID
      responses:
        '200':
          description: Setup + safety + setupStatus
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SetupView'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_setup
    put:
      tags:
        - risk
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Setup'
      responses:
        '200':
          description: Gravado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SetupView'
        '403':
          description: PAPER_NOT_GRANTED | PROVIDER_NOT_GRANTED | RISK_ENVELOPE_EXCEEDED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: RISK_ACK_REQUIRED | API_NOT_CONFIGURED | DAILY_LOSS_HALT
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: put_v1_users_externalUserId_setup
  /v1/users/{externalUserId}/setup/preview:
    post:
      tags:
        - risk
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Setup'
      responses:
        '200':
          description: safety {fingerprint, required, flags[]} (não grava)
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  providerId:
                    type: string
                  safety:
                    $ref: '#/components/schemas/Safety'
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_users_externalUserId_setup_preview
  /v1/users/{externalUserId}/risk:
    put:
      tags:
        - risk
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - providerId
                - maxConcurrentTrades
                - maxMarginPerTradeUsd
                - maxDailyLossUsd
              properties:
                providerId:
                  type: string
                maxConcurrentTrades:
                  type: integer
                  minimum: 1
                  maximum: 3
                  description: Configurável de 1 a 3 no B2B (release P0/P1/P2); operação REAL admite 1 posição simultânea.
                maxMarginPerTradeUsd:
                  type: number
                maxDailyLossUsd:
                  type: number
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SetupView'
        default:
          $ref: '#/components/responses/Error'
      operationId: put_v1_users_externalUserId_risk
  /v1/users/{externalUserId}/providers:
    get:
      tags:
        - providers
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  providers:
                    type: array
                    items:
                      $ref: '#/components/schemas/ProviderStatus'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_providers
  /v1/users/{externalUserId}/connect-sessions:
    post:
      tags:
        - providers
      summary: Cria sessão de conexão hospedada (uso único, 15 min)
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - providerId
              properties:
                providerId:
                  type: string
                  enum:
                    - BINANCE
                    - HYPERLIQUID
                returnUrl:
                  type: string
                  description: https, de origem registrada pelo FINAUTON para o tenant
                purpose:
                  type: string
                  enum:
                    - CONNECT
                    - BUILDER_APPROVAL
                  default: CONNECT
      responses:
        '201':
          description: Sessão criada
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ConnectSession'
                  - type: object
                    properties:
                      connectUrl:
                        type: string
                        description: Não registrar em log
        '403':
          description: PROVIDER_NOT_GRANTED | RETURN_URL_NOT_ALLOWED | CLIENT_SUSPENDED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_users_externalUserId_connect_sessions
  /v1/users/{externalUserId}/connect-sessions/{sessionId}:
    get:
      tags:
        - providers
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: sessionId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConnectSession'
        '404':
          $ref: '#/components/responses/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_connect_sessions_sessionId
  /v1/users/{externalUserId}/accounts/{provider}/test:
    post:
      tags:
        - providers
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: provider
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: success, latencyMs, permissions (sem segredo)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountTest'
        '400':
          $ref: '#/components/responses/Error'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountTest'
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_users_externalUserId_accounts_provider_test
  /v1/users/{externalUserId}/accounts/{provider}:
    delete:
      tags:
        - providers
      summary: Revoga a conexão no FINAUTON (bloqueia novas entradas; preserva histórico)
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: provider
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
        default:
          $ref: '#/components/responses/Error'
      operationId: delete_v1_users_externalUserId_accounts_provider
    put:
      tags:
        - providers
      deprecated: true
      summary: LEGADO — segredo no corpo. Cliente de tenant recebe 403 HOSTED_CONNECT_REQUIRED.
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: provider
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '403':
          $ref: '#/components/responses/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: put_v1_users_externalUserId_accounts_provider
  /v1/users/{externalUserId}/automation:
    get:
      tags:
        - automation
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: 'Por provider: newEntries ALLOWED|BLOCKED, blockReason, positionMaintenance CONTINUES'
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  providers:
                    type: array
                    items:
                      type: object
                      properties:
                        providerId:
                          type: string
                        setupEnabled:
                          type: boolean
                        mode:
                          type: string
                          nullable: true
                        haltedToday:
                          type: boolean
                        automation:
                          type: object
                          additionalProperties: true
                          nullable: true
                        newEntries:
                          type: string
                          enum:
                            - ALLOWED
                            - BLOCKED
                        blockReason:
                          type: string
                          nullable: true
                          description: >-
                            Primeiro portão que impede nova entrada. Valores: CLIENT_SUSPENDED, B2B_ACCESS_SUSPENDED,
                            reasonCode comercial (ex. OBLIGATION_OVERDUE, INITIAL_SUBSCRIPTION_PAYMENT_REQUIRED),
                            SETUP_DISABLED, AUTOMATION_OFF, STRATEGY_VERSION_INCOMPATIBLE, PAPER_NOT_GRANTED,
                            SETUP_INCOMPLETE, RISK_ACK_REQUIRED, STRATEGY_NOT_SELECTED, DAILY_LOSS_HALT,
                            ENTRY_CIRCUIT_OPEN, ASSET_POLICY_REQUIRED, POSITION_COUNT_CAP, DAILY_RISK_EXHAUSTED,
                            API_NOT_CONFIGURED, BUILDER_APPROVAL_REQUIRED, READINESS_UNKNOWN. Trate valores novos
                            como bloqueio. READINESS_UNKNOWN = não foi possível avaliar (estado conservador).
                        blockDetail:
                          type: string
                          nullable: true
                          description: >-
                            Detalhe do bloqueio quando houver (ex. motivo do circuito como RECONCILIATION_UNRESOLVED,
                            códigos de SETUP_INCOMPLETE, BUILDER_APPROVAL_UNVERIFIED).
                        positionMaintenance:
                          type: string
                          enum:
                            - CONTINUES
        default:
          $ref: '#/components/responses/Error'
      description: >-
        newEntries reflete os portões de admissão avaliáveis sem enviar ordem (estado do cliente e do contrato,
        setup, aceite de risco, trava e orçamento diário, circuit breaker, política de ativo, vagas e, na
        Hyperliquid, aprovação do Builder Fee). Portões do instante da entrada (book, spread, slippage, teto
        agregado, distribuição da call, posições externas) ainda podem recusar uma entrada com ALLOWED.
        Na dúvida a resposta é BLOCKED, nunca ALLOWED.
      operationId: get_v1_users_externalUserId_automation
    put:
      tags:
        - automation
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - providerId
                - strategyId
                - enabled
                - risk
              properties:
                providerId:
                  type: string
                strategyId:
                  type: string
                enabled:
                  type: boolean
                risk:
                  type: object
                  required:
                    - leverage
                    - maxMarginPerTradeUsd
                    - maxConcurrentTrades
                    - maxDailyLossUsd
                  properties:
                    leverage:
                      type: integer
                    maxMarginPerTradeUsd:
                      type: number
                    maxConcurrentTrades:
                      type: integer
                    maxDailyLossUsd:
                      type: number
                conditions:
                  type: object
                  properties:
                    symbols:
                      type: array
                      items:
                        type: string
                    tradingWindowUtc:
                      type: object
                      properties:
                        from:
                          type: integer
                        to:
                          type: integer
                    minConfidence:
                      type: number
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  automation:
                    $ref: '#/components/schemas/AutomationSummary'
        '403':
          description: STRATEGY_NOT_GRANTED | PROVIDER_NOT_GRANTED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: put_v1_users_externalUserId_automation
  /v1/users/{externalUserId}/intents:
    get:
      tags:
        - execution
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: status
          in: query
          schema:
            type: string
            enum:
              - OPEN
              - ALL
            default: OPEN
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  intents:
                    type: array
                    items:
                      type: object
                      properties:
                        intentId:
                          type: string
                        type:
                          type: string
                        providerId:
                          type: string
                        symbol:
                          type: string
                          nullable: true
                        side:
                          type: string
                          nullable: true
                        quantity:
                          type: number
                          nullable: true
                        status:
                          type: string
                        executedQuantity:
                          type: number
                        executedPrice:
                          type: number
                          nullable: true
                        errorCode:
                          type: string
                          nullable: true
                        createdAt:
                          type: string
                        finalizedAt:
                          type: string
                          nullable: true
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_intents
  /v1/users/{externalUserId}/execution-status:
    get:
      tags:
        - execution
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: Posições com protection.status PROTECTED|PROTECTION_DEGRADED|PROVIDER_ACCESS_LOST|UNKNOWN
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  providers:
                    type: array
                    items:
                      type: object
                      properties:
                        providerId:
                          type: string
                        access:
                          type: string
                        reasonCode:
                          type: string
                  positions:
                    type: array
                    items:
                      type: object
                      properties:
                        positionId:
                          type: string
                        providerId:
                          type: string
                        symbol:
                          type: string
                        side:
                          type: string
                        mode:
                          type: string
                        quantity:
                          type: number
                        entryPrice:
                          type: number
                        leverage:
                          type: number
                        protection:
                          type: object
                          properties:
                            status:
                              type: string
                            stopLossPrice:
                              type: number
                              nullable: true
                            takeProfitPrice:
                              type: number
                              nullable: true
                            reason:
                              type: string
                              nullable: true
                        settlement:
                          type: object
                          additionalProperties: true
                        openedAt:
                          type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_execution_status
  /v1/users/{externalUserId}/positions:
    get:
      tags:
        - execution
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: providerId
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_positions
  /v1/users/{externalUserId}/account:
    get:
      tags:
        - execution
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: providerId
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_account
  /v1/orders/prepare:
    post:
      tags:
        - execution
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExecutionInput'
      responses:
        '200':
          description: Intent
          content:
            application/json:
              schema:
                type: object
                properties:
                  intent:
                    type: object
                    properties:
                      intentId:
                        type: string
                      providerId:
                        type: string
                      type:
                        type: string
                      symbol:
                        type: string
                        nullable: true
                      side:
                        type: string
                        nullable: true
                      orderType:
                        type: string
                        nullable: true
                      quantity:
                        type: number
                        nullable: true
                      price:
                        type: number
                        nullable: true
                      leverage:
                        type: number
                        nullable: true
                      reduceOnly:
                        type: boolean
                      status:
                        type: string
                  requestId:
                    type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_orders_prepare
  /v1/orders/execute:
    post:
      tags:
        - execution
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExecutionInput'
      responses:
        '200':
          description: Resultado da execução
          content:
            application/json:
              schema:
                type: object
                properties:
                  execution:
                    type: object
                    additionalProperties: true
                  requestId:
                    type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_orders_execute
  /v1/orders/{intentId}:
    get:
      tags:
        - execution
      parameters:
        - name: intentId
          in: path
          required: true
          schema:
            type: string
        - name: externalUserId
          in: query
          required: true
          schema:
            type: string
        - name: providerId
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Status da intenção
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IntentStatus'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_orders_intentId
  /v1/orders/{intentId}/reconcile:
    post:
      tags:
        - execution
      parameters:
        - name: intentId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Reconciliação + status
          content:
            application/json:
              schema:
                type: object
                properties:
                  reconciliation:
                    type: object
                    additionalProperties: true
                  intent:
                    $ref: '#/components/schemas/IntentStatus'
                  requestId:
                    type: string
        default:
          $ref: '#/components/responses/Error'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                externalUserId:
                  $ref: '#/components/schemas/ExternalUserId'
                providerId:
                  type: string
              required:
                - externalUserId
                - providerId
      operationId: post_v1_orders_intentId_reconcile
  /v1/users/{externalUserId}/performance:
    get:
      tags:
        - performance
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: current (LIVE_ESTIMATE) + closedStatements
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  current:
                    type: object
                    properties:
                      status:
                        type: string
                        enum:
                          - LIVE_ESTIMATE
                          - NO_CONTRACT
                      contract:
                        type: object
                        additionalProperties: true
                        nullable: true
                      periodStart:
                        type: string
                      periodEnd:
                        type: string
                      providers:
                        type: array
                        items:
                          type: object
                          additionalProperties: true
                  closedStatements:
                    type: array
                    items:
                      $ref: '#/components/schemas/Statement'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_performance
  /v1/users/{externalUserId}/statements:
    get:
      tags:
        - performance
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  statements:
                    type: array
                    items:
                      $ref: '#/components/schemas/Statement'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_statements
  /v1/users/{externalUserId}/billing:
    get:
      tags:
        - billing
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: status ACTIVE|DUE|GRACE|SUSPENDED, policy, builder, payment, openObligations
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  status:
                    type: string
                    enum:
                      - ACTIVE
                      - DUE
                      - GRACE
                      - SUSPENDED
                  policy:
                    type: object
                    properties:
                      contractId:
                        type: string
                      version:
                        type: number
                      effectiveFrom:
                        type: string
                      suspended:
                        type: boolean
                      subscriptionMonthlyUsd:
                        type: number
                      subscriptionProviders:
                        type: array
                        items:
                          type: string
                      currency:
                        type: string
                      performanceFeePercent:
                        type: number
                      performancePeriod:
                        type: string
                      carryPolicy:
                        type: string
                      dueDays:
                        type: number
                      graceHours:
                        type: number
                    nullable: true
                  builder:
                    type: object
                    properties:
                      source:
                        type: string
                      version:
                        type: number
                      feeTenthsBps:
                        type: number
                    nullable: true
                  providerCurrencies:
                    type: object
                    description: Moeda de novas cobranças por provider; documentos emitidos preservam a moeda original.
                    properties:
                      BINANCE:
                        type: string
                        enum: [USDT]
                      HYPERLIQUID:
                        type: string
                        enum: [USDC]
                  payment:
                    type: object
                    properties:
                      networks:
                        type: array
                        items:
                          type: string
                      tokens:
                        type: array
                        items:
                          type: string
                    nullable: true
                  openObligations:
                    type: array
                    items:
                      $ref: '#/components/schemas/Obligation'
                  newEntriesBlockedBy:
                    type: array
                    items:
                      type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_billing
  /v1/users/{externalUserId}/obligations:
    get:
      tags:
        - billing
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  obligations:
                    type: array
                    items:
                      $ref: '#/components/schemas/Obligation'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_obligations
  /v1/users/{externalUserId}/deposit-invoices:
    get:
      tags:
        - billing
      summary: Faturas de depósito por endereço exclusivo (últimas 30)
      description: Somente leitura, no escopo do cliente do tenant. O endereço só aparece depois que a fatura sai de PREPARING. Valores em unidades do token (string decimal). Sem identificadores internos — o escopo vem de externalUserId/tenantId do envelope (userId, partner e tenant removidos do objeto da fatura).
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  invoices:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        obligationId:
                          type: string
                          nullable: true
                        purpose:
                          type: string
                        source:
                          type: string
                        networkId:
                          type: string
                        tokenSymbol:
                          type: string
                        tokenAddress:
                          type: string
                        address:
                          type: string
                          nullable: true
                        expected:
                          type: string
                        received:
                          type: string
                        remaining:
                          type: string
                        credit:
                          type: string
                        status:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                        paymentInstruction:
                          type: string
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_deposit_invoices
  /v1/users/{externalUserId}/obligations/{obligationId}/payment-instructions:
    post:
      tags:
        - billing
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: obligationId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - networkId
                    - token
                    - payerAddress
                  properties:
                    method:
                      type: string
                      enum:
                        - EVM_TRANSFER
                      default: EVM_TRANSFER
                    networkId:
                      type: string
                      example: arbitrum
                    token:
                      type: string
                      enum:
                        - USDT
                        - USDC
                    payerAddress:
                      type: string
                      pattern: ^0x[0-9a-fA-F]{40}$
                    amountUsd:
                      type: number
                      exclusiveMinimum: true
                      minimum: 0
                      description: Pagamento parcial opcional (USD); o saldo restante segue aberto. Sem o campo, valor integral em aberto.
                - type: object
                  additionalProperties: false
                  required:
                    - method
                  description: Pagamento assinado pela carteira PRINCIPAL do cliente na página FIN (usdSend). Não é débito automático.
                  properties:
                    method:
                      type: string
                      enum:
                        - HYPERLIQUID_USD_SEND
                    returnUrl:
                      type: string
                    amountUsd:
                      type: number
                      exclusiveMinimum: true
                      minimum: 0
                      description: Pagamento parcial opcional (USD).
                - type: object
                  additionalProperties: false
                  required:
                    - method
                    - networkId
                  description: Fatura com endereço exclusivo de depósito (o cliente transfere para o endereço da fatura).
                  properties:
                    method:
                      type: string
                      enum:
                        - DEPOSIT_INVOICE
                    networkId:
                      type: string
                      enum:
                        - bnb
                        - arbitrum
      responses:
        '201':
          description: 'Instrução (EVM: valor exato + destino; HYPERLIQUID_USD_SEND: + paymentUrl e paymentSession; DEPOSIT_INVOICE: invoice)'
          content:
            application/json:
              schema:
                type: object
                properties:
                  invoice:
                    type: object
                    additionalProperties: true
                    description: 'Só DEPOSIT_INVOICE: mesmo objeto de GET …/deposit-invoices, sem identificadores internos'
                  payment:
                    $ref: '#/components/schemas/Payment'
                  instructions:
                    type: string
                  paymentUrl:
                    type: string
                    description: 'Só HYPERLIQUID_USD_SEND: página FIN (token no fragmento, 15 min, uso único)'
                  paymentSession:
                    type: object
        '400':
          description: >-
            RECIPIENT_NOT_CONFIGURED | NETWORK_NOT_ENABLED | TOKEN_NOT_SUPPORTED | CURRENCY_MISMATCH | API_NOT_CONFIGURED |
            RETURN_URL_NOT_ALLOWED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_users_externalUserId_obligations_obligationId_payment_instructions
  /v1/users/{externalUserId}/payments/{paymentId}:
    get:
      tags:
        - billing
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: paymentId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  payment:
                    $ref: '#/components/schemas/Payment'
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_users_externalUserId_payments_paymentId
  /v1/users/{externalUserId}/payments/{paymentId}/confirm:
    post:
      tags:
        - billing
      summary: Informa o txHash; a verificação on-chain do FINAUTON decide
      parameters:
        - $ref: '#/components/parameters/ExternalUserId'
        - name: paymentId
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - txHash
              properties:
                txHash:
                  type: string
                  pattern: ^0x[0-9a-fA-F]{64}$
      responses:
        '200':
          description: Confirmado (code null) ou quitado com excedente em revisão manual (code PAYMENT_OVERPAID_MANUAL_REVIEW, sem crédito automático)
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  payment:
                    $ref: '#/components/schemas/Payment'
                  credited:
                    type: boolean
                  code:
                    type: string
                    nullable: true
                  message:
                    type: string
        '202':
          description: 'Não creditado ainda: code PAYMENT_AWAITING_CONFIRMATIONS | PAYMENT_UNDERPAID | PAYMENT_WRONG_*'
          content:
            application/json:
              schema:
                type: object
                properties:
                  externalUserId:
                    type: string
                  tenantId:
                    type: string
                    nullable: true
                  requestId:
                    type: string
                  payment:
                    $ref: '#/components/schemas/Payment'
                  credited:
                    type: boolean
                  code:
                    type: string
                    nullable: true
                  message:
                    type: string
        '400':
          description: PAYMENT_METHOD_MISMATCH (pagamento HYPERLIQUID_USD_SEND é verificado pelo FIN) | INVALID_TX_HASH
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: TX_ALREADY_USED | PAYMENT_EXPIRED | TX_MISMATCH
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          $ref: '#/components/responses/Error'
      operationId: post_v1_users_externalUserId_payments_paymentId_confirm
  /v1/events:
    get:
      tags:
        - events
      parameters:
        - name: after
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 100
        - name: type
          in: query
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  events:
                    type: array
                    items:
                      $ref: '#/components/schemas/Event'
                  next:
                    type: string
                    nullable: true
        default:
          $ref: '#/components/responses/Error'
      operationId: get_v1_events
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: clientId:clientSecret (ou X-Client-Id/X-Client-Secret)
  parameters:
    ExternalUserId:
      name: externalUserId
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/ExternalUserId'
    TenantId:
      name: tenantId
      in: path
      required: true
      schema:
        type: string
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema:
        type: string
        pattern: ^[A-Za-z0-9._:-]{8,128}$
  requestBodies:
    Reason:
      required: true
      content:
        application/json:
          schema:
            type: object
            additionalProperties: false
            required:
              - reason
            properties:
              reason:
                type: string
                minLength: 3
                maxLength: 500
  responses:
    Error:
      description: Erro
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    ExternalUserId:
      type: string
      minLength: 1
      maxLength: 120
    Error:
      type: object
      properties:
        error:
          type: object
          required:
            - code
            - message
            - requestId
          properties:
            code:
              type: string
            message:
              type: string
            requestId:
              type: string
    Health:
      type: object
      properties:
        api:
          type: string
          enum:
            - UP
        providers:
          type: array
          items:
            type: object
            properties:
              providerId:
                type: string
              status:
                type: string
              realExecution:
                type: string
                enum:
                  - ENABLED
                  - NOT_VALIDATED
    Tenant:
      type: object
      properties:
        tenantId:
          type: string
        name:
          type: string
        status:
          type: string
          enum:
            - ACTIVE
            - SUSPENDED
        grants:
          type: object
          properties:
            providers:
              type: array
              items:
                type: string
            strategies:
              type: array
              items:
                type: string
            capabilities:
              type: array
              items:
                type: string
        partnerRestrictions:
          type: object
          nullable: true
        returnUrlOrigins:
          type: array
          items:
            type: string
        contract:
          type: object
          nullable: true
          properties:
            version:
              type: integer
            suspended:
              type: boolean
            subscriptionMonthlyUsd:
              type: number
            currency:
              type: string
            performanceFeePercent:
              type: number
            performancePeriod:
              type: string
              enum:
                - WEEKLY
                - MONTHLY
            carryPolicy:
              type: string
              enum:
                - CARRY
                - NO_CARRY
        clients:
          type: integer
    Client:
      type: object
      properties:
        externalUserId:
          type: string
        tenantId:
          type: string
          nullable: true
        status:
          type: string
          enum:
            - ACTIVE
            - SUSPENDED
        createdAt:
          type: string
          format: date-time
    Commercial:
      type: object
      properties:
        providerId:
          type: string
        allowed:
          type: boolean
        state:
          type: string
        reasonCode:
          type: string
        graceUntil:
          type: string
          nullable: true
        source:
          type: string
    Setup:
      type: object
      required:
        - providerId
        - mode
        - enabled
        - leverage
        - orderSizeUsd
        - maxConcurrentTrades
        - maxMarginPerTradeUsd
        - maxDailyLossUsd
      properties:
        providerId:
          type: string
          enum:
            - BINANCE
            - HYPERLIQUID
        mode:
          type: string
          enum:
            - REAL
          description: PAPER não é oferecido no B2B (PAPER_NOT_GRANTED)
        enabled:
          type: boolean
        leverage:
          type: integer
          minimum: 1
        orderSizeUsd:
          type: number
        maxConcurrentTrades:
          type: integer
          minimum: 1
          maximum: 3
          description: Configurável de 1 a 3 no B2B (release P0/P1/P2); a operação REAL admite 1 posição simultânea por conta. Valores acima de 3 → 400 VALIDATION_ERROR.
        maxMarginPerTradeUsd:
          type: number
        maxDailyLossUsd:
          type: number
        capitalBase:
          type: number
        maxLossPerTrade:
          type: number
        entryTimeoutMinutes:
          type: integer
        allowedSymbols:
          type: array
          items:
            type: string
        autoStopLoss:
          type: boolean
        autoTakeProfit:
          type: boolean
        autoBreakEven:
          type: boolean
        riskAcknowledgement:
          type: object
          properties:
            fingerprint:
              type: string
            codes:
              type: array
              items:
                type: string
    ProviderStatus:
      type: object
      properties:
        providerId:
          type: string
        connectionScheme:
          type: string
          enum:
            - API_KEY
            - AGENT_WALLET
        connectionFlow:
          type: string
          enum:
            - HOSTED
            - DIRECT_LEGACY
        connection:
          type: string
          enum:
            - NOT_CONNECTED
            - CONNECT_PENDING
            - CONNECTED
            - ACCESS_LOST
            - RECOVERING
            - REVOKED
        permissions:
          type: object
          nullable: true
          properties:
            canRead:
              type: boolean
            canFutures:
              type: boolean
            canWithdraw:
              type: boolean
        eligibleForNewEntries:
          type: boolean
        commercial:
          $ref: '#/components/schemas/Commercial'
        builder:
          type: object
          nullable: true
          properties:
            required:
              type: boolean
            feeTenthsBps:
              type: integer
            approvedByUser:
              type: boolean
              nullable: true
              description: Consulta maxBuilderFee na Hyperliquid; null significa desconhecido, nunca aprovação implícita.
            approvalStatus:
              type: string
              enum: [APPROVED, REQUIRED, UNKNOWN, NOT_CONNECTED]
            approvedMaxFeeTenthsBps:
              type: number
              nullable: true
            approvalRequiredFromWallet:
              type: boolean
    ConnectSession:
      type: object
      properties:
        sessionId:
          type: string
        externalUserId:
          type: string
        providerId:
          type: string
        scheme:
          type: string
          enum:
            - API_KEY
            - AGENT_WALLET
        purpose:
          type: string
          enum:
            - CONNECT
            - BUILDER_APPROVAL
        status:
          type: string
          enum:
            - PENDING
            - CONNECTED
            - FAILED
            - EXPIRED
            - CANCELLED
        failureCode:
          type: string
          nullable: true
        opened:
          type: boolean
        expiresAt:
          type: string
          format: date-time
        completedAt:
          type: string
          format: date-time
          nullable: true
    Statement:
      type: object
      properties:
        statementId:
          type: string
        kind:
          type: string
          enum:
            - ORIGINAL
            - ADJUSTMENT
        status:
          type: string
          enum:
            - CLOSED
        adjustsStatementId:
          type: string
          nullable: true
        providerId:
          type: string
        contractId:
          type: string
        contractVersion:
          type: integer
        period:
          type: string
          enum:
            - WEEKLY
            - MONTHLY
        policy:
          type: string
          enum:
            - CARRY
            - NO_CARRY
        periodStart:
          type: string
          format: date-time
        periodEnd:
          type: string
          format: date-time
        basis:
          type: string
          enum:
            - CANONICAL_NET_REALIZED_PNL
        providerNetRealizedPnlUsd:
          type: number
          description: 'BASE FINANCEIRA: Σ resultado líquido realizado canônico (normalizado no servidor). Não recalcular.'
        auditComponents:
          type: object
          description: RAW COMPONENTS = evidência/auditoria; não somar ao líquido de novo
          properties:
            role:
              type: string
              enum:
                - AUDIT_EVIDENCE
            providerRealizedPnlUsd:
              type: number
            venueFeesUsd:
              type: number
            fundingUsd:
              type: number
        builderFees:
          type: object
          description: BUILDER FEE = receita FINAUTON separada; não reduz a performance
          properties:
            role:
              type: string
              enum:
                - FINAUTON_REVENUE_SEPARATE
            builderFeesUsd:
              type: number
        netPerformanceUsd:
          type: number
        carryInUsd:
          type: number
        carryOutUsd:
          type: number
        chargeablePerformanceUsd:
          type: number
        performanceFeePercent:
          type: number
        performanceFeeUsd:
          type: number
        currency:
          type: string
          enum:
            - USDT
            - USDC
        creditUsd:
          type: number
        reason:
          type: string
          nullable: true
        obligationId:
          type: string
          nullable: true
    Obligation:
      type: object
      properties:
        obligationId:
          type: string
        source:
          type: string
          enum:
            - MONTHLY_SUBSCRIPTION
            - WEEKLY_PERFORMANCE_FEE
            - MONTHLY_PERFORMANCE_FEE
            - CUSTOM
        reference:
          type: string
        status:
          type: string
          enum:
            - PENDING
            - DUE
            - PAID
            - WAIVED
            - CANCELLED
        effectiveStatus:
          type: string
          enum:
            - PENDING
            - GRACE
            - OVERDUE_AFTER_GRACE
            - PAID
            - WAIVED
            - CANCELLED
        amountUsd:
          type: number
        currency:
          type: string
        dueAt:
          type: string
          format: date-time
        graceUntil:
          type: string
          format: date-time
        settledAt:
          type: string
          format: date-time
          nullable: true
    Payment:
      type: object
      properties:
        paymentId:
          type: string
        obligationId:
          type: string
        method:
          type: string
          enum:
            - EVM_TRANSFER
            - HYPERLIQUID_USD_SEND
        status:
          type: string
          enum:
            - PENDING
            - SUBMITTED
            - CONFIRMED
            - EXPIRED
            - FAILED
        review:
          type: string
          nullable: true
          enum:
            - MANUAL_REVIEW
          description: 'Sobrepagamento voluntário: quitado, excedente sem crédito automático'
        overpaidTokenAmount:
          type: string
          nullable: true
        amountUsd:
          type: number
        tokenSymbol:
          type: string
        tokenAddress:
          type: string
        tokenDecimals:
          type: integer
        tokenAmount:
          type: string
          description: Valor EXATO em unidades mínimas (inclui etiqueta única)
        networkId:
          type: string
        recipient:
          type: string
        receiverVersion:
          type: integer
          nullable: true
        payerAddress:
          type: string
        txHash:
          type: string
          nullable: true
        expiresAt:
          type: string
          format: date-time
        confirmedAt:
          type: string
          format: date-time
          nullable: true
        failureReason:
          type: string
          nullable: true
    Event:
      type: object
      properties:
        eventId:
          type: string
        eventType:
          type: string
          enum:
            - client.updated
            - provider.connected
            - provider.connect_failed
            - provider.disconnected
            - provider.access_lost
            - automation.updated
            - position.opened
            - position.updated
            - position.closed
            - protection.degraded
            - statement.created
            - statement.adjusted
            - obligation.created
            - obligation.paid
            - commercial.grace
            - commercial.suspended
            - commercial.reactivated
        occurredAt:
          type: string
          format: date-time
        tenantId:
          type: string
          nullable: true
        externalUserId:
          type: string
          nullable: true
        data:
          type: object
    AutomationSummary:
      type: object
      properties:
        providerId:
          type: string
        strategyId:
          type: string
        strategyVersion:
          type: string
        enabled:
          type: boolean
        risk:
          type: object
          additionalProperties: true
        conditions:
          type: object
          additionalProperties: true
        runtime:
          type: string
          enum:
            - ROUTING
            - DISABLED
            - REGISTERED_NOT_ROUTING
    Safety:
      type: object
      properties:
        policyVersion:
          type: string
        fingerprint:
          type: string
        required:
          type: boolean
        acknowledged:
          type: boolean
        flags:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
              severity:
                type: string
              message:
                type: string
    SetupView:
      type: object
      properties:
        externalUserId:
          type: string
        tenantId:
          type: string
          nullable: true
        requestId:
          type: string
        providerId:
          type: string
        mode:
          type: string
        enabled:
          type: boolean
        market:
          type: string
        leverage:
          type: number
        marginType:
          type: string
        orderSizeUsd:
          type: number
          nullable: true
        sizingStatus:
          type: string
        maxConcurrentTrades:
          type: number
        maxMarginPerTradeUsd:
          type: number
        allowedSymbols:
          type: array
          items:
            type: string
        allowMemecoins:
          type: boolean
        autoStopLoss:
          type: boolean
        autoTakeProfit:
          type: boolean
        autoBreakEven:
          type: boolean
        maxAdverseEntryPercent:
          type: number
        quoteCurrency:
          type: string
          nullable: true
        capitalBase:
          type: number
          nullable: true
        maxLossPerTrade:
          type: number
          nullable: true
        entryTimeoutMinutes:
          type: number
          nullable: true
        allowedStrategies:
          type: array
          items:
            type: string
        setupStatus:
          type: object
          properties:
            status:
              type: string
            issues:
              type: array
              items:
                type: object
                properties:
                  code:
                    type: string
                  field:
                    type: string
                  message:
                    type: string
        risk:
          type: object
          properties:
            maxDailyLossUsd:
              type: number
            maxOpenNotionalUsd:
              type: number
            maxSameDirection:
              type: number
            haltedToday:
              type: boolean
        safety:
          $ref: '#/components/schemas/Safety'
    AccountTest:
      type: object
      properties:
        externalUserId:
          type: string
        tenantId:
          type: string
          nullable: true
        requestId:
          type: string
        providerId:
          type: string
        success:
          type: boolean
        error:
          type: string
          nullable: true
        latencyMs:
          type: number
          nullable: true
        permissions:
          type: object
          additionalProperties: true
          nullable: true
    IntentStatus:
      type: object
      properties:
        intentId:
          type: string
        providerId:
          type: string
        status:
          type: string
        orderId:
          type: string
          nullable: true
        clientOrderId:
          type: string
          nullable: true
        executedQuantity:
          type: number
        executedPrice:
          type: number
          nullable: true
        errorCode:
          type: string
          nullable: true
        errorMessage:
          type: string
          nullable: true
        reconciledAt:
          type: string
          nullable: true
        requestId:
          type: string
    ExecutionInput:
      type: object
      properties:
        externalUserId:
          $ref: '#/components/schemas/ExternalUserId'
        type:
          type: string
          enum:
            - PLACE_ORDER
            - OPEN_POSITION
            - CLOSE_POSITION
            - CANCEL_ORDER
            - CANCEL_ALL_ORDERS
            - UPDATE_ORDER
            - SET_LEVERAGE
            - SET_MARGIN_MODE
            - SET_STOP_LOSS
            - SET_TAKE_PROFIT
        providerId:
          type: string
          minLength: 2
        symbol:
          type: string
          minLength: 3
        side:
          type: string
          enum:
            - BUY
            - SELL
        orderType:
          type: string
          enum:
            - LIMIT
            - MARKET
            - STOP_MARKET
            - TAKE_PROFIT_MARKET
        quantity:
          type: number
          minimum: 0
          exclusiveMinimum: true
        notionalUsd:
          type: number
          minimum: 0
          exclusiveMinimum: true
        price:
          type: number
          minimum: 0
          exclusiveMinimum: true
        triggerPrice:
          type: number
          minimum: 0
          exclusiveMinimum: true
        timeInForce:
          type: string
          enum:
            - GTC
            - IOC
            - FOK
            - POST_ONLY
        reduceOnly:
          type: boolean
        leverage:
          type: integer
          minimum: 1
          maximum: 125
        marginMode:
          type: string
          enum:
            - ISOLATED
            - CROSS
        stopLossPrice:
          type: number
          minimum: 0
          exclusiveMinimum: true
          nullable: true
        takeProfits:
          type: array
          items:
            type: object
            properties:
              price:
                type: number
                minimum: 0
                exclusiveMinimum: true
              share:
                type: number
                minimum: 0
                maximum: 1
        portion:
          type: number
          minimum: 0
          maximum: 1
        orderId:
          type: string
        positionSide:
          type: string
          enum:
            - BUY
            - SELL
        intentId:
          type: string
          minLength: 8
          maxLength: 64
      required:
        - externalUserId
        - type
        - providerId
      description: "Ordem manual (opcional; a automação não precisa). Abertura REAL só com orderType LIMIT e price; fechar/reduzir com reduceOnly true ou type CLOSE_POSITION. Envie intentId próprio (8–64) para idempotência na corretora. Sujeita a contrato, risco, cobrança e prontidão. Não executar no smoke seguro."
      example:
        externalUserId: cli-1001
        type: OPEN_POSITION
        providerId: BINANCE
        intentId: ord-cli-1001-0001
        symbol: BTCUSDT
        side: BUY
        orderType: LIMIT
        quantity: 0.001
        price: 62000
        timeInForce: GTC
        leverage: 3
        marginMode: ISOLATED
        stopLossPrice: 60800
        takeProfits:
          - price: 63500
            share: 0.5
          - price: 64500
            share: 0.5
