Python SDK watenga

Python 3.9 or later (httpx).

Installation

bash
pip install watenga

Before the first release

The package is release-ready; until it is published, install it from a checkout of the Watenga repository:
bash
pip install ./packages/watenga-python

Take a test payment

Use a test secret key (sk_test_…) from the developer console. Test keys never move money: use the test cards and wallet numbers.

python
import os
from watenga import Watenga

watenga = Watenga(os.environ["WATENGA_SECRET_KEY"])  # sk_test_...

checkout = watenga.checkout.create(
    amount="25.00",
    currency="USD",
    merchant_transaction_id="ORD-1001",
    return_url="https://shop.example/return",
)
# Send the buyer to checkout["payment_url"]

Receive the webhook

Verify the Watenga-Signature header against the raw request body before you trust an event. While you rotate the endpoint's signing secret, pass both secrets: either one verifies. On your machine, watenga listen --forward-to <your URL> (the CLI) forwards test events signed with a session secret.

python
from flask import Flask, request
from watenga import construct_event, SignatureVerificationError

@app.post("/webhooks")
def webhooks():
    try:
        event = construct_event(request.get_data(), request.headers.get("Watenga-Signature"), os.environ["WATENGA_WEBHOOK_SECRET"])
    except SignatureVerificationError:
        return "", 400
    if event["type"] == "payment.capture.completed":
        ...  # fulfil the order for event["data"]["object"]
    return "", 200

Errors

Every failed call raises one error type with the stable code, the HTTP status, the request_id to quote to support, the field at fault (param) and the code's page in the error reference.

python
from watenga import WatengaError

try:
    watenga.refunds.create("txn_...", amount="5.00", reason="customer_request")
except WatengaError as err:
    print(err.code, err.status_code, err.param, err.request_id, err.doc_url)

Retries and idempotency

Network errors, 429 (after Retry-After) and 5xx answers are retried twice with backoff. Every write carries an Idempotency-Key, kept across those retries, so a retry is answered once and never applied twice; checkout.create uses checkout:<merchant_transaction_id>. See Idempotency.

python
# Every write gets an Idempotency-Key, kept across the SDK's own retries.
# When you retry a call yourself, pass the same key:
watenga.refunds.create("txn_...", reason="duplicate", idempotency_key="refund-ORD-1001")

Pagination

Every list answers one page, { object: "list", data, has_more, next_cursor }; the auto-paginating form reads them all. See Pagination.

python
page = watenga.transactions.list(status="completed", limit=50)
# {"object": "list", "data": [...], "has_more": ..., "next_cursor": ...}

for txn in watenga.transactions.list_all(status="completed"):
    print(txn["id"], txn["amount"], txn["currency"])

Resources

The SDK sends Watenga-Version: 2026-10-29; fields use the API's names (snake_case) and money is a decimal string. The same method names in every language.

ResourceMethods
checkoutcreate, get_status
checkout_sessionscreate, retrieve, expire
transactionslist, list_all, retrieve, get_mobile_status
refundscreate
payment_linkscreate, list, list_all, retrieve, update, deactivate, clone
invoicescreate, list, list_all, retrieve, update, send, remind, void
quotationscreate, list, list_all, retrieve, update, issue, void, convert_to_invoice
planscreate, list, list_all, retrieve, update, delete
subscriptionscreate, list, list_all, retrieve, cancel, pause, resume, upcoming_invoice
billingrecord_usage, reverse_usage, check_entitlement
customerscreate, list, list_all, retrieve, update, timeline, set_tag
payment_methodscreate, list, list_all, retrieve, delete, charge
accountget_balance, get_profile, get_api_key
construct_eventwebhook verification (several secrets while rotating)

Resources come back as dicts; watenga.types has a TypedDict for each, generated from the OpenAPI document.

Refunds and payouts

A secret key refunds when its app's Refunds switch is on and an Admin has set refund limits; a restricted key needs the refunds scope (Refunds). Payouts to your bank are dashboard-only, with two-step verification: they are not in the API or the SDKs.