> Источник: https://apipay.kz/guides/integraciya-apipay-s-1c · Обновлено: 2026-08-26 · apipay.kz
> ApiPay — независимый сервис приёма платежей поверх вашего Kaspi Pay.

# Как выставлять Kaspi-счета из 1С через API ApiPay?

**TL;DR.** 1С ведёт учёт (документы, номенклатура), а деньги вы принимаете через Kaspi без терминала: документ 1С → `POST /invoices` → покупатель платит в Kaspi → 1С узнаёт об оплате и проводит платёж. Основной способ узнать об оплате из 1С — **поллинг `GET /invoices/{id}`, лимит специально поднят до 1000/min** под 1С (вебхуки — опция, если у 1С есть публичный HTTP-сервис). Два поля-ссылки не путать: `external_order_id` = ссылка на документ для матчинга оплаты, `external_order_id_idempotency` = ключ идемпотентности (повторное проведение не создаёт дубль-счёт, а даёт `409`). Готового модуля для 1С нет — это доработка конфигурации силами вашего 1С-специалиста; почему так — на витрине [ApiPay для 1С](/kaspi-pay-1c).

## Коротко

| Параметр | Значение |
|---|---|
| Хост API | `https://api.apipay.kz/api/v1`, заголовок `X-API-Key` |
| Даты | UTC `+00:00` везде, **кроме** `GET /tariff` и `GET /account/health` (`+05:00`) |
| Суммы в ответах | Строки: `"amount": "15000.00"` — парсить как строку |

## Сценарий: счета и фискализация позиций из 1С

Поток:

**Документ 1С → `POST /invoices` (или `bulk`) → покупателю приходит push в Kaspi → покупатель оплатил → 1С узнаёт об оплате (поллинг/вебхук) → проводит платёж по `external_order_id`.**

Если в чек Kaspi нужны **позиции** (фискализация, Нацкаталог `ntin`/`gtin`/`barcode`), номенклатура заранее заводится в каталог ApiPay, и счёт создаётся корзиной `cart_items` — механику каталога держит отдельная статья [Каталог, корзина и Нацкаталог](/guides/katalog-korzina-nackatalog).

> Одна поверхность — клиентский `X-API-Key` (`/api/v1`). Отдельный [Partner API](/guides/partner-api-white-label) для интеграции своей 1С не нужен.

## Маппинг данных: номенклатура и документы

Это стержень 1С-интеграции. Две независимые связки, которые нельзя путать.

**(а) Номенклатура 1С ↔ товар каталога ApiPay — через `external_ref`.** Код (или GUID) номенклатуры 1С кладёте в `external_ref` при создании товара (`POST /catalog`). Потом точечно читаете `GET /catalog?external_refs[]=…` и получаете двусторонний матчинг «номенклатура ↔ товар каталога». Подробно — в [статье про каталог](/guides/katalog-korzina-nackatalog).

**(б) Документ 1С ↔ счёт — через два поля-ссылки.** Их постоянно путают:

| Поле | Назначение | Ограничения | Поведение |
|---|---|---|---|
| `external_order_id` | Свободная ссылка на документ 1С для **матчинга оплаты**. Возвращается в счёте и в вебхуке — по ней 1С находит документ и проводит платёж. | ≤255 | Не уникально, дублей не ловит |
| `external_order_id_idempotency` | **Ключ идемпотентности** проведения: номер/GUID документа 1С. Повторное проведение того же документа не создаёт второй счёт. | ≤191, пусто = выкл. | Дубль → `409 duplicate_idempotency_key` с телом `{ invoice_id, status }` уже созданного счёта. Уникально в пределах организации |

**Рецепт для 1С:** кладите идентификатор документа в **оба** поля — `external_order_id` для поиска документа по вебхуку/GET, `external_order_id_idempotency` для защиты от дубля при повторном проведении или сетевом ретрае. `409` — это не ошибка, а «счёт уже есть»: возьмите `invoice_id`/`status` из тела и продолжайте.

> **Важно:** HTTP-заголовок `Idempotency-Key` — отдельный механизм, это **не** он. Идемпотентность счёта — через body-поле `external_order_id_idempotency`.

## Выставление счёта: одиночное и пакетное

