Документация

Заказы дропшиппера со своего сайта

Ключ из кабинета дропшиппера, получатель, отделение, схема расчёта, оплата и цена продажи в теле заказа, ответы, причины отказа и сообщения о заказах.

На этой странице

Эта страница для программиста сайта дропшиппера. Дропшиппер работает с магазином по программе плагина «Дропшиппинг». Он продаёт товары магазина своим покупателям, а посылки им отправляет магазин. Свои заказы он может оформлять не только в кабинете на сайте магазина, но и прямо со своего сайта через API. Как программа устроена для магазина, описано на странице «Дропшиппинг».

Ключ дропшиппера принимает более широкое тело заказа, чем ключ обычного партнёра. Кроме товаров и комментария, сайт передаёт получателя, доставку в отделение или почтомат, схему расчёта, оплату и свою цену продажи. Заказ сразу приходит к менеджеру готовым к отправке, а деньги по нему магазин считает так же, как по заказу из кабинета дропшиппера.

Адреса, ключ повтора Idempotency-Key, номер external_id, общие коды ошибок и поля заказа работают так же, как у обычного партнёра. Они описаны на страницах «Заказы партнёра» и «Заказы: адреса и поля».

Ключ

Ключ дропшиппер выдаёт себе сам. В кабинете на сайте магазина (/dropship) он открывает раздел «Подключения» и нажимает «Выдать ключ». Кнопка доступна, когда магазин одобрил заявку дропшиппера. Магазин показывает ключ один раз, поэтому скопируйте его сразу. Там же стоит «Адрес API» магазина, например https://shop.example.ua/api/v1.

Права ключа дропшиппер не выбирает. Магазин выдаёт ключ с этими правами, а владелец магазина может их сузить или ограничить срок ключа. Если ключ выдать заново, права и срок, которые задал владелец, сохраняются.

Право Что открывает
shop:read справочники магазина, в том числе способы доставки и оплаты
catalog:read товары, категории и характеристики
prices:read цены дропшиппера
inventory:read остатки
orders:read заказы дропшиппера, в том числе оформленные в кабинете
orders:create проверка и создание заказа

Кнопка «Выдать ключ заново» выпускает новый ключ, и прежний перестаёт работать сразу. Кнопка «Отозвать ключ» выключает его, и позже ключ можно выдать снова. Владелец магазина видит ключ в своей панели под именем «Дропшиппер: имя» и тоже может его отозвать. Ключ, который отозвал магазин, дропшиппер сам заново не выдаст. В разделе «Подключения» появится сообщение «Магазин отозвал ваш ключ. Чтобы подключить сайт снова, обратитесь к магазину.» Так же нельзя выдать ключ заново, если истёк срок, который задал владелец. В обоих случаях новый ключ выдаёт магазин. Если магазин закрыл работу с дропшиппером, ключ отзывается сам.

Такое же тело принимает любой ключ, привязанный к дропшипперу, в том числе ключ, который ему выдал владелец магазина. Пока заявка ждёт решения, а также когда работа приостановлена или закрыта, магазин отвечает на заказ отказом not_active.

Тело заказа

POST /api/v1/orders/check и POST /api/v1/orders принимают одно и то же тело. Сначала отправьте его на проверку, потом то же самое на создание.

{
    "external_id": "SITE-1024",
    "scheme": "a",
    "items": [
        { "product_id": 1045, "sku_id": 2108, "qty": "2", "sale_price": "1200" }
    ],
    "recipient": {
        "last_name": "Шевченко",
        "first_name": "Олена",
        "phone": "+380671234567"
    },
    "delivery": {
        "method_id": 3,
        "city": "Київ",
        "point_ref": "1ec09d88-e1c2-11e3-8c4a-0050568002cf",
        "point_type": "warehouse"
    },
    "payment": { "method_id": 1 },
    "comment": "Позвонить перед отправкой",
    "expected_total": "2470.00"
}

Поля тела

