Quick Pay

The Quick Pay endpoint creates a customer, order, order line, and payment in a single API request. It is designed for one-time payments — typically an e-commerce checkout or a face-to-face transaction where the amount is known at the time of the request.

When a customer completes a Quick Pay payment, they are redirected back to the redirect_url you supply. An optional webhook_url can be used to receive real-time status updates (see the Webhooks guide).

Base URL: https://api.wonderful.one

Authentication: All requests require a Authorization: Bearer {YOUR_AUTH_KEY} header. Obtain your token from your dashboard.


Payment flow

  1. The customer reaches your checkout and chooses "Pay by Bank".
  2. Your application calls POST /v2/quick-pay with the amount, a reference, and a redirect URL.
  3. The API returns a pay_link. Send the customer to that URL.
  4. The customer selects their bank, authorises the payment in their banking app, and is redirected back to your redirect_url with a ?wonderful-payment-id= query parameter.
  5. Your application calls GET /v2/payments/{id} to verify the final status.

You can optionally pre-select a bank by passing a bank_id. If omitted, the customer chooses from a list on a Wonderful-hosted page.

Important for mobile integrations

When redirecting a customer to the pay_link URL, the redirect must happen in the device's native browser — Safari or Chrome on iOS, Chrome on Android. If you are integrating the API within a mobile app, do not use in-app browser views or WebUI panels. The hand-off to the customer's mobile banking app will only work correctly when launched from the native browser. Some Samsung users have also reported issues triggering their banking app when using the default Samsung browser; where possible, direct those customers to Chrome instead.


Fetch supported banks

Before creating a payment, you may want to display a list of supported banks so the customer can choose.

Request

GET /v2/supported-banks

Response

{
    "data": [
        {
            "bank_id": "natwest",
            "bank_name": "NatWest",
            "status": "available"
        },
        {
            "bank_id": "barclays",
            "bank_name": "Barclays",
            "status": "available"
        }
    ]
}

Example

curl --request GET \
    --get "https://api.wonderful.one/v2/supported-banks" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL("https://api.wonderful.one/v2/supported-banks");

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, { method: "GET", headers })
    .then(response => response.json())
    .then(data => console.log(data.data));
$client = new \GuzzleHttp\Client();
$url = 'https://api.wonderful.one/v2/supported-banks';
$response = $client->get($url, [
    'headers' => [
        'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
        'Content-Type' => 'application/json',
        'Accept' => 'application/json',
    ],
]);
$body = json_decode((string) $response->getBody());
print_r($body->data);

Create a Quick Pay payment

Request

POST /v2/quick-pay
Content-Type: application/json

Body parameters

Parameter Type Required Description
amountintegeryesAmount in GB pence (e.g. 1000 = £10.00). Minimum 5.
merchant_payment_referencestringyesShown on the customer's bank statement. Max 18 characters, A-Z, 0-9, -.
payment_descriptionstringnoDescription for the order line.
customer_email_addressstringnoEmail address. When provided, the order is linked to (or creates) a customer record.
redirect_urlstringnoURL to return the customer to after payment.
webhook_urlstringnoURL to receive POST notifications for payment status changes.
bank_idstringnoPre-select a specific bank (e.g. natwest).
skip_confirmationbooleannoSet to true to skip the Wonderful-hosted confirmation page.
send_to_tapstringnoA Tap device ID to push the payment to a Tap terminal.

Response

{
    "data": {
        "id": "ed6d3016",
        "order_id": "ed6d3016",
        "amount": 1000,
        "amount_formatted": "£10.00",
        "status": "created",
        "reference": "ORDER-1234",
        "pay_link": "https://api.wonderful.one/pay/AB12",
        "created_at": "2024-03-05T11:50:43.000000Z",
        "updated_at": "2024-03-05T11:50:43.000000Z"
    }
}

Example

curl --request POST \
    "https://api.wonderful.one/v2/quick-pay" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data '{
        "amount": 1000,
        "merchant_payment_reference": "ORDER-1234",
        "payment_description": "Website Order #1234",
        "customer_email_address": "[email protected]",
        "redirect_url": "https://mysite.com/success",
        "webhook_url": "https://mysite.com/webhooks",
        "bank_id": "natwest"
    }'
const url = new URL("https://api.wonderful.one/v2/quick-pay");

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

const body = {
    amount: 1000,
    merchant_payment_reference: "ORDER-1234",
    payment_description: "Website Order #1234",
    customer_email_address: "[email protected]",
    redirect_url: "https://mysite.com/success",
    webhook_url: "https://mysite.com/webhooks",
    bank_id: "natwest",
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
})
    .then(response => response.json())
    .then(data => {
        // Redirect the customer to data.data.pay_link
        window.location.href = data.data.pay_link;
    });
$client = new \GuzzleHttp\Client();
$url = 'https://api.wonderful.one/v2/quick-pay';
$response = $client->post($url, [
    'headers' => [
        'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
        'Content-Type' => 'application/json',
        'Accept' => 'application/json',
    ],
    'json' => [
        'amount' => 1000,
        'merchant_payment_reference' => 'ORDER-1234',
        'payment_description' => 'Website Order #1234',
        'customer_email_address' => '[email protected]',
        'redirect_url' => 'https://mysite.com/success',
        'webhook_url' => 'https://mysite.com/webhooks',
        'bank_id' => 'natwest',
    ],
]);
$body = json_decode((string) $response->getBody());
$payLink = $body->data->pay_link;
// Redirect the customer to $payLink

Verify payment status

After the customer is redirected back to your redirect_url, inspect the wonderful-payment-id query parameter and call the API to get the authoritative payment status.

Request

GET /v2/payments/{id}

Response

{
    "data": {
        "id": "ed6d3016",
        "order_id": "ed6d3016",
        "amount": 1000,
        "amount_formatted": "£10.00",
        "status": "completed",
        "reference": "ORDER-1234",
        "pay_link": "https://api.wonderful.one/pay/AB12",
        "created_at": "2024-03-05T11:50:43.000000Z",
        "updated_at": "2024-03-05T11:55:00.000000Z"
    }
}

Possible status values: created, pending, paid, failed, cancelled, expired, errored.

Example

curl --request GET \
    --get "https://api.wonderful.one/v2/payments/ed6d3016" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const paymentId = new URLSearchParams(window.location.search)
    .get("wonderful-payment-id");

fetch(`https://api.wonderful.one/v2/payments/${paymentId}`, {
    headers: {
        "Authorization": "Bearer {YOUR_AUTH_KEY}",
        "Content-Type": "application/json",
        "Accept": "application/json",
    },
})
    .then(response => response.json())
    .then(data => {
        if (data.data.status === "completed") {
            // Show success page
        }
    });
$client = new \GuzzleHttp\Client();
$paymentId = $_GET['wonderful-payment-id'];
$url = "https://api.wonderful.one/v2/payments/{$paymentId}";
$response = $client->get($url, [
    'headers' => [
        'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
        'Content-Type' => 'application/json',
        'Accept' => 'application/json',
    ],
]);
$body = json_decode((string) $response->getBody());
$status = $body->data->status;

if ($status === 'completed') {
    // Process the order
}

Error handling

The API returns standard HTTP status codes and a consistent error payload:

{
    "error": true,
    "message": "Validation failed",
    "invalid_fields": {
        "amount": ["The amount must be at least 5."]
    }
}
Status Meaning
201Created successfully
400Validation error
401Invalid or missing API token
404Resource not found

Next steps