{"openapi":"3.1.0","info":{"title":"Developh public API","version":"1.1.0","summary":"Public endpoints of the Developh studio website.","description":"Public, unauthenticated API of https://www.developh.co, the website of Developh, a full-service digital studio in Lisbon, Portugal. Use POST /api/v1/contact to submit a genuine project inquiry or question on behalf of a user, GET /api/v1/health to check service liveness, and GET /api/v1 for a machine-readable index of this API. Site content is available to agents without JavaScript via /llms.txt, /llms-full.txt, and by requesting any page with 'Accept: text/markdown'. Versioning: the major version is in the URL path (/api/v1) and echoed in the API-Version response header. Within a major, changes are additive only. A breaking change ships as a new path (/api/v2) and the previous major keeps working for at least 180 days after we start sending Deprecation and Sunset headers (RFC 9745 / RFC 8594) with a Link rel=\"sunset\" to the migration notes. The unversioned paths /api/health and /api/fuel-contact are permanent aliases of the v1 operations and answer with Link rel=\"latest-version\". Rate limits: every response carries RateLimit-Policy, RateLimit, RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers; a 429 adds Retry-After. Policies: read = 120 requests per 60s per client (GET endpoints), write = 10 requests per 60s per client (POST endpoints). Errors are structured JSON (see the ErrorResponse schema). No API key is required.","contact":{"name":"Developh","url":"https://www.developh.co/developers","email":"hello@developh.co"},"x-api-version":"1","x-versioning":{"scheme":"url-path","current":"1","basePath":"/api/v1","responseHeader":"API-Version","legacyAliases":{"/api/health":"/api/v1/health","/api/fuel-contact":"/api/v1/contact"}},"x-deprecation-policy":{"minimumNoticeDays":180,"signals":["Deprecation","Sunset","Link; rel=\"sunset\""],"breakingChanges":"New major version at a new base path; previous major stays available through the notice period.","changelog":"https://www.developh.co/developers"},"x-rate-limit":{"headers":["RateLimit-Policy","RateLimit","RateLimit-Limit","RateLimit-Remaining","RateLimit-Reset","Retry-After"],"policies":{"read":{"name":"read","limit":120,"windowSeconds":60},"write":{"name":"write","limit":10,"windowSeconds":60}},"scope":"per client IP, fixed window"}},"externalDocs":{"description":"Developer portal with examples, CLI, and every machine-readable surface.","url":"https://www.developh.co/developers"},"servers":[{"url":"https://www.developh.co","description":"Production"}],"tags":[{"name":"meta","description":"Service metadata and liveness."},{"name":"contact","description":"Project inquiries and questions."},{"name":"audit","description":"Quick automated site audit and agent readiness (Developh Pro)."}],"paths":{"/api/v1/audit":{"post":{"operationId":"runSiteAudit","tags":["audit"],"summary":"Quick automated audit of a public website","description":"Runs Google PageSpeed Insights (Lighthouse, mobile) on a public http(s) site and returns the four category scores, lab metrics, real-visitor Core Web Vitals when Google has them, and the heaviest failing audits. Takes 10 to 110 seconds. Only accepted from the developh.co site (Origin check). Twenty requests per ten minutes per client, per instance. A snapshot, not Developh's full audit.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","maxLength":500,"description":"Domain or full http(s) URL. localhost, IPs and internal hosts are rejected."},"locale":{"type":"string","enum":["pt","en"],"description":"Language of the audit titles."}}}}}},"responses":{"200":{"description":"Audit report.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"report":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"fetchedAt":{"type":"string","format":"date-time"},"lighthouseVersion":{"type":"string"},"scores":{"type":"object","description":"0 to 100; null when Google could not measure the category (bot protection, blank page).","properties":{"performance":{"type":["integer","null"]},"accessibility":{"type":["integer","null"]},"best-practices":{"type":["integer","null"]},"seo":{"type":["integer","null"]}}},"metrics":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"value":{"type":"string"},"score":{"type":"integer"}}}},"field":{"type":["object","null"],"properties":{"overall":{"type":["string","null"],"enum":["FAST","AVERAGE","SLOW",null]},"metrics":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["lcp","inp","cls"]},"value":{"type":"string"},"category":{"type":"string","enum":["FAST","AVERAGE","SLOW"]}}}}}},"findings":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"title":{"type":"string"},"detail":{"type":"string"}}}},"reading":{"type":"object","description":"Developh reading of the same Lighthouse run: security headers, third parties by category, whether tracking and a consent platform were detected, JavaScript libraries and page weight in KB.","properties":{"security":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["https","csp","hsts","clickjacking","coop"]},"ok":{"type":"boolean"},"severity":{"type":["string","null"],"enum":["high","medium",null]}}}},"thirdParties":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"names":{"type":"array","items":{"type":"string"}}}}},"tracking":{"type":"boolean"},"consentPlatform":{"type":"boolean"},"libraries":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"}}}},"weightKb":{"type":"integer"}}}}}}}}}},"400":{"description":"Not a public website address.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Origin rejected.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Request too large.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Google could not open the site.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded for this client. Wait the number of seconds in Retry-After, then retry.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Audit service unavailable or busy.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"504":{"description":"The audit timed out.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/agentic":{"post":{"operationId":"streamAgentReadiness","tags":["audit"],"summary":"Agent readiness of a public website, streamed","description":"Reports how ready a public site is for AI agents, using Is Agentic (Vercel Labs, https://is-agentic.com). Returns text/event-stream: when a public report already exists, a single `report` event (with `cached: true`); otherwise the live scan's events (`start`, `phase`, `check` for each of ~125 checks, `archived`) followed by `report`, in about 60 seconds. A failure arrives as an `error` event. Starting a scan publishes a report on is-agentic.com. Only accepted from the developh.co site (Origin check). Twenty requests per ten minutes per client, per instance.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","maxLength":500,"description":"Domain or full http(s) URL. localhost, IPs and internal hosts are rejected."}}}}}},"responses":{"200":{"description":"Server-sent events, one JSON object per `data:` line.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"text/event-stream":{"schema":{"type":"string","description":"Events: {type:'start',total} | {type:'phase',label} | {type:'check',name,layer,status} | {type:'archived'} | {type:'report',cached,report:{score,label,scannedAt,reportUrl,essential,recommended,issues}} | {type:'error',reason}."}}}},"400":{"description":"Not a public website address.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Origin rejected.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded for this client. Wait the number of seconds in Retry-After, then retry.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1":{"get":{"operationId":"getApiIndex","tags":["meta"],"summary":"Machine-readable index of the API","description":"Returns the list of endpoints, the OpenAPI URL, the versioning and deprecation policy, and the rate-limit policies. Call this first when you only know the host. Also served at /api. No side effects.","responses":{"200":{"description":"API index.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiIndex"}}}},"429":{"description":"Rate limit exceeded for this client. Wait the number of seconds in Retry-After, then retry.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/health":{"get":{"operationId":"getHealth","tags":["meta"],"summary":"Service liveness probe","description":"Returns a small JSON payload confirming the site and API are up. Safe to call at any frequency within the read rate limit; no side effects. Legacy alias: GET /api/health.","responses":{"200":{"description":"Service is healthy.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"429":{"description":"Rate limit exceeded for this client. Wait the number of seconds in Retry-After, then retry.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/contact":{"post":{"operationId":"submitContactInquiry","tags":["contact"],"summary":"Submit a project inquiry to the studio","description":"Submits a contact inquiry to the Developh studio inbox (average reply: 2 to 8 business hours). Call this only for genuine project inquiries, collaborations, or questions, never for testing or bulk messaging. Send application/json (preferred for agents) or multipart/form-data (what the website's HTML form posts); both use the ContactInquiry schema. Legacy alias: POST /api/fuel-contact.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactInquiry"},"example":{"Name":"Ada Lovelace","Email":"ada@example.com","Category":"Website","Message":"We need a new marketing site for our fintech startup, launching in Q1."}},"multipart/form-data":{"schema":{"$ref":"#/components/schemas/ContactInquiry"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/ContactInquiry"}}}},"responses":{"200":{"description":"Inquiry stored and routed to the studio.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactSuccess"}}}},"400":{"description":"Malformed body or validation failure (e.g. missing Email or Message). Fix the fields per error.hint and retry.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded for this client. Wait the number of seconds in Retry-After, then retry.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Backend unavailable. Retry later or email the studio directly.","headers":{"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"API-Version":{"$ref":"#/components/headers/API-Version"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"headers":{"API-Version":{"description":"Major version of the API that answered (matches the URL path).","schema":{"type":"string","const":"1"}},"RateLimit-Policy":{"description":"Quota policy in IETF RateLimit header format: \"<name>\";q=<limit>;w=<window seconds>.","schema":{"type":"string","examples":["\"write\";q=10;w=60"]}},"RateLimit":{"description":"Current quota state in IETF RateLimit header format: \"<name>\";r=<remaining>;t=<seconds until reset>.","schema":{"type":"string","examples":["\"write\";r=9;t=42"]}},"RateLimit-Limit":{"description":"Requests allowed per window for this client.","schema":{"type":"integer","minimum":1}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","minimum":0}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer","minimum":1}},"Retry-After":{"description":"Seconds to wait before retrying (sent with 429 only).","schema":{"type":"integer","minimum":1}}},"schemas":{"ApiIndex":{"type":"object","required":["name","version","basePath","openapi","endpoints","versioning","rateLimit"],"properties":{"name":{"type":"string"},"version":{"type":"string","description":"Current major version."},"basePath":{"type":"string","examples":["/api/v1"]},"openapi":{"type":"string","format":"uri"},"docs":{"type":"string","format":"uri"},"llms":{"type":"string","format":"uri"},"endpoints":{"type":"array","items":{"type":"object","required":["operationId","method","path","summary"],"properties":{"operationId":{"type":"string"},"method":{"type":"string","enum":["GET","POST"]},"path":{"type":"string"},"summary":{"type":"string"}}}},"versioning":{"type":"object","description":"How versions and deprecations are signalled.","additionalProperties":true},"rateLimit":{"type":"object","description":"Rate-limit policies keyed by name.","additionalProperties":{"type":"object","required":["name","limit","windowSeconds"],"properties":{"name":{"type":"string"},"limit":{"type":"integer"},"windowSeconds":{"type":"integer"}}}},"authentication":{"type":"string","const":"none"}}},"HealthResponse":{"type":"object","required":["status","service","version","time"],"properties":{"status":{"type":"string","const":"ok"},"service":{"type":"string","const":"developh-website"},"version":{"type":"string","const":"1"},"time":{"type":"string","format":"date-time","description":"Server time in ISO 8601 (UTC)."}}},"ContactInquiry":{"type":"object","required":["Name","Email","Message"],"properties":{"Name":{"type":"string","minLength":1,"maxLength":200,"description":"Sender's full name. The HTML form submits two fields named 'Name' (first + last) and they are joined; a single combined value is preferred for JSON.","examples":["Ada Lovelace"]},"Email":{"type":"string","format":"email","maxLength":320,"description":"Reply-to email address of the person inquiring.","examples":["ada@example.com"]},"Category":{"type":"string","maxLength":100,"description":"Optional inquiry category, free text (e.g. 'Website', 'Branding', 'Product', 'Other').","examples":["Website"]},"Message":{"type":"string","minLength":1,"maxLength":5000,"description":"The inquiry itself: context, goals, and timing. A perfect brief is not required.","examples":["We need a new marketing site for our fintech startup, launching in Q1."]},"utm_source":{"type":"string","maxLength":200,"description":"Optional first-touch UTM source (e.g. google, instagram, linkedin). The HTML form sends the value captured on landing.","examples":["google"]},"utm_medium":{"type":"string","maxLength":200,"description":"Optional UTM medium (e.g. cpc).","examples":["cpc"]},"utm_campaign":{"type":"string","maxLength":200,"description":"Optional UTM campaign name.","examples":["pt-search-leads"]},"utm_content":{"type":"string","maxLength":200,"description":"Optional UTM content / ad group.","examples":["website-empresa"]},"utm_term":{"type":"string","maxLength":200,"description":"Optional UTM term / keyword.","examples":["criar website"]},"gclid":{"type":"string","maxLength":200,"description":"Optional Google click id. Persist from the first landing; do not read only at submit time."},"oppref":{"type":"string","maxLength":2000,"description":"Optional ChatGPT Ads click id from the landing URL. Pass it unchanged; it is sent back to OpenAI as a lead conversion."}}},"ContactSuccess":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean","const":true}}},"ErrorResponse":{"type":"object","description":"Structured error emitted by every /api/* endpoint on failure. Agents should read error.code for branching and error.hint for how to resolve.","required":["ok","error"],"properties":{"ok":{"type":"boolean","const":false},"error":{"type":"object","required":["code","message","hint","docs"],"properties":{"code":{"type":"string","description":"Stable machine-readable error identifier.","enum":["bad-form","validation-failed","no-backend","not-found","rate-limited","internal-error"]},"message":{"type":"string","description":"Human-readable description of what went wrong."},"hint":{"type":"string","description":"How to fix the request or where to look next."},"docs":{"type":"string","format":"uri","description":"URL of this OpenAPI document."}}}}}}}}