# Accept an Alternative Payment

This guide covers hosted redirect payments through payment sessions, using Paysafecard (`psc`) as the payment method. The customer completes the payment on the provider's hosted page instead of entering details on your site, so no card or voucher data ever touches your integration.

Creating a session also creates a linked transaction. The transaction follows the standard [transaction lifecycle](/guides/transaction-statuses) and emits the standard [webhook events](/guides/webhooks), so payment sessions plug into the same confirmation machinery as card payments.

For a walkthrough of the Paysafecard flow party by party, with a diagram, see [Paysafecard via Skrill: Customer Journey](/guides/paysafecard-via-skrill).

## Before you start

- You need an API key. Send it on every request as `Authorization: Bearer {YOUR_API_KEY}`.
- All examples use the sandbox base URL `https://api.sandbox.softlemons.com`.
- Redirect payments and the specific payment method must be enabled for your account. Requests for a method that is not enabled fail with `ERR_PAYMENT_METHOD_NOT_ENABLED`. Contact [support](/api-basics/support) to get a method enabled.
- Each method is only available in certain countries, and the provider risk-checks the customer's IP. Send `customer.country_code` and `customer.ip_address` on every session. See [Availability](#availability) below.
- Send `customer.email` too. For Paysafecard, Skrill uses it to take the customer straight to paysafecard's page instead of showing its own checkout form first.
- You need two browser URLs on your site: a success URL and a cancel URL for the customer's return.
- Amounts are major units in requests (`25.00`) and minor units in responses (`2500`). See [conventions](/api-basics/conventions).
- Never send card fields. A session request carrying card, token, CVV or voucher data is rejected with HTTP 422 regardless of where the field appears in the payload.

## Step 1: Create a payment session

Call `POST /api/v1/payment-sessions` with the amount, a unique `reference`, the payment method and your return URLs:

{/* snippet:accept-an-alternative-payment:create-session */}
<CodeTabs syncKey="request-lang">

```shell title="cURL"
curl https://api.sandbox.softlemons.com/api/v1/payment-sessions \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer {YOUR_API_KEY}' \
  --data '{
  "amount": 25,
  "currency": "EUR",
  "reference": "DEP-2048",
  "payment_method": "psc",
  "customer": {
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "country_code": "GB",
    "ip_address": "198.51.100.5",
    "merchant_customer_id": "player-981"
  },
  "customer_reference": "player-981",
  "success_url": "https://merchant.example.com/deposit/complete",
  "cancel_url": "https://merchant.example.com/deposit/cancelled"
}'
```

```js title="JavaScript"
fetch('https://api.sandbox.softlemons.com/api/v1/payment-sessions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer {YOUR_API_KEY}'
  },
  body: JSON.stringify({
    amount: 25,
    currency: 'EUR',
    reference: 'DEP-2048',
    payment_method: 'psc',
    customer: {
      first_name: 'Jane',
      last_name: 'Doe',
      email: 'jane@example.com',
      country_code: 'GB',
      ip_address: '198.51.100.5',
      merchant_customer_id: 'player-981'
    },
    customer_reference: 'player-981',
    success_url: 'https://merchant.example.com/deposit/complete',
    cancel_url: 'https://merchant.example.com/deposit/cancelled'
  })
})
```

```python title="Python"
requests.post(
    "https://api.sandbox.softlemons.com/api/v1/payment-sessions",
    headers={
      "Content-Type": "application/json",
      "Authorization": "Bearer {YOUR_API_KEY}"
    },
    json={
      "amount": 25,
      "currency": "EUR",
      "reference": "DEP-2048",
      "payment_method": "psc",
      "customer": {
        "first_name": "Jane",
        "last_name": "Doe",
        "email": "jane@example.com",
        "country_code": "GB",
        "ip_address": "198.51.100.5",
        "merchant_customer_id": "player-981"
      },
      "customer_reference": "player-981",
      "success_url": "https://merchant.example.com/deposit/complete",
      "cancel_url": "https://merchant.example.com/deposit/cancelled"
    }
)
```

```java title="Java"
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n  \"amount\": 25,\n  \"currency\": \"EUR\",\n  \"reference\": \"DEP-2048\",\n  \"payment_method\": \"psc\",\n  \"customer\": {\n    \"first_name\": \"Jane\",\n    \"last_name\": \"Doe\",\n    \"email\": \"jane@example.com\",\n    \"country_code\": \"GB\",\n    \"ip_address\": \"198.51.100.5\",\n    \"merchant_customer_id\": \"player-981\"\n  },\n  \"customer_reference\": \"player-981\",\n  \"success_url\": \"https://merchant.example.com/deposit/complete\",\n  \"cancel_url\": \"https://merchant.example.com/deposit/cancelled\"\n}");
Request request = new Request.Builder()
  .url("https://api.sandbox.softlemons.com/api/v1/payment-sessions")
  .post(body)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer {YOUR_API_KEY}")
  .build();

Response response = client.newCall(request).execute();
```

```go title="Go"
package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
)

func main() {
	requestUrl := "https://api.sandbox.softlemons.com/api/v1/payment-sessions"

	payload := strings.NewReader(`{
  "amount": 25,
  "currency": "EUR",
  "reference": "DEP-2048",
  "payment_method": "psc",
  "customer": {
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "country_code": "GB",
    "ip_address": "198.51.100.5",
    "merchant_customer_id": "player-981"
  },
  "customer_reference": "player-981",
  "success_url": "https://merchant.example.com/deposit/complete",
  "cancel_url": "https://merchant.example.com/deposit/cancelled"
}`)

	req, _ := http.NewRequest("POST", requestUrl, payload)

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Authorization", "Bearer {YOUR_API_KEY}")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```csharp title="C#"
using var client = new HttpClient();

var request = new HttpRequestMessage(HttpMethod.Post, "https://api.sandbox.softlemons.com/api/v1/payment-sessions");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");
request.Content = new StringContent(
"""
{
  "amount": 25,
  "currency": "EUR",
  "reference": "DEP-2048",
  "payment_method": "psc",
  "customer": {
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "country_code": "GB",
    "ip_address": "198.51.100.5",
    "merchant_customer_id": "player-981"
  },
  "customer_reference": "player-981",
  "success_url": "https://merchant.example.com/deposit/complete",
  "cancel_url": "https://merchant.example.com/deposit/cancelled"
}
""",
System.Text.Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
```

```kotlin title="Kotlin"
val client = OkHttpClient()

val mediaType = MediaType.parse("application/json")
val body = RequestBody.create(mediaType, "{\n  \"amount\": 25,\n  \"currency\": \"EUR\",\n  \"reference\": \"DEP-2048\",\n  \"payment_method\": \"psc\",\n  \"customer\": {\n    \"first_name\": \"Jane\",\n    \"last_name\": \"Doe\",\n    \"email\": \"jane@example.com\",\n    \"country_code\": \"GB\",\n    \"ip_address\": \"198.51.100.5\",\n    \"merchant_customer_id\": \"player-981\"\n  },\n  \"customer_reference\": \"player-981\",\n  \"success_url\": \"https://merchant.example.com/deposit/complete\",\n  \"cancel_url\": \"https://merchant.example.com/deposit/cancelled\"\n}")
val request = Request.Builder()
  .url("https://api.sandbox.softlemons.com/api/v1/payment-sessions")
  .post(body)
  .addHeader("Content-Type", "application/json")
  .addHeader("Authorization", "Bearer {YOUR_API_KEY}")
  .build()

val response = client.newCall(request).execute()
```

```objc title="Objective-C"
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Content-Type": @"application/json",
                           @"Authorization": @"Bearer {YOUR_API_KEY}" };

NSDictionary *parameters = @{ @"amount": @25,
                              @"currency": @"EUR",
                              @"reference": @"DEP-2048",
                              @"payment_method": @"psc",
                              @"customer": @{ @"first_name": @"Jane", @"last_name": @"Doe", @"email": @"jane@example.com", @"country_code": @"GB", @"ip_address": @"198.51.100.5", @"merchant_customer_id": @"player-981" },
                              @"customer_reference": @"player-981",
                              @"success_url": @"https://merchant.example.com/deposit/complete",
                              @"cancel_url": @"https://merchant.example.com/deposit/cancelled" };

NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.sandbox.softlemons.com/api/v1/payment-sessions"]
                                                      cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                  timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  if (error) {
    NSLog(@"%@", error);
  } else {
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
    NSLog(@"%@", httpResponse);
  }
}];
[dataTask resume];
```

```php title="PHP"
$ch = curl_init("https://api.sandbox.softlemons.com/api/v1/payment-sessions");

curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json', 'Authorization: Bearer {YOUR_API_KEY}']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
  'amount' => 25,
  'currency' => 'EUR',
  'reference' => 'DEP-2048',
  'payment_method' => 'psc',
  'customer' => [
    'first_name' => 'Jane',
    'last_name' => 'Doe',
    'email' => 'jane@example.com',
    'country_code' => 'GB',
    'ip_address' => '198.51.100.5',
    'merchant_customer_id' => 'player-981'
  ],
  'customer_reference' => 'player-981',
  'success_url' => 'https://merchant.example.com/deposit/complete',
  'cancel_url' => 'https://merchant.example.com/deposit/cancelled'
]));

curl_exec($ch);

curl_close($ch);
```

```ruby title="Ruby"
require 'uri'
require 'net/http'

url = URI("https://api.sandbox.softlemons.com/api/v1/payment-sessions")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request["Authorization"] = 'Bearer {YOUR_API_KEY}'
request.body = <<~JSON
{
  "amount": 25,
  "currency": "EUR",
  "reference": "DEP-2048",
  "payment_method": "psc",
  "customer": {
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "country_code": "GB",
    "ip_address": "198.51.100.5",
    "merchant_customer_id": "player-981"
  },
  "customer_reference": "player-981",
  "success_url": "https://merchant.example.com/deposit/complete",
  "cancel_url": "https://merchant.example.com/deposit/cancelled"
}
JSON

response = http.request(request)
puts response.read_body
```

```swift title="Swift"
import Foundation

var request = URLRequest(url: URL(string: "https://api.sandbox.softlemons.com/api/v1/payment-sessions")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer {YOUR_API_KEY}", forHTTPHeaderField: "Authorization")
let jsonBody = #"""
{
  "amount": 25,
  "currency": "EUR",
  "reference": "DEP-2048",
  "payment_method": "psc",
  "customer": {
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "country_code": "GB",
    "ip_address": "198.51.100.5",
    "merchant_customer_id": "player-981"
  },
  "customer_reference": "player-981",
  "success_url": "https://merchant.example.com/deposit/complete",
  "cancel_url": "https://merchant.example.com/deposit/cancelled"
}
"""#
request.httpBody = jsonBody.data(using: .utf8)

let (data, response) = try await URLSession.shared.data(for: request)

guard let httpResponse = response as? HTTPURLResponse,
      200..<300 ~= httpResponse.statusCode else {
  throw URLError(.badServerResponse)
}

print(String(data: data, encoding: .utf8) ?? "")
```

</CodeTabs>
{/* /snippet */}

```json
{
  "success": true,
  "message": "Payment session created",
  "code": "",
  "data": {
    "payment_session": {
      "payment_session_id": "ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE",
      "transaction_id": 4512,
      "merchant_id": 123,
      "merchant_reference": "DEP-2048",
      "provider": "skrill",
      "payment_method": "psc",
      "status": "pending_redirect",
      "amount": 2500,
      "amount_formatted": "25.00",
      "currency": "EUR",
      "checkout_url": "https://pay.skrill.com/?sid=a1b2c3d4e5",
      "return_url": "https://merchant.example.com/deposit/complete",
      "cancel_url": "https://merchant.example.com/deposit/cancelled",
      "provider_session_id": "a1b2c3d4e5",
      "provider_transaction_id": null,
      "customer_reference": "player-981",
      "expires_at": "2026-08-08T10:30:00.000000Z",
      "finalised_at": null,
      "created_at": "2026-08-08T10:15:00.000000Z",
      "updated_at": "2026-08-08T10:15:00.000000Z"
    }
  }
}
```

The response gives you everything the flow needs:

- `payment_session_id` identifies the session in later status calls.
- `checkout_url` is the provider's hosted page for this payment. Send the customer there in Step 2.
- `transaction_id` is the linked transaction. Webhook events reference it.
- `expires_at` is 15 minutes after creation. An unfinished session expires at that point.
- The request field `success_url` comes back as `return_url` on the session.

The `reference` must be unique and [duplicate protection](/guides/duplicate-protection) applies. Reusing a reference that has an active session or transaction returns HTTP 409.

Partner API keys create sessions on behalf of a linked merchant by adding `merchant_id` to the body, with the same rules as [partner card payments](/guides/partner-integration).

Two `customer` fields deserve special care:

- `customer.country_code` is the customer's country. It is checked against the method's availability before anything is sent to the provider (see [Availability](#availability)).
- `customer.ip_address` is the customer's IP address as your server saw it, IPv4 or IPv6. Your call to this API is server-to-server, so without this field the provider only ever sees the IP of your server. Pass the value you actually observed and never a substitute: it is your attestation about the customer, and the provider uses it for its risk decision.

## Step 2: Redirect the customer

Send the customer's browser to `checkout_url`. This is a full page redirect, not an iframe. The customer confirms the payment on the provider's page, for Paysafecard by entering their voucher PIN there.

The session stays `pending_redirect` while the customer is on the hosted page. It only changes when the provider reports back: `pending_provider` if the provider says the payment is still in progress, otherwise straight to `paid`, `failed` or `cancelled`. If the customer does not finish within 15 minutes the session becomes `expired` and you need to create a new one.

## Step 3: Handle the browser return

After the hosted page the provider sends the customer back through the gateway, which immediately redirects the browser to your `success_url` or `cancel_url` with three query parameters appended:

```
https://merchant.example.com/deposit/complete?payment_session_id=ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE&reference=DEP-2048&status=pending_redirect
```

Treat this landing as navigation only. It tells you which session the customer came back from, never whether money moved. Confirmation of the provider's outcome can arrive before or after the browser does, so render a waiting state and resolve it in Step 4. Customers who close the tab never hit your return URL at all and the outcome still arrives by webhook.

## Step 4: Confirm the outcome

The reliable signal is the webhook on the linked transaction. When the provider confirms the payment the session becomes `paid` and its transaction becomes `captured`, which delivers `transaction.captured` to your [webhook endpoint](/guides/webhooks). A failed payment delivers `transaction.failed` and an abandoned or expired session delivers `transaction.cancelled`.

To resolve a waiting page or reconcile on demand, poll the session:

{/* snippet:accept-an-alternative-payment:poll-session */}
<CodeTabs syncKey="request-lang">

```shell title="cURL"
curl https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE \
  --header 'Authorization: Bearer {YOUR_API_KEY}'
```

```js title="JavaScript"
fetch('https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE', {
  headers: {
    Authorization: 'Bearer {YOUR_API_KEY}'
  }
})
```

```python title="Python"
requests.get(
    "https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE",
    headers={
      "Authorization": "Bearer {YOUR_API_KEY}"
    }
)
```

```java title="Java"
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE")
  .get()
  .addHeader("Authorization", "Bearer {YOUR_API_KEY}")
  .build();

Response response = client.newCall(request).execute();
```

```go title="Go"
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	requestUrl := "https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE"

	req, _ := http.NewRequest("GET", requestUrl, nil)

	req.Header.Add("Authorization", "Bearer {YOUR_API_KEY}")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```csharp title="C#"
using var client = new HttpClient();

var request = new HttpRequestMessage(HttpMethod.Get, "https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");

using var response = await client.SendAsync(request);
```

```kotlin title="Kotlin"
val client = OkHttpClient()

val request = Request.Builder()
  .url("https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE")
  .get()
  .addHeader("Authorization", "Bearer {YOUR_API_KEY}")
  .build()

val response = client.newCall(request).execute()
```

```objc title="Objective-C"
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": @"Bearer {YOUR_API_KEY}" };

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE"]
                                                      cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                  timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  if (error) {
    NSLog(@"%@", error);
  } else {
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
    NSLog(@"%@", httpResponse);
  }
}];
[dataTask resume];
```

```php title="PHP"
$ch = curl_init("https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE");

curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer {YOUR_API_KEY}']);

curl_exec($ch);

curl_close($ch);
```

```ruby title="Ruby"
require 'uri'
require 'net/http'

url = URI("https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer {YOUR_API_KEY}'

response = http.request(request)
puts response.read_body
```

```swift title="Swift"
import Foundation

var request = URLRequest(url: URL(string: "https://api.sandbox.softlemons.com/api/v1/payment-sessions/ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE")!)
request.httpMethod = "GET"
request.setValue("Bearer {YOUR_API_KEY}", forHTTPHeaderField: "Authorization")

let (data, response) = try await URLSession.shared.data(for: request)

guard let httpResponse = response as? HTTPURLResponse,
      200..<300 ~= httpResponse.statusCode else {
  throw URLError(.badServerResponse)
}

print(String(data: data, encoding: .utf8) ?? "")
```

</CodeTabs>
{/* /snippet */}

```json
{
  "success": true,
  "message": "Payment session retrieved",
  "code": "",
  "data": {
    "payment_session": {
      "payment_session_id": "ps_01J8FYK3ZQ4T9RB2M6XD5A7CWE",
      "transaction_id": 4512,
      "merchant_id": 123,
      "merchant_reference": "DEP-2048",
      "provider": "skrill",
      "payment_method": "psc",
      "status": "paid",
      "amount": 2500,
      "amount_formatted": "25.00",
      "currency": "EUR",
      "checkout_url": "https://pay.skrill.com/?sid=a1b2c3d4e5",
      "return_url": "https://merchant.example.com/deposit/complete",
      "cancel_url": "https://merchant.example.com/deposit/cancelled",
      "provider_session_id": "a1b2c3d4e5",
      "provider_transaction_id": "2649912345",
      "customer_reference": "player-981",
      "expires_at": "2026-08-08T10:30:00.000000Z",
      "finalised_at": "2026-08-08T10:18:42.000000Z",
      "created_at": "2026-08-08T10:15:00.000000Z",
      "updated_at": "2026-08-08T10:18:42.000000Z"
    }
  }
}
```

Credit the customer only when the session is `paid` or the `transaction.captured` webhook arrives. The full session lifecycle (`created`, `pending_redirect`, `pending_provider`, `paid`, `failed`, `cancelled`, `chargeback`, `expired`) is documented in the [statuses reference](/guides/transaction-statuses).

## Availability

Alternative payment methods are not available everywhere. Two checks decide whether a session can be opened:

1. **Country.** Each method has a list of countries it can serve. For Paysafecard (`psc`) that is paysafecard's published availability (most of Europe plus, among others, Australia, Canada, Mexico, New Zealand, the United Kingdom and the United States; not, for example, South Africa or Costa Rica). Your account may carry a narrower list. The check runs on `customer.country_code` before the provider is contacted, and a country the method does not serve is refused with HTTP 400 `ERR_PAYMENT_METHOD_NOT_AVAILABLE_IN_COUNTRY`. Nothing is created and the `reference` stays free. If you do not send `customer.country_code` the check is skipped and the provider decides on its hosted page.
2. **Provider risk rules on the customer's IP.** The provider risk-checks the IP it receives as the customer's device IP. That IP is `customer.ip_address` when you send it, and the IP of the server calling this API when you do not. A server in a country the method does not serve therefore gets every payment refused unless it forwards the real customer IP. When the provider declines to open the checkout, the session fails with HTTP 400 `ERR_PROVIDER_REJECTED`, the `message` carries the provider's reason (for example `The transaction has been blocked`), the linked transaction is `failed` with the same `status_reason`, and the `reference` is released.

To avoid surprises, always send both `customer.country_code` and `customer.ip_address`, and offer the customer another method when you receive either code. Neither check creates a provider payment, so they are safe to hit as often as your checkout needs.

### Ask before you show a method

`GET /api/v1/payment-methods` answers the same questions ahead of time so your checkout only shows methods that can actually be opened. Pass the customer's `country` and the payment `currency`; partner keys add `merchant_id`.

{/* snippet:accept-an-alternative-payment:list-methods */}
<CodeTabs syncKey="request-lang">

```shell title="cURL"
curl 'https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR' \
  --header 'Authorization: Bearer {YOUR_API_KEY}'
```

```js title="JavaScript"
fetch('https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR', {
  headers: {
    Authorization: 'Bearer {YOUR_API_KEY}'
  }
})
```

```python title="Python"
requests.get(
    "https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR",
    headers={
      "Authorization": "Bearer {YOUR_API_KEY}"
    }
)
```

```java title="Java"
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR")
  .get()
  .addHeader("Authorization", "Bearer {YOUR_API_KEY}")
  .build();

Response response = client.newCall(request).execute();
```

```go title="Go"
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	requestUrl := "https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR"

	req, _ := http.NewRequest("GET", requestUrl, nil)

	req.Header.Add("Authorization", "Bearer {YOUR_API_KEY}")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```csharp title="C#"
using var client = new HttpClient();

var request = new HttpRequestMessage(HttpMethod.Get, "https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "{YOUR_API_KEY}");

using var response = await client.SendAsync(request);
```

```kotlin title="Kotlin"
val client = OkHttpClient()

val request = Request.Builder()
  .url("https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR")
  .get()
  .addHeader("Authorization", "Bearer {YOUR_API_KEY}")
  .build()

val response = client.newCall(request).execute()
```

```objc title="Objective-C"
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": @"Bearer {YOUR_API_KEY}" };

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR"]
                                                      cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                  timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  if (error) {
    NSLog(@"%@", error);
  } else {
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
    NSLog(@"%@", httpResponse);
  }
}];
[dataTask resume];
```

```php title="PHP"
$ch = curl_init("https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR");

curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer {YOUR_API_KEY}']);

curl_exec($ch);

curl_close($ch);
```

```ruby title="Ruby"
require 'uri'
require 'net/http'

url = URI("https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer {YOUR_API_KEY}'

response = http.request(request)
puts response.read_body
```

```swift title="Swift"
import Foundation

var request = URLRequest(url: URL(string: "https://api.sandbox.softlemons.com/api/v1/payment-methods?country=GB&currency=EUR")!)
request.httpMethod = "GET"
request.setValue("Bearer {YOUR_API_KEY}", forHTTPHeaderField: "Authorization")

let (data, response) = try await URLSession.shared.data(for: request)

guard let httpResponse = response as? HTTPURLResponse,
      200..<300 ~= httpResponse.statusCode else {
  throw URLError(.badServerResponse)
}

print(String(data: data, encoding: .utf8) ?? "")
```

</CodeTabs>
{/* /snippet */}

```json
{
  "success": true,
  "message": "Payment methods retrieved",
  "code": "",
  "data": {
    "merchant_id": 123,
    "country": "GB",
    "currency": "EUR",
    "payment_methods": [
      {
        "payment_method": "psc",
        "label": "Paysafecard",
        "provider": "paycent",
        "available": true,
        "unavailable_reasons": [],
        "supported_countries": ["AR", "AT", "AU", "BE", "BG", "CA", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "GE", "DE", "GI", "GR", "HU", "IS", "IE", "IT", "KW", "LV", "LI", "LT", "LU", "MT", "MX", "MD", "ME", "NL", "NZ", "NO", "PY", "PE", "PL", "PT", "RO", "SA", "SK", "SI", "ES", "SE", "CH", "TR", "AE", "GB", "US", "UY"],
        "supported_currencies": ["EUR", "GBP", "USD"]
      },
      {
        "payment_method": "ideal",
        "label": "iDEAL",
        "provider": "paycent",
        "available": false,
        "unavailable_reasons": ["country_not_supported"],
        "supported_countries": ["NL"],
        "supported_currencies": ["EUR"]
      }
    ]
  }
}
```

Each row is a redirect method enabled for the account. `supported_countries` and `supported_currencies` are the restrictions in force for it (an empty list means no restriction is known), and when you pass filters `available` tells you whether a session for that customer would be accepted, with `unavailable_reasons` being one or more of `country_not_supported`, `currency_not_supported` and `provider_not_offering`. A method that is `available: false` here would be refused by `POST /api/v1/payment-sessions` with the matching error. The endpoint reads configuration and the provider's published catalogue only; it never opens a provider payment, so call it per checkout if you like. It is advisory: the session create still runs the full provider checks, and card payments are not listed because they are governed by your acquirer routing rather than by this list.

## Errors you should handle

| Response | Meaning | What to do |
|---|---|---|
| 400 `ERR_PAYMENT_METHOD_NOT_ENABLED` | The method or currency is not enabled for the merchant. | Offer a different payment method or contact [support](/api-basics/support) about enablement. |
| 400 `ERR_PAYMENT_METHOD_NOT_AVAILABLE_IN_COUNTRY` | The method is not available for `customer.country_code`. Checked before the provider is called; nothing is created. | Offer a different payment method for that country. See [Availability](#availability). |
| 400 `ERR_PROVIDER_REJECTED` | The provider refused to open the payment for this customer (risk or availability rules, typically the customer's country or IP). `message` carries the provider's reason. The session and transaction are marked failed and the `reference` is released. | Make sure you send the real `customer.ip_address` and `customer.country_code`. Do not retry the same data blindly; offer another method. |
| 409 `ERR_DUPLICATE` | A session or transaction with this `reference` already exists. | Fetch the existing session instead of retrying. See [duplicate protection](/guides/duplicate-protection). |
| 422 `ERR_VALIDATION_FAILED` | A field failed validation. This includes any request carrying card, token, CVV or voucher data, and a `customer.ip_address` that is not a valid IP. | Fix the request. Card data never belongs in a redirect session. |
| 429 `ERR_RATE_LIMITED` | Too many requests. | Back off and retry. See [rate limits](/api-basics/rate-limits). |
| 502 `ERR_GATEWAY_ERROR` | The provider could not prepare the hosted session. The session and its transaction are marked failed. | Create a new session to retry. |

Full details for every code are in the [error catalogue](/api-basics/errors).
