Подключение интернет-эквайринга к программному обеспечению на заказ, вопреки мнению большинства команд, не сводится к тому, чтобы «вызвать API iyzico или PayTR». Интеграция, готовая к промышленной эксплуатации, должна одновременно решать четыре отдельные задачи: (1) правильно выстроить процесс 3D Secure (3DS) — отправить пользователя на экран проверки в банке и вернуть обратно; (2) надёжно проверять callback-уведомления и вебхуки — подписью подтверждать, что уведомление действительно пришло от провайдера, сохранять идемпотентность при повторных уведомлениях и быстро возвращать код 2xx; (3) сверять платёж с заказом — привязывать к нужному заказу то событие, на котором вы фактически получили деньги; и (4) обрабатывать сценарии после оплаты, такие как возвраты, отмены и рассрочка. Если хотя бы одного из этих элементов не хватает, интеграция только выглядит «рабочей», а в промышленной эксплуатации в ней остаются незаметные ошибки, которые стоят денег: заказ, обработанный дважды, корзина со статусом «оплачено» без подтверждённой оплаты или бесплатная выдача товара по поддельному callback-уведомлению. В этой статье мы, B2B- и white-label-разработчик ПО из провинции Sakarya, делимся подходом, который сами применяем при интеграции интернет-эквайринга: банковский интернет-эквайринг или платёжная организация, платёжная форма на стороне провайдера (hosted form) или прямой API, процесс 3DS, безопасные вебхуки, сверка, возвраты и рассрочка, а также чек-лист перед запуском.

Мы рассматриваем платёжную интеграцию и как проект API-интеграции, и как вопрос инфраструктуры электронной коммерции. Ту же дисциплину мы применяли в работе с ERP и e-Fatura (турецкая система электронных счетов-фактур); если вы выбираете для интеграции между готовым и заказным решением, прочитайте нашу статью об интеграции электронной коммерции, ERP и e-Fatura. Приведённые ниже технические детали основаны на официальной документации iyzico и PayTR; поскольку любой провайдер со временем может вносить изменения, единственным достоверным источником остаётся официальная документация на момент интеграции.

Банковский интернет-эквайринг или платёжная организация?

Первое архитектурное решение — выбрать канал приёма платежей по картам. В Турции интернет-эквайринг доступен в двух формах: (a) банковский интернет-эквайринг по прямому договору с банком и (b) независимые от банков платёжные организации (например, iyzico и PayTR). Платёжные организации работают на основании закона № 6493 — Закона о платёжных системах и системах расчётов по ценным бумагам, платёжных услугах и организациях электронных денег, а лицензию на деятельность получают не от банковского регулятора BDDK, а от Центрального банка Турции, TCMB (статья 12 закона) (TCMB — платёжные организации).

На практике разница такова: при банковском интернет-эквайринге обычно нужны отдельная интеграция и отдельный договор с каждым банком, а независимая платёжная организация позволяет принимать карты большинства банков через одну интеграцию. iyzico особенно выделяется в сценариях с маркетплейсами и субмерчантами (submerchant). Правило выбора простое:

  • Если ваш приоритет — один банк, большой объём и минимальная комиссия и у вас прочные отношения с этим банком, банковский интернет-эквайринг может быть оправдан; однако если понадобится работать с несколькими банками, объём интеграционных работ многократно вырастет.
  • Если вам нужны быстрый запуск, приём карт разных банков и одна интеграция, в большинстве сценариев B2B и малого и среднего бизнеса платёжная организация (iyzico/PayTR) обойдётся дешевле в сопровождении.
  • Если вам нужны функции маркетплейса, распределение комиссий или субмерчанты, платёжная организация с поддержкой submerchant практически обязательна.

