{"openapi":"3.0.3","info":{"title":"Community Swap V1","version":"1.0.0","description":"One network, geographic namespaces. Anonymous browsing and verified interaction. JSON clients send Origin on all writes. Cookie sessions last 90 days. Never expose contact addresses or exact pickup coordinates in public responses. HTML form clients may POST to status/location routes and use _method=PATCH for edits; form success/errors redirect with HTTP 303. Unsupported V1 features remain disabled."},"servers":[{"url":"/api/v1"}],"paths":{"/health":{"get":{"summary":"Application and database health","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"version":{"type":"string"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/openapi.json":{"get":{"summary":"This OpenAPI document","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/communities":{"get":{"summary":"List geographic namespaces and database feature flags","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Community"}}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/listings":{"get":{"summary":"Anonymous nearest-first inventory; overlapping communities share listings","parameters":[{"name":"community","in":"query","schema":{"type":"string","default":"esterones"}},{"name":"lat","in":"query","schema":{"type":"number","minimum":-85,"maximum":85},"description":"Supply both coordinates, or omit both."},{"name":"lng","in":"query","schema":{"type":"number","minimum":-180,"maximum":180},"description":"Supply both coordinates, or omit both."},{"name":"radius","in":"query","schema":{"type":"number","minimum":1,"maximum":100,"description":"Kilometers; defaults to community radius."}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"language","in":"query","schema":{"type":"string","enum":["en","es"],"default":"es"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Listing"}},"next_cursor":{"type":"string","nullable":true}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Post a free item at the saved location; expires in exactly seven days","security":[{"sessionCookie":[]}],"parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingInput"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"moderation_status":{"type":"string","enum":["approved","review"]},"translation_status":{"type":"string","enum":["pending"]}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/listings/{id}":{"get":{"summary":"Get a visible listing without identity or exact coordinates","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},{"name":"language","in":"query","schema":{"type":"string","enum":["en","es"],"default":"es"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Listing"}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Owner edits description; expiration stays unchanged; translation regenerated","security":[{"sessionCookie":[]}],"parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListingInput"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"boolean"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Owner marks item gone; irreversible through API","security":[{"sessionCookie":[]}],"parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/listings/{id}/status":{"patch":{"summary":"Owner changes state: available ↔ reserved → gone","security":[{"sessionCookie":[]}],"parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["available","reserved","gone"]}},"required":["status"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"boolean"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/listings/{id}/contact":{"post":{"summary":"Verified, rate-limited contact handoff; demo returns no external URL","security":[{"sessionCookie":[]}],"parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/listings/{id}/report":{"post":{"summary":"Report once per verified user; three distinct reports hide listing","security":[{"sessionCookie":[]}],"parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["reason"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"reported":{"type":"boolean"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports":{"post":{"summary":"Report a listing (alias)","security":[{"sessionCookie":[]}],"parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"listing_id":{"type":"string"},"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["listing_id","reason"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"reported":{"type":"boolean"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/me":{"get":{"summary":"Private profile including own exact location and nonexpired inventory","security":[{"sessionCookie":[]}],"parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/me/location":{"put":{"summary":"Save private pickup location and stable coarse public area","security":[{"sessionCookie":[]}],"parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Location"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"saved":{"type":"boolean"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/development/start":{"post":{"summary":"Localhost only: begin simulated provider verification; sets HttpOnly challenge cookie","parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","enum":["whatsapp","telegram"]},"alias":{"type":"string","pattern":"^[a-z][a-z0-9_-]{2,30}$"},"community":{"type":"string"}},"required":["provider","alias","community"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"challenge_id":{"type":"string","format":"uuid"},"development":{"type":"boolean"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/development/verify":{"post":{"summary":"Consume single-use challenge bound to browser cookie; sets session","parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"challenge_id":{"type":"string","format":"uuid"}},"required":["challenge_id"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"verified":{"type":"boolean"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/telegram":{"post":{"summary":"Validate Telegram signed Login Widget proof (5 minute age; no replay); sets session","parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"community":{"type":"string"},"language":{"type":"string","enum":["en","es"],"default":"es"},"proof":{"type":"object","properties":{"id":{"oneOf":[{"type":"string"},{"type":"integer"}]},"first_name":{"type":"string"},"last_name":{"type":"string"},"username":{"type":"string"},"photo_url":{"type":"string"},"auth_date":{"oneOf":[{"type":"string"},{"type":"integer"}]},"hash":{"type":"string"}},"required":["id","auth_date","hash","username"]}},"required":["community","proof"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"verified":{"type":"boolean"},"next":{"type":"string"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/whatsapp":{"post":{"summary":"Request WhatsApp OTP; alias of /auth/whatsapp/start","parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string"},"community":{"type":"string"},"language":{"type":"string","enum":["en","es"],"default":"es"}},"required":["phone","community"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"challenge_id":{"type":"string","format":"uuid"},"expires_in":{"type":"integer"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/whatsapp/start":{"post":{"summary":"Send a five-minute OTP and set HttpOnly swap_whatsapp_challenge cookie; max three sends per phone/hour","parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string"},"community":{"type":"string"},"language":{"type":"string","enum":["en","es"],"default":"es"}},"required":["phone","community"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"challenge_id":{"type":"string","format":"uuid"},"expires_in":{"type":"integer"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/whatsapp/verify":{"post":{"summary":"Consume OTP using originating browser cookie; five attempts maximum; sets session cookie","parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"challenge_id":{"type":"string","format":"uuid"},"code":{"type":"string"},"community":{"type":"string"},"language":{"type":"string","enum":["en","es"],"default":"es"}},"required":["challenge_id","code","community"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"verified":{"type":"boolean"},"next":{"type":"string"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/whatsapp/webhook":{"get":{"summary":"Meta subscription challenge; verify token required","parameters":[{"name":"hub.mode","in":"query","required":true,"schema":{"type":"string"}},{"name":"hub.verify_token","in":"query","required":true,"schema":{"type":"string"}},{"name":"hub.challenge","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge echoed","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Invalid token"},"503":{"description":"Disabled"}}},"post":{"summary":"Signed raw-body Meta messages webhook; no browser Origin required; duplicates ignored","parameters":[{"name":"X-Hub-Signature-256","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Events processed and replies queued"},"400":{"description":"Malformed event"},"401":{"description":"Invalid signature"},"413":{"description":"Payload above 64 KiB"},"500":{"description":"Retryable processing failure"},"503":{"description":"Not configured"}}}},"/auth/logout":{"post":{"summary":"Revoke current session and clear cookie","security":[{"sessionCookie":[]}],"parameters":[{"name":"Origin","in":"header","required":true,"description":"Must exactly match APP_ORIGIN. Required on every mutation, including login.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"signed_out":{"type":"boolean"}}}}}},"400":{"description":"400 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"401 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"403 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"404 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"409 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"413 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"415 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"422 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"429 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"500 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"503 error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"sessionCookie":{"type":"apiKey","in":"cookie","name":"swap_session"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]},"Listing":{"type":"object","properties":{"id":{"type":"string"},"description":{"type":"string"},"description_original":{"type":"string"},"language_original":{"type":"string","enum":["en","es"],"default":"es"},"translation_status":{"type":"string","enum":["complete","pending"]},"icon":{"type":"string"},"status":{"type":"string","enum":["available","reserved","gone","expired"]},"pickup_type":{"type":"string","enum":["owner","swap_center"]},"pickup_label":{"type":"string","nullable":true},"area":{"type":"string"},"community":{"type":"string"},"distance_km":{"type":"number","description":"Distance rounded to 0.5 km between stable coarse points; never an exact pickup distance."},"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"}},"required":["id","description","description_original","language_original","translation_status","icon","status","pickup_type","area","community","created_at","expires_at"]},"ListingInput":{"type":"object","properties":{"description":{"type":"string","minLength":3,"maxLength":1200},"language":{"type":"string","enum":["en","es"],"default":"es"},"pickup_type":{"type":"string","enum":["owner","swap_center"],"default":"owner"}},"required":["description"]},"Community":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"lat":{"type":"number"},"lng":{"type":"number"},"radius_km":{"type":"number"},"language":{"type":"string","enum":["en","es"],"default":"es"},"swap_center_enabled":{"type":"boolean"},"sales_enabled":{"type":"boolean"},"services_enabled":{"type":"boolean"},"photos_enabled":{"type":"boolean"},"whatsapp_enabled":{"type":"boolean"},"telegram_enabled":{"type":"boolean"},"swap_center_label":{"type":"string","nullable":true},"swap_center_lat":{"type":"number","nullable":true},"swap_center_lng":{"type":"number","nullable":true}},"required":["slug","name","lat","lng","radius_km","language"]},"Location":{"type":"object","properties":{"lat":{"type":"number","minimum":-85,"maximum":85},"lng":{"type":"number","minimum":-180,"maximum":180},"community":{"type":"string"},"language":{"type":"string","enum":["en","es"],"default":"es"}},"required":["lat","lng","community"]},"Profile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"preferred_language":{"type":"string","enum":["en","es"],"default":"es"},"location":{"$ref":"#/components/schemas/Location","nullable":true},"listings":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/Listing"},{"type":"object","properties":{"moderation_status":{"type":"string","enum":["approved","review","rejected"]}}}]}}},"required":["id","preferred_language","location","listings"]},"Contact":{"type":"object","properties":{"url":{"type":"string","nullable":true},"provider":{"type":"string","enum":["whatsapp","telegram"]},"development":{"type":"boolean"},"message":{"type":"string"}},"required":["url","provider","development"]}}}}