Помощь кассиру

Оповещения о чеках

с версии 400

После каждого пробитого чека касса отправляет его вашей программе одним HTTP-запросом.

Работает с версии кассы 2.2.09.400. Касса сама подключается к вашей программе, поэтому они должны быть в одной сети, а порт программы открыт в брандмауэре. Регистрировать программу на сервере не нужно. Для проб подойдёт демо-касса: она шлёт те же оповещения.

Включение на кассе

  1. Настройки → Обмен → Отправлять чеки во внешнюю программу.
  2. В поле IP программы, можно с портом укажите адрес: 192.168.1.10, 192.168.1.10:8080 или целиком http://host:порт. Путь /yakassa/check касса добавит сама.
  3. Нажмите Тест : проверить связь с программой. Касса отправит событие ping и покажет итог.
  4. Итог по каждому чеку виден в журнале на экране кассы: Настройки → Системные функции → Показать логи.

Запрос

POST/yakassa/checkв вашу программу
ПараметрЗначение
ЗаголовокContent-Type: application/json; charset=utf-8
ТелоJSON в UTF-8, поля со значением null не передаются
Авторизациянет
Успехлюбой ответ 2xx, тело ответа касса не читает
Таймаутысоединение 3 секунды, отправка и ответ 5 секунд
Повторынет, одна попытка на чек
Порядокпо одному, в порядке пробития

Отправляется каждый чек после фискализации: продажа, возврат продажи, покупка, возврат покупки, и пробитый кассиром, и пришедший обменом.

Не отправляются операции со сменой, внесение и изъятие, оплата без чека, повторная печать.

Отправка идёт после того, как чек уже пробит, и на него не влияет. Если программа выключена, касса работает как обычно, а этот чек программа уже не получит.

Тело запроса

ПолеТипЧто это
eventStringreceipt чек пробит, ping кнопка «Тест»
kkmCodeStringлицевой счёт кассы. Сразу после установки может не прийти, различать кассы надёжнее по result.kkmID
sourceStringоткуда чек, см. ниже
resultObjectфискальные реквизиты, суммы в сомах
receiptObjectсам чек, суммы в тыйынах
sourceОткуда чек
TERMINALкассир на экране кассы
TCPдокумент пришёл по TCP
HTTPдокумент пришёл через сервер
STATIC_QRоплата статическим QR: документ сделал сервер YaKassa. Эту метку ставит только сервер
INTENTдругое приложение на этом же устройстве

Событие ping приходит на тот же адрес, в нём нет чека. Просто ответьте 2xx.

JSON
{ "event": "ping", "kkmCode": "123456789" }

Если вы сами шлёте чеки на кассу, оповещение придёт и по ним: result.id совпадёт с id вашего документа.

Блок result

Тот же формат, что ответ на статус документа.

ПолеТипЧто это
idStringid чека. Ключ для защиты от дублей
statusStringвсегда OK
fdNumberStringномер фискального документа
fpdStringфискальный признак
shiftNumberStringномер смены
receiptNumberStringномер чека внутри смены
gnsDateStringдата и время, ГГГГММДДTччммсс, местное время кассы
qrStringссылка на проверку в ГНС
rnKKM, fnKKMStringрегистрационный номер и номер фискального модуля
kkmIDStringid кассы на сервере
amountNumberсумма чека, сом
cashlessBooleantrue: часть или вся сумма оплачена безналом
printObjectреквизиты печатного чека, см. печатные поля. Кроме них operation и title

Блок receipt

Тело чека, как оно ушло на фискализацию. Все суммы в тыйынах: 1 сом = 100 тыйын.

