openapi: 3.1.0
info:
  title: Sluzen Admin / Onboard (stub)
  version: 1.2.1
  description: |
    Non-public operator / issuer surfaces. Most admin paths are tag inventory
    only (no full request/response schemas). Authoritative behavior lives in
    `src/routes/admin.ts`, `src/routes/onboard.ts`, `.ops/OPS.md`, and
    `docs/FRONTEND_SPEC.md` §5–§6.

    Documented in this file: `GET /admin/calls` (issuer call export by `callId`).
    Operational narrative: `docs/CALL_OBSERVABILITY.md`. Synthetic body:
    `docs/fixtures/admin-calls-export.example.json`.

    Do not put real `ADMIN_TOKEN` values, seed secrets, or treasury addresses in examples.
servers:
  - url: https://api.sluzen.network
  - url: http://127.0.0.1:3000
tags:
  - name: Admin
    description: |
      Paths under `/admin/*` (keys, credits, endpoints, calls, capacity, terms,
      session, invites, recover, facilitator-endpoints, suspend, announcements).
      Operator Bearer or scoped API keys as implemented in code. Out-of-band only.
  - name: Onboard
    description: |
      Invite-gated issuer file under `/onboard/*`. Not public signup.
      See `.ops/LEGAL.md` and operator invite scripts.
paths:
  /admin/calls:
    get:
      tags: [Admin]
      summary: Export settlement/delivery events for this principal
      description: |
        Issuer-scoped call observability. API keys with `admin:endpoints` see
        only their `apiKeyId` rows. `ADMIN_TOKEN` is not apiKey-scoped.
        Mapper omits internal `id`, `apiKeyId`, and FX/take fields.
        See `docs/CALL_OBSERVABILITY.md`.
      operationId: getAdminCalls
      security:
        - bearerAuth: []
      parameters:
        - name: callId
          in: query
          required: false
          description: Filter to one PaymentChallenge id (1–64 characters).
          schema:
            type: string
            minLength: 1
            maxLength: 64
        - name: limit
          in: query
          required: false
          description: Max events to return (1–100). Default 50.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        "200":
          description: Events newest-first (`createdAt` descending).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminCallsResponse"
              examples:
                happyPathProxy:
                  summary: Synthetic happy path (chronological in fixture file)
                  externalValue: ./fixtures/admin-calls-export.example.json
        "400":
          description: Invalid `callId` or `limit`
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminErrorBody"
              examples:
                badLimit:
                  value:
                    error: Invalid limit
                    message: limit must be an integer from 1 to 100
        "401":
          description: Missing or invalid Bearer / insufficient scope
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminErrorBody"
              examples:
                unauthorized:
                  value:
                    error: Unauthorized
                    message: Valid Bearer ADMIN_TOKEN or API key with admin:endpoints required
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Operator `ADMIN_TOKEN` or issuer API key with the required admin scope.
  schemas:
    CallEvent:
      type: object
      required: [type, sourceRoute, createdAt]
      additionalProperties: false
      properties:
        callId:
          type: string
        type:
          type: string
          enum: [challenge, settlement_ok, settlement_fail, delivery]
        sourceRoute:
          type: string
        currency:
          type: string
        amountDrops:
          type: integer
        txHash:
          type: string
        httpStatus:
          type: integer
        latencyMs:
          type: integer
        message:
          type: string
        originAssertion:
          type: string
          description: Blind issuer passthrough when present on settlement_ok.
        createdAt:
          type: string
          format: date-time
      description: |
        Fields returned by `src/routes/admin.ts`. Not included: event id,
        apiKeyId, takeDrops, fxUsdPerXrp, takeUsd, fxSource. Not on public live feed.
    AdminCallsResponse:
      type: object
      required: [events]
      additionalProperties: false
      properties:
        events:
          type: array
          items:
            $ref: "#/components/schemas/CallEvent"
    AdminErrorBody:
      type: object
      additionalProperties: false
      properties:
        error:
          type: string
        message:
          type: string
security:
  - bearerAuth: []
