{"openapi":"3.1.0","info":{"title":"Lummo public API","version":"1.0.0","summary":"Public Lummo landing APIs: newsletter, Lummito chat, health, sandbox, and self-serve keys.","description":"Machine-readable description of public endpoints on lummo.ar.\nThe authenticated construction ERP at app.lummo.ar is out of scope.\n\n## Versioning\nCurrent stable version is **v1**, exposed under `/api/v1/*`.\nLegacy aliases `/api/newsletter` and `/api/lummito/chat` remain supported and map to the same handlers.\nBreaking changes ship under a new path prefix (`/api/v2/…`) or a documented `Lummo-API-Version` request header.\n\n## Deprecation\nDeprecated operations are marked with OpenAPI `deprecated: true` and return\n`Deprecation: true` plus `Sunset: <HTTP-date>` response headers at least 90 days before removal.\nAgents should migrate to the replacement path listed in the operation description.\n\nHuman docs: https://lummo.ar/developers. Contact: contacto@lummo.ar.","contact":{"name":"Lummo","email":"contacto@lummo.ar","url":"https://lummo.ar"},"license":{"name":"Proprietary","url":"https://lummo.ar/terminos-y-condiciones"}},"servers":[{"url":"https://lummo.ar","description":"Production landing (canonical)"}],"tags":[{"name":"v1","description":"Stable URL-path versioned public API (/api/v1)"},{"name":"newsletter","description":"Product newsletter subscription"},{"name":"lummito","description":"Landing-site Lummito assistant (quota limited)"},{"name":"onboarding","description":"Self-serve keys, health, and sandbox for agents"},{"name":"discovery","description":"Agent discovery documents"}],"paths":{"/api/v1/health":{"get":{"operationId":"getApiV1Health","tags":["v1","onboarding"],"summary":"Lummo public API health (zero-auth)","description":"Unauthenticated readiness probe. Always returns IETF RateLimit headers so agents can observe throttling conventions without credentials.","responses":{"200":{"description":"Service healthy","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/v1/keys":{"post":{"operationId":"createPublicApiKey","tags":["v1","onboarding"],"summary":"Self-serve free-tier Lummo API key","description":"Issues a free-tier public API key without a sales form. Landing APIs remain zero-auth; the key optionally stabilizes rate-limit identity. ERP tenant credentials stay on app.lummo.ar.","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}}},"responses":{"201":{"description":"Key issued","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"400":{"description":"Invalid request — RFC 9457 problem+json","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Unknown API path — RFC 9457 problem+json (never HTML)","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"Retry-After":{"description":"Seconds to wait before retrying","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}}},"get":{"operationId":"describePublicApiKeys","tags":["v1","onboarding"],"summary":"Describe self-serve key issuance","description":"Returns how to mint a free Lummo public API key via POST /api/v1/keys.","responses":{"200":{"description":"Issuance instructions","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysDescribeResponse"}}}}}}},"/api/v1/sandbox/echo":{"post":{"operationId":"sandboxEcho","tags":["v1","onboarding"],"summary":"Sandbox echo (zero-auth dry-run)","description":"Sandbox environment for agents: echoes a message without mutating obra data. No API key required.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEchoRequest"}}}},"responses":{"200":{"description":"Echo accepted","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEchoResponse"}}}},"400":{"description":"Invalid request — RFC 9457 problem+json","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Unknown API path — RFC 9457 problem+json (never HTML)","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"Retry-After":{"description":"Seconds to wait before retrying","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}}},"get":{"operationId":"sandboxEchoInfo","tags":["v1","onboarding"],"summary":"Sandbox echo usage","description":"Returns sandbox usage instructions for POST /api/v1/sandbox/echo.","responses":{"200":{"description":"Usage info","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEchoInfoResponse"}}}}}}},"/api/v1/newsletter":{"post":{"operationId":"subscribeNewsletterV1","tags":["v1","newsletter"],"summary":"Subscribe an email to the Lummo newsletter (v1)","description":"Creates or updates a newsletter contact. No API key required. Rate limited per IP+email. Errors use application/problem+json. Preferred over the legacy /api/newsletter alias.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsletterSubscribeRequest"},"examples":{"default":{"value":{"email":"obra@constructora.example"}}}}}},"responses":{"200":{"description":"Subscription accepted","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsletterSubscribeResponse"}}}},"400":{"description":"Invalid request — RFC 9457 problem+json","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Unknown API path — RFC 9457 problem+json (never HTML)","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"Retry-After":{"description":"Seconds to wait before retrying","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"503":{"description":"Newsletter provider unavailable","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}}}},"/api/v1/lummito/chat":{"post":{"operationId":"lummitoLandingChatV1","tags":["v1","lummito"],"summary":"Send a message to the landing Lummito assistant (v1)","description":"Quota-limited chat for the marketing site. Uses an HTTP-only cookie quota. Not a substitute for in-app Lummito on app.lummo.ar. Preferred versioned path.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LummitoChatRequest"}}}},"responses":{"200":{"description":"Assistant reply","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LummitoChatResponse"}}}},"400":{"description":"Invalid request — RFC 9457 problem+json","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Unknown API path — RFC 9457 problem+json (never HTML)","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"Retry-After":{"description":"Seconds to wait before retrying","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"503":{"description":"Upstream model unavailable","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}}},"get":{"operationId":"lummitoLandingQuotaV1","tags":["v1","lummito"],"summary":"Read remaining Lummito landing quota (v1)","description":"Returns the remaining free Lummito landing messages for this client cookie. Includes RateLimit headers mirroring the quota window.","responses":{"200":{"description":"Current quota","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LummitoQuotaResponse"}}}}}}},"/api/newsletter":{"post":{"operationId":"subscribeNewsletter","tags":["newsletter"],"summary":"Subscribe an email to the Lummo newsletter (legacy alias)","description":"Legacy alias of POST /api/v1/newsletter. Prefer the versioned path. Creates or updates a newsletter contact. No API key required. Rate limited per IP+email. Errors use application/problem+json.","deprecated":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsletterSubscribeRequest"},"examples":{"default":{"value":{"email":"obra@constructora.example"}}}}}},"responses":{"200":{"description":"Subscription accepted","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsletterSubscribeResponse"}}}},"400":{"description":"Invalid request — RFC 9457 problem+json","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Unknown API path — RFC 9457 problem+json (never HTML)","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"Retry-After":{"description":"Seconds to wait before retrying","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"503":{"description":"Newsletter provider unavailable","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}}}},"/api/lummito/chat":{"post":{"operationId":"lummitoLandingChat","tags":["lummito"],"summary":"Send a message to the landing Lummito assistant (legacy alias)","description":"Legacy alias of POST /api/v1/lummito/chat. Prefer the versioned path. Quota-limited chat for the marketing site. Uses an HTTP-only cookie quota.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LummitoChatRequest"}}}},"responses":{"200":{"description":"Assistant reply","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LummitoChatResponse"}}}},"400":{"description":"Invalid request — RFC 9457 problem+json","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Unknown API path — RFC 9457 problem+json (never HTML)","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"Retry-After":{"description":"Seconds to wait before retrying","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"503":{"description":"Upstream model unavailable","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}}},"get":{"operationId":"lummitoLandingQuota","tags":["lummito"],"summary":"Read remaining Lummito landing quota (legacy alias)","description":"Legacy alias of GET /api/v1/lummito/chat. Returns remaining free Lummito landing messages and RateLimit headers.","responses":{"200":{"description":"Current quota","headers":{"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"RateLimit":{"$ref":"#/components/headers/RateLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LummitoQuotaResponse"}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApiJson","tags":["discovery"],"summary":"OpenAPI 3.1 document (JSON)","description":"Returns this OpenAPI 3.1 document describing Lummo public landing APIs, versioning, and deprecation policy.","responses":{"200":{"description":"OpenAPI document","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/api/openapi.yaml":{"get":{"operationId":"getOpenApiYaml","tags":["discovery"],"summary":"OpenAPI 3.1 document (YAML)","description":"Same OpenAPI 3.1 document as /openapi.json, serialized as YAML for agents that prefer text specs.","responses":{"200":{"description":"OpenAPI document as YAML","content":{"application/yaml":{"schema":{"type":"string"}}}}}}},"/llms.txt":{"get":{"operationId":"getLlmsTxt","tags":["discovery"],"summary":"Agent site index (llms.txt)","description":"Plain-text index of Lummo product pages and developer resources for LLM agents.","responses":{"200":{"description":"Plain-text agent index","content":{"text/plain":{"schema":{"type":"string"}}}}}}}},"components":{"headers":{"RateLimitLimit":{"description":"Request quota ceiling for the current window","schema":{"type":"integer"}},"RateLimitRemaining":{"description":"Remaining requests in the current window","schema":{"type":"integer"}},"RateLimitReset":{"description":"Seconds until the quota window resets","schema":{"type":"integer"}},"RateLimit":{"description":"IETF RateLimit structured field","schema":{"type":"string"}}},"schemas":{"HealthResponse":{"type":"object","required":["ok","service","version"],"properties":{"ok":{"type":"boolean"},"service":{"type":"string"},"version":{"type":"string","enum":["v1"]},"documentation":{"type":"string","format":"uri"},"openapi":{"type":"string","format":"uri"}},"additionalProperties":false},"CreateKeyRequest":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":64,"description":"Optional agent/integration label"}},"additionalProperties":false},"CreateKeyResponse":{"type":"object","required":["api_key","tier","expires_at"],"properties":{"api_key":{"type":"string"},"tier":{"type":"string","enum":["free"]},"label":{"type":"string"},"rate_limit":{"type":"object","properties":{"limit":{"type":"integer"},"window_seconds":{"type":"integer"}}},"expires_at":{"type":"string","format":"date-time"},"documentation":{"type":"string","format":"uri"},"note":{"type":"string"}}},"KeysDescribeResponse":{"type":"object","required":["endpoint","tier","authentication"],"properties":{"endpoint":{"type":"string"},"tier":{"type":"string"},"authentication":{"type":"string"},"body":{"type":"object","additionalProperties":true},"documentation":{"type":"string","format":"uri"}}},"SandboxEchoRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string","minLength":1,"maxLength":2000},"echo_headers":{"type":"boolean"}},"additionalProperties":false},"SandboxEchoResponse":{"type":"object","required":["ok","sandbox","version","echo","received_at"],"properties":{"ok":{"type":"boolean"},"sandbox":{"type":"boolean"},"version":{"type":"string","enum":["v1"]},"echo":{"type":"string"},"received_at":{"type":"string","format":"date-time"},"request_accept":{"type":"string"},"request_user_agent":{"type":"string"}}},"SandboxEchoInfoResponse":{"type":"object","required":["ok","sandbox","version","usage"],"properties":{"ok":{"type":"boolean"},"sandbox":{"type":"boolean"},"version":{"type":"string"},"usage":{"type":"string"}}},"NewsletterSubscribeRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","maxLength":254,"description":"Subscriber email (stored lowercased)"}},"additionalProperties":false},"NewsletterSubscribeResponse":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"},"mode":{"type":"string","enum":["contact","notify"]},"alreadyExists":{"type":"boolean"}}},"LummitoChatRequest":{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","minItems":1,"maxItems":12,"items":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string","minLength":1,"maxLength":2000}}}},"clientUsed":{"type":"number","description":"Optional client-side quota echo"}}},"LummitoChatResponse":{"type":"object","required":["message","used","max","remaining"],"properties":{"message":{"type":"string","description":"Assistant reply text"},"used":{"type":"integer"},"max":{"type":"integer"},"remaining":{"type":"integer"},"reply":{"type":"string","description":"Deprecated alias — prefer message"},"quota":{"type":"object","properties":{"used":{"type":"integer"},"max":{"type":"integer"},"remaining":{"type":"integer"}}}}},"LummitoQuotaResponse":{"type":"object","required":["used","max","remaining"],"properties":{"used":{"type":"integer"},"max":{"type":"integer"},"remaining":{"type":"integer"}}},"ProblemDetails":{"type":"object","required":["type","title","status","detail","code"],"properties":{"type":{"type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"code":{"type":"string"},"resolution":{"type":"string"},"instance":{"type":"string"}}}}}}