openapi: 3.1.0
info:
  title: BrainArk RWA API
  version: "1.0"
  description: |
    REST API for the BrainArk Real-World Asset (RWA) platform running on BrainArk Chain (chain ID 1236).
    BAK is the native coin (18 decimals). All stakedBAK / priceBAK values are in wei (string) unless noted.

    **Authentication** — all `/api/v1/*` endpoints except `/api/v1/status` require one of:
    - `Authorization: Bearer <api_key>`
    - `X-API-Key: <api_key>`

    Enterprise API keys are created via the developer portal or `POST /api/enterprise/register`.
  contact:
    name: BrainArk Support
    url: https://brainark.online
  license:
    name: Proprietary

servers:
  - url: https://rwa.brainark.online
    description: Production

components:
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: X-API-Key
    BearerAuth:
      type: http
      scheme: bearer

  schemas:
    AssetMetadata:
      type: object
      properties:
        name:             { type: string }
        description:      { type: string }
        image:            { type: string }
        externalUrl:      { type: string }
        ipfsMetadataHash: { type: string }

    Asset:
      type: object
      properties:
        id:            { type: string, description: "Token ID (uint256 as string)" }
        assetType:     { type: string, example: "Retail Product" }
        stakedBAK:     { type: string, description: "BAK staked in wei" }
        issuer:        { type: string, description: "Ethereum address" }
        currentOwner:  { type: string, description: "Ethereum address" }
        issuedAt:      { type: integer, description: "Unix timestamp" }
        lastTransferAt:{ type: integer, description: "Unix timestamp" }
        isActive:      { type: boolean }
        isUnstaked:    { type: boolean }
        assetHash:     { type: string, description: "bytes32 hex" }
        metadata:      { $ref: '#/components/schemas/AssetMetadata' }

    Listing:
      type: object
      properties:
        id:           { type: string }
        assetId:      { type: string }
        seller:       { type: string }
        priceInBAK:   { type: string, description: "Price in BAK wei" }
        priceInNative:{ type: string }
        startTime:    { type: integer }
        endTime:      { type: integer }
        active:       { type: boolean }

    TxResponse:
      type: object
      properties:
        success:     { type: boolean }
        txHash:      { type: string }
        explorerUrl: { type: string }
        org:         { type: string }

    Error:
      type: object
      properties:
        error:  { type: string }
        reason: { type: string }
        hint:   { type: string }

security:
  - ApiKey: []
  - BearerAuth: []

