Для разработчиков · API v1 · контракт 1.2
Подключите вашу CRM
и бухгалтерию к ELPOS
Единый интерфейс к контрагентам, товарам, складу и документам Odoo. Штатные права доступа и защита от дублей при повторных запросах.
Это документация опубликованного контракта. Доступ к API на вашем сервере требует отдельного подключения. Публикация этой страницы не означает установку API в demo. Здесь не нужно вводить ключи доступа.
Что доступно сейчас
Девять групп справочников и документов, полностью оплаченные продажи через /sales и маршрутная доставка с долгом через /delivery. Обычные маршруты создания документов сохраняют черновики; проведение выполняется отдельными описанными процессами.
| Ресурс | Чтение | Создание |
|---|---|---|
| contacts | Контрагенты | Новый контрагент |
| products | Товары, цены, единицы измерения | — |
| stock | Остатки и резерв по внутренним местам хранения | — |
| leads | Сделки CRM | Новая сделка |
| sale-orders | Заказы продаж | Коммерческое предложение |
| purchase-orders | Заказы закупок | Запрос предложения поставщику |
| invoices | Счета и возвратные документы | Черновик счёта покупателю или поставщику |
| payments | Бухгалтерские платежи | — |
| pos-orders | Продажи кассы, строки и оплаты POS | — |
Отдельный маршрут POST /sales позволяет интегратору выбрать кассовую продажу или подтверждённый заказ со счётом и оплатой. Требуется обновлённое подключение API с правами sales:read,sales:write. Регистрация оплаты не означает подтверждение списания банком или готовность фискального чека.
Оплаты POS вложены в кассовые заказы и не обязательно представлены отдельными бухгалтерскими платежами. Не суммируйте эти выгрузки как независимую выручку.
Как подключиться
- Уточните у администратора адрес сервера ELPOS, на котором включён API. Базовый путь:
/api/elpos/v1. Для внешнего доступа используйте HTTPS. - Администратор создаёт отдельного внутреннего пользователя с нужными ролями Odoo, затем подключение в Настройки → External business API: компания, пользователь и права по ресурсам. Пользователь подключения не должен быть администратором настроек.
- Получите отдельный ключ для вашей системы и сохраните его в защищённых настройках вашего сервера. Ключ показывается один раз; в ELPOS хранится его хеш.
- На своём сервере откройте
/api/elpos/v1/docs, нажмите Authorize и проверьтеGET /ping. На публичном Swagger доступны только просмотр схем и примеров. - Проверьте обмен на тестовой базе, затем выдайте рабочему подключению минимально необходимые права.
Права задаются отдельно: например, contacts:read, sale-orders:write. Они не расширяют штатные права пользователя. Каждое подключение ограничено одной компанией; общие товары и контакты доступны только согласно штатным правилам.
Архивация подключения или смена ключа прекращает прежний доступ. Ключ не размещают в браузерном коде, URL или мобильной сборке. Запросы выполняет сервер внешней системы; CORS не поддерживается.
Реальная продажа: выбор интегратора
В POST /api/elpos/v1/sales передайте mode: "pos" либо mode: "sale". Это отдельный маршрут: прежний POST /sale-orders по-прежнему создаёт коммерческое предложение.
| Режим | Что создаётся | Что передать |
|---|---|---|
pos | Оплаченный кассовый заказ и оплаты POS в указанной открытой смене. | config_id, session_id, товары и оплаты с payment_method_id. |
sale | Подтверждённый заказ продажи, проведённый счёт покупателю и штатные платежи, сверенные со счётом. | partner_id, товары и оплаты с journal_id, payment_method_line_id. |
Получить способы оплаты
GET /sales-options?mode=pos показывает кассы, открытые смены и способы оплаты. GET /sales-options?mode=sale — журналы кассы/банка и входящие способы оплаты. Используйте ID из ответа: одного названия «карта» недостаточно. Поддерживаются limit и after_id. Для POS выбирайте кассу с supported: true. Если payment_methods_truncated: true, список способов оплаты неполон — уточните настройку у администратора.
Пример для кассы
Пример рассчитан на итог 200 в валюте кассы. Все ID и суммы замените данными вашей базы; итог с налогами проверяет Odoo.
{
"mode": "pos",
"config_id": 10,
"session_id": 12,
"reference": "CRM-1007",
"lines": [{"product_id": 20, "quantity": 2, "price_unit": 100}],
"payments": [{"payment_method_id": 5, "amount": 200}],
"expected_total": 200
}Пример для раздела «Продажи»
{
"mode": "sale",
"partner_id": 42,
"reference": "CRM-1008",
"lines": [{"product_id": 20, "quantity": 2, "price_unit": 100}],
"payments": [{"journal_id": 4, "payment_method_line_id": 6, "amount": 200}],
"expected_total": 200
}Для каждого запроса нужны Bearer-ключ и свой Idempotency-Key. Передавайте прежний ключ и тело при повторе после таймаута. Можно разделить оплату на несколько ручных способов; сумма должна точно совпадать с итогом.
Что означает успешный ответ
record — неизменяемый результат создания. current — актуальные состояния заказа, счёта, платежей, задолженности и складских документов. Повтор POST возвращает тот же record и свежий current. Также доступен GET /sales/{mode}/{id} для продаж этого подключения.
API регистрирует заявленную ручную оплату: provider_verified: false. Он не списывает деньги через банк или эквайера. У счёта может быть нулевая задолженность и состояние in_payment до банковской сверки. Проверяйте валюту каждой оплаты и флаги усечения в ответе.
В режиме sale складская отгрузка проходит обычным процессом Odoo и автоматически не подтверждается. В POS расход зависит от настройки кассы — сразу или при закрытии смены. Оплаченный заказ не доказывает отгрузку.
Если в кассе подключена поддерживаемая фискализация, действует штатная очередь. Смотрите current.fiscal: ожидание или ошибка не означают готовый фискальный чек. В режиме sale кассовая фискализация этим маршрутом не выполняется.
Границы маршрута /sales
- До 100 строк и 20 оплат, только положительная продажа с полной оплатой. Частичная оплата, долг, сдача, переплата и возвраты не поддерживаются.
- Только настроенные ручные способы кассы/банка. Терминальные и онлайн-способы оплаты не принимаются; подтвердить оплату у провайдера этим запросом нельзя.
- Обычные товары без партий, серий, наборов и бонусов. Для
sale— выставление счёта по заказанному количеству, настроенный ручной входящий платёж и счёт ожидаемых поступлений; валюта журнала совпадает с заказом. - Кассовый режим пока не поддерживает конфигурации с входом сотрудников по PIN, рестораном, пресетами и округлением наличных. Касса и смена проверяются повторно при записи.
- Штатные роли пользователя обязательны. Если API вернул ошибку, вся операция откатывается; дубликат не создаётся при повторе с тем же ключом.
Доставка с долгом: ELCRM → ElJet → ElPOS
Контракт 1.2 проверен на изолированном стенде. Документация не означает установку модуля на рабочие серверы. Автоматический выпуск фискальных чеков доставки в адаптере пока не реализован; импорт внешних реквизитов описан отдельно.
Для маршрутной доставки используется раздел «Продажи»: принятый товар отражается в складе и счёте покупателю независимо от оплаты. Новые методы находятся под /api/elpos/v1/delivery. Не вызывайте дополнительно /sales для той же доставки.
| Операция | Метод после /delivery | Результат |
|---|---|---|
| План заказа | POST /orders | Подтверждённый заказ с исходными строками и ценами. |
| Рейс и погрузка | POST /tripsPOST /trips/{external_id}/loads | Фактическая передача склад → водитель. |
| Доставка | POST /delivery-results | Только принятый товар: водитель → клиент и проведённый счёт. Оплата необязательна. |
| Доплата | POST /payments | Оплата существующего счёта без нового заказа и расхода товара. |
| Непринятые остатки | POST /trips/{external_id}/stock-returns | Фактический возврат водитель → склад, без кредит-ноты. |
| Закрытие рейса | POST /trips/{external_id}/close | Только при нулевых остатках; автоматического обнуления нет. |
| Возврат после продажи | POST /returns | Обратное движение и кредит-нота исходного счёта. |
| Выплата клиенту | POST /refunds | Отдельная регистрация возврата денег. |
| Внешний чек | POST /fiscal-receipts | Реквизиты EKASSA от ELCRM без повторного вызова ККМ. |
| Восстановление связи | GET /lookup | По внешнему ID и виду, event_id либо idempotency_key. |
До первого проведения настройте счета, журналы и ручные способы оплаты. Для компании Кыргызстана заполните профиль учёта: правовую форму, налоговый режим и статус НДС; одного выбора страны и валюты недостаточно.
Пример задолженности
Доставлено на 1 000 сом без оплаты → долг 1 000. Затем 400 наличными → долг 600. Подтверждённые ELCRM 600 через банк → долг 0. ElPOS регистрирует оплату, не списывая деньги у эквайера.
Загружено 10 единиц, клиент принял 8: расход клиенту равен 8, у водителя остаются 2. Возврат двух непринятых единиц на склад не создаёт новую продажу. Возврат уже принятого товара сначала уменьшает долг или создаёт кредит клиента; выплата оформляется отдельно.
Повторы и состояния
Каждый POST получает Idempotency-Key, event_id и external_id. Сохраняйте тело до отправки. После таймаута ищите операцию и повторяйте прежний запрос. Идентичность доставки сохраняется при смене ключа доступа. Изменённое содержание под прежним ID даёт конфликт.
current.settlement отделяет выставленную сумму, кредит-ноты, реальные оплаты, возвраты денег, долг и кредит клиента. payment_status, refund_status, складские документы и current.fiscal возвращаются отдельно. Сумма исходного заказа не подменяет сумму частичной доставки.
item_id ElJet — UUID строки заказа. Для товара нужно проверенное сопоставление с вариантом product.product, а не шаблоном. Проведённая история старых заказов автоматически не мигрирует.
Семь сценариев доставки и оплаты: примеры JSON
Фискальная граница и ограничения
Владелец фискализации — ELCRM. Переданный чек получает reported_by_elcrm и independently_verified: false: это сохранённые внешние реквизиты, а не самостоятельная проверка EKASSA. Повторная фискальная очередь ElPOS не создаётся. Накладная Xprinter — нефискальный документ.
Первый выпуск ограничен одношаговым складом, обычными товарами без партий/серий, базовой единицей и валютой компании. Переплата, валютная конвертация и распределение оплаты между разными заказами не поддерживаются. Новые операции API и готовность водительских экранов проверяются отдельно.
Выгрузка для бухгалтерии — дополнение 1.3
Подготовлены дополнительные маршруты чтения: прайс-листы и правила цен, план счетов, журналы и проводки, аналитика, техническая оборотно-сальдовая ведомость, движения склада и корректировки оценки, кассовые смены и движения наличных, сверка и текущий долг клиента. Доступ определяется правами подключения и штатного пользователя одной компании.
Клиенты есть и в POS: /contacts/{id}/pos-orders показывает кассовые покупки выбранного клиента, включая возвраты. Связанный бухгалтерский документ может быть индивидуальным счётом или общей проводкой смены. Не складывайте оборот POS и счета повторно; задолженность рассчитывается по проведённым проводкам. Продажи без выбранного клиента не включаются в его историю.
/contacts/{id}/ledger и /customer-balances отделяют долг от кредита клиента. Текущий остаток не означает восстановленный долг на прошлую дату. /trial-balance показывает начальное сальдо и обороты в валюте компании по проведённым записям без условного закрытия года.
Оценка stock.move и корректировки product.value отражают штатную модель Odoo20. Если ELPOS сохранил снимок закрытия смены, API выдаёт ожидаемую сумму, пересчитанную наличность и расхождение. Для старых смен без снимка неизвестное расхождение передаётся явно, без подмены нулём.
Фильтрация по клиенту использует точный partner_id. Установка версии 1.3 на сервер конкретной компании проверяется отдельно; опубликованная документация не подтверждает развёртывание.
Пример создания черновика
POST /api/elpos/v1/sale-orders создаёт коммерческое предложение. Замените ID контрагента и товара значениями из вашей базы.
Authorization: Bearer <ключ>
Content-Type: application/json
Idempotency-Key: crm-order-1007
{
"partner_id": 42,
"client_order_ref": "CRM-1007",
"lines": [{"product_id": 65, "quantity": 2}]
}Без переопределения цены и налоги рассчитывает Odoo. Первый успешный запрос возвращает 201, повтор того же запроса — 200 с replayed: true.
Если связь оборвалась
До отправки сохраните тело и уникальный Idempotency-Key. После таймаута повторите тот же ключ и то же тело. Новый ключ может создать новый документ. Изменённое тело или другой маршрут с прежним ключом возвращают 409.
Повтор возвращает сохранённый результат создания после проверки текущих прав. Чтобы узнать сегодняшнее состояние документа, выполните GET по его ID.
Синхронизация и ограничения
- Списки:
limitдо 100, курсорafter_id. Передавайтеnext_after_idследующему запросу, пока он не станетnull. updated_sinceфильтрует дату изменения родительской записи в UTC. Это не полноценная очередь изменений: изменения строк и удаления требуют периодической полной сверки.- Архивные контакты, товары и лиды возвращаются с
active: false. Для создания документов нужны активные записи. - В документе возвращается до 100 строк, в заказе POS — также до 100 оплат. Для полной выгрузки используйте
/{ресурс}/{id}/lines; оплаты POS —/pos-orders/{id}/payments. Переходите поnext_after_idдоnull. Старые встроенные списки остаются ограниченными для совместимости. - Тело запроса — до 64 КиБ. Сохраняйте соответствия ID внешней системы и Odoo.
- Webhooks, произвольное редактирование, удаление и готовые адаптеры ко всем CRM/1С в эту версию не входят. Проведение поддерживается в явно описанных процессах
/salesи/delivery; у каждого свои условия и ограничения.
Ошибки
401 — ключ недействителен; 403 — недостаточно прав; 404 — запись не найдена или недоступна; 409 — конфликт ключа повтора; 422 — неверные данные; 500 — внутренняя ошибка. Формат: {"error":{"code":"…","message":"…"}}.
Контракт и проверка
Спецификация OpenAPI 3.0.3 содержит поля, обязательные параметры, ответы и примеры. Интерфейс Swagger загружается с этого сайта, без внешнего CDN и валидатора.
Пройдены изолированные проверки HTTP, прав, компаний, конкурентных повторов и соответствия ответов OpenAPI. Подключение конкретной внешней системы проверяется отдельно.