Skip to content

Repository files navigation

langgraph-ucashpay

LangGraph nodes and LangChain tools to monetize individual graph steps via U.CASH (HTTP-402). Non-custodial: the only credential in flight is a publishable store Cloud token, and funds always settle directly to the merchant. This library never touches money.

Gate an expensive LLM call, a tool, or a whole subgraph behind a hosted U.CASH checkout link. The library exposes three layers of increasing convenience:

  • UcashPayClient - a thin client over the two pay.u.cash public pay endpoints (embed link + server-tracked checkout).
  • build_ucashpay_node(...) / require_payment(...) - LangGraph nodes that inject a pay link into your graph state.
  • ucashpay_tool(...) - a LangChain StructuredTool an agent can call to charge-and-return a link.

Install

pip install langgraph-ucashpay
# with the LangGraph / LangChain extras:
pip install "langgraph-ucashpay[langgraph]"

Python 3.9+. The only hard runtime dependency is httpx. LangGraph and LangChain are optional (installed via the [langgraph] extra) so the client is usable in any project.

Quick start

1. Client: build a publishable pay link

from langgraph_ucashpay import UcashPayClient

client = UcashPayClient.from_cloud(
    "st_your_store_cloud_token",   # publishable, safe in the browser/app
    default_currency="USD",
    default_title="Premium answer",
)

link = client.embed_url(
    amount=0.05,
    external_reference="order_123",  # your idempotency / order id
)
print(link)  # https://pay.u.cash/embed.php?cloud=st_...&amount=0.05&...

2. LangGraph: gate a step behind a checkout

from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict
from langgraph_ucashpay import build_ucashpay_node

class State(TypedDict, total=False):
    input: str
    payment_url: str
    payment_reference: str
    payment_pending: bool
    answer: str

def expensive_step(state: State) -> dict:
    # only run if payment has been completed upstream
    return {"answer": run_your_llm(state["input"])}

g = StateGraph(State)
g.add_node("bill", build_ucashpay_node(client, amount=0.05))
g.add_node("work", expensive_step)

g.add_edge(START, "bill")

# Branch: if payment is still pending, end with the pay link; else continue to work.
g.add_conditional_edges(
    "bill",
    lambda s: "work" if not s.get("payment_pending") else END,
    {"work": "work", END: END},
)
g.add_edge("work", END)

graph = g.compile()
print(graph.invoke({"input": "Summarize the changelog."}))

By default the node builds the publishable embed link locally (no network call, fully non-custodial). Pass use_embed_link=False to instead POST to pay.u.cash and create a server-tracked, idempotent checkout from a server route:

bill = build_ucashpay_node(client, amount=0.05, use_embed_link=False)

3. LangChain: expose "charge and return a link" as a tool

from langgraph_ucashpay import ucashpay_tool

tool = ucashpay_tool(client, amount=0.05, name="ucash_pay")
# An agent can now call ucash_pay(reference="order_123", amount=0.05)
# and receive the hosted pay link to surface to the user.

4. Decorator: wrap any node

from langgraph_ucashpay import require_payment

@require_payment(client, amount=0.05)
def summarize(state):
    return {"answer": run_your_llm(state["input"])}

How it maps to the pay.u.cash API

This package implements exactly two documented endpoints. It does not invent fields.

Client-side hosted pay link (publishable Cloud token, usable straight from the browser, no server secret):

GET https://pay.u.cash/embed.php
query: cloud, amount, currency (default USD), title,
       external_reference, redirect

UcashPayClient.embed_url() and the default node mode produce this URL. Because the Cloud token is publishable, this URL is safe to render in a chat message, embed in a tool result, or ship to the browser.

Server-side tracked checkout (call from a server route; idempotent per external_reference):

POST https://pay.u.cash/payment/ajax.php
body (application/x-www-form-urlencoded):
    function=create-transaction, amount, currency_code,
    cryptocurrency_code= (empty string), external_reference, title,
    redirect, cloud, idempotent=1
response JSON { success: true, response: [paymentUrl, transactionId, ...] }
  -> the payment URL is the array element that starts with http(s)://

UcashPayClient.create_checkout() / create_checkout_async() and the node in use_embed_link=False mode call this. The client locates the payment URL by scanning the response array for the first element starting with http:// or https://.

Both clients also ship async variants (embed_url_async, create_checkout_async) for use in async servers and async LangGraph runtimes.

Non-custodial model and limitations

  • Non-custodial. This library carries only the publishable store Cloud token. It never receives, holds, or moves funds. Settlement goes directly to the merchant's configured receive addresses.
  • The Cloud token is publishable. It is safe to embed in the browser, in a rendered tool result, or in an LLM message. It is not an account secret.
  • HTTP-402 framing, request-then-pay. A graph step produces a hosted pay link the caller opens; the caller pays on pay.u.cash; you reconcile via your own webhook or a status check before running the paid work. This is the U.CASH agent model.
  • No automatic crypto recurring billing. pay.u.cash does not provide a hosted auto-charge API for recurring crypto payments. For recurring revenue, treat each graph run as a discrete, idempotent checkout keyed on external_reference and re-gate per invocation. This package does not attempt to fake recurring billing.
  • Payment confirmation is out of scope for this client. pay.u.cash notifies you via webhook of completion. Configure your webhook (see your pay.u.cash store settings) and flip your state's payment_pending flag when the webhook confirms external_reference. The example graph above shows the branch pattern; the webhook handler is yours to wire.

Examples

See examples/gated_graph.py for a runnable end-to-end gating demo:

UCASH_CLOUD_TOKEN=st_your_store_token python examples/gated_graph.py

Publish

This repository ships the packaging files; publishing is left to the maintainer. To build and publish to PyPI:

python -m pip install --upgrade build twine
python -m build
python -m twine upload dist/*

Set up your pay.u.cash account

  1. Sign up at pay.u.cash, then click the verification link in the email.
  2. Set receive addresses under Settings -> Addresses (raw address, ENS, Unstoppable Domains, or FIO).
  3. Create a store under Account -> Stores and copy its Store Cloud Token (use the store-level token, not the account-wide one).
  4. For fiat cards, connect your own Stripe under Settings -> Payment processors.

License

MIT, see LICENSE.

Releases

Packages

Contributors

Languages