Building an advanced Kayana integration with Stripe in React/Next.js
Last updated Mar 4, 2026
Build an advanced Kayana integration to securely collect card payments using Kayana’s Payment API, powered by Stripe, for your e-commerce store.
Overview
The Kayana Payment API enables you to accept payments without building your own PCI-compliant checkout.
This guide walks you through integrating the Stripe Checkout (Embedded) flow in sandbox mode.
What you’ll build:
- Create a payment instance on your server
- Retrieve the Stripe publishable key
- Initialise Stripe on the frontend
- Render Stripe’s secure Checkout capsule
- Complete the payment securely
Before you begin
You’ll need:
- A Kayana property ID
- Access to the sandbox environment
- Basic knowledge of server-side development
- Node.js / Next.js (examples provided)
Sandbox vs Production
Sandbox
- Safe test environment
- Uses test Stripe keys
- No real transactions
Production
- Requires an authorisation token
- Uses live Stripe keys
- Processes real payments
How it works
The Stripe payment flow consists of:
- Server-side – Create a payment instance
- Server-side – Receive:
- client_secret (cs_test_…)
- publishable_key
- Client-side – Initialise Stripe and render Embedded Checkout
- Stripe – Handles payment confirmation securely
Set up the server
Base URL
Sandbox:
https://integration.dev.kayana.co.uk
Production:
https://integration.kayana.co.uk
Step 1: Create a Payment
Create a payment instance by calling:
POST /web/payment
Headers
| Header | Value | Required |
| Content-Type | application/json | Yes |
| x-api-key | YOUR_API_KEY | Yes |
| type | business | 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. Format: Prop_* | YES |
| psp_code | string | Payment service provider code. Value: STRIPE | YES |
| currency_code | string | ISO currency code. Supported values include GBP, EUR, USD | YES |
| amount | number | Payment amount in decimal format (e.g., 12.0) | YES |
| customer_email | string | Customer email address used for the payment session | YES |
| payment_mode | string | Payment method used for the transaction. Value: CARD | YES |
| Field | Type | Description | Required |
|---|---|---|---|
| userAgent | string | Browser user agent | NO |
| acceptHeader | string | Accept header | NO |
| language | string | Browser language | NO |
| colorDepth | number | Screen color depth | NO |
| screenHeight | number | Screen height | NO |
| screenWidth | number | Screen width | NO |
| timeZoneOffset | number | Timezone offset | NO |
| Field | Type | Description | Required |
|---|---|---|---|
| street | string | Street address | NO |
| city | string | City | NO |
| postalCode | string | Postal code | NO |
| country | string | Country code | NO |
| state | string | State or region | NO |
EXAMPLE REQUEST
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: "STRIPE", 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();
EXAMPLE RESPONSE
const data = await response.json();
{
“status”: true,
“data”: {
“instance_id”: “Payment_xyz789example”,
“client_secret”: “cs_test_abc123_secret_xyz456”,
“publishable_key”: “pk_test_abc123example”,
“next_step”: {
“action”: “FORM”,
“proceed”: true
},
“transaction_id”: “Tx_txn456example”
}
}
Response Parameters
| Parameter | Description |
| instance_id | Unique payment instance ID |
| client_secret | Stripe Checkout session secret |
| publishable_key | Stripe public key |
| transaction_id | Internal transaction reference |
Important: client_secret must only be used on the frontend to initialise Stripe.
Step 2: Complete Payment on Frontend (Stripe Embedded Checkout)
Since the API returns:
cs_test_…
This means the Stripe Checkout Session is created.
You must use Stripe Embedded Checkout, not confirmCardPayment.
Install Stripe SDK
npm install @stripe/react-stripe-js @stripe/stripe-js
Frontend Implementation (Next.js Example)
“use client”;
import { useState } from “react”;
import { loadStripe } from “@stripe/stripe-js”;
import {
EmbeddedCheckoutProvider,
EmbeddedCheckout,
} from “@stripe/react-stripe-js”;
export default function Home() {
const [clientSecret, setClientSecret] = useState(null);
const [stripePromise, setStripePromise] = useState(null);
const createPayment = async () => {
const res = await fetch(“/api/business-payment”, {
method: “POST”,
});
const data = await res.json();
setStripePromise(loadStripe(data.data.publishable_key));
setClientSecret(data.data.client_secret);
};
if (clientSecret && stripePromise) {
return (
<EmbeddedCheckoutProvider
stripe={stripePromise}
options={{ clientSecret }}
>
<EmbeddedCheckout />
</EmbeddedCheckoutProvider>
);
}
return (
<>
<h1>Stripe Payment Testing Page</h1>
<button onClick={createPayment}>Open Payment Capsule</button>
</>
);
}
Testing in Sandbox
Use Stripe test cards:
| Card Number | Brand | Scenario |
| 4242 4242 4242 4242 | Visa | Successful |
| 4000 0025 0000 3155 | Visa | Requires 3D Secure |
| 4000 0000 0000 9995 | Visa | Declined |
Additional Details:
- Expiry: Any future date
- CVC: Any 3 digits
- ZIP: Any valid format
Warning: Never use test cards in production.
Error Handling
All responses include:
{
“status”: false,
“message”: “Description of error”
}
Common Errors
| Error | Cause | Solution |
| Invalid API key | Incorrect x-api-key | Verify with Kayana |
| Invalid property ID | Wrong format | Must start with Prop_* |
| Unsupported currency | Not enabled | Contact Kayana |
| Stripe configuration missing | PSP not enabled | Contact Kayana |
Going Live Checklist
Before production:
- Get production x-api-key
- Switch to production base URL
- Use live Stripe publishable key
- Test real card transactions
- Implement webhooks for payment confirmation
Never:
- Use sandbox keys in production
- Expose secret keys in frontend
Support
Need help?
- Technical issues: Contact Kayana Technical Support
- Production credentials: Request from your Kayana account manager
- PSP configuration: Reach out to Kayana Technical Support
Next steps
- Explore webhook integration for payment notifications
- Learn about refunds and dispute handling
- Set up recurring payments for subscriptions
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 Building an advanced Kayana integration with RYFT in React/Next.js.



