openapi: 3.1.0
info:
  title: Pingpong API
  version: 2026-07-07
  description: OpenAI-compatible endpoints for Pingpong requests.
servers:
  - url: https://api.pingpongit.com/v1
security:
  - bearerAuth: []
tags:
  - name: Models
  - name: Chat
  - name: Responses
paths:
  /models:
    get:
      tags: [Models]
      summary: List models
      operationId: listModels
      responses:
        "200":
          description: Available Pingpong model aliases.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ModelList"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /chat/completions:
    post:
      tags: [Chat]
      summary: Create a chat completion
      operationId: createChatCompletion
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ChatCompletionRequest"
            examples:
              fast:
                summary: Fast route
                value:
                  model: pingpong-fast
                  messages:
                    - role: user
                      content: Pressure-test this vendor exception before approval.
                  stream: false
      responses:
        "200":
          description: OpenAI-style chat completion.
          headers:
            X-PingPong-Request-Id:
              $ref: "#/components/headers/RequestId"
            X-PingPong-Trace-Id:
              $ref: "#/components/headers/TraceId"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ChatCompletionResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/Unavailable"
  /responses:
    post:
      tags: [Responses]
      summary: Create a response
      operationId: createResponse
      parameters:
        - $ref: "#/components/parameters/IdempotencyKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ResponsesRequest"
      responses:
        "200":
          description: OpenAI-style response object.
          headers:
            X-PingPong-Request-Id:
              $ref: "#/components/headers/RequestId"
            X-PingPong-Trace-Id:
              $ref: "#/components/headers/TraceId"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResponseObject"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
  /responses/{response_id}:
    get:
      tags: [Responses]
      summary: Retrieve a response
      operationId: retrieveResponse
      parameters:
        - name: response_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Stored response object.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResponseObject"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: Response not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorEnvelope"
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Pingpong API key
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
        maxLength: 255
      description: Stable key for retried requests.
  headers:
    RequestId:
      description: Request identifier for support and reconciliation.
      schema:
        type: string
    TraceId:
      description: Trace identifier for support and reconciliation.
      schema:
        type: string
  responses:
    BadRequest:
      description: Invalid request body or parameter.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
    Unauthorized:
      description: Missing, invalid, expired, paused, or revoked API key.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
    RateLimited:
      description: Request exceeded an account limit.
      headers:
        Retry-After:
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
    Unavailable:
      description: Route or provider work is temporarily unavailable.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorEnvelope"
  schemas:
    ModelList:
      type: object
      required: [object, data]
      properties:
        object:
          type: string
          const: list
        data:
          type: array
          items:
            type: object
            required: [id, object, owned_by]
            properties:
              id:
                type: string
                enum: [pingpong-fast, pingpong-pro, pingpong-verify]
              object:
                type: string
                const: model
              owned_by:
                type: string
                example: pingpong
    ChatCompletionRequest:
      type: object
      required: [model, messages]
      properties:
        model:
          type: string
          enum: [pingpong-fast, pingpong-pro, pingpong-verify]
        messages:
          type: array
          minItems: 1
          items:
            $ref: "#/components/schemas/ChatMessage"
        stream:
          type: boolean
          default: false
        temperature:
          type: number
          minimum: 0
          maximum: 2
    ChatMessage:
      type: object
      required: [role, content]
      properties:
        role:
          type: string
          enum: [system, user, assistant, tool]
        content:
          oneOf:
            - type: string
            - type: array
              items:
                type: object
                additionalProperties: true
    ChatCompletionResponse:
      type: object
      required: [id, object, created, model, choices]
      properties:
        id:
          type: string
        object:
          type: string
          const: chat.completion
        created:
          type: integer
        model:
          type: string
        choices:
          type: array
          items:
            type: object
            required: [index, message, finish_reason]
            properties:
              index:
                type: integer
              message:
                $ref: "#/components/schemas/ChatMessage"
              finish_reason:
                type: string
        usage:
          $ref: "#/components/schemas/Usage"
        pingpong:
          $ref: "#/components/schemas/PingpongTrace"
    ResponsesRequest:
      type: object
      required: [model, input]
      properties:
        model:
          type: string
          enum: [pingpong-fast, pingpong-pro, pingpong-verify]
        input:
          oneOf:
            - type: string
            - type: array
              items:
                type: object
                additionalProperties: true
        stream:
          type: boolean
          default: false
    ResponseObject:
      type: object
      required: [id, object, status]
      properties:
        id:
          type: string
        object:
          type: string
          example: response
        status:
          type: string
          enum: [queued, in_progress, completed, failed]
        output_text:
          type: string
        usage:
          $ref: "#/components/schemas/Usage"
        pingpong:
          $ref: "#/components/schemas/PingpongTrace"
    Usage:
      type: object
      properties:
        prompt_tokens:
          type: integer
        completion_tokens:
          type: integer
        total_tokens:
          type: integer
    PingpongTrace:
      type: object
      properties:
        request_id:
          type: string
        trace_id:
          type: string
        route:
          type: string
        models:
          type: array
          items:
            type: string
        source_gathering:
          type: string
        verifier:
          type: string
    ErrorEnvelope:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [message, type, code]
          properties:
            message:
              type: string
            type:
              type: string
            code:
              type: string
            param:
              type: string
              nullable: true
        pingpong:
          type: object
          properties:
            request_id:
              type: string
            docs_url:
              type: string