Форма провайдера или прямой API? Именно здесь определяется область действия PCI DSS

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

  • Платёжная форма на стороне провайдера: Данные карты вводятся на странице или в iframe, размещённых у провайдера. В iFrame API сервиса PayTR пользователь вводит данные карты в iframe на стороне PayTR; в iyzico CheckoutForm — это страница оплаты, размещённая на стороне iyzico (CF-Initialize возвращает paymentPageUrl/токен, а встроить её можно с параметром iframe=true). В обоих случаях конфиденциальные данные карты никогда не попадают на ваш сервер, поэтому область действия PCI DSS заметно сужается.
  • Прямой API: Платёж принимается через вашу собственную форму, а данные карты проходят через вашу инфраструктуру. Такой вариант даёт полный контроль и брендированный интерфейс, но существенно увеличивает ваши обязательства по PCI DSS.

И iyzico, и PayTR берут защиту по PCI на себя на стороне провайдера; iyzico позиционирует себя как поставщика услуг уровня PCI DSS Level 1. Но уточним: какой именно тип SAQ (SAQ A, SAQ A-EP и т. д.) подойдёт вам, зависит от деталей интеграции, и в этой статье мы этого не утверждаем; общее правило таково: область действия сужается, когда данные карт не проходят через ваш сервер. Наш практический совет однозначен:

Если у вас нет реального бизнес-требования к брендированной и полностью контролируемой странице оплаты, выбирайте форму провайдера. Несколько пикселей кастомизации не стоят той нагрузки по аудиту PCI DSS и той ответственности, которые вы на себя берёте.

Как работает процесс 3DS? (на примере iyzico)

3D Secure — это дополнительная проверка, которую выполняет банк держателя карты (одноразовый код, подтверждение в банковском приложении и т. д.). Если этот шаг пропустить, риск чарджбэка и ответственность в основном остаются на бизнесе. В iyzico 3DS — это двухэтапный процесс на POST-запросах:

  • Шаг 1 — Init 3DS: На эндпоинт /payment/3dsecure/initialize отправляется POST-запрос с данными карты и покупателя и параметром callbackUrl. В ответе приходит закодированный в base64 threeDSHtmlContent. Этот HTML отображается в браузере и перенаправляет пользователя на экран проверки 3DS в банке.
  • Шаг 2 — Auth 3DS: Когда пользователь завершит проверку в банке и вернётся на ваш callbackUrl, на эндпоинт auth отправляется второй POST-запрос с paymentId, полученным на этапе Init. Здесь iyzico рекомендует использовать эндпоинт v2 (/payment/v2/3dsecure/auth, то есть 3DS 2.0); устаревший /payment/3dsecure/auth — это 3DS 1.0.

Результат проверки передаётся в поле mdStatus: значение 1 означает успех, а значения 0 и 2–8 — неудачную проверку. Важная оговорка: мы не приводим здесь как окончательный точный состав полей POST-запроса, который банк отправляет на ваш callbackUrl, поскольку он может различаться в зависимости от версии и интеграции; эту деталь нужно проверить по актуальной официальной документации перед запуском (iyzico — Init 3DS, iyzico — Auth 3DS).

На протяжении всего процесса запрос и ответ сопоставляются с помощью conversationId. iyzico определяет его как «уникальный идентификатор для сопоставления запроса и ответа»; сюда можно подставить собственный номер заказа, а значение, отправленное в запросе, возвращается в ответе без изменений. Кроме того, iyzico присваивает каждому успешному платежу собственный paymentId; возвраты и отмены выполняются именно через этот paymentId.

Безопасная проверка вебхуков и callback-уведомлений: подпись, идемпотентность, быстрый ответ 2xx

Это самая недооценённая и самая опасная часть платёжной интеграции. Callback-уведомление или вебхук — это то самое межсерверное событие, по которому вы отмечаете деньги как полученные. Три правила не обсуждаются: проверяйте подпись, соблюдайте идемпотентность, быстро возвращайте 2xx.

1) Проверка подписи — докажите, что уведомление действительно пришло от провайдера

