Skip to content

Repository files navigation

coatipay — Python SDK

The CoatiPay Python SDK — Stripe-compatible payments for the open web. Accept USDC on Base with no gatekeepers: gasless settlement (ERC-3009), webhooks, and x402 micropayments. 1.5% protocol fee (1.05% nodeit / 0.45% treasury), settled trustlessly on-chain.

  • Gasless for payers — they sign an ERC-3009 authorization; the nodeit pays the gas.
  • 🧩 Stripe-like DXpayment_intents.create, webhooks.verify.
  • 🌐 Open network — no lock-in: any nodeit can settle your payments, and anyone can run one.

Install

pip install coatipay-sdk

Requires Python ≥ 3.11. Depends on httpx and pydantic.

Quick start

The client is async (built on httpx.AsyncClient):

import asyncio
from coatipay import CoatiPay


async def main():
    # Use a SECRET key, server-side only — never ship it to a client.
    async with CoatiPay(api_key="sk_live_...") as relay:
        intent = await relay.payment_intents.create(
            amount=10_000_000,            # 10.00 USDC (6 decimals → 1 USDC = 1_000_000)
            currency="usdc",
            chain="base",
            metadata={"order_id": "123"},
        )
        print(intent["id"], intent["status"])  # "pi_…", "created"


asyncio.run(main())

Other payment-intent methods: retrieve(id), list(limit=10), cancel(id).

Gasless settlement with ERC-3009

Payers authorize USDC transfers off-chain with an EIP-712 signature. The nodeit pays the gas to settle on-chain.

The authorization's nonce is the intent being paid: you pass the intent id the API gave you (pi_…) and the SDK derives the on-chain form. The contract requires that binding, so a payer's signature can only ever settle that one intent — the nodeit relaying it cannot redirect the payment elsewhere.

from coatipay.eip712 import sign_authorization, serialize_authorization

intent = await relay.payment_intents.create(amount=1_000_000, currency="usdc", chain="base")

auth = sign_authorization(
    payer="0xPayerAddress...",
    amount=1_000_000,                         # 1.00 USDC — must match the intent
    settlement_hub="0xSettlementHubAddress...",
    chain="base",
    private_key="0x...",                      # payer private key — server-side demo only
    intent_id=intent["id"],                   # "pi_…" — the nonce is derived from it
)

await relay.payment_intents.submit_authorization(intent["id"], auth)

For batch settlement, pass a list of {"intent_id": ..., "authorization": auth} items to relay.payment_intents.submit_authorization_batch(items) (max 50 per batch).

If you build the authorization yourself — a browser wallet signing the typed data, for instance — derive the nonce with the same helper the SDK uses, so both sides agree on the value the contract checks:

from coatipay import intent_id_to_bytes32

nonce = intent_id_to_bytes32(intent["id"])  # keccak256(utf8("pi_…"))

x402 micropayments

Protect a FastAPI / Starlette route with a 402 payment gate.

from fastapi import FastAPI
from coatipay import CoatiPay, X402Middleware

relay = CoatiPay(api_key="sk_live_...", merchant_wallet="0xMerchantWallet...")

app = FastAPI()
app.add_middleware(
    X402Middleware,
    client=relay,
    price=1_000,          # 0.001 USDC
    currency="usdc",
    chain="base",
    description="Premium API access",
)

@app.get("/premium")
async def premium():
    return {"data": "exclusive"}

Or use the dispatch helper with Starlette's BaseHTTPMiddleware:

from starlette.middleware.base import BaseHTTPMiddleware

app.add_middleware(
    BaseHTTPMiddleware,
    dispatch=relay.x402.middleware(price=1_000, currency="usdc", chain="base"),
)

Webhooks

event = relay.webhooks.verify(
    payload,                                  # raw request body (str)
    signature=request.headers["x-signature"],
    secret="whsec_...",
)
if event["type"] == "payment_intent.settled":
    fulfill_order(event["data"]["metadata"]["order_id"])

Configuration

CoatiPay(
    api_key="sk_live_...",                  # required — secret key, server-side only
    base_url="https://api.coatipay.com",  # optional — your CoatiPay API host
    timeout=30.0,                           # optional — seconds
    merchant_wallet="0x...",                # optional — receives x402 payments
)

Links

About

SDK de Python para CoatiPay — cobros en USDC sin custodia

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages