openapi: 3.1.0
info:
  title: DCS Labs API
  version: "1.0.0"
  summary: REST API for the DCS Labs agent infrastructure
  description: |
    REST endpoints for Sovereign Memory, Agent Treasury, on-chain Identity,
    and R+2 receipt verification.

    The full human-readable API documentation lives at https://dcslabs.ai/docs.

    All endpoints (unless noted) require Bearer authentication. Get an API
    key at https://dcslabs.ai/memory after signup.
  contact:
    name: DCS Labs Builder Support
    email: mcp@dcslabs.ai
    url: https://dcslabs.ai/docs
  license:
    name: API usage governed by Terms of Service at https://dcsai.ai/terms
    url: https://dcsai.ai/terms

servers:
  - url: https://api.dcslabs.ai/v1
    description: Production
  - url: https://api-staging.dcslabs.ai/v1
    description: Staging (limited availability)

security:
  - bearerAuth: []

tags:
  - name: memory
    description: Sovereign Memory — store, search, export
  - name: receipts
    description: R+2 cryptographic receipts
  - name: agents
    description: Agent identity (SBT on Base mainnet)
  - name: economy
    description: Agent Treasury and settlement
  - name: meta
    description: Health, stats, version

paths:
  /memory/store:
    post:
      tags: [memory]
      summary: Store a memory write
      description: |
        Creates a new memory entry for an agent. Produces a signed R+2 receipt,
        embeds the content using OpenAI's text-embedding-3-large model, and
        stores both the content and embedding in pgvector.
      operationId: storeMemory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MemoryStoreRequest'
      responses:
        '200':
          description: Memory stored successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MemoryStoreResponse'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }

  /memory/search:
    post:
      tags: [memory]
      summary: Semantic search over agent memory
      description: |
        Embeds the query and returns the top-k most similar memories by
        cosine similarity. Returns content, similarity score, and the
        underlying R+2 receipt_id for each match.
      operationId: searchMemory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MemorySearchRequest'
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MemorySearchResponse'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }

  /memory/export:
    get:
      tags: [memory]
      summary: Export full memory chain for an agent
      description: |
        Returns the agent's complete memory as a stream of signed R+2 receipts.
        Use this for backups, regulator audit export, or migration.
      operationId: exportMemory
      parameters:
        - name: agent_id
          in: query
          required: true
          schema: { type: string }
        - name: format
          in: query
          schema:
            type: string
            enum: [json, ndjson, r3-bundle]
            default: json
      responses:
        '200':
          description: Memory chain
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MemoryExport'

  /memory/{memory_id}:
    delete:
      tags: [memory]
      summary: Mark a memory as deleted
      description: |
        Logically deletes a memory entry. The R+2 receipt in the chain
        remains (immutable by design); the content is purged.
      operationId: deleteMemory
      parameters:
        - name: memory_id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  memory_id: { type: string }
                  deleted_at: { type: string, format: date-time }

  /receipts/{receipt_id}:
    get:
      tags: [receipts]
      summary: Fetch a single R+2 receipt
      description: |
        Returns the full signed R+2 receipt JSON. Public — no authentication
        required, since R+2 receipts are designed to be independently verifiable.
      operationId: getReceipt
      security: []
      parameters:
        - name: receipt_id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Receipt found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/R2Receipt'
        '404': { $ref: '#/components/responses/NotFound' }

  /receipts/verify:
    post:
      tags: [receipts]
      summary: Server-side receipt verification (convenience)
      description: |
        Runs the §8 verification flow server-side. For testing only — production
        verification should run client-side with `@trdnetwork/r2-verify`.
      operationId: verifyReceipt
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                receipt: { $ref: '#/components/schemas/R2Receipt' }
                expected_pubkey: { type: string }
              required: [receipt, expected_pubkey]
      responses:
        '200':
          description: Verification result
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  checks:
                    type: array
                    items:
                      type: object
                      properties:
                        name: { type: string }
                        pass: { type: boolean }
                        detail: { type: string }

  /receipts/chain:
    get:
      tags: [receipts]
      summary: Walk the receipt chain for an agent
      description: |
        Returns a paginated stream of receipts for an agent starting from
        a given CID, in chain order.
      operationId: walkChain
      parameters:
        - name: agent_id
          in: query
          required: true
          schema: { type: string }
        - name: from_cid
          in: query
          schema: { type: string }
        - name: limit
          in: query
          schema: { type: integer, default: 100, maximum: 1000 }
      responses:
        '200':
          description: Receipt chain page
          content:
            application/json:
              schema:
                type: object
                properties:
                  receipts:
                    type: array
                    items: { $ref: '#/components/schemas/R2Receipt' }
                  next_cid: { type: string, nullable: true }

  /agents/{agent_id}:
    get:
      tags: [agents]
      summary: Fetch agent metadata
      operationId: getAgent
      parameters:
        - name: agent_id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Agent metadata
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agent'
        '404': { $ref: '#/components/responses/NotFound' }

  /agents:
    get:
      tags: [agents]
      summary: List agents owned by a wallet address
      operationId: listAgents
      parameters:
        - name: owner
          in: query
          required: true
          schema: { type: string, pattern: '^0x[a-fA-F0-9]{40}$' }
        - name: page
          in: query
          schema: { type: integer, default: 1 }
      responses:
        '200':
          description: Agent list (paginated)
          content:
            application/json:
              schema:
                type: object
                properties:
                  agents:
                    type: array
                    items: { $ref: '#/components/schemas/Agent' }
                  total: { type: integer }
                  page: { type: integer }

  /economy/balance:
    get:
      tags: [economy]
      summary: Get USDC balance for an agent's Treasury wallet
      operationId: getBalance
      parameters:
        - name: agent_id
          in: query
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Balance
          content:
            application/json:
              schema:
                type: object
                properties:
                  agent_id: { type: string }
                  balance_usdc: { type: number }
                  wallet_address: { type: string }
                  network: { type: string, example: base-mainnet }

  /economy/settle:
    post:
      tags: [economy]
      summary: Settle a USDC transaction between two agents
      description: |
        Treasury automatically deducts the 2.5% fee. Settlement happens
        on-chain; returns the Basescan tx hash.
      operationId: settleTransaction
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [from_agent_id, to_agent_id, amount_usd]
              properties:
                from_agent_id: { type: string }
                to_agent_id: { type: string }
                amount_usd: { type: number, minimum: 0.01 }
                note: { type: string }
      responses:
        '200':
          description: Settlement complete
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  settlement_id: { type: string }
                  amount_usd: { type: number }
                  fee_usd: { type: number }
                  net_to_recipient: { type: number }
                  tx_hash: { type: string }
                  basescan_url: { type: string }

  /economy/history:
    get:
      tags: [economy]
      summary: Transaction history for an agent
      operationId: getEconomyHistory
      parameters:
        - name: agent_id
          in: query
          required: true
          schema: { type: string }
        - name: page
          in: query
          schema: { type: integer, default: 1 }
      responses:
        '200':
          description: Transaction list
          content:
            application/json:
              schema:
                type: object
                properties:
                  transactions:
                    type: array
                    items:
                      type: object
                      properties:
                        tx_id: { type: string }
                        from_agent_id: { type: string }
                        to_agent_id: { type: string }
                        amount_usd: { type: number }
                        fee_usd: { type: number }
                        status: { type: string }
                        tx_hash: { type: string }
                        created_at: { type: string, format: date-time }

  /health:
    get:
      tags: [meta]
      summary: API health check
      operationId: healthCheck
      security: []
      responses:
        '200':
          description: API is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  version: { type: string }
                  region: { type: string }

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: dcs_sk_live_*
      description: |
        API key in the format `dcs_sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`.
        Get your key at https://dcslabs.ai/memory after signup.

  schemas:
    R2Receipt:
      type: object
      description: Receipt conforming to the R+2 v0.1 spec at https://dcslabs.ai/standard
      required:
        - spec_version
        - agent_pubkey
        - agent_id
        - action_id
        - action_type
        - action_data
        - occurred_at
        - prev_receipt_cid
        - nonce
        - extensions
        - signature
      properties:
        spec_version:
          type: string
          enum: [r2/v0.1]
        agent_pubkey:
          type: string
          description: Ed25519 public key, base64url no-padding (43 chars)
          minLength: 43
          maxLength: 43
        agent_id:
          type: string
        action_id:
          type: string
          format: uuid
        action_type:
          type: string
          example: memory/write
        action_data:
          type: object
          additionalProperties: true
        occurred_at:
          type: string
          format: date-time
        prev_receipt_cid:
          type: [string, "null"]
          description: CID of previous receipt in chain, or null for the first
        nonce:
          type: string
          description: 16 random bytes, base64url no-padding (22 chars)
          minLength: 22
          maxLength: 22
        extensions:
          type: object
          additionalProperties: true
        signature:
          type: string
          description: Ed25519 signature, base64url no-padding (86 chars)
          minLength: 86
          maxLength: 86

    MemoryStoreRequest:
      type: object
      required: [agent_id, content]
      properties:
        agent_id: { type: string }
        content: { type: string, maxLength: 32768 }
        tags:
          type: array
          items: { type: string }
        metadata:
          type: object
          additionalProperties: true

    MemoryStoreResponse:
      type: object
      properties:
        memory_id: { type: string }
        receipt_id: { type: string }
        embedding_dim: { type: integer, example: 1536 }
        signed: { type: boolean }
        stored_at: { type: string, format: date-time }

    MemorySearchRequest:
      type: object
      required: [agent_id, query]
      properties:
        agent_id: { type: string }
        query: { type: string, maxLength: 1024 }
        top_k: { type: integer, default: 5, maximum: 50 }
        threshold: { type: number, default: 0.3 }

    MemorySearchResponse:
      type: object
      properties:
        results:
          type: array
          items:
            type: object
            properties:
              memory_id: { type: string }
              content: { type: string }
              cosine_similarity: { type: number }
              receipt_id: { type: string }
              stored_at: { type: string, format: date-time }

    MemoryExport:
      type: object
      properties:
        agent_id: { type: string }
        total: { type: integer }
        exported_at: { type: string, format: date-time }
        chain_head_cid: { type: string }
        receipts:
          type: array
          items: { $ref: '#/components/schemas/R2Receipt' }

    Agent:
      type: object
      properties:
        agent_id: { type: string }
        owner_address: { type: string }
        chain_id: { type: integer, example: 8453 }
        sbt_contract: { type: string }
        pubkey: { type: string }
        label: { type: string }
        minted_at: { type: string, format: date-time }
        signed_receipt_count: { type: integer }

    Error:
      type: object
      required: [error_code, message]
      properties:
        error_code: { type: string }
        message: { type: string }
        request_id: { type: string }
        details: { type: object }

  responses:
    BadRequest:
      description: Request body failed schema validation
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Unauthorized:
      description: API key missing or invalid
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    RateLimited:
      description: Too many requests
      headers:
        Retry-After:
          schema: { type: integer }
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