Поле Тип Нужно Что значит
items список да позиции заказа, как у обычного партнёра, плюс поле sale_price
recipient объект да получатель посылки, ваш покупатель. Описан ниже
delivery объект да доставка в отделение или почтомат. Описана ниже
scheme строка нет схема расчёта a или b. Описана ниже
payment объект нет оплата. Описана ниже
cod_amount строка или число нет сколько курьер возьмёт с покупателя, только в схеме b
external_id строка нет ваш номер заказа, до 64 знаков
expected_total строка или число нет итог, который вы ожидаете. Он включает доставку
comment строка нет комментарий для магазина, до 2000 знаков
storefront_id целое нет заказы дропшипперов принимает одна витрина, которую выбрал владелец. Поле можно не передавать, а если передать, то только номер этой витрины
locale строка нет язык заказа, один из языков этой витрины. Если не передать, берётся её основной язык

Пробелы по краям строк магазин отбрасывает. На поле, которого он не знает, приходит ошибка 422 validation_failed, как и у обычного партнёра.

Причины отказа и предупреждения приходят на языке запроса из заголовка Accept-Language. Сам заказ магазин записывает на языке из поля locale.

Получатель recipient

Поле Нужно Что значит
last_name да фамилия, до 190 знаков
first_name да имя, до 190 знаков
middle_name нет отчество, до 190 знаков
phone да телефон, до 32 знаков, например +380671234567

Магазин отправит посылку на имя этого человека. Заказчиком в заказе остаётся дропшиппер.

Доставка delivery

Поле Нужно Что значит
method_id да номер способа доставки, целое или строка из цифр
city да город отделения, до 190 знаков. Подходит украинское или русское название, например Київ или Киев
point_ref да код отделения или почтомата у перевозчика, до 64 знаков. Для «Нова Пошта» это Ref
point_type нет warehouse для отделения или postomat для почтомата. Если не передать, магазин ищет среди отделений

Магазин сам находит у способа доставки нужное поле и проверяет, что такое отделение есть в списке, который он посчитал для этого города и этой посылки. У «Нова Пошта» почтомат ищется только при "point_type": "postomat", среди отделений его нет. Доставки по адресу курьером через API нет.

Схема расчёта scheme

Значение Как считаются деньги
a покупатель платит магазину вашу цену продажи и доставку. Когда покупатель заберёт посылку, разница между ценой продажи и вашей ценой поступит вам на баланс
b вы платите магазину свою цену и доставку сами. Если курьер берёт деньги с покупателя (cod_amount), после выкупа эта сумма поступает вам на баланс

Если поле не передать, магазин выберет a, когда ваш уровень её разрешает, а иначе b. На схему, которой нет у вашего уровня, магазин ответит отказом scheme_not_allowed.

Цена продажи items[].sale_price. Только для схемы a. Это цена одной единицы для покупателя в валюте витрины, до двух знаков после точки. Если её не передать, товар продаётся по рекомендованной цене магазина, то есть по розничной. Она не может быть ниже вашей цены, иначе придёт отказ below_drop. Продавать ниже розничной можно. Заказ примут с предупреждением below_retail, и магазин эту отметку тоже увидит. Скидки корзины магазина к заказу не применяются.

В схеме b позиции идут по вашей цене, и sale_price передавать нельзя.

Оплата payment

Вид Что значит
{ "method_id": 1 } способ оплаты магазина. В схеме a так платит покупатель, например при получении. В схеме b так платите вы, а способы с оплатой при получении в этой схеме не принимаются
{ "balance": true } магазин спишет итог заказа с вашего баланса при оформлении. Только в схеме b

Поле можно не передавать, если для этого заказа у магазина подходит ровно один способ оплаты. Тогда магазин подставит его сам. Если подходящих способов несколько, будет отказ payment_required.

При оплате с баланса магазин не тратит деньги, на которые вы уже попросили выплату. Если их не хватает, будет отказ not_enough_balance. Если в схеме b вы выбрали обычный способ оплаты, ссылку на страницу оплаты API не отдаёт. Если у способа есть страница оплаты, оплатить заказ можно в кабинете кнопкой «Оплатить» в заказе.

