Quickstart
Five minutes from zero to your first verified receipt. We'll install the Python tool, sign in with a crypto wallet, ask an AI question, and check the receipt.
What you need
- Python 3.10 or newer on your computer.
- A crypto wallet — MetaMask, Rabby, or any modern browser wallet. You don't need any money in it; it's just used as your login identity.
- A few minutes.
If you've never used a crypto wallet before, MetaMask has a good installation guide. Come back here when you've set one up.
1. Install the Plumb toolkit
pip install plumb-sdk
This installs two things: the plumb command-line tool (for signing in) and the Python library (for using Plumb in your code).
2. Sign in
Plumb doesn't use email and password. Instead, you prove who you are by signing a message with your wallet — the same wallet logs you into every Plumb-compatible app without any shared credentials.
Run:
plumb auth login --api-base https://api.plumbtech.xyz
A browser window will open. Connect your wallet, click "Sign" when prompted (this doesn't cost anything — you're just signing a text message, not sending any money), and the CLI will print a session token.
Save it for the next step:
export PLUMB_SESSION=sess_01HVBZ...
First-time visitors get free test credits — a small amount of PLMB (Plumb's usage token) is dropped into your account automatically so you can try things out.
3. Ask an AI question
Make a file called hello.py:
import os
from plumb_sdk import Client
c = Client(
base_url="https://api.plumbtech.xyz",
session_token=os.environ["PLUMB_SESSION"],
)
resp = c.chat.completions.create(
model="anthropic/claude-haiku-4.5",
messages=[{"role": "user", "content": "in one sentence, what is a receipt?"}],
)
print(resp.choices[0].message.content)
print("receipt →", resp.id)
Run it:
python hello.py
You'll see the AI's answer, plus a receipt ID that looks like c7f3e0a4-5b82-4a1c-.... That ID is your receipt for this exact answer.
4. Verify the receipt
Same script, add a few lines at the bottom:
rcpt = c.receipts.get(resp.id)
assert c.verify_receipt(rcpt), "signature didn't match"
print("verified ✓", rcpt.id)
print("cost:", rcpt.cost_micro, "μPLMB")
print("model:", rcpt.model)
verify_receipt does all the cryptography for you. If it returns True, you have mathematical proof that:
- Plumb really produced this receipt.
- Nobody modified it after the fact.
- It was issued by the exact model and at the exact cost it claims.
That's the whole promise of Plumb, in a single line of Python.
5. See it in the explorer
Open this URL in your browser, swapping in your receipt ID:
https://explorer.plumbtech.xyz/receipt/<your-receipt-id>
You'll see the receipt, laid out nicely, with a Verify signature button. Click it — the explorer redoes the check right in your browser. Green means genuine.
Anyone with the link can open this page. The receipt is yours to share, archive, or use as evidence.
6. (Optional) Watch it settle on-chain
A couple of minutes after you got your receipt, Plumb batches it up with other recent receipts and records a summary on the Base blockchain. This gives your receipt a second, independent timestamp that nobody — including Plumb — can erase.
Re-fetch your receipt after a few minutes:
rcpt2 = c.receipts.get(resp.id)
if rcpt2.settlement_tx_hash:
print("settled on-chain:", rcpt2.settlement_tx_hash)
print("→ https://base-sepolia.blockscout.com/tx/" + rcpt2.settlement_tx_hash)
else:
print("not settled yet — try again in a minute")
If settlement_tx_hash is populated, you can click that Blockscout link and see the public record of the batch your receipt was part of. See Settlement for what this means and why it matters.
What next?
Now that you have a working connection, you can try:
- Memory — let Plumb remember earlier conversations across sessions. Pass
extra_body={"plumb_memory": True}on a chat call. Memory docs. - Hub — upload your own AI model and run it through Plumb. Hub docs.
- Pipe — let a smart contract on Base call an AI model and receive a verifiable answer. Pipe docs.
- Self-host — run your own Plumb server on any VPS. About 30 minutes start to finish. Self-hosting guide.
For developers
The login flow is SIWE (Sign-In-With-Ethereum, EIP-4361). The CLI fetches a nonce from /v1/auth/nonce, prompts your wallet to personal_sign a formatted message over it, and exchanges the signature at /v1/auth/verify for an opaque session token. Session tokens go in Authorization: Bearer <token>.
The completion call goes through /v1/chat/completions (OpenAI-compatible, so any OpenAI SDK also works with base_url swapped). Internally the gateway hashes the request, routes to the upstream provider (Anthropic in this example), captures the response, runs a single Postgres transaction that debits the PLMB balance and inserts a receipt row, and signs the canonical v1 payload with Ed25519. Receipt id is returned on the X-Plumb-Receipt response header.
verify_receipt re-derives the canonical payload from the receipt fields, fetches the public key for rcpt.signer_key_id from /v1/verification/keys, and runs Ed25519 verification. The explorer's browser-side verifier (@noble/ed25519) does the same thing in a separate implementation — cross-implementation divergence is caught by a shared fixture of input → output vectors in CI.
Self-hosted instances mint test balances via the admin endpoint:
curl -X POST https://api.yourdomain/admin/mint \
-H "Authorization: Bearer $PLUMB_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"addr":"0xYOUR_ADDRESS","amountMicro":"1000000"}'
PLUMB_ADMIN_TOKEN must be set in the gateway env; otherwise the admin routes return 404.