| Donors ENGLISH, DR 80–88 | HTTP 200, 4 forums | GET /v1/donors?language=ENGLISH&drFrom=80&drTo=88 | {"donors":[{"id":3079,"domain":"chess.com","language":"ENGLISH","domainRating":85},{"id":3193,"domain":"forums.gentoo.org","language":"ENGLISH","domainRating":85},{"id":2679,"domain":"software.informer.com","language":"ENGLISH","domainRating":84},{"id":647,"domain":"support.nabble.com","language":"ENGLISH","domainRating":81}]} |
| Donors, language KLINGON | HTTP 400 | GET /v1/donors?language=KLINGON | {"detail":"Unsupported language KLINGON. Allowed: DUTCH, ENGLISH, FRENCH, GERMAN, ITALIAN, JAPANESE, POLISH, PORTUGUESE, RUSSIAN, SPANISH, VIETNAMESE."} |
| Donors with only drFrom | HTTP 400 | GET /v1/donors?drFrom=10 | {"detail":"drFrom and drTo must be sent together."} |
| POST /v1/donors | HTTP 405 | POST /v1/donors {} | {"detail":"Method not allowed."} |
| GET /v1/tasks | HTTP 405 | GET /v1/tasks | {"detail":"Method not allowed."} |
| Task: keyword and url | HTTP 201, taskId 16 | POST /v1/tasks {"keyword":"pass3 url only","url":"https://www.pass3-cycle.example/immortality-application"} | {"status":"Link task created successfully","taskId":16} |
| Task: DR 30–50 | HTTP 201, taskId 17 | POST /v1/tasks {"keyword":"pass3 dr range","url":"https://pass3-range.example/join","drFrom":30,"drTo":50} | {"status":"Link task created successfully","taskId":17} |
| Task: DR below 30 | HTTP 400 | POST /v1/tasks {"keyword":"pass3 dr below","url":"https://pass3-below.example/join","drFrom":20,"drTo":50} | {"detail":"drFrom and drTo must stay inside the enabled donor rating range 30 to 88."} |
| Task: DR above 88 | HTTP 400 | POST /v1/tasks {"keyword":"pass3 dr above","url":"https://pass3-above.example/join","drFrom":80,"drTo":89} | {"detail":"drFrom and drTo must stay inside the enabled donor rating range 30 to 88."} |
| Task: DR edges 30–88 | HTTP 201, taskId 18 | POST /v1/tasks {"keyword":"pass3 dr edges","url":"https://pass3-edges.example/join","drFrom":30,"drTo":88} | {"status":"Link task created successfully","taskId":18} |
| Task: donor 3079 and DR 80–88 | HTTP 201, taskId 19 | POST /v1/tasks {"keyword":"pass3 donor in range","url":"https://pass3-donor.example/join","donorId":3079,"drFrom":80,"drTo":88} | {"status":"Link task created successfully","taskId":19} |
| Task: donor 3079 only | HTTP 201, taskId 20 | POST /v1/tasks {"keyword":"pass3 donor only","url":"https://pass3-donor-only.example/join","donorId":3079} | {"status":"Link task created successfully","taskId":20} |
| Donor 3079 outside DR 30–50 | HTTP 400 | POST /v1/tasks {"keyword":"pass3 donor outside","url":"https://pass3-outside.example/join","donorId":3079,"drFrom":30,"drTo":50} | {"detail":"donor domain rating is outside drFrom and drTo."} |
| Catalog 4171 | HTTP 400 | POST /v1/tasks {"keyword":"pass3 catalog donor","url":"https://pass3-catalog.example/join","donorId":4171} | {"detail":"donorId is not an enabled donor."} |
| Donor 99999999 | HTTP 400 | POST /v1/tasks {"keyword":"pass3 unknown donor","url":"https://pass3-unknown.example/join","donorId":99999999} | {"detail":"donorId is not an enabled donor."} |
| Task with only drFrom | HTTP 400 | POST /v1/tasks {"keyword":"pass3 half range","url":"https://pass3-half.example/join","drFrom":30} | {"detail":"drFrom and drTo must be sent together."} |
| Task with drFrom above drTo | HTTP 400 | POST /v1/tasks {"keyword":"pass3 inverted range","url":"https://pass3-inverted.example/join","drFrom":50,"drTo":30} | {"detail":"drFrom must be less than or equal to drTo."} |
| Task with drTo 101 | HTTP 400 | POST /v1/tasks {"keyword":"pass3 dr 101","url":"https://pass3-dr101.example/join","drFrom":30,"drTo":101} | {"detail":"drFrom and drTo must be integers from 0 to 100."} |
| Task without a keyword | HTTP 400 | POST /v1/tasks {"url":"https://pass3-nokeyword.example/join"} | {"detail":"keyword is required."} |
| Task without a url | HTTP 400 | POST /v1/tasks {"keyword":"pass3 no url"} | {"detail":"url is required."} |
| Task with an ftp url | HTTP 400 | POST /v1/tasks {"keyword":"pass3 bad scheme","url":"ftp://pass3-ftp.example/join"} | {"detail":"url must be an http(s) URL."} |
| Task with a 101-character keyword | HTTP 400 | POST /v1/tasks {"keyword":"k"×101,"url":"https://pass3-long.example/join"} | {"detail":"keyword must be at most 100 characters."} |
| Task with price 77 | HTTP 201, taskId 21 | POST /v1/tasks {"keyword":"pass3 price ignored","url":"https://pass3-price.example/join","price":77} | {"status":"Link task created successfully","taskId":21} |
| Status of task 16 | HTTP 200 | GET /v1/tasks/16/status | {"status":"NEW","keyword":"pass3 url only","targetUrl":"https://www.pass3-cycle.example/immortality-application","createdAt":"2026-10-08T11:31:14.479Z","updatedAt":"2026-10-08T11:31:14.479Z"} |
| Status of 99999999 | HTTP 404 | GET /v1/tasks/99999999/status | {"detail":"Task not found."} |
| Reject task 16 while NEW | HTTP 400 | PATCH /v1/tasks/16/reject {"reason":"Too early"} | {"detail":"Task can be rejected only while its status is COMPLETED."} |
| Reject with an empty reason | HTTP 400 | PATCH /v1/tasks/16/reject {"reason":""} | {"detail":"reason is required."} |
| Reject with a 256-character reason | HTTP 400 | PATCH /v1/tasks/20/reject {"reason":"r"×256} | {"detail":"reason must be at most 255 characters."} |
| Delete task 17 | HTTP 200 | DELETE /v1/tasks/17 | {"message":"Link task deleted successfully"} |
| Delete task 17 again | HTTP 400 | DELETE /v1/tasks/17 | {"detail":"Task can be deleted only while its status is NEW."} |
| Delete 99999999 | HTTP 404 | DELETE /v1/tasks/99999999 | {"detail":"Task not found."} |
| Reject task 19 after COMPLETED | HTTP 200 | PATCH /v1/tasks/19/reject {"reason":"Only Adrian Paul counts as a real Highlander. Please fix the page."} | {"message":"Link task sent for rework successfully"} |
| Webhook for creating task 16 | HTTP 200 | POST webhook {"taskId":16,"status":"NEW","keyword":"pass3 url only","targetUrl":"https://www.pass3-cycle.example/immortality-application","createdAt":"2026-10-08T11:31:14.479Z","updatedAt":"2026-10-08T11:31:14.479Z"} | {"received":true,"stored":true,"taskId":16,"status":"NEW"} |
| Webhook for creating task 17 | HTTP 200 | POST webhook {"taskId":17,"status":"NEW","keyword":"pass3 dr range","targetUrl":"https://pass3-range.example/join","createdAt":"2026-10-08T11:31:15.515Z","updatedAt":"2026-10-08T11:31:15.515Z"} | {"received":true,"stored":true,"taskId":17,"status":"NEW"} |
| Webhook for creating task 18 | HTTP 200 | POST webhook {"taskId":18,"status":"NEW","keyword":"pass3 dr edges","targetUrl":"https://pass3-edges.example/join","createdAt":"2026-10-08T11:31:17.670Z","updatedAt":"2026-10-08T11:31:17.670Z"} | {"received":true,"stored":true,"taskId":18,"status":"NEW"} |
| Webhook for creating task 19 | HTTP 200 | POST webhook {"taskId":19,"status":"NEW","keyword":"pass3 donor in range","targetUrl":"https://pass3-donor.example/join","createdAt":"2026-10-08T11:31:19.258Z","updatedAt":"2026-10-08T11:31:19.258Z"} | {"received":true,"stored":true,"taskId":19,"status":"NEW"} |
| Webhook for creating task 20 | HTTP 200 | POST webhook {"taskId":20,"status":"NEW","keyword":"pass3 donor only","targetUrl":"https://pass3-donor-only.example/join","createdAt":"2026-10-08T11:31:20.321Z","updatedAt":"2026-10-08T11:31:20.321Z"} | {"received":true,"stored":true,"taskId":20,"status":"NEW"} |
| Webhook for creating task 21 | HTTP 200 | POST webhook {"taskId":21,"status":"NEW","keyword":"pass3 price ignored","targetUrl":"https://pass3-price.example/join","createdAt":"2026-10-08T11:31:27.088Z","updatedAt":"2026-10-08T11:31:27.088Z"} | {"received":true,"stored":true,"taskId":21,"status":"NEW"} |
| Webhook for deleting task 17 | HTTP 200 | POST webhook {"taskId":17,"status":"DELETED","keyword":"pass3 dr range","targetUrl":"https://pass3-range.example/join","createdAt":"2026-10-08T11:31:15.515Z","updatedAt":"2026-10-08T11:31:30.298Z"} | {"received":true,"stored":true,"taskId":17,"status":"DELETED"} |
| Webhook for rejecting task 19 | HTTP 200 | POST webhook {"taskId":19,"status":"REJECTED","keyword":"pass3 donor in range","targetUrl":"https://pass3-donor.example/join","createdAt":"2026-10-08T11:31:19.258Z","updatedAt":"2026-10-08T11:31:34.983Z"} | {"received":true,"stored":true,"taskId":19,"status":"REJECTED"} |
| Event for task 16 | NEW | SELECT client_webhook_events task_id=16 | {"task_id":16,"status":"NEW","body":{"taskId":16,"status":"NEW","keyword":"pass3 url only","targetUrl":"https://www.pass3-cycle.example/immortality-application","createdAt":"2026-10-08T11:31:14.479Z","updatedAt":"2026-10-08T11:31:14.479Z"}} |
| Event for task 17 | DELETED | SELECT client_webhook_events task_id=17 | {"task_id":17,"status":"DELETED","body":{"taskId":17,"status":"DELETED","keyword":"pass3 dr range","targetUrl":"https://pass3-range.example/join","createdAt":"2026-10-08T11:31:15.515Z","updatedAt":"2026-10-08T11:31:30.298Z"}} |
| Event for task 19 | REJECTED | SELECT client_webhook_events task_id=19 | {"task_id":19,"status":"REJECTED","body":{"taskId":19,"status":"REJECTED","keyword":"pass3 donor in range","targetUrl":"https://pass3-donor.example/join","createdAt":"2026-10-08T11:31:19.258Z","updatedAt":"2026-10-08T11:31:34.983Z"}} |
| taskId 0 in events | no row | SELECT client_webhook_events task_id=0 | [] |
| price in the database | null | SELECT api_tasks id=21 | {"id":21,"keyword":"pass3 price ignored","status":"NEW","price":null,"donor_id":null,"dr_from":null,"dr_to":null,"target_url":"https://pass3-price.example/join"} |
| DR after delete | DELETED, 30–50 | SELECT api_tasks id=17 | {"id":17,"keyword":"pass3 dr range","status":"DELETED","price":null,"donor_id":null,"dr_from":30,"dr_to":50,"target_url":"https://pass3-range.example/join"} |
| Donor in the database | 3079 | SELECT api_tasks id=20 | {"id":20,"keyword":"pass3 donor only","status":"NEW","price":null,"donor_id":3079,"dr_from":null,"dr_to":null,"target_url":"https://pass3-donor-only.example/join"} |
| Host with www | kept | SELECT projects domain='www.pass3-cycle.example' | [{"domain":"www.pass3-cycle.example"}] |