Skip to main content

PayWay REST API - Python

  • Store customers, their card and bank account in PayWay
  • Take payment using a stored credit card or bank account
  • Process and Capture a pre-authorisation
  • Lookup or poll transactions
  • Refund transactions
  • Void transactions
  • Update a customer's payment setup in PayWay

Install

Requires Python 3.11 or later.

pip install python-payway

Take payment using a stored credit card

Create a Client class with your PayWay API credentials

from payway.client import Client

client = Client(merchant_id='<your_payway_merchant_id>',
                bank_account_id='<your_payway_bank_account_id>',
                publishable_api_key='<your_payway_publishable_api_key>',
                secret_api_key='<your_payway_secret_api_key>')

Create a PayWayCustomer class with your customer's details

customer = PayWayCustomer(custom_id='c981a',
                          customer_name='John Smith',
                          email_address='johnsmith@example.com',
                          send_email_receipts=False,  # not available in sandbox
                          phone_number='0343232323',
                          street='1 Test Street',
                          street2='2 Test Street',
                          city_name='Sydney',
                          state='NSW',
                          postal_code='2000')

Create a PayWayCard class with your customer's card details

card = PayWayCard(card_number='',
                  cvn='',
                  card_holder_name='',
                  expiry_date_month='',
                  expiry_date_year='')

Create a token from your card and create a customer in PayWay

token_response, errors = client.create_card_token(card)
token = token_response.token        
customer.token = token
payway_customer, customer_errors = client.create_customer(customer)

Note the 'payway_customer' object contains the full customer response fields from PayWay.

Create a Payment class with the payment details and process the transaction

customer_number = payway_customer.customer_number
payment = PayWayPayment(customer_number=customer_number,
                        transaction_type='payment',
                        amount='',
                        currency='aud',
                        order_number='',
                        ip_address='')
transaction, errors = client.process_payment(payment)

Check the transaction for the result

if not errors and transaction.status == 'approved':
    # process successful response

Take payment using a credit card token only

client = Client(merchant_id='',
                bank_account_id='',
                publishable_api_key='',
                secret_api_key='')
card = PayWayCard(card_number='',
                  cvn='',
                  card_holder_name='',
                  expiry_date_month='',
                  expiry_date_year='')
token_response, errors = client.create_card_token(card)
# your customer reference number or a stored PayWay customer number
customer_number = ''    
payment = PayWayPayment(customer_number=customer_number,
                        transaction_type='payment',
                        amount='',
                        currency='aud',
                        order_number='',
                        ip_address='',
                        token=token_response.token,
                        merchant_id=client.merchant_id)
transaction, errors = client.process_payment(payment)

Retries

Retries are off by default. Opt in with max_retries (and optionally retry_delay, the base wait in seconds between attempts):

client = Client(merchant_id='<your_payway_merchant_id>',
                bank_account_id='<your_payway_bank_account_id>',
                publishable_api_key='<your_payway_publishable_api_key>',
                secret_api_key='<your_payway_secret_api_key>',
                max_retries=2,
                retry_delay=1.0)

