{
  "openapi": "3.1.0",
  "info": {
    "title": "Apostl Public API",
    "version": "2026-08-25",
    "description": "Public JSON endpoints for Apostl service discovery, agent-readiness audits, Agent Arena proof packs, and the cross-origin Apostl Pulse setup flow hosted by platform.apostl.dev. Every documented error response includes a stable code, a message, and a resolution hint.",
    "contact": {
      "name": "Apostl founders",
      "url": "https://apostl.dev/contact",
      "email": "founders@apostl.dev"
    }
  },
  "servers": [
    {
      "url": "https://apostl.dev",
      "description": "Apostl production landing API"
    }
  ],
  "externalDocs": {
    "description": "Apostl developer portal and agent setup guidance",
    "url": "https://apostl.dev/developers"
  },
  "tags": [
    {
      "name": "System",
      "description": "Public service and browser configuration endpoints."
    },
    {
      "name": "Audits",
      "description": "Submit a public developer-onboarding journey for an agent-readiness evidence report."
    },
    {
      "name": "Arena",
      "description": "Request the proof pack attached to a published Agent Arena benchmark finding."
    },
    {
      "name": "Pulse",
      "description": "Create and verify an accountless Apostl Pulse installation on an authorized public HTTPS origin."
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "getLandingHealth",
        "summary": "Check Apostl landing service health",
        "description": "Returns the current landing service status and non-secret Apostl Pulse configuration state. Use this before submitting a public request when service availability matters.",
        "tags": ["System"],
        "responses": {
          "200": {
            "description": "The landing service is available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/turnstile-config": {
      "get": {
        "operationId": "getTurnstileConfiguration",
        "summary": "Read public form challenge configuration",
        "description": "Returns whether Cloudflare Turnstile is required for public landing forms and exposes only the public site key when enabled. No secret key is returned.",
        "tags": ["System"],
        "responses": {
          "200": {
            "description": "Current public challenge configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TurnstileConfiguration"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/quickstart-submissions": {
      "post": {
        "operationId": "submitAgentReadinessAudit",
        "summary": "Submit a public quickstart for an agent-readiness audit",
        "description": "Queues one public HTTP or HTTPS developer-onboarding journey. The email receives the evidence report. Do not submit credentials, private repository URLs, session cookies, private keys, or wallet seed phrases.",
        "tags": ["Audits"],
        "requestBody": {
          "required": true,
          "description": "A public quickstart URL and report-delivery email. A Turnstile token is required only when the configuration endpoint reports that challenge protection is enabled.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuickstartSubmission"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The audit was accepted for processing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuickstartAccepted"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamFailure"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/api/arena/report-requests": {
      "post": {
        "operationId": "requestArenaProofPack",
        "summary": "Request an Agent Arena finding proof pack",
        "description": "Requests the commands, trace, likely owner, and acceptance test for a published Agent Arena entry. The endpoint returns 404 when Agent Arena is not enabled on the landing service.",
        "tags": ["Arena"],
        "requestBody": {
          "required": true,
          "description": "A company email and the public benchmark entry context shown by Agent Arena.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ArenaProofPackRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The proof-pack request was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArenaProofPackAccepted"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamFailure"
          }
        }
      }
    },
    "/api/v1/pulse/setups": {
      "servers": [
        {
          "url": "https://platform.apostl.dev"
        }
      ],
      "post": {
        "operationId": "createPulseSetup",
        "summary": "Create an unclaimed Pulse setup",
        "description": "Reserves one authorized public HTTPS origin for seven days and returns the server-only API key plus opaque setup token once. Use the public Agent Traffic Analytics helper so these credentials are written directly to an owner-only file. Reserved documentation domains are rejected before credentials are issued.",
        "tags": ["Pulse"],
        "requestBody": {
          "required": true,
          "description": "The exact public origin where the caller is authorized to deploy Pulse, plus the public path Apostl should verify.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PulseSetupRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The unclaimed setup was created. The credential fields are returned only in this response and the response is marked no-store.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PulseSetupCreated"
                }
              }
            }
          },
          "409": {
            "description": "The origin already has an active or unexpired Pulse owner or reservation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PulseErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The origin or another setup field cannot be used. Reserved example domains receive this response before credentials are issued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PulseErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pulse/setups/{setup}/verify": {
      "servers": [
        {
          "url": "https://platform.apostl.dev"
        }
      ],
      "post": {
        "operationId": "verifyPulseSetup",
        "summary": "Verify the deployed Pulse installation",
        "description": "Fetches the exact public verification URL with a signed challenge. A claim URL appears only after the same verifier request is also accepted as a genuine eligible Pulse event with its IP address, full User-Agent, and canonical page URL.",
        "tags": ["Pulse"],
        "security": [
          {
            "PulseSetupToken": []
          }
        ],
        "parameters": [
          {
            "name": "setup",
            "in": "path",
            "required": true,
            "description": "Opaque setup identifier returned by createPulseSetup.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The signed response and its genuine event were verified; the one-time claim URL is now available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PulseVerifyResponse"
                }
              }
            }
          },
          "202": {
            "description": "The signed response passed, but the corresponding genuine event has not arrived yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PulseVerifyResponse"
                }
              }
            }
          },
          "401": {
            "description": "The setup token is missing or invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PulseErrorResponse"
                }
              }
            }
          },
          "410": {
            "description": "The unclaimed setup expired or has already been claimed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PulseErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "The exact public URL did not return a valid Pulse verification proof.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PulseErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiSpecification",
        "summary": "Download the Apostl OpenAPI specification",
        "description": "Returns this OpenAPI 3.1 JSON document so agents and developer tools can discover the current public API surface.",
        "tags": ["System"],
        "responses": {
          "200": {
            "description": "The current OpenAPI 3.1 specification.",
            "content": {
              "application/vnd.oai.openapi+json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "required": ["ok", "pulse"],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true,
            "description": "Confirms that the landing server handled the health request."
          },
          "pulse": {
            "type": "object",
            "required": ["enabled", "configured", "endpoint"],
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Whether Pulse request observation is enabled for this service."
              },
              "configured": {
                "type": "boolean",
                "description": "Whether the Pulse client has the server-side configuration it needs."
              },
              "endpoint": {
                "type": "string",
                "format": "uri",
                "description": "The non-secret Pulse ingest endpoint."
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "TurnstileConfiguration": {
        "type": "object",
        "required": ["enabled", "siteKey"],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether a Turnstile token is required by public forms."
          },
          "siteKey": {
            "type": "string",
            "description": "The public Turnstile site key when enabled, otherwise an empty string."
          }
        },
        "additionalProperties": false
      },
      "QuickstartSubmission": {
        "type": "object",
        "required": ["email", "quickstart_url"],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 320,
            "description": "Address that receives or follows the evidence report."
          },
          "quickstart_url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https?://",
            "description": "Public HTTP or HTTPS documentation or quickstart URL to execute."
          },
          "turnstile_token": {
            "type": "string",
            "description": "Cloudflare Turnstile token when challenge protection is enabled."
          },
          "metadata": {
            "type": "object",
            "description": "Optional client context. The server accepts only its bounded metadata fields and adds authoritative request metadata.",
            "additionalProperties": true
          }
        },
        "additionalProperties": false
      },
      "QuickstartAccepted": {
        "type": "object",
        "required": ["ok", "status"],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "status": {
            "type": "string",
            "description": "Initial processing status, normally queued."
          },
          "id": {
            "oneOf": [
              { "type": "integer" },
              { "type": "string" },
              { "type": "null" }
            ],
            "description": "Run identifier when supplied by the audit service."
          },
          "slug": {
            "type": ["string", "null"],
            "description": "Public report slug when supplied by the audit service."
          },
          "report_url": {
            "type": ["string", "null"],
            "format": "uri",
            "description": "Public tracking or report URL when available."
          }
        },
        "additionalProperties": false
      },
      "ArenaProofPackRequest": {
        "type": "object",
        "required": ["email", "entry_slug", "entry_name", "category"],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Company email that receives the proof pack."
          },
          "entry_slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
            "maxLength": 120,
            "description": "Stable slug of the published Arena entry."
          },
          "entry_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 160,
            "description": "Display name of the published Arena entry."
          },
          "category": {
            "type": "string",
            "enum": ["blockchain", "stablecoin", "prediction_market", "web3_inference"],
            "description": "Arena category containing the entry."
          },
          "page_url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https?://",
            "description": "Optional public page where the request originated."
          },
          "benchmark_timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the published benchmark snapshot."
          },
          "finding_type": {
            "type": "string",
            "enum": ["docs_mismatch", "environment_blocker", "sdk_mismatch", "api_mismatch", "auth_blocker"],
            "description": "Reviewed finding class shown by Arena."
          }
        },
        "additionalProperties": false
      },
      "ArenaProofPackAccepted": {
        "type": "object",
        "required": ["ok", "status"],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "status": {
            "type": "string",
            "description": "Initial proof-pack request status."
          }
        },
        "additionalProperties": false
      },
      "PulseSetupRequest": {
        "type": "object",
        "required": ["origin", "project_name"],
        "properties": {
          "origin": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://",
            "maxLength": 300,
            "description": "Exact public HTTPS origin where the caller is authorized to deploy Pulse. Paths, queries, credentials, custom ports, IP literals, localhost, and reserved documentation domains are rejected."
          },
          "verification_path": {
            "type": "string",
            "pattern": "^/",
            "maxLength": 1024,
            "default": "/",
            "description": "Public path that will answer the signed verifier request and emit the matching real event. Query strings and fragments are not allowed."
          },
          "project_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "Human-readable project name shown during claim."
          },
          "environment": {
            "type": "string",
            "enum": ["production", "staging", "development"],
            "default": "production"
          },
          "agent_name": {
            "type": ["string", "null"],
            "maxLength": 120,
            "description": "Optional name of the agent performing the installation."
          }
        },
        "additionalProperties": false
      },
      "PulseSetupCreated": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["setup_id", "status", "origin", "verification_url", "expires_at", "setup_token", "verify_url", "credentials"],
            "properties": {
              "setup_id": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "type": "string",
                "const": "pending_deployment"
              },
              "origin": {
                "type": "string",
                "format": "uri"
              },
              "verification_url": {
                "type": "string",
                "format": "uri"
              },
              "expires_at": {
                "type": "string",
                "format": "date-time"
              },
              "setup_token": {
                "type": "string",
                "writeOnly": true,
                "description": "Opaque Bearer credential for the verify operation. Returned once; store server-side and never log it."
              },
              "verify_url": {
                "type": "string",
                "format": "uri"
              },
              "credentials": {
                "type": "object",
                "required": ["api_key", "endpoint"],
                "properties": {
                  "api_key": {
                    "type": "string",
                    "writeOnly": true,
                    "description": "Server-only Pulse ingest API key. Returned once and remains active after claim."
                  },
                  "endpoint": {
                    "type": "string",
                    "format": "uri"
                  }
                },
                "additionalProperties": false
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "PulseVerifyResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["status"],
            "properties": {
              "status": {
                "type": "string",
                "enum": ["waiting_for_event", "verified"]
              },
              "claim_url": {
                "type": "string",
                "format": "uri",
                "description": "One-time human claim URL returned only when status is verified. It never contains the ingest API key."
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "PulseErrorResponse": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message", "resolution"],
            "properties": {
              "code": {
                "type": "string",
                "enum": ["invalid_request", "invalid_origin", "origin_unavailable", "invalid_setup_token", "setup_expired", "verification_failed"]
              },
              "message": {
                "type": "string"
              },
              "resolution": {
                "type": "string",
                "description": "Safe next action for an agent or operator."
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["ok", "error", "message", "resolution"],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string",
            "description": "Stable machine-readable error code."
          },
          "message": {
            "type": "string",
            "description": "Concise human-readable explanation."
          },
          "resolution": {
            "type": "string",
            "description": "Specific action the caller can take next."
          },
          "scope": {
            "type": "string",
            "description": "Rate-limit scope when applicable."
          },
          "retry_after_seconds": {
            "type": "integer",
            "minimum": 1,
            "description": "Seconds until retry when applicable."
          }
        },
        "additionalProperties": true
      }
    },
    "securitySchemes": {
      "PulseSetupToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "pulse_setup_*",
        "description": "Opaque setup token returned once by createPulseSetup. Do not use the Pulse ingest API key here."
      }
    },
    "responses": {
      "InvalidRequest": {
        "description": "The JSON body or one of its fields is invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "RequestTooLarge": {
        "description": "The request body exceeds the public endpoint limit.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "UnprocessableRequest": {
        "description": "The request is valid JSON but the selected public resource cannot be processed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested API feature or resource is not available.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "RateLimited": {
        "description": "The caller has reached a bounded public submission limit. Use the Retry-After header before retrying.",
        "headers": {
          "Retry-After": {
            "description": "Seconds until a retry is allowed.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "UpstreamFailure": {
        "description": "Apostl could not complete the request through its processing service.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "A required challenge or processing service is not configured or temporarily unavailable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ServerError": {
        "description": "The landing service encountered an unexpected error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    }
  }
}