paths:
  /api/v1/status:
    get:
      operationId: getStatus
      summary: Health check
      description: Returns chain status and contract addresses. No authentication required.
      security: []
      tags: [Status]
      responses:
        "200":
          description: Service healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:    { type: string, example: ok }
                  chain:     { type: string, example: "BrainArk (1236)" }
                  rpc:       { type: string }
                  contracts:
                    type: object
                    properties:
                      AssetRegistry: { type: string }
                      Marketplace:   { type: string }
                      StakingManager:{ type: string }
                      ClaimSystem:   { type: string }
                      Extensions:    { type: string }
                  auth: { type: string }

  /api/v1/assets:
    get:
      operationId: listAssets
      summary: List assets by owner
      tags: [Assets]
      parameters:
        - name: owner
          in: query
          required: true
          schema: { type: string }
          description: Ethereum address (checksummed or lowercase)
      responses:
        "200":
          description: Asset list
          content:
            application/json:
              schema:
                type: object
                properties:
                  assets: { type: array, items: { $ref: '#/components/schemas/Asset' } }
                  total:  { type: integer }
        "400":
          description: Missing or invalid owner address
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Error' }

  /api/v1/assets/{tokenId}:
    get:
      operationId: getAsset
      summary: Get single asset
      tags: [Assets]
      parameters:
        - name: tokenId
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Asset detail
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Asset' }
        "404":
          description: Asset not found
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Error' }

  /api/v1/nft/{tokenId}:
    get:
      operationId: getNFTMetadata
      summary: OpenSea-compatible NFT metadata
      tags: [Assets]
      parameters:
        - name: tokenId
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: ERC-721 metadata JSON
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:        { type: string }
                  description: { type: string }
                  image:       { type: string }
                  external_url:{ type: string }
                  attributes:
                    type: array
                    items:
                      type: object
                      properties:
                        trait_type: { type: string }
                        value:      {}

  /api/v1/marketplace:
    get:
      operationId: listMarketplace
      summary: Get active marketplace listings
      tags: [Marketplace]
      responses:
        "200":
          description: Listings list
          content:
            application/json:
              schema:
                type: object
                properties:
                  listings:   { type: array, items: { $ref: '#/components/schemas/Listing' } }
                  total:      { type: integer }
                  totalCount: { type: integer }

  /api/v1/marketplace/{id}:
    get:
      operationId: getListing
      summary: Get single marketplace listing
      tags: [Marketplace]
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
          description: Listing ID
      responses:
        "200":
          description: Listing detail
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Listing' }
        "404":
          description: Listing not found

  /api/v1/bak-price:
    get:
      operationId: getBakPrice
      summary: Get BAK/USD price
      description: Fetches BAK price from PancakeSwap V3. Cached 60s.
      tags: [Market Data]
      responses:
        "200":
          description: Current BAK price
          content:
            application/json:
              schema:
                type: object
                properties:
                  price:    { type: number, example: 0.012 }
                  currency: { type: string, example: USD }
                  source:   { type: string, example: "PancakeSwap V3" }
                  cached:   { type: boolean }
                  ts:       { type: integer, description: "Unix ms timestamp" }

  /api/v1/write/issue-asset:
    post:
      operationId: issueAsset
      summary: Issue a new RWA
      description: |
        Mints a new asset NFT on BrainArk chain from the enterprise custodial wallet.
        Minimum staked amount is 0.1 BAK. The enterprise wallet must have sufficient BAK.
      tags: [Write — Assets]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [assetType, name]
              properties:
                assetType:
                  type: string
                  description: Registered asset type (e.g. "Retail Product")
                  example: "Retail Product"
                name:
                  type: string
                  example: "Gold Ring #42"
                description:
                  type: string
                  default: ""
                image:
                  type: string
                  description: Image URL (IPFS or HTTPS)
                externalUrl:
                  type: string
                ipfsHash:
                  type: string
                  description: IPFS CID of off-chain metadata
                stakedAmount:
                  type: string
                  description: BAK to stake (decimal string, minimum "0.1")
                  default: "0.1"
                  example: "5.0"
                recipientAddress:
                  type: string
                  description: Address to receive the NFT. Defaults to enterprise wallet.
                metadata:
                  type: object
                  description: Arbitrary JSON encoded as externalUrl
      responses:
        "200":
          description: Asset issued
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/TxResponse'
                  - type: object
                    properties:
                      tokenId:       { type: string }
                      assetType:     { type: string }
                      name:          { type: string }
                      owner:         { type: string }
                      stakedBAK:     { type: string }
                      walletAddress: { type: string }
                      issuedAt:      { type: integer }
        "400":
          description: Validation error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Error' }
        "401":
          description: Missing or invalid API key
        "500":
          description: On-chain transaction failed

  /api/v1/write/batch-issue:
    post:
      operationId: batchIssueAssets
      summary: Issue multiple assets in one request
      description: Issues up to 50 assets sequentially. Partial success is possible — check each result's `success` flag.
      tags: [Write — Assets]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [assets]
              properties:
                assets:
                  type: array
                  maxItems: 50
                  items:
                    type: object
                    required: [assetType, name]
                    properties:
                      assetType:        { type: string }
                      name:             { type: string }
                      description:      { type: string }
                      image:            { type: string }
                      ipfsHash:         { type: string }
                      stakedAmount:     { type: string, default: "0.1" }
                      recipientAddress: { type: string }
      responses:
        "200":
          description: Batch result (may include individual failures)
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: { type: boolean, description: "true only if all issued" }
                  issued:  { type: integer }
                  failed:  { type: integer }
                  total:   { type: integer }
                  org:     { type: string }
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        index:     { type: integer }
                        success:   { type: boolean }
                        tokenId:   { type: string }
                        txHash:    { type: string }
                        name:      { type: string }
                        assetType: { type: string }
                        owner:     { type: string }
                        stakedBAK: { type: string }
                        error:     { type: string, description: "Present on failure" }

  /api/v1/write/transfer:
    post:
      operationId: transferAsset
      summary: Transfer an asset NFT
      description: Transfers ownership. The enterprise custodial wallet must own the token (or be approved).
      tags: [Write — Assets]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [tokenId, to]
              properties:
                tokenId:
                  type: string
                  description: Token ID to transfer
                to:
                  type: string
                  description: Recipient Ethereum address
                from:
                  type: string
                  description: Sender address. Defaults to enterprise wallet.
      responses:
        "200":
          description: Transfer complete
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/TxResponse'
                  - type: object
                    properties:
                      tokenId: { type: string }
                      from:    { type: string }
                      to:      { type: string }
        "400":
          description: Validation error
        "500":
          description: Transfer failed (wallet does not own token, or not approved)

  /api/v1/write/marketplace/list:
    post:
      operationId: listOnMarketplace
      summary: List an asset for sale
      description: Creates a marketplace listing. Enterprise wallet must own the token.
      tags: [Write — Marketplace]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [tokenId, priceBAK]
              properties:
                tokenId:
                  type: string
                priceBAK:
                  type: string
                  description: Asking price in BAK (decimal), e.g. "100"
                  example: "100"
                durationDays:
                  type: string
                  description: Listing duration in days
                  default: "30"
      responses:
        "200":
          description: Listed successfully
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/TxResponse'
                  - type: object
                    properties:
                      listingId:   { type: string }
                      tokenId:     { type: string }
                      priceBAK:    { type: string }
                      durationDays:{ type: integer }
        "400":
          description: Missing required fields
        "500":
          description: Listing failed

  /api/v1/write/marketplace/buy:
    post:
      operationId: buyFromMarketplace
      summary: Buy a listed asset
      description: Purchases a marketplace listing. Enterprise wallet must have enough BAK.
      tags: [Write — Marketplace]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [listingId]
              properties:
                listingId:
                  type: string
                maxPriceBAK:
                  type: string
                  description: Maximum price willing to pay in BAK. Prevents price-change front-running.
      responses:
        "200":
          description: Purchase complete
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/TxResponse'
                  - type: object
                    properties:
                      listingId: { type: string }
                      paidBAK:   { type: string }
                      buyer:     { type: string }
        "404":
          description: Listing not found or inactive
        "500":
          description: Buy transaction failed

  /api/v1/write/marketplace/delist:
    post:
      operationId: delistFromMarketplace
      summary: Cancel a marketplace listing
      description: Cancels an active listing. Enterprise wallet must be the listing seller.
      tags: [Write — Marketplace]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [listingId]
              properties:
                listingId:
                  type: string
      responses:
        "200":
          description: Listing cancelled
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TxResponse' }
        "400":
          description: Missing listingId
        "500":
          description: Delist failed (not the seller, or already inactive)

  /api/v1/write/register-asset-type:
    post:
      operationId: registerAssetType
      summary: Register a new asset type on-chain
      description: |
        Registers a custom asset type in the AssetTypeRegistrar contract.
        Costs 1 BAK from the enterprise wallet.
        Once registered, the type can be used in `POST /api/v1/write/issue-asset`.
      tags: [Write — Assets]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [typeName]
              properties:
                typeName:
                  type: string
                  description: Name of the asset type (1-50 chars)
                  example: "Vintage Watch"
                description:
                  type: string
                schema:
                  type: object
                  description: Optional JSON Schema defining required metadata fields
      responses:
        "200":
          description: Type registered
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:     { type: boolean }
                  typeName:    { type: string }
                  schema:      {}
                  description: { type: string }
                  org:         { type: string }
                  txHash:      { type: string }
                  note:        { type: string }
        "400":
          description: Invalid type name
        "500":
          description: Registration failed

  /api/analytics/issuer:
    get:
      operationId: getIssuerAnalytics
      summary: Issuer analytics dashboard data
      description: Returns aggregated stats, asset list, campaigns, yield distributions, and marketplace activity for a given issuer address. No authentication required.
      security: []
      tags: [Analytics]
      parameters:
        - name: address
          in: query
          required: true
          schema: { type: string }
          description: Issuer Ethereum address
      responses:
        "200":
          description: Analytics payload
          content:
            application/json:
              schema:
                type: object
                properties:
                  address: { type: string }
                  stats:
                    type: object
                    properties:
                      totalAssetsIssued:        { type: integer }
                      activeAssets:             { type: integer }
                      stakedAssets:             { type: integer }
                      totalStakedBAK:           { type: string }
                      totalCampaigns:           { type: integer }
                      activeCampaigns:          { type: integer }
                      totalBAKFundedCampaigns:  { type: string }
                      totalBAKClaimedCampaigns: { type: string }
                      totalDistributions:       { type: integer }
                      totalBAKDistributed:      { type: string }
                      activeListings:           { type: integer }
                  typeBreakdown:
                    type: object
                    additionalProperties: { type: integer }
                    description: "{ 'Retail Product': 5, 'Gift Voucher': 2, ... }"
                  assets:
                    type: array
                    items:
                      type: object
                      properties:
                        id:        { type: string }
                        name:      { type: string }
                        assetType: { type: string }
                        stakedBAK: { type: string }
                        isActive:  { type: boolean }
                        isUnstaked:{ type: boolean }
                        issuedAt:  { type: integer }
                  campaigns:
                    type: array
                    items:
                      type: object
                      properties:
                        id:             { type: integer }
                        assetType:      { type: string }
                        baseName:       { type: string }
                        totalTickets:   { type: integer }
                        ticketsClaimed: { type: integer }
                        isActive:       { type: boolean }
                        createdAt:      { type: integer }
                        totalBAKFunded: { type: string }
                        totalBAKClaimed:{ type: string }
                  distributions:
                    type: array
                    items:
                      type: object
                      properties:
                        id:           { type: integer }
                        memo:         { type: string }
                        totalAmount:  { type: string }
                        assetCount:   { type: integer }
                        claimedCount: { type: integer }
                        createdAt:    { type: integer }
                        active:       { type: boolean }
                  marketplaceListings:
                    type: array
                    items:
                      type: object
                      properties:
                        listingId:  { type: string }
                        assetId:    { type: string }
                        priceBAK:   { type: string }
                        startTime:  { type: integer }
        "400":
          description: Invalid address
        "500":
          description: Internal error

