# Pay by Link

br
Pay by Link is Token.io's flexible solution for fast, secure account-to-account payments. Merchants, banks, and third-party providers can generate unique payment links to share with customers via email, SMS, messaging apps, or QR codes. These links pre-fill recipient account details, making payments easier and reducing manual errors. Customers can pay remotely or in person, with a seamless experience on [Token.io's hosted payment pages](../hosted-pages/hosted-pages-v2/hosted-pages-v2).

## Key Features

- **Flexible Payment Links:** Generate links with or without pre-filled amount and reference. The payer can enter missing details if needed.
- **Reusable Payment Links:** Generate links with maximum usage count, per-payment amount limits and total limits.
- **Custom Branding:** Landing pages can be customised with your own logo, colours, field labels and error descriptions.
- **Bespoke Validity:** Set how long a link is valid for or leave open-ended.
- **Status Tracking:** Easily check if a link is active, expired, cancelled or unavailable due to restriction limits.
- **API-First:** All features are available via Token.io's API. See the [Token Open Banking API](https://preview.redoc.ly/tpp-api-definition/PAYE-2/).


## How It Works

1. **Create a Payment Link:** A unique link is generated by the requester.
2. **Share the Link:** The PSU / Merchant shares the link via SMS, email, chat, or invoice.
3. **Customer Pays:** The receiver clicks the link and authenticates in their own banking app.
4. **Receive Payment Updates:** The payment moves instantly, account-to-account, with no need for card details or sort codes. The payer is immediately notified on the confirmation page once the payment is completed. After this, the third-party provider or merchant receives a real-time notification (such as a webhook or API callback) confirming the payment status.


## Use Cases

**1. Peer-to-Peer (P2P) Payments**

br
Pay by Link enables individuals to transfer money directly between accounts without the need to share sort codes or IBANs.

br
**Common use cases include:**

- **Splitting bills**: Share a payment link to quickly settle expenses such as dinner, rent, or group activities.
- **Personal reimbursements**: Repay friends or family securely without exchanging bank details.
- **Gifting**: Send money instantly through a secure and personalised payment link.
- **One-off transfers**: Provide a simple alternative to manually entering account details.


br
**2. Online Orders Without a Checkout**

br
An eCommerce store empowers small online stores to sell directly through chat or social media using Pay by Link, eliminating the need for a full e-commerce checkout.

br
**Example flow:**

1. eCommerce store: Creates a Pay by Link for each order, including the item, price, and expiry time. The link opens a secure, branded payment page.
2. Seller: Shares the payment link with the customer and receives instant confirmation once payment is complete.
3. Customer: Clicks the link, pays using their preferred bank, and receives immediate order confirmation.


br
**3. In-Store Reusable Link for Merchants**

br
A small business owner selling goods uses Pay by Link to collect in-person payments.

br
**Example flow:**

1. Business owner generates a reuseable payment link and displays it as a QR code at the checkout counter.
2. Customers scan the code using their mobile device, review or enter the payment amount, and confirm payment through their mobile banking app.
3. Business owner receives instant notification once the payment is successfully processed.


## QR Codes

- **QR code image** can be generated via a dedicated endpoint `GET /qr-code` if required
- **QR code** is returned in 240x240px as an embedded string format (SVG)


