openapi: 3.1.0
info:
  title: API de Contas — CryptoRisk
  version: ''
  description: >
    Consulta de risco de carteiras cripto (Ethereum e Tron) pela API de Contas
    (`/api/v2`).


    Escopos: `crypto-risk.read` e `crypto-risk.write`. Credenciais já emitidas

    não recebem esses escopos automaticamente — crie uma nova credencial ou

    atualize a existente em **Configurações → API Contas → Nova credencial**.

    Credencial BaaS envia `x-account-id`.


    <h4>Fluxo 201 vs 202</h4>

    <ol>
      <li><code>POST /crypto-risk/analyses</code> com <code>{ network, address }</code>.</li>
      <li><code>201</code> — histórico já ingerido: snapshot fechado com events.</li>
      <li><code>202</code> — ingestão desta carteira começou ou ainda está rodando.
      O body <b>não</b> tem analysis id.</li>
      <li>Faça poll em <code>GET /crypto-risk/ingest?network=&amp;address=</code>
      até <code>IDLE</code> com <code>persisted != null</code> (0 transações é índice vazio válido).</li>
      <li>Repita o POST para obter <code>201</code>.</li>
    </ol>

    Retry do POST enquanto o ingest desta carteira está <code>RUNNING</code>
    também

    devolve <code>202</code>. Ingest de outra carteira devolve <code>409</code>.

    <code>BITCOIN</code>, <code>TRX</code> e demais redes devolvem
    <code>422</code>

    antes de qualquer chamada upstream.


    <h4>Ingest vazio não é carteira limpa</h4>

    Risk 0 + baixa confiança + <code>historyCovered=false</code> é ingest vazio,

    <b>não</b> carteira limpa. Os scores passam como o CryptoRisk devolve.


    O snapshot público não inclui features, grafo de exposição, PDF, sanctions

    nem hash / endereço de contraparte nos events.


    Guia: documentação <i>CryptoRisk</i> (seção Pagamentos).
servers:
  - url: https://api.example.com/api/v2
tags:
  - name: CryptoRisk
    description: >
      Consulta de risco de carteiras cripto (Ethereum e Tron) pela API de
      Contas.


      Escopos: `crypto-risk.read` e `crypto-risk.write`.
