Для разработчиков · версия 2.0

API Анкоры

REST API для касс, 1С, CRM, сайтов, Zapier, Make и своих скриптов. Через него можно получить всех клиентов с картами и балансами, историю операций, начислить бонусы за покупку, списать кэшбэк и баллы, начислить штампы и выдать награду.

Запросы и ответы — JSON в UTF-8. Ключ доступа выдаёт сам бизнес в кабинете: Интеграции → «API и Zapier».

Адрес API

https://ankora.pro/api/v2/public

Спецификация OpenAPI 3.1

/api/v2/public/openapi.json

Импорт в Postman, Insomnia и генераторы клиентов.

Содержание

Начало работы

Быстрый старт Ключ и права Как указать клиента Ответы и ошибки Повтор запроса Списки и синхронизация Лимиты Вебхуки Сценарии с кодом

Справочники

Спецификация OpenAPI Аккаунт и состояние ключа Точки продажи Точка продажи Программы лояльности Программа лояльности Акции

Клиенты

Список клиентов Найти или создать клиента Найти карту клиента Профиль клиента Изменить профиль клиента Найти карту Карта

Покупки и бонусы

Рассчитать продажу Провести продажу Вернуть покупку Начислить вручную Списать Установить баланс Скорректировать баланс Изменить сумму покупок Начислить за покупку Списать кэшбэк или баллы

Штампы

Начислить штампы на карту Снять штампы Выдать награду Начислить штампы Выдать награду за штампы

Абонементы

Продать абонемент Абонемент Засчитать визит Отменить визит Заморозить абонемент Разморозить абонемент Рассчитать возврат абонемента Вернуть абонемент

Подписки

Продать подписку Подписка Использовать действие Продлить подписку Поставить на паузу Снять с паузы Отменить подписку

Статус гостя

Засчитать визит Отменить визит

Операции

История карты История операций

Вебхуки

Подписки на вебхуки Подписаться на события Подписка и журнал доставок Отписаться Отправить тестовое событие

Справочник

События вебхуков Объекты История изменений

Быстрый старт

  1. В кабинете Анкоры откройте Интеграции → «API и Zapier» и нажмите «Включить API». Скопируйте ключ — он начинается с ak_.
  2. Проверьте ключ первым запросом — он вернёт ваш бизнес и состояние подписки:
curl
curl https://ankora.pro/api/v2/public/account \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"
  1. Найдите карту клиента — по телефону или номеру карты с QR на кассе:
curl
curl -G https://ankora.pro/api/v2/public/cards/lookup \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  --data-urlencode "phone=+79991234567"
  1. Проведите продажу: Анкора посчитает скидку, спишет бонусы и начислит новые по правилам программы.
curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/checkout \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"amount":1000,"redeem_cashback":200,"external_id":"CHEK-2026-000125","location_id":3}'

Запросы и ответы — JSON в UTF-8, даты — ISO 8601, суммы — числа в рублях. Все методы — в справочнике ниже, у каждого — пример запроса, успешного ответа и ошибок.

Ключ и права

Каждый запрос — с заголовком Authorization: Bearer ak_…. Один ключ — один бизнес: все запросы идут в его клиентов, карты и программы, указывать бизнес не нужно. Ключ можно перевыпустить в кабинете — старый сразу перестанет работать. Не публикуйте ключ в коде сайта или мобильного приложения: он даёт доступ ко всей клиентской базе.

Нет ключа, ключ неверен или API выключен — ответ 401 unauthorized.

Права ключа

Чтение, начисление за покупки, списание бонусов, штампы, абонементы, подписки, визиты и клиенты работают с любым ключом. Операции, которые обходят правила программы, включаются отдельно на странице «API и Zapier» — по умолчанию они выключены:

ПравоЧто открывает
balance_management — «Управление балансами»Начисление вручную, установка и корректировка кэшбэка, баллов и штампов, изменение суммы покупок для ступеней.
refunds — «Возвраты и отмены»Возврат покупки, возврат абонемента, отмена подписки.

Без права — ответ 403 permission_denied с именем права в details.permission. Какие права у ключа сейчас — в GET /account.

Подписка бизнеса

Если подписка Анкоры истекла или API не входит в тариф, чтение продолжает работать, а операции возвращают 403 subscription_required с причиной в details.reason. Состояние видно заранее: api.operations_allowed в GET /account.

Как указать клиента и карту

У клиента по карте в каждой программе бизнеса. Методы над картой принимают её id в пути — /cards/{id}/…; найти карту можно через GET /cards/lookup любым идентификатором:

ПараметрЧто это
card_idId карты в Анкоре — однозначно.
card_numberНомер карты — то, что кассир сканирует с QR. Регистр и пробелы не важны. Однозначно.
customer_idId клиента в Анкоре.
phoneТелефон в любом российском формате: +79991234567, 8 999 123-45-67.
external_customer_idId клиента в вашей системе — если вы уже передавали его вместе с телефоном, дальше клиент находится по нему.
program_idПрограмма, если у клиента карты в нескольких. Без него ответ program_required со списком программ клиента.

Методы первой версии — POST /purchases, /redemptions, /stamps, /stamp_redemptions, GET /customers/search — принимают эти же параметры в теле запроса. Если клиент с картами в нескольких программах указан без program_id, они, как и раньше, берут первую активную программу.

Точка продажи — location_id у любой операции: покупки и списания попадут в аналитику по точкам. Список точек — GET /locations.

Ответы и ошибки

Успех — 200 или 201 с JSON. Ошибка — код HTTP и тело одного вида:

JSON
{
  "error": "insufficient_balance",
  "message": "Недостаточно кэшбэка: на карте 25 ₽, запрошено 50 ₽",
  "details": { "currency": "cashback", "balance": 25.0, "requested": 50.0 }
}

error — стабильный код: по нему ветвится ваш код. message — текст для человека, его можно показать кассиру; формулировка может меняться. details — подробности, свои у каждого кода.

КодHTTPКогдаdetails
unauthorized401Ключ не передан, неверен или API выключен.—
permission_denied403Операция выключена в правах ключа.permission
subscription_required403Подписка бизнеса истекла или API не входит в тариф. Чтение работает.reason
invalid_json400Тело запроса не разбирается как JSON.—
parameter_missing422Не передан обязательный параметр.param или params — если нужен один из нескольких
parameter_invalid422Параметр не того формата: сумма не число, дата не разбирается, неизвестное значение.param
not_found404Клиент, карта, программа, точка, абонемент, подписка или покупка не найдены у этого бизнеса.resource
program_required422У клиента карты в нескольких программах — передайте program_id.program_ids
mechanic_disabled422Механика выключена в программе: например, начисляют штампы, а штампов в программе нет.mechanic
insufficient_balance422Не хватает кэшбэка, баллов, штампов или наград. Ничего не списано.currency, balance, requested
redemption_limit_exceeded422Списание по чеку больше лимита программы — например, не больше 30% чека.currency, max, requested
limit_reached422Исчерпан лимит действия подписки или визит гостя уже засчитан сегодня.—
operation_rejected422Отказ по другому правилу Анкоры — причина в message: абонемент заморожен, у клиента уже есть подписка, телефон занят другим клиентом.бывает
idempotency_key_reused409Тот же Idempotency-Key пришёл с другим запросом.—
idempotency_key_in_progress409Запрос с этим ключом ещё выполняется — повторите через пару секунд.—
rate_limited429Больше 120 запросов в минуту на ключ.retry_after_seconds
internal_error500Сбой на стороне Анкоры. Повторите позже — с Idempotency-Key это безопасно.—

Повтор запроса

Сеть рвётся: запрос ушёл, а ответ не дошёл. Чтобы повтор не списал бонусы второй раз, передавайте в каждом POST, PUT, PATCH и DELETE заголовок Idempotency-Key — уникальную строку на операцию, до 255 символов: UUID или номер вашего документа.

  • Повтор с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция второй раз не выполнится.
  • Сохраняются только успешные ответы. Ошибка ничего не изменила — после исправления повторите с тем же ключом, операция выполнится.
  • Тот же ключ с другим методом, адресом или телом — 409 idempotency_key_reused: для новой операции нужен новый ключ.
  • Ответ 500 тоже не сохраняется: повтор с тем же ключом безопасен.
curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/balance/spend \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: 9b2f7c1e-4a3d-4e8b-a6f0-2c5d8e1b7a94" \
  -H "Content-Type: application/json" \
  -d '{"currency":"cashback","amount":50}'

Номер чека

У покупок свой надёжный ключ — номер чека external_id, он обязателен в POST /purchases и POST /cards/{id}/checkout. Чек с тем же номером не проведётся второй раз (ответ — skipped с причиной already_processed), а по номеру работает возврат POST /purchases/{external_id}/refund. Если списываете бонусы отдельно от покупки через POST /redemptions, передайте тот же external_id — возврат чека вернёт и списанное.

Списки и синхронизация

Списки — клиенты, операции, точки, программы, акции, подписки на вебхуки — отдаются страницами по возрастанию id:

JSON
{ "data": [ … ], "has_more": true, "next_after_id": 1234 }

limit — от 1 до 100, по умолчанию 50. Следующая страница — с after_id из next_after_id; пока has_more равно true, есть ещё. На пустой странице next_after_id равен переданному after_id — с ним и приходите в следующий раз за новыми записями.

Выгрузить всю базу

Python
import requests

API = "https://ankora.pro/api/v2/public"
HEADERS = {"Authorization": "Bearer ak_ВАШ_КЛЮЧ"}

after_id = 0
while True:
    page = requests.get(f"{API}/customers", headers=HEADERS,
                        params={"after_id": after_id, "limit": 100}, timeout=30).json()
    for customer in page["data"]:
        save_customer(customer)          # профиль и все карты с балансами
    after_id = page["next_after_id"]
    if not page["has_more"]:
        break

Забирать изменения

  • Новые операции — GET /transactions с after_id = последний полученный id. Операции не меняются, поэтому этого достаточно.
  • Изменившихся клиентов — GET /customers с updated_since: клиент попадёт в выборку, если изменился профиль или любая из карт, включая баланс.
  • Чтобы не опрашивать вовсе — подпишитесь на вебхуки: Анкора пришлёт событие сама.

Лимиты

Не больше 120 запросов в минуту на ключ — с запасом для кассы и регулярной синхронизации. Сверх лимита — ответ 429 rate_limited и заголовок Retry-After: через сколько секунд можно продолжить. Для разовой большой выгрузки берите страницы по 100 записей; если лимита не хватает — напишите в поддержку.

Вебхуки

Анкора сама отправит POST-запрос на ваш адрес, как только событие случится, — опрашивать API не нужно. События:

  • card.created — Новый клиент программы — выпущена карта.
  • customer.updated — Изменился профиль клиента.
  • transaction.created — Новая операция по карте: покупка, начисление, списание, сгорание, абонемент, подписка.

Подписаться можно в кабинете (Интеграции → «API и Zapier» → «Вебхуки») или через POST /webhooks — так работают мгновенные триггеры Zapier. Адрес — только https и только публичный, до 10 подписок на ключ.

Что приходит

HTTP
POST /ankora-webhook HTTP/1.1
Content-Type: application/json; charset=utf-8
Ankora-Event-Id: evt_6f1c2a9e-5b7d-4e8a-9c41-0d2b6f7e8a10
Ankora-Event-Type: transaction.created
Ankora-Signature: t=1761298200,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

{"id":"evt_6f1c2a9e-…","type":"transaction.created","created_at":"2026-10-24T12:30:00+03:00","business_id":42,"data":{…}}

Данные — на момент события: карта в transaction.created показывает баланс сразу после операции, даже если доставка ушла позже.

Проверка подписи

Любой может отправить запрос на ваш адрес, поэтому прежде чем доверять данным, проверьте подпись. Ankora-Signature — это t=<время>,v1=<подпись>, где подпись — HMAC-SHA256 секретом подписки (whsec_…, виден в кабинете) от строки <t>.<тело запроса>. Считайте подпись от сырого тела — до разбора JSON — и отклоняйте запросы старше 5 минут: так старый запрос не повторить.

Python
import hashlib, hmac, time

def ankora_signature_valid(secret: str, body: bytes, header: str, tolerance: int = 300) -> bool:
    parts = dict(part.split("=", 1) for part in header.split(",") if "=" in part)
    timestamp = int(parts.get("t", "0"))
    if abs(time.time() - timestamp) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))
Node.js
const crypto = require("crypto");

function ankoraSignatureValid(secret, rawBody, header, tolerance = 300) {
  const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")));
  const timestamp = Number(parts.t);
  if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > tolerance) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  const given = Buffer.from(parts.v1 || "");
  return given.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), given);
}
PHP
function ankora_signature_valid(string $secret, string $body, string $header, int $tolerance = 300): bool {
    $parts = [];
    foreach (explode(',', $header) as $part) {
        [$key, $value] = array_pad(explode('=', $part, 2), 2, '');
        $parts[$key] = $value;
    }
    $timestamp = (int) ($parts['t'] ?? 0);
    if (abs(time() - $timestamp) > $tolerance) {
        return false;
    }
    $expected = hash_hmac('sha256', $timestamp . '.' . $body, $secret);
    return hash_equals($expected, $parts['v1'] ?? '');
}

// $body = file_get_contents('php://input');
// ankora_signature_valid($secret, $body, $_SERVER['HTTP_ANKORA_SIGNATURE'] ?? '');
Ruby
require "openssl"

def ankora_signature_valid?(secret, body, header, tolerance: 300)
  parts = header.to_s.split(",").filter_map { |part| part.split("=", 2) if part.include?("=") }.to_h
  timestamp = parts["t"].to_i
  return false if (Time.now.to_i - timestamp).abs > tolerance

  expected = OpenSSL::HMAC.hexdigest("SHA256", secret, "#{timestamp}.#{body}")
  Rack::Utils.secure_compare(expected, parts["v1"].to_s)
end

Ответ, повторы и дубли

  • Ответьте любым кодом 2xx в течение 10 секунд. Тяжёлую обработку делайте в фоне после ответа.
  • Другой код, ошибка соединения или долгий ответ — отказ. Повторы: через 1 минуту, 5 минут, 30 минут, 2 часа, 6, 12 и 24 часа. Редиректы не повторяются.
  • Одно событие может прийти дважды — например, ваш сервер принял его, но ответ потерялся. Отсекайте дубли по Ankora-Event-Id: он одинаковый во всех повторах.
  • События могут прийти не в том порядке, в каком случились: сверяйтесь с created_at и id операций.
  • Если адрес трое суток не принимает ничего, подписка выключается, а владельцу бизнеса уходит письмо. Включить её снова можно в кабинете.

Проверить адрес и проверку подписи — кнопкой «Отправить тестовое событие» в кабинете или POST /webhooks/{id}/test: придёт событие webhook.test, а журнал последних доставок с кодами ответа — в GET /webhooks/{id}.

Сценарии с кодом

Касса: продажа со списанием бонусов и возврат

  1. Кассир сканирует QR с карты клиента — найдите карту: GET /cards/lookup?card_number=….
  2. Покажите, сколько можно списать и сколько начислится: POST /cards/{id}/checkout/preview. Скидка по ступени клиента уже посчитана.
  3. Клиент согласился — проведите продажу: POST /cards/{id}/checkout с номером чека. Повтор с тем же номером не проведёт её дважды.
  4. Чек вернули — POST /purchases/{external_id}/refund: начисленное снимется, списанные бонусы вернутся.
JavaScript
const API = "https://ankora.pro/api/v2/public";
const headers = { Authorization: "Bearer ak_ВАШ_КЛЮЧ", "Content-Type": "application/json" };

async function call(method, path, body, idempotencyKey) {
  const response = await fetch(API + path, {
    method,
    headers: idempotencyKey ? { ...headers, "Idempotency-Key": idempotencyKey } : headers,
    body: body && JSON.stringify(body),
  });
  const json = await response.json();
  if (!response.ok) throw Object.assign(new Error(json.message), { code: json.error, details: json.details });
  return json;
}