More can be found in the [QR code API spec](https://reference.token.io/tag/Payments-v2#operation/GetQrCode).

## Link Statuses

In Pay by Link, link status indicates whether a payment link is currently usable and, if not, why it’s no longer available. Links can be active, expired, or canceled, and they may also become unavailable when a configured usage limit or amount limit has been reached. These statuses help customers understand the current state of a link and guide when a new link needs to be created.

| Status | Name |
|  --- | --- |
| `LINK_ACTIVE` | The payment link is active. |
| `LINK_EXPIRED` | The payment link has expired. |
| `LINK_CANCELED` | The payment link has been canceled. |
| `USAGE_LIMIT_REACHED` | Maximum usage count reached. |
| `AMOUNT_LIMIT_REACHED` | Total amount limit reached. |


## RefId Management for Links

For Payment Links to align with existing payments functionality, an enhancement has been added to manage the generation of a unique `refId` for each payment under a given link.

Unlike in `POST /v2/payments` where the `refid` has a limit of 18 character, for Payment Links this will now be limited to **13 characters**.
This client-provided value will be treated as the base `refId` for all payments initiated from that link.
For each individual payment created from the Payment Link, Token will generate a unique `refId` by appending an incrementing suffix to the base value.

For example:

- TPP provided base refId: ORDER-ABC
  - **First payment** created: ORDER-ABC-0001
  - **Second payment** created: ORDER-ABC-0002
  - **Third payment** created: ORDER-ABC-0003, and so on.


### Format constraints

To support this behaviour and ensure compatibility across payment rails:

* The client-provided base `refId` is limited to **13 characters**
* Allowed characters are alphanumeric characters and hyphens (-)
* Token will append a hyphen delimiter plus 4-character incrementing suffix, and incremented using IDs generated using Base62 i.e. -0001 --> -ZZZZ
* The final `refId`, including the suffix added by Token, will have a maximum length of 18 characters.


> **PLEASE NOTE**: That the refId value must be globally unique across both the Payments v2 and Pay by Link endpoints.
For example:
* Creating a payment via Payments v2 with **refId = ORDER-123-0001**
* And later creating a Payment Link with a base **refId = ORDER-123-0001** would result in a collision and is not supported. **Distinct base refId should be used for each flow to avoid this.**



## What is a Reusable Payment Link?

A reusable payment links can support multiple payments with configurable controls, including: per-payment amount limits, cumulative total link limits, and maximum usage/expiry behaviours. The platform exposes visibility of link configuration and status via the `GET/payment-links` API - supporting tracking, reporting, and compliance needs for TPPs.

### Link Configuration Parameters

| Parameters | Description | Request |
|  --- | --- | --- |
| Maximum usage count | Defines how many times the reusable link can be used e.g. "100". **'Usage' is defined as a redirection to the bank.** | ` "max_usage_count": 100` |
| Per-payment limit | Defines the maximum payment limit per payment on a specific link e.g. £500. Currency is dictated by the payment template. | `"per_payment_amount_limit": "500.00"` |
| Total amount per link | Define the total amount of money receivable by a single link e.g. £1000. Currency is dictated by the payment template. | `"totalAmountLimit": "1000.00"` |
| Link expiry | Defines a time where a specific link will expire e.g. `2025-02-27T10:28:07.160Z` | `"expires_at": "2025-02-27T10:28:07.160Z"` |


## API Flow

## Example API Usage

### Create a Payment Link

**Endpoint**: `POST v2/payment-links`

- Create a payment link by providing payment template information and any link config


**Example Request:**


```json
{
    "linkConfig": {
        "maxUsageCount": 1000,
        "perPaymentAmountLimit": "500.00",
        "totalAmountLimit": "20000.00"
    },
    "paymentTemplate": {
        "refId": "{{C_REFID}}",
        "amount": {
            "currency": "GBP"
        },
        "creditor": {
            "name": "Dana Creditor",
            "accountNumber": "543512",
            "sortCode": "123312"
        },
        "localInstrument": "FASTER_PAYMENTS"
    }
}
```

**Example Response:**


```json
{
    "paymentLink": {
        "id": "pl-019d4862-21dd-77ad-851c-b615fd587e3e",
        "status": "LINK_ACTIVE",
        "createdAt": "2026-04-01T09:31:23.997748Z",
        "paymentTemplate": {
            "id": "pt-019d4862-21db-71ac-a6a2-45f3870dacfd",
            "amount": {
                "currency": "GBP"
            },
            "localInstrument": "FASTER_PAYMENTS",
            "creditor": {
                "name": "Dana Creditor",
                "sortCode": "123312",
                "accountNumber": "543512"
            },
            "refId": "1775035882"
        },
        "linkConfig": {
            "maxUsageCount": 1000,
            "perPaymentAmountLimit": "500.00",
            "totalAmountLimit": "20000.00"
        },
        "url": "https://app.sandbox.token.io/pay-by-link/pl-019d4862-21dd-77ad-851c-b615fd587e3e",
        "currentUsage": {
            "remainingCount": 1000,
            "remainingAmount": "20000.00"
        },
        "memberId": "m:R7mNpQ2wXcBv4Ls123y8FhKn3EgU:9aWmKpZx"
    }
}
```

### Get a Payment Link(s)

**Endpoint**: `GET /v2/payment-links/{id}`

- Get a payment link based on the ID


**Endpoint**: `GET /v2/payment-links`

- Supports query parameters below as part of the GET request. **NOTE: At least one filter must be provided.**


| Query Parameter | Description |
|  --- | --- |
| `paymentLinkId` | Filter by a specific payment link ID |
| `status` | Filter by payment link status |
| `createdAfter` | Return links created after this timestamp |
| `createdBefore` | Return links created before this timestamp |
| `expiresAfter` | Return links expiring after this timestamp |
| `expiresBefore` | Return links expiring before this timestamp |
| `externalPsuReference` | Filter by the external PSU reference |
| `onBehalfOfId` | Filter by the acting entity ID (where applicable) |


br
**Example Response:**


```json
{
    "paymentLink": {
        "id": "pl-019d4560-aa5e-7f96-9c50-c9c86b521f54",
        "status": "LINK_ACTIVE",
        "createdAt": "2026-03-31T19:30:56.223122Z",
        "paymentTemplate": {
            "id": "pt-019d4560-aa5b-754c-a96a-fd1c6d743b43",
            "amount": {
                "currency": "EUR"
            },
            "localInstrument": "FASTER_PAYMENTS",
            "creditor": {
                "name": "Dana Creditor",
                "sortCode": "123312",
                "accountNumber": "543512"
            },
            "refId": "1774985456",
            "risk": {}
        },
        "linkConfig": {
            "maxUsageCount": 1000,
            "perPaymentAmountLimit": "500.00",
            "totalAmountLimit": "20000.00"
        },
        "url": "https://app.sandbox.token.io/pay-by-link/pl-019d4560-aa5e-7f96-9c50-c9c86b521f54",
        "currentUsage": {
            "remainingCount": 1000,
            "remainingAmount": "20000.00"
        },
        "memberId": "m:R7mNpQ2wXcBv4LsJdTy8FhKn3EgU:9aWmKpZx"
    }
}
```

br
#### Get Payments for a Link

To get a list of payments that have been initiated from a given link, you can do so by using the following request

br
**Endpoint:** `GET /v2/payments?paymentLinkId={paymentLinkId}`

br
This will return a list of payment attributed to a link.

br
### Cancel a Payment Link

**Endpoint**: `DELETE /v2/payment-links/{id}`

- Cancel an **active** payment link


> **PLEASE NOTE**: The ability to cancel a link is dependent on the status of the payment link. To highlight this, the response from the endpoint will differ accordingly.


br
**Possible outcomes**

br
* If the link already has `LINK_CANCELED` or `LINK_ACTIVE` - the response will be a `200 OK`
* If the link has a different status - the response will be a `409 Conflict` with an additional error message to highlight the reason why it can not be cancelled.


br

```json
{
    "paymentLink": {
        "id": "pl-019d4560-aa5e-7f96-9c50-c9c86b521f54",
        "status": "LINK_CANCELED",
        "createdAt": "2026-03-31T19:30:56.223122Z",
        "paymentTemplate": {
            "id": "pt-019d4560-aa5b-754c-a96a-fd1c6d743b43",
            "amount": {
                "currency": "EUR"
            },
            "localInstrument": "FASTER_PAYMENTS",
            "creditor": {
                "name": "Dana Creditor",
                "sortCode": "123312",
                "accountNumber": "543512"
            },
            "refId": "1774985456",
            "risk": {}
        },
        "linkConfig": {
            "maxUsageCount": 1000,
            "perPaymentAmountLimit": "500.00",
            "totalAmountLimit": "20000.00"
        },
        "url": "https://app.sandbox.token.io/pay-by-link/pl-019d4560-aa5e-7f96-9c50-c9c86b521f54",
        "currentUsage": {
            "remainingCount": 1000,
            "remainingAmount": "20000.00"
        },
        "memberId": "m:R7mNpQ2wXcBv4LsJdTy8FhKn3EgU:9aWmKpZx"
    }
}
```

## Customisation Options

### Dashboard Customisation Options

#### 1. Branding & Visual Identity

- **Logo:** Upload your company logo to appear on the Pay by Link payment page. The logo can be inherited from your existing WAV2 configuration or uploaded specifically for Pay by Link. Supported formats include PNG, JPG, and JPEG, with size and dimension guidelines to ensure optimal display.
- **Logo Alt Text:** Add descriptive alt text for your logo to improve accessibility for users with screen readers.
- **Primary Colour:** Set your brand’s primary colour, which will be used for key UI elements (such as buttons and highlights) on the payment page.
- **Favicon:** Upload a custom favicon to appear in the browser tab when customers open your payment link.


#### 2. Text & Field Labels

- **Custom Field Names:** Change the labels for key fields such as “Amount” and “Reference” to match your business terminology (e.g., “Total,” “Order Number,” etc.).
- **Header Text:** Customise the welcome or header message displayed at the top of the payment page (e.g., “Welcome to [Your Brand] Pay by Link”).
- **Instructional Text:** Add or edit instructional or informational text to guide your customers through the payment process.


#### 3. Feature Toggles

- **PDF Download Option:** Enable or disable the option for customers to download a PDF receipt of their payment directly from the confirmation page.


#### 4. Accessibility & Usability

- **Alt Text for Images:** Ensure all uploaded images (logos, favicons) have descriptive alt text for accessibility.


These customisation options are managed directly from the Pay by Link configuration section in your Dashboard, allowing you to update branding, text, and features without any code changes.

## Further information

- Review the [API reference](https://reference.token.io) for integration details.
- For more on integrating with other Token.io features, visit our [developer documentation](https://developer.token.io/).


If you have any feedback about the developer documentation, please contact [devdocs@token.io](mailto:devdocs@token.io)