Payment methods
How global and per-user P2P payment methods work, what the metadata field is actually for, why details are snapshotted onto a trade, and what blocks a deletion.
A P2P payment method is a label plus a set of instructions telling the buyer how to send fiat. That is all it is. Nothing here connects to a bank, verifies a transfer or reconciles anything — the platform holds crypto and arbitrates, and the fiat leg happens entirely between the two people.
Every published offer must name at least one, so this list is a prerequisite for having a marketplace at all.
A method and a trader's details are two different records
This is the single most important thing to understand on this page, and it changed in 6.2.5.
A payment method used to be one row carrying two unrelated things: the identity — "PayPal" — and one trader's own credentials. So every trader who accepted PayPal created another row named PayPal, and the marketplace filter (which groups on the row) ended up with one "PayPal" entry per trader. A taker who picked one narrowed the whole board to a single maker without being told.
They are separate records now:
| The rail (shared) | The trader's details (private) | |
|---|---|---|
| What it holds | The name, and the fields a buyer must be given | One trader's actual account information |
| Who sees it | Everyone — it is the filter entry | Only the counterparty, and only once a trade opens |
| Managed at | /admin/p2p/payment-rail |
The trader's own payment methods |
| How many | One per real-world method | One per trader who uses it |
The filter groups on the rail, so PayPal is one entry however many people accept it.
An offer still points at the trader's own record, and a trade still copies that record's details at the instant it opens. No live offer changed and no settled trade was rewritten — only the grouping above them is new.
Two kinds
| Global | Personal | |
|---|---|---|
| Created at | /admin/p2p/payment-method |
the user's own P2P settings |
userId on the row |
null |
the owner |
isGlobal |
true |
always false |
| Who can attach it to an offer | everyone | only the owner |
| Who can edit or delete it | admins | the owner, and admins |
| Default sort rank | whatever you set | 999, so personal methods list after global ones |
A user may hold up to 20 personal methods, and may not have two with the same name. They can reuse the name of a global method — a user's "Bank Transfer" carrying their own account details is a different thing from yours.
Personal method creation is rate-limited to 15 per hour.
Seed the global list first
An empty payment-method list means nobody can publish an offer. Before you announce P2P, create the methods your market actually uses.
Each global method takes:
| Field | Required | Notes |
|---|---|---|
name |
yes | 2–50 characters |
icon |
yes | an icon reference or URL |
description |
no | up to 200 characters, shown in listings |
instructions |
no | up to 500 characters — how to actually pay |
metadata |
no | key/value payment details, see below |
processingTime |
no | free text, e.g. "instant", "1–2 business days" |
fees |
no | free text, informational only — the platform charges nothing here |
available |
no | off takes it out of circulation without deleting it |
popularityRank |
no | lower sorts first |
It exists so a maker can warn takers that a rail costs the sender something. The platform's only fee is the escrow fee on the crypto side. Nothing reads this field to compute money.
Personal methods created by users go through a stricter validator: the name is
sanitised and length-checked, and the icon is matched against an allowlist
(credit-card, bank, wallet, cash, bitcoin, ethereum, paypal,
venmo, zelle, wire-transfer), falling back to credit-card. Description,
instructions and processing time are truncated at 200, 500 and 50 characters.
The metadata field
This is the part that does real work, and the part that gets misused.
metadata is a free-form map of up to 20 key/value pairs, keys capped at
100 characters and values at 500. It is where the actual payment coordinates
live:
{
"Bank name": "Example Bank",
"Account holder": "A. Trader",
"IBAN": "GB00EXMP00000000000000",
"Reference": "Use the trade ID"
}Keeping details here rather than mashed into instructions is what lets the
trade room render them as a labelled list the buyer can copy, and it is what
gets snapshotted onto the trade.
Metadata on a global method is visible to every user who attaches it. Put generic guidance there — which reference to quote, what the rail is called — and leave the account numbers to personal methods, where they belong to the maker who typed them.
What the taker sees, and when
When a trade is opened, the selected method's name, icon, instructions,
processing time and all of its metadata are copied onto the trade as
paymentDetails.
That copy is deliberate. If the maker later edits their bank details, or the method is edited by an admin, or it is switched to unavailable, the running trade still shows exactly what the buyer agreed to pay against. It also means the record of an old trade survives the method being deleted.
The snapshot is the agreement. A counterparty who posts different account details in the trade chat after the trade opens is running the single most common P2P fraud there is. Support should treat "I paid the details they sent me in the chat" as a red flag, not as evidence of payment.
Availability
available: false hides a method from new use. Trade initiation checks it — a
taker cannot open a trade on a method that is no longer available, even if the
offer still lists it.
Use this rather than deletion when a rail goes down temporarily. Deleting is final for the user's list; unavailability is reversible and leaves running trades alone.
What blocks a deletion
Deleting a personal method is refused while it is in use:
- Used by an offer in
ACTIVE,PENDING_APPROVALorPAUSED— the error names how many offers, and the user must detach it from those offers first. - Used by a trade in
PENDING,PAYMENT_SENTorDISPUTED— the user has to wait for those trades to finish.
A user can only delete their own methods; global methods are refused outright with a 401 message saying so.
Deletion is a soft delete, so historical rows keep resolving.
Admins deleting a global method from /admin/p2p/payment-method should check
the offers using it first — offers keep the association, and a taker on such an
offer will find the method missing at initiation.
Choosing which methods to offer
Two operational points worth thinking about before you seed the list.
Reversible rails are where disputes come from. Card payments and anything with a chargeback window let a buyer take their money back long after the crypto has gone, and the trade is terminal by then. If you allow them, expect fraud cases; many operators simply do not list them.
One method per rail, not one per bank. A list with forty near-identical entries makes the market board's payment filter useless. Keep the global list short and let makers put their specifics in personal methods.
Where they appear
| Surface | What it shows |
|---|---|
| Offer creation | The maker's attachable methods — global plus their own |
| Market board filter | One entry per rail, not per trader |
| Trade room | The snapshot: instructions, processing time and every metadata pair |
/admin/p2p/payment-method |
Every method, global and personal, with the owner |
/admin/p2p/payment-rail |
The shared rails the public filter is built from |
/admin/p2p/payment-method/setup |
The setup console — field shapes for the common rails |
When a trader's own method reaches the public filter
A rail a trader defines themselves does not go straight into the filter every visitor sees. It:
- works immediately, on their own offers
- is findable by name by the next trader who needs the same thing
- shows on the offers that carry it
It enters the public filter only when more than one maker is using it, or when you list it yourself in Admin → P2P → Payment Rails.
That threshold is what stops the filter refilling with one-off entries — which is the problem the split was made to solve.
The setup console
/admin/p2p/payment-method/setup ships field shapes for the rails most
operators already have: bank transfer, SEPA, PayPal, Wise, Revolut, Zelle, Cash
App, UPI, IMPS/NEFT, Pix, M-Pesa, Mercado Pago, GCash, Papara and cash in
person.
Anything else has its fields inferred from what traders using it have actually filled in, and you can correct any of it afterwards.
The console refuses everyone except a Super Admin until you grant the payment-method permissions in Admin → Roles. Do that before handing the screen to whoever runs your payment operations.