from l402.payment_clients import Client, CoinbaseProvider
from cdp import Wallet
l402-python
Usage
Installation
Install latest from pypi
$ pip install l402
Documentation
Documentation can be found hosted on this GitHub repository’s pages. Additionally you can find package manager specific guidelines on conda and pypi respectively.
How to use
Paying with the L402
The L402 supports multiple payment providers. In this example we’ll use a coinbase wallet as an onchain provider. This wallet will be used to pay for L402 offers.
# CDP can be directly used as an onchain provider.
= Wallet.create()
w
= Client(onchain_provider=CoinbaseProvider(wallet=w)) c
Next we retrieve an offer from a demo server. This will return a 402 status code and a JSON response with the available offers.
= httpx.get("http://localhost:9000/offers")
r1 r1.status_code, r1.json()
(402,
{'offers': [{'amount': 1,
'currency': 'USD',
'description': 'Purchase 1 credit for API access',
'offer_id': '58e1ee0a-e283-4f80-8a41-5c2f0ea138ca',
'payment_methods': ['onchain'],
'title': '1 Credit Package',
'type': 'one-time'}],
'payment_context_token': '42f46106-8989-4ed1-a770-adf9ad64c30b',
'payment_request_url': 'http://localhost:9000/payment_request',
'version': '0.2.2'})
To pay, we just need to provide the L402 response to the client and it will automatically use configured payment provider that matches the payment method.
if r1.status_code == HTTPStatus.PAYMENT_REQUIRED:
= c.pay(r1.json()) ps
Getting paid with the L402
The L402 protocol implements a two-step payment flow:
- The server returns a
402 Payment Required
status code and information about the available offers. - The client uses the L402 response to fetch the information for a specific payment method.
In this example, we implement this using a server with two endpoints:
/offers
- Returns available payment options with 402 status/payment_request
- Generates payment details for chosen payment method
from l402.payment_providers import PaymentServer, Offer
= FastAPI()
app
= PaymentServer(
ps ="http://localhost:9000/payment_request",
payment_request_url=w,
onchain_provider
)
@app.get("/offers")
def offers():
= [Offer(
offers_list =1,
amount='USD',
currency='Purchase 1 credit for API access',
description=str(uuid4()),
offer_id=['onchain'],
payment_methods='1 Credit Package',
titletype='one-time'
)]
= ps.create_offers(offers_list)
offers_response # Return the status code 402 Payment Required with the offers
return JSONResponse(content=offers_response.model_dump(), status_code=402)
@app.post("/payment_request")
async def create_payment_request(request: PaymentRequest):
= ps.create_payment_request(**request.model_dump())
payment_request return JSONResponse(content=payment_request)
= httpx.get("http://localhost:9000/offers")
r = r.json()
offers_data r.status_code, offers_data
(402,
{'offers': [{'amount': 1,
'currency': 'USD',
'description': 'Purchase 1 credit for API access',
'offer_id': '1808e12c-1824-49d8-a348-278959f6008d',
'payment_methods': ['onchain'],
'title': '1 Credit Package',
'type': 'one-time'}],
'payment_context_token': '82dbf89a-b18f-4737-b350-c58731b1cc18',
'payment_request_url': 'http://localhost:9000/payment_request',
'version': '0.2.2'})
The client can use this offer to request the information for a payment method. We have to choose the payment method and, in the case of coinbase, the chain and asset.
= dict2obj(offers_data)
offers_data = {
data "offer_id": offers_data.offers[0].offer_id,
"payment_method": 'onchain',
"chain": 'base-sepolia', # choose the chain where you want to pay
"asset": 'usdc', # choose the asset you want to pay
"payment_context_token": offers_data.payment_context_token
}= httpx.post(offers_data.payment_request_url, json=data)
r r, r.json()
(<Response [200 OK]>,
{'expires_at': '2025-01-30T21:03:46.502392+00:00',
'offer_id': '1808e12c-1824-49d8-a348-278959f6008d',
'payment_request': {'address': '0x6EC717D99534aF3917E25De1024f9e5BcDc1B262',
'chain': 'base-sepolia',
'asset': 'usdc'},
'version': '0.2.2'})