{"openapi":"3.1.0","info":{"title":"ADAM vendor ingest API","version":"1.0.0","description":"Push your product feed to ADAM. A new position reaches a review queue once; after it is linked, PATCH /v1/offers moves its price and stock with no review."},"servers":[{"url":"https://168-119-161-237.sslip.io","description":"ingest service"}],"externalDocs":{"url":"https://adam.ua/docs/api","description":"Field-by-field guide"},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"The key issued in Settings → Integrations. Shown once at creation."}},"schemas":{"ProductItem":{"type":"object","required":["name","brand","category","unit","price","stock"],"additionalProperties":false,"properties":{"name":{"type":"string","maxLength":300,"description":"Назва товару у вашій системі. Обрізається, не може бути порожньою."},"brand":{"type":"string","maxLength":120,"description":"Розпізнається матчером у межах категорії."},"category":{"type":"string","maxLength":120,"description":"У людському вигляді. Розпізнається за списком нижче."},"unit":{"type":"string","maxLength":40,"description":"У людському вигляді: «шт», «шт.», «кг», «т», «каністра» — усі розпізнаються."},"price":{"type":"number","exclusiveMinimum":0,"description":"Більше 0. Число, не рядок; десятковий розділювач — «.»."},"stock":{"type":"number","minimum":0,"description":"0 або більше. Нуль означає «немає в наявності», а не «невідомо»."},"sku":{"type":"string","maxLength":100,"description":"Ваш артикул. За схемою необов’язковий, але без нього подальший PATCH не має за чим шукати позицію."},"warehouse":{"type":"string","maxLength":200,"description":"Звіряється з вашими адресами. Неоднозначність — попередження, не відмова."},"moq":{"type":"number","exclusiveMinimum":0,"description":"Більше 0. За замовчуванням 1."},"description":{"type":"string","maxLength":500,"description":"Вільний текст. Використовується, коли рядок стає заявкою на новий товар каталогу."},"updated_at":{"type":"string","format":"date-time","description":"Коли позиція останній раз змінилася у вашій системі. Дає правило порядку для PATCH."}}},"OfferItem":{"type":"object","required":["sku"],"additionalProperties":false,"minProperties":2,"description":"sku plus at least one of price, stock, moq, discontinued. sku alone changes nothing and is rejected as no_change_requested.","properties":{"sku":{"type":"string","maxLength":100,"description":"Ваш артикул, той самий, що надсилали в POST /v1/products. Єдиний спосіб назвати позицію."},"price":{"type":"number","exclusiveMinimum":0,"description":"Більше 0. Не надсилайте — ціна залишиться як є."},"stock":{"type":"number","minimum":0,"description":"0 або більше. Нуль ставить «немає в наявності» й залишає пропозицію в каталозі."},"moq":{"type":"number","exclusiveMinimum":0,"description":"Більше 0. Мінімальна партія; одиниця виміру тут не змінюється."},"discontinued":{"type":"boolean","description":"true знімає пропозицію з продажу, false повертає. Зняття завжди проходить; повернення може бути відхилене."},"updated_at":{"type":"string","format":"date-time","description":"Коли позиція останній раз змінилася у вашій системі. Надішліть — і запізніла повторна спроба не перезапише новішу ціну; не надішлете — переможе останній запит, що надійшов. Той самий час і ті самі значення — це no-op; той самий час з іншими значеннями — equal_timestamp_conflict."}}},"Rejection":{"type":"object","required":["index","reason"],"properties":{"index":{"type":"integer","minimum":0,"description":"Your own position in items."},"sku":{"type":["string","null"]},"reason":{"type":"string","enum":["required_field_missing","field_too_long","price_invalid","stock_invalid","moq_invalid","sku_duplicate_in_payload","updated_at_invalid","category_unresolved","unit_unresolved","wrong_endpoint","no_change_requested","discontinued_invalid","sku_unknown","sku_ambiguous","offer_missing","stale_update","equal_timestamp_conflict","relist_blocked","price_tiered"]},"field":{"type":"string"},"detail":{"type":"string"}}}}},"security":[{"apiKey":[]}],"paths":{"/v1/whoami":{"get":{"summary":"Confirm a key works","responses":{"200":{"description":"The key is live","content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"vendor_slug":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"server_time":{"type":"string","format":"date-time"}}}}}},"401":{"description":"No key, or a revoked one"}}}},"/v1/products":{"post":{"summary":"Send a product feed","description":"At most 5000 items per request, once per 10 minutes. The response carries the first 20 rejections plus rejected_total; fetch the rest from /v1/requests/{id}/rejections, which pages the first 1000 we store.","parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean"},"description":"Validate and report without writing anything."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":16,"maxLength":255},"description":"Required unless dry_run=true. A repeat returns the stored result."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"additionalProperties":false,"properties":{"items":{"type":"array","minItems":1,"maxItems":5000,"items":{"$ref":"#/components/schemas/ProductItem"}}}},"example":{"items":[{"sku":"KRB-46","name":"Карбамід 46% гранульований","brand":"Sumykhimprom","category":"Добрива","unit":"кг","price":12.5,"stock":1000,"warehouse":"Київський склад","moq":100,"updated_at":"2026-08-24T14:02:31Z"}]}}}},"responses":{"200":{"description":"Same shape, for dry_run=true — nothing was written"},"202":{"description":"Accepted for processing","content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"job_id":{"type":["string","null"],"format":"uuid"},"accepted":{"type":"integer","minimum":0},"rejected":{"type":"array","items":{"$ref":"#/components/schemas/Rejection"}},"rejected_total":{"type":"integer","minimum":0}}},"example":{"request_id":"8f14e45f-ceea-467a-9c4c-1b0f0e5c9e2a","job_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","accepted":1198,"rejected":[{"index":42,"sku":"XYZ-1","reason":"category_unresolved","detail":"«Хімія» matches no category"},{"index":87,"sku":"KRB-99","reason":"required_field_missing","field":"brand"}],"rejected_total":2}}}},"400":{"description":"See the request-level reason codes"},"401":{"description":"No key, or a revoked one"},"403":{"description":"The key lacks products:write, or the vendor is inactive"},"409":{"description":"review_backlog — unreviewed rows are at the limit, or idempotency_key_reused"},"413":{"description":"The body exceeds 16777216 bytes"},"429":{"description":"rate_limited — carries Retry-After"}}}},"/v1/offers":{"patch":{"summary":"Update price and stock on positions already linked","description":"At most 5000 items per request, 30 requests per 60 seconds. No review queue: an item whose sku resolves to exactly one of your offers is applied immediately. not_published counts rows applied to offers a farmer cannot see — a draft stays a draft.","parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean"},"description":"Judge every item and report, without writing anything."},{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":16,"maxLength":255},"description":"Required unless dry_run=true. A repeat returns the stored result."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"additionalProperties":false,"properties":{"items":{"type":"array","minItems":1,"maxItems":5000,"items":{"$ref":"#/components/schemas/OfferItem"}}}},"example":{"items":[{"sku":"KRB-46","price":12.9,"stock":840,"updated_at":"2026-08-25T09:00:00Z"},{"sku":"KAS-32","stock":0},{"sku":"OLD-01","discontinued":true}]}}}},"responses":{"200":{"description":"Same shape, for dry_run=true — nothing was written"},"202":{"description":"Applied","content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"applied":{"type":"integer","minimum":0},"unchanged":{"type":"integer","minimum":0,"description":"Items whose offer already held the values sent. Nothing was written and nothing is wrong — a retried identical batch reports these instead of rejections."},"not_published":{"type":"integer","minimum":0,"description":"Of the applied rows, how many sit on an offer a farmer cannot see."},"rejected":{"type":"array","items":{"$ref":"#/components/schemas/Rejection"}},"rejected_total":{"type":"integer","minimum":0}}},"example":{"request_id":"1c9d4b7e-3f60-4a21-8de5-7a2b6c0f9e11","applied":1198,"unchanged":613,"not_published":42,"rejected":[{"index":17,"sku":"ZIR-20","reason":"sku_ambiguous","detail":"7 of your offers carry this code: Зірочка Z-20, Зірочка Z-22, …"},{"index":63,"sku":"KRB-46","reason":"stale_update","detail":"last applied 2026-08-25T09:00:00+00"}],"rejected_total":2}}}},"400":{"description":"See the request-level reason codes"},"401":{"description":"No key, or a revoked one"},"403":{"description":"The key lacks offers:write, or the vendor is inactive"},"409":{"description":"idempotency_key_reused — this Idempotency-Key was used for a different body"},"413":{"description":"The body exceeds 16777216 bytes"},"429":{"description":"rate_limited — carries Retry-After. Dry runs are metered too, against their own count"}}}},"/v1/requests/{request_id}/rejections":{"get":{"summary":"Page through one request's rejections","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"One page, ordered by your own item index","content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"rejected_total":{"type":"integer","minimum":0},"offset":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"rejected":{"type":"array","items":{"$ref":"#/components/schemas/Rejection"}}}}}}},"401":{"description":"No key, or a revoked one"},"404":{"description":"No such request for this vendor"}}}}},"x-adam-units":[{"unit":"piece","accepts":["шт","штука","штук","штуки","од","одиниця","pcs","pc","piece","unit"]},{"unit":"kg","accepts":["кг","кілограм","килограмм","кілограмів","kg"]},{"unit":"ton","accepts":["т","t","тонна","тонн","тонни","ton","tonne"]},{"unit":"liter","accepts":["л","l","літр","литр","літрів","liter","litre"]},{"unit":"bag","accepts":["мішок","мешок","мішків","bag"]},{"unit":"pack","accepts":["уп","пак","пачка","упаковка","паковання","pack"]},{"unit":"canister","accepts":["каністра","канистра","кан","canister"]},{"unit":"bottle","accepts":["пляшка","бутылка","флакон","bottle"]},{"unit":"set","accepts":["набір","набор","set"]},{"unit":"hectare","accepts":["га","гектар","гектарів","ha","hectare"]}],"x-adam-reason-codes":[{"code":"invalid_envelope","scope":"request","endpoints":["products","offers"],"meaning":"Тіло запиту — не об’єкт із масивом items."},{"code":"unknown_field","scope":"request","endpoints":["products","offers"],"meaning":"Поле, яке ми не читаємо. Повертаємо помилку, а не тихо відкидаємо — щоб ви не вважали, що задали те, чого не задали."},{"code":"idempotency_key_reused","scope":"request","endpoints":["products","offers"],"meaning":"Цей Idempotency-Key уже використано для запиту з іншим тілом. Візьміть новий ключ — збережений результат належить попередньому запиту, а не цьому."},{"code":"no_items","scope":"request","endpoints":["products","offers"],"meaning":"items порожній."},{"code":"too_many_items","scope":"request","endpoints":["products","offers"],"meaning":"Позицій більше за ліміт на запит. Надішліть меншими партіями."},{"code":"required_field_missing","scope":"row","endpoints":["products","offers"],"meaning":"Містить `field` — обов’язкове поле, якого немає або воно порожнє. На PATCH /v1/offers це завжди sku."},{"code":"field_too_long","scope":"row","endpoints":["products","offers"],"meaning":"Містить `field`. Межа для кожного поля — у таблиці вище."},{"code":"price_invalid","scope":"row","endpoints":["products","offers"],"meaning":"Не число або не більше 0."},{"code":"stock_invalid","scope":"row","endpoints":["products","offers"],"meaning":"Не число або від’ємне. Нуль допустимий."},{"code":"moq_invalid","scope":"row","endpoints":["products","offers"],"meaning":"Не число або не більше 0."},{"code":"sku_duplicate_in_payload","scope":"row","endpoints":["products","offers"],"meaning":"Той самий артикул вже є раніше в цьому запиті. Перемагає перше входження."},{"code":"updated_at_invalid","scope":"row","endpoints":["products","offers"],"meaning":"Не RFC 3339, наприклад 2026-08-24T14:02:31Z."},{"code":"review_backlog","scope":"request","endpoints":["products"],"meaning":"Ваші невідпрацьовані рядки досягли ліміту. Завершіть перевірку, перш ніж надсилати ще."},{"code":"category_unresolved","scope":"row","endpoints":["products"],"meaning":"Значення не збігається ні зі slug, ні з псевдонімом."},{"code":"unit_unresolved","scope":"row","endpoints":["products"],"meaning":"Значення не збігається з жодною одиницею."},{"code":"wrong_endpoint","scope":"row","endpoints":["products"],"meaning":"Ви надіслали `discontinued` сюди. Зняття з продажу й повернення — це PATCH /v1/offers."},{"code":"no_change_requested","scope":"row","endpoints":["offers"],"meaning":"Лише sku, без жодного змінюваного поля. Один timestamp — не зміна: надішліть price, stock, moq або discontinued."},{"code":"discontinued_invalid","scope":"row","endpoints":["offers"],"meaning":"Присутнє, але не булеве. `\"yes\"` — це не true."},{"code":"sku_unknown","scope":"row","endpoints":["offers"],"meaning":"Для цього коду немає активного зв’язку. Надішліть позицію через POST /v1/products один раз — після підтвердження PATCH працює завжди."},{"code":"sku_ambiguous","scope":"row","endpoints":["offers"],"meaning":"Цей код мають кілька ваших пропозицій, тому неясно, яку ціну змінювати. `detail` перелічує товари. Дайте їм різні коди у своїй системі."},{"code":"offer_missing","scope":"row","endpoints":["offers"],"meaning":"Зв’язок є, але його пропозиція зникла. Надішліть позицію через POST /v1/products ще раз."},{"code":"stale_update","scope":"row","endpoints":["offers"],"meaning":"Ваш updated_at старіший за останній застосований, тому нічого не змінилося. `detail` містить наш timestamp."},{"code":"equal_timestamp_conflict","scope":"row","endpoints":["offers"],"meaning":"Ваш updated_at збігається з уже застосованим, але значення інші — ми не можемо визначити, яке актуальне, і відмовляємо, а не вгадуємо. Змістіть updated_at. Якщо значення однакові, позиція йде в `unchanged` і помилки немає."},{"code":"relist_blocked","scope":"row","endpoints":["offers"],"meaning":"`discontinued: false` відхилено перевіркою публікації. Зняття з продажу завжди проходить; повернення потребує повної пропозиції та права публікувати. `detail` містить причину."},{"code":"price_tiered","scope":"row","endpoints":["offers"],"meaning":"У цієї пропозиції є сходинки ціни за кількістю, і одна фіксована ціна їх не заміняє. Приберіть сходинки в кабінеті — далі позицією керує API."}]}