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

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

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

## Какие есть способы связать 1С с Kaspi Pay?

Два. **Вручную** — выгрузить операции из кабинета Kaspi Pay файлом и загрузить его в 1С, сопоставляя строки с документами: это разобрано в статье [Как импортировать платежи Kaspi Pay в 1С](/guides/import-platezhey-kaspi-pay-v-1c). **Через API** — так работает ApiPay: счёт создаётся из самой 1С, статус оплаты 1С забирает запросом, файлы не нужны. Дальше — как устроен второй путь.

## Какие параметры API нужны 1С?

| Параметр | Значение |
|---|---|
| Хост 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С-интеграции. Две независимые связки, которые нельзя путать.

**(а) Номенклатура 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 }` уже созданного счёта. Уникально в пределах организации. Если прежний счёт в `expired`/`cancelled`/`error`, тот же ключ выпускает новый счёт — это перевыставление, а не дубль |

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

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

## Как выставить счёт из 1С — один или пачкой?

**Одиночный — `POST /invoices`.** Обязателен `phone_number` (`8XXXXXXXXXX`). Опционально: `amount` (**только целые тенге**, от `1` до `99 999 999` — обязателен, если нет `cart_items`; дробная сумма и дробный итог корзины после скидок отбиваются `422 amount_must_be_whole_tenge`), `description` (≤60 — длиннее отклоняется с `422 description_too_long`), `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` сначала разберите `error_code`/`error`: если есть `Retry-After`, выдержите указанное число секунд. `meta.reset_at` используйте только там, где это поле опубликовано: у `trial_daily_limit`/`outstanding_*` поля `meta` нет, а у общего лимита запросов время сброса — в `reset_at` верхнего уровня и в `Retry-After`. `qr_rate_limit` приходит без времени повтора — подождите примерно минуту; `kyc_daily_limit_reached` с `meta.limit = 0` требует одобрения анкеты, а не ожидания нового окна («[Лимиты и квоты](/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С узнаёт об оплате без вебхука?

У 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. Реагировать на ПОСЛЕДНИЙ статус.
5. Раз в сутки — сверка GET /invoices с date_field=paid_at и origin=apipay:
   она догоняет оплату, пришедшую после cancelled/expired.
```

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

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

## Как провести возврат из 1С?

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

## Нужно ли выгружать номенклатуру 1С в ApiPay?

Нужно, только если счёт должен нести позиции в чек 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).

## Как проверить интеграцию в песочнице перед запуском?

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

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

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

**Как выставить счёт Kaspi из 1С?**
Отправить из 1С `POST /invoices` с телефоном покупателя и суммой; номер документа положить в `external_order_id`, чтобы по нему найти документ при оплате. Покупателю приходит счёт в приложении Kaspi.

**Нужен ли вебхук, чтобы 1С узнала об оплате?**
Нет. Достаточно регламентного задания, которое опрашивает `GET /invoices/{id}` (до 1000 запросов в минуту) или пачкой `POST /invoices/status/check`. Вебхук ускоряет проведение, если 1С доступна из интернета.

**Есть готовый модуль/обработка для 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
