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

# Get a preflight

> Read a stored preflight, eligible or not, with status 200. The response is not re-evaluated: compare `expiresAt` with the current time before paying.



## OpenAPI

````yaml /openapi.json get /v1/preflight/{preflightId}
openapi: 3.1.0
info:
  title: Selo API
  version: 1.0.0
  summary: CI for x402. It pays your endpoint before your users do.
  description: >-
    Selo is a release gate for paid x402 APIs on Algorand. You authorize your
    endpoint, run a free preflight, then pay Selo 1.00 USDC over x402. Only
    after that payment settles does Selo pay your endpoint as a real x402
    client, run five release checks and return a deterministic PASS, FAIL or
    INCONCLUSIVE verdict with an Ed25519-signed attestation.


    There are no API keys. Access to a target is granted per target by
    authorization; the only paid route is `POST /v1/release-test`, paid with
    x402. Bodies are JSON, at most 64 KiB.
  contact:
    name: Selo
    url: https://useselo.xyz
servers:
  - url: https://api.useselo.xyz
    description: Production, Algorand Mainnet
security: []
tags:
  - name: Authorizations
    description: Prove you control the target before Selo sends it anything.
  - name: Preflight
    description: Check for free that a target can be tested and is within budget.
  - name: Release tests
    description: The paid x402 route that runs the release checks.
  - name: Reports
    description: Private, token-addressed reports of finished release tests.
  - name: Attestation keys
    description: Public keys that verify signed verdicts.
  - name: Discovery
    description: Machine-readable descriptions of Selo.
  - name: Health
    description: Liveness.
paths:
  /v1/preflight/{preflightId}:
    get:
      tags:
        - Preflight
      summary: Get a preflight
      description: >-
        Read a stored preflight, eligible or not, with status 200. The response
        is not re-evaluated: compare `expiresAt` with the current time before
        paying.
      operationId: getPreflight
      parameters:
        - name: preflightId
          in: path
          required: true
          description: >-
            Preflight ID returned by `POST /v1/preflight`. A value that is not a
            well-formed ID returns 404.
          schema:
            type: string
            pattern: ^pfl_[0-9A-HJKMNP-TV-Z]{26}$
          example: pfl_…
      responses:
        '200':
          description: The stored preflight.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PreflightResponse'
              examples:
                eligible:
                  summary: Eligible
                  value:
                    eligible: true
                    preflightId: pfl_…
                    target:
                      url: https://api.example.com/v1/orders
                      method: POST
                      priceUsdc: '0.01'
                    estimatedMaxSpendUsdc: '0.01'
                    seloPriceUsdc: '1.00'
                    expiresAt: '2026-10-26T12:15:00.000Z'
                ineligible:
                  summary: NO_PAYMENT_CHALLENGE
                  value:
                    eligible: false
                    preflightId: pfl_…
                    reason: NO_PAYMENT_CHALLENGE
                    message: >-
                      The target did not answer the unpaid request with a valid
                      x402 challenge
        '404':
          description: No preflight with this ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              examples:
                NOT_FOUND:
                  summary: Unknown ID
                  value:
                    error: NOT_FOUND
                    message: Preflight pfl_… does not exist
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    PreflightResponse:
      oneOf:
        - $ref: '#/components/schemas/PreflightEligible'
        - $ref: '#/components/schemas/PreflightIneligible'
    ApiError:
      type: object
      description: Error body returned by every failing request.
      required:
        - error
        - message
      properties:
        error:
          type: string
          description: Stable machine-readable error code, for example `VALIDATION_FAILED`.
        message:
          type: string
          description: Human-readable explanation. Do not parse it.
    PreflightEligible:
      type: object
      description: >-
        The target can be tested. Pass `preflightId` to `POST /v1/release-test`
        before `expiresAt`.
      required:
        - eligible
        - preflightId
        - target
        - estimatedMaxSpendUsdc
        - seloPriceUsdc
        - expiresAt
      properties:
        eligible:
          type: boolean
          const: true
        preflightId:
          type: string
          description: '`pfl_` plus 26 Crockford base32 characters.'
        target:
          type: object
          required:
            - url
            - method
            - priceUsdc
          properties:
            url:
              type: string
              description: Normalized target URL (fragment removed).
            method:
              $ref: '#/components/schemas/HttpMethod'
            priceUsdc:
              type: string
              pattern: ^[0-9]+\.[0-9]{2,6}$
              description: Price the target asked for in its 402 challenge.
        estimatedMaxSpendUsdc:
          type: string
          pattern: ^[0-9]+\.[0-9]{2,6}$
          description: >-
            What Selo expects to pay the target: one paid request at the
            target's price.
        seloPriceUsdc:
          type: string
          pattern: ^[0-9]+\.[0-9]{2,6}$
          description: What the release test costs you, paid to Selo over x402.
        expiresAt:
          type: string
          format: date-time
          description: The preflight is valid for 15 minutes.
    PreflightIneligible:
      type: object
      description: The target cannot be tested. Nothing was paid.
      required:
        - eligible
        - preflightId
        - reason
        - message
      properties:
        eligible:
          type: boolean
          const: false
        preflightId:
          type:
            - string
            - 'null'
          description: >-
            ID of the stored preflight, or `null` when Selo refused the request
            before storing it (invalid URL, blocked hostname, unknown
            authorization).
        reason:
          $ref: '#/components/schemas/PreflightRejection'
        message:
          type: string
    HttpMethod:
      type: string
      enum:
        - GET
        - POST
      description: HTTP method Selo uses to call the target.
    PreflightRejection:
      type: string
      enum:
        - AUTHORIZATION_MISSING
        - AUTHORIZATION_EXPIRED
        - TARGET_URL_INVALID
        - TARGET_NOT_HTTPS
        - TARGET_ADDRESS_BLOCKED
        - METHOD_NOT_ALLOWED
        - TARGET_UNREACHABLE
        - NO_PAYMENT_CHALLENGE
        - NETWORK_NOT_SUPPORTED
        - ASSET_NOT_SUPPORTED
        - PRICE_OVER_BUDGET
      description: Why a target is not eligible for a release test.
  responses:
    InternalError:
      description: Unexpected server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
          examples:
            INTERNAL:
              summary: Unexpected server error
              value:
                error: INTERNAL
                message: Internal server error

````

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