Bag is live โ€” accept USDC & card payments globally. Get started โ†’
BagBag Docs
SDKs

Python SDK

Official Python SDK for the Bag payment platform.

Python SDK

The official Bag Python SDK provides typed access to the Bag API with built-in retry logic, timeout handling, and idiomatic Python interfaces.

Installation

pip install bag-sdk

Quick Start

import os
from bag_sdk import Bag

bag = Bag(api_key=os.environ["BAG_API_KEY"])

# Create a payment link
link = bag.payment_links.create(
    name="Pro Plan",
    amount=29.99,
    network="base",
    description="Monthly Pro subscription",
)
print(f"Payment URL: https://getbags.app/pay/{link.id}")

# List payment links
result = bag.payment_links.list(limit=25)
for link in result.data:
    print(f"{link.name}: ${link.amount}")

# Get a single link
link = bag.payment_links.get("link_id")

# Update a link
updated = bag.payment_links.update("link_id", amount=39.99, active=False)

# Delete a link
bag.payment_links.delete("link_id")

Checkout

# Get a tax quote
quote = bag.checkout.get_tax_quote(
    paymentLinkId="link_id",
    customerAddress={
        "address_line_1": "100 Main St",
        "address_city": "San Francisco",
        "address_province": "CA",
        "address_postal_code": "94105",
        "address_country": "US",
        "address_type": "billing",
    },
)

# Create a checkout session
session = bag.checkout.create_session(
    linkId="link_id",
    quoteToken=quote.quote_token,
    walletAddress="0xCustomerWallet",
    walletType="evm",
    network="base",
    customer={
        "name": "Jane Doe",
        "email": "jane@example.com",
        "address": "100 Main St, San Francisco, CA 94105",
        "country": "US",
    },
    totalsSnapshot={
        "subtotalCents": quote.subtotal_cents,
        "taxCents": quote.tax_cents,
        "totalCents": quote.total_cents,
        "calculationId": quote.calculation_id,
    },
)

# Check session status
session = bag.checkout.get_session(session.id)
print(f"Status: {session.status}")

# Submit a transaction hash
bag.checkout.submit(session_id=session.id, tx_hash="0xabc123...")

Transactions

# List transactions
result = bag.transactions.list(limit=50)
for tx in result.data:
    print(f"{tx.status}: ${tx.amount} on {tx.network}")

# Record a transaction
tx = bag.transactions.create(
    amount=29.99,
    token="USDC",
    network="base",
    txHash="0xabc123...",
    walletAddress="0xCustomerWallet",
    customerEmail="customer@example.com",
    paymentLinkId="link_id",
)

Refunds

# List refunds
result = bag.refunds.list()
for refund in result.data:
    print(f"Refund {refund.id}: ${refund.amount}")

# Create a refund
refund = bag.refunds.create(
    transactionId="txn_123abc",
    amount=29.99,
    reason="customer_request",
)

Webhooks

# List webhook endpoints and delivery history
wh = bag.webhooks.list()
for endpoint in wh.endpoints:
    print(f"{endpoint.url}: {'active' if endpoint.active else 'paused'}")
print(f"Success rate (24h): {wh.health_stats.success_rate}%")

# Create a webhook endpoint
endpoint = bag.webhooks.create(
    url="https://yourapp.com/webhooks/bag",
    events=["payment.completed", "payment.failed"],
)
print(f"Secret (store this!): {endpoint.secret}")

# Update a webhook endpoint
bag.webhooks.update("endpoint_id", active=False)

# Delete a webhook endpoint
bag.webhooks.delete("endpoint_id")

Verify webhook signatures

import hashlib
import hmac
import time

def verify_webhook(raw_body: bytes, signature_header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in signature_header.split(","))
    timestamp = parts["t"]
    expected = parts["v1"]

    if abs(time.time() - int(timestamp)) > 300:
        return False

    message = f"{timestamp}.{raw_body.decode()}"
    computed = hmac.new(
        secret.encode(), message.encode(), hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(computed, expected)

Events

# List all events
result = bag.events.list(limit=50)
for event in result.data:
    print(f"{event.event}: {event.status} ({event.attempts} attempts)")

# Filter by type and status
failed = bag.events.list(event="payment.completed", status="failed")

# Filter by date range
recent = bag.events.list(since="2026-03-01T00:00:00Z", until="2026-04-01T00:00:00Z")

Customers

# List customers
result = bag.customers.list(limit=25)
for customer in result.data:
    print(f"{customer.email}: ${customer.total_spent} ({customer.transaction_count} txns)")

# Get a customer
customer = bag.customers.get("customer_id")

# Create a customer
customer = bag.customers.create(
    email="alice@example.com",
    name="Alice Johnson",
    country="US",
)

# Update a customer
updated = bag.customers.update("customer_id", name="Alice J.", country="GB")

Error Handling

from bag_sdk import Bag, BagError

bag = Bag(api_key="bag_test_sk_...")

try:
    link = bag.payment_links.create(name="Test", amount=0, network="base")
except BagError as e:
    print(f"Error {e.status_code}: {e}")
    print(f"Code: {e.code}")

Context Manager

The SDK supports Python's context manager protocol for automatic cleanup:

with Bag(api_key=os.environ["BAG_API_KEY"]) as bag:
    links = bag.payment_links.list()
    # connection is automatically closed when the block exits

What's next

On this page