{"openapi":"3.1.0","info":{"title":"Cabivet Public API","version":"2026-06-02-beta","description":"Beta public REST API. Stable-by-intent until first real integrator, then frozen as /public/v1.\n\nWebhook signature: each delivery sends `Cabivet-Webhook-Timestamp` (Unix seconds) and\n`Cabivet-Webhook-Signature` (lowercase hex HMAC-SHA256). The signed message is\n`timestamp + \".\" + rawBody`. Reject deliveries whose timestamp is more than 300 seconds\nfrom now, then compare the signature in constant time.\n\nNo sandbox environment yet — integrate against a read-only demo or low-stakes clinic."},"servers":[{"url":"https://api.cabivet.com/public/v1"}],"components":{"schemas":{},"parameters":{},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}}},"paths":{"/me":{"get":{"responses":{"200":{"description":"Authenticated clinic and key","content":{"application/json":{"schema":{"type":"object","properties":{"clinic":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"name":{"type":"string"},"plan":{"type":["string","null"]}},"required":["id","name","plan"]},"key":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["read","write","webhooks"]}}},"required":["id","name","prefix","scopes"]}},"required":["clinic","key"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/owners":{"get":{"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_after","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_before","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"updated_after","in":"query"}],"responses":{"200":{"description":"Owners","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string"},"phone_alt":{"type":["string","null"]},"email":{"type":["string","null"],"format":"email"},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","first_name","last_name","phone","phone_alt","email","address","city","created_at","updated_at"]}},"next_cursor":{"type":["string","null"]}},"required":["data","next_cursor"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}},"post":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"first_name":{"type":"string","minLength":1,"maxLength":80},"last_name":{"type":"string","minLength":1,"maxLength":80},"phone":{"type":"string","minLength":6,"maxLength":40},"phone_alt":{"type":["string","null"],"maxLength":40},"email":{"type":["string","null"],"format":"email"},"address":{"type":["string","null"],"maxLength":500},"city":{"type":["string","null"],"maxLength":120}},"required":["first_name","last_name","phone"]}}}},"responses":{"201":{"description":"Created owner","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string"},"phone_alt":{"type":["string","null"]},"email":{"type":["string","null"],"format":"email"},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","first_name","last_name","phone","phone_alt","email","address","city","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/owners/{id}":{"get":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Owner","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string"},"phone_alt":{"type":["string","null"]},"email":{"type":["string","null"],"format":"email"},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","first_name","last_name","phone","phone_alt","email","address","city","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}},"patch":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"first_name":{"type":"string","minLength":1,"maxLength":80},"last_name":{"type":"string","minLength":1,"maxLength":80},"phone":{"type":"string","minLength":6,"maxLength":40},"phone_alt":{"type":["string","null"],"maxLength":40},"email":{"type":["string","null"],"format":"email"},"address":{"type":["string","null"],"maxLength":500},"city":{"type":["string","null"],"maxLength":120}}}}}},"responses":{"200":{"description":"Updated owner","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"first_name":{"type":"string"},"last_name":{"type":"string"},"phone":{"type":"string"},"phone_alt":{"type":["string","null"]},"email":{"type":["string","null"],"format":"email"},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","first_name","last_name","phone","phone_alt","email","address","city","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/animals":{"get":{"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_after","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_before","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"updated_after","in":"query"},{"schema":{"type":"string"},"required":false,"name":"species","in":"query"}],"responses":{"200":{"description":"Animals","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"owner_id":{"type":"integer","exclusiveMinimum":0},"name":{"type":"string"},"species":{"type":"string"},"breed":{"type":["string","null"]},"sex":{"type":["string","null"]},"date_of_birth":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"color":{"type":["string","null"]},"microchip":{"type":["string","null"]},"is_sterilized":{"type":"boolean"},"weight_kg":{"type":["string","null"]},"allergies":{"type":"array","items":{"type":"string"}},"alerts":{"type":["string","null"]},"is_deceased":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","owner_id","name","species","breed","sex","date_of_birth","color","microchip","is_sterilized","weight_kg","allergies","alerts","is_deceased","created_at","updated_at"]}},"next_cursor":{"type":["string","null"]}},"required":["data","next_cursor"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}},"post":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"owner_id":{"type":"integer","exclusiveMinimum":0},"name":{"type":"string","minLength":1,"maxLength":80},"species":{"type":"string","minLength":1,"maxLength":40},"breed":{"type":["string","null"],"maxLength":100},"sex":{"type":["string","null"],"enum":["M","F","inconnu",null]},"date_of_birth":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"color":{"type":["string","null"],"maxLength":80},"microchip":{"type":["string","null"],"maxLength":80},"is_sterilized":{"type":"boolean"},"weight_kg":{"type":["string","null"],"pattern":"^\\d+(\\.\\d{1,2})?$"},"allergies":{"type":"array","items":{"type":"string","maxLength":120}},"alerts":{"type":["string","null"],"maxLength":500}},"required":["owner_id","name","species"]}}}},"responses":{"201":{"description":"Created animal","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"owner_id":{"type":"integer","exclusiveMinimum":0},"name":{"type":"string"},"species":{"type":"string"},"breed":{"type":["string","null"]},"sex":{"type":["string","null"]},"date_of_birth":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"color":{"type":["string","null"]},"microchip":{"type":["string","null"]},"is_sterilized":{"type":"boolean"},"weight_kg":{"type":["string","null"]},"allergies":{"type":"array","items":{"type":"string"}},"alerts":{"type":["string","null"]},"is_deceased":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","owner_id","name","species","breed","sex","date_of_birth","color","microchip","is_sterilized","weight_kg","allergies","alerts","is_deceased","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/animals/{id}":{"get":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Animal","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"owner_id":{"type":"integer","exclusiveMinimum":0},"name":{"type":"string"},"species":{"type":"string"},"breed":{"type":["string","null"]},"sex":{"type":["string","null"]},"date_of_birth":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"color":{"type":["string","null"]},"microchip":{"type":["string","null"]},"is_sterilized":{"type":"boolean"},"weight_kg":{"type":["string","null"]},"allergies":{"type":"array","items":{"type":"string"}},"alerts":{"type":["string","null"]},"is_deceased":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","owner_id","name","species","breed","sex","date_of_birth","color","microchip","is_sterilized","weight_kg","allergies","alerts","is_deceased","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}},"patch":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"species":{"type":"string","minLength":1,"maxLength":40},"breed":{"type":["string","null"],"maxLength":100},"sex":{"type":["string","null"],"enum":["M","F","inconnu",null]},"date_of_birth":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"color":{"type":["string","null"],"maxLength":80},"microchip":{"type":["string","null"],"maxLength":80},"is_sterilized":{"type":"boolean"},"weight_kg":{"type":["string","null"],"pattern":"^\\d+(\\.\\d{1,2})?$"},"allergies":{"type":"array","items":{"type":"string","maxLength":120}},"alerts":{"type":["string","null"],"maxLength":500},"owner_id":{"type":"integer","exclusiveMinimum":0}}}}}},"responses":{"200":{"description":"Updated animal","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"owner_id":{"type":"integer","exclusiveMinimum":0},"name":{"type":"string"},"species":{"type":"string"},"breed":{"type":["string","null"]},"sex":{"type":["string","null"]},"date_of_birth":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"color":{"type":["string","null"]},"microchip":{"type":["string","null"]},"is_sterilized":{"type":"boolean"},"weight_kg":{"type":["string","null"]},"allergies":{"type":"array","items":{"type":"string"}},"alerts":{"type":["string","null"]},"is_deceased":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","owner_id","name","species","breed","sex","date_of_birth","color","microchip","is_sterilized","weight_kg","allergies","alerts","is_deceased","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/visits":{"get":{"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_after","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_before","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"updated_after","in":"query"}],"responses":{"200":{"description":"Visits","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"animal_id":{"type":["integer","null"],"exclusiveMinimum":0},"owner_id":{"type":["integer","null"],"exclusiveMinimum":0},"vet_id":{"type":"integer","exclusiveMinimum":0},"appointment_id":{"type":["integer","null"],"exclusiveMinimum":0},"invoice_id":{"type":["integer","null"],"exclusiveMinimum":0},"visit_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"visit_time":{"type":["string","null"]},"reason":{"type":"string"},"weight_kg":{"type":["string","null"]},"temperature_c":{"type":["string","null"]},"follow_up_date":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"follow_up_notes":{"type":["string","null"]},"status":{"type":"string"},"is_free":{"type":"boolean"},"is_farm_visit":{"type":"boolean"},"herd_id":{"type":["integer","null"],"exclusiveMinimum":0},"farm_animal_count":{"type":["integer","null"],"exclusiveMinimum":0},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","animal_id","owner_id","vet_id","appointment_id","invoice_id","visit_date","visit_time","reason","weight_kg","temperature_c","follow_up_date","follow_up_notes","status","is_free","is_farm_visit","herd_id","farm_animal_count","created_at","updated_at"]}},"next_cursor":{"type":["string","null"]}},"required":["data","next_cursor"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}},"post":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"animal_id":{"type":"integer","exclusiveMinimum":0},"owner_id":{"type":"integer","exclusiveMinimum":0},"vet_id":{"type":"integer","exclusiveMinimum":0},"appointment_id":{"type":"integer","exclusiveMinimum":0},"visit_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"visit_time":{"type":["string","null"],"pattern":"^\\d{2}:\\d{2}(:\\d{2})?$"},"reason":{"type":"string","minLength":1,"maxLength":500},"weight_kg":{"type":["string","null"],"pattern":"^\\d+(\\.\\d{1,2})?$"},"temperature_c":{"type":["string","null"],"pattern":"^\\d+(\\.\\d{1,2})?$"},"follow_up_date":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"follow_up_notes":{"type":["string","null"],"maxLength":500}},"required":["vet_id","visit_date","reason"]}}}},"responses":{"201":{"description":"Created visit","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"animal_id":{"type":["integer","null"],"exclusiveMinimum":0},"owner_id":{"type":["integer","null"],"exclusiveMinimum":0},"vet_id":{"type":"integer","exclusiveMinimum":0},"appointment_id":{"type":["integer","null"],"exclusiveMinimum":0},"invoice_id":{"type":["integer","null"],"exclusiveMinimum":0},"visit_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"visit_time":{"type":["string","null"]},"reason":{"type":"string"},"weight_kg":{"type":["string","null"]},"temperature_c":{"type":["string","null"]},"follow_up_date":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"follow_up_notes":{"type":["string","null"]},"status":{"type":"string"},"is_free":{"type":"boolean"},"is_farm_visit":{"type":"boolean"},"herd_id":{"type":["integer","null"],"exclusiveMinimum":0},"farm_animal_count":{"type":["integer","null"],"exclusiveMinimum":0},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","animal_id","owner_id","vet_id","appointment_id","invoice_id","visit_date","visit_time","reason","weight_kg","temperature_c","follow_up_date","follow_up_notes","status","is_free","is_farm_visit","herd_id","farm_animal_count","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/visits/{id}":{"get":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Visit","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"animal_id":{"type":["integer","null"],"exclusiveMinimum":0},"owner_id":{"type":["integer","null"],"exclusiveMinimum":0},"vet_id":{"type":"integer","exclusiveMinimum":0},"appointment_id":{"type":["integer","null"],"exclusiveMinimum":0},"invoice_id":{"type":["integer","null"],"exclusiveMinimum":0},"visit_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"visit_time":{"type":["string","null"]},"reason":{"type":"string"},"weight_kg":{"type":["string","null"]},"temperature_c":{"type":["string","null"]},"follow_up_date":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"follow_up_notes":{"type":["string","null"]},"status":{"type":"string"},"is_free":{"type":"boolean"},"is_farm_visit":{"type":"boolean"},"herd_id":{"type":["integer","null"],"exclusiveMinimum":0},"farm_animal_count":{"type":["integer","null"],"exclusiveMinimum":0},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","animal_id","owner_id","vet_id","appointment_id","invoice_id","visit_date","visit_time","reason","weight_kg","temperature_c","follow_up_date","follow_up_notes","status","is_free","is_farm_visit","herd_id","farm_animal_count","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/visits/{id}/attachments":{"post":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"file_name":{"type":"string","minLength":1,"maxLength":200},"file_type":{"type":"string","enum":["image/jpeg","image/png","application/pdf","audio/webm","audio/mp4","audio/mpeg","audio/ogg"]},"size_bytes":{"type":"integer","exclusiveMinimum":0,"maximum":10485760},"description":{"type":["string","null"],"maxLength":300}},"required":["file_name","file_type","size_bytes"]}}}},"responses":{"201":{"description":"Presigned attachment upload","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"method":{"type":"string","enum":["PUT"]},"object_key":{"type":"string"},"upload_url":{"type":"string","format":"uri"},"expires_at":{"type":"string","format":"date-time"},"headers":{"type":"object","additionalProperties":{"type":"string"}}},"required":["id","method","object_key","upload_url","expires_at","headers"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/appointments":{"get":{"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_after","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_before","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"updated_after","in":"query"}],"responses":{"200":{"description":"Appointments","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"animal_id":{"type":["integer","null"],"exclusiveMinimum":0},"owner_id":{"type":["integer","null"],"exclusiveMinimum":0},"vet_id":{"type":"integer","exclusiveMinimum":0},"start_at":{"type":"string","format":"date-time"},"end_at":{"type":"string","format":"date-time"},"reason":{"type":["string","null"]},"notes":{"type":["string","null"]},"status":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","animal_id","owner_id","vet_id","start_at","end_at","reason","notes","status","source","created_at","updated_at"]}},"next_cursor":{"type":["string","null"]}},"required":["data","next_cursor"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}},"post":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"animal_id":{"type":"integer","exclusiveMinimum":0},"owner_id":{"type":"integer","exclusiveMinimum":0},"vet_id":{"type":"integer","exclusiveMinimum":0},"start_at":{"type":"string","format":"date-time"},"end_at":{"type":"string","format":"date-time"},"reason":{"type":["string","null"],"maxLength":500},"notes":{"type":["string","null"],"maxLength":1000},"status":{"type":"string","default":"scheduled"}},"required":["vet_id","start_at","end_at"]}}}},"responses":{"201":{"description":"Created appointment","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"animal_id":{"type":["integer","null"],"exclusiveMinimum":0},"owner_id":{"type":["integer","null"],"exclusiveMinimum":0},"vet_id":{"type":"integer","exclusiveMinimum":0},"start_at":{"type":"string","format":"date-time"},"end_at":{"type":"string","format":"date-time"},"reason":{"type":["string","null"]},"notes":{"type":["string","null"]},"status":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","animal_id","owner_id","vet_id","start_at","end_at","reason","notes","status","source","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/appointments/{id}":{"patch":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"animal_id":{"type":"integer","exclusiveMinimum":0},"owner_id":{"type":"integer","exclusiveMinimum":0},"vet_id":{"type":"integer","exclusiveMinimum":0},"start_at":{"type":"string","format":"date-time"},"end_at":{"type":"string","format":"date-time"},"reason":{"type":["string","null"],"maxLength":500},"notes":{"type":["string","null"],"maxLength":1000},"status":{"type":"string","default":"scheduled"}}}}}},"responses":{"200":{"description":"Updated appointment","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"animal_id":{"type":["integer","null"],"exclusiveMinimum":0},"owner_id":{"type":["integer","null"],"exclusiveMinimum":0},"vet_id":{"type":"integer","exclusiveMinimum":0},"start_at":{"type":"string","format":"date-time"},"end_at":{"type":"string","format":"date-time"},"reason":{"type":["string","null"]},"notes":{"type":["string","null"]},"status":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","animal_id","owner_id","vet_id","start_at","end_at","reason","notes","status","source","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/invoices":{"get":{"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_after","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_before","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"updated_after","in":"query"}],"responses":{"200":{"description":"Invoices","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"invoice_number":{"type":["string","null"]},"status":{"type":"string"},"owner_id":{"type":"integer","exclusiveMinimum":0},"animal_id":{"type":["integer","null"],"exclusiveMinimum":0},"issue_date":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_minor_units":{"type":"string"},"amount_paid_minor_units":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","invoice_number","status","owner_id","animal_id","issue_date","total_minor_units","amount_paid_minor_units","created_at","updated_at"]}},"next_cursor":{"type":["string","null"]}},"required":["data","next_cursor"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/invoices/{id}":{"get":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Invoice","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"invoice_number":{"type":["string","null"]},"status":{"type":"string"},"owner_id":{"type":"integer","exclusiveMinimum":0},"animal_id":{"type":["integer","null"],"exclusiveMinimum":0},"issue_date":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"total_minor_units":{"type":"string"},"amount_paid_minor_units":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","invoice_number","status","owner_id","animal_id","issue_date","total_minor_units","amount_paid_minor_units","created_at","updated_at"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/invoices/{id}/payments":{"post":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount_minor_units":{"type":"string","pattern":"^d+$"},"payment_method":{"type":"string","minLength":1,"maxLength":40},"payment_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"reference":{"type":["string","null"],"maxLength":120},"notes":{"type":["string","null"],"maxLength":500}},"required":["amount_minor_units","payment_method","payment_date"]}}}},"responses":{"201":{"description":"Payment recorded","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"invoice_id":{"type":"number"}},"required":["ok","invoice_id"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/webhooks":{"get":{"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_after","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_before","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"updated_after","in":"query"}],"responses":{"200":{"description":"Webhook subscriptions","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean"},"consecutive_failures":{"type":"integer","minimum":0},"last_failure_at":{"type":["string","null"],"format":"date-time"},"last_success_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}},"required":["id","url","events","is_active","consecutive_failures","last_failure_at","last_success_at","created_at"]}},"next_cursor":{"type":["string","null"]}},"required":["data","next_cursor"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}},"post":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"},"minItems":1}},"required":["url","events"]}}}},"responses":{"201":{"description":"Created webhook","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","exclusiveMinimum":0},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean"},"consecutive_failures":{"type":"integer","minimum":0},"last_failure_at":{"type":["string","null"],"format":"date-time"},"last_success_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"secret":{"type":"string"}},"required":["id","url","events","is_active","consecutive_failures","last_failure_at","last_success_at","created_at","secret"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/webhooks/{id}":{"delete":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Webhook disabled","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/webhooks/{id}/test":{"post":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"responses":{"202":{"description":"Test delivery queued","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"delivery_id":{"type":"string"}},"required":["ok","delivery_id"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/webhook-deliveries":{"get":{"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_after","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"created_before","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"updated_after","in":"query"},{"schema":{"type":"string","enum":["queued","delivered","failed","dead"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0},"required":false,"name":"subscription_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"event_type","in":"query"}],"responses":{"200":{"description":"Webhook delivery log","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"subscription_id":{"type":"integer","exclusiveMinimum":0},"event_id":{"type":"string","format":"uuid"},"event_type":{"type":"string"},"status":{"type":"string","enum":["queued","delivered","failed","dead"]},"attempt_number":{"type":"integer","exclusiveMinimum":0},"response_status":{"type":["integer","null"]},"response_body_excerpt":{"type":["string","null"]},"error":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"delivered_at":{"type":["string","null"],"format":"date-time"}},"required":["id","subscription_id","event_id","event_type","status","attempt_number","response_status","response_body_excerpt","error","created_at","delivered_at"]}},"next_cursor":{"type":["string","null"]}},"required":["data","next_cursor"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}},"/webhook-deliveries/{id}":{"get":{"parameters":[{"schema":{"type":"integer","exclusiveMinimum":0},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Webhook delivery detail","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"subscription_id":{"type":"integer","exclusiveMinimum":0},"event_id":{"type":"string","format":"uuid"},"event_type":{"type":"string"},"status":{"type":"string","enum":["queued","delivered","failed","dead"]},"attempt_number":{"type":"integer","exclusiveMinimum":0},"response_status":{"type":["integer","null"]},"response_body_excerpt":{"type":["string","null"]},"error":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"delivered_at":{"type":["string","null"],"format":"date-time"},"request_body_excerpt":{"type":"string"},"signature_header":{"type":["string","null"]}},"required":["id","subscription_id","event_id","event_type","status","attempt_number","response_status","response_body_excerpt","error","created_at","delivered_at","request_body_excerpt","signature_header"]}}}},"400":{"description":"Validation or request error","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"403":{"description":"Scope or role required","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"]}}}}}}}},"webhooks":{},"security":[{"bearerAuth":[]}],"x-beta":true,"x-deprecation-policy":"Breaking changes require minimum 90 days notice and Sunset headers before GA."}