> ## Documentation Index
> Fetch the complete documentation index at: https://docs.moonbounce.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# List review items

> With state=open (the default), the reviewer's open items, oldest fill first and in rank order within it. An open listing first tops the queue up to the daily budget (12 per decision, 25 in total, per UTC day), expiring items queued more than 3 days ago. Listing does not count as showing an item (see /shown). Blind items (spot checks) carry no prediction until answered. `remaining_today` counts every open item matching the filter, not just this page, even for state=done. state=done lists this reviewer's answered, withdrawn, skipped and expired items, newest settled first, then id descending, without filling or expiring the queue. Settled items carry handled from the reviewer's latest answer (POST .../change replaces it; a correction through POST /v1/feedback does not). Skipped and expired blind items keep their prediction and summary hidden. With counts=true, a first page (no cursor) of either state also carries `counts`: the reviewer's open, done and done-today totals and a per-decision breakdown, ignoring decision_id; cursor pages and pages that don't ask omit it.



## OpenAPI

````yaml /openapi.json get /v1/review/items
openapi: 3.1.0
info:
  title: Moonbounce Decisions API
  version: 0.0.0
  description: >-
    Moonbounce decisions: evaluate items against a decision spec (features
    combined by aggregators), record feedback and seed examples, review a ranked
    queue, and improve the spec through suggestions that ship as code diffs,
    each with a preview (backtest) and an evidence label.


    **Authentication.** Send an API key as `Authorization: Bearer <key>` on
    every operation except `GET /health` and `POST /v1/specs/hash`. Call the API
    from a server, never a browser: a key must not reach one, and the API sends
    no CORS headers. A key belongs to one organization and one environment:
    production, or test for a key with the `env:test` permission. Test traffic
    never counts as production traffic.


    **Requests.** JSON bodies (`Content-Type: application/json`) of at most 1
    MB, parsed strictly: duplicate keys, lone surrogates, integers outside
    ±(2^53 - 1), `__proto__` keys, U+0000 and nesting deeper than 64 are a 400.


    **Retries.** Send an `Idempotency-Key` on every POST under /v1 that takes
    one (all but `POST /v1/specs/hash`). Keep it for the request's retries. The
    same key with the same request returns the first stored result, marked
    `Idempotent-Replayed: true`, for 24 hours (410 if that result was since
    deleted); with another request it is 422 IDEMPOTENCY_KEY_REUSED. Keys are
    scoped to the organization and environment across every operation, so use a
    fresh key per request. A request that failed before its result was stored
    runs again when retried. 429 and 503 under /v1 may carry `Retry-After`
    (seconds); a daily QUOTA_EXCEEDED cap instead names its reset time.


    **Errors.** Every error under /v1 is `{"error": {"type", "message",
    "reason"?, "param"?, "details"?}}` (ErrorBody); `GET /health` answers its
    own shape. Every response carries a `Request-Id` header. Rate limits apply
    per key and per client IP, counted per Cloudflare location.
servers:
  - url: https://api.moonbounce.ai
    description: Production