Наложенный платёж cod_amount. Это сумма больше нуля, которую курьер возьмёт с покупателя, в валюте витрины, до двух знаков после точки. Поле работает только в схеме b. Если его не передать, курьер ничего с покупателя не берёт.

Где взять номера

  • Товар и артикул берутся из каталога /products или /skus, как у обычного партнёра. Ваши цены отдаёт /prices, остатки отдаёт /inventory.
  • Способ доставки и способ оплаты берутся из GET /api/v1/shipping_methods и GET /api/v1/payment_methods, поле id. Эти адреса отдают все способы магазина, а владелец может оставить дропшипперам только часть. Если способ вам недоступен или не возит посылку в город получателя, придёт отказ delivery_not_allowed.
  • Ref отделения или почтомата «Нова Пошта» берётся из справочника самой «Нова Пошта». Это поле Ref в ответе её метода Address.getWarehouses. Своего адреса со списком отделений у API магазина нет.

POST /api/v1/orders/check

Считает заказ, ничего не создавая. Право: orders:create. Ответ 200 приходит, даже когда заказ создать нельзя, поэтому смотрите на can_place и problems. Ошибки формы тела приходят ответом 422 validation_failed.

curl https://shop.example.ua/api/v1/orders/check \
  -X POST \
  -H "Authorization: Bearer <ключ>" \
  -H "Content-Type: application/json" \
  -d @order.json

Ответ на тело из примера выше. Розничная цена товара 1000 грн, скидка уровня 20%, доставка 70 грн:

{
    "data": {
        "can_place": true,
        "storefront_id": 1,
        "locale": "uk",
        "currency": "UAH",
        "rate": "1.000000",
        "base_currency": "UAH",
        "items": [
            {
                "index": 0,
                "product_id": 1045,
                "sku_id": 2108,
                "name": "Крем для рук 50 мл",
                "qty_requested": "2.000",
                "qty": "2.000",
                "price": "1200.00",
                "compare_price": null,
                "total": "2400.00",
                "is_gift": false,
                "problems": []
            }
        ],
        "discounts": [],
        "totals": {
            "items_total": "2400.00",
            "services_total": "0.00",
            "discount_total": "0.00",
            "shipping_total": "70.00",
            "total": "2470.00"
        },
        "problems": [],
        "extensions": {
            "dropshipping": {
                "scheme": "a",
                "shipping": { "method_id": 3, "option_id": "3:nova_poshta", "name": "Нова Пошта" },
                "currency": "UAH",
                "lines_currency": "UAH",
                "drop_total": "1600.00",
                "margin": "800.00",
                "balance": "350.00",
                "lines": [
                    { "sku_id": 2108, "sale_price": "1200.00", "drop_price": "800.00", "retail": "1000.00", "below_retail": false }
                ]
            }
        }
    }
}

От ответа обычного партнёра он отличается в нескольких местах.

  • В totals есть shipping_total, и total включает доставку. С этим итогом сравнивается expected_total.
  • price позиции в схеме a равна цене продажи, в схеме b вашей цене. compare_price здесь всегда null.
  • Скидок корзины в заказе дропшиппера нет, поэтому discounts пустой.
  • В extensions.dropshipping лежат ваши суммы.
Поле extensions.dropshipping Что значит
scheme схема, по которой посчитан заказ
shipping способ доставки, который магазин нашёл по method_id, с полями method_id, option_id и name. null, если доставку подобрать не удалось
currency основная валюта магазина. В ней приходят drop_total, margin и balance, как в вашем журнале денег
lines_currency валюта заказа. В ней приходят цены в lines
drop_total товары по вашей цене
margin ваша разница в схеме a. В схеме b всегда "0.00"
balance ваш баланс сейчас. Деньги, на которые вы уже попросили выплату, из него не вычтены
lines для каждой позиции sku_id, цена продажи sale_price, ваша цена drop_price, розничная цена retail и below_retail, продаёте ли вы дешевле розничной

POST /api/v1/orders