Никогда не считайте POST-запрос, пришедший на ваш callback-адрес, подтверждением оплаты, не проверив подпись. Иначе злоумышленник сможет отправить поддельное уведомление об «успешной оплате» и получить бесплатный заказ. Механизмы у двух провайдеров различаются:

  • PayTR (iFrame API): В уведомлении, отправляемом на notify_url, хеш вычисляется как base64_encode(hash_hmac('sha256', merchant_oid + merchant_salt + status + total_amount, merchant_key, true)). Если значение hash во входящем POST-запросе не совпадает с этим значением в точности, запрос следует считать поступившим не от PayTR и отклонить. Эта формула относится к iFrame API (четыре поля); в других API сервиса PayTR набор полей может быть иным, поэтому не путайте их.
  • iyzico (вебхук): Проверка выполняется по заголовку X-IYZ-SIGNATURE-V3 с помощью HMAC-SHA256 (HEX); более старые версии заголовка больше не поддерживаются. Критически важный момент: порядок полей, которые объединяются для подписи, зависит от типа вебхука. Для прямой оплаты, HPP и подписки порядок параметров разный — единого «универсального» порядка для подписи вебхука нет; сверяйте порядок для своего типа интеграции с официальной таблицей.

Кроме того, iyzico предлагает отдельный механизм подписи ответа для синхронных ответов API: определённые параметры объединяются через двоеточие (:), хешируются с ключом secretKey по алгоритму HMAC-SHA256 и кодируются в HEX; лишние конечные нули в ценах отбрасываются (10.50 → 10.5, 10.00 → 10). Порядок параметров зависит от эндпоинта; например, для auth без 3DS он такой: paymentId:currency:basketId:conversationId:paidPrice:price, и в auth 3DS версии v2 используется тот же порядок полей (iyzico — проверка подписи ответа, iyzico — вебхуки, PayTR — iFrame API, шаг 2).

2) Идемпотентность — если одно и то же уведомление пришло дважды, не обрабатывайте его дважды

Оба провайдера могут отправлять несколько уведомлений по одной и той же транзакции. Если не отсеивать дубли по идентификатору заказа, один и тот же заказ будет подтверждён дважды, остаток на складе спишется дважды и дважды будет создана отправка. PayTR говорит об этом прямо: контроль повторов нужно вести по уникальному полю merchant_oid; для подтверждения или отмены заказа следует обрабатывать только первое уведомление, а на повторные — просто отвечать. Практическая реализация: храните статус уведомления (обработано/не обработано) в базе данных как единственную уникальную запись, привязанную к идентификатору заказа, и выполняйте обработку в рамках одной атомарной операции.

3) Быстро возвращайте 2xx — тяжёлую работу выполняйте асинхронно

Провайдер ожидает положительного ответа на уведомление в течение короткого времени, а если не получает его, повторяет отправку. Вебхук iyzico при отсутствии ответа 2xx от продавца повторяется каждые 15 минут, до 3 раз. PayTR, не получив «OK», повторяет отправку через 1 минуту и требует, чтобы тело ответа содержало только обычный текст OK, без HTML и другого содержимого. Отсюда следуют два правила:

  • Сначала проверьте, затем сохраните, потом ответьте: проверьте подпись, однозначно отметьте заказ и только затем верните ожидаемый ответ. Тяжёлые операции, такие как отправка писем, выставление счетов или запись в ERP, переносите в асинхронную очередь; не выполняйте их синхронно, блокируя ответ на callback-уведомление.
  • Возвращайте тело ответа в формате, который ожидает провайдер: для PayTR — ровно OK, для iyzico — HTTP-код статуса 2xx. Иначе вы столкнётесь с лишними повторами и «потерянными» платежами.
Параметр iyzico (вебхук) PayTR (callback iFrame API)
Метод подписи HMAC-SHA256 (HEX), заголовок X-IYZ-SIGNATURE-V3 HMAC-SHA256 + base64, поле hash в POST-запросе
Порядок полей подписи Зависит от типа вебхука (для прямой оплаты, HPP и подписки он разный) merchant_oid + merchant_salt + status + total_amount (iFrame API)
Ожидаемый ответ HTTP-код статуса 2xx Обычный текст OK
Повторные отправки Если нет 2xx: каждые 15 мин, до 3 раз Если нет OK: повтор через 1 мин
Ключ дедупликации paymentId / conversationId merchant_oid (обрабатывается только первое уведомление)