security: []
paths:
  /v1/review/items:
    get:
      tags:
        - review
      summary: List review items
      description: >-
        With state=open (the default), the reviewer's open items, oldest fill
        first and in rank order within it. An open listing first tops the queue
        up to the daily budget (12 per decision, 25 in total, per UTC day),
        expiring items queued more than 3 days ago. Listing does not count as
        showing an item (see /shown). Blind items (spot checks) carry no
        prediction until answered. `remaining_today` counts every open item
        matching the filter, not just this page, even for state=done. state=done
        lists this reviewer's answered, withdrawn, skipped and expired items,
        newest settled first, then id descending, without filling or expiring
        the queue. Settled items carry handled from the reviewer's latest answer
        (POST .../change replaces it; a correction through POST /v1/feedback
        does not). Skipped and expired blind items keep their prediction and
        summary hidden. With counts=true, a first page (no cursor) of either
        state also carries `counts`: the reviewer's open, done and done-today
        totals and a per-decision breakdown, ignoring decision_id; cursor pages
        and pages that don't ask omit it.
      operationId: listReviewItems
      parameters:
        - schema:
            type: string
            enum:
              - open
              - done
            default: open
          required: false
          name: state
          in: query
        - schema:
            $ref: '#/components/schemas/DecisionId'
          required: false
          name: decision_id
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 20
          required: false
          name: limit
          in: query
        - schema:
            type: string
            minLength: 1
            maxLength: 1024
          required: false
          name: cursor
          in: query
        - schema:
            type: boolean
            default: false
            description: >-
              `true` adds `counts` to a first page (no `cursor`). Default
              `false`.
          required: false
          description: '`true` adds `counts` to a first page (no `cursor`). Default `false`.'
          name: counts
          in: query
      responses:
        '200':
          description: The queue
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReviewQueue'
        '400':
          description: 'Invalid request: `param` names the field at fault when one applies'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '401':
          description: Missing or invalid API key (reason KEY_INVALID)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '403':
          description: The key may not do this
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '429':
          description: >-
            RATE_LIMITED: retry after Retry-After seconds; QUOTA_EXCEEDED:
            details.reset_at gives the daily reset time (no Retry-After), or
            details.too_large asks for a smaller request
          headers:
            Retry-After:
              schema:
                type: string
                description: Seconds to wait before retrying, when waiting helps.
              required: false
              description: Seconds to wait before retrying, when waiting helps.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '503':
          description: >-
            Temporarily unavailable, with Retry-After (for example reason
            AUTH_UNAVAILABLE, ENGINE_UNAVAILABLE or STORE_UNAVAILABLE): retry
            with the same Idempotency-Key
          headers:
            Retry-After:
              schema:
                type: string
                description: Seconds to wait before retrying, when waiting helps.
              required: true
              description: Seconds to wait before retrying, when waiting helps.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
      security:
        - bearerAuth:
            - decisions:develop
