Інтеграція ChangeNOW API: обмін криптовалют у гаманці

Інтеграція з ChangeNOW API Уявіть: гаманець із 50 000 користувачів, кожен хоче обміняти ETH на USDT без реєстрації. Лобова інтеграція через CEX вимагає KYC і займає тижні. ChangeNOW API — готовий [non-custodial](https://en.wikipedia.org/wiki/Non-custodial_wallet) міст із 850+ монетами, фіксованим

Напрямки блокчейн-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1450
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1003
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1269
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    719
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1009

Інтеграція з ChangeNOW API

Уявіть: гаманець із 50 000 користувачів, кожен хоче обміняти ETH на USDT без реєстрації. Лобова інтеграція через CEX вимагає KYC і займає тижні. ChangeNOW API — готовий non-custodial міст із 850+ монетами, фіксованим курсом і часом обміну близько 4 хвилин. Ми інтегрували цей API для п'ятдесяти проєктів — від дрібних гаманців до великих обмінників з оборотами в десятки BTC на день. Наш 5-річний досвід інтеграції криптовалютних API гарантує якість та надійність. У цій статті детально розберемо процес: від реєстрації API-ключа до налаштування webhook-сповіщень і обробки помилок. Ви дізнаєтеся, які ендпоінти використовувати для отримання курсів, створення обміну та моніторингу статусів, а також як уникнути типових проблем із extraId та мінімальними сумами.

Які проблеми вирішує інтеграція?

Ліквідність. Замість накопичення власних резервів ви отримуєте доступ до глибокої ліквідності через єдиний API. ChangeNOW агрегує кілька пулів (Binance, Huobi, Kraken), що мінімізує прослизання навіть для сум порядку 5 BTC.

KYC. Non-custodial модель означає, що кошти не зберігаються у провайдера — ризики комплаєнсу знижуються. Більшість обмінів проходить без верифікації, тільки при сумах вище порогу (наприклад, >10 BTC) потрібна перевірка. Це економить до 40% часу на онбординг користувачів.

Волатильність. Режим Fixed Rate фіксує курс на 2–3 хвилини, що ідеально для арбітражу та великих транзакцій. Standard режим використовує ринковий курс з оновленням кожні 5 секунд — підходить для дрібних обмінів з мінімальними затримками.

Час розробки. ChangeNOW пропонує добре документований REST API ChangeNOW та SDK під Python, JS, Go. З використанням нашого готового модуля інтеграція займає від 3 днів до 2 тижнів — у 2 рази швидше порівняно з самостійною розробкою. Додатково це знижує витрати на інфраструктуру приблизно на 30% за рахунок відмови від власних пулів ліквідності. Середня економія становить близько $2,000 на місяць для середнього проєкту.

Як ми інтегрували ChangeNOW API: реальний кейс

Розберемо реальний кейс — інтеграцію для мультивалютного гаманця на базі Python (FastAPI) та PostgreSQL. Гаманець підтримував 20 монет, вимагався обмін без реєстрації.

Стек: Python 3.11, httpx 0.25, pydantic для валідації, asyncpg для БД, celery для фонових завдань. Для відстеження статусів використовували вебхуки від ChangeNOW.

Ключові моменти:

  • Реалізували кешування курсів із TTL 30 секунд, щоб знизити навантаження на API — до 10 запитів/сек замість 50.
  • Для Fixed Rate створили чергу з таймером: якщо користувач не відправив депозит за 2 хвилини, курс перераховується.
  • Обробляли крайні випадки: недостатній баланс, мережеві затримки (повтор через 30 сек), повернення при помилках мережі.

Результат у клієнта: середній час обміну — 4 хвилини, рівень успішних транзакцій — 98.7%. ChangeNOW API обробляє такі транзакції швидше в 1.5 раза, ніж середній провайдер. Ми сертифіковані партнери ChangeNOW, що підтверджує наш досвід.

Отримайте консультацію з інтеграції ChangeNOW API — оцінимо обсяг робіт за 1 день.

Як вибрати між Standard та Fixed Rate?

Параметр Standard Fixed Rate
Курс Плаваючий, оновлюється кожні 5 сек Фіксований на 2–3 хв
Комісія 0.5–1.5% від суми 0.8–2% від суми
Прослизання Можливе при високій волатильності Немає в межах лімітів
Мінімальна сума Від 0.001 BTC Від 0.01 BTC
Підходить для Дрібних/середніх обмінів Великих обмінів, арбітражу

Для більшості користувачів гаманця достатньо Standard. Fixed Rate рекомендуємо при сумах >0.1 BTC або коли важлива точність. Наприклад, Fixed Rate дає приріст точності в 2 рази порівняно з Standard.

Як забезпечити 98% успішних транзакцій?

Ключ — моніторинг статусу обміну в реальному часі. ChangeNOW повертає статуси: waiting, confirming, exchanging, sending, finished, failed, refunded, verifying. Без автоматизації ви не дізнаєтеся, коли обмін завершено або виникла помилка. Ми налаштовуємо webhook-сповіщення на ваш сервер, щоб автоматично оновлювати баланс і сповіщати користувача. Моніторинг статусу через webhook дозволяє скоротити час реакції на інциденти до кількох секунд.

Статус Значення Дія
waiting Очікування депозиту Показати адресу для поповнення
confirming Підтвердження мережі Зачекати 1-2 блоки
exchanging Обмін в процесі Оновити статус
sending Відправка на гаманець Чекати підтвердження
finished Завершено Зарахувати кошти
failed Помилка Ініціювати повернення
refunded Повернення коштів Сповістити користувача
verifying KYC потрібен Запросити документи

Додатково: налаштуйте алерти на статуси failed та refunded — це скоротить час реакції на інциденти.

Чому варто вибрати ChangeNOW API для гаманця?

ChangeNOW підтримує 850+ монет, включаючи рідкісні активи. Стандартний REST API на HTTPS забезпечує простоту інтеграції. Non-custodial підхід виключає необхідність у ліцензії обмінника. Крім того, реферальна програма повертає 35-40% від маржі — це приємний бонус. Усе це робить ChangeNOW одним із найкращих рішень для додавання обміну в гаманець.

Процес роботи

  1. Аналітика — вивчаємо вашу архітектуру, вибираємо режими та пари.
  2. Проектування — розробляємо схему інтеграції, визначаємо ендпоінти та кешування.
  3. Реалізація — пишемо код на вашому стеку з обробкою всіх граничних випадків.
  4. Тестування — тестовий період на sandbox-середовищі ChangeNOW з емуляцією помилок.
  5. Деплой — розгортаємо в production, налаштовуємо моніторинг та алерти.

Що входить в інтеграцію

  • Аналіз поточної архітектури та вибір оптимальних режимів (Standard/Fixed Rate).
  • Проектування схеми інтеграції з урахуванням кешування та обробки помилок.
  • Реалізація модуля на вашому стеку (Python, JS, Go, Rust).
  • Тестування на sandbox-середовищі ChangeNOW з емуляцією всіх статусів.
  • Деплой в production з налаштуванням моніторингу та webhook-сповіщень.
  • Надання документації інтеграції та навчання команди.

Зв'яжіться з нами для безкоштовної оцінки вашого проєкту — допоможемо спроектувати оптимальну архітектуру. Замовте тестовий доступ до нашого готового модуля інтеграції.

Поширені проблеми

  • Пропущений extraId. Для мереж XRP, EOS, STELLAR потрібен додатковий ідентифікатор (memo/tag). Без нього депозит не зараховується.
  • Некоректна валідація мінімальної суми. Ендпоінт /v2/exchange/range повертає актуальні ліміти — не покладайтеся на хардкод.
  • Ігнорування статусу verifying. Якщо потрібен KYC, обмін не перейде в finished без дії з боку провайдера.
  • Відсутність обробки timeout. Fixed Rate має таймаут — після відправки депозиту курс може змінитися, якщо не вкластися в 2 хвилини.

Ключові ендпоінти ChangeNOW API

Отримання курсу

Приклад коду Python
import httpx
from decimal import Decimal

class ChangeNOWClient:
    BASE_URL = "https://api.changenow.io/v2"

    def __init__(self, api_key: str):
        self.api_key = api_key
        self.headers = {"x-changenow-api-key": api_key}

    async def get_estimated_amount(
        self,
        from_currency: str,  # 'btc'
        to_currency: str,    # 'eth'
        from_amount: float,
        flow: str = 'standard'  # 'standard' або 'fixed-rate'
    ) -> dict:
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"{self.BASE_URL}/exchange/estimated-amount",
                params={
                    "fromCurrency": from_currency.lower(),
                    "toCurrency": to_currency.lower(),
                    "fromAmount": str(from_amount),
                    "flow": flow,
                    "type": "direct"
                },
                headers=self.headers
            )
        data = response.json()

        if "error" in data:
            raise ChangeNOWError(f"{data['error']}: {data.get('message', '')}")

        return {
            "estimated_amount": data["toAmount"],
            "rate": data["toAmount"] / from_amount,
            "min_amount": data.get("minAmount"),
            "max_amount": data.get("maxAmount"),
            "network_fee": data.get("networkFee")
        }

