API

Send your price list to ADAM

One HTTP call replaces the spreadsheet. Your system posts the feed, we tell you row by row what we read and what we could not.

Validate a payload without creating anything in Settings → Integrations → Sandbox. OpenAPI document

Getting a key

Settings → Integrations → Connect. The secret is shown once at creation and stored only as a hash, so keep it where your ERP can read it. Send it as Authorization: Bearer ….

curl -X POST https://168-119-161-237.sslip.io/v1/products \
  -H "Authorization: Bearer adam_live_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"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"}]}'

The item, field by field

FieldTypeRule
namestring · ≤300
required
What the product is called in your system. Trimmed, non-empty.
brandstring · ≤120
required
Resolved within the category by the matcher.
categorystring · ≤120
required
Human form. Resolved against the slugs and aliases listed below.
unitstring · ≤40
required
Human form: «шт», «шт.», «кг», «т», «каністра» all resolve.
pricenumber
required
Greater than 0. A number, not a string; `.` as the decimal separator.
stocknumber
required
0 or more. Zero means out of stock, not unknown.
skustring · ≤100
optional
Your own article number. Optional by schema, but without it a later PATCH has nothing to resolve against.
warehousestring · ≤200
optional
Matched against your own addresses. Ambiguity is a warning, not a rejection.
moqnumber
optional
Greater than 0. Defaults to 1.
descriptionstring · ≤500
optional
Free text. Used when a row becomes a request for a new catalogue product.
updated_atrfc3339
optional
When the item last changed in your system. Enables the ordering rule on PATCH.

A field we do not read fails the whole request instead of being dropped. Dropping it quietly is how you come to believe you set a currency you did not set.

The response

202, because rows are accepted for processing with matching and review still ahead. Rejections name your own item index, so a feed you fix one pass at a time converges.

{
  "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
}

Reason codes

CodeScopeMeaning
invalid_envelopewhole request

The body is not an object with an items array.

unknown_fieldwhole request

A field we do not read. Sent back rather than dropped, so you never believe you set something you did not.

idempotency_key_reusedwhole request

This Idempotency-Key was already used for a request with a different body. Use a new key — the stored result belongs to the earlier request, not this one.

no_itemswhole request

items is empty.

too_many_itemswhole request

More items than the per-request limit. Send fewer.

required_field_missingone row

Carries field — the required field that was absent or blank. On PATCH /v1/offers that is always sku.

field_too_longone row

Carries field. The bound for each field is in the table above.

price_invalidone row

Not a number, or not greater than 0.

stock_invalidone row

Not a number, or negative. Zero is valid.

moq_invalidone row

Not a number, or not greater than 0.

sku_duplicate_in_payloadone row

The same SKU appears earlier in this request. The first occurrence wins.

updated_at_invalidone row

Not RFC 3339, for example 2026-08-24T14:02:31Z.

review_backlogwhole request

Your unreviewed rows are at the limit. Finish reviewing before sending more.

category_unresolvedone row

The value matches no slug and no alias.

unit_unresolvedone row

The value matches no unit.

wrong_endpointone row

You sent discontinued here. Withdrawal and relisting belong to PATCH /v1/offers.

A closed set, so your integration can branch on them. One code per rejected row: a row failing several checks reports the first in the order above.

Updating price and stock

Once a position is linked, PATCH /v1/offers moves its price and stock with no review and no human step. You send the article number you already sent to the product feed; we change the offer behind it. This is the call your ERP runs on a schedule.

curl -X PATCH https://168-119-161-237.sslip.io/v1/offers \
  -H "Authorization: Bearer adam_live_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"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}]}'
FieldTypeRule
skustring · ≤100
required
Your own article number, as sent to POST /v1/products. The only way to name the position.
pricenumber
optional
Greater than 0. Omit it and the price stays as it is.
stocknumber
optional
0 or more. Zero sets the offer to out of stock and leaves it listed.
moqnumber
optional
Greater than 0. The minimum order quantity; the unit is not changed here.
discontinuedboolean
optional
true withdraws the offer, false puts it back. Withdrawal always succeeds; relisting can be refused.
updated_atrfc3339
optional
When the position last changed in your system. Send it and an out-of-order retry cannot overwrite a newer price; omit it and the last request to arrive wins. Equal to the stored one with the same values is a no-op; equal with different values is equal_timestamp_conflict.

