Track and reconcile
Confirm payment outcomes, keep your systems in sync, and know what to do when something fails.
Webhooks are the source of truth
Treat webhook events as the authoritative record of payment state. Do not rely on:
- The confirmation screen the payer sees
- Redirect URLs
- Client-side confirmation
- API responses alone, which are not sufficient to determine final state in every case
Update orders, accounts, balances, and customer communications only after you have received and validated a webhook.
The event
Payment Links uses the standard Payrails notifications framework. Depending on your configuration, you may receive a single consolidated event type covering authorizations and payment confirmations; refunds; and disputes, chargebacks, and reversals.
Payloads include:
- Payment details and outcome
- Payment method information
- The amount paid
- Payer information, where collection is enabled
- Your merchant reference
- The link's status and paid amount
Fields to persist
| Field | Use it for |
|---|---|
merchantReference | Matching the payment to your invoice or order |
id of the link | Grouping everything against one payment request |
executionId | Pulling the full payment history for that request |
| Payment identifier | Identifying an individual payment, and deduplicating repeated events |
paidAmount | Reconciling how much has been collected. See Payment modes for the balance calculation |
status | Deciding whether the request is still open. See How it works |
The x-idempotency-key you sent | Safely retrying a create call without producing a duplicate link |
Handling rules
- Verify authenticity. Confirm each event genuinely came from Payrails before acting on it
- Be idempotent. Delivery is at-least-once, so the same event may arrive more than once. Key your processing on the individual payment identifier, not on
executionId— a partial payments link has one execution but many payments, soexecutionIdrepeats across every event for that link - Do not assume ordering. Events may arrive out of sequence. Compare against the state you already hold before applying an update
- Acknowledge quickly. Confirm receipt, then process asynchronously
- Do not poll as your primary mechanism. Use the get endpoint to reconcile or recover, not instead of webhooks
When a payment fails
A failed payment is recorded beneath the execution and sends a webhook. The link stays enabled unless it has expired or closed, and the payer can retry.
Do not treat the absence of a webhook as failure. Absence means you do not know yet.
What to monitor
Set up alerting on:
- Webhook delivery failures
- Events received but not processed, or processed late
- Repeated failed payments on the same link
- Mismatches between your records and
paidAmount
Webhook failures are the leading cause of Payment Links incidents. Alert on them first to protect production stability.
Common failure modes
- Webhooks not received, or received and silently dropped
- Test and live configuration mismatch
- Expired links shared with customers
- Refunds, disputes, or chargebacks not reflected in internal balances
- Treating the frontend success screen as settlement
- Retrying a create call with a fresh idempotency key, producing duplicate links
Reconciling in bulk
Use GET /merchant/dropInLinks with filter[status] and filter[createdAt] to sweep links for a period and compare against your own records, following links.next to page through results. See Create a payment link for the available filters.
Tracking in the Portal
Payment Links appears under Operations → Payment Links. Before this view existed, links were visible only indirectly as executions, so if your Portal does not show this section, contact your Payrails contact to confirm it is enabled on your account.
The list view shows the link ID, merchant reference, created date, expiry date, status, total amount, amount paid, amount remaining, and execution ID. You can filter by creation date and status, and search by link ID, merchant reference, or execution ID.
The detail view shows the link URL, status, the total, paid, and remaining amounts, and the associated payments. From there you can navigate through to the execution and the individual payments beneath it.
Limitations
| Limitation | What to do instead |
|---|---|
| Only one authorization session per link at a time | Concurrent attempts may be blocked until the active payment completes. This prevents double charges. A payer who tries to pay twice at once may briefly see a block, and retrying afterwards is expected |
| Links are served on a Payrails-managed domain | Custom domains are not supported |
| The hosted page is English only | Localization and right-to-left support are not available |
| Branding is configured by Payrails, not self-serve | Agree brand assets during onboarding. See Overview |
Three further constraints are documented where they apply: links cannot be edited and every link needs an expiry, both in Create a payment link ; and the API returns no remaining-balance field, in Payment modes .
Handling sensitive data
The description field is rendered on the payment page and readable by anyone with the link. See Create a payment link for what not to put in it.
Errors when creating a link
The create endpoint returns these HTTP status codes.
| Code | Meaning | What to check |
|---|---|---|
400 | Bad request | The request is well-formed JSON and x-idempotency-key is a valid UUID |
401 | Unauthorized | Your access token is present and has not expired |
403 | Insufficient scope | Your token carries the required drop-in link scope |
404 | Not found | The workspaceId exists and you have access to it |
422 | Unprocessable entity | Values are acceptable: amount, currency, expiresAt format, workflowCode |
For the full list of Payrails error codes and how to resolve them, see the error codes reference.
Errors during payment
| Cause | Result | What to do |
|---|---|---|
| Authorization declined | Failed payment recorded, webhook sent, link stays enabled | The payer can retry |
| 3-D Secure authentication failed | Failed payment recorded, webhook sent, link stays enabled | The payer can retry |
| The link has expired | Payment cannot start | Create a new link |
| The link is fully paid or deleted | Payment cannot start | Create a new link if payment is still owed |
| Another payment is in progress | The attempt may be blocked | Wait for the active payment to complete |
When state is unclear
Use GET /merchant/dropInLinks/:dropInLinkId to read the link's current status and paid amount rather than inferring state from events you did not receive.
Updated 15 minutes ago