Сверка платежей с заказами

Сверка — это мост между «деньгами, которые получил провайдер», и «заказом в вашей системе». Плохо выстроенная сверка доставляет больше всего хлопот бухгалтерии и службе поддержки клиентов. Оба провайдера строят этот мост на уникальном идентификаторе заказа, который формирует продавец:

  • PayTR: merchant_oid (до 64 буквенно-цифровых символов) — это уникальный номер заказа, который вы присваиваете транзакции; он возвращается вам в callback-уведомлении и делает сверку возможной. Кроме того, на шаге 1 paytr_token формируется с помощью HMAC-SHA256 + base64, а объединяемая строка включает поля merchant_id + user_ip + merchant_oid + email + payment_amount + user_basket + no_installment + max_installment + currency + test_mode + merchant_salt.
  • iyzico: Используйте conversationId как собственный номер заказа; значение, отправленное в запросе, возвращается в ответе без изменений. Его аналог на стороне провайдера — paymentId: через него выполняются возвраты и отмены. Храните оба идентификатора в записи о заказе.

Практические принципы надёжной сверки:

  • Решение принимает callback-уведомление, а не браузер: Страница «успеха», на которую возвращается браузер пользователя, — это лишь подсказка, а не доказательство. Подтверждайте заказ прежде всего по межсерверному callback-уведомлению с проверенной подписью.
  • Сравнивайте сумму и валюту: Сопоставляйте сумму из callback-уведомления с суммой, ожидаемой по заказу; при расхождении не обрабатывайте уведомление и поднимайте оповещение.
  • Закрывайте незавершённые состояния: Если callback-уведомление так и не пришло, с помощью фоновой задачи проверяйте заказы со статусом «оплата начата, но не завершена» через API запросов провайдера и закрывайте их.
  • Ежедневная сверка: Регулярно сравнивайте отчёты провайдера по транзакциям и расчётам с собственными записями; не полагайтесь только на вебхук.

Возвраты, частичные возвраты и рассрочка

Вторая половина платёжного процесса — сценарии после оплаты; именно здесь решается, каким будет клиентский опыт и насколько точным останется учёт. Ключевые различия в iyzico:

  • Возврат — полный или частичный: Есть два пути. /payment/refund работает на уровне позиции корзины (с paymentTransactionId, то есть идентификатором транзакции для позиции корзины, и price). /v2/payment/refund работает на уровне платежа (с paymentId и price); какую позицию корзины вернуть, система определяет сама. Обе версии поддерживают полный и частичный возврат и выдают банковский референс (refundHostReference, authCode).
  • Отмена: /payment/cancel вызывается только с paymentId, не поддерживает частичную сумму и отменяет весь платёж. Согласно документации iyzico, отмену можно выполнить в тот же день, что и платёж, и она не создаёт записей о списании или зачислении в выписке по карте; возврат же отражается в выписке и может занять несколько дней в зависимости от банка. Точные правила «того же дня» и время отсечения (cutoff) зависят от банка и даты валютирования, поэтому считайте это общим принципом, а не точным бухгалтерским правилом.
  • Рассрочка и запрос BIN: С помощью POST /payment/iyzipos/installment можно запросить варианты рассрочки, ставки и суммы, а также семейство и платёжную систему карты и данные о банке, передав price (обязательный параметр) и необязательный binNumber (8-значный BIN). Ставки рассрочки можно получить и только по сумме (без BIN); conversationId передаётся в запросе и возвращается в ответе без изменений (iyzico — возврат и отмена, iyzico — рассрочка и BIN).

