{"openapi":"3.1.0","info":{"title":"ADOPTR API for rescues","version":"1","description":"Read ADOPTR's upcoming departures and your own animals, hold seats, and turn held seats into animals. Every answer holds only your rescue's animals and seats. Guide: https://adoptr.uk/developers","contact":{"name":"ADOPTR","email":"contact@adoptr.uk","url":"https://adoptr.uk/developers"}},"servers":[{"url":"https://sandbox.adoptr.uk/api/v1","description":"Sandbox: test keys (adk_test_…), made-up departures"},{"url":"https://adoptr.uk/api/v1","description":"Live: live keys (adk_live_…)"}],"security":[{"key":[]}],"tags":[{"name":"Departures","description":"When the vans leave, their deadlines and seats free"},{"name":"Animals","description":"Your own animals"},{"name":"Seats","description":"Holding seats and turning them into animals"}],"paths":{"/departures":{"get":{"tags":["Departures"],"operationId":"listDepartures","summary":"Upcoming departures","description":"The departures listed on adoptr.uk that haven't left, and any still on the road with your animals, soonest first.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["departures"],"properties":{"departures":{"type":"array","items":{"$ref":"#/components/schemas/Departure"}}}},"example":{"departures":[{"leaves_on":"2026-12-01","uk_entry":"2026-12-03","last_drop_off":"2026-12-04","status":"open","confirmed":false,"deadlines":{"closes_on":"2026-11-24","rabies_by":"2026-11-10","brucella_window_from":"2026-11-09","brucella_window_to":"2026-11-13","last_brucella_sample":"2026-11-13"},"zones":[],"seats_free":18,"yours":{"animals":2,"seats_held":0,"holds":[],"places_kept":0}}]}}}},"401":{"description":"`unauthorized`, `wrong_environment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/departures/{leaves_on}":{"get":{"tags":["Departures"],"operationId":"getDeparture","summary":"One departure, with your animals on it","parameters":[{"name":"leaves_on","in":"path","required":true,"description":"The day it leaves Romania","schema":{"type":"string","format":"date","examples":["2026-12-01"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["departure"],"properties":{"departure":{"allOf":[{"$ref":"#/components/schemas/Departure"},{"type":"object","required":["animals"],"properties":{"animals":{"type":"array","items":{"$ref":"#/components/schemas/Animal"}}}}]}}}}}},"400":{"description":"`bad_request`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`unauthorized`, `wrong_environment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/animals":{"get":{"tags":["Animals"],"operationId":"listAnimals","summary":"Your animals","description":"Your animals on departures still ahead or on the road, and on the waiting list (`leaves_on` null), by id.","parameters":[{"name":"leaves_on","in":"query","schema":{"type":"string","format":"date","examples":["2026-12-01"]},"description":"Only those on this departure"},{"name":"papers","in":"query","schema":{"type":"string","enum":["ready","missing","blocked"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":100}},{"name":"after","in":"query","schema":{"type":"integer","minimum":1},"description":"The `next_after` of the page before"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["animals","next_after"],"properties":{"animals":{"type":"array","items":{"$ref":"#/components/schemas/Animal"}},"next_after":{"type":["integer","null"],"description":"Send it as `after` for the next page; null on the last"}}},"example":{"animals":[{"id":2,"name":"Max","species":"dog","sex":"male","chip":"999000000100001","born_on":"2025-07-01","leaves_on":"2026-12-01","destination":"GB","papers":"missing","to_do":[{"item":"passport","state":"missing","note":"needed"}],"passport":null,"rabies":{"on":"2026-07-16","valid_until":"2027-07-16"},"brucella":{"sampled_on":"2026-11-10","result":"negative"},"adopter":{"name":"Priya Desai","postcode":"BS8 4PP","address_confirmed":true},"ched_ref":null,"apha":null}],"next_after":null}}}},"400":{"description":"`bad_request`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`unauthorized`, `wrong_environment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/animals/{id}":{"get":{"tags":["Animals"],"operationId":"getAnimal","summary":"One of your animals","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["animal"],"properties":{"animal":{"$ref":"#/components/schemas/Animal"}}},"example":{"animal":{"id":2,"name":"Max","species":"dog","sex":"male","chip":"999000000100001","born_on":"2025-07-01","leaves_on":"2026-12-01","destination":"GB","papers":"missing","to_do":[{"item":"passport","state":"missing","note":"needed"}],"passport":null,"rabies":{"on":"2026-07-16","valid_until":"2027-07-16"},"brucella":{"sampled_on":"2026-11-10","result":"negative"},"adopter":{"name":"Priya Desai","postcode":"BS8 4PP","address_confirmed":true},"ched_ref":null,"apha":null}}}}},"401":{"description":"`unauthorized`, `wrong_environment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/holds":{"get":{"tags":["Seats"],"operationId":"listHolds","summary":"Your holds still counting","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["holds"],"properties":{"holds":{"type":"array","items":{"$ref":"#/components/schemas/Hold"}}}}}}},"401":{"description":"`unauthorized`, `wrong_environment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Seats"],"operationId":"holdSeats","summary":"Hold seats on an open departure","description":"Before its animals are known. Needs a key with `hold`. Within `seats_free` and your rescue's seat limit: the seats your app holds at once on one departure.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Yours to choose (a UUID, for example): sent again with the same key and body within a day, the API answers as the first time and does nothing twice.","schema":{"type":"string","pattern":"^[\\x21-\\x7e]{1,100}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HoldRequest"},"example":{"leaves_on":"2026-12-28","seats":3,"note":"for the litter","expires_at":"2026-11-25T18:00:00Z"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["hold","seats_free"],"properties":{"hold":{"$ref":"#/components/schemas/Hold"},"seats_free":{"type":"integer","minimum":0}}},"example":{"hold":{"id":41,"leaves_on":"2026-12-28","seats":3,"expires_at":"2026-11-25T18:00:00.000Z"},"seats_free":15}}}},"400":{"description":"`bad_request`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`unauthorized`, `wrong_environment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_running`, `departure_closed`, `not_enough_seats`, `over_seat_limit`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"`too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/holds/{id}":{"delete":{"tags":["Seats"],"operationId":"releaseHold","summary":"Give back every seat of a hold","description":"Animals already added stay. Needs a key with `hold`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Yours to choose (a UUID, for example): sent again with the same key and body within a day, the API answers as the first time and does nothing twice.","schema":{"type":"string","pattern":"^[\\x21-\\x7e]{1,100}$"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["released"],"properties":{"released":{"type":"object","required":["id","seats"],"properties":{"id":{"type":"integer"},"seats":{"type":"integer"}}}}},"example":{"released":{"id":41,"seats":2}}}}},"400":{"description":"`bad_request`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`unauthorized`, `wrong_environment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_running`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`idempotency_conflict`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/holds/{id}/animals":{"post":{"tags":["Seats"],"operationId":"addAnimal","summary":"Turn one held seat into an animal going to the UK","description":"A hold of several seats keeps the rest; the answer's `hold` is its id, or null once its last seat is taken. Refused with `papers_blocked` when the animal already can't make this departure: the seat is kept. Needs a key with `confirm`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Yours to choose (a UUID, for example): sent again with the same key and body within a day, the API answers as the first time and does nothing twice.","schema":{"type":"string","pattern":"^[\\x21-\\x7e]{1,100}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnimalRequest"},"example":{"name":"Pufi","species":"dog","sex":"male","chip":"999000000777001","born_on":"2025-03-12","microchipped_on":"2025-05-01","passport":"RO-9777001","rabies_on":"2026-07-01","rabies_vaccine":"Rabisin","rabies_batch":"A123","rabies_valid_until":"2027-07-01","brucella_sampled_on":"2026-12-01","brucella_tube":"7","brucella_result":"negative","adopter":"Charlotte Evans","adopter_address":"4 Bramble Way, Taunton","adopter_postcode":"TA1 1AA","adopter_phone":"+44 7700 900777","adopter_email":"charlotte@example.com"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["animal","hold"],"properties":{"animal":{"$ref":"#/components/schemas/Animal"},"hold":{"type":["integer","null"],"description":"The hold, or null once its last seat is taken"}}}}}},"400":{"description":"`bad_request`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`unauthorized`, `wrong_environment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`forbidden`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_running`, `departure_closed`, `hold_expired`, `chip_taken`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"`too_large`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`idempotency_conflict`, `papers_blocked`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","headers":{"Retry-After":{"description":"Seconds to wait","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"key":{"type":"http","scheme":"bearer","description":"Your rescue's API key: adk_test_… on the sandbox, adk_live_… on adoptr.uk. Keep it on your server, never in a web page or a phone app."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"description":"Some errors say more: `to_do` (papers_blocked), `seats_free` (not_enough_seats), `limit` and `held` (over_seat_limit).","properties":{"code":{"type":"string","enum":["unauthorized","wrong_environment","forbidden","rate_limited","not_found","bad_request","too_large","departure_closed","not_enough_seats","over_seat_limit","hold_expired","papers_blocked","chip_taken","idempotency_conflict","idempotency_running"]},"message":{"type":"string"},"to_do":{"type":"array","items":{"$ref":"#/components/schemas/ToDo"}},"seats_free":{"type":"integer"},"limit":{"type":"integer"},"held":{"type":"integer"}}}}},"Departure":{"type":"object","required":["leaves_on","uk_entry","last_drop_off","status","confirmed","deadlines","zones","seats_free","yours"],"properties":{"leaves_on":{"type":"string","format":"date","examples":["2026-12-01"],"description":"The day the van leaves Romania: the departure's name"},"uk_entry":{"type":"string","format":"date","examples":["2026-12-01"],"description":"The day it crosses into the UK"},"last_drop_off":{"type":"string","format":"date","examples":["2026-12-01"]},"status":{"type":"string","enum":["open","closed","on_the_road","done","not_listed"],"description":"`closed`: past `closes_on`, no animal can join. `not_listed`: not on adoptr.uk, shown because your animals are on it."},"confirmed":{"type":"boolean","description":"Enough animals booked for the van to go on this day; until then the day is an estimate"},"deadlines":{"type":"object","required":["closes_on","rabies_by","brucella_window_from","brucella_window_to","last_brucella_sample"],"properties":{"closes_on":{"type":"string","format":"date","examples":["2026-12-01"],"description":"The last day an animal can join"},"rabies_by":{"type":"string","format":"date","examples":["2026-12-01"],"description":"The last day a rabies vaccine counts for this departure"},"brucella_window_from":{"type":"string","format":"date","examples":["2026-12-01"],"description":"When to take dogs' Brucella samples"},"brucella_window_to":{"type":"string","format":"date","examples":["2026-12-01"]},"last_brucella_sample":{"type":"string","format":"date","examples":["2026-12-01"],"description":"The last day a sample is accepted"}}},"zones":{"type":"array","items":{"type":"string"},"description":"UK delivery zones on this departure"},"seats_free":{"type":"integer","minimum":0,"description":"Seats anyone can still ask for, counted as adoptr.uk counts its places for the UK"},"yours":{"type":"object","required":["animals","seats_held","holds","places_kept"],"properties":{"animals":{"type":"integer"},"seats_held":{"type":"integer"},"holds":{"type":"array","items":{"type":"object","required":["id","seats","expires_at"],"properties":{"id":{"type":"integer"},"seats":{"type":"integer"},"expires_at":{"type":"string","format":"date-time"}}}},"places_kept":{"type":"integer","description":"Places ADOPTR keeps for you, not filled yet"}}}}},"ToDo":{"type":"object","required":["item","state","note"],"properties":{"item":{"type":"string","examples":["passport","rabies","brucella"]},"state":{"type":"string","enum":["missing","blocked"]},"note":{"type":["string","null"]}}},"Animal":{"type":"object","required":["id","name","species","leaves_on","destination","papers","to_do","adopter"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"species":{"type":"string","enum":["dog","cat"]},"sex":{"type":["string","null"],"enum":["male","female",null]},"chip":{"type":["string","null"]},"born_on":{"type":["string","null"],"format":"date"},"leaves_on":{"type":["string","null"],"format":"date","description":"Null while on the waiting list"},"destination":{"type":"string","description":"GB, or an EU country's code"},"papers":{"type":["string","null"],"enum":["ready","missing","blocked",null],"description":"`missing`: still to come (`to_do` says what). `blocked`: can't make this departure"},"to_do":{"type":"array","items":{"$ref":"#/components/schemas/ToDo"}},"passport":{"type":["string","null"]},"rabies":{"type":"object","properties":{"on":{"type":["string","null"],"format":"date"},"valid_until":{"type":["string","null"],"format":"date"}}},"brucella":{"type":["object","null"],"description":"Dogs going to the UK only","properties":{"sampled_on":{"type":["string","null"],"format":"date"},"result":{"type":["string","null"],"enum":["negative","positive",null]}}},"adopter":{"type":"object","description":"Their address, phone and email are never sent back","properties":{"name":{"type":["string","null"]},"postcode":{"type":["string","null"]},"address_confirmed":{"type":"boolean"}}},"ched_ref":{"type":["string","null"]},"apha":{"type":["object","null"],"properties":{"status":{"type":"string"},"decided_at":{"type":["string","null"],"format":"date-time"}}}}},"Hold":{"type":"object","required":["id","leaves_on","seats","expires_at"],"properties":{"id":{"type":"integer"},"leaves_on":{"type":"string","format":"date","examples":["2026-12-01"]},"seats":{"type":"integer"},"expires_at":{"type":"string","format":"date-time"}}},"HoldRequest":{"type":"object","additionalProperties":false,"required":["leaves_on","seats"],"properties":{"leaves_on":{"type":"string","format":"date","examples":["2026-12-01"]},"seats":{"type":"integer","minimum":1,"maximum":99},"expires_at":{"type":["string","null"],"format":"date-time","description":"With its offset. 7 days if left out; at most 14 days, never after the end of `closes_on` (midnight, London), at least an hour ahead"},"note":{"type":["string","null"],"minLength":1,"maxLength":500}}},"AnimalRequest":{"type":"object","additionalProperties":false,"required":["name","species","chip"],"description":"Days are YYYY-MM-DD and not in the future. Everything but name, species and chip can follow later through ADOPTR.","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"species":{"type":"string","enum":["dog","cat"]},"sex":{"type":["string","null"],"enum":["male","female",null]},"chip":{"type":"string","description":"15 digits; spaces are dropped"},"born_on":{"type":["string","null"],"format":"date"},"microchipped_on":{"type":["string","null"],"format":"date"},"passport":{"type":["string","null"],"minLength":1,"maxLength":40},"rabies_on":{"type":["string","null"],"format":"date"},"rabies_vaccine":{"type":["string","null"],"minLength":1,"maxLength":120},"rabies_batch":{"type":["string","null"],"minLength":1,"maxLength":60},"rabies_valid_until":{"type":["string","null"],"format":"date"},"brucella_sampled_on":{"type":["string","null"],"format":"date"},"brucella_tube":{"type":["string","null"],"minLength":1,"maxLength":20},"brucella_result":{"type":["string","null"],"enum":["negative","positive",null],"description":"Needs brucella_sampled_on"},"adopter":{"type":["string","null"],"minLength":1,"maxLength":120,"description":"The adopter's name"},"adopter_address":{"type":["string","null"],"minLength":1,"maxLength":300,"description":"Never sent back"},"adopter_postcode":{"type":["string","null"],"minLength":1,"maxLength":12},"adopter_phone":{"type":["string","null"],"minLength":1,"maxLength":40,"description":"Never sent back"},"adopter_email":{"type":["string","null"],"format":"email","maxLength":200,"description":"Never sent back"}}}}},"x-rate-limits":"Per key: 60 reads and 20 writes a minute, 5000 calls a day."}