const { card } = await call("GET", `/cards/lookup?card_number=${encodeURIComponent(qrValue)}`);
const preview = await call("POST", `/cards/${card.id}/checkout/preview`, { amount: 1500, redeem_cashback: 100 });
// preview.to_pay — к оплате деньгами, preview.cashback.earn — сколько начислится

const sale = await call("POST", `/cards/${card.id}/checkout`,
  { amount: 1500, redeem_cashback: 100, external_id: receiptNumber, location_id: 3 }, crypto.randomUUID());
// sale.receipt.paid, sale.receipt.earned_cashback, sale.card.cashback_balance

1С: начисление за чек и баланс клиента

1С (8.3)
Функция АнкораЗапрос(Метод, Путь, Тело = Неопределено, КлючПовтора = "") Экспорт
    Соединение = Новый HTTPСоединение("ankora.pro", 443, , , , 30, Новый ЗащищенноеСоединениеOpenSSL());
    Заголовки = Новый Соответствие;
    Заголовки.Вставить("Authorization", "Bearer " + Константы.КлючАнкоры.Получить());
    Заголовки.Вставить("Content-Type", "application/json");
    Если ЗначениеЗаполнено(КлючПовтора) Тогда
        Заголовки.Вставить("Idempotency-Key", КлючПовтора);
    КонецЕсли;
    Запрос = Новый HTTPЗапрос("/api/v2/public" + Путь, Заголовки);
    Если Тело <> Неопределено Тогда
        Запись = Новый ЗаписьJSON;
        Запись.УстановитьСтроку();
        ЗаписатьJSON(Запись, Тело);
        Запрос.УстановитьТелоИзСтроки(Запись.Закрыть(), КодировкаТекста.UTF8);
    КонецЕсли;
    Ответ = Соединение.ВызватьHTTPМетод(Метод, Запрос);
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
    Результат = Новый Структура("Код, Данные", Ответ.КодСостояния, ПрочитатьJSON(Чтение, Истина));
    Чтение.Закрыть();
    Возврат Результат;
КонецФункции

// Начислить за чек: номер документа — защита от двойного начисления.
Тело = Новый Структура("phone, amount, external_id", Телефон, СуммаЧека, Документ.Номер);
Результат = АнкораЗапрос("POST", "/purchases", Тело);
Если Результат.Код >= 400 Тогда
    // Результат.Данные["error"] — код ошибки, Результат.Данные["message"] — текст
    ЗаписьЖурналаРегистрации("Анкора", УровеньЖурналаРегистрации.Ошибка, , , Результат.Данные["message"]);
КонецЕсли;

// Баланс клиента по телефону.
Результат = АнкораЗапрос("GET", "/cards/lookup?phone=" + КодироватьСтроку(Телефон, СпособКодированияСтроки.КодировкаURL));
Если Результат.Код = 200 Тогда
    Кэшбэк = Результат.Данные["card"]["cashback_balance"];
КонецЕсли;

Синхронизация с CRM

  1. Один раз выгрузите всех клиентов — постранично через after_id.
  2. Подпишитесь на card.created, customer.updated и transaction.created — новые клиенты и движения балансов придут сами.
  3. Изменения из CRM отправляйте в Анкору: профиль — PATCH /customers/{id}, бонусы за сделку — POST /purchases с номером сделки как external_id.

Zapier, Make и другие no-code сервисы

Подключите модуль HTTP-запроса с заголовком Authorization: Bearer ak_…. Для мгновенного триггера подпишитесь через POST /webhooks на адрес, который выдаст сервис, а при отключении сценария отпишитесь через DELETE /webhooks/{id}. Для триггера по расписанию — GET /transactions или GET /customers с after_id.

Справочники

Аккаунт, точки продажи, программы лояльности со всеми настройками механик, акции.

Спецификация OpenAPI

GET /openapi.json без ключа

Эта документация в формате OpenAPI 3.1 — для импорта в Postman или Insomnia, генерации клиента и чтения ИИ-агентами. Ключ не нужен.

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

curl
curl https://ankora.pro/api/v2/public/openapi.json

Ответы

200 Спецификация.
JSON
{
  "openapi": "3.1.0",
  "info": {
    "title": "API Анкоры",
    "version": "2.0"
  },
  "paths": {
  }
}

Ещё: 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Аккаунт и состояние ключа

GET /account

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

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

curl
curl https://ankora.pro/api/v2/public/account \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Аккаунт.
JSON
{
  "business": {
    "id": 42,
    "name": "Кофейня «Зерно»",
    "slug": "zerno",
    "timezone": "Europe/Moscow"
  },
  "subscription": {
    "status": "active",
    "plan": "Бизнес",
    "active_until": "2026-11-20T00:00:00+03:00",
    "trial_ends_at": null
  },
  "api": {
    "operations_allowed": true,
    "blocked_reason": null,
    "rate_limit_per_minute": 120,
    "permissions": {
      "balance_management": false,
      "refunds": true
    }
  }
}

Ещё: 401, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Точки продажи

GET /locations

Точки бизнеса. Их id передают в location_id операций, чтобы покупки и списания попали в аналитику по точкам.

Параметры

ИмяГдеТипОписание
limit строка запроса integer Сколько записей на странице, от 1 до 100.
after_id строка запроса integer Вернуть записи с id больше этого — значение next_after_id из предыдущей страницы.

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

curl
curl https://ankora.pro/api/v2/public/locations \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Страница точек.
JSON
{
  "data": [
    {
      "id": 3,
      "name": "Кофейня на Тверской",
      "address": "Москва, Тверская, 1",
      "latitude": 55.7576,
      "longitude": 37.6136,
      "radius_meters": 100,
      "nearby_message": "Мы рядом — заходите за кофе",
      "active": true,
      "geo_program_ids": [
        7
      ],
      "created_at": "2026-03-02T10:00:00+03:00",
      "updated_at": "2026-09-12T18:20:00+03:00"
    }
  ],
  "has_more": false,
  "next_after_id": 3
}

Ещё: 401, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Точка продажи

GET /locations/{id}

Одна точка бизнеса.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.

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

