openapi: 3.0.3
info:
  title: RoRo Quantum API
  version: "1.0.0"
  description: |
    The public RoRo Quantum REST API. Authenticate with an API key (`qcs_live_…`)
    created in the console, sent as a Bearer token. Every run executes on a real
    Qiskit Aer backend and returns normalized counts.
  contact:
    name: RoRo Quantum
    url: https://roroquantum.com
  license:
    name: Proprietary
servers:
  - url: https://api.roroquantum.com
    description: Production
security:
  - apiKey: []
tags:
  - name: Machines
  - name: Runs
paths:
  /v1/machines:
    get:
      tags: [Machines]
      summary: List targets
      description: List the targets (simulators, and later real machines) available to your account.
      responses:
        "200":
          description: Available targets
          content:
            application/json:
              schema:
                type: array
                items: { $ref: "#/components/schemas/Machine" }
        "401": { $ref: "#/components/responses/Unauthorized" }
  /v1/runs:
    post:
      tags: [Runs]
      summary: Submit a run
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/RunRequest" }
      responses:
        "200":
          description: The created (and executed) run
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Run" }
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "402": { $ref: "#/components/responses/InsufficientCredits" }
    get:
      tags: [Runs]
      summary: List runs
      responses:
        "200":
          description: Your runs, most recent first
          content:
            application/json:
              schema:
                type: array
                items: { $ref: "#/components/schemas/Run" }
        "401": { $ref: "#/components/responses/Unauthorized" }
  /v1/runs/{id}:
    get:
      tags: [Runs]
      summary: Fetch a run
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: The run
          content:
            application/json:
              schema: { $ref: "#/components/schemas/Run" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }
components:
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: An API key created in the console, e.g. `qcs_live_…`.
  responses:
    Unauthorized:
      description: Missing or invalid API key
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    BadRequest:
      description: Invalid request (bad QASM, missing field, bad shots)
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    NotFound:
      description: Run not found
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
    InsufficientCredits:
      description: Not enough credits for the run
      content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } }
  schemas:
    Machine:
      type: object
      properties:
        targetId: { type: string, description: The id to pass as machineTargetId when submitting a run., example: "roro.sim.sv" }
        displayName: { type: string, example: "RoRo Statevector Simulator" }
        provider: { type: string, example: "roro" }
        kind: { type: string, enum: [sim, qpu], example: "sim" }
        qubits: { type: integer, description: Maximum qubits for this target., example: 8 }
        costPerShot: { type: number, format: float, description: Credits charged per shot (a run costs ceil(shots × costPerShot))., example: 0.005 }
        online: { type: boolean, description: Whether the target is currently accepting runs., example: true }
    RunRequest:
      type: object
      required: [machineTargetId, shots]
      properties:
        machineTargetId: { type: string, example: "roro.sim.sv" }
        shots: { type: integer, minimum: 1, maximum: 1000000, example: 5000 }
        qasm:
          type: string
          description: OpenQASM 2.0 source for the circuit.
          example: "OPENQASM 2.0; include \"qelib1.inc\"; qreg q[2]; creg c[2]; h q[0]; cx q[0],q[1]; measure q -> c;"
        layout:
          type: array
          items: { type: integer }
          nullable: true
          description: Optional initial qubit layout — pin logical qubits to physical qubits on a QPU target. Omit for automatic routing.
          example: [0, 7]
    Run:
      type: object
      properties:
        id: { type: string, example: "run_8f3a…" }
        machineTargetId: { type: string, example: "roro.sim.sv" }
        machineName: { type: string, description: Friendly display name of the target., example: "RoRo Statevector Simulator" }
        shots: { type: integer, example: 5000 }
        status: { type: string, enum: [queued, running, completed, failed], example: "completed" }
        cost: { type: number, description: Credits charged for this run., example: 25 }
        counts:
          type: object
          description: Measured bitstring counts (present when completed).
          additionalProperties: { type: integer }
          example: { "00": 2500, "11": 2500 }
        probabilities:
          type: object
          description: Normalized probabilities per bitstring (present when completed).
          additionalProperties: { type: number }
          example: { "00": 0.5, "11": 0.5 }
        error: { type: string, nullable: true, description: Failure reason (present when status is failed). }
        createdAt: { type: string, format: date-time, example: "2026-06-05T00:00:00Z" }
        qasm: { type: string, nullable: true, description: The submitted OpenQASM source. }
        providerJobId: { type: string, nullable: true, description: Upstream provider job id when applicable. }
        refundable: { type: boolean, description: True when a failed run is eligible for a credit refund (machine-side failure)., example: false }
        refundStatus:
          type: string
          nullable: true
          enum: [pending, approved, rejected]
          description: Status of a refund request for this run, if any.
    Error:
      type: object
      properties:
        error: { type: string, example: "Insufficient credits for this run" }