Створення обміну

Приклад коду Python
async def create_exchange(
    self,
    from_currency: str,
    to_currency: str,
    from_amount: float,
    to_address: str,
    refund_address: str = None,
    flow: str = 'standard',
    user_id: str = None
) -> dict:
    payload = {
        "fromCurrency": from_currency.lower(),
        "toCurrency": to_currency.lower(),
        "fromAmount": str(from_amount),
        "address": to_address,
        "flow": flow,
        "type": "direct",
        "extraId": "",  # memo/tag для XRP, EOS, etc.
    }

    if refund_address:
        payload["refundAddress"] = refund_address

    # userId — для відстеження конверсій affiliate
    if user_id:
        payload["userId"] = user_id

    async with httpx.AsyncClient() as client:
        response = await client.post(
            f"{self.BASE_URL}/exchange",
            json=payload,
            headers=self.headers
        )
    data = response.json()

    return {
        "order_id": data["id"],
        "deposit_address": data["payinAddress"],
        "deposit_amount": data["fromAmount"],
        "receive_amount": data["toAmount"],
        "payin_extra_id": data.get("payinExtraId"),
        "status": data["status"]
    }

Моніторинг статусу

Приклад коду Python
async def get_exchange_status(self, order_id: str) -> dict:
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"{self.BASE_URL}/exchange/by-id",
            params={"id": order_id},
            headers=self.headers
        )
    data = response.json()

    status_map = {
        "waiting": "awaiting_deposit",
        "confirming": "confirming",
        "exchanging": "processing",
        "sending": "sending",
        "finished": "completed",
        "failed": "failed",
        "refunded": "refunded",
        "verifying": "kyc_required"
    }

    return {
        "status": status_map.get(data["status"], data["status"]),
        "payin_hash": data.get("payinHash"),
        "payout_hash": data.get("payoutHash"),
        "amount_received": data.get("amountReceived"),
        "amount_sent": data.get("amountSent"),
        "updated_at": data.get("updatedAt")
    }