components:
  securitySchemes:
    OAuth2:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: /oauth/token
          scopes:
            crypto-risk.read: >-
              Permite consultar análises e o status de ingestão de carteiras
              cripto
            crypto-risk.write: Permite solicitar análise de risco de carteira cripto
  parameters:
    XAccountId:
      name: x-account-id
      in: header
      description: >
        Identificador interno da conta filha que será operada. Obrigatório
        quando o token foi emitido por uma credencial BaaS (`clientId` com
        prefixo `baas_`) em endpoints operacionais de conta.
      required: false
      schema:
        type: integer
        format: int64
  schemas:
    ErrorRFC7807:
      type: object
      properties:
        type:
          type: string
        title:
          type: string
        detail:
          type: string
        instance:
          type: string
    CryptoRiskNetwork:
      type: string
      enum:
        - ETHEREUM
        - TRON
      description: >
        Redes suportadas na API de Contas. `BITCOIN`, `TRX` e qualquer outro
        valor

        respondem `422` antes de qualquer chamada upstream.
    CryptoRiskAnalyzeRequest:
      type: object
      required:
        - network
        - address
      properties:
        network:
          $ref: '#/components/schemas/CryptoRiskNetwork'
        address:
          type: string
          minLength: 1
          maxLength: 128
          description: Endereço da carteira na rede informada.
          example: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
    CryptoRiskAnalysisEvent:
      type: object
      description: >
        Resumo de evento do snapshot fechado. Sem hash da transação e sem
        endereço

        de contraparte.
      properties:
        eventType:
          type: string
          example: SANCTION_HIT
        component:
          type: string
          example: KNOWN_RISK
        severity:
          type: string
          example: HIGH
        riskPoints:
          type: number
          example: 40
        hopDistance:
          type: number
          example: 0
        status:
          type: string
          example: OPEN
        detectedAt:
          type: string
          format: date-time
    CryptoRiskAnalysis:
      type: object
      description: >
        Snapshot fechado da análise. Scores entram como o CryptoRisk devolve.

        Risk 0 + baixa confiança + `historyCovered=false` é ingest vazio,
        **não**

        carteira limpa. Sem features snapshot, grafo de exposição, PDF ou
        sanctions.
      properties:
        id:
          description: Identificador da análise. Ausente no `202`.
          oneOf:
            - type: string
            - type: integer
          example: '10'
        network:
          $ref: '#/components/schemas/CryptoRiskNetwork'
        address:
          type: string
        status:
          type: string
          example: COMPLETED
        riskScore:
          type:
            - number
            - 'null'
        riskLevel:
          type:
            - string
            - 'null'
        reputationScore:
          type:
            - number
            - 'null'
        confidenceScore:
          type:
            - number
            - 'null'
        knownRiskScore:
          type:
            - number
            - 'null'
        exposureRiskScore:
          type:
            - number
            - 'null'
        behavioralRiskScore:
          type:
            - number
            - 'null'
        anomalyRiskScore:
          type:
            - number
            - 'null'
        hardStop:
          type: boolean
        hardStopRule:
          type:
            - string
            - 'null'
        historyCovered:
          type: boolean
          description: >
            `false` com risk 0 e baixa confiança indica ingest vazio, não
            carteira limpa.
        scoringModelVersion:
          type: string
        rulesVersion:
          type: string
        featureVersion:
          type: string
        startedAt:
          type: string
          format: date-time
        completedAt:
          type:
            - string
            - 'null'
          format: date-time
        createdAt:
          type: string
          format: date-time
        events:
          type: array
          description: >-
            Presente no `201` e no `GET /analyses/{id}`. Ausente nos itens da
            listagem.
          items:
            $ref: '#/components/schemas/CryptoRiskAnalysisEvent'
    CryptoRiskAnalysisSummary:
      type: object
      description: Item da listagem. Mesmos campos do snapshot fechado, sem `events`.
      properties:
        id:
          oneOf:
            - type: string
            - type: integer
        network:
          $ref: '#/components/schemas/CryptoRiskNetwork'
        address:
          type: string
        status:
          type: string
        riskScore:
          type:
            - number
            - 'null'
        riskLevel:
          type:
            - string
            - 'null'
        reputationScore:
          type:
            - number
            - 'null'
        confidenceScore:
          type:
            - number
            - 'null'
        knownRiskScore:
          type:
            - number
            - 'null'
        exposureRiskScore:
          type:
            - number
            - 'null'
        behavioralRiskScore:
          type:
            - number
            - 'null'
        anomalyRiskScore:
          type:
            - number
            - 'null'
        hardStop:
          type: boolean
        hardStopRule:
          type:
            - string
            - 'null'
        historyCovered:
          type: boolean
        scoringModelVersion:
          type: string
        rulesVersion:
          type: string
        featureVersion:
          type: string
        startedAt:
          type: string
          format: date-time
        completedAt:
          type:
            - string
            - 'null'
          format: date-time
        createdAt:
          type: string
          format: date-time
    CryptoRiskAnalysisEnvelope:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/CryptoRiskAnalysis'
    CryptoRiskIngestProgress:
      type: object
      required:
        - status
        - network
        - address
      properties:
        status:
          type: string
          enum:
            - IDLE
            - RUNNING
        network:
          type: string
        address:
          type: string
        fetched:
          type:
            - number
            - 'null'
        persisted:
          type:
            - number
            - 'null'
          description: >
            Quando `status` é `IDLE` e `persisted` não é `null`, o índice está
            pronto

            (inclusive `0`, que é ingest vazio válido). Repita o POST para obter
            `201`.
        errorMessage:
          type:
            - string
            - 'null'
    CryptoRiskIngestAccepted:
      type: object
      description: >
        Body do `202`. Ingestão aceita desta carteira. **Não há analysis id**
        até o

        ingest terminar e o POST ser repetido.
      required:
        - status
        - network
        - address
        - maxTransactions
        - ingest
      properties:
        status:
          type: string
          const: ACCEPTED
        network:
          type: string
        address:
          type: string
        maxTransactions:
          type: number
        ingest:
          $ref: '#/components/schemas/CryptoRiskIngestProgress'
    CryptoRiskIngestAcceptedEnvelope:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/CryptoRiskIngestAccepted'
    CryptoRiskIngestProgressEnvelope:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/CryptoRiskIngestProgress'
    CryptoRiskAnalysisList:
      type: object
      required:
        - meta
        - data
      properties:
        meta:
          type: object
          required:
            - total
            - page
            - limit
          properties:
            total:
              type: integer
              minimum: 0
            page:
              type: integer
              minimum: 1
            limit:
              type: integer
              minimum: 1
        data:
          type: array
          description: Snapshots sem `events`.
          items:
            $ref: '#/components/schemas/CryptoRiskAnalysisSummary'
