openapi: 3.0.3
info:
  title: Wallet Registry API
  version: 1.0.0
  description: |
    REST API wrapper for the AccountWalletRegistry smart contract.
    
    Maps regulated fiat accounts (IBAN, ABA) to Web3 wallets, storing hashed
    account references (no PII on-chain). Supports 1-to-many mappings between
    accounts and wallets.
    
    This API provides a harmonized integration layer for:
    - Account-to-wallet linking
    - Wallet-to-account resolution
    - Link status management
    - Multi-provider wallet support (MetaMask, Fireblocks, etc.)
    
  contact:
    name: DBIS API Support
    email: api-support@dbis.org
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.d-bis.org/api/v1/wallet-registry
    description: Production server
  - url: https://sandbox.d-bis.org/api/v1/wallet-registry
    description: Sandbox server
  - url: http://localhost:8080/api/v1/wallet-registry
    description: Development server

security:
  - BearerAuth: []
  - OAuth2MTLS: []

tags:
  - name: Wallet Registry
    description: Account-to-wallet mapping operations
  - name: Health
    description: Health check endpoints

paths:
  /health:
    get:
      tags: [Health]
      summary: Health check
      description: Returns the health status of the Wallet Registry API and contract connection
      operationId: getHealth
      security: []
      responses:
        '200':
          description: Service is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "healthy"
                  contract:
                    type: object
                    properties:
                      address:
                        type: string
                        example: "0xBeEF0128B7ff030e25beeda6Ff62f02041Dedbd0"
                      connected:
                        type: boolean
                        example: true
                      chainId:
                        type: integer
                        example: 138
                  timestamp:
                    type: string
                    format: date-time

  /accounts/{accountRefId}/wallets:
    post:
      tags: [Wallet Registry]
      summary: Link account to wallet
      description: Creates a link between an account reference and a wallet reference
      operationId: linkAccountToWallet
      parameters:
        - $ref: '#/components/parameters/AccountRefId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LinkAccountWalletRequest'
            examples:
              metamask:
                value:
                  walletRefId: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
                  provider: "METAMASK"
      responses:
        '201':
          description: Account linked to wallet successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletLinkResponse'
              example:
                success: true
                data:
                  accountRefId: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
                  walletRefId: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
                  provider: "METAMASK"
                  linkedAt: 1704067200
                  active: true
                  transactionHash: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
                timestamp: "2024-01-01T00:00:00Z"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalServerError'

    get:
      tags: [Wallet Registry]
      summary: Get wallets for account
      description: Returns all wallet links associated with an account reference
      operationId: getWalletsForAccount
      parameters:
        - $ref: '#/components/parameters/AccountRefId'
        - name: active
          in: query
          description: Filter by active status
          required: false
          schema:
            type: boolean
      responses:
        '200':
          description: List of wallet links
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletLinkListResponse'
              example:
                success: true
                data:
                  accountRefId: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
                  wallets:
                    - walletRefId: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
                      provider: "METAMASK"
                      linkedAt: 1704067200
                      active: true
                    - walletRefId: "0x8ba1f109551bD432803012645Hac136c85C3e06b"
                      provider: "FIREBLOCKS"
                      linkedAt: 1704070800
                      active: false
                timestamp: "2024-01-01T00:00:00Z"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /accounts/{accountRefId}/wallets/{walletRefId}:
    delete:
      tags: [Wallet Registry]
      summary: Unlink account from wallet
      description: Deactivates the link between an account reference and wallet reference
      operationId: unlinkAccountFromWallet
      parameters:
        - $ref: '#/components/parameters/AccountRefId'
        - $ref: '#/components/parameters/WalletRefId'
      responses:
        '200':
          description: Account unlinked from wallet successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WalletLinkResponse'
              example:
                success: true
                data:
                  accountRefId: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
                  walletRefId: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
                  active: false
                  transactionHash: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
                timestamp: "2024-01-01T00:01:00Z"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /wallets/{walletRefId}/accounts:
    get:
      tags: [Wallet Registry]
      summary: Get accounts for wallet
      description: Returns all account references associated with a wallet reference
      operationId: getAccountsForWallet
      parameters:
        - $ref: '#/components/parameters/WalletRefId'
      responses:
        '200':
          description: List of account references
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountListResponse'
              example:
                success: true
                data:
                  walletRefId: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
                  accounts:
                    - accountRefId: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
                    - accountRefId: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
                timestamp: "2024-01-01T00:00:00Z"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /accounts/{accountRefId}/wallets/{walletRefId}/status:
    get:
      tags: [Wallet Registry]
      summary: Check link status
      description: Checks if an account and wallet are linked and/or active
      operationId: getLinkStatus
      parameters:
        - $ref: '#/components/parameters/AccountRefId'
        - $ref: '#/components/parameters/WalletRefId'
      responses:
        '200':
          description: Link status
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LinkStatusResponse'
              example:
                success: true
                data:
                  accountRefId: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
                  walletRefId: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
                  isLinked: true
                  isActive: true
                timestamp: "2024-01-01T00:00:00Z"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalServerError'

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token for authentication
    OAuth2MTLS:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://auth.d-bis.org/oauth2/token
          scopes:
            wallet-registry:read: Read access to wallet registry
            wallet-registry:write: Write access to wallet registry

  parameters:
    AccountRefId:
      name: accountRefId
      in: path
      required: true
      description: Hashed account reference ID (bytes32 hex string)
      schema:
        type: string
        pattern: '^0x[a-fA-F0-9]{64}$'
        example: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
    
    WalletRefId:
      name: walletRefId
      in: path
      required: true
      description: Hashed wallet reference ID (bytes32 hex string) or wallet address
      schema:
        type: string
        pattern: '^0x[a-fA-F0-9]{40,64}$'
        example: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"

  schemas:
    LinkAccountWalletRequest:
      type: object
      required:
        - walletRefId
        - provider
      properties:
        walletRefId:
          type: string
          description: Hashed wallet reference ID or wallet address
          pattern: '^0x[a-fA-F0-9]{40,64}$'
          example: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
        provider:
          type: string
          description: Wallet provider identifier
          enum: [METAMASK, FIREBLOCKS, CUSTODY_X, LEDGER, TREZOR, OTHER]
          example: "METAMASK"

    WalletLink:
      type: object
      properties:
        walletRefId:
          type: string
          description: Hashed wallet reference ID
          example: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
        provider:
          type: string
          description: Wallet provider identifier
          example: "METAMASK"
        linkedAt:
          type: integer
          format: int64
          description: Unix timestamp when the link was created
          example: 1704067200
        active:
          type: boolean
          description: Whether the link is currently active
          example: true

    WalletLinkResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                accountRefId:
                  type: string
                  example: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
                walletRefId:
                  type: string
                  example: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
                provider:
                  type: string
                  example: "METAMASK"
                linkedAt:
                  type: integer
                  format: int64
                  example: 1704067200
                active:
                  type: boolean
                  example: true
                transactionHash:
                  type: string
                  description: Transaction hash of the blockchain operation
                  example: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"

    WalletLinkListResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                accountRefId:
                  type: string
                  example: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
                wallets:
                  type: array
                  items:
                    $ref: '#/components/schemas/WalletLink'

    AccountListResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                walletRefId:
                  type: string
                  example: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
                accounts:
                  type: array
                  items:
                    type: object
                    properties:
                      accountRefId:
                        type: string
                        example: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"

    LinkStatusResponse:
      allOf:
        - $ref: '#/components/schemas/BaseResponse'
        - type: object
          properties:
            data:
              type: object
              properties:
                accountRefId:
                  type: string
                  example: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
                walletRefId:
                  type: string
                  example: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5"
                isLinked:
                  type: boolean
                  description: Whether the account and wallet are linked (regardless of active status)
                  example: true
                isActive:
                  type: boolean
                  description: Whether the link is currently active
                  example: true

    BaseResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        timestamp:
          type: string
          format: date-time

    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            code:
              type: string
              example: "VALIDATION_ERROR"
            message:
              type: string
              example: "Invalid request parameters"
            details:
              type: object
        timestamp:
          type: string
          format: date-time

  responses:
    BadRequest:
      description: Bad request - validation error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: "VALIDATION_ERROR"
              message: "Invalid accountRefId format"
              details:
                field: "accountRefId"
                reason: "Must be a 64-character hex string prefixed with 0x"
            timestamp: "2024-01-01T00:00:00Z"

    Unauthorized:
      description: Unauthorized - missing or invalid authentication
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: "UNAUTHORIZED"
              message: "Missing or invalid authentication token"
            timestamp: "2024-01-01T00:00:00Z"

    Forbidden:
      description: Forbidden - insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: "FORBIDDEN"
              message: "Insufficient permissions. ACCOUNT_MANAGER_ROLE required"
            timestamp: "2024-01-01T00:00:00Z"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: "NOT_FOUND"
              message: "Account or wallet not found"
            timestamp: "2024-01-01T00:00:00Z"

    Conflict:
      description: Conflict - link already exists
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: "CONFLICT"
              message: "Account and wallet are already linked"
            timestamp: "2024-01-01T00:00:00Z"

    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            error:
              code: "INTERNAL_ERROR"
              message: "An internal error occurred"
            timestamp: "2024-01-01T00:00:00Z"