Создаёт заказ. Право: orders:create. Нужен заголовок Idempotency-Key, как у обычного партнёра.

curl https://shop.example.ua/api/v1/orders \
  -X POST \
  -H "Authorization: Bearer <ключ>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: site-SITE-1024" \
  -d @order.json

Ответ 201 Created с заказом целиком. Поля заказа описаны на странице «Заказы: адреса и поля». В отличие от обычного партнёра, у вашего заказа сразу заполнены recipient, shipping и payment, а доставка входит в итог. Канал заказа называется «Дропшиппер: имя».

{
    "data": {
        "id": 5120,
        "number": "#1005120",
        "external_id": "SITE-1024",
        "status": "new",
        "...": "все поля заказа",
        "extensions": {
            "dropshipping": {
                "scheme": "a",
                "state": "waiting",
                "source": "api",
                "external_id": "SITE-1024",
                "currency": "UAH",
                "buyer_total": "2470.00",
                "drop_total": "1600.00",
                "margin": "800.00",
                "from_balance": false,
                "below_retail": false,
                "returning": false,
                "returned_at": null,
                "supplier_fault": false
            }
        }
    },
    "warnings": []
}

Блок extensions.dropshipping приходит и в GET /orders и GET /orders/{id}, в том числе у заказов, которые вы оформили в кабинете. У обычных заказов поля extensions нет.

Поле Что значит
scheme схема расчёта, a или b
state что с вашими деньгами по заказу: waiting — ждёт выкупа, credited — выкуплен и деньги начислены, refused — покупатель отказался от посылки, canceled — отменён или деньги покупателю вернули
source откуда пришёл заказ, api с вашего сайта или cabinet из кабинета
external_id ваш номер заказа или null
currency основная валюта магазина. Все суммы блока в ней
buyer_total в схеме a сколько платит покупатель, в схеме b сколько курьер возьмёт с покупателя
drop_total товары по вашей цене
margin ваша разница в схеме a, в схеме b "0.00"
from_balance заказ оплачен с вашего баланса
below_retail вы продали дешевле розничной цены магазина
returning отказная посылка едет назад на склад, а деньги за товар ждут её возврата
returned_at когда отказная посылка вернулась на склад, или null
supplier_fault магазин признал отказ своей виной и ничего за него не удержал

Предупреждения

Заказ с предупреждением всё равно создаётся. Кроме предупреждения backorder, которое бывает и у обычного партнёра, у вас бывает below_retail.

code Поля Когда
below_retail sku_id, sale_price, retail и currency, валюта обеих цен. Это валюта заказа позиция продана дешевле розничной цены магазина. Текст: «Позиция продана дешевле розничной цены магазина. Заказ принят, магазин видит эту отметку.»

Ошибки

Сначала магазин проверяет поля, которые есть у любого партнёра, а потом ваши. Поэтому после исправления первой порции ошибок может прийти вторая.

422 validation_failed

Ошибки в ваших полях приходят все сразу. Ключ каждой ошибки — путь к полю, например recipient.phone.

Поле в errors Сообщение
recipient, delivery, recipient.last_name, recipient.first_name, recipient.phone, delivery.city, delivery.point_ref «Поле обязательно.»
recipient, delivery, payment, если передан не объект «Ожидается объект.»
recipient.nickname и другие лишние поля в объекте «Неизвестное поле. Допустимые: last_name, first_name, middle_name, phone.» со списком полей этого объекта
строка длиннее предела или не строка «Ожидается строка не длиннее 190 знаков.» с пределом поля
delivery.method_id «Ожидается номер способа доставки из /shipping_methods.»
delivery.point_type «point_type принимает warehouse (отделение) или postomat (почтомат).»
scheme «Укажите схему a или b.»
payment «Укажите method_id способа оплаты или balance: true.»
payment.balance «С баланса можно платить только в схеме b.»
cod_amount, если схема не b «cod_amount передают только в схеме b.»
items.N.sale_price, если схема не a «sale_price передают только в схеме a. В схеме b покупатель платит при получении сумму из cod_amount.»
cod_amount, items.N.sale_price с неверной суммой «Ожидается сумма больше нуля, до двух знаков после точки.»
storefront_id «Заказы дропшипперов принимает одна витрина магазина. Не передавайте storefront_id или передайте её номер.»
locale «Язык заказа — один из языков витрины: uk, ru.» со списком языков витрины

