{"openapi":"3.1.0","info":{"title":"CAPM public API","summary":"Public directory, news, contact, and newsletter endpoints for CAPM.","description":"Read-only local business directory and official news for CAPM, plus contact and newsletter forms. No authentication is required. Admin, billing, interviews, and document downloads are private and are not part of this spec.","version":"1.0.0","contact":{"name":"CAPM","email":"contact@capm35.fr","url":"https://capm35.fr"},"license":{"name":"Use restricted to public CAPM data","url":"https://capm35.fr/politique-confidentialite/"}},"servers":[{"url":"https://api.capm35.fr","description":"Production public API"}],"tags":[{"name":"meta","description":"Service health and discovery."},{"name":"directory","description":"Public member directory for the Pays Martignolais."},{"name":"news","description":"Published CAPM articles and events."},{"name":"contact","description":"Public contact form."},{"name":"newsletter","description":"Public newsletter subscription."}],"paths":{"/health":{"get":{"operationId":"getHealth","tags":["meta"],"summary":"API health check","description":"Return a simple OK payload so agents can confirm api.capm35.fr is reachable.","responses":{"200":{"description":"The API process is up.","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","example":"ok"}}}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApiSpec","tags":["meta"],"summary":"OpenAPI document","description":"Return this OpenAPI 3.1 document for function calling and API discovery.","responses":{"200":{"description":"OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/api/public/directory":{"get":{"operationId":"getDirectory","tags":["directory"],"summary":"Full public directory","description":"Return every directory-visible CAPM member plus the sector catalog. Prefer this when an agent needs the complete local business list in one call.","responses":{"200":{"description":"Sectors and directory companies.","content":{"application/json":{"schema":{"type":"object","required":["sectors","companies"],"properties":{"sectors":{"type":"array","items":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"]},"color":{"type":["string","null"]},"searchKeywords":{"type":["string","null"]},"order":{"type":"integer"}}}},"companies":{"type":"array","items":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"tags":{"type":["string","null"]},"sectorId":{"type":["string","null"]},"showInDirectory":{"type":"boolean"},"address":{"type":["object","null"],"properties":{"street":{"type":"string"},"city":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"},"hideFullAddress":{"type":"boolean"}}},"sector":{"oneOf":[{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"]},"color":{"type":["string","null"]},"searchKeywords":{"type":["string","null"]},"order":{"type":"integer"}}},{"type":"null"}]},"phones":{"type":"array","items":{"type":"object","properties":{"phone":{"type":"string"},"label":{"type":["string","null"]}}}},"emails":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"label":{"type":["string","null"]}}}},"links":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"label":{"type":["string","null"]}}}}}}}}}}}}}}},"/api/public/companies":{"get":{"operationId":"listCompanies","tags":["directory"],"summary":"List directory companies","description":"List CAPM members currently shown in the public directory. Use sectorId to filter one activity sector.","parameters":[{"name":"sectorId","in":"query","required":false,"description":"Optional sector id from listSectors or getDirectory.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Maximum number of companies to return. Default 100, maximum 200.","schema":{"type":"integer","minimum":1,"maximum":200}},{"name":"offset","in":"query","required":false,"description":"Number of companies to skip for pagination.","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Directory companies.","content":{"application/json":{"schema":{"type":"object","required":["companies"],"properties":{"companies":{"type":"array","items":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"tags":{"type":["string","null"]},"sectorId":{"type":["string","null"]},"showInDirectory":{"type":"boolean"},"address":{"type":["object","null"],"properties":{"street":{"type":"string"},"city":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"},"hideFullAddress":{"type":"boolean"}}},"sector":{"oneOf":[{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"]},"color":{"type":["string","null"]},"searchKeywords":{"type":["string","null"]},"order":{"type":"integer"}}},{"type":"null"}]},"phones":{"type":"array","items":{"type":"object","properties":{"phone":{"type":"string"},"label":{"type":["string","null"]}}}},"emails":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"label":{"type":["string","null"]}}}},"links":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"label":{"type":["string","null"]}}}}}}}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","message","hint"],"properties":{"error":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"hint":{"type":"string","description":"Where to look next or how to fix the request."}}}}}}}}},"/api/public/companies/{slug}":{"get":{"operationId":"getCompanyBySlug","tags":["directory"],"summary":"Get one company","description":"Return one public company by its URL slug, including contact details when published.","parameters":[{"name":"slug","in":"path","required":true,"description":"Company slug from the directory, for example boulangerie-martin.","schema":{"type":"string","minLength":1,"maxLength":255}}],"responses":{"200":{"description":"Company found.","content":{"application/json":{"schema":{"type":"object","required":["company"],"properties":{"company":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"tags":{"type":["string","null"]},"sectorId":{"type":["string","null"]},"showInDirectory":{"type":"boolean"},"address":{"type":["object","null"],"properties":{"street":{"type":"string"},"city":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"},"hideFullAddress":{"type":"boolean"}}},"sector":{"oneOf":[{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"]},"color":{"type":["string","null"]},"searchKeywords":{"type":["string","null"]},"order":{"type":"integer"}}},{"type":"null"}]},"phones":{"type":"array","items":{"type":"object","properties":{"phone":{"type":"string"},"label":{"type":["string","null"]}}}},"emails":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"label":{"type":["string","null"]}}}},"links":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"label":{"type":["string","null"]}}}}}}}}}}},"404":{"description":"No public company uses this slug.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","message","hint"],"properties":{"error":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"hint":{"type":"string","description":"Where to look next or how to fix the request."}}}}}}}}},"/api/public/sectors":{"get":{"operationId":"listSectors","tags":["directory"],"summary":"List activity sectors","description":"Return the public sector catalog used to group directory companies.","responses":{"200":{"description":"Sectors ordered for display.","content":{"application/json":{"schema":{"type":"object","required":["sectors"],"properties":{"sectors":{"type":"array","items":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"icon":{"type":["string","null"]},"color":{"type":["string","null"]},"searchKeywords":{"type":["string","null"]},"order":{"type":"integer"}}}}}}}}}}}},"/api/public/posts":{"get":{"operationId":"listPosts","tags":["news"],"summary":"List published articles","description":"Return official published CAPM news and event articles, newest first.","parameters":[{"name":"limit","in":"query","required":false,"description":"Maximum number of articles to return. Default 20, maximum 100.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"description":"Number of articles to skip for pagination.","schema":{"type":"integer","minimum":0}},{"name":"categoryId","in":"query","required":false,"description":"Optional category id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Published articles.","content":{"application/json":{"schema":{"type":"object","required":["posts"],"properties":{"posts":{"type":"array","items":{"type":"object","required":["id","title","slug","status"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"status":{"type":"string","enum":["draft","published"]},"publishedAt":{"type":["string","null"]},"metaTitle":{"type":["string","null"]},"metaDescription":{"type":["string","null"]}}}}}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","message","hint"],"properties":{"error":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"hint":{"type":"string","description":"Where to look next or how to fix the request."}}}}}}}}},"/api/public/posts/{slug}":{"get":{"operationId":"getPostBySlug","tags":["news"],"summary":"Get one article","description":"Return one published CAPM article by slug, including body content.","parameters":[{"name":"slug","in":"path","required":true,"description":"Article slug from listPosts.","schema":{"type":"string","minLength":1,"maxLength":255}}],"responses":{"200":{"description":"Article found.","content":{"application/json":{"schema":{"type":"object","required":["post"],"properties":{"post":{"type":"object","required":["id","title","slug","status"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"status":{"type":"string","enum":["draft","published"]},"publishedAt":{"type":["string","null"]},"metaTitle":{"type":["string","null"]},"metaDescription":{"type":["string","null"]}}}}}}}},"404":{"description":"No published article uses this slug.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","message","hint"],"properties":{"error":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"hint":{"type":"string","description":"Where to look next or how to fix the request."}}}}}}}}},"/api/public/contact":{"post":{"operationId":"submitContact","tags":["contact"],"summary":"Send a contact message","description":"Submit a public contact request to CAPM. Use this for membership, partnership, event, or general questions. Do not send secrets.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["name","email","subject","message"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string","format":"email","maxLength":255},"subject":{"type":"string","enum":["adhesion","information","partenariat","suggestion","balade","autre"],"description":"Contact motive. Use adhesion for membership requests."},"message":{"type":"string","minLength":1,"maxLength":5000}}}}}},"responses":{"200":{"description":"Message accepted.","content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}}}}},"400":{"description":"Invalid payload.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","message","hint"],"properties":{"error":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"hint":{"type":"string","description":"Where to look next or how to fix the request."}}}}}}}}},"/api/public/newsletter/subscribe":{"post":{"operationId":"subscribeNewsletter","tags":["newsletter"],"summary":"Subscribe to the newsletter","description":"Subscribe an email to the CAPM newsletter. consentAccepted must be true and consentVersion must match the current public notice version.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["email","consentAccepted","consentVersion"],"properties":{"email":{"type":"string","format":"email","maxLength":255},"source":{"type":"string","enum":["homepage","footer","admin","article","contact","other"]},"consentAccepted":{"type":"boolean","enum":[true]},"consentVersion":{"type":"string","description":"Must equal 2026-08-05."}}}}}},"responses":{"200":{"description":"Subscription recorded or already active.","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["subscribed","already_subscribed","resubscribed"]}}}}}},"400":{"description":"Invalid payload or missing consent.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["error","message","hint"],"properties":{"error":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"hint":{"type":"string","description":"Where to look next or how to fix the request."}}}}}}}}}},"components":{"schemas":{"ApiError":{"type":"object","additionalProperties":false,"required":["error","message","hint"],"properties":{"error":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"hint":{"type":"string","description":"Where to look next or how to fix the request."}}}}}}