What you’ll build
A research agent that pays for API credits on demand. The LLM sees abuy_credits tool, decides when to call it, and your code uses Tally to settle the payment. The policy you approved in the dashboard caps how much it can spend.
Prerequisites
- Quickstart complete: an agent registered, a permission granted on your test wallet, Sepolia USDC in the wallet, a working
tally.payments.create()call. - An OpenAI API key (or any LLM with tool/function calling).
The shape
Every paying-agent loop looks like this:- The LLM gets a prompt and a list of tools, one of which is “pay for something.”
- The LLM decides to call the payment tool with structured arguments.
- Your code receives the tool call, asks Tally to execute the payment, and returns the result to the LLM.
- The LLM uses the result (success, failure, balance, etc.) to continue.
1. Define the tool
2. Map vendor → recipient address
You’ll need to translate a friendly vendor name into an EVM address Tally can pay. Keep this table somewhere your code controls — never let the LLM pick the destination.recipient_allowlist policy bound would block it.
3. Implement the tool handler
- Errors are returned to the LLM as natural language, not thrown. The LLM can then decide what to do — try a smaller amount, ask the user for guidance, abandon the task. Throwing breaks the agent loop.
- The idempotency key is deterministic-ish within a session. For a production agent, use something more stable than
Date.now()— a request id, a session id, a workflow step id — so retries within the same session are safe.
4. The agent loop
runAgent("Find recent papers on RLHF.") runs an LLM loop where the model can buy credits from approved vendors as needed. Every payment is bounded by the policy you approved for research-bot; the LLM has no way to bypass it.
Per-agent attribution
If you run several agents in parallel —research-bot, summarizer, publisher — give each its own Tally agent id and a separate permission with its own policy. The dashboard will show per-agent spend; webhooks will carry the originating agent_id so your downstream system can attribute too.
Patterns
- Return errors as content, not exceptions. The LLM can recover from a structured error message (“daily cap reached”) in a way it can’t recover from an exception.
- Keep recipient addresses out of LLM-visible state. Map labels server-side. Tally’s
recipient_allowlistis a second line of defense, but server-side mapping prevents the LLM from even trying. - Use idempotency keys derived from a deterministic source. A workflow step id, a tool call id, an invoice id — anything that survives a retry. Avoid
Date.now()in production. - Subscribe to
payment.confirmedwebhooks for downstream reconciliation. The LLM gets apendingpayment back from the tool call; if your business logic cares about confirmation, react in the webhook, not in the agent loop.