Merchants
Use the invoice endpoints to charge your customers in any supported token and receive a different one in your own wallet. p3p handles the cross chain routing.
How it works
p3p never takes custody of your funds beyond the few seconds needed to route the swap. Refunds, when applicable, go to the deposit sender automatically.
1. Become a merchant
Register at the Partner Dashboard using a wallet you control. For swaps (/exchange/rate, /exchange/create), attribution and your fee come from authenticating with your partner api-key — opts.partner_id in the body is ignored. For invoices (/invoice/create), the merchant is identified by wallet_merchant.
There is no signup form, no email confirmation and no API token. The wallet is the credential.
Treat your merchant wallet like an API key
Anyone who controls the wallet controls the merchant account. Use a dedicated wallet for your business, separate from personal funds.
2. Create an invoice
Two ways to do this.
Programmatic (recommended)
POST /invoice/create
const invoice = await fetch("https://api.p3p.xyz/invoice/create", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
chain_from: "eth", token_from: "usdt", amount_from: "50",
chain_to: "ton", token_to: "usdt",
wallet_merchant: "UQYourMerchantTonWallet"
}),
}).then(r => r.json())
console.log(invoice.deposit_address) // show to your customerResponse:
{
"id": "in_ab12cd...",
"invoice": true,
"chain_from": "eth", "token_from": "usdt", "amount_from": "50",
"chain_to": "ton", "token_to": "usdt",
"amount_to": "50.0",
"wallet_merchant": "UQYourMerchantTonWallet",
"deposit_address": "0xDepositAddressForCustomer",
"rate": "1.0",
"duration": 60
}Shareable URL (no integration needed)
For a checkout button, QR code or share link, you can build the invoice from a URL:
https://api.p3p.xyz/invoice/create/:merchantId/:pathFrom/:pathTo?Examples:
# customer pays 100 USDT on TON, you receive USDT on TON
https://api.p3p.xyz/invoice/create/0xYourMerchantWallet/100:usdt.ton/usdt.ton
# customer pays 50 TON, you receive USDT on TON
https://api.p3p.xyz/invoice/create/acme/50:ton.ton/usdt.ton
# simple form: pay and receive the same asset
https://api.p3p.xyz/invoice/create/acme/100:usdt.ton:merchantId may be:
- the partner id returned during registration,
- a partner
nameif you set one, or - a wallet address already registered as a merchant.
3. Show the deposit address
Render invoice.deposit_address and invoice.amount_from in your UI, ideally as a QR code:
import QRCode from "qrcode"
const dataUrl = await QRCode.toDataURL(
`${invoice.chain_from}:${invoice.deposit_address}?amount=${invoice.amount_from}`
)The customer sends amount_from of token_from to that address. Anything else (wrong amount, wrong token, expired window) gets auto refunded.
4. Confirm payment
Poll /check/:id exactly like a regular exchange:
async function waitForInvoicePayment(id: string) {
while (true) {
const s = await fetch(`https://api.p3p.xyz/check/${id}`).then(r => r.json())
if (s.status === "complete") return s
if (s.status === "failed" || s.status === "refunded") throw new Error(s.status)
await new Promise(r => setTimeout(r, 4000))
}
}
await waitForInvoicePayment(invoice.id)
// funds are now in wallet_merchant5. Inspecting your earnings
Three partner endpoints are read only and require no authentication beyond knowing the partnerId. Earnings settle according to your configured payout settings (either instantly per swap or via USDT scheduled withdrawals) — configure this in the Partner Dashboard.
| Endpoint | Returns |
|---|---|
GET /partners/:partnerId/stats | Volume, transaction count, revenue share |
GET /partners/:partnerId/exchanges | All exchanges credited to this partner |
GET /partners/:partnerId/invoices | All invoices created for this partner |
curl https://api.p3p.xyz/partners/0xYourMerchantWallet/statsTips & gotchas
- One wallet per chain: a partner accumulates wallets, one per chain. Use the right wallet for the destination chain in
wallet_merchant. - Same chain + same token: skips the swap engine and acts as a plain forwarding address — useful for simple "pay me X USDT on TON" links.
- Deposit window: invoices share the standard ~6 minute window. If the customer takes longer, call
/check/:id?bump=trueto refresh it. - Refunds: only available when the deposit is detected but the swap fails. For invoices without a
wallet_refund, funds attempt to refund to the sender address detected on chain.
Endpoint reference
All merchant endpoints are open — no api-key header required. Your wallet is the credential.
1. Create Invoice
POST /invoice/create
| Field | Type | Required | Description |
|---|---|---|---|
chain_from | string | yes | Chain the customer pays from |
token_from | string | yes | Token the customer pays with |
amount_from | string | yes | Amount the customer pays |
chain_to | string | yes | Chain you receive funds on |
token_to | string | yes | Token you receive |
wallet_merchant | string | yes | Your wallet on the destination chain |
Returns an invoice object including id, deposit_address, amount_from, amount_to, rate and duration.
2. Create Shareable Invoice URL
GET /invoice/create/:merchantId/:pathFrom/:pathTo?
Shareable invoice URL — drop it in a QR code or a button.
merchantId— partner id, partner name, or a wallet already registered as a merchantpathFrom—<amount>:<token>.<chain>(e.g.100:usdt.ton)pathTo— optional,<token>.<chain>if you want to convert; defaults topathFrom
Returns the same object as POST /invoice/create.
3. Get Partner Stats
GET /partners/:partnerId/stats
Aggregate volume, transaction count and lifetime revenue share for the partner wallet.
4. Get Partner Exchanges
GET /partners/:partnerId/exchanges
Paginated list of exchanges credited to the partner.
5. Get Partner Invoices
GET /partners/:partnerId/invoices
Paginated list of invoices created for the partner.
Errors
{ "error": "merchant_id_required", "message": "..." }| Code | Meaning |
|---|---|
invalid_json | Request body is not valid JSON |
merchant_id_required | Invoice GET endpoint called without a merchant identifier |
partner_not_found | No partner matches the given merchantId |
merchant_wallet_not_found | Partner exists but has no wallet on the destination chain |
amount_too_small | Amount below the supplier minimum |
amount_too_big | Amount above the supplier maximum |