curl
curl https://ankora.pro/api/v2/public/locations/123 \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Точка.
JSON
{
  "location": {
    "id": 3,
    "name": "Кофейня на Тверской",
    "address": "Москва, Тверская, 1",
    "latitude": 55.7576,
    "longitude": 37.6136,
    "radius_meters": 100,
    "nearby_message": "Мы рядом — заходите за кофе",
    "active": true,
    "geo_program_ids": [
      7
    ],
    "created_at": "2026-03-02T10:00:00+03:00",
    "updated_at": "2026-09-12T18:20:00+03:00"
  }
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Программы лояльности

GET /programs

Все программы бизнеса, включая выключенные, со всеми настройками механик.

Параметры

ИмяГдеТипОписание
limit строка запроса integer Сколько записей на странице, от 1 до 100.
after_id строка запроса integer Вернуть записи с id больше этого — значение next_after_id из предыдущей страницы.

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

curl
curl https://ankora.pro/api/v2/public/programs \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Страница программ.
JSON
{
  "data": [
    {
      "id": 7,
      "name": "Кофейня",
      "active": true,
      "cashback": {
        "enabled": true,
        "percent": 3.0,
        "tiers": [
          {
            "threshold": 10000.0,
            "percent": 5.0,
            "name": "Серебро",
            "color": "#9ca3af"
          },
          {
            "threshold": 30000.0,
            "percent": 7.0,
            "name": "Золото",
            "color": null
          }
        ],
        "auto_award": true,
        "max_balance": 5000.0,
        "max_redemption_percent": 30.0,
        "expiry": {
          "enabled": true,
          "days": 90,
          "policy": "from_earn",
          "fixed_date": null
        },
        "description": null
      },
      "points": {
        "enabled": false,
        "percent": 5.0,
        "tiers": [

        ],
        "auto_award": true,
        "currency_name": "баллы",
        "redemption_rate": 1.0,
        "max_balance": null,
        "max_redemption_percent": 100.0,
        "expiry": {
          "enabled": false,
          "days": null,
          "policy": "from_earn",
          "fixed_date": null
        },
        "description": null
      },
      "stamps": {
        "enabled": true,
        "target": 6,
        "reward_description": "Капучино в подарок",
        "auto_reset": true,
        "expiry": {
          "enabled": false,
          "days": null,
          "mode": "per_stamp"
        },
        "description": null
      },
      "discount": {
        "enabled": false,
        "percent": 0.0,
        "tiers": [

        ],
        "description": null
      },
      "tier_windows": {
        "spend_months": 12,
        "visits_months": null,
        "drop_reminder": {
          "enabled": true,
          "days": 7
        }
      },
      "guest_status": {
        "enabled": false,
        "counting_mode": "manual",
        "tiers": [

        ],
        "description": null
      },
      "welcome_bonus": {
        "enabled": true,
        "type": "cashback",
        "amount": 200.0,
        "expiry_days": 30,
        "delay_hours": 0,
        "after_first_purchase": false,
        "message": null
      },
      "birthday_bonus": {
        "enabled": true,
        "gift": true,
        "type": "cashback",
        "amount": 300.0,
        "days_before": 3,
        "expiry_days": 14,
        "message": null,
        "greeting_message": null
      },
      "referral": {
        "enabled": true,
        "type": "cashback",
        "recipients": "both",
        "referee_amount": 100.0,
        "referrer_amount": 150.0,
        "message": null
      },
      "expiry_reminders": {
        "enabled": true,
        "days": [
          7,
          1
        ],
        "message": "Напоминаем: {amount} бонусов сгорит через {days} дн. Успейте воспользоваться!"
      },
      "visit_passes": {
        "enabled": false,
        "default_expiry_days": null,
        "grant_cashback": true,
        "notify_exhausted": true
      },
      "memberships": {
        "enabled": true,
        "expiry_reminder_days": 3,
        "plans": [
          {
            "id": 11,
            "name": "Безлимит на месяц",
            "description": null,
            "duration_days": 30,
            "suggested_sale_price": 3500.0,
            "suggested_renewal_price": 3000.0,
            "overall_limit_count": null,
            "overall_limit_period_days": null,
            "actions": [
              {
                "id": 21,
                "label": "Тренировка",
                "limit_count": 1,
                "limit_period_days": 1
              }
            ]
          }
        ]
      },
      "registration_fields": [
        {
          "key": "phone",
          "label": "Телефон",
          "type": "phone",
          "required": true
        },
        {
          "key": "name",
          "label": "Имя",
          "type": "text",
          "required": true
        }
      ],
      "created_at": "2026-03-02T10:00:00+03:00",
      "updated_at": "2026-10-01T09:00:00+03:00"
    }
  ],
  "has_more": false,
  "next_after_id": 7
}

Ещё: 401, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Программа лояльности

GET /programs/{id}

Все настройки механик программы так, как их задал владелец в кабинете: кэшбэк, баллы и скидка со ступенями, штампы, сгорание, приветственный бонус, бонус ко дню рождения, рефералка, статусы гостя, абонементы и шаблоны подписок, поля анкеты.

Действующий для конкретного клиента процент (с учётом его ступени) приходит в карте — card.tier.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.

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

curl
curl https://ankora.pro/api/v2/public/programs/123 \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Программа.
JSON
{
  "program": {
    "id": 7,
    "name": "Кофейня",
    "active": true,
    "cashback": {
      "enabled": true,
      "percent": 3.0,
      "tiers": [
        {
          "threshold": 10000.0,
          "percent": 5.0,
          "name": "Серебро",
          "color": "#9ca3af"
        },
        {
          "threshold": 30000.0,
          "percent": 7.0,
          "name": "Золото",
          "color": null
        }
      ],
      "auto_award": true,
      "max_balance": 5000.0,
      "max_redemption_percent": 30.0,
      "expiry": {
        "enabled": true,
        "days": 90,
        "policy": "from_earn",
        "fixed_date": null
      },
      "description": null
    },
    "points": {
      "enabled": false,
      "percent": 5.0,
      "tiers": [

      ],
      "auto_award": true,
      "currency_name": "баллы",
      "redemption_rate": 1.0,
      "max_balance": null,
      "max_redemption_percent": 100.0,
      "expiry": {
        "enabled": false,
        "days": null,
        "policy": "from_earn",
        "fixed_date": null
      },
      "description": null
    },
    "stamps": {
      "enabled": true,
      "target": 6,
      "reward_description": "Капучино в подарок",
      "auto_reset": true,
      "expiry": {
        "enabled": false,
        "days": null,
        "mode": "per_stamp"
      },
      "description": null
    },
    "discount": {
      "enabled": false,
      "percent": 0.0,
      "tiers": [

      ],
      "description": null
    },
    "tier_windows": {
      "spend_months": 12,
      "visits_months": null,
      "drop_reminder": {
        "enabled": true,
        "days": 7
      }
    },
    "guest_status": {
      "enabled": false,
      "counting_mode": "manual",
      "tiers": [

      ],
      "description": null
    },
    "welcome_bonus": {
      "enabled": true,
      "type": "cashback",
      "amount": 200.0,
      "expiry_days": 30,
      "delay_hours": 0,
      "after_first_purchase": false,
      "message": null
    },
    "birthday_bonus": {
      "enabled": true,
      "gift": true,
      "type": "cashback",
      "amount": 300.0,
      "days_before": 3,
      "expiry_days": 14,
      "message": null,
      "greeting_message": null
    },
    "referral": {
      "enabled": true,
      "type": "cashback",
      "recipients": "both",
      "referee_amount": 100.0,
      "referrer_amount": 150.0,
      "message": null
    },
    "expiry_reminders": {
      "enabled": true,
      "days": [
        7,
        1
      ],
      "message": "Напоминаем: {amount} бонусов сгорит через {days} дн. Успейте воспользоваться!"
    },
    "visit_passes": {
      "enabled": false,
      "default_expiry_days": null,
      "grant_cashback": true,
      "notify_exhausted": true
    },
    "memberships": {
      "enabled": true,
      "expiry_reminder_days": 3,
      "plans": [
        {
          "id": 11,
          "name": "Безлимит на месяц",
          "description": null,
          "duration_days": 30,
          "suggested_sale_price": 3500.0,
          "suggested_renewal_price": 3000.0,
          "overall_limit_count": null,
          "overall_limit_period_days": null,
          "actions": [
            {
              "id": 21,
              "label": "Тренировка",
              "limit_count": 1,
              "limit_period_days": 1
            }
          ]
        }
      ]
    },
    "registration_fields": [
      {
        "key": "phone",
        "label": "Телефон",
        "type": "phone",
        "required": true
      },
      {
        "key": "name",
        "label": "Имя",
        "type": "text",
        "required": true
      }
    ],
    "created_at": "2026-03-02T10:00:00+03:00",
    "updated_at": "2026-10-01T09:00:00+03:00"
  }
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Акции

GET /promotions

Акции бизнеса: подарочный бонус сегменту клиентов (bonus) или множитель начисления на период (multiplier, например «двойные штампы»). Множитель идущей акции Анкора применяет сама — при начислении за покупку и при начислении штампов.

Параметры

ИмяГдеТипОписание
limit строка запроса integer Сколько записей на странице, от 1 до 100.
after_id строка запроса integer Вернуть записи с id больше этого — значение next_after_id из предыдущей страницы.
state строка запроса string Статус акции; несколько — через запятую.
program_id строка запроса integer

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

curl
curl https://ankora.pro/api/v2/public/promotions \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Страница акций.
JSON
{
  "data": [
    {
      "id": 31,
      "program_id": 7,
      "name": "Двойные штампы до конца октября",
      "kind": "multiplier",
      "state": "active",
      "starts_at": "2026-10-20T00:00:00+03:00",
      "ends_at": "2026-10-31T23:59:59+03:00",
      "bonus": null,
      "multiplier": {
        "value": 2.0,
        "targets": [
          "stamps"
        ]
      },
      "message": "Двойные штампы до 31 октября",
      "card_text": "Двойные штампы до 31.10",
      "control_group_percent": 20,
      "cards_count": 480,
      "control_count": 120,
      "launched_at": "2026-10-20T00:00:05+03:00",
      "finished_at": null,
      "cancelled_at": null,
      "created_at": "2026-10-18T15:00:00+03:00"
    }
  ],
  "has_more": false,
  "next_after_id": 31
}

Ещё: 401, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Клиенты

База клиентов, профили и карты.

Список клиентов

GET /customers

Все клиенты бизнеса, у которых есть карта, страницами по возрастанию id. В каждой записи — профиль и все карты клиента с балансами.

Чтобы выгрузить всю базу, повторяйте запрос с after_id из next_after_id, пока has_more не станет false. Для регулярной синхронизации добавьте updated_since: клиент попадёт в выборку, если изменился его профиль или любая из карт, включая баланс.

Параметры

ИмяГдеТипОписание
limit строка запроса integer Сколько записей на странице, от 1 до 100.
after_id строка запроса integer Вернуть записи с id больше этого — значение next_after_id из предыдущей страницы.
since_id строка запроса integer Старое имя after_id, работает так же.
phone строка запроса string Телефон в любом российском формате.
email строка запроса string Email, без учёта регистра.
card_number строка запроса string Номер карты, без учёта регистра и пробелов.
program_id строка запроса integer Только клиенты с картой в этой программе. В записи всё равно приходят все карты клиента.
segment строка запроса RfmSegment RFM-сегмент карты.
created_since строка запроса string Клиент зарегистрирован не раньше этого момента. Дата 2026-10-01 или время ISO 8601; без смещения — в часовом поясе бизнеса.
updated_since строка запроса string Профиль клиента или любая его карта изменились не раньше этого момента. Формат — как у created_since.

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

curl
curl https://ankora.pro/api/v2/public/customers \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Страница клиентов.
JSON
{
  "data": [
    {
      "id": 456,
      "name": "Анна",
      "phone": "+79991234567",
      "email": "anna@example.ru",
      "birthday": "1990-05-17",
      "gender": null,
      "custom_fields": {
      },
      "consent_accepted_at": "2026-03-02T10:15:00+03:00",
      "marketing_consent": true,
      "marketing_consent_at": "2026-03-02T10:15:00+03:00",
      "marketing_unsubscribed_at": null,
      "telegram_linked": false,
      "created_at": "2026-03-02T10:15:00+03:00",
      "updated_at": "2026-10-24T12:30:00+03:00",
      "cards": [
        {
          "id": 123,
          "card_number": "AABBCCDD00000001",
          "status": "active",
          "customer_id": 456,
          "program_id": 7,
          "location_id": null,
          "cashback_balance": 75.0,
          "points_balance": 0.0,
          "stamps_count": 3,
          "rewards_available": 0,
          "total_spent": 12500.0,
          "total_visits": 14,
          "last_visit_at": "2026-10-24T12:30:00+03:00",
          "rfm_segment": "loyal",
          "created_at": "2026-03-02T10:15:00+03:00",
          "updated_at": "2026-10-24T12:30:00+03:00"
        }
      ]
    }
  ],
  "has_more": true,
  "next_after_id": 457
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Найти или создать клиента

POST /customers

Заводит клиента и карту в программе program_id (по умолчанию — в первой активной) и возвращает created. Если клиент с таким телефоном или email уже есть с картой в этой программе — возвращает его со статусом exists; если есть, но без карты в ней — заводит карту ему же.

Клиент создаётся с согласием на обработку персональных данных: его собирает ваша система. Согласие на рекламные рассылки — только если передан marketing_consent: true. Приветственный бонус начисляется по правилам программы.

Параметры

ИмяГдеТипОписание
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
phone string | null Телефон в любом российском формате.
email string | null
name string | null
birthday string | null
gender string | null Значения: male, female, other
custom_fields object Поля анкеты сверх стандартных — ключи из registration_fields программы. При правке сливаются с записанными; пустое значение удаляет поле.
program_id integer Программа
location_id integer Точка продажи — операция попадёт в аналитику по точкам.
marketing_consent boolean Клиент дал согласие на рекламные рассылки.

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

curl
curl -X POST https://ankora.pro/api/v2/public/customers \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"phone":"+79991234567","name":"Анна","email":"anna@example.ru","birthday":"1990-05-17","gender":"female","custom_fields":{"car":"Kia Rio"}}'

Ответы

200 Клиент уже есть с картой в этой программе — вернули его.
JSON
{
  "status": "exists",
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "customer": {
    "id": 456,
    "name": "Анна",
    "phone": "+79991234567",
    "email": "anna@example.ru",
    "birthday": "1990-05-17",
    "gender": null,
    "custom_fields": {
    },
    "consent_accepted_at": "2026-03-02T10:15:00+03:00",
    "marketing_consent": true,
    "marketing_consent_at": "2026-03-02T10:15:00+03:00",
    "marketing_unsubscribed_at": null,
    "telegram_linked": false,
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "cards": [
      {
        "id": 123,
        "card_number": "AABBCCDD00000001",
        "status": "active",
        "customer_id": 456,
        "program_id": 7,
        "location_id": null,
        "cashback_balance": 75.0,
        "points_balance": 0.0,
        "stamps_count": 3,
        "rewards_available": 0,
        "total_spent": 12500.0,
        "total_visits": 14,
        "last_visit_at": "2026-10-24T12:30:00+03:00",
        "rfm_segment": "loyal",
        "created_at": "2026-03-02T10:15:00+03:00",
        "updated_at": "2026-10-24T12:30:00+03:00",
        "tier": {
          "name": "Серебро",
          "spend_base": 12500.0,
          "cashback_percent": 5.0,
          "points_percent": null,
          "discount_percent": null
        },
        "guest_status": null,
        "nearest_expiry": {
          "date": "2026-11-30T23:59:59+03:00",
          "cashback": 40.0,
          "points": 0.0,
          "stamps": 0
        },
        "visit_passes": [

        ],
        "membership": null,
        "wallet": {
          "state": "installed",
          "apple_wallet": true,
          "google_wallet": false,
          "telegram": false,
          "web_push": false,
          "installed_at": "2026-03-02T10:16:00+03:00",
          "uninstalled_at": null
        },
        "referred_by_card_id": null,
        "welcome_bonus_due_at": null
      }
    ]
  }
}
201 Клиент и карта созданы.
JSON
{
  "status": "created",
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "customer": {
    "id": 456,
    "name": "Анна",
    "phone": "+79991234567",
    "email": "anna@example.ru",
    "birthday": "1990-05-17",
    "gender": null,
    "custom_fields": {
    },
    "consent_accepted_at": "2026-03-02T10:15:00+03:00",
    "marketing_consent": true,
    "marketing_consent_at": "2026-03-02T10:15:00+03:00",
    "marketing_unsubscribed_at": null,
    "telegram_linked": false,
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "cards": [
      {
        "id": 123,
        "card_number": "AABBCCDD00000001",
        "status": "active",
        "customer_id": 456,
        "program_id": 7,
        "location_id": null,
        "cashback_balance": 75.0,
        "points_balance": 0.0,
        "stamps_count": 3,
        "rewards_available": 0,
        "total_spent": 12500.0,
        "total_visits": 14,
        "last_visit_at": "2026-10-24T12:30:00+03:00",
        "rfm_segment": "loyal",
        "created_at": "2026-03-02T10:15:00+03:00",
        "updated_at": "2026-10-24T12:30:00+03:00",
        "tier": {
          "name": "Серебро",
          "spend_base": 12500.0,
          "cashback_percent": 5.0,
          "points_percent": null,
          "discount_percent": null
        },
        "guest_status": null,
        "nearest_expiry": {
          "date": "2026-11-30T23:59:59+03:00",
          "cashback": 40.0,
          "points": 0.0,
          "stamps": 0
        },
        "visit_passes": [

        ],
        "membership": null,
        "wallet": {
          "state": "installed",
          "apple_wallet": true,
          "google_wallet": false,
          "telegram": false,
          "web_push": false,
          "installed_at": "2026-03-02T10:16:00+03:00",
          "uninstalled_at": null
        },
        "referred_by_card_id": null,
        "welcome_bonus_due_at": null
      }
    ]
  }
}
422 Не передан телефон или клиента нельзя создать.

Нет ни телефона, ни email

JSON
{
  "error": "parameter_missing",
  "message": "Передайте один из параметров: phone, email",
  "details": {
    "params": [
      "phone",
      "email"
    ]
  }
}

Поля нет в анкете программы

JSON
{
  "error": "parameter_invalid",
  "message": "Неизвестные поля анкеты: pet. Допустимы: car",
  "details": {
    "param": "custom_fields"
  }
}

Отказ по правилам Анкоры

JSON
{
  "error": "operation_rejected",
  "message": "Достигнут лимит карт вашего тарифа"
}

Ещё: 400, 401, 403, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Найти карту клиента

GET /customers/search

Карта клиента с балансами по любому идентификатору: телефону, номеру карты (например, с QR на кассе), id карты или клиента, id клиента во внешней системе.

Если у клиента карты в нескольких программах и program_id не передан, вернётся карта первой активной программы.

Параметры

ИмяГдеТипОписание
card_id строка запроса integer
card_number строка запроса string Номер карты, без учёта регистра и пробелов.
customer_id строка запроса integer
phone строка запроса string Телефон в любом российском формате.
external_customer_id строка запроса string Id клиента в вашей системе — если вы уже передавали его вместе с телефоном.
program_id строка запроса integer Программа лояльности, если у клиента карты в нескольких.

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

curl
curl https://ankora.pro/api/v2/public/customers/search \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Карта найдена.
JSON
{
  "found": true,
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  }
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Профиль клиента

GET /customers/{id}

Всё о клиенте — контакты, день рождения, поля анкеты, согласия — и все его карты целиком.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.

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

curl
curl https://ankora.pro/api/v2/public/customers/123 \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Профиль.
JSON
{
  "customer": {
    "id": 456,
    "name": "Анна",
    "phone": "+79991234567",
    "email": "anna@example.ru",
    "birthday": "1990-05-17",
    "gender": null,
    "custom_fields": {
    },
    "consent_accepted_at": "2026-03-02T10:15:00+03:00",
    "marketing_consent": true,
    "marketing_consent_at": "2026-03-02T10:15:00+03:00",
    "marketing_unsubscribed_at": null,
    "telegram_linked": false,
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "cards": [
      {
        "id": 123,
        "card_number": "AABBCCDD00000001",
        "status": "active",
        "customer_id": 456,
        "program_id": 7,
        "location_id": null,
        "cashback_balance": 75.0,
        "points_balance": 0.0,
        "stamps_count": 3,
        "rewards_available": 0,
        "total_spent": 12500.0,
        "total_visits": 14,
        "last_visit_at": "2026-10-24T12:30:00+03:00",
        "rfm_segment": "loyal",
        "created_at": "2026-03-02T10:15:00+03:00",
        "updated_at": "2026-10-24T12:30:00+03:00",
        "tier": {
          "name": "Серебро",
          "spend_base": 12500.0,
          "cashback_percent": 5.0,
          "points_percent": null,
          "discount_percent": null
        },
        "guest_status": null,
        "nearest_expiry": {
          "date": "2026-11-30T23:59:59+03:00",
          "cashback": 40.0,
          "points": 0.0,
          "stamps": 0
        },
        "visit_passes": [

        ],
        "membership": null,
        "wallet": {
          "state": "installed",
          "apple_wallet": true,
          "google_wallet": false,
          "telegram": false,
          "web_push": false,
          "installed_at": "2026-03-02T10:16:00+03:00",
          "uninstalled_at": null
        },
        "referred_by_card_id": null,
        "welcome_bonus_due_at": null
      }
    ]
  }
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Изменить профиль клиента

PATCH /customers/{id}

Меняет только переданные поля. Телефон и email, которые уже у другого клиента бизнеса, не принимаются — иначе карты двух людей склеятся. Изменения попадают в журнал действий кабинета.

Согласие на рекламные рассылки через API можно только отозвать (marketing_consent: false), дать его клиент должен сам — на карте или в форме регистрации.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
phone string | null Телефон в любом российском формате.
email string | null
name string | null
birthday string | null
gender string | null Значения: male, female, other
custom_fields object Поля анкеты сверх стандартных — ключи из registration_fields программы. При правке сливаются с записанными; пустое значение удаляет поле.
marketing_consent boolean Отзыв согласия на рекламу. Значения: false

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

curl
curl -X PATCH https://ankora.pro/api/v2/public/customers/123 \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"birthday":"1990-05-17","custom_fields":{"car":"Kia Rio"}}'

Ответы

200 Профиль обновлён.
JSON
{
  "customer": {
    "id": 456,
    "name": "Анна",
    "phone": "+79991234567",
    "email": "anna@example.ru",
    "birthday": "1990-05-17",
    "gender": null,
    "custom_fields": {
    },
    "consent_accepted_at": "2026-03-02T10:15:00+03:00",
    "marketing_consent": true,
    "marketing_consent_at": "2026-03-02T10:15:00+03:00",
    "marketing_unsubscribed_at": null,
    "telegram_linked": false,
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "cards": [
      {
        "id": 123,
        "card_number": "AABBCCDD00000001",
        "status": "active",
        "customer_id": 456,
        "program_id": 7,
        "location_id": null,
        "cashback_balance": 75.0,
        "points_balance": 0.0,
        "stamps_count": 3,
        "rewards_available": 0,
        "total_spent": 12500.0,
        "total_visits": 14,
        "last_visit_at": "2026-10-24T12:30:00+03:00",
        "rfm_segment": "loyal",
        "created_at": "2026-03-02T10:15:00+03:00",
        "updated_at": "2026-10-24T12:30:00+03:00",
        "tier": {
          "name": "Серебро",
          "spend_base": 12500.0,
          "cashback_percent": 5.0,
          "points_percent": null,
          "discount_percent": null
        },
        "guest_status": null,
        "nearest_expiry": {
          "date": "2026-11-30T23:59:59+03:00",
          "cashback": 40.0,
          "points": 0.0,
          "stamps": 0
        },
        "visit_passes": [

        ],
        "membership": null,
        "wallet": {
          "state": "installed",
          "apple_wallet": true,
          "google_wallet": false,
          "telegram": false,
          "web_push": false,
          "installed_at": "2026-03-02T10:16:00+03:00",
          "uninstalled_at": null
        },
        "referred_by_card_id": null,
        "welcome_bonus_due_at": null
      }
    ]
  }
}
422 Ошибка в полях, телефон или email заняты, согласие на рекламу нельзя дать.
JSON
{
  "error": "operation_rejected",
  "message": "Телефон +79991234567 уже у другого клиента (id 457)",
  "details": {
    "field": "phone",
    "customer_id": 457
  }
}
JSON
{
  "error": "parameter_invalid",
  "message": "Согласие на рекламу клиент даёт сам — на карте или в форме регистрации; через API его можно только отозвать",
  "details": {
    "param": "marketing_consent"
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Найти карту

GET /cards/lookup

Карта по любому идентификатору: телефону, номеру карты, id клиента или id клиента в вашей системе. Если у клиента карты в нескольких программах, передайте program_id — иначе ответ program_required со списком программ.

Параметры

ИмяГдеТипОписание
card_number строка запроса string Номер карты, без учёта регистра и пробелов.
customer_id строка запроса integer
phone строка запроса string Телефон в любом российском формате.
external_customer_id строка запроса string Id клиента в вашей системе — если вы уже передавали его вместе с телефоном.
program_id строка запроса integer Программа лояльности, если у клиента карты в нескольких.

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

curl
curl https://ankora.pro/api/v2/public/cards/lookup \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Карта.
JSON
{
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  }
}
422 Не передан идентификатор или нужна программа.

Карты в нескольких программах

JSON
{
  "error": "program_required",
  "message": "У клиента карты в нескольких программах — передайте program_id",
  "details": {
    "program_ids": [
      7,
      9
    ]
  }
}

Нет идентификатора

JSON
{
  "error": "parameter_missing",
  "message": "Передайте один из параметров: card_id, card_number, customer_id, phone, external_customer_id",
  "details": {
    "params": [
      "card_id",
      "card_number",
      "customer_id",
      "phone",
      "external_customer_id"
    ]
  }
}

Ещё: 401, 404, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Карта

GET /cards/{id}

Карта целиком — балансы, ступень, ближайшее сгорание, абонементы, подписка, Wallet.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.

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

curl
curl https://ankora.pro/api/v2/public/cards/123 \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Карта.
JSON
{
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  }
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Покупки и бонусы

Начисление за покупку и списание кэшбэка и баллов.

Рассчитать продажу

POST /cards/{id}/checkout/preview

Расчёт продажи без записи — то же, что покажет касса Анкоры: скидка по ступени клиента, сколько бонусов можно списать по этому чеку, сколько начислится с оплаченной суммы и сколько клиент платит деньгами. Ошибки — те же, что вернёт POST /cards/{id}/checkout, поэтому расчёт заодно проверяет списание.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.

Тело запроса

ПолеТипОписание
amountобяз. number | string Сумма чека до скидки, ₽.
redeem_cashback number | string Сколько кэшбэка списать в оплату, ₽ — не больше max_redeemable из расчёта.
redeem_points number | string Сколько баллов списать в оплату.
cashback_to_add number | string Ручной режим кэшбэка: сколько начислить — не больше max_manual_award.
points_to_add number | string Ручной режим баллов: сколько начислить — не больше max_manual_award.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/checkout/preview \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{"amount":1000,"redeem_cashback":100}'

Ответы

200 Расчёт.
JSON
{
  "amount": 1000.0,
  "discount_percent": 10.0,
  "discount_amount": 100.0,
  "after_discount": 900.0,
  "cashback": {
    "enabled": true,
    "available": 300.0,
    "max_redeemable": 300.0,
    "redeem": 100.0,
    "earn_percent": 10.0,
    "earn": 80.0,
    "auto_award": true,
    "max_manual_award": null
  },
  "points": {
    "enabled": false,
    "available": 0.0,
    "max_redeemable": 0.0,
    "redeem": 0.0,
    "earn_percent": 0.0,
    "earn": 0.0,
    "auto_award": false,
    "max_manual_award": null
  },
  "promotion_multipliers": {
    "cashback": 1.0,
    "points": 1.0
  },
  "to_pay": 800.0
}
422 Не хватает баланса, превышен лимит списания или ошибка в параметрах.

Больше лимита списания программы

JSON
{
  "error": "redemption_limit_exceeded",
  "message": "Списание кэшбэка по этому чеку — не больше 500 (50% от суммы после скидки)",
  "details": {
    "currency": "cashback",
    "max": 500.0,
    "requested": 600.0
  }
}

Не хватает баланса

JSON
{
  "error": "insufficient_balance",
  "message": "Недостаточно кэшбэка: на карте 300 ₽, запрошено 400 ₽",
  "details": {
    "currency": "cashback",
    "balance": 300.0,
    "requested": 400.0
  }
}

Нет номера чека

JSON
{
  "error": "parameter_missing",
  "message": "Не передан параметр external_id",
  "details": {
    "param": "external_id"
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Провести продажу

POST /cards/{id}/checkout

Продажа одним вызовом, как на кассе Анкоры: скидка по ступени → списание кэшбэка и баллов → покупка → начисление с суммы, оплаченной деньгами. Клиенту уходит одно уведомление.

external_id — номер чека: повтор с тем же номером вернёт skipped и не проведёт продажу второй раз, по нему же работает возврат POST /purchases/{external_id}/refund. Неудачная продажа номер не занимает.

Если программа в ручном режиме начисления, передайте cashback_to_add или points_to_add — не больше max_manual_award из расчёта.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
amountобяз. number | string Сумма чека до скидки, ₽.
redeem_cashback number | string Сколько кэшбэка списать в оплату, ₽ — не больше max_redeemable из расчёта.
redeem_points number | string Сколько баллов списать в оплату.
cashback_to_add number | string Ручной режим кэшбэка: сколько начислить — не больше max_manual_award.
points_to_add number | string Ручной режим баллов: сколько начислить — не больше max_manual_award.
external_idобяз. string Номер чека в вашей системе.
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/checkout \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"amount":1000,"redeem_cashback":200,"external_id":"CHEK-2026-000125","location_id":3}'

Ответы

200 Чек с этим external_id уже проведён.
JSON
{
  "status": "skipped",
  "reason": "already_processed"
}
201 Продажа проведена.
JSON
{
  "status": "completed",
  "external_id": "CHEK-2026-000125",
  "receipt": {
    "amount": 1000.0,
    "discount_amount": 0.0,
    "after_discount": 1000.0,
    "redeemed_cashback": 200.0,
    "redeemed_points": 0.0,
    "paid": 800.0,
    "earned_cashback": 80.0,
    "earned_points": 0.0
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9010,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "purchase_record",
      "operation_label": "Покупка",
      "mechanic": "purchase",
      "direction": "neutral",
      "amount": 1000.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": 1000.0,
      "description": "Покупка на 1000 ₽",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    },
    {
      "id": 9011,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "cashback_spend",
      "operation_label": "Списание кэшбека",
      "mechanic": "cashback",
      "direction": "debit",
      "amount": 200.0,
      "balance_before": 300.0,
      "balance_after": 100.0,
      "purchase_amount": null,
      "description": "Списание кэшбека при покупке",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": 9010,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    },
    {
      "id": 9012,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "cashback_earn",
      "operation_label": "Начисление кэшбека (за покупку)",
      "mechanic": "cashback",
      "direction": "credit",
      "amount": 80.0,
      "balance_before": 100.0,
      "balance_after": 180.0,
      "purchase_amount": 800.0,
      "description": "Начисление кэшбека при покупке",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": 9010,
      "expires_at": "2026-11-30T23:59:59+03:00",
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
422 Не хватает баланса, превышен лимит списания или ошибка в параметрах.

Больше лимита списания программы

JSON
{
  "error": "redemption_limit_exceeded",
  "message": "Списание кэшбэка по этому чеку — не больше 500 (50% от суммы после скидки)",
  "details": {
    "currency": "cashback",
    "max": 500.0,
    "requested": 600.0
  }
}

Не хватает баланса

JSON
{
  "error": "insufficient_balance",
  "message": "Недостаточно кэшбэка: на карте 300 ₽, запрошено 400 ₽",
  "details": {
    "currency": "cashback",
    "balance": 300.0,
    "requested": 400.0
  }
}

Нет номера чека

JSON
{
  "error": "parameter_missing",
  "message": "Не передан параметр external_id",
  "details": {
    "param": "external_id"
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Вернуть покупку

POST /purchases/{external_id}/refund

Возврат по номеру чека — продажи (POST /cards/{id}/checkout), покупки (POST /purchases) или списания (POST /redemptions с external_id). Снимает ровно то, что начислила эта покупка (с той ступенью и множителем акции, что действовали тогда), возвращает бонусы, списанные по чеку, и уменьшает сумму покупок клиента. Баланс в минус не уходит. Уведомление клиенту не отправляется.

Возврат может быть частичным: передайте amount и свой refund_id для каждого документа возврата — вместе они не вернут больше, чем было по чеку. Без refund_id возврат один, на весь чек.

Нужно право ключа «Возвраты и отмены».

Параметры

ИмяГдеТипОписание
external_idобяз. путь string Номер чека, переданный при продаже или покупке.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
refund_id string Номер документа возврата.
amount number | string Сумма возврата в деньгах чека; без неё — весь чек.

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

curl
curl -X POST https://ankora.pro/api/v2/public/purchases/CHEK-2026-000125/refund \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"refund_id":"VOZ-17","amount":400}'

Ответы

200 Возврат проведён — или этот документ возврата уже проведён.
JSON
{
  "status": "refunded",
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9020,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "cashback_spend",
      "operation_label": "Списание кэшбека",
      "mechanic": "cashback",
      "direction": "debit",
      "amount": 80.0,
      "balance_before": 180.0,
      "balance_after": 100.0,
      "purchase_amount": null,
      "description": "Возврат покупки №CHEK-2026-000125",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": 9010,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    },
    {
      "id": 9021,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "total_spent_decrease",
      "operation_label": "Уменьшение суммы покупок",
      "mechanic": "total_spent",
      "direction": "debit",
      "amount": 1000.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Возврат покупки №CHEK-2026-000125",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": 9010,
      "expires_at": null,
      "expired": false,
      "customer_visible": false,
      "created_at": "2026-10-24T12:30:00+03:00"
    },
    {
      "id": 9022,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "cashback_add",
      "operation_label": "Начисление кэшбека",
      "mechanic": "cashback",
      "direction": "credit",
      "amount": 200.0,
      "balance_before": 100.0,
      "balance_after": 300.0,
      "purchase_amount": null,
      "description": "Возврат покупки №CHEK-2026-000125: бонусы возвращены",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": 9011,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
JSON
{
  "status": "skipped",
  "reason": "already_processed"
}
403 Операция выключена в правах ключа, или подписка бизнеса истекла.

Нет права ключа

JSON
{
  "error": "permission_denied",
  "message": "Операция выключена в правах ключа: включите «Начисление вручную, установка и корректировка балансов, сумма покупок» в кабинете → Интеграции → «API и Zapier»",
  "details": {
    "permission": "balance_management"
  }
}

Подписка истекла

JSON
{
  "error": "subscription_required",
  "message": "Подписка бизнеса истекла — операция интеграции пропущена",
  "details": {
    "reason": "subscription_expired"
  }
}
404 Покупки с таким номером чека нет.
JSON
{
  "error": "not_found",
  "message": "Покупка с номером чека CHEK-1 не найдена",
  "details": {
    "resource": "purchase"
  }
}

Ещё: 400, 401, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Начислить вручную

POST /cards/{id}/balance/add

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

Это ручная операция владельца: правила программы и потолок накопления к ней не применяются. Нужно право ключа «Управление балансами».

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
currencyобяз. string Значения: cashback, points
amountобяз. number | string Сколько начислить: рубли кэшбэка или баллы.
expires_at string Когда сгорит начисленное: дата 2026-12-31 или время ISO 8601. Без него — бессрочно.
description string Текст в истории карты.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/balance/add \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"currency":"cashback","amount":200,"expires_at":"2026-11-30","description":"Спасибо за отзыв"}'

Ответы

201 Начислено.
JSON
{
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "cashback_add",
      "operation_label": "Начисление кэшбека",
      "mechanic": "cashback",
      "direction": "credit",
      "amount": 200.0,
      "balance_before": 0.0,
      "balance_after": 75.0,
      "purchase_amount": null,
      "description": "Спасибо за отзыв",
      "location_id": null,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": "2026-11-30T23:59:59+03:00",
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
403 Операция выключена в правах ключа, или подписка бизнеса истекла.

Нет права ключа

JSON
{
  "error": "permission_denied",
  "message": "Операция выключена в правах ключа: включите «Начисление вручную, установка и корректировка балансов, сумма покупок» в кабинете → Интеграции → «API и Zapier»",
  "details": {
    "permission": "balance_management"
  }
}

Подписка истекла

JSON
{
  "error": "subscription_required",
  "message": "Подписка бизнеса истекла — операция интеграции пропущена",
  "details": {
    "reason": "subscription_expired"
  }
}
422 Механика выключена или ошибка в параметрах.
JSON
{
  "error": "mechanic_disabled",
  "message": "Баллы выключены в программе «Кофейня»",
  "details": {
    "mechanic": "points"
  }
}
JSON
{
  "error": "parameter_invalid",
  "message": "Параметр currency: неизвестное значение rubles. Допустимо: cashback, points",
  "details": {
    "param": "currency"
  }
}

Ещё: 400, 401, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Списать

POST /cards/{id}/balance/spend

Списывает кэшбэк или баллы с карты, например когда вы применяете их как скидку у себя на кассе. Клиенту уходит уведомление о списании. Списать кэшбэк и баллы одним запросом можно через POST /redemptions или в продаже — POST /cards/{id}/checkout.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
currencyобяз. string Значения: cashback, points
amountобяз. number | string Сколько списать: рубли кэшбэка или баллы.
description string Текст в истории карты.
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/balance/spend \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"currency":"points","amount":150,"location_id":3}'

Ответы

200 Списано.
JSON
{
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "points_spend",
      "operation_label": "Списание баллов",
      "mechanic": "points",
      "direction": "debit",
      "amount": 150.0,
      "balance_before": 300.0,
      "balance_after": 150.0,
      "purchase_amount": null,
      "description": "Списание через API",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
422 Не хватает баланса или ошибка в параметрах.
JSON
{
  "error": "insufficient_balance",
  "message": "Недостаточно баллов: на карте 50, запрошено 150",
  "details": {
    "currency": "points",
    "balance": 50.0,
    "requested": 150.0
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Установить баланс

POST /cards/{id}/balance/set

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

Нужно право ключа «Управление балансами».

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
currencyобяз. string Значения: cashback, points
balanceобяз. number | string Каким должен стать баланс.
expires_at string Срок сгорания добавленной части.
description string

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/balance/set \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"currency":"points","balance":1240,"description":"Перенос из старой программы"}'

Ответы

200 Баланс установлен. Если он уже был таким, transactions пуст.
JSON
{
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "points_set",
      "operation_label": "Установка баланса баллов",
      "mechanic": "points",
      "direction": "credit",
      "amount": 1240.0,
      "balance_before": 0.0,
      "balance_after": 1240.0,
      "purchase_amount": null,
      "description": "Перенос из старой программы",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
403 Операция выключена в правах ключа, или подписка бизнеса истекла.

Нет права ключа

JSON
{
  "error": "permission_denied",
  "message": "Операция выключена в правах ключа: включите «Начисление вручную, установка и корректировка балансов, сумма покупок» в кабинете → Интеграции → «API и Zapier»",
  "details": {
    "permission": "balance_management"
  }
}

Подписка истекла

JSON
{
  "error": "subscription_required",
  "message": "Подписка бизнеса истекла — операция интеграции пропущена",
  "details": {
    "reason": "subscription_expired"
  }
}

Ещё: 400, 401, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Скорректировать баланс

POST /cards/{id}/balance/adjust

Прибавляет к балансу или отнимает от него delta: кэшбэк, баллы или штампы. Отнять больше, чем есть, нельзя — спишется остаток.

Нужно право ключа «Управление балансами».

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
currencyобяз. string Значения: cashback, points, stamps
deltaобяз. number | string Изменение со знаком, не ноль. Для штампов — целое.
description string

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/balance/adjust \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"currency":"cashback","delta":-50,"description":"Ошибочное начисление"}'

Ответы

200 Скорректировано.
JSON
{
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "cashback_adjust",
      "operation_label": "Корректировка кэшбека",
      "mechanic": "cashback",
      "direction": "debit",
      "amount": 50.0,
      "balance_before": 125.0,
      "balance_after": 75.0,
      "purchase_amount": null,
      "description": "Ошибочное начисление",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
403 Операция выключена в правах ключа, или подписка бизнеса истекла.

Нет права ключа

JSON
{
  "error": "permission_denied",
  "message": "Операция выключена в правах ключа: включите «Начисление вручную, установка и корректировка балансов, сумма покупок» в кабинете → Интеграции → «API и Zapier»",
  "details": {
    "permission": "balance_management"
  }
}

Подписка истекла

JSON
{
  "error": "subscription_required",
  "message": "Подписка бизнеса истекла — операция интеграции пропущена",
  "details": {
    "reason": "subscription_expired"
  }
}
422 Уменьшать нечего или ошибка в параметрах.
JSON
{
  "error": "insufficient_balance",
  "message": "Уменьшать нечего: на карте 0",
  "details": {
    "currency": "stamps",
    "balance": 0.0,
    "requested": 1.0
  }
}
JSON
{
  "error": "parameter_invalid",
  "message": "Параметр delta не может быть нулём",
  "details": {
    "param": "delta"
  }
}

Ещё: 400, 401, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Изменить сумму покупок

PUT /cards/{id}/total_spent

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

Нужно право ключа «Управление балансами».

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
total_spentобяз. number | string Какой должна стать сумма покупок, ₽.
reason string Причина — попадёт в журнал изменений.

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

curl
curl -X PUT https://ankora.pro/api/v2/public/cards/123/total_spent \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"total_spent":15000,"reason":"Чеки со старой карты"}'

Ответы

200 Сумма покупок изменена.
JSON
{
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "total_spent_increase",
      "operation_label": "Увеличение суммы покупок",
      "mechanic": "total_spent",
      "direction": "credit",
      "amount": 2500.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Чеки со старой карты",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": false,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
403 Операция выключена в правах ключа, или подписка бизнеса истекла.

Нет права ключа

JSON
{
  "error": "permission_denied",
  "message": "Операция выключена в правах ключа: включите «Начисление вручную, установка и корректировка балансов, сумма покупок» в кабинете → Интеграции → «API и Zapier»",
  "details": {
    "permission": "balance_management"
  }
}

Подписка истекла

JSON
{
  "error": "subscription_required",
  "message": "Подписка бизнеса истекла — операция интеграции пропущена",
  "details": {
    "reason": "subscription_expired"
  }
}

Ещё: 400, 401, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Начислить за покупку

POST /purchases

Главный метод для кассы и 1С: на каждый чек передайте сумму покупки, Анкора сама начислит кэшбэк и баллы по правилам программы — с учётом ступени клиента, идущих акций и потолка накопления. Штампы за покупку не начисляются, для них есть POST /stamps.

external_id — номер чека или заказа в вашей системе. Повтор с тем же external_id не начислит второй раз и вернёт skipped с причиной already_processed, так что повторять запрос после сбоя сети безопасно.

Если клиент передан телефоном или внешним id и не найден, ответ — skipped со статусом 200: покупка человека не из программы — обычное событие для кассы. Если передан card_id, card_number или customer_id и такой карты нет — ошибка 404.

Параметры

ИмяГдеТипОписание
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
card_id integer Id карты в Анкоре.
card_number string Номер карты
customer_id integer Id клиента в Анкоре.
phone string Телефон в любом российском формате.
external_customer_id string Id клиента в вашей системе.
program_id integer Программа лояльности.
external_idобяз. string Номер чека или заказа в вашей системе — защита от двойного начисления.
amountобяз. number | string Сумма покупки, ₽.
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/purchases \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"phone":"+79991234567","external_id":"CHEK-2026-000123","amount":1500}'

Ответы

200 Покупка принята, но ничего не начислено.

Чек уже обработан

JSON
{
  "status": "skipped",
  "reason": "already_processed"
}

Клиента нет в программе

JSON
{
  "status": "skipped",
  "reason": "no_customer"
}
201 Начислено.
JSON
{
  "status": "applied",
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  }
}
422 Ошибка в параметрах.

Нет номера чека

JSON
{
  "error": "parameter_missing",
  "message": "Не передан параметр external_id",
  "details": {
    "param": "external_id"
  }
}

Сумма не больше нуля

JSON
{
  "error": "parameter_invalid",
  "message": "Параметр amount должен быть больше нуля",
  "details": {
    "param": "amount"
  }
}

Карты в нескольких программах

JSON
{
  "error": "program_required",
  "message": "У клиента карты в нескольких программах — передайте program_id",
  "details": {
    "program_ids": [
      7,
      9
    ]
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Списать кэшбэк или баллы

POST /redemptions

Списывает бонусы клиента, которые вы применяете как скидку у себя на кассе. Можно списать кэшбэк, баллы или и то и другое одним запросом.

Списание атомарно: если чего-то не хватает, не списывается ничего. Клиенту уходит одно уведомление о списании. Чтобы повтор запроса после сбоя сети не списал второй раз, передавайте заголовок Idempotency-Key.

Параметры

ИмяГдеТипОписание
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
card_id integer Id карты в Анкоре.
card_number string Номер карты
customer_id integer Id клиента в Анкоре.
phone string Телефон в любом российском формате.
external_customer_id string Id клиента в вашей системе.
program_id integer Программа лояльности.
cashback_amount number | string Сколько кэшбэка списать, ₽.
points_amount number | string Сколько баллов списать.
location_id integer Точка продажи — операция попадёт в аналитику по точкам.
external_id string Номер чека. Повтор с тем же номером не спишет второй раз; возврат покупки с этим номером (POST /purchases/{external_id}/refund) вернёт списанное.

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

curl
curl -X POST https://ankora.pro/api/v2/public/redemptions \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"phone":"+79991234567","cashback_amount":50}'

Ответы

200 Списано — или чек с этим external_id уже обработан.
JSON
{
  "status": "redeemed",
  "redeemed": {
    "cashback": 50.0
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  }
}

Повтор того же чека

JSON
{
  "status": "skipped",
  "reason": "already_processed"
}
422 Не хватает баланса или ошибка в параметрах. Ничего не списано.

Не хватает кэшбэка

JSON
{
  "error": "insufficient_balance",
  "message": "Недостаточно кэшбэка: на карте 25 ₽, запрошено 50 ₽",
  "details": {
    "currency": "cashback",
    "balance": 25.0,
    "requested": 50.0
  }
}

Не передана сумма

JSON
{
  "error": "parameter_missing",
  "message": "Передайте один из параметров: cashback_amount, points_amount",
  "details": {
    "params": [
      "cashback_amount",
      "points_amount"
    ]
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Штампы

Штампы и награды за них.

Начислить штампы на карту

POST /cards/{id}/stamps

Добавляет штампы. Во время акции «двойные штампы» начисляется больше — фактическое число в count. Набралось на награду — она появится в card.rewards_available.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
count integer
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/stamps \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"count":1,"location_id":3}'

Ответы

201 Начислено.
JSON
{
  "count": 1,
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "stamp_add",
      "operation_label": "Добавление штампа",
      "mechanic": "stamps",
      "direction": "credit",
      "amount": 1.0,
      "balance_before": 2.0,
      "balance_after": 3.0,
      "purchase_amount": null,
      "description": "Штамп",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
422 Штампы выключены или ошибка в параметрах.
JSON
{
  "error": "mechanic_disabled",
  "message": "Штампы выключены в программе «Кофейня»",
  "details": {
    "mechanic": "stamps"
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Снять штампы

POST /cards/{id}/stamps/remove

Снимает ошибочно поставленные штампы. Если просят больше, чем есть, снимаются все — partial будет true.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
count integer
reason string Текст в истории карты.
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/stamps/remove \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"count":1,"reason":"Ошибка кассира"}'

Ответы

200 Сняты.
JSON
{
  "removed": 1,
  "partial": false,
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "stamp_adjust",
      "operation_label": "Корректировка штампов",
      "mechanic": "stamps",
      "direction": "debit",
      "amount": 1.0,
      "balance_before": 4.0,
      "balance_after": 3.0,
      "purchase_amount": null,
      "description": "Ошибка кассира",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
422 На карте нет штампов.
JSON
{
  "error": "insufficient_balance",
  "message": "На карте нет штампов для списания",
  "details": {
    "currency": "stamps",
    "balance": 0,
    "requested": 1
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Выдать награду

POST /cards/{id}/rewards/redeem

Списывает одну доступную награду за штампы.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/rewards/redeem \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)"

Ответы

200 Награда выдана.
JSON
{
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "reward_use",
      "operation_label": "Использование награды",
      "mechanic": "stamps",
      "direction": "debit",
      "amount": 1.0,
      "balance_before": 1.0,
      "balance_after": 0.0,
      "purchase_amount": null,
      "description": "Использована награда: Капучино в подарок",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
422 Нет доступной награды.
JSON
{
  "error": "insufficient_balance",
  "message": "Нет доступных наград: соберите 6 штампов",
  "details": {
    "currency": "rewards",
    "balance": 0,
    "requested": 1
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Начислить штампы

POST /stamps

Добавляет штампы на карту. Когда штампов набирается на награду, у клиента появляется доступная награда (rewards_available). Во время акции «двойные штампы» начисляется больше запрошенного — фактическое число приходит в count.

Параметры

ИмяГдеТипОписание
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
card_id integer Id карты в Анкоре.
card_number string Номер карты
customer_id integer Id клиента в Анкоре.
phone string Телефон в любом российском формате.
external_customer_id string Id клиента в вашей системе.
program_id integer Программа лояльности.
count integer Сколько штампов начислить.
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/stamps \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"card_number":"AABBCCDD00000001"}'

Ответы

201 Штампы начислены.
JSON
{
  "status": "added",
  "count": 1,
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  }
}
422 Штампы выключены в программе или ошибка в параметрах.

Штампы выключены

JSON
{
  "error": "mechanic_disabled",
  "message": "Штампы выключены в программе «Кофейня»",
  "details": {
    "mechanic": "stamps"
  }
}

Неверное количество

JSON
{
  "error": "parameter_invalid",
  "message": "Параметр count должен быть не меньше 1",
  "details": {
    "param": "count"
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Выдать награду за штампы

POST /stamp_redemptions

Списывает одну доступную награду (например, «Капучино в подарок»).

Параметры

ИмяГдеТипОписание
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
card_id integer Id карты в Анкоре.
card_number string Номер карты
customer_id integer Id клиента в Анкоре.
phone string Телефон в любом российском формате.
external_customer_id string Id клиента в вашей системе.
program_id integer Программа лояльности.

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

curl
curl -X POST https://ankora.pro/api/v2/public/stamp_redemptions \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"card_id":123}'

Ответы

200 Награда выдана.
JSON
{
  "status": "redeemed",
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  }
}
422 Нет доступной награды.
JSON
{
  "error": "insufficient_balance",
  "message": "Нет доступных наград: соберите 6 штампов",
  "details": {
    "currency": "rewards",
    "balance": 0,
    "requested": 1
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Абонементы

Пакеты визитов — продажа, визиты, заморозка, возврат.

Продать абонемент

POST /cards/{id}/visit_passes

Продаёт абонемент — пакет визитов — на карту. Если в программе включено «Начислять кэшбэк за абонемент», за продажу начисляется кэшбэк, а сумма попадает в сумму покупок.

expires_at: не передан — срок по умолчанию из настроек программы; null — бессрочный; дата или время — свой срок.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
titleобяз. string Название абонемента.
total_visitsобяз. integer Сколько визитов в абонементе.
priceобяз. number | string Цена абонемента, ₽.
expires_at string | null
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/visit_passes \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"title":"10 занятий","total_visits":10,"price":5000,"expires_at":"2026-12-31"}'

Ответы

201 Абонемент продан.
JSON
{
  "visit_pass": {
    "id": 41,
    "card_id": 123,
    "title": "10 занятий",
    "state": "active",
    "total_visits": 10,
    "used_visits": 0,
    "remaining_visits": 10,
    "price": 5000.0,
    "expires_at": "2026-12-31T00:00:00+03:00",
    "frozen_since": null,
    "last_usage_id": null,
    "created_at": "2026-10-24T12:00:00+03:00"
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "visit_pass_issue",
      "operation_label": "Продажа абонемента",
      "mechanic": "visit_pass",
      "direction": "credit",
      "amount": 10.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Продан абонемент: 10 занятий",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
422 Абонементы выключены или ошибка в параметрах.
JSON
{
  "error": "mechanic_disabled",
  "message": "Абонементы выключены в программе «Кофейня»",
  "details": {
    "mechanic": "visit_passes"
  }
}
JSON
{
  "error": "parameter_missing",
  "message": "Не передан параметр total_visits",
  "details": {
    "param": "total_visits"
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Абонемент

GET /visit_passes/{id}

Абонемент с историей визитов.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.

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

curl
curl https://ankora.pro/api/v2/public/visit_passes/123 \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Абонемент.
JSON
{
  "visit_pass": {
    "id": 41,
    "card_id": 123,
    "title": "10 занятий",
    "state": "active",
    "total_visits": 10,
    "used_visits": 1,
    "remaining_visits": 9,
    "price": 5000.0,
    "expires_at": "2026-12-31T00:00:00+03:00",
    "frozen_since": null,
    "last_usage_id": 77,
    "created_at": "2026-10-24T12:00:00+03:00"
  },
  "usages": [
    {
      "id": 77,
      "used_at": "2026-10-24T18:00:00+03:00",
      "reversed": false,
      "reversed_at": null
    }
  ]
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Засчитать визит

POST /visit_passes/{id}/use

Списывает один визит. Последний визит закрывает абонемент (state = exhausted). Замороженный, истёкший и исчерпанный абонемент визит не принимает.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/visit_passes/123/use \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"location_id":3}'

Ответы

200 Визит засчитан.
JSON
{
  "visit_pass": {
    "id": 41,
    "card_id": 123,
    "title": "10 занятий",
    "state": "active",
    "total_visits": 10,
    "used_visits": 1,
    "remaining_visits": 9,
    "price": 5000.0,
    "expires_at": "2026-12-31T00:00:00+03:00",
    "frozen_since": null,
    "last_usage_id": 77,
    "created_at": "2026-10-24T12:00:00+03:00"
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "visit_pass_use",
      "operation_label": "Списан визит абонемента",
      "mechanic": "visit_pass",
      "direction": "debit",
      "amount": 1.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Списан визит: 10 занятий",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Отменить визит

POST /visit_pass_usages/{id}/reverse

Возвращает ошибочно списанный визит на абонемент.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
reason string

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

curl
curl -X POST https://ankora.pro/api/v2/public/visit_pass_usages/123/reverse \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Отметили по ошибке"}'

Ответы

200 Визит отменён.
JSON
{
  "visit_pass": {
    "id": 41,
    "card_id": 123,
    "title": "10 занятий",
    "state": "active",
    "total_visits": 10,
    "used_visits": 0,
    "remaining_visits": 10,
    "price": 5000.0,
    "expires_at": "2026-12-31T00:00:00+03:00",
    "frozen_since": null,
    "last_usage_id": null,
    "created_at": "2026-10-24T12:00:00+03:00"
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "visit_pass_reverse",
      "operation_label": "Отмена визита абонемента",
      "mechanic": "visit_pass",
      "direction": "credit",
      "amount": 1.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Визит восстановлен: 10 занятий",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Заморозить абонемент

POST /visit_passes/{id}/freeze

Ставит абонемент на паузу — например, клиент уехал в отпуск. Пока абонемент заморожен, визиты не списываются.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
reason string

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

curl
curl -X POST https://ankora.pro/api/v2/public/visit_passes/123/freeze \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Отпуск"}'

Ответы

200 Заморожен.
JSON
{
  "visit_pass": {
    "id": 41,
    "card_id": 123,
    "title": "10 занятий",
    "state": "frozen",
    "total_visits": 10,
    "used_visits": 1,
    "remaining_visits": 9,
    "price": 5000.0,
    "expires_at": "2026-12-31T00:00:00+03:00",
    "frozen_since": "2026-10-24T12:00:00+03:00",
    "last_usage_id": 77,
    "created_at": "2026-10-24T12:00:00+03:00"
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [

  ]
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Разморозить абонемент

POST /visit_passes/{id}/unfreeze

Снимает заморозку.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

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

curl
curl -X POST https://ankora.pro/api/v2/public/visit_passes/123/unfreeze \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)"

Ответы

200 Разморожен.
JSON
{
  "visit_pass": {
    "id": 41,
    "card_id": 123,
    "title": "10 занятий",
    "state": "active",
    "total_visits": 10,
    "used_visits": 1,
    "remaining_visits": 9,
    "price": 5000.0,
    "expires_at": "2026-12-31T00:00:00+03:00",
    "frozen_since": null,
    "last_usage_id": 77,
    "created_at": "2026-10-24T12:00:00+03:00"
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [

  ]
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Рассчитать возврат абонемента

GET /visit_passes/{id}/refund_preview

Сколько денег вернуть за неиспользованные визиты — без записи.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
partial_amount строка запроса number Своя сумма возврата вместо расчётной.

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

curl
curl https://ankora.pro/api/v2/public/visit_passes/123/refund_preview \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Расчёт.
JSON
{
  "visit_pass_id": 41,
  "refund_amount": 4500.0,
  "remaining_visits": 9,
  "total_visits": 10
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Вернуть абонемент

POST /visit_passes/{id}/refund

Закрывает абонемент с возвратом денег за неиспользованные визиты (state = refunded). Деньги возвращаете вы — Анкора фиксирует возврат и сумму. Нужно право ключа «Возвраты и отмены».

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
partial_amount number | string Своя сумма возврата вместо расчётной, ₽.

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

curl
curl -X POST https://ankora.pro/api/v2/public/visit_passes/123/refund \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"partial_amount":4000}'

Ответы

200 Абонемент возвращён.
JSON
{
  "visit_pass": {
    "id": 41,
    "card_id": 123,
    "title": "10 занятий",
    "state": "refunded",
    "total_visits": 10,
    "used_visits": 1,
    "remaining_visits": 9,
    "price": 5000.0,
    "expires_at": "2026-12-31T00:00:00+03:00",
    "frozen_since": null,
    "last_usage_id": 77,
    "created_at": "2026-10-24T12:00:00+03:00"
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "visit_pass_refund",
      "operation_label": "Возврат за абонемент",
      "mechanic": "visit_pass",
      "direction": "debit",
      "amount": 4500.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Возврат абонемента: 10 занятий",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
403 Операция выключена в правах ключа, или подписка бизнеса истекла.

Нет права ключа

JSON
{
  "error": "permission_denied",
  "message": "Операция выключена в правах ключа: включите «Начисление вручную, установка и корректировка балансов, сумма покупок» в кабинете → Интеграции → «API и Zapier»",
  "details": {
    "permission": "balance_management"
  }
}

Подписка истекла

JSON
{
  "error": "subscription_required",
  "message": "Подписка бизнеса истекла — операция интеграции пропущена",
  "details": {
    "reason": "subscription_expired"
  }
}

Ещё: 400, 401, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Подписки

Подписки клиентов с лимитами действий.

Продать подписку

POST /cards/{id}/memberships

Продаёт подписку по шаблону программы (шаблоны — в GET /programs/{id}, memberships.plans). У клиента может быть одна действующая подписка.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
plan_idобяз. integer Шаблон подписки.
sale_price number | string Цена продажи, ₽; без неё — цена из шаблона.
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/memberships \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"plan_id":11,"sale_price":3500}'

Ответы

201 Подписка продана.
JSON
{
  "membership": {
    "id": 51,
    "card_id": 123,
    "plan_id": 11,
    "name": "Безлимит на месяц",
    "status": "active",
    "started_at": "2026-10-24T12:00:00+03:00",
    "ends_at": "2026-11-23T12:00:00+03:00",
    "remaining_days": 30,
    "duration_days": 30,
    "sale_price": 3500.0,
    "overall_limit_count": null,
    "overall_limit_period_days": null,
    "paused_since": null,
    "actions": [
      {
        "id": 61,
        "label": "Тренировка",
        "limit_count": 1,
        "limit_period_days": 1,
        "used_in_window": 1,
        "remaining": 0,
        "window": "rolling"
      }
    ]
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "membership_issue",
      "operation_label": "Продажа подписки",
      "mechanic": "membership",
      "direction": "neutral",
      "amount": 3500.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Продана подписка: Безлимит на месяц",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
422 Подписки выключены, у клиента уже есть подписка или ошибка в параметрах.
JSON
{
  "error": "mechanic_disabled",
  "message": "Подписки выключены в программе «Кофейня»",
  "details": {
    "mechanic": "memberships"
  }
}
JSON
{
  "error": "operation_rejected",
  "message": "У клиента уже есть активная подписка"
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Подписка

GET /memberships/{id}

Подписка с действиями и остатком лимитов.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.

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

curl
curl https://ankora.pro/api/v2/public/memberships/123 \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Подписка.
JSON
{
  "membership": {
    "id": 51,
    "card_id": 123,
    "plan_id": 11,
    "name": "Безлимит на месяц",
    "status": "active",
    "started_at": "2026-10-24T12:00:00+03:00",
    "ends_at": "2026-11-23T12:00:00+03:00",
    "remaining_days": 30,
    "duration_days": 30,
    "sale_price": 3500.0,
    "overall_limit_count": null,
    "overall_limit_period_days": null,
    "paused_since": null,
    "actions": [
      {
        "id": 61,
        "label": "Тренировка",
        "limit_count": 1,
        "limit_period_days": 1,
        "used_in_window": 1,
        "remaining": 0,
        "window": "rolling"
      }
    ]
  }
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Использовать действие

POST /memberships/{id}/actions/{action_id}/use

Отмечает использование действия подписки (например, «Тренировка»). Лимит действия или подписки исчерпан — ошибка limit_reached; force: true отметит сверх лимита (как кнопка «всё равно отметить» у кассира).

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
action_idобяз. путь integer
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
force boolean
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/memberships/123/actions/61/use \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"location_id":3}'

Ответы

200 Действие отмечено.
JSON
{
  "membership": {
    "id": 51,
    "card_id": 123,
    "plan_id": 11,
    "name": "Безлимит на месяц",
    "status": "active",
    "started_at": "2026-10-24T12:00:00+03:00",
    "ends_at": "2026-11-23T12:00:00+03:00",
    "remaining_days": 30,
    "duration_days": 30,
    "sale_price": 3500.0,
    "overall_limit_count": null,
    "overall_limit_period_days": null,
    "paused_since": null,
    "actions": [
      {
        "id": 61,
        "label": "Тренировка",
        "limit_count": 1,
        "limit_period_days": 1,
        "used_in_window": 1,
        "remaining": 0,
        "window": "rolling"
      }
    ]
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "membership_use",
      "operation_label": "Использование подписки",
      "mechanic": "membership",
      "direction": "debit",
      "amount": 1.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Тренировка",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
422 Лимит исчерпан или подписка не действует.
JSON
{
  "error": "limit_reached",
  "message": "Лимит исчерпан"
}
JSON
{
  "error": "operation_rejected",
  "message": "Подписка на паузе"
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Продлить подписку

POST /memberships/{id}/extend

Продлевает подписку на срок шаблона. price — цена продления; по умолчанию — из шаблона.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
price number | string Цена продления, ₽; без неё — из шаблона.
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/memberships/123/extend \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"price":3000}'

Ответы

200 Продлена.
JSON
{
  "membership": {
    "id": 51,
    "card_id": 123,
    "plan_id": 11,
    "name": "Безлимит на месяц",
    "status": "active",
    "started_at": "2026-10-24T12:00:00+03:00",
    "ends_at": "2026-12-23T12:00:00+03:00",
    "remaining_days": 60,
    "duration_days": 30,
    "sale_price": 3500.0,
    "overall_limit_count": null,
    "overall_limit_period_days": null,
    "paused_since": null,
    "actions": [
      {
        "id": 61,
        "label": "Тренировка",
        "limit_count": 1,
        "limit_period_days": 1,
        "used_in_window": 1,
        "remaining": 0,
        "window": "rolling"
      }
    ]
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "membership_extend",
      "operation_label": "Продление подписки",
      "mechanic": "membership",
      "direction": "neutral",
      "amount": 3000.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Продлена подписка: Безлимит на месяц",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Поставить на паузу

POST /memberships/{id}/pause

Пауза останавливает срок подписки; после возобновления дни паузы добавляются к сроку.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
reason string

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

curl
curl -X POST https://ankora.pro/api/v2/public/memberships/123/pause \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Болеет"}'

Ответы

200 На паузе.
JSON
{
  "membership": {
    "id": 51,
    "card_id": 123,
    "plan_id": 11,
    "name": "Безлимит на месяц",
    "status": "paused",
    "started_at": "2026-10-24T12:00:00+03:00",
    "ends_at": "2026-11-23T12:00:00+03:00",
    "remaining_days": 30,
    "duration_days": 30,
    "sale_price": 3500.0,
    "overall_limit_count": null,
    "overall_limit_period_days": null,
    "paused_since": "2026-10-24T12:00:00+03:00",
    "actions": [
      {
        "id": 61,
        "label": "Тренировка",
        "limit_count": 1,
        "limit_period_days": 1,
        "used_in_window": 1,
        "remaining": 0,
        "window": "rolling"
      }
    ]
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [

  ]
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Снять с паузы

POST /memberships/{id}/resume

Возобновляет подписку после паузы.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

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

curl
curl -X POST https://ankora.pro/api/v2/public/memberships/123/resume \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)"

Ответы

200 Возобновлена.
JSON
{
  "membership": {
    "id": 51,
    "card_id": 123,
    "plan_id": 11,
    "name": "Безлимит на месяц",
    "status": "active",
    "started_at": "2026-10-24T12:00:00+03:00",
    "ends_at": "2026-11-23T12:00:00+03:00",
    "remaining_days": 30,
    "duration_days": 30,
    "sale_price": 3500.0,
    "overall_limit_count": null,
    "overall_limit_period_days": null,
    "paused_since": null,
    "actions": [
      {
        "id": 61,
        "label": "Тренировка",
        "limit_count": 1,
        "limit_period_days": 1,
        "used_in_window": 1,
        "remaining": 0,
        "window": "rolling"
      }
    ]
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [

  ]
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Отменить подписку

POST /memberships/{id}/cancel

Отменяет подписку, при необходимости — с возвратом денег (refund_amount; деньги возвращаете вы). Нужно право ключа «Возвраты и отмены».

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
refund_amount number | string Сколько денег вернули клиенту, ₽ — для учёта.
reason string
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/memberships/123/cancel \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"refund_amount":1000,"reason":"Переезд"}'

Ответы

200 Отменена.
JSON
{
  "membership": {
    "id": 51,
    "card_id": 123,
    "plan_id": 11,
    "name": "Безлимит на месяц",
    "status": "cancelled",
    "started_at": "2026-10-24T12:00:00+03:00",
    "ends_at": "2026-11-23T12:00:00+03:00",
    "remaining_days": 30,
    "duration_days": 30,
    "sale_price": 3500.0,
    "overall_limit_count": null,
    "overall_limit_period_days": null,
    "paused_since": null,
    "actions": [
      {
        "id": 61,
        "label": "Тренировка",
        "limit_count": 1,
        "limit_period_days": 1,
        "used_in_window": 1,
        "remaining": 0,
        "window": "rolling"
      }
    ]
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "membership_cancel_refund",
      "operation_label": "Возврат за подписку",
      "mechanic": "membership",
      "direction": "debit",
      "amount": 1000.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Отмена подписки: Безлимит на месяц",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
403 Операция выключена в правах ключа, или подписка бизнеса истекла.

Нет права ключа

JSON
{
  "error": "permission_denied",
  "message": "Операция выключена в правах ключа: включите «Начисление вручную, установка и корректировка балансов, сумма покупок» в кабинете → Интеграции → «API и Zapier»",
  "details": {
    "permission": "balance_management"
  }
}

Подписка истекла

JSON
{
  "error": "subscription_required",
  "message": "Подписка бизнеса истекла — операция интеграции пропущена",
  "details": {
    "reason": "subscription_expired"
  }
}

Ещё: 400, 401, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Статус гостя

Визиты, по которым растёт статус гостя.

Засчитать визит

POST /cards/{id}/guest_visits

Засчитывает визит для статуса гостя. Не больше одного визита в день — повтор вернёт limit_reached. Дошёл до нового статуса — клиенту уходит поздравление.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
location_id integer Точка продажи — операция попадёт в аналитику по точкам.

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

curl
curl -X POST https://ankora.pro/api/v2/public/cards/123/guest_visits \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"location_id":3}'

Ответы

201 Визит засчитан.
JSON
{
  "guest_visit": {
    "id": 81,
    "card_id": 123,
    "source": "manual",
    "visited_at": "2026-10-24T12:00:00+03:00",
    "reversed_at": null
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "guest_visit_record",
      "operation_label": "Засчитан визит гостя",
      "mechanic": "guest_visit",
      "direction": "credit",
      "amount": 1.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Засчитан визит",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}
422 Визит уже засчитан сегодня или статус гостя выключен.
JSON
{
  "error": "limit_reached",
  "message": "Гость уже отмечен сегодня"
}
JSON
{
  "error": "mechanic_disabled",
  "message": "Статус гостя выключен в программе «Кофейня»",
  "details": {
    "mechanic": "guest_status"
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Отменить визит

POST /guest_visits/{id}/reverse

Отменяет ошибочно засчитанный визит.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
reason string

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

curl
curl -X POST https://ankora.pro/api/v2/public/guest_visits/123/reverse \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Отметили по ошибке"}'

Ответы

200 Визит отменён.
JSON
{
  "guest_visit": {
    "id": 81,
    "card_id": 123,
    "source": "manual",
    "visited_at": "2026-10-24T12:00:00+03:00",
    "reversed_at": "2026-10-24T12:05:00+03:00"
  },
  "card": {
    "id": 123,
    "card_number": "AABBCCDD00000001",
    "status": "active",
    "customer_id": 456,
    "program_id": 7,
    "location_id": null,
    "cashback_balance": 75.0,
    "points_balance": 0.0,
    "stamps_count": 3,
    "rewards_available": 0,
    "total_spent": 12500.0,
    "total_visits": 14,
    "last_visit_at": "2026-10-24T12:30:00+03:00",
    "rfm_segment": "loyal",
    "created_at": "2026-03-02T10:15:00+03:00",
    "updated_at": "2026-10-24T12:30:00+03:00",
    "tier": {
      "name": "Серебро",
      "spend_base": 12500.0,
      "cashback_percent": 5.0,
      "points_percent": null,
      "discount_percent": null
    },
    "guest_status": null,
    "nearest_expiry": {
      "date": "2026-11-30T23:59:59+03:00",
      "cashback": 40.0,
      "points": 0.0,
      "stamps": 0
    },
    "visit_passes": [

    ],
    "membership": null,
    "wallet": {
      "state": "installed",
      "apple_wallet": true,
      "google_wallet": false,
      "telegram": false,
      "web_push": false,
      "installed_at": "2026-03-02T10:16:00+03:00",
      "uninstalled_at": null
    },
    "referred_by_card_id": null,
    "welcome_bonus_due_at": null
  },
  "transactions": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "guest_visit_reverse",
      "operation_label": "Отменён визит гостя",
      "mechanic": "guest_visit",
      "direction": "debit",
      "amount": 1.0,
      "balance_before": null,
      "balance_after": null,
      "purchase_amount": null,
      "description": "Визит отменён",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": null,
      "expires_at": null,
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Операции

История всех движений по картам.

История карты

GET /cards/{id}/transactions

Операции по одной карте страницами по возрастанию id. Фильтры — как у GET /transactions.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
limit строка запроса integer Сколько записей на странице, от 1 до 100.
after_id строка запроса integer Вернуть записи с id больше этого — значение next_after_id из предыдущей страницы.
operation строка запроса string Тип операции; несколько — через запятую.
location_id строка запроса integer
created_since строка запроса string
created_until строка запроса string

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

curl
curl https://ankora.pro/api/v2/public/cards/123/transactions \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Страница операций карты.
JSON
{
  "data": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "cashback_earn",
      "operation_label": "Начисление кэшбека (за покупку)",
      "mechanic": "cashback",
      "direction": "credit",
      "amount": 75.0,
      "balance_before": 0.0,
      "balance_after": 75.0,
      "purchase_amount": 1500.0,
      "description": "Кэшбэк 5% с покупки",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": 9000,
      "expires_at": "2026-11-30T23:59:59+03:00",
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ],
  "has_more": false,
  "next_after_id": 9001
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

История операций

GET /transactions

Все движения по картам бизнеса страницами по возрастанию id: покупки, начисления, списания, сгорания, корректировки, абонементы, подписки, визиты.

Для регулярного забора новых операций храните последний полученный id и передавайте его в after_id.

Параметры

ИмяГдеТипОписание
limit строка запроса integer Сколько записей на странице, от 1 до 100.
after_id строка запроса integer Вернуть записи с id больше этого — значение next_after_id из предыдущей страницы.
since_id строка запроса integer Старое имя after_id, работает так же.
card_id строка запроса integer
customer_id строка запроса integer Операции по всем картам клиента.
program_id строка запроса integer
location_id строка запроса integer Операции в точке продажи.
operation строка запроса string Тип операции; несколько — через запятую, например cashback_earn,cashback_spend.
created_since строка запроса string Не раньше этого момента. Дата 2026-10-01 или время ISO 8601.
created_until строка запроса string Раньше этого момента. Дата 2026-10-01 или время ISO 8601.

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

curl
curl https://ankora.pro/api/v2/public/transactions \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Страница операций.
JSON
{
  "data": [
    {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "cashback_earn",
      "operation_label": "Начисление кэшбека (за покупку)",
      "mechanic": "cashback",
      "direction": "credit",
      "amount": 75.0,
      "balance_before": 0.0,
      "balance_after": 75.0,
      "purchase_amount": 1500.0,
      "description": "Кэшбэк 5% с покупки",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": 9000,
      "expires_at": "2026-11-30T23:59:59+03:00",
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ],
  "has_more": false,
  "next_after_id": 9001
}

Ещё: 401, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Вебхуки

Подписки на события — Анкора сама отправит их на ваш адрес.

Подписки на вебхуки

GET /webhooks

Подписки этого ключа — и созданные в кабинете, и через API. Секрет подписи в списке не показывается.

Параметры

ИмяГдеТипОписание
limit строка запроса integer Сколько записей на странице, от 1 до 100.
after_id строка запроса integer Вернуть записи с id больше этого — значение next_after_id из предыдущей страницы.

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

curl
curl https://ankora.pro/api/v2/public/webhooks \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Страница подписок.
JSON
{
  "data": [
    {
      "id": 5,
      "url": "https://example.ru/ankora-webhook",
      "events": [
        "transaction.created",
        "card.created"
      ],
      "description": "CRM",
      "active": true,
      "consecutive_failures": 0,
      "disabled_at": null,
      "last_success_at": "2026-10-24T12:30:01+03:00",
      "last_failure_at": null,
      "created_at": "2026-10-20T10:00:00+03:00"
    }
  ],
  "has_more": false,
  "next_after_id": 5
}

Ещё: 401, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Подписаться на события

POST /webhooks

Создаёт подписку: на url будут приходить выбранные события (формат — в разделе «События вебхуков»). Секрет подписи приходит только в этом ответе — сохраните его; в кабинете он тоже виден.

Адрес — только https и только публичный: внутренние адреса, localhost и логин с паролем в ссылке не принимаются. До 10 подписок на ключ.

Параметры

ИмяГдеТипОписание
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

Тело запроса

ПолеТипОписание
urlобяз. string
eventsобяз. array of WebhookEventType | string События — массив или строка через запятую.
description string

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

curl
curl -X POST https://ankora.pro/api/v2/public/webhooks \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.ru/ankora-webhook","events":["transaction.created","card.created"],"description":"CRM"}'

Ответы

201 Подписка создана.
JSON
{
  "webhook": {
    "id": 5,
    "url": "https://example.ru/ankora-webhook",
    "events": [
      "transaction.created",
      "card.created"
    ],
    "description": "CRM",
    "active": true,
    "consecutive_failures": 0,
    "disabled_at": null,
    "last_success_at": "2026-10-24T12:30:01+03:00",
    "last_failure_at": null,
    "created_at": "2026-10-20T10:00:00+03:00",
    "secret": "whsec_3fk9X2mQ7pL0vT8sN4bR1cY6wZ5aE2dH9jK7uI0oP3q"
  }
}
422 Адрес не подходит, событий нет или подписок уже 10.
JSON
{
  "error": "operation_rejected",
  "message": "Адрес ведёт во внутреннюю сеть — нужен публичный адрес"
}
JSON
{
  "error": "parameter_missing",
  "message": "Не передан параметр url",
  "details": {
    "param": "url"
  }
}

Ещё: 400, 401, 403, 404, 409, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Подписка и журнал доставок

GET /webhooks/{id}

Подписка и последние 20 доставок — с кодом ответа вашего адреса и ошибкой, если была. Журнал хранится 14 дней.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.

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

curl
curl https://ankora.pro/api/v2/public/webhooks/123 \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ"

Ответы

200 Подписка.
JSON
{
  "webhook": {
    "id": 5,
    "url": "https://example.ru/ankora-webhook",
    "events": [
      "transaction.created",
      "card.created"
    ],
    "description": "CRM",
    "active": true,
    "consecutive_failures": 0,
    "disabled_at": null,
    "last_success_at": "2026-10-24T12:30:01+03:00",
    "last_failure_at": null,
    "created_at": "2026-10-20T10:00:00+03:00"
  },
  "deliveries": [
    {
      "id": 901,
      "event_id": "evt_6f1c2a9e-5b7d-4e8a-9c41-0d2b6f7e8a10",
      "event_type": "transaction.created",
      "status": "succeeded",
      "attempts": 1,
      "last_response_status": 200,
      "last_error": null,
      "next_attempt_at": null,
      "delivered_at": "2026-10-24T12:30:01+03:00",
      "created_at": "2026-10-24T12:30:00+03:00"
    }
  ]
}

Ещё: 401, 404, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Отписаться

DELETE /webhooks/{id}

Удаляет подписку и её журнал. Доставки, которые ждали повтора, не уйдут.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

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

curl
curl -X DELETE https://ankora.pro/api/v2/public/webhooks/123 \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)"

Ответы

200 Удалена.
JSON
{
  "deleted": true,
  "id": 5
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

Отправить тестовое событие

POST /webhooks/{id}/test

Отправляет событие webhook.test сразу, одной попыткой, и возвращает результат — удобно проверить адрес и проверку подписи.

Параметры

ИмяГдеТипОписание
idобяз. путь integer Id из адреса метода — карты, клиента, абонемента, подписки и т.д.
Idempotency-Key заголовок string Защита от повтора: уникальная строка на операцию (например, UUID или номер документа), до 255 символов. Повтор успешного запроса с тем же ключом в течение суток вернёт сохранённый ответ с заголовком Idempotent-Replayed: true, а операция не выполнится второй раз.

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

curl
curl -X POST https://ankora.pro/api/v2/public/webhooks/123/test \
  -H "Authorization: Bearer ak_ВАШ_КЛЮЧ" \
  -H "Idempotency-Key: $(uuidgen)"

Ответы

200 Результат доставки — смотрите status и last_response_status.
JSON
{
  "delivery": {
    "id": 901,
    "event_id": "evt_6f1c2a9e-5b7d-4e8a-9c41-0d2b6f7e8a10",
    "event_type": "webhook.test",
    "status": "succeeded",
    "attempts": 1,
    "last_response_status": 200,
    "last_error": null,
    "next_attempt_at": null,
    "delivered_at": "2026-10-24T12:30:01+03:00",
    "created_at": "2026-10-24T12:30:00+03:00"
  }
}

Адрес ответил ошибкой

JSON
{
  "delivery": {
    "id": 901,
    "event_id": "evt_6f1c2a9e-5b7d-4e8a-9c41-0d2b6f7e8a10",
    "event_type": "webhook.test",
    "status": "failed",
    "attempts": 1,
    "last_response_status": 500,
    "last_error": "Адрес ответил 500",
    "next_attempt_at": null,
    "delivered_at": null,
    "created_at": "2026-10-24T12:30:00+03:00"
  }
}

Ещё: 400, 401, 403, 404, 409, 422, 429, 500 — общие ошибки, формат и коды — в разделе «Ответы и ошибки».

События вебхуков

Что Анкора присылает на адрес подписки. Как подписаться и проверить подпись — в разделе «Вебхуки».

Новая операция по карте

transaction.created

Любое движение по карте: покупка, начисление, списание, сгорание, корректировка, абонемент, подписка, визит. Что именно — в data.transaction.operation; карта — в состоянии сразу после операции.

Поля data

ПолеТипОписание
data.transaction Transaction Одно движение по карте.
data.card Card Карта клиента в одной программе лояльности. В списках — краткая, в остальных ответах — полная (CardFull).

Пример тела запроса

JSON
{
  "id": "evt_6f1c2a9e-5b7d-4e8a-9c41-0d2b6f7e8a10",
  "type": "transaction.created",
  "created_at": "2026-10-24T12:30:00+03:00",
  "business_id": 42,
  "data": {
    "transaction": {
      "id": 9001,
      "card_id": 123,
      "customer_id": 456,
      "program_id": 7,
      "operation": "cashback_earn",
      "operation_label": "Начисление кэшбека (за покупку)",
      "mechanic": "cashback",
      "direction": "credit",
      "amount": 75.0,
      "balance_before": 0.0,
      "balance_after": 75.0,
      "purchase_amount": 1500.0,
      "description": "Кэшбэк 5% с покупки",
      "location_id": 3,
      "staff_member_id": null,
      "source_transaction_id": 9000,
      "expires_at": "2026-11-30T23:59:59+03:00",
      "expired": false,
      "customer_visible": true,
      "created_at": "2026-10-24T12:30:00+03:00"
    },
    "card": {
      "id": 123,
      "card_number": "AABBCCDD00000001",
      "status": "active",
      "customer_id": 456,
      "program_id": 7,
      "location_id": null,
      "cashback_balance": 75.0,
      "points_balance": 0.0,
      "stamps_count": 3,
      "rewards_available": 0,
      "total_spent": 12500.0,
      "total_visits": 14,
      "last_visit_at": "2026-10-24T12:30:00+03:00",
      "rfm_segment": "loyal",
      "created_at": "2026-03-02T10:15:00+03:00",
      "updated_at": "2026-10-24T12:30:00+03:00"
    }
  }
}

Новый клиент программы

card.created

Клиенту выпущена карта в программе — при регистрации, кассиром, из кабинета, интеграцией или через API.

Поля data

ПолеТипОписание
data.card Card Карта клиента в одной программе лояльности. В списках — краткая, в остальных ответах — полная (CardFull).
data.customer Customer Клиент бизнеса со всеми картами.

Пример тела запроса

JSON
{
  "id": "evt_0b8e4d2c-1f3a-4c5b-8d9e-7a6b5c4d3e2f",
  "type": "card.created",
  "created_at": "2026-10-24T12:00:00+03:00",
  "business_id": 42,
  "data": {
    "card": {
      "id": 123,
      "card_number": "AABBCCDD00000001",
      "status": "active",
      "customer_id": 456,
      "program_id": 7,
      "location_id": null,
      "cashback_balance": 75.0,
      "points_balance": 0.0,
      "stamps_count": 3,
      "rewards_available": 0,
      "total_spent": 12500.0,
      "total_visits": 14,
      "last_visit_at": "2026-10-24T12:30:00+03:00",
      "rfm_segment": "loyal",
      "created_at": "2026-03-02T10:15:00+03:00",
      "updated_at": "2026-10-24T12:30:00+03:00"
    },
    "customer": {
      "id": 456,
      "name": "Анна",
      "phone": "+79991234567",
      "email": "anna@example.ru",
      "birthday": "1990-05-17",
      "gender": null,
      "custom_fields": {
      },
      "consent_accepted_at": "2026-03-02T10:15:00+03:00",
      "marketing_consent": true,
      "marketing_consent_at": "2026-03-02T10:15:00+03:00",
      "marketing_unsubscribed_at": null,
      "telegram_linked": false,
      "created_at": "2026-03-02T10:15:00+03:00",
      "updated_at": "2026-10-24T12:30:00+03:00",
      "cards": [
        {
          "id": 123,
          "card_number": "AABBCCDD00000001",
          "status": "active",
          "customer_id": 456,
          "program_id": 7,
          "location_id": null,
          "cashback_balance": 75.0,
          "points_balance": 0.0,
          "stamps_count": 3,
          "rewards_available": 0,
          "total_spent": 12500.0,
          "total_visits": 14,
          "last_visit_at": "2026-10-24T12:30:00+03:00",
          "rfm_segment": "loyal",
          "created_at": "2026-03-02T10:15:00+03:00",
          "updated_at": "2026-10-24T12:30:00+03:00"
        }
      ]
    }
  }
}

Изменился профиль клиента

customer.updated

Изменились контакты, день рождения, пол, поля анкеты, согласия или привязка Telegram. Какие поля — в data.changed_fields.

Поля data

ПолеТипОписание
data.customer Customer Клиент бизнеса со всеми картами.
data.changed_fields array of string

Пример тела запроса

JSON
{
  "id": "evt_3c2b1a09-8f7e-4d6c-9b5a-4f3e2d1c0b9a",
  "type": "customer.updated",
  "created_at": "2026-10-24T12:10:00+03:00",
  "business_id": 42,
  "data": {
    "customer": {
      "id": 456,
      "name": "Анна",
      "phone": "+79991234567",
      "email": "anna@example.ru",
      "birthday": "1990-05-17",
      "gender": null,
      "custom_fields": {
      },
      "consent_accepted_at": "2026-03-02T10:15:00+03:00",
      "marketing_consent": true,
      "marketing_consent_at": "2026-03-02T10:15:00+03:00",
      "marketing_unsubscribed_at": null,
      "telegram_linked": false,
      "created_at": "2026-03-02T10:15:00+03:00",
      "updated_at": "2026-10-24T12:30:00+03:00",
      "cards": [
        {
          "id": 123,
          "card_number": "AABBCCDD00000001",
          "status": "active",
          "customer_id": 456,
          "program_id": 7,
          "location_id": null,
          "cashback_balance": 75.0,
          "points_balance": 0.0,
          "stamps_count": 3,
          "rewards_available": 0,
          "total_spent": 12500.0,
          "total_visits": 14,
          "last_visit_at": "2026-10-24T12:30:00+03:00",
          "rfm_segment": "loyal",
          "created_at": "2026-03-02T10:15:00+03:00",
          "updated_at": "2026-10-24T12:30:00+03:00"
        }
      ]
    },
    "changed_fields": [
      "birthday"
    ]
  }
}

Тестовое событие

webhook.test

Приходит по кнопке «Отправить тестовое событие» в кабинете и по POST /webhooks/{id}/test. Подписываться на него не нужно.

Поля data

ПолеТипОписание
data.message string
data.webhook_id integer

Пример тела запроса

JSON
{
  "id": "evt_9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
  "type": "webhook.test",
  "created_at": "2026-10-24T12:00:00+03:00",
  "business_id": 42,
  "data": {
    "message": "Тестовое событие Анкоры: подписка https://example.ru/ankora-webhook работает",
    "webhook_id": 5
  }
}

Объекты

Поля объектов в ответах. Поле всегда присутствует; если значения нет — null.

Account

ПолеТипОписание
business object
business.id integer
business.name string
business.slug string Адрес бизнеса в ссылках карт — ankora.pro/<slug>.
business.timezone string Часовой пояс — в нём считаются даты без смещения.
subscription object
subscription.status string grace — оплаченный период кончился, ждём продления; операции пока работают. Значения: trial, active, grace, expired
subscription.plan string | null Название тарифа.
subscription.active_until string | null
subscription.trial_ends_at string | null
api object
api.permissions object Права ключа. Включаются в кабинете на странице «API и Zapier».
api.permissions.balance_management boolean Начисление вручную, установка и корректировка балансов, сумма покупок.
api.permissions.refunds boolean Возврат покупки и абонемента, отмена подписки.
api.operations_allowed boolean Можно ли сейчас начислять
api.blocked_reason string | null Почему операции закрыты: subscription_expired — подписка истекла, plan_gate — API недоступен на тарифе, billing_gate — интеграция не оплачена. Значения: subscription_expired, plan_gate, billing_gate
api.rate_limit_per_minute integer

Location

ПолеТипОписание
id integer
name string
address string | null
latitude number | null
longitude number | null
radius_meters integer | null Радиус гео-уведомления.
nearby_message string | null Текст гео-уведомления на экране блокировки.
active boolean
geo_program_ids array of integer Программы, картам которых точка шлёт гео-уведомления; пусто — всем.
created_at string
updated_at string

Program

Программа лояльности со всеми настройками механик.

ПолеТипОписание
id integer
name string
active boolean
cashback object
cashback.enabled boolean
cashback.percent number Базовый процент кэшбэка от покупки.
cashback.tiers array of PercentTier
cashback.auto_award boolean Начислять автоматически с каждой покупки.
cashback.max_balance number | null Потолок накопления
cashback.max_redemption_percent number Сколько процентов чека можно оплатить кэшбэком.
cashback.expiry BalanceExpiry Сгорание баланса.
cashback.description string | null
points object
points.enabled boolean
points.percent number Базовый процент: сколько баллов начисляется со 100 ₽ покупки.
points.tiers array of PercentTier
points.auto_award boolean
points.currency_name string Как называются баллы у бизнеса.
points.redemption_rate number Сколько рублей скидки даёт один балл.
points.max_balance number | null
points.max_redemption_percent number
points.expiry BalanceExpiry Сгорание баланса.
points.description string | null
stamps object
stamps.enabled boolean
stamps.target integer | null Сколько штампов до награды.
stamps.reward_description string | null
stamps.auto_reset boolean | null Начинать новый круг штампов после награды.
stamps.expiry object
stamps.expiry.enabled boolean
stamps.expiry.days integer | null
stamps.expiry.mode string per_stamp — каждый штамп сгорает сам; cycle — весь круг сгорает, если не собран за срок. Значения: per_stamp, cycle
stamps.description string | null
discount object
discount.enabled boolean
discount.percent number
discount.tiers array of PercentTier
discount.description string | null
tier_windows object За какой период считается сумма покупок для ступени и визиты для статуса гостя; null — за всё время.
tier_windows.spend_months integer | null
tier_windows.visits_months integer | null
tier_windows.drop_reminder object
tier_windows.drop_reminder.enabled boolean
tier_windows.drop_reminder.days integer За сколько дней предупредить клиента
guest_status object
guest_status.enabled boolean
guest_status.counting_mode string manual — визит засчитывает кассир; purchase — каждая покупка. Значения: manual, purchase
guest_status.tiers array of object
guest_status.tiers[].threshold integer С какого числа визитов.
guest_status.tiers[].name string | null
guest_status.tiers[].perk string | null
guest_status.tiers[].color string | null
guest_status.description string | null
welcome_bonus object
welcome_bonus.enabled boolean
welcome_bonus.type string Значения: points, cashback
welcome_bonus.amount number
welcome_bonus.expiry_days integer | null
welcome_bonus.delay_hours integer Через сколько часов после регистрации придёт бонус.
welcome_bonus.after_first_purchase boolean Начислять после первой покупки
welcome_bonus.message string | null
birthday_bonus object
birthday_bonus.enabled boolean
birthday_bonus.gift boolean false — только поздравление, без бонуса.
birthday_bonus.type string Значения: points, cashback
birthday_bonus.amount number
birthday_bonus.days_before integer | null
birthday_bonus.expiry_days integer | null
birthday_bonus.message string | null
birthday_bonus.greeting_message string | null
referral object
referral.enabled boolean
referral.type string Значения: points, cashback
referral.recipients string Кому начисляется бонус: обоим, только приглашённому или только пригласившему. Значения: both, referee, referrer
referral.referee_amount number
referral.referrer_amount number
referral.message string | null
expiry_reminders object
expiry_reminders.enabled boolean
expiry_reminders.days array of integer За сколько дней до сгорания напомнить.
expiry_reminders.message string | null
visit_passes object
visit_passes.enabled boolean
visit_passes.default_expiry_days integer | null
visit_passes.grant_cashback boolean Начислять кэшбэк за покупку абонемента.
visit_passes.notify_exhausted boolean
memberships object
memberships.enabled boolean
memberships.expiry_reminder_days integer
memberships.plans array of MembershipPlan
registration_fields array of object Поля анкеты регистрации. Стандартные ключи — phone, name, email, birthday, gender; остальные попадают в custom_fields клиента.
registration_fields[].key string
registration_fields[].label string
registration_fields[].type string
registration_fields[].required boolean
created_at string
updated_at string

PercentTier

Ступень по сумме покупок.

ПолеТипОписание
threshold number С какой суммы покупок действует ступень
percent number
name string | null
color string | null Цвет карты на этой ступени.

BalanceExpiry

Сгорание баланса.

ПолеТипОписание
enabled boolean
days integer | null
policy string from_earn — через days дней после начисления; from_last_activity — через days дней без покупок; fixed_date — в дату fixed_date. Значения: from_earn, from_last_activity, fixed_date
fixed_date string | null

MembershipPlan

Шаблон подписки — его продают клиенту.

ПолеТипОписание
id integer
name string
description string | null
duration_days integer
suggested_sale_price number
suggested_renewal_price number
overall_limit_count integer | null
overall_limit_period_days integer | null
actions array of object
actions[].id integer
actions[].label string
actions[].limit_count integer | null
actions[].limit_period_days integer | null

Promotion

ПолеТипОписание
id integer
program_id integer
name string
kind string Значения: bonus, multiplier
state string Значения: draft, scheduled, launching, active, finished, cancelled
starts_at string | null
ends_at string | null
bonus object | null Для kind = bonus — подарок каждому в аудитории.
multiplier object | null Для kind = multiplier — во сколько раз растёт начисление.
message string | null Текст уведомления клиентам.
card_text string | null Строка на карте в Wallet на время акции.
control_group_percent integer Доля аудитории
cards_count integer
control_count integer
launched_at string | null
finished_at string | null
cancelled_at string | null
created_at string

Customer

Клиент бизнеса со всеми картами.

ПолеТипОписание
id integer
name string | null
phone string | null
email string | null
birthday string | null
gender string | null
custom_fields object Дополнительные поля анкеты, ключи — из настроек регистрации программы.
consent_accepted_at string | null Согласие на обработку персональных данных.
marketing_consent boolean Действующее согласие на рекламные рассылки.
marketing_consent_at string | null
marketing_unsubscribed_at string | null
telegram_linked boolean
created_at string
updated_at string
cards array of Card

CustomerFull

Профиль клиента — как в списке, но карты полные.

ПолеТипОписание
id integer
name string | null
phone string | null
email string | null
birthday string | null
gender string | null
custom_fields object Дополнительные поля анкеты, ключи — из настроек регистрации программы.
consent_accepted_at string | null Согласие на обработку персональных данных.
marketing_consent boolean Действующее согласие на рекламные рассылки.
marketing_consent_at string | null
marketing_unsubscribed_at string | null
telegram_linked boolean
created_at string
updated_at string
cards array of CardFull

Card

Карта клиента в одной программе лояльности. В списках — краткая, в остальных ответах — полная (CardFull).

ПолеТипОписание
id integer
card_number string
status string Значения: active, suspended, expired
customer_id integer
program_id integer
location_id integer | null Точка
cashback_balance number Кэшбэк
points_balance number Баллы.
stamps_count integer Штампы в текущем круге.
rewards_available integer Награды за штампы
total_spent number Сумма покупок за всё время
total_visits integer Число покупок.
last_visit_at string | null
rfm_segment RfmSegment | null
created_at string
updated_at string Меняется при любой операции по карте.

CardFull

Полная карта — с текущей ступенью, статусом гостя, ближайшим сгоранием, абонементами, подпиской и тем, где карта у клиента.

ПолеТипОписание
id integer
card_number string
status string Значения: active, suspended, expired
customer_id integer
program_id integer
location_id integer | null Точка
cashback_balance number Кэшбэк
points_balance number Баллы.
stamps_count integer Штампы в текущем круге.
rewards_available integer Награды за штампы
total_spent number Сумма покупок за всё время
total_visits integer Число покупок.
last_visit_at string | null
rfm_segment RfmSegment | null
created_at string
updated_at string Меняется при любой операции по карте.
tier CardTier Текущая ступень и действующие проценты. null у процента — механика выключена.
guest_status GuestStatus | null Статус гостя по числу визитов.
nearest_expiry NearestExpiry | null Что сгорит в ближайшую дату.
visit_passes array of VisitPass Действующие абонементы.
membership Membership | null Действующая подписка.
wallet Wallet Где карта у клиента и куда доходят уведомления.
referred_by_card_id integer | null Карта пригласившего по реферальной программе.
welcome_bonus_due_at string | null Когда придёт отложенный приветственный бонус.

CardTier

Текущая ступень и действующие проценты. null у процента — механика выключена.

ПолеТипОписание
name string | null Название ступени
spend_base number Сумма покупок
cashback_percent number | null
points_percent number | null
discount_percent number | null

GuestStatus

Статус гостя по числу визитов.

ПолеТипОписание
name string | null
visits integer
perk string | null Что даёт статус.
next_name string | null
visits_left integer | null Визитов до следующего статуса.
visited_today boolean

NearestExpiry

Что сгорит в ближайшую дату.

ПолеТипОписание
date string
cashback number
points number
stamps integer

Wallet

Где карта у клиента и куда доходят уведомления.

ПолеТипОписание
state string installed — карта в Apple Wallet или Google Wallet; removed — была и удалена. Значения: not_installed, installed, removed
apple_wallet boolean
google_wallet boolean
telegram boolean Клиент подключил Telegram-бота карты.
web_push boolean Включены уведомления в браузере.
installed_at string | null
uninstalled_at string | null

VisitPass

Абонемент — пакет визитов.

ПолеТипОписание
id integer
card_id integer
title string
state string Значения: active, frozen, exhausted, expired, refunded
total_visits integer
used_visits integer
remaining_visits integer
price number
expires_at string | null
frozen_since string | null
last_usage_id integer | null Последний засчитанный визит — его можно отменить.
created_at string

Membership

Подписка клиента с лимитами действий.

ПолеТипОписание
id integer
card_id integer
plan_id integer
name string
status string Значения: active, paused, expired, cancelled
started_at string
ends_at string
remaining_days integer
duration_days integer
sale_price number
overall_limit_count integer | null
overall_limit_period_days integer | null
paused_since string | null
actions array of MembershipAction

MembershipAction

ПолеТипОписание
id integer
label string
limit_count integer | null
limit_period_days integer | null
used_in_window integer
remaining integer | null null — без лимита.
window string Значения: unlimited, lifetime, rolling

Transaction

Одно движение по карте.

ПолеТипОписание
id integer
card_id integer
customer_id integer
program_id integer
operation TransactionOperation Тип операции.
operation_label string Название операции по-русски.
mechanic string | null Значения: points, cashback, stamps, purchase, total_spent, visit_pass, membership, guest_visit
direction string credit — начисление, debit — списание, neutral — покупка или оплата подписки. Значения: credit, debit, neutral
amount number Всегда больше нуля; направление — в direction. Единица — по механике: ₽, баллы, штампы, визиты.
balance_before number | null
balance_after number | null
purchase_amount number | null Сумма покупки
description string | null
location_id integer | null
staff_member_id integer | null Сотрудник
source_transaction_id integer | null Операция
expires_at string | null Когда сгорит начисление.
expired boolean
customer_visible boolean Видна ли операция клиенту в истории карты.
created_at string

CheckoutPreview

ПолеТипОписание
amount number Сумма чека.
discount_percent number Скидка по ступени клиента.
discount_amount number
after_discount number
cashback CheckoutMechanicPreview
points CheckoutMechanicPreview
promotion_multipliers object Множители идущих акций — уже учтены в earn.
promotion_multipliers.cashback number
promotion_multipliers.points number
to_pay number Сколько клиент платит деньгами.

CheckoutMechanicPreview

ПолеТипОписание
enabled boolean
available number Баланс на карте.
max_redeemable number Сколько можно списать по этому чеку: не больше баланса и лимита программы.
redeem number Сколько списывается в этом расчёте.
earn_percent number Процент начисления по ступени клиента.
earn number Сколько начислится с оплаченной суммы
auto_award boolean false — программа в ручном режиме: начисляет кассир, передайте cashback_to_add или points_to_add.
max_manual_award number | null Сколько можно начислить вручную в ручном режиме.

Webhook

ПолеТипОписание
id integer
url string
events array of WebhookEventType
description string | null
active boolean false — выключена: вами или после трёх суток отказов адреса.
consecutive_failures integer Отказов подряд.
disabled_at string | null
last_success_at string | null
last_failure_at string | null
created_at string

WebhookDelivery

ПолеТипОписание
id integer
event_id string Совпадает с id события и заголовком Ankora-Event-Id — по нему отсекайте дубли.
event_type string
status string pending — ждёт повтора. Значения: pending, succeeded, failed
attempts integer
last_response_status integer | null Код ответа вашего адреса.
last_error string | null
next_attempt_at string | null
delivered_at string | null
created_at string

Error

Ошибка. Код в error стабилен — по нему ветвится ваш код; message — текст для человека.

ПолеТипОписание
error string Значения: unauthorized, permission_denied, subscription_required, invalid_json, parameter_missing, parameter_invalid, not_found, program_required, mechanic_disabled, insufficient_balance, redemption_limit_exceeded, limit_reached, operation_rejected, idempotency_key_reused, idempotency_key_in_progress, rate_limited, internal_error
message string
details object Подробности, свои у каждого кода — см. раздел «Ошибки».

TransactionOperation

Тип операции в истории — поле operation. Направление движения — в direction, название для человека — в operation_label.

ЗначениеЧто это
points_earnНачисление баллов (за покупку)
points_spendСписание баллов
points_expireСгорание баллов
points_adjustКорректировка баллов
points_setУстановка баланса баллов
points_addНачисление баллов
cashback_earnНачисление кэшбека (за покупку)
cashback_spendСписание кэшбека
cashback_expireСгорание кэшбека
cashback_adjustКорректировка кэшбека
cashback_setУстановка баланса кэшбека
cashback_addНачисление кэшбека
stamp_addДобавление штампа
stamp_redeemНаграда за штампы
stamp_adjustКорректировка штампов
reward_useИспользование награды
stamp_expireСгорание штампа
stamp_cycle_expireСгорание цикла штампов
purchase_recordПокупка
total_spent_increaseУвеличение суммы покупок
total_spent_decreaseУменьшение суммы покупок
visit_pass_issueПродажа абонемента
visit_pass_useСписан визит абонемента
visit_pass_reverseОтмена визита абонемента
visit_pass_refundВозврат за абонемент
visit_pass_expireИстёк срок абонемента
membership_issueПродажа подписки
membership_extendПродление подписки
membership_useИспользование подписки
membership_cancel_refundВозврат за подписку
guest_visit_recordЗасчитан визит гостя
guest_visit_reverseОтменён визит гостя
guest_visits_resetОбнуление визитов гостя

RfmSegment

RFM-сегмент карты — по давности, частоте и сумме покупок. Пересчитывается ночью.

ЗначениеСегмент
championsЧемпионы
loyalЛояльные
potential_loyalistsПотенциально лояльные
new_customersНовые
promisingМногообещающие
need_attentionТребуют внимания
about_to_sleepСкоро уснут
at_riskПод угрозой ухода
cant_lose_themНельзя потерять
hibernatingСпящие
lostПотерянные

История изменений

Октябрь 2026 — версия 2.0

  • Новые методы: аккаунт, точки, программы со всеми настройками механик, акции, профиль клиента и его правка, карта и её история, продажа с расчётом, возврат покупки, начисление вручную, установка и корректировка балансов, сумма покупок, снятие штампов, абонементы, подписки, визиты статуса гостя, вебхуки.
  • Ошибки: поле error — стабильный код вместо фразы, текст — в message, подробности — в details. GET /customers/search без результата отвечает 404 not_found в том же формате.
  • Списки GET /customers и GET /transactions — в виде { data, has_more, next_after_id }, по возрастанию id, с фильтрами. Элемент GET /customers — клиент со всеми картами, а не карта. since_id работает как after_id.
  • Клиента можно указать номером карты, id карты или клиента и программой — во всех методах, включая методы первой версии.
  • Карта в ответах — полная: к полям первой версии добавились ступень, ближайшее сгорание, абонементы, подписка и Wallet.
  • POST /stamps при выключенных штампах отвечает mechanic_disabled.
  • Защита от повтора Idempotency-Key, точка продажи location_id, права ключа, ответы 429 и 500 — в JSON.

Ключ API — в кабинете Анкоры

7 дней бесплатно. Включите «API и Zapier» в разделе «Интеграции» и сделайте первый запрос за пять минут.

Начать бесплатно