Guides

Hosted checkout

The payment page your buyer sees. Send them to one link and it handles the choice of method, the address and the confirmations, with no JavaScript and no account.

Every transaction has its own checkout at /checkout/{transaction_id}, using the transaction_id that Create a transaction returns. Redirect the buyer there or show it as a link. It works on both addresses:

Clearnet
https://anonpay.org/checkout/{transaction_id}
Onion service
http://anonpay666ie3ah4nl55ssimvacwrdkbbji6h4a4snvry26lnemfaxid.onion/checkout/{transaction_id}
Redirect
from flask import Flask, redirect
from shop.anonpay import create_transaction
from shop.orders import Order

app = Flask(__name__)
CHECKOUT = "https://anonpay.org/checkout/"


@app.post("/orders/<int:order_id>/pay")
def pay(order_id):
    order = Order.get(order_id)
    created = create_transaction(order)
    order.save_payment(created["transaction_id"], created["private_key"])
    return redirect(CHECKOUT + created["transaction_id"], code=303)
import express from "express";
import { createTransaction } from "./anonpay.js";
import { Order } from "./orders.js";

const app = express();
const CHECKOUT = "https://anonpay.org/checkout/";

app.post("/orders/:id/pay", async (req, res) => {
  const order = await Order.find(req.params.id);
  const created = await createTransaction(order);
  await order.savePayment(created.transaction_id, created.private_key);
  res.redirect(303, CHECKOUT + created.transaction_id);
});
$order = Order::find((int) $_POST["order_id"]);
$created = createTransaction($order);
$order->savePayment($created["transaction_id"], $created["private_key"]);

header("Location: https://anonpay.org/checkout/" . $created["transaction_id"], true, 303);
exit;
  • Answer the POST that created the order with a 303 redirect, so reloading your page cannot create a second transaction.
  • The link carries no secret. The buyer can bookmark it and come back until the transaction ends.
  • Keep the private_key on your server. The checkout never needs it.
  • Create a new transaction for every order. A checkout belongs to one transaction and ends with it.

What the buyer sees

  1. Choose a method

    The methods on offer, each with its name and icon, and the network for tokens.

  2. Pay

    The exact amount, the receiving address and a QR code, or the PayPal account to pay.

  3. Done

    The payment shows as complete, and you receive the completed webhook.

TransactionThe checkout shows
pendingno method yet
The methods on offer.
pendingmethod chosen
The amount, the address and a QR code.
pendingpartly paid
What is still owed, with a QR code for exactly that.
pendingconfirming
The confirmations so far.
completedThe payment is complete.
expiredExpired, as soon as expires passes, even before the status changes.
cancelledCancelled. Nothing more can be paid.

Which methods are offered

A method is offered when all three hold: it is enabled on your account, it is in the transaction's allowed_payment_methods if you set any, and the platform has it available right now. Methods appear in the platform's order. Payment methods lists every code.

With exactly one method on offer, the buyer gets a single button for it. If the platform refuses a choice, for example because the amount is outside the method's limits or the method was paused a moment ago, the buyer is told why and the method leaves the list.

A choice is final

Choosing a method fixes the rate and creates the receiving address, and it cannot be undone. To let a buyer switch, cancel the transaction with its private_key and send them a new one.

Paying

For crypto the page shows the exact amount, rounded up to the coin's precision so you are never short, the receiving address, and a QR code. The QR code includes the amount for coins whose wallet links have a standard amount field, such as Bitcoin and Monero. A token's QR code carries the address alone, because a correct token link needs the token's contract address; the buyer types the amount.

For a token, the network is part of the method. Tether on Tron and Tether on Ethereum are different methods, the page names the network, and coins sent on another network do not arrive.

If less arrives than asked, the page asks for the rest until the transaction expires. Your completion threshold decides how far short still counts as paid. If more arrives, the transaction still completes, and until it does the page shows the extra.

For PayPal the page shows your PayPal email, the amount, the currency to send it in, and the payment type your account accepts: Friends and Family, Goods and Services, or either. A deposit accepts any amount, so the page asks for none.

While the buyer waits

The buyer never has to keep the page open. The transaction completes once the payment confirms, and your webhook tells you.

To see confirmations arrive, the buyer refreshes the page. Each load reads the payment again.

Your store on the page

The checkout shows your store name, your logo and your theme colour, set in the dashboard under Settings, Store and Settings, Checkout. A deposit shows none of it, because it tops up your own balance.

Styling with link parameters

Not active yet

These parameters arrive with the redesigned checkout. Until then the checkout ignores them, so a link that already carries them works today and takes on the style when the redesign ships.