422 cannot_place

Заказ собрать нельзя. Причины приходят списком problems, у каждой есть field, code и message. Проверяйте в программе code, потому что текст может меняться. В ответе /orders/check причины стоят в problems, а причины позиций ещё и в problems самой позиции.

Проверка называет те же причины, что и создание заказа, в том числе схему, способ оплаты, деньги на балансе и обязательные поля способа доставки. Если есть хоть одна причина, в ответе стоит "can_place": false. Деньги на балансе проверка сверяет с суммой, на которую вы ещё не попросили выплату, а окончательно магазин проверяет их при списании.

Коды причин у ключа дропшиппера свои и отличаются от кодов обычного партнёра.

code field Когда
not_active partner магазин ещё не одобрил заявку, приостановил или закрыл работу с вами
scheme_not_allowed scheme этой схемы нет у вашего уровня
external_id_taken external_id только в ответе /orders/check: у вас уже есть заказ с этим номером, в том числе оформленный в кабинете
not_found items.N товара нет в каталоге, он не опубликован или артикул относится к другому товару
not_for_sale items.N артикул сейчас не продаётся
out_of_stock items.N на складе меньше, чем в заказе. Сколько есть, сказано в тексте
qty_not_allowed items.N количество меньше минимального или не кратно шагу. Минимум и шаг сказаны в тексте
below_drop items.N.sale_price цена продажи ниже вашей цены
delivery_not_allowed delivery.method_id способа с таким номером нет среди доступных вам или он не возит эту посылку в этот город
point_not_found delivery.point_ref отделения с таким кодом нет в этом городе среди отделений или почтоматов способа
field_required delivery.city или delivery.point_ref у способа доставки осталось незаполненным обязательное поле. Его название сказано в тексте
shipping_required, shipping_not_allowed delivery.method_id доставку подобрать не удалось или она недоступна дропшипперам
payment_required payment оплату не передали, а подходящих способов больше одного или нет ни одного
payment_not_allowed payment этот способ оплаты недоступен дропшипперам или не подходит схеме
not_enough_balance payment на балансе не хватает денег. Сколько есть и сколько нужно, сказано в тексте
stock_reserve_failed items бывает только при создании, если пока заказ оформлялся, часть товара закончилась. В поле products для каждого артикула sku_id, name и short_qty
invalid поле, к которому относится отказ бывает только при создании, если магазин не принял заказ по другой причине. Причина названа в тексте
{
    "type": "https://cartixx.com/docs/api/errors#cannot-place",
    "title": "Данные не прошли проверку",
    "status": 422,
    "detail": "Заказ не создан. Причины перечислены в поле problems.",
    "code": "cannot_place",
    "request_id": "P8W3NB2Z",
    "problems": [
        {
            "field": "delivery.point_ref",
            "code": "point_not_found",
            "message": "У этого способа доставки нет отделения 1ec09d88-e1c2-11e3-8c4a-0050568002cf в городе «Львів». Проверьте Ref и point_type."
        }
    ]
}

При создании отказ point_not_found или delivery_not_allowed приходит один, без других причин, потому что без доставки остальное магазин не проверяет. Проверка /orders/check называет его вместе с остальными причинами, но не дублирует его причинами по полям delivery.

409 total_mismatch

Если вы передали expected_total, а итог магазина с доставкой другой, заказ не создаётся. Ответ тот же, что у обычного партнёра, итог магазина в поле actual_total. В ответе /orders/check расхождение приходит причиной total_mismatch в problems.

Номер заказа и повтор

Если external_id уже занят вашим заказом, переданным через API или оформленным в кабинете, ответ будет 409 external_id_taken с номером этого заказа в order_id, как у обычного партнёра. Проверка /orders/check сообщает о таком номере причиной external_id_taken в problems.

