openapi: 3.1.0
info:
  title: Naturecode API
  version: 0.2.0
  description: The mainstream-friendly REST surface for Naturecode. Auth is a Tenzro DPoP-bound JWT; tenancy is the active community DID carried in the token's RAR scopes.
tags: []
paths:
  /agents:
    get:
      operationId: Agents_list
      description: List agents in the caller's active community. `?project=<id>` narrows to project-scoped + community-wide; `?project=community` returns community-wide only.
      parameters:
        - name: project
          in: query
          required: false
          schema:
            type: string
          explode: false
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                anyOf:
                  - type: object
                    required:
                      - items
                    properties:
                      items:
                        type: array
                        items:
                          $ref: '#/components/schemas/Agent'
                      nextCursor:
                        type: string
                    description: Cursor-paginated list envelope. `nextCursor` is opaque; pass it back as `?cursor=` to continue.
                  - $ref: '#/components/schemas/ApiError'
      security:
        - BearerAuth: []
    post:
      operationId: Agents_create
      description: Deploy a new agent under the caller's active community. Starts paused — flip to active via PATCH /agents/{id}/status.
      parameters: []
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '201':
          description: The request has succeeded and a new resource has been created as a result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agent'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAgentBody'
      security:
        - BearerAuth: []
  /datasets:
    get:
      operationId: Datasets_list
      description: List datasets in the caller's active community. Tenant-scoped — never returns cross-community results.
      parameters: []
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                anyOf:
                  - type: object
                    required:
                      - items
                    properties:
                      items:
                        type: array
                        items:
                          $ref: '#/components/schemas/Dataset'
                      nextCursor:
                        type: string
                    description: Cursor-paginated list envelope. `nextCursor` is opaque; pass it back as `?cursor=` to continue.
                  - $ref: '#/components/schemas/ApiError'
      security:
        - BearerAuth: []
    post:
      operationId: Datasets_create
      description: Publish a new dataset under the caller's active community. Project must belong to the same community.
      parameters: []
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '201':
          description: The request has succeeded and a new resource has been created as a result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Dataset'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDatasetBody'
      security:
        - BearerAuth: []
  /me:
    get:
      operationId: Me_get
      description: The caller's identity envelope. Single round-trip used to bootstrap a session.
      parameters: []
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: '#/components/schemas/Identity'
                  - $ref: '#/components/schemas/ApiError'
      security:
        - BearerAuth: []