**Одиночный — `POST /invoices`.** Обязателен `phone_number` (`8XXXXXXXXXX`). Опционально: `amount` (**только целые тенге**, от `1` до `99 999 999` — обязателен, если нет `cart_items`; дробная сумма и дробный итог корзины после скидок отбиваются `422 amount_must_be_whole_tenge`), `description` (≤60 — с 05.09.2026 длиннее 60 отклоняется с `422 description_too_long`; организациям, зарегистрированным с 26.08.2026, — уже сейчас), `external_order_id`, `external_order_id_idempotency`, `kaspi_connection_id` (выбор кассира), `cart_items` (для каталог-организации), `discount_percentage` (1–99).

```bash
curl -X POST https://api.apipay.kz/api/v1/invoices \
  -H "X-API-Key: ВАШ_КЛЮЧ" -H "Content-Type: application/json" \
  -d '{
    "phone_number": "8XXXXXXXXXX",
    "amount": 15000,
    "description": "Оплата по счёту №123 от 01.07.2026",
    "external_order_id": "1c-doc-000000123",
    "external_order_id_idempotency": "1c-doc-000000123"
  }'
# 201, status: "processing" — Kaspi ещё не вызван; статус доедет поллингом/вебхуком (pending/error).
```

Отказы, которые обработчик 1С обязан различать: `422 amount_must_be_whole_tenge` — сумма документа с копейками, счёт не создан; округлите до целых тенге и повторите, ключ идемпотентности при этом не расходуется; `409 duplicate_idempotency_key` — счёт уже есть, возьмите `invoice_id` и `status` из тела и продолжайте; `403 tariff_inactive` — подписка на ApiPay не активна, ретрай бесполезен до продления; `429` с `Retry-After` — упёрлись в лимит, повторять не раньше момента из `meta.reset_at` («[Лимиты и квоты](/guides/limity-i-kvoty-apipay)»).

Псевдокод из 1С (HTTP-сервис / внешняя обработка):

```bsl
// 1С (условный BSL)
Запрос = Новый HTTPЗапрос("/api/v1/invoices");
Запрос.Заголовки.Вставить("X-API-Key", КлючAPI);
Запрос.Заголовки.Вставить("Content-Type", "application/json");
Запрос.УстановитьТелоИзСтроки(ЗаписатьJSON(ПараметрыСчёта)); // с external_order_id = НомерДокумента
Ответ = HTTPСоединение.ОтправитьДляОбработки(Запрос);
// 201 → сохранить invoice_id у документа; 409 → счёт уже есть, взять invoice_id из тела
```

**Пакетный — `POST /invoices/bulk`** (отдельный лимит **20/min**). Тело: `invoices` (массив 1–100), опц. общий `kaspi_connection_id` (один кассир на батч). Ответ `201`: `{ created, duplicates, failed, invoices: [ { index, status: "created"|"duplicate"|"failed", … } ] }` — результат по каждому элементу по индексу. **Структурная ошибка тела** (например элемент без `phone_number`) отклоняет **весь батч атомарно** (`422`, частичного применения нет).

**Рецепт:** ночная выгрузка пачки неоплаченных документов → один `bulk` (≤100) → разобрать `invoices[]` по `index`, сохранить `id` у каждого документа. `duplicate` = документ уже выставлялся (сработал `external_order_id_idempotency`).

## Отслеживание оплаты: поллинг (основной путь) и вебхуки (опция)

У 1С часто нет публичного веб-адреса (крутится в локальной сети / на терминальном сервере), поэтому **основной путь — поллинг**.

**Поллинг `GET /invoices/{id}` — лимит 1000/min** (заменяет общий 200/min именно под 1С). Читает из БД/кэша, **не бьёт в Kaspi**; терминальные счета кэшируются 24 часа. Ответ `200` — полный объект счёта + `items[]`. Пока счёт в `processing`, в объекте видны `last_kaspi_error_code`/`last_kaspi_error_message` — диагностика без ожидания вебхука.

**Пакетная проверка `POST /invoices/status/check`** `{ invoice_ids: [...] }` — опросить сразу все неоплаченные счета одним запросом; ответ `{ invoices: [ { id, status, kaspi_invoice_id, amount, error_message, updated_at } ] }`.

**Паттерн регламентного задания 1С:**

