Hosted Payment Page (HPP)
The Hosted Payment Page lets you accept payments without handling card details directly. You redirect the customer to a secure, Flowlix-hosted page where they enter their card information. After payment, the customer is sent back to your site.
Why use HPP?
- No PCI scope — Flowlix handles all card data on our servers.
- Less development effort — No need to build a card input form.
- Consistent UX — A professional, mobile-optimized payment page.
- Security — Card details never touch your servers.
How it works
- The customer clicks “Pay” on your site.
- Your server creates an HPP session via
POST /v1/payments/hpp.
- You redirect the customer to the
hpp_url from the response.
- The customer enters their card details on the Flowlix payment page.
- After payment, the customer is redirected to your
redirect_url with query parameters.
- Your server fetches the payment to verify the status.
Step 1: Create an HPP session
curl -X POST https://api.flowlix.eu/v1/payments/hpp \
-H "Authorization: Bearer fl_test_sk_abc123def456" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: hpp-order-5678" \
-d '{
"amount": 2500,
"currency": "eur",
"customer": {
"email": "alex@example.com",
"first_name": "Alex",
"last_name": "Johnson",
"country": "DE",
"phone": "+491709876543",
"address": "Friedrichstrasse 100",
"city": "Berlin",
"zip": "10117"
},
"redirect_url": "https://shop.example.com/checkout/complete"
}'
Request parameters
| Parameter | Required | Description |
|---|
amount | Yes | Amount in minor units (e.g., 2500 = EUR 25.00). |
currency | Yes | Three-letter ISO 4217 code (e.g., eur). |
customer.email | Yes | Customer email. |
customer.first_name | Yes | Customer first name. |
customer.last_name | Yes | Customer last name. |
customer.country | Yes | Country code (ISO 3166-1 alpha-2). |
customer.phone | Yes | Phone in international format. |
customer.address | Yes | Street address. |
customer.city | Yes | City. |
customer.zip | Yes | Postal code. |
redirect_url | Yes | Where to send the customer after payment. |
Response
{
"id": "pay_1N4gLy3fAvLZmn3D1YkNs9qW",
"object": "payment",
"amount": 2500,
"currency": "eur",
"status": "pending",
"description": null,
"card": null,
"customer": {
"email": "alex@example.com",
"name": "Alex Johnson"
},
"metadata": {},
"decline_code": null,
"decline_message": null,
"redirect_url": "https://pay.flowlix.eu/hpp/pay_1N4gLy3fAvLZmn3D1YkNs9qW",
"refunded_at": null,
"succeeded_at": null,
"failed_at": null,
"created": 1719792000,
"livemode": false
}
Note that the payment starts with "status": "pending" and "card": null because the customer has not entered their card details yet.
Step 2: Redirect the customer
Redirect the customer to the hpp_url:
# Flask example
from flask import redirect
@app.route("/checkout/pay")
def pay():
# ... create HPP session ...
return redirect(payment["hpp_url"])
// Express example
app.get("/checkout/pay", async (req, res) => {
// ... create HPP session ...
res.redirect(payment.hpp_url);
});
Step 3: Handle the redirect back
After the customer completes (or abandons) the payment, Flowlix redirects them to your redirect_url with query parameters:
https://shop.example.com/checkout/complete?payment_id=pay_1N4gLy3fAvLZmn3D1YkNs9qW&status=succeeded
| Query parameter | Description |
|---|
payment_id | The payment ID. |
status | The payment status (succeeded, failed, or pending). |
Always verify the payment status server-side. Do not trust the query parameters alone — a
malicious user could modify them. Fetch the payment from the API to confirm the actual status.
Step 4: Verify the payment
Fetch the payment from your server to confirm the status:
curl https://api.flowlix.eu/v1/payments/pay_1N4gLy3fAvLZmn3D1YkNs9qW \
-H "Authorization: Bearer fl_test_sk_abc123def456"
{
"id": "pay_1N4gLy3fAvLZmn3D1YkNs9qW",
"object": "payment",
"amount": 2500,
"currency": "eur",
"status": "succeeded",
"card": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2027,
"country": "US"
},
"customer": {
"email": "alex@example.com",
"name": "Alex Johnson"
},
...
}
Full integration example
import requests
import uuid
from flask import Flask, redirect, request, jsonify
app = Flask(__name__)
FLOWLIX_API_KEY = "fl_test_sk_abc123def456"
@app.route("/checkout/pay", methods=["POST"])
def create_checkout():
"""Create HPP session and redirect customer."""
order = get_current_order() # Your order logic
response = requests.post(
"https://api.flowlix.eu/v1/payments/hpp",
headers={
"Authorization": f"Bearer {FLOWLIX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": f"hpp-{order.id}",
},
json={
"amount": order.total_in_cents,
"currency": "eur",
"customer": {
"email": order.customer_email,
"first_name": order.customer_first_name,
"last_name": order.customer_last_name,
"country": order.customer_country,
"phone": order.customer_phone,
"address": order.customer_address,
"city": order.customer_city,
"zip": order.customer_zip,
},
"redirect_url": f"https://shop.example.com/checkout/{order.id}/complete",
},
)
payment = response.json()
order.payment_id = payment["id"]
order.save()
return redirect(payment["hpp_url"])
@app.route("/checkout/<order_id>/complete")
def checkout_complete(order_id):
"""Handle redirect back from Flowlix HPP."""
order = get_order(order_id)
payment_id = request.args.get("payment_id")
# Always verify server-side
response = requests.get(
f"https://api.flowlix.eu/v1/payments/{payment_id}",
headers={"Authorization": f"Bearer {FLOWLIX_API_KEY}"},
)
payment = response.json()
if payment["status"] == "succeeded":
order.mark_paid()
return render_template("success.html", order=order)
else:
return render_template("failed.html", order=order)
Best practices
- Always verify payment status server-side after the redirect. Never rely on query parameters alone.
- Store the
payment_id in your database when you create the HPP session, so you can reconcile later.
- Use the
Idempotency-Key tied to your order ID to prevent creating duplicate payment sessions.
- Handle all statuses in your redirect handler:
succeeded, failed, and pending.
- Set a reasonable
redirect_url that your customer recognizes and trusts.