This follows PayWay's retry guidance (https://www.payway.com.au/docs/rest.html#network-errors):

  • Requests are resent on connection errors, timeouts and HTTP 429/503 responses, waiting retry_delay seconds between attempts (linear backoff, or the response's Retry-After header when present). PayWay suggests a 20 second wait; keep retry_delay small for synchronous checkout flows.
  • POSTs are only retried when an idempotency_key was supplied — the same Idempotency-Key is resent so PayWay replays the original response instead of processing a duplicate payment. POSTs without a key (and PUTs) are never retried. GETs are always safe to retry.
  • Other errors (including HTTP 500/502/504) are never retried, per PayWay's advice.
transaction, errors = client.process_payment(payment, idempotency_key=str(uuid.uuid4()))

Handling errors

Documented errors (such as 422 Unprocessable entity) are parsed into an PaymentError class that you can use in an customer error message. For more info, visit https://www.payway.com.au/docs/rest.html#http-response-codes

if errors:
    for error in errors: 
        print(error.field_name)
        print(error.message) 
        print(error.field_name)
    # or use a method
    PaymentError().list_to_message(errors) 

Direct Debit

Direct debit transactions are possible by creating a token from a bank account:

bank_account = BankAccount(account_name='Test', bsb='000-000', account_number=123456)
token_response, errors = client.create_bank_account_token(bank_account)
token = token_response.token

Store the token with a customer in PayWay using the same process as the card outlined above.

Note: direct debit transactions take days to process so they must be polled regularly for the latest transaction status from the customer's bank.

Lookup transaction

Poll a transaction using the get_transaction method.

transaction, errors = client.get_transaction(transaction.transaction_id)

Search transactions

PayWay has no plain GET /transactions resource, only three search paths. Each returns a paginated list (20 per page, most recent first) with next/prev links.

response = client.search_transactions_by_customer(customer_number)
response = client.search_transactions_by_receipt(receipt_number)
response = client.search_transactions_by_order(order_number)

transactions = response["data"]

Pass page to fetch a later page, using the number from the next/prev links:

response = client.search_transactions_by_customer(customer_number, page=2)

list_customers() takes the same page argument.

Process and capture a pre-authorisation

To process a credit card pre-authorisation using a credit card stored against a customer use preAuth as the transaction_type along with the customer's PayWay number, amount and currency.

pre_auth_payment = PayWayPayment(customer_number='',
                                 transaction_type='preAuth',
                                 amount='',
                                 currency='aud',
                                 order_number='',
                                 ip_address='')
transaction, errors = client.process_payment(pre_auth_payment)

To capture the pre-authorisation supply a pre-authorisation transaction ID, capture as the transaction_type along with an amount to capture.

capture_payment = PayWayPayment(transaction_type='capture',
                                parent_transaction_id='',
                                amount='',
                                order_number='',
                                ip_address='')
transaction, errors = client.process_payment(capture_payment)

Refunds

Refund a transaction by supplying a PayWay transaction ID and the refund amount.

refund, errors = client.refund_transaction(
    transaction_id=transaction.transaction_id,
    amount=transaction.principal_amount,
)

Voiding a transaction

Void a transaction by supplying a PayWay transaction ID.

void_transaction, errors = client.void_transaction(transaction.transaction_id)

Update Payment Setup

Update a customer's payment setup with a new credit card or bank account in PayWay. Supply the new token and an existing PayWay customer number.

payment_setup, errors = client.update_payment_setup(new_token, payway_customer.customer_number)

Renewing the secret API key

Secret API keys expire one year after they are created. PayWay generates the replacement 40 days before that, so an application that asks for the latest key once a day and stores what it gets back rolls onto the new key without an administrator creating one in the PayWay website.

api_key, errors = client.get_latest_api_key()
if api_key and api_key.key != stored_secret_api_key:
    # Persist api_key.key. Log api_key.key_name - it is masked; the key itself is a password.
    save_secret_api_key(api_key.key)

Usually the key returned is the one that authenticated the call. Renewal chains off the live key, so if the stored key is left to expire the call fails with a PaywayError and recovery means minting a key by hand — poll daily and alert on repeated failures.

To test your renewal code, create two secret API keys in the PayWay website, configure the first, and confirm the application switches to the second on its own.

Additional notes

PayWay API documentation https://www.payway.com.au/docs/rest.html

It is recommended to use PayWay's Trusted Frame https://www.payway.com.au/docs/rest.html#trusted-frame when creating a single use token of a card or bank account so your PCI-compliance scope is reduced.

Keeping the raw response

Models parsed from a PayWay response keep that response verbatim on raw:

transaction, errors = client.process_payment(payment)
transaction.raw  # exactly what PayWay returned

Parsing is lossy — keys PayWay sends that the dataclass does not declare are dropped, absent keys become None, and a few are renamed (maskedCardNumber is parsed into card_number). Store raw rather than to_dict() if you are persisting responses for auditing, reconciliation or dispute resolution. Models you construct yourself, such as a PayWayPayment you are about to send, leave raw as None.

Fraud

Please follow PayWay's advice about reducing your risk of fraudulent transactions. https://www.payway.com.au/docs/card-testing.html#card-testing

Running the project

uv sync

uv provisions a suitable Python (3.11+) and installs the dev dependencies automatically.

Testing

uv run pytest tests/ -v

Release files for python-payway 0.0.11

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

Source distribution (sdist)

Source distribution for python-payway 0.0.11
File Size Uploaded
python_payway-0.0.11.tar.gz 24.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for python-payway 0.0.11
File Interpreter ABI Platform
python_payway-0.0.11-py3-none-any.whl Python 3 none any Details

Total release size: 42.5 kB

Release files / python_payway-0.0.11.tar.gz

Download URL python_payway-0.0.11.tar.gz
Size 24.1 kB
Tags Source
SHA-256 checksum
How to use checksums
9a2703b49c5d8c85a22c3af0fd87a4b7dd9ec16d839a23bda3b49e347c0e9693
BLAKE2b-256 checksum
How to use checksums
5904f1f411d40673afc8ca9688cf9411567346099ced59d1ec8689dc25c2852e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.

Transparency log

Release files / python_payway-0.0.11-py3-none-any.whl

Download URL python_payway-0.0.11-py3-none-any.whl
Size 18.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9ecd631e8ea39cb60c10a86b61158200b28084b45d77af692e08e7048e7dda32
BLAKE2b-256 checksum
How to use checksums
cc199372ae22e0fc2fe8feb691e4d93ec213a24495fde2d7a5fd6dea8209798e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.11 This release

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

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