Payment links: guide
How a Qvard payment link works, how to create one in the cabinet, and how to create a payment per customer through the API.
What a link is
A payment link is a wrapper around payments. Each customer who pays through it gets a payment of their own, made on the same hosted payment page as any other Qvard payment.
A payment is an invoice with a fixed rate. A link is a reusable entry point that creates these payments. One link can create many payments, but it does not replace the payment itself.
The link has its own currency: the one the customer sees and pays in. Each payment fixes its rate at the moment it is created. The current rates are on the rates page.
Create a link in the cabinet
In the cabinet, open Payment links and set up the link. The options are:
- Amount: fixed, or entered by the customer with a minimum and a maximum.
- Payment limit: no limit, one payment only, or N payments.
- Term: 1, 7 or 30 days, or no term.
- Customer e-mail: do not ask, optional or required.
Each link has its own address: https://qvard.com/l/<slug>. The customer opens it, chooses a token and a network, and then sees the usual payment page.
You can download the link as a PNG QR code, for printed invoices, receipts and posters. The Share button gives you the link to send in any channel.
One link per customer through the API
To know exactly who pays, create a payment for each customer through the API from your server, and send the customer the redirectUrl from the response. The secret key (qvard_sk_…) must stay on your server.
Example request
# Create a payment for one customer
curl -X POST https://api.qvard.com/api/v1/payment \
-H 'x-api-key: qvard_sk_YOUR_SECRET_KEY' \
-H 'Content-Type: application/json' \
-d '{"price":12499.00,"currency":"INR","id":"order-123"}'
# The response contains "data": { "redirectUrl": "https://my.qvard.com/pay/..." }
# Send that redirectUrl to the customer.// Run on your server only: the secret key must not reach the browser
async function createPaymentLink(orderId, amount) {
const res = await fetch('https://api.qvard.com/api/v1/payment', {
method: 'POST',
headers: {
'x-api-key': process.env.QVARD_SECRET_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ price: amount, currency: 'INR', id: orderId })
});
if (!res.ok) throw new Error('Qvard API error: ' + res.status);
const payment = await res.json();
return payment.data.redirectUrl; // send this link to the customer
}
// Usage inside an async handler: const link = await createPaymentLink('order-123', 10);The response contains the payment id and a redirectUrl such as https://my.qvard.com/pay/<uuid>. Send the redirectUrl to the customer. The id value in the request is your own order number.
Never put the secret key (qvard_sk_…) in browser code or in a public repository. Create payments only from your server.
Limited sale and one-time links
A one-time link accepts one payment, which suits an invoice. A link with a limit of N payments accepts N payments and then stops, which suits a limited offer such as 100 seats.
Link statuses
- Active: the link accepts payments.
- Disabled: you switched the link off in the cabinet. It accepts no payments until you switch it on again.
- Expired: the term (1, 7 or 30 days) has passed.
- Exhausted: the payment limit has been reached.
Webhook for payments from a link
Payments created from a link use the same webhook and the same X-Qvard-Signature header. Their body has two extra optional fields: paymentLink, which is the link slug, and customerEmail, which is the e-mail the customer entered if the link asked for one. Payments that do not come from a link do not have these fields.
How to verify the webhook signature
What a link does not tell you
A reusable link does not show who paid. The webhook reports the payment, not the buyer.
The customerEmail field is optional and it is not verified: the customer types it in, and nothing checks it. If you need to know the buyer for sure, create a payment through the API for each buyer.