API Эндпоинты для POS интеграции#

Полная документация API эндпоинтов для интеграции с кассовой системой и работы с бонусной программой.

Базовый URL#

Production: https://gateway.sagi.kz
Sandbox:    https://test.sagi.kz

Все запросы требуют авторизации через JWT токен в заголовке Authorization: Bearer {token}.


ВАЖНОЕ ПРИМЕЧАНИЕ#

Все эндпоинты API возвращают результат в следующем формате:

type Response struct {
    Code    int32       `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
}

В документации ниже показано только содержимое поля data для упрощения чтения. В реальных ответах API все данные будут обернуты в структуру Response.

Пример реального ответа:

{
  "code": 200,
  "message": "Success",
  "data": {
    "id": 1460220481801031680,
    "phone": "+77071234567",
    "first_name": "Иван"
  }
}

1. Поиск клиента#

GET /api/v1/promoters/find#

Поиск клиента по номеру телефона для работы с бонусной программой.

Query параметры:

  • phone (string, обязательный) - номер телефона клиента (формат: +77071234567)

  • branch_id (int64, обязательный) - ID филиала для проверки черного списка

Пример запроса:

curl -X GET "{{baseURL}}/api/v1/promoters/find?phone=+77071234567&branch_id=1234567890123456" \
  -H "Authorization: Bearer {token}"

Успешный ответ (200) - объект User (Пользователь):

{
  "id": 1460220481801031680,
  "first_name": "Иван",
  "last_name": "Иванов",
  "birthday": "02-10-2025",
  "avatar": "https://storage.example.com/avatars/user.jpg",
  "phone": "+77071234567",
  "username": "",
  "tags": [
    {
      "id": 128390023012930123,
      "name": "Соседи по дому",
      "bonus_percentage": 50,
      "background_color": "",
      "color": "",
      "created_at": 1761647590144,
      "updated_at": 1761647590144,
      "user_count": 0,
      "is_discount": false
    }
  ],
  "send_code_for_use_cashback": true,
  "gradation_status": ""
}

Ошибки:

  • 404 - Пользователь не найден

  • 400 - Неверный формат телефона

  • 403 - Пользователь в черном списке филиала


2. Редактирование личных данных клиента#

PUT /api/v1/customers/{user_id}/personal-info#

Редактирование ФИО и даты рождения клиента.

Тело запроса:

{
    "first_name": "Иван",
    "last_name": "Иванов",
    "birthday": "15-03-1990",        // формат DD-MM-YYYY
    "phone_number": "+77071234567",
    "new_phone_number": "+77716254424",
    "branch_id": 12399231239344,
    "tags": [23412432412341, 32142341234234, 12341234344934]
}

Пример запроса:

curl -X PUT "{{baseURL}}/api/v1/customers/1460220481801031680/personal-info" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Иван",
    "last_name": "Иванов",
    "birthday": "15-03-1990"
  }'

Успешный ответ (200) - объект User (Пользователь):

{
  "id": 1460220481801031680,
  "phone": "+77071234567",
  "first_name": "Иван", 
  "last_name": "Иванов",
  "birthday": "1990-03-15T00:00:00Z"
}

3. Получение баланса клиента в филиале#

GET /api/v1/branches/{branch_id}/private/balance#

Получение доступных бонусов клиента в конкретном филиале.

Query параметры:

  • user_id (int64, обязательный) - ID пользователя

  • group_id (int64, обязательный) - Group ID филиала

Пример запроса:

curl -X GET "{{baseURL}}/api/v1/branches/1234567890123456/private/balance?user_id=1460220481801031680&group_id=9876543210987654" \
  -H "Authorization: Bearer {token}"

Успешный ответ (200) - число (float64):

2500.50

4. Получение информации о частном филиале клиента#

GET /api/v1/branches/{branch_id}/customers/{user_id}/private-branch#

Получение детальной информации о клиенте в филиале.

Пример запроса:

curl -X GET "{{baseURL}}/api/v1/branches/1234567890123456/customers/1460220481801031680/private-branch" \
  -H "Authorization: Bearer {token}"

Успешный ответ (200) - объект PrivateBranch (Частный филиал):

{
  "branch_id": 1234567890123456,
  "group_id": 9876543210987654,
  "balance": 2500.50,
  "is_client": true,
  "cash_back_percent": 5.0,
  "daily_tx_count": 2,
  "daily_tx_limit": 5,
  "spend_amount": 45000.0,
  "updated_at": 1705332000000
}

5. Получение процента кешбека клиента#

GET /api/v1/branches/{branch_id}/cashback#

Получение актуального процента кешбека для клиента с учетом всех условий и ограничений.

Query параметры:

  • user_id (int64, обязательный) - ID клиента

  • type (string, опциональный) - тип заказа («direct», «qr»)

  • use_certificate (boolean, опциональный) - использование сертификата

Пример запроса:

curl -X GET "{{baseURL}}/api/v1/branches/1234567890123456/cashback?user_id=1460220481801031680" \
  -H "Authorization: Bearer {token}"

Успешный ответ (200) - число (float64):

5.0

Логика расчета:

  • Проверяется наличие клиента в черном списке филиала

  • Учитывается дневной лимит транзакций (если превышен → кешбек = 0)

  • Применяются градационные настройки кешбека

  • Возвращается максимальный процент из доступных

Ошибки:

  • 400 - Клиент в черном списке филиала

  • 404 - Филиал или клиент не найден


6. Получение информации о штампах клиента#

GET /api/v1/branches/{branch_id}/customers/{user_id}/award#

Получение детальной информации о накопленных штампах и доступных наградах клиента.

Пример запроса:

curl -X GET "{{baseURL}}/api/v1/branches/1234567890123456/customers/1460220481801031680/award" \
  -H "Authorization: Bearer {token}"

Успешный ответ (200) - объект UserAward (Награда пользователя):

{
  "id": "60f1b2b3c4d5e6f7g8h9i0j1",
  "title": "Бесплатный кофе",
  "description": "Получите бесплатный кофе за 10 покупок",
  "stamp_count": 10,
  "received_stamp_count": 7,
  "created_at": 1642204800000,
  "activated_at": 1642204800000,
  "expired_at": 1735689600000,
  "total": 3,
  "is_active": true
}

Случай отсутствия данных: Если клиент еще не участвовал в программе наград, возвращаются настройки филиала с received_stamp_count: 0.

Бизнес-логика:

  • Если received_stamp_count >= stamp_count → клиент может получить награду

  • Программа наград должна быть активна (is_active = true)


7. Выдача награды клиенту#

POST /api/v1/branches/{branch_id}/awards/{award_id}/give#

Выдача подарка клиенту при достижении необходимого количества штампов.

Тело запроса:

{
  "user_id": 1460220481801031680,
  "stamp_count": 10
}

Пример запроса:

curl -X POST "{{baseURL}}/api/v1/branches/1234567890123456/awards/60f1b2b3c4d5e6f7g8h9i0j1/give" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": 1460220481801031680,
    "stamp_count": 10
  }'

Успешный ответ (200) - объект UserAward (Награда пользователя):

{
  "id": "60f1b2b3c4d5e6f7g8h9i0j1",
  "title": "Бесплатный кофе",
  "description": "Получите бесплатный кофе за 10 покупок",
  "stamp_count": 10,
  "received_stamp_count": 0,
  "total": 4,
  "updated_at": 1705332000000
}

Условия:

  • Клиент должен иметь достаточное количество штампов

  • Программа наград должна быть активна в филиале

  • Счетчик штампов сбрасывается к 0 после выдачи награды


8. Создание транзакции для начисления бонусов#

POST /api/v1/branches/{branch_id}/cash/order#

Создание транзакции для начисления или списания бонусов.

Тело запроса:

{
  "user_id": 1460220481801031680,       // ID клиента (обязательное)
  "amount": 2000,                       // сумма покупки в тенге (обязательное)
  "bonus_amount": 1000,                 // сумма списываемых бонусов (0 если не списываем)
  "comment": "Покупка в кассе #1",      // комментарий к транзакции (опционально)
  "user_phone": "+77077000087",         // телефон для незарегистрированных клиентов (опционально)
  "add_stamp": false,                   // начислить штампик true/false (опционально)
  "stamp_count": 1,                     // количество начисляемых штампиков (опционально)
  "give_award": false,                  // выдается ли награда true/false (опционально)
  "use_balance_code": "123456"          // код подтверждения для списания (требуется при bonus_amount > 0)
}

Описание полей:

  • user_id - уникальный идентификатор клиента в системе

  • amount - общая сумма покупки в тенге

  • bonus_amount - сумма к списанию с баланса бонусов (0 = только начисление)

  • comment - произвольный комментарий, отображается в истории

  • user_phone - используется для создания нового клиента, если user_id не указан

  • add_stamp - добавить штамп в программу наград (не может быть true одновременно с give_award)

  • stamp_count - количество штампов к добавлению

  • give_award - выдается ли награда (не может быть true одновременно с add_stamp)

  • use_balance_code - код подтверждения, отправленный клиенту SMS (обязателен при списании бонусов)

Пример запроса:

curl -X POST "{{baseURL}}/api/v1/branches/1234567890123456/cash/order" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": 1460220481801031680,
    "amount": 2000,
    "bonus_amount": 0,
    "comment": "Покупка в кассе #1",
    "user_phone": "+77077000087",
    "add_stamp": true,
    "stamp_count": 1,
    "give_award": false
  }'

Успешный ответ (201) - объект Order (Заказ):

{
  "id": 12345678901234567890,
  "order_number": 1001,
  "type": "direct",
  "status": "CREATED",
  "initial_order_total_amount": 2000.0,
  "order_total_amount": 2000.0,
  "created_at": 1705332000000,
  "sender": {
    "id": 1460220481801031680,
    "first_name": "Иван",
    "last_name": "Иванов",
    "phone": "+77077000087"
  },
  "recipient": {
    "id": 1234567890123456,
    "name": "Кофейня Аромат",
    "address": "ул. Абая 10"
  }
}

Важные правила:

  • add_stamp и give_award не могут быть одновременно true

  • use_balance_code обязателен при bonus_amount > 0 и если филиал требует код подтверждения


9. Завершение транзакции и начисление бонусов#

POST /api/v1/orders/{order_id}/cash/complete#

Завершение транзакции и фактическое начисление/списание бонусов клиенту.

Тело запроса:

{
  "use_balance": false,              // списывались ли бонусы (true/false)
  "amount": 0,                       // сумма списанных бонусов (обязательно указать при use_balance=true)
  "payment_method": "cash"           // способ оплаты: cash, card, online, mixed
}

Описание полей:

  • use_balance - ОБЯЗАТЕЛЬНО true при списании бонусов, false при начислении

  • amount - при СПИСАНИИ указать желаемую сумму списания, при начислении указать 0

  • payment_method - способ оплаты остатка суммы после списания бонусов

Пример запроса (без списания бонусов):

curl -X POST "{{baseURL}}/api/v1/orders/12345678901234567890/cash/complete" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "use_balance": false,
    "amount": 0,
    "payment_method": "card"
  }'

Пример запроса (со списанием 1000 тенге бонусов):

curl -X POST "{{baseURL}}/api/v1/orders/12345678901234567890/cash/complete" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "use_balance": true,
    "amount": 1000,
    "payment_method": "mixed"
  }'

Успешный ответ (200):

null

При успешном завершении возвращается пустой ответ.


10. Отправка кода подтверждения для списания бонусов#

POST /api/v1/customers/{user_id}/send-use-cashback-code#

Отправка SMS кода подтверждения для списания бонусов клиента.

Тело запроса:

{
  "branch_id": 1234567890123456
}

Пример запроса:

curl -X POST "{{baseURL}}/api/v1/customers/1460220481801031680/send-use-cashback-code" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "branch_id": 1234567890123456
  }'

Успешный ответ (200) - строка (код):

"1234"

Ошибка неверного кода (400):

{
  "code": 3025,
  "message": "code for using private balance is wrong"
}

11. Отмена транзакции#

POST /api/v1/orders/{order_id}/revert-transaction#

Отмена транзакции и возврат начисленных бонусов. Также отменяет начисление штампов.

Тело запроса: пустое

Пример запроса:

curl -X POST "{{baseURL}}/api/v1/orders/12345678901234567890/revert-transaction" \
  -H "Authorization: Bearer {token}"

Успешный ответ (200) - объект Order (Заказ):

{
  "id": 12345678901234567890,
  "status": "DECLINED",
  "updated_at": 1705335600000,
  "error": {
    "code": 3015,
    "message": "order was manually reverted"
  }
}

Условия: Статус транзакции должен быть «COMPLETED».


12. Частичный возврат#

PATCH /api/v1/orders/{order_id}/refund#

Частичный возврат суммы и соответствующих бонусов. Штампы остаются.

Тело запроса:

{
  "amount": "500"                      // сумма возврата как строка (не должна быть >= суммы транзакции)
}

Пример запроса:

curl -X PATCH "{{baseURL}}/api/v1/orders/12345678901234567890/refund" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "500"
  }'

Успешный ответ (200) - объект Order (Заказ):

{
  "id": 12345678901234567890,
  "updated_at": 1705335600000,
  "initial_order_total_amount": 2000.0,
  "order_total_amount": 1500.0,
  "refunds": [
    {
      "amount": 500.0,
      "refunded_bonus": 25.0,
      "created_at": 1705335600000
    }
  ]
}

Условия:

  • Статус транзакции должен быть «COMPLETED»

  • Сумма возврата не должна быть больше или равна сумме транзакции

  • Поле amount передается как строка


13. Обновление токена авторизации#

POST /api/v1/auth/refresh_token#

Обновление истекшего JWT токена с помощью refresh token.

Заголовки:

  • Authorization: Bearer {expired_token} - истекший токен

  • Content-Type: application/json

Тело запроса: пустое

Пример запроса:

curl -X POST "{{baseURL}}/api/v1/auth/refresh_token" \
  -H "Authorization: Bearer {expired_token}"

Успешный ответ (200):

{
  "code": 200,
  "expire": "2024-03-16T14:30:00Z",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Ошибки:

  • 401 - Токен недействителен или не может быть обновлен

  • 403 - Refresh token истек

Примечания:

  • Используется для автоматического обновления токенов в POS системах

  • Рекомендуется настроить cron-задачу для периодического обновления