Unofficial Python SDK for the Airwallex API — payouts, FX, global accounts, and more.
Project description
airwallex-python
Unofficial Python SDK for the Airwallex API — payouts, FX, balances, global accounts, beneficiaries, deposits, and webhooks.
[!IMPORTANT] This is an unofficial, community-maintained library. It is not affiliated with, endorsed by, or supported by Airwallex Pty Ltd — "Airwallex" is their trademark, used here only to describe compatibility. The SDK is in beta: the public interface may change before v1.0, so pin your version. For vendor-supported tooling, use the official Node.js SDK.
Airwallex's only official server-side SDK is Node.js. This library brings the same developer experience to Python:
- Sync and async clients (
Airwallex/AsyncAirwallex) built on httpx - Automatic authentication — token fetched on first use and refreshed before expiry; no manual login calls
- Idempotent by default —
request_idis auto-generated for money-moving calls, so retries never double-pay - Automatic retries with full-jitter exponential backoff on 408/429/5xx/network failures (honours
Retry-After; 409 business conflicts are never retried) - Typed responses — Pydantic v2 models that are immutable and forward-compatible (unknown fields preserved, never dropped)
- Auto-pagination — iterate every page with one loop
- Webhook signature verification with replay protection
- Typed errors —
RateLimitError,AuthenticationError, … each carrying the Airwallex errorcode,source, andrequest_id
Installation
Available on PyPI:
pip install airwallex
Requires Python 3.9+. Releases follow semantic versioning; see the changelog.
Quickstart
Create API credentials in the Airwallex web app under Developer → API keys, then:
from airwallex import Airwallex
client = Airwallex(
client_id="your_client_id", # or set AIRWALLEX_CLIENT_ID
api_key="your_api_key", # or set AIRWALLEX_API_KEY
environment="demo", # "production" (default) or "demo" sandbox
)
# Current wallet balances
for balance in client.balances.current():
print(balance.currency, balance.available_amount)
Send a payout
Payouts use
/api/v1/transfers, which requires API version 2024-01-31 or later. If your account default is older, passapi_version="2024-01-31"(or newer) to the client.
transfer = client.transfers.create(
beneficiary_id="ben_abc123",
source_currency="USD",
transfer_currency="PHP",
transfer_amount=5000,
transfer_method="LOCAL",
reference="Invoice 42",
reason="professional_service_fees",
)
print(transfer.id, transfer.status)
request_id is generated for you (pass your own to control idempotency). Airwallex will never execute the same request_id twice — including across the SDK's automatic retries.
FX: quote and convert
rate = client.rates.current(buy_currency="USD", sell_currency="SGD", buy_amount=1000)
print(rate.client_rate)
conversion = client.conversions.create(
buy_currency="USD",
sell_currency="SGD",
buy_amount=1000,
term_agreement=True,
)
Accept a payment
intent = client.payment_intents.create(
amount=25.00,
currency="USD",
merchant_order_id="order_42",
)
confirmed = client.payment_intents.confirm(intent.id, payment_method={"type": "card", "card": {...}})
refund = client.refunds.create(payment_intent_id=intent.id, amount=5.00)
Issue a card
cardholder = client.issuing_cardholders.create(
email="employee@example.com",
individual={"name": {"first_name": "Ada", "last_name": "Lovelace"}},
type="INDIVIDUAL",
)
card = client.issuing_cards.create(
cardholder_id=cardholder.cardholder_id,
form_factor="VIRTUAL",
created_by="Ada Lovelace",
program={"purpose": "COMMERCIAL"},
)
Test flows in the sandbox
client.simulation.create_deposit(amount=1000, currency="USD") # demo environment only
client.simulation.transition_transfer("tra_123", next_status="PAID")
Auto-pagination
# Iterates page by page under the hood
for beneficiary in client.beneficiaries.list(page_size=100).auto_paging_iter():
print(beneficiary.beneficiary_id, beneficiary.nickname)
Async
import asyncio
from airwallex import AsyncAirwallex
async def main() -> None:
async with AsyncAirwallex(environment="demo") as client:
page = await client.transfers.list(status="PAID")
async for transfer in page.auto_paging_iter():
print(transfer.id)
asyncio.run(main())
Webhooks
Verify and parse incoming notifications (get the secret when you create the webhook endpoint):
from airwallex import webhooks, WebhookSignatureError
def handle(request): # any web framework
try:
event = webhooks.construct_event(
payload=request.body, # raw bytes — do not re-serialise
timestamp=request.headers["x-timestamp"],
signature=request.headers["x-signature"],
secret=WEBHOOK_SECRET,
)
except WebhookSignatureError:
return 400
if event.name == "transfer.settled":
...
return 200
Error handling
from airwallex import Airwallex, RateLimitError, APIStatusError
try:
client.transfers.retrieve("tra_missing")
except RateLimitError:
... # already retried automatically; back off further
except APIStatusError as err:
print(err.status_code, err.code, err.message, err.request_id)
All API errors inherit from airwallex.APIError; network failures raise airwallex.APIConnectionError.
Calling endpoints the SDK doesn't wrap yet
Every list method accepts extra query params as keyword arguments, and the client exposes a raw escape hatch with auth, retries, and error mapping intact:
page = client.transfers.list(short_reference_id="REF123") # extra filter
disputes = client.request("GET", "/api/v1/pa/payment_disputes", params={"status": "OPEN"})
Typed responses
Response models live in airwallex.types and preserve unknown fields for forward compatibility:
from airwallex.types import Transfer, Balance
def settle(transfer: Transfer) -> None: ...
Bring your own httpx client
import httpx
client = Airwallex(http_client=httpx.Client(proxy="http://proxy:3128"))
The SDK applies the base URL and default headers per request, so proxies and custom TLS work without extra configuration; the SDK will not close a client you own.
Connected accounts (platforms)
client = Airwallex(on_behalf_of="acct_connected_account_id") # sets x-on-behalf-of
Pinning an API version
client = Airwallex(api_version="2024-01-31") # sets x-api-version on every request
Two quirks observed against the live demo API, worth knowing:
- Airwallex versions endpoint groups independently — e.g.
conversions.listrequires2024-01-31on some accounts whilefx/rates/currentrejects it. If you hitincorrect_versionerrors, use a second client pinned differently for that endpoint group. - Several list endpoints enforce a minimum
page_sizeof 10 and returninvalid_argumentbelow it. - Payment-acceptance lifecycle actions (
payment_intents.confirm/capture/cancel,customers.update) require arequest_id— the SDK auto-generates one, like it does for creates. webhook_endpoints.createrequires aversionfield (e.g.version="2024-01-31").
Resources covered
| Resource | Methods |
|---|---|
client.balances |
current, history |
client.transfers |
create, retrieve, list, cancel, validate, confirm_funding |
client.batch_transfers |
create, retrieve, list, add_items, delete_items, items, quote, submit, delete |
client.wallet_transfers |
create, retrieve, list |
client.payers |
create, retrieve, update, delete, list, validate |
client.beneficiaries |
create, retrieve, update, delete, list, validate |
client.conversions |
create, retrieve, list |
client.rates |
current |
client.fx_quotes |
create, retrieve |
client.conversion_amendments |
create, quote, retrieve, list |
client.payment_intents |
create, retrieve, list, confirm, confirm_continue, capture, cancel |
client.customers |
create, retrieve, update, list, generate_client_secret |
client.refunds |
create, retrieve, list |
client.issuing_cardholders |
create, retrieve, update, delete, list |
client.issuing_cards |
create, retrieve, update, activate, limits, list |
client.issuing_transactions |
retrieve, list |
client.issuing_authorizations |
retrieve, list |
client.accounts |
retrieve |
client.financial_transactions |
retrieve, list |
client.settlements |
retrieve, list |
client.simulation |
demo-only: deposit create/settle/reject/reverse, transfer/payment transitions |
client.global_accounts |
create, retrieve, update, close, list, transactions |
client.deposits |
list |
client.reference |
supported_currencies, settlement_accounts, invalid_conversion_dates |
client.webhook_endpoints |
create, retrieve, update, delete, list |
airwallex.webhooks |
verify_signature, construct_event |
Coverage now matches (and in webhooks/pagination/simulation, exceeds) the official Node.js SDK's main surfaces — contributions welcome for the remaining areas (disputes, payment consents, linked accounts, scale/platform APIs).
Status
This SDK is beta software:
- The wrapped endpoints are grounded in Airwallex's published API spec and covered by tests, but they have not yet been exercised against every account configuration.
- Semantic versioning applies: breaking changes only in minor versions while
0.x, and patch releases never change behavior. - Response models tolerate unknown fields, so new Airwallex API versions won't break parsing.
- Test in the
demoenvironment before pointing at production, and pin the version in your dependency file (e.g.airwallex==0.2.0).
Development
uv sync # install dependencies
uv run pytest # run tests
uv run ruff check . # lint
uv run mypy # type-check
Disclaimer
This project is an independent, unofficial SDK maintained by the community. It is not affiliated with, endorsed by, sponsored by, or supported by Airwallex Pty Ltd. "Airwallex" and related marks are trademarks of Airwallex Pty Ltd; they are used here solely to indicate API compatibility. This software is provided "as is" under the MIT license — review the SECURITY policy and test against the demo environment before moving real money. If you need vendor support or SLAs, use the official Node.js SDK.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file airwallex-0.2.1.tar.gz.
File metadata
- Download URL: airwallex-0.2.1.tar.gz
- Upload date:
- Size: 119.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7a4e109d40d088bc94f163a0822e4959e222a79f1cc58566f154a95c8c520922
|
|
| MD5 |
2b0d752530d04e5c4b0f762484cbe9fd
|
|
| BLAKE2b-256 |
1c39906e0c2cd773c8beba97fb5eea854e91acde3c1fb6d6769538fffdd34aec
|
Provenance
The following attestation bundles were made for airwallex-0.2.1.tar.gz:
Publisher:
release.yml on Cyvid7-Darus10/airwallex-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
airwallex-0.2.1.tar.gz -
Subject digest:
7a4e109d40d088bc94f163a0822e4959e222a79f1cc58566f154a95c8c520922 - Sigstore transparency entry: 2044124257
- Sigstore integration time:
-
Permalink:
Cyvid7-Darus10/airwallex-python@c681d2c667ab0259964af7a88d95fa2eb0a44d11 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/Cyvid7-Darus10
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c681d2c667ab0259964af7a88d95fa2eb0a44d11 -
Trigger Event:
push
-
Statement type:
File details
Details for the file airwallex-0.2.1-py3-none-any.whl.
File metadata
- Download URL: airwallex-0.2.1-py3-none-any.whl
- Upload date:
- Size: 53.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0944f28b3d84069f7c28175a5a408a589ad7cfcd628e72ea60fbf83f9f89f633
|
|
| MD5 |
9a1c4b1cc209f7de30c638fa51b7f619
|
|
| BLAKE2b-256 |
38e754e26b4674ed66485b5d38d13b331f4208dc283678ab0e8e43d3789cb19f
|
Provenance
The following attestation bundles were made for airwallex-0.2.1-py3-none-any.whl:
Publisher:
release.yml on Cyvid7-Darus10/airwallex-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
airwallex-0.2.1-py3-none-any.whl -
Subject digest:
0944f28b3d84069f7c28175a5a408a589ad7cfcd628e72ea60fbf83f9f89f633 - Sigstore transparency entry: 2044124283
- Sigstore integration time:
-
Permalink:
Cyvid7-Darus10/airwallex-python@c681d2c667ab0259964af7a88d95fa2eb0a44d11 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/Cyvid7-Darus10
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c681d2c667ab0259964af7a88d95fa2eb0a44d11 -
Trigger Event:
push
-
Statement type: