# Generate Payment Link

Create a **hosted checkout link** for an order. Redirect the shopper to the returned URL, they complete the PayLater flow (identity, instalment plan, payment), and we redirect them back to your success or failure URL.

**POST** `/api/paylater/merchant-portal/v2/web-checkout`

- Sandbox: `https://connect.uat.paylaterapp.com/api/paylater/merchant-portal/v2/web-checkout`
- Production: `https://connect.paylaterapp.com/api/paylater/merchant-portal/v2/web-checkout`

> **Info: Authentication**
>
> All requests require a bearer token from the [OAuth 2.0 token endpoint](https://docs.paylaterapp.com/authentication.html). Pass it as `Authorization: Bearer <ACCESS_TOKEN>`.

## Request

#### Headers

| Header | Value |
| --- | --- |
| `Authorization` | `Bearer <ACCESS_TOKEN>` |
| `Content-Type` | `application/json` |

**Body parameters**

- `outlet_id` (Long, required): The storefront / outlet identifier issued to your merchant account.
- `currency` (String, required): The order currency. Must be `QAR`.
- `amount` (Double, required): Order amount. Accepted range is `300`–`25,000` QAR (your outlet may be configured with a narrower range).
- `order_id` (String, required): Your unique reference for this transaction. Must be unique per merchant.
- `success_redirect_url` (String, required): URL the shopper is redirected to after a successful payment.
- `fail_redirect_url` (String, required): URL the shopper is redirected to if the payment fails or is abandoned.
- `expiry_duration` (Integer, required): How long the link stays valid, in minutes. Range `1`–`1440`.

### Example request

**cURL**

```bash
curl --location 'https://connect.uat.paylaterapp.com/api/paylater/merchant-portal/v2/web-checkout' \
  --header 'Authorization: Bearer <ACCESS_TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
    "outlet_id": 1000000061,
    "currency": "QAR",
    "amount": 350.00,
    "order_id": "O-3445",
    "success_redirect_url": "https://test.com/success",
    "fail_redirect_url": "https://test.com/fail",
    "expiry_duration": 10
  }'
```

**Node.js**

```javascript
const res = await fetch(
  'https://connect.uat.paylaterapp.com/api/paylater/merchant-portal/v2/web-checkout',
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      outlet_id: 1000000061,
      currency: 'QAR',
      amount: 350.0,
      order_id: 'O-3445',
      success_redirect_url: 'https://test.com/success',
      fail_redirect_url: 'https://test.com/fail',
      expiry_duration: 10,
    }),
  },
);

const { paymentLinkUrl } = await res.json();
```

**Python**

```python
import requests

resp = requests.post(
    "https://connect.uat.paylaterapp.com/api/paylater/merchant-portal/v2/web-checkout",
    headers={
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json",
    },
    json={
        "outlet_id": 1000000061,
        "currency": "QAR",
        "amount": 350.00,
        "order_id": "O-3445",
        "success_redirect_url": "https://test.com/success",
        "fail_redirect_url": "https://test.com/fail",
        "expiry_duration": 10,
    },
)

payment_link_url = resp.json()["paymentLinkUrl"]
```

**PHP**

```php
$ch = curl_init('https://connect.uat.paylaterapp.com/api/paylater/merchant-portal/v2/web-checkout');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $accessToken,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'outlet_id' => 1000000061,
        'currency' => 'QAR',
        'amount' => 350.00,
        'order_id' => 'O-3445',
        'success_redirect_url' => 'https://test.com/success',
        'fail_redirect_url' => 'https://test.com/fail',
        'expiry_duration' => 10,
    ]),
]);

$response = json_decode(curl_exec($ch), true);
```

## Response

A `200 OK` returns the hosted checkout URL. Redirect the shopper there to complete payment.

**200 OK**

```json
{
  "paymentLinkUrl": "https://payments.uat.paylaterapp.com/paylink/uuid?token=xyz&channel=web"
}
```

> **Warning: Payment links are single-use**
>
> Each link is valid for one payment attempt and expires after `expiry_duration` minutes. Generate a fresh link per checkout attempt.

## Errors

| Example response | Cause |
| --- | --- |
| `{ "error": "Merchant ID cannot be null" }` | `outlet_id` / merchant context missing or invalid. |
| `{ "error": "Order ID must be unique" }` | An order with this `order_id` already exists. |
| `{ "error": "Amount must be between 300 and 25000" }` | `amount` is outside the accepted range for your outlet. |

See [Error handling & response codes](https://docs.paylaterapp.com/errors.html) for the full catalogue.

## Next steps

- [Check Payment Status](https://docs.paylaterapp.com/check-payment-status.html): Poll the order status, or let webhooks tell you when it changes.
- [Webhooks](https://docs.paylaterapp.com/webhooks.html): Receive a signed notification the moment the payment succeeds or fails.