An item needs its sku plus at least one of price, stock, moq, discontinued. Everything you leave out stays as it is, so a stock-only sweep never touches a price. sku on its own is rejected rather than counted as applied.

Send updated_at and retries stop being dangerous: an item whose timestamp is older than the last one we applied changes nothing and comes back as stale_update. Omit it and the last request to arrive wins, which is fine for a single scheduled job and wrong for two.

unchanged counts items whose offer already held the values you sent. Nothing was written and nothing is wrong — a nightly feed that resends everything gets applied for what moved and unchanged for the rest, instead of thousands of errors. Sending the same updated_at with the same values lands here too; sending it with different values is equal_timestamp_conflict, because equal timestamps cannot say which version is current.

Withdrawal and relisting are not symmetric, and it is better you know why than discover it. discontinued: true always succeeds — taking your own offer down needs nobody's permission. discontinued: false puts it back only if the offer is complete and your account may publish; otherwise the row comes back as relist_blocked with the reason in detail.

not_published is the number of applied rows sitting on an offer a farmer cannot see — a draft, a paused offer. The price did change; nobody is looking at it. A patch never publishes on your behalf, so this count is how you find out rather than wondering why nothing moved.

{
  "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
}
CodeScopeMeaning
no_change_requestedone row

sku and nothing changeable. A timestamp alone is not a change — send price, stock, moq or discontinued.

discontinued_invalidone row

Present but not a boolean. "yes" is not true.

sku_unknownone row

No live mapping for this code. Send the position through POST /v1/products once; after it is confirmed, PATCH works forever.

sku_ambiguousone row

More than one of your offers carries this code, so we cannot tell which price to move. detail names the products. Give them distinct codes in your own system.

offer_missingone row

The mapping exists but its offer is gone. Send the position through POST /v1/products again.

stale_updateone row

Your updated_at is older than the last one we applied, so nothing changed. detail carries the timestamp we hold.

equal_timestamp_conflictone row

Your updated_at equals the one we already applied, but the values differ — so we cannot tell which is current and refuse rather than guess. Advance updated_at. If the values match, the item is counted in unchanged instead and no error is returned.

relist_blockedone row

discontinued: false was refused by the publish gate. Withdrawal always succeeds; relisting needs the offer to be complete and your account able to publish. detail carries the reason.

price_tieredone row

This offer has a quantity price ladder, and a single flat price cannot replace it. Remove the ladder in the dashboard, then the API manages this position.

Only the codes this endpoint alone returns. Every request-level code and every value check in the table above applies here too, with field naming sku where the product feed would name a dozen fields.

Categories we recognise

