{"openapi":"3.1.0","info":{"title":"Ariso Website API","version":"1.0.0","summary":"Public HTTP endpoints served by ariso.ai.","description":"The public endpoints behind ariso.ai: lead capture for the contact and program\napplication forms, newsletter subscription, blog share counts, and dynamic Open\nGraph image generation.\n\nNo authentication is required — these are the same endpoints the website itself\ncalls from the browser. They are rate-limited at the edge and every one of them\nreturns errors as JSON in the shape of `#/components/schemas/Error`.\n\nEvery page on ariso.ai also serves a Markdown representation: send\n`Accept: text/markdown` or append `.md` to any URL. `GET /llms.txt` and\n`GET /llms-full.txt` give a condensed and a long-form guide to the product.\n\nAri — Ariso's AI management system — exposes the product itself through a Model\nContext Protocol server at https://mcp.ari.ariso.ai/mcp (Streamable HTTP,\nOAuth 2.1 with PKCE). See https://ariso.ai/developers.\n\n## Versioning\n\nThe major version is in the URL path: every operation below lives under `/api/v1/`,\nand every response carries an `Ariso-Api-Version` header naming the version that\nserved it. Integrate against the versioned paths. The unversioned `/api/*` paths\nare aliases kept for the website's own forms and are not part of this contract.\n\nA breaking change — removing an endpoint or field, renaming one, tightening\nvalidation, or changing a response shape — ships as a new major version at a new\npath (`/api/v2/`) running alongside this one. Additive changes (new optional\nrequest fields, new response fields, new endpoints) ship in place without a\nversion bump, so clients must ignore fields they do not recognize.\n\n## Deprecation\n\nWhen a version or operation is retired, its responses carry a `Deprecation`\nheader (RFC 9745) giving the date the deprecation took effect and a `Sunset`\nheader (RFC 8594) giving the date it stops working, with at least six months\nbetween them. A `Link` header with `rel=\"deprecation\"` points at the notice.\nNothing is deprecated today.\n\n## Rate limits\n\nLimits are per client IP, in a fixed window, and differ per endpoint — see the\n`429` response of each operation. Every response carries `RateLimit-Limit`,\n`RateLimit-Remaining`, `RateLimit-Reset` (seconds until the window resets) and\n`RateLimit-Policy`, so a client can pace itself without being refused first. A\n`429` adds `Retry-After`.","contact":{"name":"Ariso","email":"hi@ariso.ai","url":"https://ariso.ai/contact"},"termsOfService":"https://ariso.ai/terms","license":{"name":"Proprietary","url":"https://ariso.ai/terms"}},"servers":[{"url":"https://ariso.ai","description":"Production"}],"externalDocs":{"description":"Ariso developer portal","url":"https://ariso.ai/developers"},"tags":[{"name":"Lead capture","description":"Contact, demo request, and program application forms."},{"name":"Content","description":"Blog engagement data and social image generation."},{"name":"Discovery","description":"Machine-readable descriptions of this site and its API."}],"paths":{"/api/v1/contact":{"post":{"operationId":"submitContactForm","tags":["Lead capture"],"summary":"Submit a contact or demo request","description":"Records an inbound enquiry — a general question, demo request, pricing question, partnership, or press enquiry — and creates the corresponding CRM record. Returns 400 when firstName or email is missing.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactRequest"},"examples":{"demo":{"summary":"Demo request","value":{"firstName":"Jordan","lastName":"Lee","email":"jordan@example.com","company":"Example Co","subject":"Product Demo","message":"We are 40 people and drowning in status meetings.","source":"Website"}}}}}},"responses":{"200":{"description":"The enquiry was recorded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadResult"}}}},"400":{"description":"The request body failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"The endpoint exists but does not accept this HTTP method.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded: this endpoint allows 5 requests per 600s per client IP. `Retry-After` gives the seconds to wait.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":0}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The policy in force, as `<limit>;w=<window-seconds>`.","schema":{"type":"string"},"example":"5;w=600"},"Ariso-Api-Version":{"description":"Major version of the API that served this response.","schema":{"type":"string"},"example":"1"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"The request could not be processed. Safe to retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/subscribe":{"post":{"operationId":"subscribeToNewsletter","tags":["Lead capture"],"summary":"Subscribe an email address to the newsletter","description":"Adds an email address to the Ariso newsletter. Returns 400 with code `invalid_request` when the address is missing or not a valid email.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeRequest"},"examples":{"basic":{"summary":"Subscribe from a blog post","value":{"email":"jordan@example.com","source":"Blog","page":"/blog"}}}}}},"responses":{"200":{"description":"The address was subscribed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadResult"}}}},"400":{"description":"The request body failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"The endpoint exists but does not accept this HTTP method.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded: this endpoint allows 10 requests per 600s per client IP. `Retry-After` gives the seconds to wait.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":0}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The policy in force, as `<limit>;w=<window-seconds>`.","schema":{"type":"string"},"example":"5;w=600"},"Ariso-Api-Version":{"description":"Major version of the API that served this response.","schema":{"type":"string"},"example":"1"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"The request could not be processed. Safe to retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/apply":{"post":{"operationId":"applyToProgram","tags":["Lead capture"],"summary":"Apply to an Ariso pricing program","description":"Submits an application to the Early Access program (one month free, then 50% off) or the Early-Stage Startup program (free for six months). Returns 400 when `program` is not one of the allowed values.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyRequest"},"examples":{"startup":{"summary":"Early-stage startup application","value":{"firstName":"Sam","lastName":"Rivera","email":"sam@startup.example","company":"Startup Example","program":"startup","source":"Pricing page"}}}}}},"responses":{"200":{"description":"The application was recorded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadResult"}}}},"400":{"description":"The request body failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"The endpoint exists but does not accept this HTTP method.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded: this endpoint allows 5 requests per 600s per client IP. `Retry-After` gives the seconds to wait.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":0}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The policy in force, as `<limit>;w=<window-seconds>`.","schema":{"type":"string"},"example":"5;w=600"},"Ariso-Api-Version":{"description":"Major version of the API that served this response.","schema":{"type":"string"},"example":"1"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"The request could not be processed. Safe to retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/share-count":{"get":{"operationId":"getBlogPostShareCounts","tags":["Content"],"summary":"Read share counts for a blog post","description":"Returns how many times a blog post has been shared, broken down by destination. Unknown post ids return zeroed counts rather than a 404.","parameters":[{"name":"postId","in":"query","required":true,"description":"Blog post slug, matching the final segment of its /blog/{postId} URL.","schema":{"type":"string","minLength":1},"example":"ai-as-an-operating-partner"}],"responses":{"200":{"description":"Current counts for the post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareCounts"}}}},"400":{"description":"The `postId` query parameter is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"The endpoint exists but does not accept this HTTP method.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded: this endpoint allows 120 requests per 600s per client IP. `Retry-After` gives the seconds to wait.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":0}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The policy in force, as `<limit>;w=<window-seconds>`.","schema":{"type":"string"},"example":"5;w=600"},"Ariso-Api-Version":{"description":"Major version of the API that served this response.","schema":{"type":"string"},"example":"1"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"incrementBlogPostShareCount","tags":["Content"],"summary":"Record a share of a blog post","description":"Increments the counter for one destination on one blog post and returns the updated tally.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareEvent"},"examples":{"linkedin":{"summary":"Shared to LinkedIn","value":{"postId":"ai-as-an-operating-partner","platform":"linkedin"}}}}}},"responses":{"200":{"description":"The updated counts for the post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareCounts"}}}},"400":{"description":"`postId` is missing or `platform` is not a known destination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded: this endpoint allows 120 requests per 600s per client IP. `Retry-After` gives the seconds to wait.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":0}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The policy in force, as `<limit>;w=<window-seconds>`.","schema":{"type":"string"},"example":"5;w=600"},"Ariso-Api-Version":{"description":"Major version of the API that served this response.","schema":{"type":"string"},"example":"1"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApiSpecification","tags":["Discovery"],"summary":"Fetch this OpenAPI document","description":"Returns this specification. Also served at /.well-known/openapi.json and /api/openapi.json, which are aliases of the same document.","responses":{"200":{"description":"The OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/mcp.json":{"get":{"operationId":"getMcpServerDescriptor","tags":["Discovery"],"summary":"Fetch the Ari MCP server descriptor","description":"Returns the Model Context Protocol server descriptor for Ari, in the MCP registry server.json format, naming the Streamable HTTP endpoint and how to authenticate against it. Also served at /.well-known/mcp.json.","responses":{"200":{"description":"An MCP registry server.json document.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/v1/og":{"get":{"operationId":"renderOpenGraphImage","tags":["Content"],"summary":"Render an Open Graph image","description":"Renders a 1200×630 PNG in the Ariso brand style. Used for social previews of pages that have no bespoke image. All parameters are optional and are truncated to the lengths given below.","parameters":[{"name":"title","in":"query","description":"Headline text. Truncated at 100 characters.","schema":{"type":"string","maxLength":100,"default":"Ariso"}},{"name":"description","in":"query","description":"Sub-headline text. Truncated at 200 characters.","schema":{"type":"string","maxLength":200}},{"name":"eyebrow","in":"query","description":"Small kicker above the headline. Truncated at 50 characters.","schema":{"type":"string","maxLength":50}},{"name":"accent","in":"query","description":"Accent color as a six-digit hex value. Invalid values fall back to #7B6FC0.","schema":{"type":"string","pattern":"^#?[0-9A-Fa-f]{6}$","default":"#7B6FC0"}},{"name":"variant","in":"query","description":"Layout variant.","schema":{"type":"string","enum":["default","home"],"default":"default"}}],"responses":{"200":{"description":"A PNG image, 1200×630.","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}}}}}},"components":{"schemas":{"Error":{"type":"object","description":"Every non-2xx response from this API uses this shape.","required":["error","code","hint","documentation"],"properties":{"error":{"type":"string","description":"Human-readable description of what went wrong."},"code":{"type":"string","description":"Stable machine-readable error code.","enum":["invalid_request","not_found","method_not_allowed","rate_limited","server_configuration_error","upstream_error","internal_error"]},"hint":{"type":"string","description":"What the caller should do to resolve the error."},"documentation":{"type":"string","format":"uri","description":"URL of this specification."},"fields":{"type":"array","items":{"type":"string"},"description":"Request fields that failed validation, when applicable."}}},"LeadResult":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean","const":true},"message":{"type":"string"}}},"ShareCounts":{"type":"object","description":"Share tally for one blog post, broken down by destination.","required":["postId","counts","total"],"properties":{"postId":{"type":"string","description":"Blog post slug, e.g. \"ai-as-an-operating-partner\"."},"counts":{"type":"object","required":["linkedin","x","facebook","message","copy"],"properties":{"linkedin":{"type":"integer","minimum":0},"x":{"type":"integer","minimum":0},"facebook":{"type":"integer","minimum":0},"message":{"type":"integer","minimum":0},"copy":{"type":"integer","minimum":0}}},"total":{"type":"integer","minimum":0,"description":"Sum of every platform count."}}},"ContactRequest":{"type":"object","required":["firstName","email","subject","message"],"properties":{"firstName":{"type":"string","minLength":1},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"company":{"type":"string"},"phone":{"type":"string"},"subject":{"type":"string","description":"What the enquiry is about; drives how the lead is routed.","enum":["General Inquiry","Product Demo","Pricing Question","Partnership Opportunity","Press & Media","Other"]},"message":{"type":"string"},"referral":{"type":"string","description":"How the sender heard about Ariso.","enum":["search","social","referral","blog","event","linkedin","producthunt","other"]},"source":{"type":"string","description":"Attribution label. Defaults to \"Website\"."},"submittedAt":{"type":"string","format":"date-time"}}},"SubscribeRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"source":{"type":"string","description":"Attribution label. Defaults to \"Website\"."},"page":{"type":"string","description":"Path the subscription came from, e.g. \"/blog\"."}}},"ApplyRequest":{"type":"object","required":["firstName","lastName","email","program"],"properties":{"firstName":{"type":"string","minLength":1},"lastName":{"type":"string","minLength":1},"email":{"type":"string","format":"email"},"company":{"type":"string"},"program":{"type":"string","enum":["early-access","startup"],"description":"`early-access` = one month free then 50% off; `startup` = free for six months."},"referral":{"type":"string"},"source":{"type":"string"},"submittedAt":{"type":"string","format":"date-time"}}},"ShareEvent":{"type":"object","required":["postId","platform"],"properties":{"postId":{"type":"string","minLength":1},"platform":{"type":"string","enum":["linkedin","x","facebook","message","copy"]}}}}}}