components:
  schemas:
    Agent:
      type: object
      required:
        - id
        - community
        - project
        - controller
        - name
        - role
        - skillId
        - modelName
        - allowedDatasets
        - status
        - createdAt
      properties:
        id:
          type: string
        community:
          $ref: '#/components/schemas/Did'
        project:
          anyOf:
            - type: string
            - type: 'null'
        controller:
          $ref: '#/components/schemas/Did'
        name:
          type: string
        role:
          $ref: '#/components/schemas/AgentRole'
        skillId:
          type: string
        modelName:
          type: string
        modelTier:
          type: string
          enum:
            - fast
            - standard
            - deep
            - max
        maxSpendPerDayNaco:
          type: number
          format: double
        allowedDatasets:
          anyOf:
            - type: array
              items:
                $ref: '#/components/schemas/Did'
            - type: string
              enum:
                - community:*
          description: Datasets the agent may read from. `"community:*"` means all datasets in the agent's community.
        status:
          type: string
          enum:
            - paused
            - active
            - stopped
        createdAt:
          type: string
          format: date-time
    AgentRole:
      type: string
      enum:
        - validator
        - detector
        - enricher
        - alerter
        - funder
        - orchestrator
        - custom
    ApiError:
      type: object
      required:
        - error
      properties:
        error:
          type: string
        detail:
          type: object
          additionalProperties: {}
      description: Standard error envelope. `error` is a stable, machine-readable code; `detail` is human-readable context.
    Balances:
      type: object
      required:
        - naco
        - usdc
      properties:
        naco:
          anyOf:
            - type: number
              format: double
            - type: 'null'
          description: NACO balance. NACO is the only product-facing financial token.
        usdc:
          anyOf:
            - type: number
              format: double
            - type: 'null'
          description: USDC balance, rendered for tranches denominated in USDC. May be null if the wallet has not been seen on the USDC ledger.
    CreateAgentBody:
      type: object
      required:
        - name
        - role
        - skillId
        - modelName
      properties:
        name:
          type: string
        role:
          $ref: '#/components/schemas/AgentRole'
        skillId:
          type: string
        modelName:
          type: string
        modelTier:
          type: string
          enum:
            - fast
            - standard
            - deep
            - max
        maxSpendPerDayNaco:
          type: number
          format: double
        allowedDatasets:
          anyOf:
            - type: array
              items:
                $ref: '#/components/schemas/Did'
            - type: string
              enum:
                - community:*
        project:
          type: string
    CreateDatasetBody:
      type: object
      required:
        - title
        - subtitle
        - kind
        - modality
        - format
        - delivery
        - license
        - cadence
      properties:
        title:
          type: string
        subtitle:
          type: string
        kind:
          $ref: '#/components/schemas/DataKind'
        modality:
          $ref: '#/components/schemas/DataModality'
        format:
          type: string
        delivery:
          type: string
          enum:
            - batch
            - stream
        transport:
          type: string
        project:
          anyOf:
            - type: string
            - type: 'null'
        license:
          type: string
          enum:
            - open
            - restricted
            - commercial
            - regulated
        cadence:
          type: string
          enum:
            - continuous
            - batch
            - snapshot
        pricePerReadNaco:
          type: number
          format: double
        attestationTier:
          type: number
          enum:
            - 0
            - 1
            - 2
            - 3
        access:
          type: string
          enum:
            - public
            - restricted
            - vote
        tags:
          type: array
          items:
            type: string
        geoLabel:
          type: string
        geoLat:
          type: number
          format: double
        geoLon:
          type: number
          format: double
    DataKind:
      type: string
      enum:
        - biodiversity
        - climate
        - water
        - air
        - soil
        - forest
        - ocean
        - edna
        - bioacoustics
        - camera-traps
        - earth-observation
        - wildfire
        - carbon
        - socioeconomic
        - other
      description: High-level data category. Drives discovery filters and default validators.
    DataModality:
      type: string
      enum:
        - tabular
        - geo-vector
        - geo-raster
        - point-cloud
        - imagery
        - video
        - audio
        - time-series
        - hyperspectral
        - genomic
      description: Physical shape of the data, independent of subject matter.
    Dataset:
      type: object
      required:
        - id
        - community
        - project
        - title
        - subtitle
        - kind
        - modality
        - format
        - delivery
        - license
        - cadence
        - createdAt
      properties:
        id:
          type: string
        community:
          $ref: '#/components/schemas/Did'
        project:
          anyOf:
            - type: string
            - type: 'null'
        title:
          type: string
        subtitle:
          type: string
        kind:
          $ref: '#/components/schemas/DataKind'
        modality:
          $ref: '#/components/schemas/DataModality'
        format:
          type: string
        delivery:
          type: string
          enum:
            - batch
            - stream
        transport:
          type: string
        license:
          type: string
          enum:
            - open
            - restricted
            - commercial
            - regulated
        cadence:
          type: string
          enum:
            - continuous
            - batch
            - snapshot
        pricePerReadNaco:
          type: number
          format: double
        attestationTier:
          type: number
          enum:
            - 0
            - 1
            - 2
            - 3
        access:
          type: string
          enum:
            - public
            - restricted
            - vote
        tags:
          type: array
          items:
            type: string
        geo:
          $ref: '#/components/schemas/GeoPoint'
        createdAt:
          type: string
          format: date-time
    Did:
      type: string
      pattern: ^did:tenzro:[a-zA-Z0-9:_-]+$
      description: 'A Tenzro DID. Shape: did:tenzro:{kind}:{uuid}.'
    GeoPoint:
      type: object
      required:
        - center
        - label
      properties:
        center:
          type: array
          items:
            type: number
            format: double
        label:
          type: string
    Identity:
      type: object
      required:
        - did
        - handle
        - displayName
        - role
        - avatarSeed
        - wallet
        - balances
        - credentials
        - activeCommunity
        - source
      properties:
        did:
          $ref: '#/components/schemas/Did'
        handle:
          type: string
        displayName:
          type: string
        role:
          type: string
        avatarSeed:
          type: string
        wallet:
          $ref: '#/components/schemas/Did'
        balances:
          $ref: '#/components/schemas/Balances'
        credentials:
          type: array
          items:
            $ref: '#/components/schemas/VerifiableCredential'
        activeCommunity:
          anyOf:
            - $ref: '#/components/schemas/Did'
            - type: 'null'
        source:
          type: string
          enum:
            - simulated
            - tenzro
            - tenzro-fallback
          description: Source of the balance numbers. `tenzro` = live RPC; `tenzro-fallback` = RPC unavailable, reconstructed from chain events; `simulated` = no live ledger configured.
        warning:
          type: string
    VerifiableCredential:
      type: object
      required:
        - id
        - type
        - issuer
        - issued_at
      properties:
        id:
          type: string
        type:
          type: string
        issuer:
          $ref: '#/components/schemas/Did'
        issued_at:
          type: string
          format: date-time
        expires_at:
          type: string
          format: date-time
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
servers:
  - url: http://localhost:3000/api
    description: Local development
    variables: {}
  - url: https://naturecode.org/api
    description: Production
    variables: {}