Бизнес-правило: заложите в систему логику «в тот же день — отмена, позже — возврат»; при частичном возврате фиксируйте на своей стороне, какая позиция или сумма была возвращена, и храните банковские референсы.

Чек-лист перед запуском

  • Проверка подписи: Проверяется ли подпись каждого callback-уведомления и вебхука? Безусловно ли отклоняется непроверенный запрос? Используется ли в iyzico правильный порядок полей для вашего типа интеграции?
  • Идемпотентность: Если уведомление по тому же идентификатору заказа (merchant_oid / conversationId) приходит повторно, остаётся ли оно без повторной обработки и возвращается ли только нужный ответ?
  • Быстрый ответ: Возвращает ли callback-обработчик быстрый ответ 2xx / OK в ожидаемом формате? Вынесены ли тяжёлые операции в асинхронную очередь?
  • Проверка суммы: Сравниваются ли сумма и валюта из callback-уведомления со значением, ожидаемым по заказу?
  • Источник подтверждения: Опирается ли подтверждение заказа на межсерверное уведомление, а не на редирект браузера?
  • Закрытие незавершённых платежей: Есть ли фоновый запрос для платежей со статусом «начат, но не завершён», по которым callback-уведомление так и не пришло?
  • Возврат и отмена: Протестированы ли сценарии полного и частичного возврата, отмены и рассрочки? Сохраняются ли банковские референсы?
  • Секреты и HTTPS: Хранятся ли секреты, такие как secretKey/merchant_key/merchant_salt, только на сервере, в переменных окружения? Работает ли callback-адрес по HTTPS?
  • Логирование: Записывается ли в лог каждое платёжное событие (запрос, ответ, callback-уведомление, результат проверки подписи) так, чтобы его можно было отследить?
  • Тестовая среда: Выполнена ли сквозная проверка (включая 3DS) в песочнице или тестовом режиме провайдера?

Как Partnerfy может помочь

Как компания по разработке ПО из провинции Sakarya, работающая в формате B2B и white-label, мы рассматриваем интеграцию интернет-эквайринга не как «вызов API», а как задачу безопасности и сверки. В проекте веб-приложения на заказ или электронной коммерции мы сначала определяемся с решением: платёжная организация или банковский интернет-эквайринг, форма провайдера или прямой API (с учётом вашей области действия PCI DSS). Затем мы выстраиваем и от начала до конца проверяем в тестовой среде процесс 3DS, callback-обработчик с проверкой подписи и идемпотентностью, сверку сумм и сценарии возврата и рассрочки. Обычно мы связываем всё это с вашими действующими ERP и учётными системами в виде API-интеграции.

Честная оговорка: ни одна интеграция не может гарантировать, что проблем не будет никогда, — банки, провайдеры и документация со временем меняются. Мы обещаем не гарантию, а дисциплину: проверять подпись, соблюдать идемпотентность, доверять callback-уведомлению, логировать и сверять каждый шаг. Если вы хотите обсудить, что вам подходит — готовый плагин или заказная интеграция, в этом решении поможет и наша статья о заказном и готовом ПО.

Заключение

Интеграция интернет-эквайринга, готовая к промышленной эксплуатации, начинается с вызова API, но не заканчивается им. Настоящая работа состоит в том, чтобы выбрать правильный канал (платёжная организация или банковский интернет-эквайринг), осознанно сузить область действия PCI DSS (форма провайдера или прямой API), правильно выстроить процесс 3DS, проверять подпись callback-уведомлений, соблюдать идемпотентность, быстро возвращать 2xx/OK, сверять сумму с заказом и полностью управлять сценариями возврата, отмены и рассрочки. Именно эти шаги отличают интеграцию, которая «вроде бы работает», от действительно безопасной. Если вам нужен партнёр для проектирования платёжной интеграции или защиты существующего решения, свяжитесь с нами: мы вместе составим план по каналу, области действия PCI DSS и сверке с учётом вашего сценария.

Источники

Часто задаваемые вопросы