Add parameters to a checkout link to change how that link looks and behaves. Only the values listed are accepted. Anything else is ignored and the default is used, so a typo can never stop a buyer paying.

Example
https://anonpay.org/checkout/9c1f0b7a4e2d8f6a3b5c7d9e1f0a2b4c?theme=dark&list=grid

Appearance

themedefault auto

Light or dark page.

auto
Follows the buyer's device setting. Tor Browser always reports light.
light
White page, grey panels, black text.
dark
The ANONPAY dark palette.
layoutdefault split

Where the order summary sits relative to the payment.

split
The summary in a column beside the payment. Stacks on phones.
card
One centred card with the summary as its header.
plain
No panels. One column on the page.
listdefault auto

How the payment methods are offered.

auto
Rows for up to 6 methods, tiles up to 15, a search box beyond.
list
One row per method.
grid
Tiles, several per row.
search
A search box over the full list. Typing suggests names.
chips
Compact pills that wrap.
select
A dropdown and a Continue button.
groups
A collapsible section per network.
tabs
One tab per network.
densitydefault cozy

How much room everything gets.

cozy
Standard spacing.
compact
About a quarter tighter, for long lists and small windows.
shapedefault round

The corner radius of panels, rows and controls.

round
Rounded corners.
square
No rounding anywhere.
pill
Fully rounded buttons, rows and fields.
fontdefault brand

The font every text uses.

brand
Roboto, the ANONPAY typeface.
system
The device's own font. Nothing to download, so the fastest over Tor.
mono
Monospace throughout.

Content

qrdefault show

How the payment QR code is shown.

show
Beside the amount.
fold
Behind a Show QR code button.
big
Large and first, for scanning with a phone.
off
No QR code. Amount and address only.
addrdefault group

How the receiving address is printed.

group
In blocks of four, easier to compare with the wallet. Copying gives the address without spaces.
plain
One unbroken string.
stepsdefault on

The Method, Payment, Done indicator.

on
Shown above the content.
off
Hidden.
summarydefault full

What the order summary shows.

full
Store, total, reference, expiry and your store's links.
min
Store and total only.
helpdefault off

Common questions under the payment details.

off
Hidden.
on
Shown, folded.
badgedefault full

The footer that says who processes the payment.

full
The ANONPAY logo.
min
One line of text.

Behaviour

confirmdefault on

Whether choosing a method takes one click or two.

on
The buyer picks a method, then presses Continue. The choice cannot be undone, so it takes two clicks.
off
One click on a method commits to it.
refreshdefault 30

How often a page waiting for payment reloads itself.

30
Every 30 seconds.
60
Every minute.
off
Never. The buyer uses Check now.
embeddefault 0

For ANONPAY's own dashboard, which frames the checkout on its deposit page.

0
A normal page.
1
No summary, steps or footer, on a transparent background. Other sites still cannot frame the checkout.
topup to 3 codes

Puts these methods first, or in a Suggested group when the list is grouped. Codes the transaction does not offer are dropped. Example: top=xmr,btc.

qtext, 40 characters

The search text for list=search. The search box sets it; a link never needs to, and it is not carried into other links.

Presets

  • Default. No parameters at all.
  • Night market. Dark page, methods as tiles.
    ?theme=dark&list=grid
  • Quick card. One card and one click per method, for stores that sell one thing.
    ?layout=card&qr=big&steps=off&summary=min&confirm=off
  • Big catalogue. Every method behind a search box, with Monero and Bitcoin first.
    ?list=search&top=xmr,btc
  • Terminal. Monospace, square and compact.
    ?theme=dark&list=chips&density=compact&shape=square&font=mono

What a link cannot change

  • The amount, the currency or the methods on offer. top only reorders methods the transaction already allows.
  • Any text on the page, including your store's name. A parameter that could set text could put a phishing message on a real ANONPAY page.
  • Where the buyer goes next. There is no redirect parameter.
  • How often the page asks for updates, except to slow it down.

Embedding

Other sites cannot show the checkout in a frame. It sends X-Frame-Options: SAMEORIGIN and frame-ancestors 'self', which stops a page from tricking a buyer into pressing a payment button they cannot see. Redirect or link to the checkout instead.

Privacy

  • No JavaScript. The page is HTML and CSS, so it works in Tor Browser at the Safest setting.
  • No third parties. Every font, icon and image comes from ANONPAY, and the QR code is drawn on the server.
  • No referrer. A link on the checkout does not tell the next site which transaction the buyer came from.
  • No caching. Pages are sent with Cache-Control: no-store, so a shared computer keeps no copy of the address or amount.