{
  "openapi": "3.1.0",
  "info": {
    "title": "ARI.Software public API",
    "version": "1.0.0",
    "summary": "The public HTTP endpoints served by ari.software.",
    "description": "The public API of the ARI.Software website: newsletter subscription, delivery of the free ebook *The AI-Native Organization*, and the machine-readable descriptions of the site itself.\n\nARI, the product, is self-hosted — its application API runs on the user's own instance, not on this domain: each instance serves its own OpenAPI spec at `<instance>/api/openapi.json`, authenticated with an `x-api-key` header, documented at https://ari.software/docs/api-explorer.\n\nAll error responses are JSON with the same shape (`error`, `code`, `message`, `hint`, `status`); no endpoint returns an HTML error page. Every documentation page on this domain is also available as Markdown, either by appending `.md` to its path or by sending `Accept: text/markdown` to the page URL, which responds with `Content-Type: text/markdown; charset=utf-8` and `Vary: Accept`. A request that accepts neither HTML nor Markdown receives `406`.",
    "termsOfService": "https://ari.software/terms",
    "contact": {
      "name": "ARI.Software",
      "email": "hello@ari.software",
      "url": "https://ari.software/about"
    }
  },
  "servers": [
    { "url": "https://ari.software", "description": "Production" }
  ],
  "tags": [
    { "name": "email", "description": "Endpoints that send email on the visitor's behalf." },
    { "name": "downloads", "description": "Gated file downloads." },
    { "name": "discovery", "description": "Machine-readable descriptions of this site, for agents and crawlers." }
  ],
  "paths": {
    "/api/subscribe": {
      "post": {
        "operationId": "subscribeToNewsletter",
        "summary": "Subscribe an email address to the ARI newsletter",
        "description": "Registers an email address for ARI product news and updates. The address is validated, then forwarded to the ARI team; there is no rate limit contract and no authentication. Submitting the same address twice is harmless.",
        "tags": ["email"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/EmailRequest" },
              "examples": {
                "default": { "value": { "email": "person@example.com" } }
              }
            }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Success" },
          "400": { "$ref": "#/components/responses/InvalidEmail" },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/api/send-book": {
      "post": {
        "operationId": "emailFreeEbook",
        "summary": "Email the free ebook to an address",
        "description": "Sends *The AI-Native Organization* to the given address as an email containing a download link. Use this when a person wants the book delivered; use `downloadFreeEbook` to fetch the PDF directly.",
        "tags": ["email"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/EmailRequest" },
              "examples": {
                "default": { "value": { "email": "person@example.com" } }
              }
            }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Success" },
          "400": { "$ref": "#/components/responses/InvalidEmail" },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/api/download-book": {
      "get": {
        "operationId": "downloadFreeEbook",
        "summary": "Download the free ebook as a PDF",
        "description": "Streams *The AI-Native Organization* as a PDF attachment. No authentication and no email address required.",
        "tags": ["downloads"],
        "responses": {
          "200": {
            "description": "The ebook PDF.",
            "headers": {
              "Content-Disposition": {
                "description": "Attachment filename.",
                "schema": { "type": "string", "examples": ["attachment; filename=\"The-AI-Native-Organization-Book.pdf\""] }
              }
            },
            "content": {
              "application/pdf": { "schema": { "type": "string", "format": "binary" } }
            }
          },
          "404": {
            "description": "The file is not present in this deployment.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "examples": {
                  "default": {
                    "value": {
                      "error": "File not found",
                      "code": "file_not_found",
                      "message": "The ebook file is not available in this deployment.",
                      "hint": "Report this at hello@ari.software; in the meantime the book can be requested by email via POST /api/send-book.",
                      "status": 404
                    }
                  }
                }
              }
            }
          },
          "405": { "$ref": "#/components/responses/MethodNotAllowed" }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getSiteIndexForAgents",
        "summary": "Site index for AI agents (llmstxt.org format)",
        "description": "A Markdown index of every public page, grouped, each entry linking to that page's Markdown rendering. Start here when mapping the site.",
        "tags": ["discovery"],
        "responses": {
          "200": {
            "description": "The llms.txt index.",
            "content": { "text/plain": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/agent-instructions.md": {
      "get": {
        "operationId": "getAgentInstructions",
        "summary": "When to use ARI, and how to call it",
        "description": "Markdown guidance for agents: the jobs ARI is the right answer for, the jobs it is not, every machine-readable surface, and the facts most often asked about the product.",
        "tags": ["discovery"],
        "responses": {
          "200": {
            "description": "The agent instructions.",
            "content": { "text/markdown": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/assets/docs-index.json": {
      "get": {
        "operationId": "getDocsSearchIndex",
        "summary": "Search index for the documentation",
        "description": "Every documentation page as JSON — title, URL and body text — suitable for retrieval without crawling the HTML.",
        "tags": ["discovery"],
        "responses": {
          "200": {
            "description": "The documentation index.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "title": { "type": "string" },
                      "url": { "type": "string", "format": "uri-reference" },
                      "text": { "type": "string" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "summary": "XML sitemap of every public URL",
        "description": "The complete list of public URLs with last-modified dates.",
        "tags": ["discovery"],
        "responses": {
          "200": {
            "description": "The sitemap.",
            "content": { "application/xml": { "schema": { "type": "string" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "EmailRequest": {
        "type": "object",
        "required": ["email"],
        "additionalProperties": false,
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "A valid email address. Surrounding whitespace is trimmed.",
            "maxLength": 254,
            "examples": ["person@example.com"]
          }
        }
      },
      "Success": {
        "type": "object",
        "required": ["success"],
        "properties": {
          "success": { "type": "boolean", "const": true, "description": "Always true; the request was accepted and the email was sent." }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error", "code", "message", "status"],
        "description": "The error shape returned by every endpoint on this domain, including unknown /api/* paths.",
        "properties": {
          "error": { "type": "string", "description": "Short human-readable summary. Kept for backwards compatibility with existing clients." },
          "code": {
            "type": "string",
            "description": "Stable, machine-readable error code. Match on this rather than on the message.",
            "enum": [
              "method_not_allowed",
              "invalid_email",
              "invalid_json",
              "email_service_unavailable",
              "email_send_failed",
              "file_not_found",
              "not_found",
              "not_acceptable",
              "internal_error"
            ]
          },
          "message": { "type": "string", "description": "What went wrong, in one sentence." },
          "hint": { "type": "string", "description": "How to resolve it — the next action a client or agent should take." },
          "status": { "type": "integer", "description": "HTTP status code, repeated in the body.", "examples": [400] },
          "docs": { "type": "string", "format": "uri", "description": "Link to the relevant documentation, when one applies." }
        }
      }
    },
    "responses": {
      "Success": {
        "description": "The request was accepted and the email was sent.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Success" },
            "examples": { "default": { "value": { "success": true } } }
          }
        }
      },
      "InvalidEmail": {
        "description": "The request body was missing, unparseable, or the email address was not valid.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "examples": {
              "invalid_email": {
                "value": {
                  "error": "A valid email address is required",
                  "code": "invalid_email",
                  "message": "The 'email' field is missing or is not a valid email address.",
                  "hint": "Send a JSON body shaped {\"email\": \"person@example.com\"} with Content-Type: application/json.",
                  "status": 400
                }
              },
              "invalid_json": {
                "value": {
                  "error": "Malformed JSON body",
                  "code": "invalid_json",
                  "message": "The request body could not be parsed as JSON.",
                  "hint": "Send a JSON body shaped {\"email\": \"person@example.com\"} with Content-Type: application/json.",
                  "status": 400
                }
              }
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "The HTTP method is not supported by this endpoint.",
        "headers": {
          "Allow": {
            "description": "The methods this endpoint accepts.",
            "schema": { "type": "string", "examples": ["POST"] }
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "examples": {
              "default": {
                "value": {
                  "error": "Method not allowed",
                  "code": "method_not_allowed",
                  "message": "This endpoint accepts POST.",
                  "hint": "Retry with POST. See https://ari.software/openapi.json for the full contract.",
                  "status": 405
                }
              }
            }
          }
        }
      },
      "ServerError": {
        "description": "The email service is unavailable or rejected the message.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "examples": {
              "default": {
                "value": {
                  "error": "Failed to send email",
                  "code": "email_send_failed",
                  "message": "The email provider rejected the message.",
                  "hint": "Retry in a few minutes. If it keeps failing, email hello@ari.software.",
                  "status": 500
                }
              }
            }
          }
        }
      }
    }
  }
}