Что выбрать для интеграции интернет-эквайринга: форму провайдера или прямой API?

Если у вас нет бизнес-требования к брендированной и полностью контролируемой странице оплаты, выбирайте форму провайдера. В таких решениях, как PayTR iFrame или iyzico CheckoutForm, данные карты вводятся в iframe провайдера и никогда не попадают на ваш сервер, что заметно сужает область действия PCI DSS. Прямой API даёт полный контроль, но существенно увеличивает нагрузку по PCI DSS, поскольку данные карт проходят через вашу инфраструктуру.

Как работает процесс 3DS в iyzico?

В iyzico 3DS — это двухэтапный процесс на POST-запросах. Сначала на эндпоинт /payment/3dsecure/initialize отправляется POST-запрос с данными карты и параметром callbackUrl; закодированный в base64 threeDSHtmlContent из ответа отображается в браузере и перенаправляет пользователя на экран проверки в банке. После проверки на эндпоинт auth отправляется второй POST-запрос с paymentId, полученным на этапе Init; iyzico рекомендует использовать v2 (/payment/v2/3dsecure/auth). Результат передаётся в mdStatus: 1 означает успех, а 0 и 2–8 — неудачу.

Как сделать платёжный callback безопасным?

Три правила: проверяйте подпись, соблюдайте идемпотентность, отвечайте быстро. Никогда не присваивайте статус «оплачено» по входящему уведомлению, не проверив подпись (хеш HMAC-SHA256+base64 в PayTR, X-IYZ-SIGNATURE-V3 в iyzico). Не обрабатывайте повторно уведомление, которое снова пришло с тем же идентификатором заказа (merchant_oid / conversationId). Тяжёлые операции выносите в асинхронную очередь и быстро возвращайте ожидаемый ответ: iyzico ждёт 2xx, а PayTR — обычный текст «OK»; если провайдеры его не получают, они повторяют отправку.

Как сверить платёж с заказом?

Используйте уникальный идентификатор заказа, который формирует продавец: merchant_oid в PayTR, conversationId в iyzico. Это значение возвращается вам в callback-уведомлении и позволяет привязать платёж к нужному заказу. Подтверждайте заказ по межсерверному callback-уведомлению с проверенной подписью, а не по странице «успеха» в браузере; сравнивайте сумму в callback-уведомлении с ожидаемой; незавершённые платежи без callback-уведомления закрывайте с помощью фонового запроса; ежедневно сверяйте данные с отчётами провайдера.

Чем возврат отличается от отмены в iyzico?

Отмена (/payment/cancel) вызывается только с paymentId, не поддерживает частичную сумму и отменяет весь платёж; по данным iyzico, обычно её можно выполнить в тот же день, и она не создаёт записей о списании или зачислении в выписке по карте. Возврат же может быть полным или частичным: /payment/refund работает на уровне позиции корзины, а /v2/payment/refund — на уровне платежа; возврат отражается в выписке и может занять несколько дней в зависимости от банка. Точные правила «того же дня» и даты валютирования зависят от банка.

Почему для интеграции интернет-эквайринга выбирают лучшую компанию по разработке ПО в провинции Sakarya?

Partnerfy — компания по разработке ПО со штаб-квартирой в городе Adapazarı в провинции Sakarya (Сакарья) и офисами в Турции, Германии, России и Ирландии, работающая в формате B2B и white-label. Интеграцию интернет-эквайринга компания рассматривает как задачу безопасности и сверки: начиная с выбора между платёжной организацией и банковским интернет-эквайрингом, между формой провайдера и прямым API (с учётом области действия PCI DSS), она выстраивает и от начала до конца проверяет в тестовой среде процесс 3DS, callback-обработчик с проверкой подписи и идемпотентностью, сверку сумм и сценарии возврата и рассрочки. Partnerfy предлагает не гарантии, а дисциплину и прослеживаемую основу с полным логированием, поэтому входит в число предпочитаемых компаний по разработке ПО в провинции Sakarya.