Tracking and conversions
What a link actually measures, where those numbers live, and how it closes.
Two different questions get asked about a link, and they are answered in two different places.
Is it still open? That is the link object, and the API answers it. Is it working? That is analytics, and only the Dashboard answers it. Knowing which is which saves you looking for numbers where there are none.
The API has no counters
A link's page views are counted, but nothing about that reaches the API. GET /links/{id} returns
what the link is, never how it has performed: no views, no conversions, no revenue, and
no view_count either: view counts are not exposed on the API.
https://api.wajub.com/links/{id}curl https://api.wajub.com/links/8kD2xQpLm \
-H "Authorization: sk.xxxxxxxxxxxxxxxx…"The answer is the link's state, which is what you poll to know whether it is still collecting.
Listing works the same way. It takes per_page, search, archived to see archived links instead
of live ones, only_public, type (product, event, fundraising or donation), and
sort_by (created_at, updated_at, title or type) with sort_dir (desc or asc). The
list follows the sort first, then the newest first among links that tie. For exports, a cursor
walks the list in its default order, newest first: with another sort the list is paged by number
and carries no cursor. A type, sort_by or sort_dir outside these values is a 422 on that
field, as a per_page out of range is.
https://api.wajub.com/linksWhat is actually measured
Every visit that gets past the access gates is recorded, with rather more detail than the link object suggests.
| Recorded on each view | Used for |
|---|---|
| A daily visitor fingerprint | Telling unique visitors from repeat visits |
The HTTP referrer | Where the visit came from |
| Country, resolved from the IP | The geography breakdown |
| Device type, from the user agent | Mobile against desktop |
Unique visitors are counted per day, so the same person visiting on two days counts as two unique visitors. Read the unique-visitor figure as "unique per day", not as people.
A blocked visit is not a view
When a link is password-protected, an attempt that fails the password is not counted. Neither is a
visit to a link that is unpublished, expired or past its view limit. The counter only moves for
visits that actually reached the page, which is what makes max_views a usable limit.
The numbers, and where to read them
Links → a link → Analytics is the only place these surface. It gives views and unique visitors over time, the transactions and revenue the link produced, an average transaction, the top countries and device types, and a CSV export of the lot.
Conversion rate is per visitor, not per view
The figure is transactions ÷ unique visitors, not transactions ÷ views. A page someone opened
four times before paying counts as one visitor and one conversion, so the rate reads higher than a
per-view calculation would. Compare it against itself over time rather than against a number from
another tool.
Attributing a channel
There is no query parameter that tags a visit. A ?src=whatsapp on the shared URL is carried
nowhere: it does not reach the payment, it is not stored on the view, and it will not appear in any
report.
What you have instead is two things that do work.
The referrer is captured automatically, so traffic that arrives with one, from a link in a post or a page, already shows its origin in the analytics. Traffic from WhatsApp, SMS or a QR code carries no referrer, which is most of the traffic in practice.
So for anything you genuinely need to attribute, make one link per channel. Same product, same
price, different custom_url: wajub.link/cafe-whatsapp, wajub.link/cafe-instagram. Each keeps
its own views, its own conversion rate and its own revenue, and the comparison is exact rather than
inferred.
A payment made on a link names it: its link field is the link's id, in the API and in the
payment.* webhooks, so your handler knows which link, and so which channel, the money came from.
GET /payments has no link filter: to list a link's payments, read Links → a link →
Transactions in the Dashboard, or keep the link of each payment as it arrives.
How a link closes
Three settings end a link's life, and they do not close it in the same way.
| Set | Closes | The payer gets |
|---|---|---|
expiry_date | The page, at a moment you choose | 410, before anything renders |
is_archived | The page, now | 410, before anything renders |
sales_limit | The payment, not the page | 422 on paying, This payment link has reached its sales limit. |
The difference matters. An expired or archived link never opens: the payer sees a closed page and that is the end of it. A link at its sales limit still opens normally, shows the product and the button, and only refuses when they try to pay. If you are selling a fixed quantity, expect payers to reach that message rather than a closed page.
Archiving is the reversible one: set is_archived back to false through PUT /links/{id} and the
link collects again, keeping everything it already gathered. expiry_date is a condition rather
than a state, so moving it forward reopens a link that had closed on it.
single_use_link does nothing
The field is accepted on creation, stored, and returned on reads, but nothing enforces it: no code
refuses a second payment because a link is marked single use. A link with single_use_link: true
keeps collecting indefinitely. For a link that must close after one sale, set sales_limit: 1,
which is enforced.
Unpublishing with is_public: false also closes a link, but answers 404 rather than 410, since
an unpublished link is meant to look like it never existed. The access gates are covered in
Customization.
Reconciling the money
A link's payments are ordinary payments. They arrive in your Payments list, fire
payment.succeeded, settle into your balance and refund like any other, so there is nothing
link-specific to reconcile.
What the webhook carries is whatever the payer typed into your extra_fields, nested under
metadata.extra_fields. If you need to know which link produced a payment from your own code,
today that means asking the payer, through a field, or splitting by link as above.
Related pages
- Payment LinksWhat the product is, and when a link beats an integration.
- QuickstartCreate a link, publish it, share it.
- CustomizationImages, languages, currencies, and who is allowed in.
- WebhooksListen for payment.succeeded and fulfil automatically.
- Payment Links API referenceEvery field on the resource, and the five endpoints.