Developers

Search for documents

Dev

Pay by Link

Pay by Link lets you create a secure, Valpay-hosted payment page and share its URL with your shopper by email, SMS, chat or invoice. The shopper opens the link, picks a payment method and pays. You don't need to build a checkout.

Availability: Pay by Link is currently available in the dev sandbox only. Production availability will be announced separately. Use test cards only; no real money moves in the sandbox.

Base URL

Environment

Base URL

Dev sandbox

https://payments.valpay.dev

Production

Coming soon

Authentication

Pay by Link uses the same credentials as the existing Payments API (/v1/payments/create). Send one of these headers on every request:

  • x-api-key: <your API key>

  • Authorization: Bearer <your token>

You can only create, view and expire links for merchants and stores your credentials are authorised for.

Endpoints

Method

Path

Description

POST

/v1/payments/links

Create a payment link

GET

/v1/payments/links/{linkId}

Retrieve a payment link and its status

PATCH

/v1/payments/links/{linkId}

Expire a payment link

Create a payment link

POST /v1/payments/links

Headers

Header

Required

Description

x-api-key or Authorization

Yes

One of the two auth headers above.

Content-Type

Yes

application/json

Idempotency-Key

No

Optional, recommended. 1–64 characters (a UUID is ideal). Retrying with the same key for the same store returns the original link instead of creating a new one, for about 7–14 days. Without a key, a retry creates a second link.

Request body

Field

Type

Required

Description

store

string (UUID)

Yes

The Valpay store the payment is for.

amount.value

integer

Yes

Amount in minor units (e.g. 1050 = 10.50).

amount.currency

string

Yes

ISO 4217 currency code, e.g. USD.

reference

string

Yes

Your own reference, 1–80 characters. Must not end in "fees" (reserved).

description

string

No

Shown to the shopper on the payment page. Max 280 characters.

expiresAt

string (ISO 8601 with offset)

No

When the link expires. Must be in the future and at most 70 days ahead. Defaults to 24 hours.

shopperEmail

string

No

Shopper's email address.

shopperReference

string

No

Your identifier for the shopper, 3–255 characters.

shopperLocale

string

No

Language of the payment page, e.g. en-US.

countryCode

string

No

ISO 3166-1 alpha-2 code, used to show relevant payment methods.

returnUrl

string

No

Where the shopper is redirected after paying.

Don't send merchantAccount. Valpay sets it from your credentials and store, and sending it returns 400.

Example request

curl -X POST https://payments.valpay.dev/v1/payments/links \
  -H "x-api-key: <your API key>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2a9e-3b7d-4e2a-9c51-0d8e4f7a1b23" \
  -d '{
    "store": "3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b",
    "reference": "INV-1001",
    "amount": { "value": 4999, "currency": "USD" },
    "description": "Invoice #1042",
    "shopperEmail": "shopper@example.com",
    "expiresAt": "2026-11-03T23:59:59Z",
    "returnUrl": "https://example.com/thanks"
  }'
curl -X POST https://payments.valpay.dev/v1/payments/links \
  -H "x-api-key: <your API key>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2a9e-3b7d-4e2a-9c51-0d8e4f7a1b23" \
  -d '{
    "store": "3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b",
    "reference": "INV-1001",
    "amount": { "value": 4999, "currency": "USD" },
    "description": "Invoice #1042",
    "shopperEmail": "shopper@example.com",
    "expiresAt": "2026-11-03T23:59:59Z",
    "returnUrl": "https://example.com/thanks"
  }'
curl -X POST https://payments.valpay.dev/v1/payments/links \
  -H "x-api-key: <your API key>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2a9e-3b7d-4e2a-9c51-0d8e4f7a1b23" \
  -d '{
    "store": "3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b",
    "reference": "INV-1001",
    "amount": { "value": 4999, "currency": "USD" },
    "description": "Invoice #1042",
    "shopperEmail": "shopper@example.com",
    "expiresAt": "2026-11-03T23:59:59Z",
    "returnUrl": "https://example.com/thanks"
  }'

Example response: 201 Created

