Skip to main content

TapPay Python SDK

CI PyPI version Python Versions Code style: ruff License: MIT

This is the unofficial Python client library for TapPay's Backend API. To use it you'll need a TapPay account. Sign up at tappaysdk.com.

Installation

Install using pip:

pip install tappay

Usage

Initialization

import tappay

# Initialize the client
client = tappay.Client(
    is_sandbox=True,
    partner_key="YOUR_PARTNER_KEY",
    merchant_id="YOUR_MERCHANT_ID",
)

For production, you can set TAPPAY_PARTNER_KEY and TAPPAY_MERCHANT_ID environment variables and omit them in the constructor:

client = tappay.Client(is_sandbox=False)

Timeouts

Every request carries a timeout by default: (3.05, 27.0) seconds, as a (connect, read) pair. Override it for all calls on a client:

client = tappay.Client(is_sandbox=False, timeout=10.0)

Or for a single call, using the keyword-only timeout argument available on every API method:

response = client.refund(rec_trade_id="rec_trade_id", amount=100, timeout=(3.05, 60.0))

Passing timeout=None to the constructor disables the timeout entirely, which lets a stalled request block the calling thread indefinitely. This is almost never what you want in a server process.

Logging

The client logs request and response details at DEBUG level. Credentials (partner_key, x-api-key), card handles (prime, card_key, card_token), and cardholder PII (name, email, phone number, address, national ID) are replaced with ***REDACTED*** before anything reaches the logger, so enabling debug logging will not spill payment data into your log aggregator.

import logging

logging.getLogger("tappay.client").setLevel(logging.DEBUG)

Pay by Prime

# Create cardholder data
card_holder = tappay.Models.CardHolderData(
    phone_number="0912345678",
    name="Wang Xiao Ming",
    email="test@example.com",
)

# Make payment
response = client.pay_by_prime(
    prime="prime_token_from_frontend",
    amount=100,
    details="Order #123",
    card_holder_data=card_holder,
)
print(response)

Pay by Token

response = client.pay_by_token(
    card_key="card_key",
    card_token="card_token",
    amount=100,
    details="Subscription",
)

Refunds

Omit amount to refund the transaction in full; pass it for a partial refund:

# Full refund
response = client.refund(rec_trade_id="rec_trade_id")

# Partial refund
response = client.refund(
    rec_trade_id="rec_trade_id",
    amount=100,
)

Currencies

Payments settle in TWD by default. TapPay documents four currencies, each tied to the acquirer configured for your merchant account:

Currency Acquirer
TWD Most acquirers
HKD Bank of China
MYR RAZER PAY
USD Global Payments

Pass currency to override the default, using either a Models.Currencies member or a plain currency string (strings are accepted so a currency TapPay adds before this list is updated remains usable):

response = client.pay_by_prime(
    prime="prime_token_from_frontend",
    amount=100,
    details="Order #123",
    card_holder_data=card_holder,
    currency=tappay.Models.Currencies.USD,
)

Handling failures

TapPay reports business failures such as a declined card with an HTTP 200 and a non-zero status in the response body, so they are invisible to HTTP-level error handling. By default the response is returned as-is and it is your job to check:

response = client.pay_by_prime(...)
if response["status"] != 0:
    ...  # declined, invalid argument, insufficient balance, and so on

Pass raise_on_error=True to have the client raise TapPayError instead:

client = tappay.Client(is_sandbox=False, raise_on_error=True)

try:
    response = client.pay_by_prime(...)
except tappay.TapPayError as exc:
    print(exc.status, exc.msg, exc.response["rec_trade_id"])

get_records is exempt from one case: the Record API answers status: 2 for "no more records under this filter", which is how pagination terminates. That is treated as a normal result, not an error, even with raise_on_error=True.

The exception hierarchy is:

Exception Raised when
AuthenticationError HTTP 401
ClientError HTTP 4xx
ServerError HTTP 5xx, or an unexpected status code
InvalidResponseError A 2xx body that is not valid JSON (subclasses ServerError)
TapPayError Non-zero status in a 2xx body (only with raise_on_error=True)

All of them subclass tappay.Error.

An intermediary such as a proxy or WAF can answer with an HTML error page under a 2xx status. That previously surfaced as a bare json.JSONDecodeError from inside requests; it now raises InvalidResponseError, reporting the status, host, content type, and body length. The body itself is deliberately left out of the message, since exception text tends to end up in logs and error trackers.

Connection reuse and retries

Each client owns a pooled session. Close it when you are done, or use the client as a context manager:

with tappay.Client(is_sandbox=False) as client:
    client.pay_by_prime(...)

The read-only query endpoints (get_records, get_trade_history) retry twice on connection errors and on HTTP 429/500/502/503/504, with exponential backoff. Payment, refund, capture, bind, and remove endpoints are never retried automatically: TapPay exposes no idempotency key, so retrying a request that actually succeeded upstream would charge the cardholder twice. Tune the retry count with max_retries=, or disable it with max_retries=0.

For more API details, please refer to the TapPay Backend API Documentation.

Development

Setup

  1. Clone the repository:
git clone https://github.com/shihweilo/tappay-python.git
cd tappay-python
  1. Create a virtual environment and install dependencies:
python3 -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
pip install -e ".[dev]"

Testing

Run tests using pytest:

pytest

Run tests with coverage:

pytest --cov=tappay --cov-report=term-missing

Type check with mypy:

mypy tappay

Linting and Formatting

Check code with ruff:

ruff check .

Format code with ruff:

ruff format .

Contributing

Please see CONTRIBUTING.md for details.

Metadata

Release files for tappay 0.7.3

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

Source distribution (sdist)

Source distribution for tappay 0.7.3
File Size Uploaded
tappay-0.7.3.tar.gz 28.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tappay 0.7.3
File Interpreter ABI Platform
tappay-0.7.3-py3-none-any.whl Python 3 none any Details

Total release size: 43.9 kB

Release files / tappay-0.7.3.tar.gz

Download URL tappay-0.7.3.tar.gz
Size 28.8 kB
Tags Source
SHA-256 checksum
How to use checksums
9376e4199e03c7ccbc050dcbba1896f64fe4b9ec2edc51a8c159171a13528846
BLAKE2b-256 checksum
How to use checksums
3a98b10747a9596ca7d8538222d9ece3615652d62431e82b3c7c601b0357abcc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 9, 2026.

Transparency log

Release files / tappay-0.7.3-py3-none-any.whl

Download URL tappay-0.7.3-py3-none-any.whl
Size 15.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dd6f6c290ad50dd0e4956de54a71d16490692172665464bb9c2d2b4142708d28
BLAKE2b-256 checksum
How to use checksums
751b01d2c0679e23d013d6c93e87647eef8aeaa3c6858cd3fcdbcb6730ba600e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 9, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.7.3 This release

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

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