Skip to content
Kayana for Business

Building an Advanced Kayana Integration with RYFT in Node.js

Last updated Mar 13, 2026

This guide shows how to integrate Kayana Payments powered by RYFT using a Node.js backend and a frontend (React / Next.js / HTML). Payment flow: 1️⃣ Backend creates a payment session 2️⃣ Backend retrieves RYFT public key 3️⃣ Frontend loads RYFT SDK 4️⃣ Frontend initialises payment 5️⃣ Customer completes payment

1. Install Dependencies

npm init -y

npm install express cors node-fetch dotenv

2. Project Structure

project

│

├── server.js

├── .env

└── routes

└── payment.js

3. Environment Variables

Create .env

PORT=5000

API_KEY=YOUR_API_KEY

PROPERTY_ID=Prop_039f025cdbc74ca9957dbec1b3e193c1

BASE_URL=https://integration.dev.kayana.co.uk

4. Express Server Setup

server.js

const express = require(“express”);

const cors = require(“cors”);

require(“dotenv”).config();

const paymentRoutes = require(“./routes/payment”);

const app = express();

app.use(cors());

app.use(express.json());

app.use(“/api/payment”, paymentRoutes);

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => {

console.log(`Server running on port ${PORT}`);

});

5. Create Payment Routes

routes/payment.js

const express = require(“express”);

const fetch = require(“node-fetch”);

const router = express.Router();

const BASE_URL = process.env.BASE_URL;

const API_KEY = process.env.API_KEY;

const PROPERTY_ID = process.env.PROPERTY_ID;

//

// Create Payment Session

//

router.post(“/create-payment”, async (req, res) => {

try {

const response = await fetch(`${BASE_URL}/web/payment`, {

method: “POST”,

headers: {

“Content-Type”: “application/json”,

“x-api-key”: API_KEY,

type: “business”,

},

body: JSON.stringify({

property_id: PROPERTY_ID,

psp_code: “RYFT”,

currency_code: “GBP”,

amount: 100.5,

customer_email: “customer@example.com”,

payment_mode: “CARD”,

}),

});

const data = await response.json();

res.status(response.status).json(data);

} catch (error) {

res.status(500).json({

error: “Payment session creation failed”,

details: error.message,

});

}

});

//

// Get RYFT Public Key

//

router.get(“/public-key”, async (req, res) => {

try {

const response = await fetch(`${BASE_URL}/web/payment/public-key`, {

method: “GET”,

headers: {

“x-api-key”: API_KEY,

“x-psp-code”: “RYFT”,

“x-currency-code”: “GBP”,

type: “business”,

},

});

const data = await response.json();

res.json(data);

} catch (error) {

res.status(500).json({

error: “Failed to fetch public key”,

details: error.message,

});

}

});

module.exports = router;

6. Frontend Integration

Load the RYFT SDK

<script src=”https://embedded.ryftpay.com/v2/ryft.min.js”></script>

7. Initialise Payment on Frontend

async function initPayment() {

// Get public key

const keyRes = await fetch(“/api/payment/public-key”);

const keyData = await keyRes.json();

const publicKey = keyData.data.public_key;

// Create payment session

const paymentRes = await fetch(“/api/payment/create-payment”, {

method: “POST”,

});

const paymentData = await paymentRes.json();

const clientSecret = paymentData.data.client_secret;

// Initialize RYFT

window.Ryft.init({

publicKey,

clientSecret,

});

}

8. Complete Payment

async function payNow() {

const paymentSession = await window.Ryft.attemptPayment();

if (

paymentSession.status === “Approved” ||

paymentSession.status === “Captured”

) {

alert(“Payment Successful”);

} else {

alert(“Payment Failed”);

}

}

9. Test Cards

9. Test Cards
CardResult
4242 4242 4242 4242Success
4000 0025 0000 31553D Secure
4000 0000 0000 9995Declined

Use:

  • Any future expiry
  • Any CVC

10. Production Checklist

Before going live:

Switch base URL

https://integration.kayana.co.uk

Use production API key Enable RYFT PSP in Kayana Add payment webhooks

Additional endpoints for orders

Suggested flow:

Create Order → Authorise Payment ↓ ├── Capture → Success ├── Cancel → Void payment └── Refund → After capture

Authentication

All API requests must include the following headers:

Authentication
HeaderTypeRequiredDescription
x-api-keyStringYesYour API key
typeStringYesMust be set to business
Content-TypeStringYesMust be application/json
x-property-idStringYesproperty id

1. Capture Authorised Payment

Endpoint

POST /web/payment/capture-authorised-payment

Request Parameters

Request Parameters
FieldTypeRequiredDescription
order_idStringYesOrder ID
amountNumberYesAmount to capture

cURL Example

curl --location 'https://integration.dev.kayana.co.uk/web/payment/capture-authorised-payment' \

--header 'Content-Type: application/json' \

--header 'type: business' \

--header 'x-api-key: <YOUR_API_KEY>' \

--data '{

"order_id": "Order_xxx",

"amount": 5

}'

Sample Response

{

"status": "success",

"message": "Payment captured successfully",

"data": {

"order_id": "Order_xxx",

"captured_amount": 5

}

}

2. Cancel Authorised Payment

Endpoint

POST /web/payment/cancel-authorised-payment

Request Parameters

Request Parameters
FieldTypeRequiredDescription
order_idStringYesOrder ID

cURL Example

curl --location 'https://integration.dev.kayana.co.uk/web/payment/cancel-authorised-payment?order_id=Order_xxx' \

--header 'Content-Type: application/json' \

--header 'type: business' \

--header 'x-api-key: <YOUR_API_KEY>'

Sample Response

{

"status": "success",

"message": "Payment cancelled successfully"

}

3. Refund Payment

Endpoint

POST /web/payment/refund

Request Parameters

Request Parameters
FieldTypeRequiredDescription
order_idStringYesOrder ID
amountNumberYesRefund amount

cURL Example

curl --location --request POST 'https://integration.dev.kayana.co.uk/web/payment/refund?order_id=Order_xxx&amount=0.4' \

--header 'Content-Type: application/json' \

--header 'type: business' \

--header 'x-api-key: <YOUR_API_KEY>'

Sample Response

{

"status": "success",

"message": "Refund processed",

"data": {

"order_id": "Order_xxx",

"refunded_amount": 0.4

}

}

4. Fetch Order Details

Endpoint

GET /web/order/fetch-order-details-by-order-id

Request Parameters

Request Parameters
FieldTypeRequiredDescription
order_idStringYesOrder ID

cURL Example

curl --location 'https://integration.dev.kayana.co.uk/web/order/fetch-order-details-by-order-id?order_id=Order_xxx' \

--header 'type: business' \

--header 'x-api-key: <YOUR_API_KEY>'

Sample Response

{

"status": "success",

"data": {

"order_id": "Order_xxx",

"status": "captured",

"amount": 5

}

}

Security Best Practices

Never expose:

API keys client_secret payment session logs

Always:

Call the Kayana API from the backend Use environment variables Validate payment status server-side

If you want, I can also give you a much better production-ready version:

  • Full React + Node.js RYFT integration
  • Proper payment component UI
  • Webhook verification
  • Error handling
  • TypeScript version

Just tell me and I’ll share a complete real-world production implementation.

Next Steps

If you prefer to use RYFT as your Payment Service Provider (PSP), Kayana also supports a full RYFT integration flow. Refer to our guide on how to build an Advanced Kayana Integration with Stripe in Node.js

Still need a hand?Contact support← All help
Chat with us on WhatsApp