ПолеТипЧто это
uuidStringid чека, равен result.id
sourceStringто же, что source наверху
operationStringINCOME, INCOME_RETURN, EXPENDITURE, EXPENDITURE_RETURN
totalSumIntegerсумма чека: 12500 это 125 сом
totalCashSumIntegerоплачено наличными
totalCashlessSumIntegerоплачено безналом
goodsArrayпозиции чека
taxSumsArrayналоги: type VAT или ST, code код ставки, sum сумма
taxSystemIntegerкод системы налогообложения, словами в result.print.sno
fdNumber, shiftNumber, fnNumberStringФД, смена, ФМ
kkmID, tinStringid кассы и ИНН
sellTypeStringрежим продаж: SIMPLE, PRODUCTS2, CURRENCY2
rrnStringRRN банковской операции, если была карта
originFdNumber, originFnSerialNumberNumber, StringФД и ФМ чека-основания, только у возврата

Поля позиции goods[]:

ПолеТипЧто это
nameStringнаименование
priceNumberцена за единицу, тыйын
quantityNumberколичество, может быть дробным
costIntegerстоимость позиции, округлена до тыйына
vat, stStringкоды ставок НДС и НСП
categoryStringсекция, если задана
calcItemAttributeCodeString0 товар, 1 услуга
sgtinStringкод маркировки, чаще пустой
taxSumsArrayналоги по позиции, только когда в чеке есть секции

Поля, которых нет в таблицах, служебные: не опирайтесь на них.

Пример

Чек на 125 сом наличными на демо-кассе. Порядок полей может отличаться.

JSON
{
  "event": "receipt",
  "kkmCode": "123456789",
  "source": "TERMINAL",
  "result": {
    "id": "8b9aecaf-5e80-4d78-a9d4-361eebed0ec2",
    "status": "OK",
    "amount": 125.0,
    "cashless": false,
    "fdNumber": "7584",
    "fpd": "97834247394950",
    "shiftNumber": "677",
    "receiptNumber": "1",
    "gnsDate": "20261102T055817",
    "qr": "https://…/ticket?date=20261102T055817&type=3&…&sum=12500",
    "rnKKM": "0000000000000000",
    "fnKKM": "0000000000000000",
    "kkmID": "65f1234567890abcdef12345",
    "print": {
      "title": "ДЕМО -> НЕ ФИСКАЛЬНЫЙ",
      "operation": "Продажа",
      "storeName": "Магазин",
      "companyName": "ОсОО Ромашка",
      "tin": "00000000000000",
      "address": "720000, Бишкек",
      "sno": "Общий налоговый режим",
      "receiptNumber": "1"
    }
  },
  "receipt": {
    "uuid": "8b9aecaf-5e80-4d78-a9d4-361eebed0ec2",
    "source": "TERMINAL",
    "operation": "INCOME",
    "sellType": "SIMPLE",
    "totalSum": 12500,
    "totalCashSum": 12500,
    "totalCashlessSum": 0,
    "fdNumber": "7584",
    "fnNumber": "0000000000000000",
    "shiftNumber": "677",
    "kkmID": "65f1234567890abcdef12345",
    "tin": "00000000000000",
    "taxSystem": 0,
    "taxSums": [ { "code": "0", "sum": 0, "type": "VAT" }, { "code": "0", "sum": 0, "type": "ST" } ],
    "goods": [
      { "name": "Товар", "price": 12500, "quantity": 1, "cost": 12500, "vat": "0", "st": "0",
        "category": "Секция 1", "calcItemAttributeCode": "0", "sgtin": "" }
    ]
  }
}

Как написать приёмник

Python
import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer


class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path != "/yakassa/check":
            self.send_response(404)
            self.end_headers()
            return
        length = int(self.headers.get("Content-Length") or 0)
        body = json.loads(self.rfile.read(length).decode("utf-8"))
        if body.get("event") == "receipt":
            r = body["result"]
            print(r["kkmID"], r["id"], "ФД", r["fdNumber"], r["amount"], "сом")
            # здесь запись в свою очередь, тяжёлая работа после ответа
        self.send_response(200)
        self.end_headers()


ThreadingHTTPServer(("0.0.0.0", 8095), Handler).serve_forever()

Проверить приёмник без кассы:

Командная строка
curl -X POST http://localhost:8095/yakassa/check \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{ "event": "ping", "kkmCode": "123456789" }'

Смотрите также