Read live from the catalogue, so this list cannot drift from what the resolver accepts. Case and trailing punctuation do not matter.

  • seedsSeeds

    Hybrids · Seed · seeds · Sowing material · Гибриды · Гібриди · Кукурудза · Кукуруза · Насіннєвий матеріал · Насіння · Насіння кукурудзи · Насіння рапсу · Насіння сої · Насіння соняшника · Посевной материал · Посівний матеріал · Пшеница · Пшениця · Рапс · Семена · Семена кукурузы · Семена подсолнечника · Семена подсолнуха · Семена рапса · Семена сои · Семенной материал · Соняшник · Соя · Ячмень · Ячмінь

  • fertilizersFertilizers

    Fertiliser · Fertilizer · fertilizers · Growth stimulants · Micro fertilizers · Агрохимия · Агрохімія · Добрива · Микроудобрения · Микроудобрения и стимуляторы роста · Минеральные удобрения · Мікродобрива · Мікродобрива та стимулятори росту · Мінеральні добрива · Органические удобрения · Органічні добрива · Стимулятори росту · Стимуляторы роста · Удобрения

  • pesticidesCrop Protection

    Agrochemicals · CPP · Crop Protection · Fungicide · Fungicides · Herbicide · Herbicides · Insecticide · Insecticides · Pesticide · pesticides · Plant protection · Агрохимикаты · Агрохімікати · Адъюванты · Адьюванти · Акарициди · Акарициды · Гербицид · Гербициды · Гербіцид · Гербіциди · Десиканти · Десиканты · Засоби захисту · Засоби захисту рослин · ЗЗР · Инсектицид · Инсектициды · Інсектицид · Інсектициди · Пестициди · Пестициди та агрохімікати · Пестициды · Пестициды и агрохимикаты · Прилипатели · Прилипачі · Прилипачі (пав) · Протравители · Протруйник · Протруйники · Родентициди · Родентициды · СЗР · Средства защиты · Средства защиты растений · Фунгицид · Фунгициды · Фунгіцид · Фунгіциди

  • fuel-lubricantsFuel & Lubricants

    Diesel · Fuel · fuel-lubricants · Grease · Lubricants · Oils · Антифриз · Бензин · Горюче-смазочные материалы · ГСМ · Дизельне пальне · Дизельное топливо · ДТ · Масла · Мастила · Пальне · Пально-мастильні матеріали · ПММ · Смазки · Топливо

  • machineryMachinery

    Combines · Equipment · Implements · machinery · Tractors · Комбайни · Комбайны · Обладнання · Оборудование · Прицепы · Причепи · Сельхозтехника · Сільгосптехніка · Техника · Техніка · Трактори · Тракторы

  • spare-partsSpare Parts

    Bearings · Belts · Filters · Parts · spare-parts · Детали · Деталі · Запчасти · Запчастини · Ножи · Ножі · Підшипники · Подшипники · Ремені · Ремни · Фильтры · Фільтри

  • tires-wheelsTires & Wheels

    Rims · Tires · tires-wheels · Tyres · Wheels · Диски · Колеса · Колёса · Покришки · Покрышки · Шини · Шини та диски · Шины · Шины и диски

  • suppliesSupplies

    supplies · Витратні матеріали · Расходные материалы · Спецодежда · Спецодяг · Тара · Упаковка

  • servicesServices

    services · Послуги · Сервис · Сервіс · Услуги

  • livestockLivestock

    livestock · Ветпрепарати · Ветпрепараты · Животноводство · Корма · Корми · Тваринництво

  • energy-systemsEnergy Systems

    energy-systems · Генератори · Генераторы · Енергосистеми · Солнечные панели · Сонячні панелі · Энергосистемы

Units we recognise

  • piece

    шт · штука · штук · штуки · од · одиниця · pcs · pc · piece · unit

  • kg

    кг · кілограм · килограмм · кілограмів · kg

  • ton

    т · t · тонна · тонн · тонни · ton · tonne

  • liter

    л · l · літр · литр · літрів · liter · litre

  • bag

    мішок · мешок · мішків · bag

  • pack

    уп · пак · пачка · упаковка · паковання · pack

  • canister

    каністра · канистра · кан · canister

  • bottle

    пляшка · бутылка · флакон · bottle

  • set

    набір · набор · set

  • hectare

    га · гектар · гектарів · ha · hectare

Limits and idempotency

  • POST /v1/products 5000 × 10 min · 30 req / 10 min
  • PATCH /v1/offers 5000 × 60 s · 30 req / 60 s
  • 20000 unresolved rows · 10 open jobs

Send Idempotency-Key on every real call. A repeat with the same key returns the stored result — the same job, the same rejections — and creates nothing, so a timeout on your side never becomes a second price list. A replay carries the first 20 rejections and rejected_total; page the rest from the rejections endpoint.

What happens next

Accepted rows are matched against our catalogue and land in your review screen. A position we recognise is confirmed there; one we do not becomes a request for a new catalogue product. Review is a human step and it is not instant — plan your first feed with that in mind. It is also a one-off: once a position is linked, its price and stock travel through PATCH /v1/offers and never queue for review again.

Not supported yet

currency, vat_rate and lead_time_days are not read on either endpoint, so sending them is an error rather than a silent drop. Quantity price ladders are not editable over the API either — an offer that has one refuses a flat price as price_tiered. Letting us pull the feed from your own URL on a schedule is the next phase.

+380 (67) 419-07-94