Guides
Payment links
A payment link is a hosted checkout you don't have to build. Generate a URL, share it with your customer, and TagPay handles the rest — card, bank transfer, USSD, hosted page, receipt, webhook. You write zero frontend code.
When to use
Reach for payment links when you don't want to (or can't) integrate the API directly. Some good fits:
- Invoices. Send an email with a one-click pay button. The link carries the amount; no manual data entry from the customer.
- Donation pages. Generate a flexible-amount link and put it behind a "Donate" button on your site or in your Instagram bio.
- No-code storefronts. One link per product, dropped into your bio link tool or marketplace listing.
- Internal tools. Operations spins up an ad-hoc link from the dashboard to collect a one-off charge — no engineering ticket.
If you already render your own checkout, stick to Charges — you get more control and metadata.
Create a link
Links can be created from the dashboard (Payments → Payment Links → New) or via the API. Two fields are always required: name (a label for your own reference) and linkType — one of fixed, open, or subscription.
curl https://gwt.tagpay.ng/v1/payment-links \-H "Authorization: Bearer $TAGPAY_SECRET_KEY" \-H "Content-Type: application/json" \-d '{"name": "Order #1184","linkType": "fixed","amount": 500000,"singleUse": true,"redirectUrl": "https://shop.example.com/orders/1184/thanks"}'
The response contains a url — that's what you share with the customer. The hosted page picks up your dashboard branding (logo, colors, business name) automatically.
Flexible amount
Set linkType to open and omit amount to let the customer decide what to pay. The hosted page shows an amount input instead of a fixed total. Useful for donations, tips, top-ups, and pay-what-you-want pricing.
# Flexible-amount donation linkcurl https://gwt.tagpay.ng/v1/payment-links \-H "Authorization: Bearer $TAGPAY_SECRET_KEY" \-H "Content-Type: application/json" \-d '{"name": "Donate to clean-water campaign","linkType": "open"}'
The response's amount field is null for flexible-amount links. The actual collected amount is on each underlying charge, not on the link itself.
Single-use vs reusable
By default a link is reusable — anyone with the URL can pay through it as many times as they want. That's what you want for a donation page or a bio-link store.
Pass singleUse: true for one-shot scenarios — an invoice, a unique order receipt, a private checkout link. The link auto-deactivates after the first successful payment.
Tracking payments
Listen for the paymentlink.paid webhook event. It fires every time a customer successfully pays through one of your links, carrying the link's current state (code, totals, whether it's still active) and the underlying transaction.
// Example payload{"event": "paymentlink.paid","data": {"paymentLink": {"linkCode": "PLK_28622c66c7454e77","singleUse": true,"paidAt": "2026-05-18T15:20:00.000Z","active": false,"totalCollected": 500000,"paymentCount": 1,"targetAmount": null},"transaction": {"id": "3b2a9e77-6c1d-4f5a-9e8b-2d1c4a6f7b90","reference": "tp_ref_8mFp2Lq9","gatewayReference": "tpg_c9a4f1e2b6d3487f","amount": 500000,"currency": "NGN","fee": 12500,"netAmount": 487500,"status": "success","paymentMethod": "card","cardBrand": "verve","cardLast4": "4081","bankName": null,"accountNumber": null,"senderName": null,"senderBankName": null,"senderAccountNumber": null,"destinationBankName": null,"destinationAccountNumber": null,"destinationAccountName": null,"collectionAccount": null,"paidAt": "2026-05-18T15:20:00.000Z","processedAt": "2026-05-18T15:20:00.000Z","createdAt": "2026-05-18T15:19:42.000Z"}}}
Each underlying charge also fires the standard charge.success event — choose whichever fits your reconciliation model. See the event catalog for full payloads.
For the full API surface, see the Payment Links API reference.