```text
1. Выбрать документы с неоплаченными счетами (свои invoice_id).
2. POST /invoices/status/check со всеми invoice_ids (или поштучно GET /invoices/{id}).
3. Для каждого терминального статуса:
     paid                      → провести оплату по external_order_id;
     cancelled/expired/error   → снять резерв / пометить неоплаченным.
4. Реагировать на ПОСЛЕДНИЙ статус.
```

Легитимны переходы `cancelled → paid` и `expired → paid` (клиент оплатил в последний момент — «деньги получены»). `error → paid` невозможен; `error → pending` — реконсиляция (счёт на самом деле прошёл, следуйте последнему статусу).

**Вебхуки — опция.** Если 1С опубликована в интернет (веб-сервер публикации, обратный прокси), можно принимать `paid`-вебхук и проводить оплату мгновенно; иначе поллинг самодостаточен. Настройка приёмника, подпись, ретраи — в статье [Вебхуки ApiPay: настройка и проверка подписи](/guides/nastroyka-webhookov-apipay); здесь не дублируем.

## Возвраты

`POST /invoices/{id}/refund`: по умолчанию — полный возврат; частичный — по сумме `amount` или позиционный `return_items[]`. Результат приходит асинхронно (вебхук/поллинг), поэтому 1С отражает возврат по последнему статусу, а не по ответу `201`. Параметры, статусы счёта после возврата и причины отказов — [Возвраты Kaspi через API](/guides/vozvraty-kaspi-cherez-api).

## Синхронизация каталога

Нужна, только если счёт должен нести позиции в чек Kaspi. Номенклатура заводится батчем `POST /catalog` (`external_ref` = код номенклатуры 1С), в рабочем режиме создание асинхронное — статус подтверждаете точечным чтением `GET /catalog?external_refs[]=…`. Инкрементальная выгрузка изменённого — `GET /catalog?updated_after=<iso>`. Ограничения батча, режимы чтения и правила обновления полей Нацкаталога — в статьях [Каталог, корзина и Нацкаталог](/guides/katalog-korzina-nackatalog) и [Массовая загрузка каталога из 1С](/guides/massovaya-zagruzka-kataloga-iz-1c).

## Чек-лист запуска: sandbox → прод

Сначала прогон в песочнице (детерминированные симуляции без реального Kaspi), потом рабочий режим. Что песочница даёт и что меняется при переходе — в статье [Песочница и рабочий режим](/guides/pesochnitsa-i-rabochiy-rezhim).

- **Симуляции жизненного цикла:** `POST /invoices/{id}/simulate-status` `{ status: paid|cancelled|expired|error }` на sandbox-счёте — прогнать все ветки проведения.
- **Идемпотентность проведения:** один и тот же документ, проведённый дважды, не создаёт второй счёт (`409`).
- **Обработка `429`/`Retry-After`:** уважайте заголовок, снижайте темп.
- **Тайм-зоны:** счета/возвраты/каталог — UTC `+00:00`; только `GET /tariff` и `GET /account/health` — `+05:00`. Частый баг 1С — сдвиг времени проведения.
- **Матчинг:** проведение строго по `external_order_id`; дедуп проводки по `invoice.id` + `status`.

## Частые вопросы

**Есть готовый модуль/обработка для 1С?**
Нет. Это доработка конфигурации силами вашего 1С-специалиста: HTTP-запросы из 1С к REST ApiPay. Почему готового модуля нет — на витрине [ApiPay для 1С](/kaspi-pay-1c).

**Почему счёт долго висит в `processing`?**
Штатно `processing` длится секунды. Дольше — либо у организации включён «Режим накопления счетов» (счета уходят в Kaspi пачкой раз в заданное окно), либо выставление не доехало до Kaspi, и тогда сервис сам финализирует счёт в `error` с вебхуком. Не пересоздавайте счёт, пока он в `processing`: получатся два живых счёта, и покупатель может оплатить оба. Смотрите `last_kaspi_error_code`/`last_kaspi_error_message` в `GET /invoices/{id}`.

---

ApiPay — независимый сервис и не аффилирован с АО «Kaspi Bank». Kaspi и Kaspi Pay — товарные знаки их правообладателя.
База знаний: https://apipay.kz/guides
