Первый чек за пять минут
Включаем обмен на демо-кассе, отправляем документ и забираем результат.
Подготовка кассы
- Поставьте YaKassa версии 2.2.09.395 или новее. Для проб подойдёт демо-касса: её чеки не фискальные.
- Откройте смену на кассе.
- Откройте Настройки → Обмен. Включите Обмен по http: появится «Номер для обмена», это и есть токен. Для работы по локальной сети включите TCP сервер: в заголовке настройки указан порт, обычно
8090, а под ней адрес кассы. - Проверьте индикаторы в правом верхнем углу:
ОбмениTCPдолжны быть зелёными. - Оставьте приложение на экране. В свёрнутом виде обмен останавливается.
Шаг 1. Отправить документ
У каждого чека свой id. Сгенерируйте GUID и не меняйте его, если придётся повторить запрос.
curl -X POST 'https://ofd.yaros.kg:8143/ofd-0.0.1/gate/receipt-v4' \
-H 'token: <токен с экрана кассы>' \
-H 'Content-Type: application/json' \
-d '{
"id": "550e8400-e29b-41d4-a716-446655440000",
"operation": "INCOME",
"cashless": false,
"products": [
{ "id": "1", "name": "Молоко", "price": 100.00, "quantity": 1,
"vat_value": 0, "st_value": 0, "calcItemAttributeCode": "0" }
]
}'curl -X POST 'http://192.168.0.50:8090/gate/receipt-v4' \
-H 'Content-Type: application/json' -H 'Expect:' \
-d '{
"id": "550e8400-e29b-41d4-a716-446655440000",
"operation": "INCOME",
"cashless": false,
"products": [
{ "id": "1", "name": "Молоко", "price": 100.00, "quantity": 1,
"vat_value": 0, "st_value": 0, "calcItemAttributeCode": "0" }
]
}'Ответ значит только «документ принят», чека ещё нет:
{ "id": "550e8400-e29b-41d4-a716-446655440000", "status": "OK", "info": "Документ принят" }Шаг 2. Забрать результат
Спрашивайте статус раз в 1–2 секунды, пока он не перестанет быть PROCESSING.
curl -X POST 'https://ofd.yaros.kg:8143/ofd-0.0.1/gate/receipt-status-v4' \
-H 'token: <токен с экрана кассы>' \
-H 'Content-Type: application/json' \
-d '{ "id": "550e8400-e29b-41d4-a716-446655440000" }'curl -X POST 'http://192.168.0.50:8090/gate/receipt-status-v4' \
-H 'Content-Type: application/json' -H 'Expect:' \
-d '{ "id": "550e8400-e29b-41d4-a716-446655440000" }'Чек пробит, когда пришёл OK с реквизитами:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "OK",
"qr": "https://…/ticket?date=20261102T101500&type=3&…",
"amount": 100.00,
"cashless": false,
"shiftNumber": "42",
"receiptNumber": "17",
"fdNumber": "3160",
"fpd": "1359586714023",
"gnsDate": "20261102T101500",
"rnKKM": "0000000000000000",
"fnKKM": "0000000000000000",
"kkmID": "65f1234567890abcdef12345"
}Сохраните fdNumber, qr и kkmID: они понадобятся для возврата, печати и поиска чека. Значения статусов разобраны в описании ответа.
Минимальный клиент
Один и тот же код работает с обоими каналами: разница только в адресе и токене.
import time
import uuid
import requests
class YaKassa:
def __init__(self, base_url, token=None):
# HTTP: "https://ofd.yaros.kg:8143/ofd-0.0.1", token="<токен>"
# TCP: "http://192.168.0.50:8090", token=None
self.base_url = base_url.rstrip("/")
self.headers = {"Content-Type": "application/json"}
if token:
self.headers["token"] = token
def _post(self, path, body):
r = requests.post(self.base_url + path, json=body, headers=self.headers, timeout=30)
data = r.json()
if data.get("status") == "fail": # формат ошибок TCP
raise RuntimeError(data.get("message"))
return data
def receipt(self, doc, timeout_sec=300):
accepted = self._post("/gate/receipt-v4", doc)
if accepted.get("status") == "ERROR":
raise RuntimeError(accepted.get("info"))
deadline = time.monotonic() + timeout_sec
while time.monotonic() < deadline:
time.sleep(1.5)
result = self._post("/gate/receipt-status-v4", {"id": doc["id"]})
status = result.get("status")
if status in ("OK", "PAID"):
return result
if status == "ERROR" and result.get("info") == "Request already working":
continue # занята сессия, а не отказ по документу
if status != "PROCESSING":
raise RuntimeError(result.get("info") or status)
raise TimeoutError("Нет результата. Не создавайте новый id: спросите статус позже по " + doc["id"])
doc = {
"id": str(uuid.uuid4()),
"operation": "INCOME",
"cashless": False,
"products": [{
"id": "1", "name": "Молоко", "price": 100.00, "quantity": 2,
"vat_value": 0, "st_value": 0, "calcItemAttributeCode": "0",
}],
}
kassa = YaKassa("https://ofd.yaros.kg:8143/ofd-0.0.1", token="<токен>")
# kassa = YaKassa("http://192.168.0.50:8090") # тот же код через TCP
result = kassa.receipt(doc)
print(result["status"], result.get("fdNumber"), result.get("qr"))