Повтор с тем же Idempotency-Key и тем же телом возвращает уже созданный заказ и ничего не списывает с баланса второй раз. Подробнее на странице «Заказы партнёра».

503 order_unavailable

Если магазин в эту минуту не может определить, по каким правилам принимать заказ с вашим ключом, он отвечает 503 order_unavailable и заказ не создаёт. В поле reference приходит код обращения. Повторите запрос позже с тем же Idempotency-Key. Если ответ повторяется, сообщите магазину этот код.

Сообщения о заказах

Чтобы не опрашивать магазин, включите сообщения в разделе «Подключения» кабинета, в блоке «Сообщения на сайт». Укажите «Адрес сайта для сообщений», отметьте события и включите «Отправлять сообщения». Там же лежат «Секрет подписи», кнопка «Отправить проверку» и журнал отправок.

Событие в кабинете type сообщения
«Сменился статус заказа» order.status_changed
«Заказ изменился» order.updated, в том числе когда появился или сменился номер накладной. Тогда в changed есть waybill
«Изменились цены» prices.changed
«Изменились остатки» inventory.changed

Получив сообщение о заказе, запросите его через GET /orders/{id}. В ответе будут новый статус, shipping.waybill_number и блок extensions.dropshipping. Вид сообщений, подпись и повторы описаны на странице «Сообщения партнёру (вебхуки)», проверка подписи — в разделе «Проверка подписи».

Пример на PHP

Сайт сначала проверяет заказ, а потом создаёт его с ожидаемым итогом и ключом повтора. Номер заказа на сайте служит и external_id, и основой ключа повтора.

function cartixPost(string $path, array $body, string $key, ?string $idempotency = null): array
{
    $headers = [
        'Authorization: Bearer '.$key,
        'Content-Type: application/json',
        'Accept: application/json',
    ];

    if ($idempotency !== null) {
        $headers[] = 'Idempotency-Key: '.$idempotency;
    }

    $ch = curl_init('https://shop.example.ua/api/v1/'.$path);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_POSTFIELDS => json_encode($body, JSON_UNESCAPED_UNICODE),
    ]);
    $response = json_decode(curl_exec($ch), true);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    return [$status, $response];
}

$key = getenv('CARTIX_KEY');
$order = [
    'external_id' => 'SITE-1024',
    'items' => [['product_id' => 1045, 'sku_id' => 2108, 'qty' => '2', 'sale_price' => '1200']],
    'recipient' => ['last_name' => 'Шевченко', 'first_name' => 'Олена', 'phone' => '+380671234567'],
    'delivery' => ['method_id' => 3, 'city' => 'Київ', 'point_ref' => '1ec09d88-e1c2-11e3-8c4a-0050568002cf'],
    'payment' => ['method_id' => 1],
];

[$status, $check] = cartixPost('orders/check', $order, $key);

if ($status !== 200 || ! $check['data']['can_place']) {
    // Ошибки формы — в $check['errors'], причины отказа — в problems
    throw new RuntimeException(json_encode($check['errors'] ?? $check['data']['problems'], JSON_UNESCAPED_UNICODE));
}

$order['expected_total'] = $check['data']['totals']['total'];
[$status, $created] = cartixPost('orders', $order, $key, 'site-'.$order['external_id']);

if ($status === 201) {
    $orderId = $created['data']['id'];
} elseif ($status === 409 && $created['code'] === 'external_id_taken') {
    $orderId = $created['order_id']; // заказ уже принят раньше
} else {
    throw new RuntimeException("{$created['code']}: {$created['detail']} (request_id {$created['request_id']})");
}

Чего нет

  • Доставки курьером по адресу. Принимается только отделение или почтомат.
  • Скидок корзины и промокодов в заказе дропшиппера.
  • Ссылки на страницу оплаты в ответах API.
  • Правки и отмены заказа через API. Чтобы изменить или отменить заказ, свяжитесь с магазином.
  • Списка отделений перевозчика в API магазина.
Обновлено 25 октября 2026