Заказы партнёра
Как магазин принимает заказ дропшиппера: на кого он записывается, по каким ценам считается, когда магазин отказывает и как не создать заказ дважды.
На этой странице
- Что передаёт партнёр
- Заказчик, доставка, оплата и получатель
- Права ключа
- Цены и скидки
- Заказ целиком или отказ
- Склады и предзаказ
- Подарки по акции
- Повтор запроса: Idempotency-Key
- Номер заказа у партнёра: external_id
- Ожидаемый итог: expected_total
- Что магазин пишет партнёру и покупателю
- Какие заказы видит ключ
- Заказы в панели магазина
- Полный цикл на примере
- Чего нет
Через API партнёр передаёт магазину заказы и потом следит за ними. Так работает дропшиппер: покупатель оформил заказ у него на сайте, программа дропшиппера передаёт магазину, какие товары и сколько нужно, а дальше заказом занимается менеджер магазина.
Вы передаёте только товары и комментарий. Доставку, оплату и получателя через API не передают: их назначает менеджер магазина в панели, когда обрабатывает заказ.
На этой странице описано, на кого магазин записывает такой заказ, по каким ценам его считает, когда может его не принять и как не создать один заказ дважды. Каждое поле запросов и ответов, все коды ошибок и причины отказа собраны на странице «Заказы: адреса и поля».
| Адрес | Право | Что делает |
|---|---|---|
POST /api/v1/orders/check |
orders:create |
считает заказ, ничего не создавая: цены, скидки, подарки, итог и причины, по которым заказ не принять |
POST /api/v1/orders |
orders:create |
создаёт заказ |
GET /api/v1/orders |
orders:read |
заказы контакта ключа |
GET /api/v1/orders/{id} |
orders:read |
один заказ |
Что передаёт партнёр
| Поле | Что это |
|---|---|
items |
товары: номер товара product_id, номер артикула sku_id и количество qty. Оба номера обязательны |
comment |
комментарий к заказу для менеджера |
external_id |
номер заказа в вашей системе, по желанию |
expected_total |
итог, который вы ожидаете, по желанию |
storefront_id, locale |
витрина и язык заказа, по желанию |
Других полей у заказа нет. Кроме тела, POST /orders требует заголовок
Idempotency-Key, о нём ниже. Если
передать доставку (shipping), способ оплаты (payment_method_id),
получателя (recipient) или промокод (coupon), магазин ответит 422 с кодом
validation_failed и сообщением «Такого поля здесь нет. Допустимые поля:
storefront_id, external_id, items, comment, expected_total, locale.». Магазин
не пропускает такие поля молча, чтобы вы не решили, что он их принял.
Товар и артикул указывайте только номерами из каталога API: id товара и
id его артикула в /products или
/skus. Код артикула и штрихкод в
заказе не принимаются, найдите по ним номера через /skus. Артикул обязан
принадлежать товару, номер которого вы передали.
Заказчик, доставка, оплата и получатель
Владелец выдаёт ключ на ваш контакт в магазине, и все заказы по этому ключу магазин записывает на этот контакт. Заказчиком в таких заказах будете вы.
- Имя, телефон и почта заказчика попадают в заказ из карточки вашего контакта. Сама карточка при заказе не меняется.
- Новых контактов и кабинетов магазин не заводит.
- Если у вашего контакта есть личный кабинет на сайте магазина, заказ появится в этом кабинете, как и любой другой ваш заказ.
Заказ создаётся без доставки, без способа оплаты и без получателя. Доставка в итог не входит, итог равен сумме товаров после скидок. Получателя, доставку и оплату менеджер магазина назначает в панели, когда обрабатывает заказ. О том, как передавать магазину адрес и данные получателя, договоритесь с ним отдельно.
Когда менеджер всё назначит, вы увидите это в ответе
GET /orders/{id}, в
полях shipping, payment и recipient заказа. Через API эти поля можно
только читать. Пока менеджер ничего не назначил, shipping и recipient
равны null, а в payment есть только состояние оплаты. Стоимость доставки,
которую назначил менеджер, входит в итог заказа, а номер накладной появится в
shipping.waybill_number.
Права ключа
| Право | Флажок в форме ключа | Что открывает |
|---|---|---|
orders:create |
«Создавать новые заказы» | POST /orders/check и POST /orders |
orders:read |
«Видеть заказы» | GET /orders и GET /orders/{id} |
Права не зависят друг от друга. Ключ только с orders:create получает
созданный заказ целиком в ответе на POST /orders, но потом посмотреть его уже
не сможет: GET /orders/{id} ответит 403 с кодом missing_scope. Чтобы
следить за заказами, вашему ключу нужны оба права.
Право на каталог для заказа не проверяется, но номера товаров и артикулов
берутся из каталога, поэтому ключу обычно отмечают и
«Видеть товары и категории». Свои цены можно сверять через
/prices.
Цены и скидки
Покупателем при расчёте считается ваш контакт.
- Цены те же, что отдаёт вам
/prices: с акциями каталога, ценой вашей категории покупателей, персональными ценами и ценами от количества. Если у вашего контакта есть личный кабинет, магазин считает вас зарегистрированным покупателем, и действуют цены для зарегистрированных покупателей. Своей цены позиции передать нельзя. - Скидки корзины, которые магазин даёт без промокода, действуют по вашему контакту: по его категории покупателей и его личным ограничениям. Промокод через API не передаётся.
- Подарки по акции магазин кладёт сам, подробнее ниже.
- Наименьшая сумма заказа витрины к заказам через API не применяется.
- Бонусы через API не списываются.
- Доставка в итог не входит, пока её не назначит менеджер.
- Валюта заказа — валюта витрины, курс записывается в заказ в момент оформления. Заказ потом не пересчитывается, даже если курс изменится.
Если ваши цены изменились между проверкой и созданием заказа, заказ будет
создан по новым ценам. Чтобы этого не случилось, передавайте ожидаемый итог в
поле expected_total.
Заказ целиком или отказ
Корзина на витрине сама подгоняет количество под остаток, шаг продажи и минимальное количество. Ваш заказ магазин так не меняет, потому что вы уже пообещали своему покупателю ровно то, что передали. Поэтому магазин либо принимает заказ ровно в том виде, в каком вы его прислали, либо не создаёт его вовсе и называет все причины сразу.
Заказ не будет принят, если:
- товара нет в каталоге или он не опубликован;
- артикула нет или он не относится к переданному товару;
- артикул снят с продажи;
- количество меньше минимального или не кратно шагу продажи;
- на складах не хватает товара, а заказ сверх остатка в магазине запрещён.
Тогда POST /orders отвечает 422 с кодом cannot_place, а причины перечислены
в поле problems. Каждая причина называет поле запроса, к которому относится,
например items.2.qty, и подсказывает, как её исправить. Например, при неверном
количестве магазин называет ближайшее количество, которое можно заказать.
Все причины описаны в разделе
«Причины отказа».
Те же причины заранее показывает POST /orders/check. Отправьте туда то же
тело, что собираетесь отправить в POST /orders. Если в ответе can_place
равно true, заказ примут, если до создания в магазине ничего не изменится.
Количество в позиции указывайте в единицах продажи товара (поле unit),
например в штуках, метрах или килограммах. Упаковок и услуг в заказе через
API нет. Товар, который продают только упаковками, заказывается количеством,
кратным упаковке.
Склады и предзаказ
Наличие магазин проверяет по тем же складам, что показывает вам
/inventory. Если в форме ключа выбраны склады,
магазин смотрит только на них. Если не выбраны, магазин смотрит на склады, с
которых продаёт витрина заказа. С этих же складов он резервирует товар под
заказ.
Дальше всё зависит от настройки «Разрешить заказ, когда товара нет» в разделе складов магазина.
- Предзаказ запрещён (так по умолчанию). Заказ на количество больше
доступного не принимается, причина
out_of_stockназывает, сколько есть. Если товар забрал другой заказ, пока ваш оформлялся, магазин тоже откажет. Причина будетstock_reserve_failed, и в ней перечислено, чего не хватило. - Предзаказ разрешён. Заказ принимается на любое количество. Сколько
товара ждёт поступления на склад, видно в ответе: в предупреждении
backorderи в полеbackorder_qtyпозиции.
Подарки по акции
Если в магазине действует акция с подарком к заказу, магазин положит подарок и
в ваш заказ, так же как в заказ на витрине. Подарок вы не передаёте и не
выбираете: его кладёт магазин. В ответах он стоит отдельной позицией с
is_gift: true.
Подарок кладётся, только если он есть на складах, по которым магазин считает наличие для ключа: выбранных в ключе, а если не выбраны — на складах витрины. Если подарка там нет, заказ всё равно принимается, просто без подарка. Если подарок — тот же артикул, что вы заказали, остаток сначала идёт на ваши позиции, а подарку достаётся то, что осталось.
Повтор запроса: Idempotency-Key
Бывает, что программа отправила заказ, но ответа не дождалась, например
оборвалась связь. Тогда неизвестно, создан ли заказ. Чтобы такой заказ можно
было безопасно отправить ещё раз, у POST /orders есть обязательный
заголовок Idempotency-Key, ключ повтора:
Idempotency-Key: 6f1c2e0a-8d4b-4f5e-9a37-0c2b1d7e5a90
Придумайте для каждого нового заказа свою строку и повторяйте запрос этого
заказа с той же строкой. Удобнее всего UUID или ваш номер заказа с
приставкой. Ключ повтора — до 255 печатных знаков ASCII: латиница, цифры,
знаки препинания и пробел, без кириллицы и переводов строки. Без заголовка
магазин отвечает 428 с кодом idempotency_key_required, а неверный ключ
повтора получает 400 с кодом bad_idempotency_key.
Что происходит, когда приходит запрос с ключом, который магазин уже видел:
| Ситуация | Ответ |
|---|---|
| заказ по этому ключу создан, тело запроса то же | 201 с тем же заказом и заголовком Idempotent-Replayed: true. Второй заказ не создаётся |
| первый запрос с этим ключом ещё оформляется | 409 с кодом idempotency_in_progress и заголовком Retry-After: 2, какое бы ни было тело. Повторите через две секунды |
| первый запрос завершён, а тело запроса другое | 422 с кодом idempotency_key_reused. Скорее всего, вы по ошибке дали новому заказу ключ прежнего |
первый запрос получил отказ: ошибку проверки, cannot_place, total_mismatch или любую другую |
ключ свободен, заказа нет. Исправьте запрос и отправьте его с тем же ключом |
| заказ по этому ключу удалили в панели | ключ свободен, и повтор оформит заказ заново |
| заказ создан, но потом владелец привязал ваш ключ API к другому контакту | 409 с кодом idempotency_order_hidden. Когда владелец меняет контакт у ключа, магазин выдаёт новый ключ, а прежний отвечает 401. Заказ остался у прежнего контакта, и новому ключу он не виден. Не отправляйте его с новым ключом повтора, иначе в магазине появится второй такой же |
Ключи повтора у каждого ключа API свои: одна и та же строка у двух ключей API
означает два разных заказа. Регистр букв в ключе повтора важен: order-a1 и
Order-A1 — разные ключи.
Что считается тем же телом. Порядок полей в объектах значения не имеет.
Числа в полях storefront_id, expected_total и в полях позиций
product_id, sku_id и qty сравниваются как числа: 2, "2", "2.000"
и 2.0 одно и то же. Поле со значением null, "" или {} равно полю,
которого нет вовсе. Пробелы по краям строк не важны. Остальное сравнивается
как написано: другой текст комментария или другой порядок позиций в items
дают другое тело. Поэтому при повторе отправляйте то же, что отправляли в
первый раз.
Сколько магазин помнит ключ повтора. Ключ повтора действует 24 часа с
первого запроса. После этого запрос с тем же ключом считается новым и создаст
новый заказ. Если ответ на создание так и не пришёл за сутки, сначала
поищите заказ через
GET /orders?external_id=….
Если магазин не закончил оформление. Бывает, что первый запрос так и не завершился, например магазин перезапустили посреди оформления. Через 10 минут такой запрос считается оборванным, и повтор с тем же ключом повтора оформит заказ заново.
Ответ на повтор — тот же заказ в его нынешнем виде, а не копия первого
ответа: если менеджер успел сменить статус или назначить доставку, вы увидите
это. Предупреждения warnings в ответе на повтор всегда пустые.
Номер заказа у партнёра: external_id
В поле external_id передайте номер заказа в вашей системе, до 64 знаков.
Магазин запомнит его и вернёт в ответах, а по параметру ?external_id= заказ
можно найти в списке.
Номер должен быть уникальным в пределах ключа API, регистр букв в нём важен:
A-1 и a-1 — разные номера. Если заказ с таким номером уже принят,
POST /orders отвечает 409 с кодом external_id_taken, а номер этого заказа
в магазине приходит в поле order_id. Если заказ с этим номером прямо сейчас
оформляется другим запросом, ответ 409 с кодом external_id_in_progress и
заголовком Retry-After: 2. Если владелец удалил заказ в панели, номер снова
свободен.
Занятые номера и ключи повтора принадлежат ключу API, а не контакту. Если владелец привяжет ключ к другому контакту, номера заказов прежнего контакта останутся занятыми, хотя сами заказы новому контакту не видны.
Номер защищает от дублей надёжнее, чем Idempotency-Key, потому что не
истекает через сутки. Если вы повторите заказ с новым ключом повтора и без
external_id, магазин создаст второй такой же заказ. С тем же external_id
второй заказ создан не будет.
Поле необязательное. Пустая строка значит то же, что номер не передан.
Ожидаемый итог: expected_total
В поле expected_total можно передать итог, который вы ожидаете, например
"416.64". Если итог по расчёту магазина отличается хотя бы на копейку, заказ
не создаётся: ответ 409 с кодом total_mismatch, а итог магазина приходит в
поле actual_total. Доставки в итоге при создании нет, поэтому сравнивайте с
суммой товаров после скидок.
Поле можно не передавать, но тогда заказ создаётся по ценам, которые
действуют в момент оформления. Внутри POST /orders магазин сверяет итог
дважды, перед оформлением и в момент оформления, потому что за это время
владелец мог изменить цену или скидку. /orders/check сообщает о расхождении
причиной total_mismatch.
Что магазин пишет партнёру и покупателю
О заказах, пришедших через API, магазин сам ничего не пишет ни вам, ни покупателю: ни письма о новом заказе, ни сообщений о смене статуса, ни автоматических сообщений CRM, ни счёта на почту. Это касается и получателя, которого назначит менеджер. Сотрудники магазина получают уведомления о таких заказах как обычно. Если менеджер сам отправит письмо из заказа, оно уйдёт.
Исключение одно — электронный чек. Если у кассы магазина включено «Отправлять чек покупателю», чек по вашему заказу уйдёт на почту или телефон заказчика, которые записаны в заказе из карточки вашего контакта. Получателю чек не уходит никогда. Владелец может выключить отправку чека в форме вашего ключа, переключателем «Отправлять партнёру электронный чек» в блоке «Заказы партнёра». Тогда магазин всё равно выдаст чек, но никуда его не отправит.
Если владелец включил в форме ключа сообщения партнёру, магазин будет сообщать вашему сайту, что у заказа сменился статус или менеджер его изменил. Это не письмо, а запрос на адрес вашего сайта. Подробнее на странице «Сообщения партнёру (вебхуки)».
Ссылки на страницу оплаты API не отдаёт.
Какие заказы видит ключ
GET /orders отдаёт все заказы вашего контакта, откуда бы они ни пришли:
переданные через API, оформленные менеджером по телефону, купленные вами на
витрине. Откуда пришёл заказ, показывает поле channel. Чужих заказов для
ключа нет: запрос чужого заказа получает 404, как запрос несуществующего.
Если у вашего контакта несколько ключей, каждый видит все заказы контакта. Если владелец привяжет ключ к другому контакту, прежний ключ сразу перестанет работать и будет получать 401. Новый ключ, который магазин выдаст вместо него, видит только заказы нового контакта.
Изменения удобно забирать параметром updated_since: он отдаёт заказы,
изменённые с указанного времени. Время изменения заказа сдвигается при смене
статуса, при оплате, при правке состава, сумм, адреса или доставки в панели.
Поэтому заказ, которому менеджер назначил доставку, оплату или получателя,
попадёт в такой ответ. Чтобы не спрашивать об изменениях постоянно, попросите
владельца включить сообщения о заказах. Тогда магазин сам сообщит, что у заказа
сменился статус или менеджер его изменил. Как это работает, описано на
странице «Сообщения партнёру (вебхуки)».
Заказы в панели магазина
В панели магазина заказы из API видны в канале продаж «API: название ключа», например «API: Сайт партнёра». Если ключ удалят, подпись канала сохранится. Заказчиком в заказе стоит контакт ключа. Доставку, оплату и получателя менеджер заполняет в самом заказе.
Запросы POST /orders и POST /orders/check, которые закончились ошибкой,
магазин хранит в журнале запросов вместе с телом длиной до 64 000 знаков. По
коду из request_id владелец найдёт ваш запрос целиком и увидит, что вы
прислали. Подробнее на странице «Журнал запросов».
Полный цикл на примере
Дропшиппер получил заказ №A-1024 на своём сайте: две баночки крема. Номера
товара (1045) и артикула (2108) он заранее взял из /products. Скидок на этот
товар в магазине нет, поэтому итог равен сумме товаров.
1. Проверка.
curl https://shop.example.ua/api/v1/orders/check \
-X POST \
-H "Authorization: Bearer <ключ>" \
-H "Content-Type: application/json" \
-d '{
"external_id": "A-1024",
"items": [{ "product_id": 1045, "sku_id": 2108, "qty": "2" }],
"comment": "Упакуйте подарком"
}'
В ответе can_place: true и итог "totals": { "total": "416.64", … }.
Полный ответ приведён в описании адреса
POST /orders/check.
2. Создание. То же тело уходит в /orders с ключом повтора и ожидаемым
итогом:
curl https://shop.example.ua/api/v1/orders \
-X POST \
-H "Authorization: Bearer <ключ>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: drop-A-1024" \
-d '{ "external_id": "A-1024", "expected_total": "416.64", "items": [{ "product_id": 1045, "sku_id": 2108, "qty": "2" }], "comment": "Упакуйте подарком" }'
Магазин отвечает 201 Created, в заголовке Location адрес заказа
https://shop.example.ua/api/v1/orders/5120, в теле заказ целиком.
3. Повтор. Ответ не дошёл, и программа отправляет тот же запрос ещё раз с
тем же Idempotency-Key: drop-A-1024. Магазин отвечает 201 тем же заказом
№5120 и заголовком Idempotent-Replayed: true. Второго заказа нет.
Если бы программа по ошибке сгенерировала новый ключ повтора, магазин ответил
бы 409 external_id_taken с "order_id": 5120: номер A-1024 уже занят.
4. Отслеживание. Раз в несколько минут программа забирает изменённые заказы:
curl "https://shop.example.ua/api/v1/orders?updated_since=2026-10-19T08:00:00Z&after_id=0&limit=100" \
-H "Authorization: Bearer <ключ>"
Когда менеджер назначит доставку, у заказа №5120 появится shipping, а итог
вырастет на её стоимость. Когда посылку отправят, сменится status, а в
shipping.waybill_number появится номер накладной.
Чего нет
- Доставки, оплаты, получателя и промокода в запросе: их назначает менеджер.
- Ссылки на страницу оплаты.
- Своей цены позиции: цену всегда считает магазин.
- Поиска товара по коду артикула или штрихкоду в заказе: только номера.
- Упаковок и услуг в позициях.
- Выбора подарка: подарки по акции магазин кладёт сам.
- Списания бонусов.
- Правки и отмены заказа через API. Чтобы изменить или отменить заказ, свяжитесь с магазином.