Вводные данные

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

  1. Быстрая обработка большого объема запросов для получения курсов валют и готовых результатов конвертации.

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

Пример конкретной задачи: Банк А принимает оплату только в PLN (польский злотый), но покупатель готов оплатить это только картой с валютой EUR. Нам необходимо определить сумму в PLN для отправки запроса к банку-эквайру. Какие есть варианты решения этой задачи?

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

  2. Отказ от принятия оплаты в неподдерживаемой валюте (неоптимальный вариант для бизнеса, но идеальный для разработчика).

  3. Попросить банк добавить поддержку нужной валюты (часто невозможно).

Изначально выбрал пе��вый вариант, который казался успешным, пока не стали поступать жалобы о том, что суммы списания превышают заявленные. Дальнейший анализ показал, что средний курс валют сильно отличается от фактического и зависит от многих факторов, таких как провайдер, который выпустил карту, правила конвертации у банка, который принимает платеж.

Пример 1: У вас карта в евро. Вы совершаете покупки в отпуске в Италии тоже в евро. Сумма покупки — 50 евро, итого с вашего счёта спишется 50 евро.

Пример 2: У вас карта в евро. Вы совершаете покупку в Польше в польских злотых. В этом случае схема пересчёта следующая: польские злотые (PLN) → пересчитываются в USD по курсу Mastercard, далее USD → пересчитываются в CNY по курсу Mastercard, затем CNY → пересчитываются в евро по курсу банка.

(ref: https://telegra.ph/Izmenenie-valyuty-raschyotov-po-kartam-Mastercard-04-03)

Для точного расчета суммы после всех конвертаций нам нужна информация о курсах валют от следующих источников:

  1. "Mastercard" PLN -> USD

  2. "Mastercard" USD -> CNY

  3. "Альфа-Банк Беларусь" CNY -> EUR

С такими вводными приступаем к анализу рынка...

Анализ рынка

Напомню, мы выделили основные критерии поиска:

1) Быстрая обработка большого объема запросов для получения курсов валют и готовых результатов конвертации.

2) Возможность создания собственных стратегий конвертации, учитывая различные ос��бенности, например, принятие оплаты в одной валюте и конвертацию в другую.

Сервис

Плюсы

Минусы

Xe

+ быстрый и удобный API
+ есть возможность выбора источника курса валют (но на данный момент только центральные банки нескольких стран, что недостаточно для моего кейса)
+ есть курсы криптовалюты

- дорого
- нет возможности создания собственных стратегий для конвертации

Openexchangerates

+ быстрый и удобный API
+ приятная цена

- нет возможности создания собственных стратегий для конвертации
- нет возможности выбрать источник курса

Currencylayer

+ быстрый и удобный API
+ приятная цена

- нет возможности создания собственных стратегий для конвертации
- нет возможности выбрать источник курса

Coinlayer

+ быстрый и удобный API
+ приятная цена
+ есть курсы криптовалюты

- нет возможности создания собственных стратегий для конвертации
- нет возможности выбрать источник курса

Fixer

+ быстрый и удобный API
+ приятная цена

- нет возможности создания собственных стратегий для конвертации
- нет возможности выбрать источник курса

Изначально выбрал https://openexchangerates.org и использовал именно его, но достаточно быстро появились новые бизнес-кейсы, такие как пример с "Альфа-Банк Беларусь" и покупкой в PLN, когда этого функционала перестало хватать. Об этом упоминалось выше.


Все сервисы имели почти одинаковый набор плюсов и минусов, но главное, что ни один из них не имел того, что требовалось мне. С этого момента произошло разочарование из-за отсутствия нужного инструмента, но с другой стороны появилось вдохновение от возможности создать то, что будет работать именно под мою конкретную задачу. Благодаря этому анализу у меня возникла некоторая насмотренность на то, как крупные игроки рынка делают свои API. Поэтому в моей голове уже начала складываться база того, как это должно выглядеть: source_currency, target_currency, amount, base_currency, и поехали, думал я. Но как я ошибался, что этим все ограничится.

Разработка

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

  • /api/v1/rates - эндпоинт, который позволяет получать курсы валют, указывая необходимые параметры.

{
  "rate_source_code": "alfa_bank_belarus", // Каждый источник курса имеет свой уникальный код.
  "exchange_type_code": "card", // Определяет, какой курс использовать. В банках могут быть разные курсы для карточек, наличных операций и т.д.
  "category_code": "bank", // Некоторые источники могут предоставлять курсы валют разных категорий, таких как банки и биржи.
  "branch": "main", // Некоторые источники курса имеют разные курсы валют для различных отделений или филиалов.
  "rounding": 2, // Округление результата до указанного числа цифр после запятой.
  "test_mode": true
}
  • /api/v1/conversions - этот эндпоинт выполнит конвертацию в соответствии с указанной стратегией, учитывая все соответствующие правила и параметры конвертации.

{
  "strategy_code": "alfa_bank_belarus_custom_1", // Код стратегии обмена, который создается отдельно (следующий эндпоинт, который ниже).
  "source_currency": "PLN",
  "target_currency": "EUR",
  "amount": 40.99,
  "source_currency_unit": "amount", // Формат суммы конвертации, который может быть как в привычном формате (1.00), так и в копеечном (100). Этот параметр регулирует формат.
  "target_currency_unit": "amount", // Как и выше, только это формат результата.
  "rounding": 2,
  "test_mode": true
}
  • /api/v1/conversion_strategies - для создания стратегии конвертации валют.

{
  "code": "alfa_bank_belarus_custom_1",
  "name": "Custom strategy for Alfa-Bank Belarus",
  "data": [
    {
      "priority": 1, // Приоритет внутренней конвертации.
      "action_type": "accurate", // Можно задавать точный курс валют у определенного источника, либо брать средний ("average").
      "rate_source_code": "mastercard",
      "category_code": "payment_system",
      "exchange_type_code": "card",
      "target_currency": "USD",
      "base_currency": "BYN" // Валюта для конвертации, используемая в случае отсутствия у источника курса прямой конвертации запрошенных валют.
    },
    {
      "priority": 2,
      "action_type": "accurate",
      "rate_source_code": "mastercard",
      "category_code": "payment_system",
      "exchange_type_code": "card",
      "target_currency": "CNY",
      "base_currency": "BYN"
    },
    {
      "priority": 3,
      "action_type": "accurate",
      "rate_source_code": "alfa_bank_belarus",
      "category_code": "bank",
      "exchange_type_code": "card",
      "target_currency": "REQUESTED",
      "base_currency": "BYN"
    }
  ]
}

Как только все было запущено в продакшн и протестировано, я почувствовал облегчение. Однако, спустя некоторое время осознал, что получился микросервис, который по своей функциональности объединяет все доступные на рынке API-сервисы для конвертации валют и получения курсов. Кроме того, он добавляет такие возможности, как:

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

  2. Создание собственных стратегий для конвертации, которые позволяют решать самые сложные кейсы.

  3. Использование точной конвертации осуществляется по определенным парам��трам, таким как источник курса, его тип обмена и категория. Альтернативно, можно использовать средний курс из всех источников, доступных в базе данных, с учетом фильтрации по категории источника валют.

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

Какие функции или возможности вам кажутся наиболее важными или полезными для улучшения этого сервиса? Я открыт к обсуждению и готов рассмотреть любые предложения по его улучшению.


P.S. Сам микросервис я трансформировал в отдельное API, к которому теперь есть доступ не только у меня. Если кто-то захочет использовать его или просто "потыкать палкой", то велкоме: https://irates.io.