---
name: tuppence
description: Take payments with Tuppence (tuppence.ai) — payment links, card payments, refunds, subscriptions, metered usage and prepaid credit, over its REST API, SDKs or MCP server. Use when the user wants to charge someone, sell access to something, bill for usage, or check what they've been paid.
---

# Tuppence

Tuppence is a payments API for developers and AI agents, built on Stripe. It takes UK card
payments through hosted pages (checkout, payment links, subscriptions) and bills usage from
prepaid credit (meters, HTTP 402). Docs: https://app.tuppence.ai/docs/ · Full docs for LLMs: https://app.tuppence.ai/docs/llms-full.txt

## Rules — follow these every time

1. **Test mode unless the user explicitly says otherwise.** Use a key starting `sk_test_` (or a
   restricted `rk_test_` key). Never ask for, print or store a live key (`sk_live_`/`rk_live_`).
   Keys come from the environment (`TUPPENCE_SECRET_KEY`), never from code or chat.
2. **Every `POST` carries an `Idempotency-Key`** — a UUID, or a natural id like `order-1042`.
   Retrying with the same key returns the first result instead of charging twice. It is
   required on payments, refunds, payouts and credit top-ups.
3. **Amounts are integers in minor units.** £20.00 is `2000`. Never send decimals.
4. **Ask a person before anything irreversible in live mode:** refunds, payouts, charging a
   saved card, cancelling a subscription.
5. **Card numbers never go through you.** Payers enter cards on Tuppence's hosted pages. Never
   ask a user for a card number, CVC or PIN.
6. **Branch on `error.code`, not the message.** Retry only network errors, `5xx`, `429` (honour
   `Retry-After`) and `409 idempotency_in_progress`.

## Connecting

- **REST:** base URL `https://api.tuppence.ai`, header `Authorization: Bearer $TUPPENCE_SECRET_KEY`,
  JSON bodies. Optional `Tuppence-Version: 2026-09-20`.
- **Node:** `npm install @tuppence/node` → `new Tuppence(process.env.TUPPENCE_SECRET_KEY)`.
- **Python:** `pip install tuppence` → `Tuppence(os.environ["TUPPENCE_SECRET_KEY"])`.
- **MCP (Claude Code):**
  `claude mcp add tuppence --env TUPPENCE_API_KEY=sk_test_… -- npx -y @tuppence/mcp`
  — gives you tools such as `create_payment_link`, `create_payment`, `create_refund`,
  `create_plan`, `create_subscription`, `record_usage`, `get_balance` and `search_docs`.
  Tools that move money take an `idempotency_key` argument.
- **No account yet?** Sign up at https://app.tuppence.ai/register — test keys are issued in seconds.

The packages are in early access; if a package isn't installable yet, use the REST API.

## Common tasks

### Get paid with a link (no website needed)

```bash
curl https://api.tuppence.ai/v1/payment_links \
  -H "Authorization: Bearer $TUPPENCE_SECRET_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name": "Research report", "amount": 2000}'
```

Reply to the user with the returned `url`. Options: omit `amount` and send `min_amount` /
`max_amount` to let the payer choose; `reusable: true` (+ optional `max_payments`);
`expires_at` (unix seconds); `redirect_url` (https, `{PAYMENT_ID}` is substituted);
`completion_message`. `GET /v1/payment_links/{id}/qr` returns a QR code (SVG, or PNG with
`?format=png`).

### Take a payment from your server

`POST /v1/payments` with `{"amount": 2000, "currency": "gbp", "description": "Order 1042"}` →
send the payer to the returned `approval_url`. Listen for the `payment.succeeded` webhook (or
`GET /v1/payments/{id}`) before fulfilling. Saved cards: `POST /v1/payments/charge_saved`.
Authorise now, capture later: `capture_method: "manual"`, then `POST /v1/payments/{id}/capture`.

### Refund

`POST /v1/refunds` with `{"payment": "pay_…"}` for the full amount, or add `"amount"` for part
of it. The customer gets the refunded amount back; the original processing fee is not returned.

### Subscriptions

1. `POST /v1/plans` `{"name": "Pro", "amount": 1200, "interval": "month", "trial_days": 14}`
   (`interval`: day, week, month or year; `interval_count` for every N). A plan's price never
   changes — a new price is a new plan.
2. `POST /v1/subscriptions` `{"customer": "cus_…", "plan": "plan_…"}` (the customer needs a
   saved card), or create a payment link with `"mode": "subscription", "plan": "plan_…"`.
3. Change plan: `POST /v1/subscriptions/{id}/preview`, then `/change` with the preview's
   `proration_at`. Cancel: `POST /v1/subscriptions/{id}/cancel` (`at_period_end` optional).

### Bill for usage (metered AI)

1. `POST /v1/meters` `{"name": "report", "unit_amount": 50}` — 50p per unit.
2. Customers prepay: `POST /v1/credits/{customer}/topups` `{"amount": 2000}` returns a payment
   whose `approval_url` the customer pays. Auto top-up:
   `POST /v1/credits/{customer}/auto_topup` `{"enabled": true, "threshold": 1000, "amount": 5000}`.
3. Record each use: `POST /v1/meter_events`
   `{"customer": "cus_…", "meter": "report", "identifier": "task_42"}`. The same `identifier`
   is counted once. If credit runs out you get `402 insufficient_credits` with a `topup_url`.

To charge per API call, wrap the route with `@tuppence/http402` (Node) or
`tuppence.http402` (Python) — see https://app.tuppence.ai/docs/http-402/.

### Check money

`GET /v1/balance` (available and pending), `GET /v1/payments?limit=10`, `GET /v1/payouts`.

## Testing

In test mode, use the test cards on the hosted pages, and the helpers under
`/v1/test_helpers/…`: advance the test clock (renewals, retries), settle payouts, open and
close disputes. Details: https://app.tuppence.ai/docs/testing/

## Errors

```json
{ "error": { "type": "invalid_request_error", "code": "amount_too_small",
             "message": "…", "param": "amount", "request_id": "req_…" } }
```

Quote `request_id` when asking Tuppence support (support@tuppence.ai) for help.

## Not available yet — don't promise these

Apple Pay / Google Pay, embeddable card fields, instant payouts, a customer portal, coupons,
invoices, quantities or custom fields on links, prices below a penny, x402, stablecoins,
live payments outside the UK.