paths:
  /crypto-risk/analyses:
    post:
      tags:
        - CryptoRisk
      summary: Solicitar análise de risco de carteira cripto.
      description: >
        Analisa a carteira `{network, address}`. Sem `accountId` no body.

        Redes: apenas `ETHEREUM` e `TRON`. `BITCOIN`, `TRX` e outras respondem

        `422` antes de qualquer chamada upstream.


        `201` quando o histórico já está ingerido — snapshot fechado com events.

        `202` se a ingestão **desta** carteira começou ou ainda está rodando.

        O `202` **não** tem analysis id. Faça poll em `GET /crypto-risk/ingest`

        até `IDLE` com `persisted != null` e repita o POST.


        Retry do POST enquanto o ingest desta carteira está `RUNNING` também

        devolve `202`. Ingest de outra carteira devolve `409`.


        Risk 0 + baixa confiança + `historyCovered=false` é ingest vazio,
        **não**

        carteira limpa.
      operationId: postCryptoRiskAnalysis
      parameters:
        - $ref: '#/components/parameters/XAccountId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CryptoRiskAnalyzeRequest'
            example:
              network: ETHEREUM
              address: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'
      responses:
        '201':
          description: Snapshot fechado (histórico já ingerido)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CryptoRiskAnalysisEnvelope'
        '202':
          description: >-
            Ingestão desta carteira aceita ou ainda em andamento. Sem analysis
            id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CryptoRiskIngestAcceptedEnvelope'
        '400':
          description: Parâmetros inválidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '401':
          description: Não autorizado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '403':
          description: Escopo ausente ou acesso negado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '409':
          description: Ingestão de outra carteira em andamento
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '422':
          description: Rede não suportada (`BITCOIN`, `TRX` ou outra)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '503':
          description: CryptoRisk indisponível ou falha upstream
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
      security:
        - OAuth2:
            - crypto-risk.write
    get:
      tags:
        - CryptoRisk
      summary: Listar análises de risco da conta.
      description: >
        Lista os snapshots fechados da conta autenticada. Itens **sem**
        `events`.

        Filtro `address` exige `network`. Paginação `{ meta: { total, page,
        limit }, data }`.
      operationId: listCryptoRiskAnalyses
      parameters:
        - $ref: '#/components/parameters/XAccountId'
        - name: network
          in: query
          schema:
            $ref: '#/components/schemas/CryptoRiskNetwork'
        - name: address
          in: query
          description: Exige `network`.
          schema:
            type: string
            maxLength: 128
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 10000
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
      responses:
        '200':
          description: Lista paginada (itens sem events)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CryptoRiskAnalysisList'
        '400':
          description: Parâmetros inválidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '401':
          description: Não autorizado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '403':
          description: Escopo ausente ou acesso negado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '422':
          description: Rede não suportada (`BITCOIN`, `TRX` ou outra)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '503':
          description: CryptoRisk indisponível ou falha upstream
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
      security:
        - OAuth2:
            - crypto-risk.read
  /crypto-risk/analyses/{id}:
    get:
      tags:
        - CryptoRisk
      summary: Consultar snapshot fechado de uma análise.
      description: |
        Devolve o snapshot fechado com resumos de events. Análise de outra conta
        responde `404`. O `id` é inteiro positivo.
      operationId: getCryptoRiskAnalysis
      parameters:
        - $ref: '#/components/parameters/XAccountId'
        - name: id
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]+$
      responses:
        '200':
          description: Snapshot fechado com events
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CryptoRiskAnalysisEnvelope'
        '400':
          description: Id inválido
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '401':
          description: Não autorizado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '403':
          description: Escopo ausente ou acesso negado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '404':
          description: Análise inexistente ou de outra conta
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '503':
          description: CryptoRisk indisponível ou falha upstream
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
      security:
        - OAuth2:
            - crypto-risk.read
  /crypto-risk/ingest:
    get:
      tags:
        - CryptoRisk
      summary: Consultar progresso da ingestão de uma carteira.
      description: |
        Use após um `202` em `POST /crypto-risk/analyses`. Faça poll até
        `status=IDLE` e `persisted != null` (0 transações é índice vazio válido)
        e então repita o POST para obter `201`.
      operationId: getCryptoRiskIngest
      parameters:
        - $ref: '#/components/parameters/XAccountId'
        - name: network
          in: query
          required: true
          schema:
            $ref: '#/components/schemas/CryptoRiskNetwork'
        - name: address
          in: query
          required: true
          schema:
            type: string
            minLength: 1
            maxLength: 128
      responses:
        '200':
          description: Progresso da ingestão
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CryptoRiskIngestProgressEnvelope'
        '400':
          description: Parâmetros inválidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '401':
          description: Não autorizado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '403':
          description: Escopo ausente ou acesso negado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '422':
          description: Rede não suportada (`BITCOIN`, `TRX` ou outra)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
        '503':
          description: CryptoRisk indisponível ou falha upstream
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorRFC7807'
      security:
        - OAuth2:
            - crypto-risk.read
