Create Invoice
Creates a payment invoice and returns the URL of a hosted payment page. Redirect your customer to that URL — they pick a coin, send the payment, and Payid19 handles detection, confirmation and crediting your balance in USDT. One request is enough for a complete checkout; everything else on this page is optional fine-tuning.
white_label=1.Request parameters
price_currency. The customer sees this amount converted to the coin they pick at the current exchange rate.0.0001USD1 to pass the platform commission on to your customer: it is added on top of your price at checkout, so you receive your full price_amount. For very small invoices (under about 0.20 USD) this is enabled automatically.1margin_ratio=1 on a 5 USDT invoice, 4 USDT completes the payment, 3.9 USDT does not. Useful because first-time crypto users often send slightly less than requested (their wallet deducts the network fee from the amount they type).0.0110015011 digits150300shownfirst 180Coins you do not want offered on this invoice, as a JSON array. A bare coin code hides it on every network; a COIN-NETWORK pair hides that network only.
["BTC","ETH","USDT-ERC20"] hides Bitcoin, Ethereum and USDT on ERC20 only · ["USDT","BNB"] hides USDT on all networks and BNB.
3003003001 to create a test invoice: it completes automatically within seconds — including the callback — without any real payment. The fastest way to verify your whole integration end to end before going live.11 to receive a JSON list of available coins instead of a payment page URL, and build the checkout under your own brand. See White Label.19670126418add_fee_to_price: a higher, less round checkout total makes incorrect transfers slightly more likely and can reduce conversion. Unless you specifically need to receive the exact price_amount, leaving it off usually converts better.Response
success or error.white_label=1, a JSON list of coins instead.Successful response — redirect your customer to the URL in message:
{"status":"success","message":"https:\/\/payid19.com\/invoice\/Xy3kP9..."}
Error responses come with HTTP status 421 and a human-readable message array — show or log message[0]:
{"status":"error","message":["Wrong public or private key."]}
Example request
curl -X POST https://payid19.com/api/v1/create_invoice \
-d public_key=YOUR_PUBLIC_KEY \
-d private_key=YOUR_PRIVATE_KEY \
-d price_amount=100 \
-d price_currency=USD \
-d order_id=42 \
-d [email protected] \
-d callback_url=https://yoursite.com/payment/callback \
-d success_url=https://yoursite.com/payment/success \
-d cancel_url=https://yoursite.com/payment/cancel
<?php
$post = [
'public_key' => 'YOUR_PUBLIC_KEY',
'private_key' => 'YOUR_PRIVATE_KEY',
'price_amount' => 100,
'price_currency' => 'USD',
'order_id' => 42,
'email' => '[email protected]',
'callback_url' => 'https://yoursite.com/payment/callback',
'success_url' => 'https://yoursite.com/payment/success',
'cancel_url' => 'https://yoursite.com/payment/cancel',
// 'test' => 1, // test invoice: completes automatically
// 'banned_coins' => json_encode(["BTC","ETH"]),
];
$ch = curl_init('https://payid19.com/api/v1/create_invoice');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$result = curl_exec($ch);
curl_close($ch);
$response = json_decode($result);
if ($response->status == 'error') {
echo $response->message[0]; // handle the error
} else {
header('Location: ' . $response->message); // redirect to the payment page
}
const axios = require('axios');
const postData = {
public_key: 'YOUR_PUBLIC_KEY',
private_key: 'YOUR_PRIVATE_KEY',
price_amount: 100,
price_currency: 'USD',
order_id: 42,
email: '[email protected]',
callback_url: 'https://yoursite.com/payment/callback',
success_url: 'https://yoursite.com/payment/success',
cancel_url: 'https://yoursite.com/payment/cancel',
};
axios.post('https://payid19.com/api/v1/create_invoice', postData)
.then(({ data }) => {
if (data.status === 'error') {
console.error(data.message[0]); // handle the error
} else {
console.log(data.message); // the payment page URL
}
})
.catch(err => console.error(err.message));
import requests
post_data = {
'public_key': 'YOUR_PUBLIC_KEY',
'private_key': 'YOUR_PRIVATE_KEY',
'price_amount': 100,
'price_currency': 'USD',
'order_id': 42,
'email': '[email protected]',
'callback_url': 'https://yoursite.com/payment/callback',
'success_url': 'https://yoursite.com/payment/success',
'cancel_url': 'https://yoursite.com/payment/cancel',
}
response = requests.post('https://payid19.com/api/v1/create_invoice', data=post_data)
result = response.json()
if result['status'] == 'error':
print(result['message'][0]) # handle the error
else:
print(result['message']) # the payment page URL
Payment callback (webhook)
When the invoice is paid, Payid19 sends a POST request with a JSON body (Content-Type: application/json) to your callback_url. A callback is only sent for completed payments — receiving one means the invoice is paid; you never get callbacks for pending or expired invoices.
user_id, email, add_fee_to_price, title, description, ref_url, cancel_url, success_url, callback_url, ip, test, created_at, expiration_date — a full snapshot of the invoice, so you rarely need a follow-up API call.privatekey equals your own private key before trusting a callback, and respond with HTTP 2xx. If your endpoint does not return 2xx, delivery is attempted up to 3 times in total (two automatic retries with increasing delays). Callbacks can arrive from different IP addresses, so do not filter by sender IP — the privatekey check is the right way to authenticate them. When in doubt, you can always confirm a payment independently with get_invoices.<?php
$data = json_decode(file_get_contents('php://input'));
if ($data->privatekey != 'YOUR_PRIVATE_KEY') { // verify the sender
http_response_code(403);
die;
}
// payment confirmed - mark order $data->order_id as paid
http_response_code(200);
const express = require('express');
const app = express();
app.use(express.json());
app.post('/payment/callback', (req, res) => {
if (req.body.privatekey !== 'YOUR_PRIVATE_KEY') { // verify the sender
return res.status(403).send('Forbidden');
}
// payment confirmed - mark order req.body.order_id as paid
res.sendStatus(200);
});
app.listen(3000);
from flask import Flask, request
app = Flask(__name__)
@app.route('/payment/callback', methods=['POST'])
def payment_callback():
data = request.get_json()
if data.get('privatekey') != 'YOUR_PRIVATE_KEY': # verify the sender
return 'Forbidden', 403
# payment confirmed - mark order data['order_id'] as paid
return 'OK', 200
app.run(port=5000)
How the payment flow works
- Checkout: your customer chooses to pay with crypto and you redirect them to the invoice URL returned by this endpoint.
- Payment: they pick a coin and network, and send the shown amount to a unique deposit address (QR code included).
- Confirmation: Payid19 monitors the blockchain and marks the invoice as paid once the payment is confirmed. Your balance is credited in USDT with the fee already deducted.
- Webhook: the callback hits your server; you verify
privatekey, mark the order as paid and respond with 200. - Redirect: the customer lands on your
success_url; they receive an email receipt and the payment appears in your dashboard notifications.
Earning on the invoices you create
If you build stores or software for other businesses, add your own referral ID to the invoices you create for them. Payid19 charges the merchant a 1% commission on incoming payments; when an invoice carries your referral ID, half of that commission is credited to your balance in USDT every time the invoice is paid — not just on the first payment, but for as long as the integration keeps running.
curl -X POST https://payid19.com/api/v1/create_invoice \
-d public_key=CLIENT_PUBLIC_KEY \
-d private_key=CLIENT_PRIVATE_KEY \
-d price_amount=100 \
-d referral=9670126418 # your referral ID - you earn on this invoice
Integration tips
- Always set an
order_idand treat the callback as the single source of truth — reachingsuccess_urlis not proof of payment (a customer can open that URL by hand). - Make your callback handler idempotent: because failed deliveries are retried, the same callback can occasionally arrive more than once. Marking an already-paid order as paid again must be harmless.
- Start with
test=1. A test invoice runs the whole pipeline — payment page, confirmation, callback — in seconds, with no real money. - Don’t reuse invoices. Create a fresh invoice for every checkout attempt; they cost nothing and each one gets its own deposit address.