components:
  schemas:
    DecisionId:
      type: string
      pattern: ^[a-z][a-z0-9_.-]{0,127}$
    ReviewQueue:
      type: object
      properties:
        environment:
          $ref: '#/components/schemas/Environment'
        items:
          type: array
          items:
            $ref: '#/components/schemas/ReviewItem'
        next_cursor:
          type:
            - string
            - 'null'
        remaining_today:
          type: integer
          minimum: 0
        counts:
          $ref: '#/components/schemas/ReviewCounts'
      required:
        - environment
        - items
        - next_cursor
        - remaining_today
      additionalProperties: false
    ErrorBody:
      type: object
      properties:
        error:
          type: object
          properties:
            type:
              $ref: '#/components/schemas/ErrorType'
            reason:
              type: string
              pattern: ^[A-Z][A-Z0-9_]+$
              description: >-
                Set where a caller can act on it, one of the reasons in the
                ErrorReason schema. New reasons may be added: treat an unknown
                one by the status and `type`.
            message:
              type: string
              description: For people; don't parse it.
            param:
              type: string
              description: >-
                The request field at fault, as a dotted path (`subject.0.text`,
                `claims.1.value`).
            details:
              type: object
              additionalProperties: {}
          required:
            - type
            - message
          additionalProperties: false
      required:
        - error
      additionalProperties: false
    Environment:
      type: string
      enum:
        - production
        - test
      description: >-
        The environment of the key that made the call: `production` or `test`.
        Evaluations, feedback, reviews and suggestions are separate per
        environment; registered structures are shared.
    ReviewItem:
      type: object
      properties:
        environment:
          $ref: '#/components/schemas/Environment'
        id:
          $ref: '#/components/schemas/InbId'
        decision_id:
          $ref: '#/components/schemas/DecisionId'
        decision_title:
          type: string
        decision_index:
          type: integer
          minimum: 0
        evaluation_id:
          $ref: '#/components/schemas/EvlId'
        version:
          type: object
          properties:
            structure:
              $ref: '#/components/schemas/VersionHash'
            weights:
              $ref: '#/components/schemas/VersionHash'
          required:
            - structure
            - weights
          additionalProperties: false
        lane:
          $ref: '#/components/schemas/ReviewLane'
        reason:
          type: object
          properties:
            tag:
              $ref: '#/components/schemas/ReviewReasonTag'
            text:
              type: string
          required:
            - tag
            - text
          additionalProperties: false
        tags:
          type: array
          items:
            $ref: '#/components/schemas/ReviewReasonTag'
          minItems: 1
        guidance:
          type: string
        blind:
          type: boolean
        rank:
          type: number
        queued_at:
          $ref: '#/components/schemas/Timestamp'
        shown_at:
          $ref: '#/components/schemas/Timestamp'
        content:
          anyOf:
            - $ref: '#/components/schemas/ReviewContent'
            - type: 'null'
        sensitive:
          type: boolean
        summary:
          type: string
        target:
          type: string
        outcome_choices:
          type: array
          items:
            $ref: '#/components/schemas/OutcomeChoice'
        cuts:
          type: array
          items:
            type: object
            properties:
              at:
                type: number
              outcome:
                $ref: '#/components/schemas/Name'
            required:
              - at
              - outcome
            additionalProperties: false
          minItems: 1
        below:
          $ref: '#/components/schemas/Name'
        features:
          type: array
          items:
            $ref: '#/components/schemas/ReviewFeature'
        prediction:
          $ref: '#/components/schemas/ReviewPrediction'
        handled:
          $ref: '#/components/schemas/ReviewHandled'
      required:
        - environment
        - id
        - decision_id
        - evaluation_id
        - lane
        - reason
        - tags
        - blind
        - rank
        - queued_at
        - content
        - sensitive
        - outcome_choices
        - features
      additionalProperties: false
    ReviewCounts:
      type: object
      properties:
        open:
          type: integer
          minimum: 0
          description: >-
            Open items: not answered, skipped, expired or withdrawn, and the
            evaluation has no human feedback. On state=open it is counted after
            the fill, so it equals an unfiltered listing's `remaining_today`;
            state=done does not fill or expire first.
        done:
          type: integer
          minimum: 0
          description: >-
            Settled items: answered (including later withdrawn), skipped (either
            reason) or expired.
        done_today:
          type: integer
          minimum: 0
          description: >-
            Settled items handled since 00:00 UTC today, by the time
            `handled.at` shows: withdrawn_at for a withdrawn answer, else when
            it was answered, skipped or expired.
        by_decision:
          type: array
          items:
            $ref: '#/components/schemas/ReviewDecisionCount'
          description: >-
            Every decision with an item in `open` or `done`, in `decision_index`
            order. Sums to the totals.
      required:
        - open
        - done
        - done_today
        - by_decision
      additionalProperties: false
      description: >-
        The reviewer's queue totals in this organization and environment, for
        counts and a decision filter. Only when asked for (`counts=true`) on a
        first page (no `cursor`), for either state. They ignore `decision_id`;
        items whose evaluation was deleted are not counted.
    ErrorType:
      type: string
      enum:
        - invalid_request
        - authentication
        - permission_denied
        - not_found
        - conflict
        - rate_limited
        - engine_failed
        - unavailable
        - internal
    InbId:
      type: string
      pattern: >-
        ^inb_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
    EvlId:
      type: string
      pattern: >-
        ^evl_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
    VersionHash:
      type: string
      pattern: ^sha256:[0-9a-f]{64}$
    ReviewLane:
      type: string
      enum:
        - active
        - random
    ReviewReasonTag:
      type: string
      enum:
        - uncertain
        - novel
        - spot_check
        - near_cut
    Timestamp:
      type: string
      format: date-time
    ReviewContent:
      type: object
      properties:
        subject:
          type: array
          items:
            $ref: '#/components/schemas/ContentPart'
        context:
          type: array
          items:
            $ref: '#/components/schemas/ContentPart'
      required:
        - subject
      additionalProperties: false
    OutcomeChoice:
      type: object
      properties:
        outcome:
          $ref: '#/components/schemas/Name'
        display:
          type: string
      required:
        - outcome
      additionalProperties: false
    Name:
      type: string
      pattern: ^[a-z][a-z0-9_]{0,63}$
    ReviewFeature:
      type: object
      properties:
        name:
          $ref: '#/components/schemas/Name'
        node_hash:
          $ref: '#/components/schemas/VersionHash'
        prompt:
          type: string
        effect:
          type: string
          enum:
            - raises
            - lowers
        guidance:
          type: string
        criteria:
          type: object
          properties:
            'true':
              type: string
            'false':
              type: string
          additionalProperties: false
      required:
        - name
        - node_hash
        - prompt
      additionalProperties: false
    ReviewPrediction:
      type: object
      properties:
        score:
          type: number
        outcome:
          $ref: '#/components/schemas/Name'
        features:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/ReviewLeafValue'
        contributions:
          type: object
          additionalProperties:
            type: number
      required:
        - features
      additionalProperties: false
    ReviewHandled:
      type: object
      properties:
        state:
          type: string
          enum:
            - confirmed
            - changed
            - answered
            - unsure
            - skipped
            - expired
            - withdrawn
        at:
          $ref: '#/components/schemas/Timestamp'
        feedback_id:
          $ref: '#/components/schemas/FbkId'
        changed_at:
          $ref: '#/components/schemas/Timestamp'
        outcome:
          $ref: '#/components/schemas/Name'
        target:
          type: boolean
        matched:
          type: boolean
      required:
        - state
        - at
      additionalProperties: false
    ReviewDecisionCount:
      type: object
      properties:
        decision_id:
          $ref: '#/components/schemas/DecisionId'
        decision_title:
          type: string
          description: >-
            The title on the structure of this reviewer's most recently queued
            item for the decision (registered meta over the spec's own meta, as
            on items). Omitted when it has none.
        decision_index:
          type: integer
          minimum: 0
          description: >-
            The decision's organization-wide creation order (created_at,
            decision_id), zero-based, as on items.
        open:
          type: integer
          minimum: 0
          description: This reviewer's open items for the decision, counted as `open` is.
        done:
          type: integer
          minimum: 0
          description: >-
            This reviewer's settled items for the decision, counted as `done`
            is.
        newest_open_version:
          type: object
          properties:
            structure:
              $ref: '#/components/schemas/VersionHash'
            weights:
              $ref: '#/components/schemas/VersionHash'
          required:
            - structure
            - weights
          additionalProperties: false
          description: >-
            The evaluated structure and weights hashes of this reviewer's most
            recently queued open item for the decision (latest `queued_at`, then
            highest id), as an item's `version`. Omitted when nothing is open.
        open_versions:
          type: integer
          minimum: 0
          description: >-
            How many distinct (structure, weights) versions this reviewer's open
            items for the decision carry.
      required:
        - decision_id
        - decision_index
        - open
        - done
        - open_versions
      additionalProperties: false
    ContentPart:
      oneOf:
        - $ref: '#/components/schemas/TextPart'
        - $ref: '#/components/schemas/JsonPart'
      discriminator:
        propertyName: type
        mapping:
          text: '#/components/schemas/TextPart'
          json: '#/components/schemas/JsonPart'
    ReviewLeafValue:
      anyOf:
        - type: object
          properties:
            type:
              type: string
              enum:
                - boolean
            value:
              type: number
              minimum: 0
              maximum: 1
          required:
            - type
            - value
          additionalProperties: false
        - type: object
          properties:
            type:
              type: string
              enum:
                - boolean
            abstained:
              type: boolean
              enum:
                - true
            reason:
              type: string
          required:
            - type
            - abstained
          additionalProperties: false
        - type: object
          properties:
            type:
              type: string
              enum:
                - boolean
            failed:
              type: boolean
              enum:
                - true
            reason:
              type: string
          required:
            - type
            - failed
          additionalProperties: false
    FbkId:
      type: string
      pattern: >-
        ^fbk_[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
    TextPart:
      type: object
      properties:
        type:
          type: string
          enum:
            - text
        text:
          type: string
          minLength: 1
        name:
          type: string
          pattern: ^[a-z][a-z0-9_]{0,63}$
          description: >-
            Names the part, so a feature's `inputs` can pick it. In `subject`,
            avoid "context" when the request also sends `context`.
        sensitive:
          type: boolean
          description: >-
            Display policy only: reviewers see the part blurred or behind a
            link. The engine still reads it and it is stored like any other
            part.
      required:
        - type
        - text
      additionalProperties: false
    JsonPart:
      type: object
      properties:
        type:
          type: string
          enum:
            - json
        data:
          anyOf:
            - type: object
              additionalProperties: {}
            - type: array
              items: {}
        name:
          type: string
          pattern: ^[a-z][a-z0-9_]{0,63}$
          description: >-
            Names the part, so a feature's `inputs` can pick it. In `subject`,
            avoid "context" when the request also sends `context`.
        sensitive:
          type: boolean
          description: >-
            Display policy only: reviewers see the part blurred or behind a
            link. The engine still reads it and it is stored like any other
            part.
      required:
        - type
        - data
      additionalProperties: false
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An API key, sent as `Authorization: Bearer <key>`. Each operation lists
        the scope its key needs: `decisions:evaluate` (evaluate and read
        evaluations), `decisions:feedback` (your app's feedback) or
        `decisions:develop` (everything else, including owner feedback and the
        review queue). An operation listing no scope takes any scoped key. A key
        with no scope, or without the operation's, gets 403 INSUFFICIENT_SCOPE.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.