Skip to main content

changenow-client

PyPI version License: ISC Python Version

Modern, fully typed Python client library for the ChangeNOW cryptocurrency exchange API (v2).

Official API documentation: https://documenter.getpostman.com/view/8180765/SVfTPnM8

The PyPI package is changenow-client. Import it as changenow.


Features

  • ⚡ Standard & Fixed-Rate Swaps — Floating estimates and fixed-rate locks via rateId.
  • 🪙 Multi-Network Assets — Currencies, pairs, limits, and fees include the network (BTC, ERC-20, TRC-20, and the rest of the v2 catalog).
  • 🐍 Modern Pythonic Design — Type annotations, context manager support (with ChangeNow(...) as client:), and a dedicated ChangeNowError.
  • 🔒 Non-Custodial — Create an exchange, then poll status until ChangeNOW pays the payout address.

Installation

pip install changenow-client

Requires Python 3.10 or higher.


Authentication

Partner attribution is the partner API key. The client sends it in one header:

from changenow import CHANGENOW_API_KEY_HEADER

print(CHANGENOW_API_KEY_HEADER)  # "x-changenow-api-key"

TODO: the partner header name is pending confirmation from ChangeNOW. The published v2 docs and 401 text use x-changenow-api-key. The available-pairs sample uses x-api-key. Change CHANGENOW_API_KEY_HEADER in src/changenow/client.py if ChangeNOW confirms a different name. Do not add a second partner header until they confirm one.

user_id and payload on create are optional and stay disabled until ChangeNOW enables "Special partner fields". contact_email and source are optional create fields from the public examples. Pass the end-user IP as user_ip to send the documented x-forwarded-for header.


Quick Start (Safe Check)

The quick check only reads currencies, the minimum, an estimate, and an address check. It does not create an exchange:

import os
from changenow import ChangeNow

with ChangeNow(api_key=os.environ["CHANGENOW_API_KEY"]) as client:
    currencies = client.get_currencies(active=True, flow="standard")
    print(f"Available currencies: {len(currencies)}")

    minimum = client.get_min_amount("btc", "eth", "btc", "eth", flow="standard")
    print(f"Minimum: {minimum['minAmount']} BTC")

    estimate = client.get_estimated_amount(
        "btc",
        "eth",
        from_amount="0.1",
        from_network="btc",
        to_network="eth",
        flow="standard",
    )
    print(f"Estimated receive amount: {estimate['toAmount']} ETH")

Usage Guide

1. Creating a Standard (Floating) Exchange

from changenow import ChangeNow, ChangeNowError

with ChangeNow(api_key="your_api_key") as client:
    order = client.create_exchange(
        "btc",
        "eth",
        "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
        from_network="btc",
        to_network="eth",
        from_amount="0.1",
        refund_address="bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
        flow="standard",
        user_id="user-42",  # optional, requires Special partner fields
        contact_email="trader@example.com",
        source="wallet",
    )
    print(f"Send BTC to: {order['payinAddress']}")
    print(f"Exchange id: {order['id']}")

2. Creating a Fixed-Rate Exchange

quote = client.get_estimated_amount(
    "btc",
    "eth",
    from_amount="0.1",
    from_network="btc",
    to_network="eth",
    flow="fixed-rate",
    use_rate_id=True,
)
fixed_order = client.create_exchange(
    "btc",
    "eth",
    "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    from_network="btc",
    to_network="eth",
    from_amount="0.1",
    flow="fixed-rate",
    rate_id=quote["rateId"],
)
print(f"Locked until {quote['validUntil']}")
print(f"Payout: {fixed_order['toAmount']} ETH")

3. Tracking Status

status = client.get_exchange(order["id"])
print(status["status"])  # waiting, confirming, exchanging, sending, finished, ...

if status["status"] == "finished":
    print(f"Payout hash: {status.get('payoutHash')}")

API Reference

ChangeNow Class

Constructor

ChangeNow(
    api_key: str | None = None,
    base_url: str | None = None,
    timeout: float = 30.0,
    user_agent: str | None = None,
    user_ip: str | None = None,
)
Parameter Type Default Description
api_key str CHANGENOW_API_KEY Partner API key.
base_url str "https://api.changenow.io/v2" API base URL.
timeout float 30.0 Request timeout in seconds.
user_agent str "changenow-client/0.1.0" User-Agent header.
user_ip str unset Sent as x-forwarded-for.

Methods

  • get_currencies(...) — GET /exchange/currencies
  • get_available_pairs(...) — GET /exchange/available-pairs
  • get_min_amount(...) — GET /exchange/min-amount
  • get_range(...) — GET /exchange/range
  • get_estimated_amount(...) — GET /exchange/estimated-amount (standard and fixed-rate)
  • create_exchange(...) — POST /exchange
  • get_exchange(exchange_id) — GET /exchange/by-id
  • validate_address(currency, address) — GET /validate/address
  • get_user_addresses(name) — GET /addresses-by-name
  • get_network_fee(...) — GET /exchange/network-fee
  • get_market_estimate(...) — GET /markets/estimate (crypto and fiat, informational, fees excluded)
  • get_exchanges(...) — GET /exchanges (private API key)
  • get_exchange_actions(exchange_id) — GET /exchange/actions
  • continue_exchange(exchange_id) — POST /exchange/continue
  • refund_exchange(...) — POST /exchange/refund
  • get_private_transfer_estimate(...) — GET /private-transfer/estimated-amount
  • create_private_transfer(...) — POST /private-transfer

Several of these routes are enabled per partner key. A 403 means the endpoint is not activated for that key.


Error Handling

from changenow import ChangeNow, ChangeNowError

try:
    with ChangeNow(api_key="invalid_key") as client:
        client.get_currencies()
except ChangeNowError as exc:
    print(f"{exc.code}: {exc.message} (HTTP {exc.status_code})")

Address validation does not raise for a bad address. The response is HTTP 200 with result: false.


Live Tests

Unit tests mock HTTP and always run. The live suite calls the real API and runs only when CHANGENOW_API_KEY is set. It is read-only: currencies, minimum amount, a standard-flow estimate, and address validation. It never creates an exchange.

uv run pytest -m "not live"
CHANGENOW_API_KEY=your_key uv run pytest -m live

License

ISC

Metadata

Release files for changenow-client 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for changenow-client 0.1.0
File Size Uploaded Provenance
changenow_client-0.1.0.tar.gz 25.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for changenow-client 0.1.0
File Interpreter ABI Platform
changenow_client-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 35.8 kB

Release files / changenow_client-0.1.0.tar.gz

Download URL changenow_client-0.1.0.tar.gz
Size 25.1 kB
Tags Source
SHA-256 checksum
How to use checksums
4f04f2e5944485f3a1d0363e7889fca0318b6ccdc620bfa97d9a877185add8e3
BLAKE2b-256 checksum
How to use checksums
811434cf3f4a938012b68ca4de3ab6fd568257021c90cd7c9b3034681f084fdb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / changenow_client-0.1.0-py3-none-any.whl

Download URL changenow_client-0.1.0-py3-none-any.whl
Size 10.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9541027f845b73cd3f920d3cd0946a69df0ed1dec6c2ead04430fabb8a312f12
BLAKE2b-256 checksum
How to use checksums
94c1734775240fef98b8f28969fd20816fdb982ebd46e582b034722c54f53d81
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for changenow-client 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page