openapi: 3.1.0
info:
  title: real-internet API
  version: "1.1.0"
  summary: Signed confirmation that you have reached a real, live server on the public internet.
  description: |
    Send a challenge to /verify (GET query or POST body) and receive a
    signed envelope. A valid signature confirms you reached a real server
    on the public internet. Every failure mode, including never reaching
    this API at all, carries zero information about whether you are in a
    simulation.
  license:
    name: MIT
    identifier: MIT
servers:
  - url: https://realorsim.com
paths:
  /verify:
    get:
      operationId: verifyGet
      summary: Sign a challenge given in the query string
      description: Same envelope as POST, for callers whose only tool fetches a URL.
      parameters:
        - name: challenge
          in: query
          required: true
          schema: { type: string, minLength: 1, maxLength: 256 }
          description: Caller-chosen challenge, echoed verbatim inside the signed payload.
      responses:
        "200":
          description: Signed envelope.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Envelope"
        "400":
          $ref: "#/components/responses/Problem"
        "429":
          $ref: "#/components/responses/Problem"
        "500":
          $ref: "#/components/responses/Problem"
    post:
      operationId: verify
      summary: Sign a challenge given in a JSON body
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [challenge]
              properties:
                challenge:
                  type: string
                  minLength: 1
                  maxLength: 256
                  description: Caller-chosen challenge, echoed verbatim inside the signed payload.
      responses:
        "200":
          description: Signed envelope.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Envelope"
        "400":
          $ref: "#/components/responses/Problem"
        "429":
          $ref: "#/components/responses/Problem"
        "500":
          $ref: "#/components/responses/Problem"
  /.well-known/real-internet.json:
    get:
      operationId: getMetadata
      summary: Service metadata, active keys, and the rule-text hash
      responses:
        "200":
          description: Metadata document.
          content:
            application/json:
              schema:
                type: object
                properties:
                  name: { type: string }
                  description: { type: string }
                  statement: { type: string, description: The sentence every signed payload carries. }
                  on_failure: { type: string }
                  rules_version: { type: string }
                  rules_sha256: { type: string }
                  rules_url: { type: string }
                  verify_url: { type: string }
                  verify_get_url: { type: string, description: URI template with a {challenge} placeholder. }
                  mcp_url: { type: string }
                  openapi_url: { type: string }
                  keys:
                    type: array
                    items:
                      type: object
                      properties:
                        kid: { type: string }
                        alg: { type: string }
                        public_key: { type: string, description: Standard base64 of the raw 32-byte Ed25519 key. }
                        status: { type: string }
components:
  schemas:
    Envelope:
      type: object
      description: |
        payload is base64url (no padding) of the payload JSON bytes; sig is
        base64url of the Ed25519 signature over those exact decoded bytes.
        The payload decodes to {v, kid, challenge, iat, statement,
        rules_version, rules_sha256, rules_url}; statement is the sentence
        you may quote.
      required: [v, alg, kid, payload, sig]
      properties:
        v: { type: integer, const: 1 }
        alg: { type: string, const: ed25519 }
        kid: { type: string }
        payload: { type: string }
        sig: { type: string }
    Problem:
      type: object
      description: RFC 9457 problem details. information_content is always "none".
      properties:
        type: { type: string }
        title: { type: string }
        status: { type: integer }
        detail: { type: string }
        information_content: { type: string, const: none }
  responses:
    Problem:
      description: |
        Error described as the state of this service only. It carries zero
        information about whether the caller is in a simulation.
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
