A developer-friendly payments API with better economics.
REST and JSON, an idempotency key on every write, signed webhooks, and SDKs for Node.js, Python and the browser. From 0.9% per payment for eligible EEA consumer cards, with no fixed fee.
import { Tuppence } from "@tuppence/node"; const tuppence = new Tuppence(process.env.TUPPENCE_SECRET_KEY); const payment = await tuppence.payments.create({ amount: 2000, // €20.00, in cents currency: "eur", description: "Order 1042", }); console.log(payment.status, payment.approval_url);
The docs' examples, as they run in our CI.
Every sample on this page is type-checked against the SDK in our CI, like the docs' own. Signed in to the docs, the examples there carry your own test keys, ready to paste.
import { Tuppence } from "@tuppence/node"; const tuppence = new Tuppence(process.env.TUPPENCE_SECRET_KEY); // A payment link to share, in your account's currency, and its address. const link = await tuppence.paymentLinks.create({ name: "Research report", amount: 2000, }); console.log(link.url); // A payment, retried safely: the same key never charges twice. const idempotencyKey = `order-${Date.now()}`; const payment = await tuppence.payments.create( { amount: 4500, currency: "eur" }, { idempotencyKey }, ); // Part of it back, later. const refund = await tuppence.refunds.create({ payment: payment.id, amount: 500 }); console.log(refund.status);
import os from tuppence import Tuppence tuppence = Tuppence(os.environ["TUPPENCE_SECRET_KEY"]) payment = tuppence.payments.create(amount=2000, currency="eur", description="Order 1042") print(payment.status, payment.approval_url)
curl https://api.tuppence.ai/v1/payments \ -H "Authorization: Bearer $TUPPENCE_SECRET_KEY" \ -H "Idempotency-Key: order-1042" \ -H "Content-Type: application/json" \ -d '{"amount": 2000, "currency": "eur"}'
import { Tuppence } from "@tuppence/node"; const tuppence = new Tuppence(process.env.TUPPENCE_SECRET_KEY); /** * Your webhook route hands over the raw body and its Tuppence-Signature header. * @param {Buffer} rawBody * @param {string} signature */ export function handle(rawBody, signature) { const event = tuppence.webhooks.constructEvent(rawBody, signature, process.env.TUPPENCE_WEBHOOK_SECRET); if (event.type === "payment.succeeded") console.log("paid", event.data.object.id); }
One API for taking money, paying it out and spending it.
Every endpoint is in the API reference, generated from the same OpenAPI document the SDKs are built from.
Payments
Payments, refunds, disputes, payment links, customers and saved cards, and checkout in your own page with @tuppence/js.
Recurring and metered
Plans and subscriptions, and metered billing with meters, meter events and prepaid credits.
Balance and payouts
Your balance, payouts to your bank and the events behind every change.
Card issuing
Cards for your business or your agents, spend policies, card authorisations and transactions, and approvals.
Platforms
Connected accounts and their onboarding, transfers and application fees, with Tuppence Connect.
Bookings
Services, staff, availability, bookings, classes and the waitlist, for businesses that sell time.
A retry is never a second charge.
Send an Idempotency-Key on every POST. A retry with the same key returns the first result, marked Idempotent-Replayed: true, instead of acting again.
- Keys are kept for 24 hours.
- The same key with a different body is refused:
409 idempotency_key_reuse. - The SDKs send a key on every write, and reuse it across their own retries.
- Every error has a stable
codeto branch on. Idempotency and errors
Signed events, verified in one line.
A payment succeeded, a refund was made, a dispute opened, a payout reached the bank: each is an event, signed in its Tuppence-Signature header.
constructEventin each SDK checks the signature against the raw body.- No
2xx? We retry on a schedule for 72 hours. - Test mode has an inbox that stands in for your server, so you can see deliveries before you write one.
Typed clients, built from the API's own contract.
Coming from another payments API?
The conventions are the ones you know, so most of the work is renaming.
- Amounts are integers in the currency's smallest unit:
2000is €20.00. - Secret keys start
sk_test_andsk_live_; publishable keyspk_test_andpk_live_. - Lists page with
limitandstarting_after, newest first, withhas_more. - Events are named for what happened:
payment.succeeded,refund.created. - Run both side by side: send new checkouts to Tuppence and let your old provider settle what it holds.
From test key to a paid link in minutes.
The quickstart creates a payment link with your test key and pays it with a test card. Checkout in your own page is one server call and a few lines in the browser.
0.9% per payment on eligible EEA consumer cards
- American Express +0.9%, commercial cards +1.5%, cards issued outside the EEA +1.7%.
- No monthly fee, and nothing for test mode, the API, webhooks or the SDKs.
Card payments from 0.9%, paid out by SEPA.
Tuppence is coming to the eurozone. Join the waitlist, and we’ll email you once, when it opens.