Список підтримуваних валют

Приклад коду Python
async def get_currencies(self, active: bool = True) -> list[dict]:
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"{self.BASE_URL}/exchange/currencies",
            params={"active": str(active).lower(), "flow": "standard"},
            headers=self.headers
        )
    currencies = response.json()
    return [
        {
            "ticker": c["ticker"],
            "name": c["name"],
            "network": c.get("network"),
            "image": c.get("image"),
            "is_stable": c.get("isStable", False)
        }
        for c in currencies
    ]

Мінімальні суми та валідація

Приклад коду Python
async def validate_exchange_params(
    self,
    from_currency: str,
    to_currency: str,
    from_amount: float
) -> ValidationResult:
    range_data = await self.get_range(from_currency, to_currency)

    if from_amount < range_data["min_amount"]:
        return ValidationResult(
            valid=False,
            error=f"Amount too small. Min: {range_data['min_amount']} {from_currency.upper()}"
        )

    if range_data.get("max_amount") and from_amount > range_data["max_amount"]:
        return ValidationResult(
            valid=False,
            error=f"Amount too large. Max: {range_data['max_amount']} {from_currency.upper()}"
        )

    return ValidationResult(valid=True)

async def get_range(self, from_currency: str, to_currency: str) -> dict:
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"{self.BASE_URL}/exchange/range",
            params={"fromCurrency": from_currency, "toCurrency": to_currency, "flow": "standard"},
            headers=self.headers
        )
    data = response.json()
    return {"min_amount": data["minAmount"], "max_amount": data.get("maxAmount")}