{
  "id": "PL6B2C1D4E5F6A7B8C",
  "url": "https://test.adyen.link/PL6B2C1D4E5F6A7B8C",
  "status": "active",
  "store": "3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b",
  "reference": "INV-1001",
  "amount": { "value": 4999, "currency": "USD" },
  "description": "Invoice #1042",
  "expiresAt": "2026-11-03T23:59:59Z",
  "reusable": false
}
{
  "id": "PL6B2C1D4E5F6A7B8C",
  "url": "https://test.adyen.link/PL6B2C1D4E5F6A7B8C",
  "status": "active",
  "store": "3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b",
  "reference": "INV-1001",
  "amount": { "value": 4999, "currency": "USD" },
  "description": "Invoice #1042",
  "expiresAt": "2026-11-03T23:59:59Z",
  "reusable": false
}
{
  "id": "PL6B2C1D4E5F6A7B8C",
  "url": "https://test.adyen.link/PL6B2C1D4E5F6A7B8C",
  "status": "active",
  "store": "3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b",
  "reference": "INV-1001",
  "amount": { "value": 4999, "currency": "USD" },
  "description": "Invoice #1042",
  "expiresAt": "2026-11-03T23:59:59Z",
  "reusable": false
}

Send the url to your shopper. Store the id; you need it to check the status or expire the link.

Retrieve a payment link

GET /v1/payments/links/{linkId}

Parameter

In

Required

Description

linkId

path

Yes

The id returned when the link was created.

store

query

Yes

The store UUID the link was created for.

Example request

curl "https://payments.valpay.dev/v1/payments/links/PL6B2C1D4E5F6A7B8C?store=3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b" \
  -H "x-api-key: <your API key>"
curl "https://payments.valpay.dev/v1/payments/links/PL6B2C1D4E5F6A7B8C?store=3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b" \
  -H "x-api-key: <your API key>"
curl "https://payments.valpay.dev/v1/payments/links/PL6B2C1D4E5F6A7B8C?store=3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b" \
  -H "x-api-key: <your API key>"

Example response: 200 OK

Same shape as the create response, with the current status.

Link statuses

Status

Meaning

active

The link can be paid.

paymentPending

The shopper started a payment that isn't final yet.

completed

The link has been paid.

paid

The link has been paid.

expired

The link expired or was expired by you. It can no longer be paid.

No webhook is sent for link payments yet. Check the result with GET /v1/payments/links/{linkId}?store=… and read status.

Expire a payment link

PATCH /v1/payments/links/{linkId}

Use this to cancel a link before the shopper pays, for example if an order is cancelled. The only supported change is setting status to expired, and an expired link can't be reactivated.

Field

Type

Required

Description

store

string (UUID)

Yes

The store UUID the link was created for.

status

string

Yes

Must be expired.

Example request

curl -X PATCH https://payments.valpay.dev/v1/payments/links/PL6B2C1D4E5F6A7B8C \
  -H "x-api-key: <your API key>" \
  -H "Content-Type: application/json" \
  -d '{ "store": "3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b", "status": "expired" }'
curl -X PATCH https://payments.valpay.dev/v1/payments/links/PL6B2C1D4E5F6A7B8C \
  -H "x-api-key: <your API key>" \
  -H "Content-Type: application/json" \
  -d '{ "store": "3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b", "status": "expired" }'
curl -X PATCH https://payments.valpay.dev/v1/payments/links/PL6B2C1D4E5F6A7B8C \
  -H "x-api-key: <your API key>" \
  -H "Content-Type: application/json" \
  -d '{ "store": "3f2b1c9e-8a7d-4e6f-9b21-5c4d3e2f1a0b", "status": "expired" }'

Example response: 200 OK

The updated link, with "status": "expired".

Errors

Pay by Link returns errors in the same format as the rest of the Payments API.

HTTP status

Meaning

400 Bad Request

Invalid request: missing or malformed fields, unknown fields (e.g. merchantAccount), or store missing.

401 Unauthorized

Missing or invalid credentials.

403 Forbidden

Your credentials are not allowed to use this endpoint.

404 Not Found

No link with this linkId for this store, or a store you cannot access.

500 Internal Server Error

The payment provider rejected the request (e.g. expiring a link that is already completed or expired; see errorDetails), or a temporary error. For temporary errors, retry with the same Idempotency-Key.

Testing in the sandbox

  1. Create a link with the example request above.

  2. Open the returned url in a browser.

  3. Pay with an Adyen test card: 4111 1111 1111 1111, expiry 03/30, CVC 737.

  4. Call GET /v1/payments/links/{linkId}?store=<your store UUID> and check status.

Try it out
POST