Building an advanced Kayana integration with RYFT in React/Next.js
Last updated Mar 9, 2026
Build a secure card payment integration using Kayana Payment API powered by RYFT in a Next.js application.
This guide explains how to:
- Create a payment session from your backend
- Retrieve the RYFT public key
- Initialise the RYFT SDK
- Render the payment form
- Complete the payment securely
Overview
The Kayana Payment API allows you to accept card payments without building your own PCI-compliant payment form.
The payment flow works like this:
1️⃣ Server creates a payment instance
2️⃣ Server retrieves the RYFT public key
3️⃣ Frontend loads RYFT SDK
4️⃣ Frontend initializes the payment session
5️⃣ Customer enters card details and completes payment
Before You Begin
You will need:
- Kayana Property ID
- API Key
- Access to Sandbox Environment
- Basic knowledge of Node.js / Next.js
Sandbox vs Production
Sandbox
Safe testing environment.
- Uses test payment data
- No real money transactions
- Base URL:
https://integration.dev.kayana.co.uk
Production
Live payment environment.
- Real transactions
- Requires production API key
- Base URL:
https://integration.kayana.co.uk
RYFT Payment Flow
Frontend loads
https://embedded.ryftpay.com/v2/ryft.min.js
Frontend initializes RYFT
Ryft.init()
User completes payment
Ryft.attemptPayment()
Set up the server
Base URL
Sandbox:
https://integration.dev.kayana.co.uk
Production:
https://integration.kayana.co.uk
Step 1 - Create Payment Instance (Server Side)
Create a payment session by calling:
POST /web/payment
| Header | Value | Required |
| Content-Type | application/json | YES |
| x-api-key | YOUR_API_KEY | YES |
| type | business | YES |
| x-property-id | String | Yes |
How to obtain your X API key
Follow these steps inside Partner Admin:
- Log in to Kayana Partner Admin.
- Navigate to Settings (left-hand sidebar).
- Select API Key Management.
- Click Create API Key.
- Copy the generated key immediately and send it in the header.
Request Parameters
| Parameter | Type | Description | Required |
| property_id | string | Kayana property identifier (Prop_*) | YES |
| psp_code | string | Payment provider (RYFT) | YES |
| pre_authorise | boolean | Indicates whether the payment should be pre-authorised instead of captured immediately | NOT MANDATORY |
| currency_code | string | Currency code (GBP, USD, EUR) | YES |
| amount | number | Payment amount | YES |
| customer_email | string | Customer email | YES |
| payment_mode | string | Payment method (CARD) | YES |
| x-property-id | String | property ID | Yes |
Optional Browser Information
| Field | Type[p | Description |
| userAgent | string | Browser user agent |
| acceptHeader | string | Accept header |
| language | string | Browser language |
| colorDepth | number | Screen color depth |
| screenHeight | number | Screen height |
| screenWidth | number | Screen width |
| timeZoneOffset | number | Timezone offset |
Optional Billing Address
| Field | Type |
| street | string |
| city | string |
| postalCode | string |
| country | string |
| state | string |
Example Server Implementation (Next.js API Route)
export async function POST() {
try {
const response = await fetch(
"https://integration.dev.kayana.co.uk/web/payment",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": "YOUR_API_KEY",
type: "business",
},
body: JSON.stringify({
property_id: "Prop_039f025cdbc74ca9957dbec1b3e193c1",
psp_code: "RYFT",
currency_code: "GBP",
amount: 100.5,
customer_email: "customer@example.com",
payment_mode: "CARD",
browser_info: {
userAgent: "Mozilla/5.0",
acceptHeader: "*/*",
language: "en-US",
colorDepth: 24,
screenHeight: 1080,
screenWidth: 1920,
timeZoneOffset: 0
},
billing_address: {
street: "221B Baker Street",
city: "London",
postalCode: "NW1 6XE",
country: "GB",
state: "Greater London"
}
}),
}
);
const data = await response.json();
return Response.json(data, { status: response.status });
} catch (error) {
return Response.json(
{ error: "Payment failed", details: error.message },
{ status: 500 }
);
}
}
Example API Response
{
"message": "Payment session created successfully",
"status": true,
"data": {
"client_secret": "ps_01KK…MKXJ8NRBCR…",
"next_step": {
"action": "FORM",
"proceed": true
},
"transaction_id": "Tx_9052db2d798f4…..ab8e032",
"order_id": "Order_5ab37f6….0efc5b0a"
}
}
⚠️ Important
client_secret must only be used on the frontend.
Never expose secret API keys to the browser.
Step 2 — Get RYFT Public Key
Your backend should call:
GET /web/payment/public-key
x-api-key
x-psp-code
x-currency-code
type
Example
export async function GET() {
const response = await fetch(
"https://integration.dev.kayana.co.uk/web/payment/public-key",
{
method: "GET",
headers: {
"x-api-key": "YOUR_API_KEY",
"x-psp-code": "RYFT",
"x-currency-code": "GBP",
"type": "business",
},
}
);
const data = await response.json();
return Response.json(data);
}
EXAMPLE RESPONSE
{
"status": true,
"data": {
"public_key": "pk_sandbox_TlD……d+iMtqu/pmWyGvThg…."
}
}
Step 3 - Load RYFT SDK (Frontend)
Add the RYFT SDK to your page.
https://embedded.ryftpay.com/v2/ryft.min.js
Example using Next.js:
<Script
src="https://embedded.ryftpay.com/v2/ryft.min.js"
strategy="afterInteractive"
/>
Step 4 - Initialise RYFT
After fetching:
- publicKey
- clientSecret
Initialise the SDK.
window.Ryft.init({
publicKey,
clientSecret
});
Step 5 - Attempt Payment
Trigger payment from the form.
const paymentSession = await window.Ryft.attemptPayment();
Example:
if (
paymentSession.status === "Approved" ||
paymentSession.status === "Captured"
) {
alert("Payment Successful");
}
Testing Payments
Use RYFT test cards in the sandbox.
Example:
| Card | Scenario |
| 4242 4242 4242 4242 | Successful |
| 4000 0025 0000 3155 | 3D Secure |
| 4000 0000 0000 9995 | Declined |
Use:
- Any future expiry
- Any CVC
⚠️ Never use test cards in production
Common Errors
| Error | Cause | Fix |
| Invalid API Key | Wrong x-api-key | Verify key |
| Invalid Property ID | Wrong format | Must start with Prop_ |
| Unsupported currency | Currency not enabled | Contact Kayana |
| PSP not enabled | RYFT not configured | Contact Kayana |
Going Live Checklist
Before moving to production:
✔ Get production API key
✔ Switch to production base URL
✔ Verify RYFT configuration
✔ Test real card transactions
✔ Implement payment confirmation webhooks
Security Best Practices
Never:
❌ Expose API keys on frontend
❌ Use sandbox keys in production
❌ Log client_secret publicly
Always:
✔ Process payments via server API routes
Next Steps
If you prefer to use Stripe as your Payment Service Provider (PSP), Kayana also supports a full Stripe integration flow. Refer to our guide on Building an advanced Kayana integration with Stripe in React/Next.js.



