Skip to content
Kayana for Business

Een geavanceerde Kayana-integratie met Stripe in PHP bouwen

Last updated Mar 17, 2026

Bouw een geavanceerde Kayana-integratie om veilig kaartbetalingen te verzamelen met behulp van Kayana's Payment API aangedreven door Stripe voor uw e-commerce winkel.

1. Overzicht

De Kayana Payment API stelt u in staat om betalingen te accepteren zonder uw eigen PCI-conforme checkout te bouwen.

Deze gids begeleidt u door de integratie van de Stripe Embedded Checkout flow met behulp van PHP in sandboxmodus.

2. Wat je gaat bouwen

In deze handleiding kun je het volgende doen:

  1. Een betaalinstantie maken op je PHP server
  2. De Stripe publishable key ophalen
  3. Stripe initialiseren op de frontend
  4. Stripe's veilige Embedded Checkout capsule weergeven
  5. De betaling veilig voltooien

3. Voordat u begint

U hebt het volgende nodig:

  • Een Kayana property ID
  • Toegang tot de sandbox environment
  • Basiskennis van PHP
  • Een PHP backend server (PHP 7.4+ aanbevolen)
  • Een frontend (HTML/JavaScript of elk ander framework)

4. Sandbox vs Productie

Sandbox

Veilige testomgeving:

  • Gebruikt Stripe testsleutels
  • Geen echte transacties
  • Ideaal voor ontwikkeling en testen

Productie

  • Vereist een autorisatietoken
  • Gebruikt live Stripe-sleutels
  • Verwerkt echte betalingen

5. Hoe het werkt

De Stripe-betalingsstroom bestaat uit:

5. Hoe het werkt
ComponentBeschrijving
Server-side (PHP)Een betalingsinstantie maken met behulp van Kayana's API
Server ontvangtclient_secret en publishable_key
Client-sideStripe initialiseren en Embedded Checkout renderen
StripeVerwerkt betalingsbevestiging veilig

6. Serverinstallatie (PHP)

Basis-URL

Basis-URL
OmgevingURL
Sandboxhttps://integration.dev.kayana.co.uk
Productiehttps://integration.kayana.co.uk

Projectstructuur

your-project/ ├── config/ │ └── config.php ├── api/ │ └── create-payment.php ├── public/ │ └── index.html └── .htaccess

7. Stap 1 — Een betaling maken (PHP Backend)

Maak een PHP API-eindpunt dat de betalings-API van Kayana aanroept.

Configuratiebestand

config/config.php

<?php

return [ 'kayana' => [ 'api_key' => 'YOUR_API_KEY', 'base_url' => 'https://integration.dev.kayana.co.uk', 'property_id' => 'Prop_abc123example', ], 'stripe' => [ 'psp_code' => 'STRIPE', ], ];

⚠️ Belangrijk: Geef uw API-sleutel nooit bloot aan de frontend en commit deze niet aan versiebeheer.

PHP Server-implementatie

api/create-payment.php

<?php

header('Content-Type: application/json'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type');

// Handle preflight requests if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit(); }

// Only allow POST requests if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode([ 'status' => false, 'message' => 'Method not allowed' ]); exit(); }

// Load configuration $config = require_once __DIR__ . '/../config/config.php';

// Get request body $input = json_decode(file_get_contents('php://input'), true);

// Set default values or use provided values $amount = $input['amount'] ?? 12.00; $currency = $input['currency_code'] ?? 'GBP'; $customerEmail = $input['customer_email'] ?? 'customer@example.com';

// Prepare request payload $payload = [ 'property_id' => $config['kayana']['property_id'], 'psp_code' => $config['stripe']['psp_code'], 'currency_code' => $currency, 'amount' => $amount, 'customer_email' => $customerEmail, ];

// Initialize cURL $ch = curl_init();

curl_setopt_array($ch, [ CURLOPT_URL => $config['kayana']['base_url'] . '/business/payment', CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'x-api-key: ' . $config['kayana']['api_key'], 'type: business', ], CURLOPT_TIMEOUT => 30, CURLOPT_SSL_VERIFYPEER => true, ]);

$response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch);

curl_close($ch);

// Handle cURL errors if ($curlError) { http_response_code(500); echo json_encode([ 'status' => false, 'message' => 'Connection error: ' . $curlError ]); exit(); }

// Handle HTTP errors if ($httpCode !== 200) { http_response_code($httpCode); echo json_encode([ 'status' => false, 'message' => 'Payment creation failed', 'http_code' => $httpCode ]); exit(); }

// Return the response echo $response;

Alternatief: Guzzle HTTP Client gebruiken

Als u liever Composer en Guzzle gebruikt:

Guzzle installeren:

composer require guzzlehttp/guzzle

api/create-payment-guzzle.php

<?php

require_once __DIR__ . '/../vendor/autoload.php';

use GuzzleHttp\Client; use GuzzleHttp\Exception\RequestException;

header('Content-Type: application/json'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit(); }

if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode([ 'status' => false, 'message' => 'Method not allowed' ]); exit(); }

$config = require_once __DIR__ . '/../config/config.php'; $input = json_decode(file_get_contents('php://input'), true);

$client = new Client([ 'base_uri' => $config['kayana']['base_url'], 'timeout' => 30, ]);

try { $response = $client->post('/business/payment', [ 'headers' => [ 'Content-Type' => 'application/json', 'x-api-key' => $config['kayana']['api_key'], 'type' => 'business', ], 'json' => [ 'property_id' => $config['kayana']['property_id'], 'psp_code' => $config['stripe']['psp_code'], 'currency_code' => $input['currency_code'] ?? 'GBP', 'amount' => $input['amount'] ?? 12.00, 'customer_email' => $input['customer_email'] ?? 'customer@example.com', ], ]);

echo $response->getBody()->getContents();

} catch (RequestException $e) { http_response_code(500); echo json_encode([ 'status' => false, 'message' => 'Payment creation failed: ' . $e->getMessage() ]); }

Aanvraagparameters

Aanvraagparameters
ParameterTypeBeschrijving
property_idstringIndeling Prop_*
psp_codestringSTRIPE
currency_codestringGBP, EUR, USD
amountnumberDecimaalbedrag (voorbeeld: 12.0)
customer_emailstringE-mailadres klant

Voorbeeld API-antwoord

{ "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" } }

Antwoordparameters

Antwoordparameters
ParameterBeschrijving
instance_idUnieke betalingsinstantie-ID
client_secretStripe Checkout-sessiesecret
publishable_keyStripe openbare sleutel
transaction_idInterne transactiereferentie

⚠️ Belangrijk: client_secret mag alleen op de frontend worden gebruikt om Stripe te initialiseren.

8. Stap 2 — Frontend-integratie (Stripe Embedded Checkout)

HTML/JavaScript-implementatie

public/index.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Kayana Stripe Payment</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> <style> body { min-height: 100vh; background: linear-gradient(135deg, #f3e8ff, #e9d5ff); } .checkout-card { max-width: 600px; border-radius: 16px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.08); } .pay-btn { background: linear-gradient(90deg, #ef4444, #f97316); border: none; height: 52px; font-size: 16px; font-weight: 600; border-radius: 10px; } .btn-spinner { width: 20px; height: 20px; border: 2px solid rgba(255, 255, 255, 0.4); border-top-color: #fff; border-radius: 50%; animation: spin 0.7s linear infinite; display: inline-block; vertical-align: middle; } @keyframes spin { to { transform: rotate(360deg); } } #checkout-container { min-height: 400px; } </style> </head> <body> <div class="container d-flex align-items-center justify-content-center py-5"> <div class="card checkout-card w-100"> <div class="card-body p-4"> <div class="text-center mb-4"> <h5 class="fw-bold mb-1">Stripe-betaling</h5> <p class="text-muted mb-0">Voltooi uw betaling veilig</p> </div>

<div id="payment-form-container"> <div class="mb-3"> <label class="form-label">E-mailadres</label> <input type="email" id="email" class="form-control" placeholder="customer@example.com" required> </div>

<div class="mb-3"> <label class="form-label">Bedrag</label> <input type="number" id="amount" class="form-control" value="12.00" step="0.01" min="0.50" required> </div>

<div class="mb-4"> <label class="form-label">Valuta</label> <select id="currency" class="form-select"> <option value="GBP">GBP - Britse pond</option> <option value="EUR">EUR - Euro</option> <option value="USD">USD - Amerikaanse dollar</option> </select> </div>

<button id="pay-btn" class="btn pay-btn text-white w-100"> <span class="btn-text">Betaling openen</span> </button>

<div id="error-message" class="alert alert-danger mt-3 d-none"></div> </div>

<div id="checkout-container"></div> </div> </div> </div>

<script src="https://js.stripe.com/clover/stripe.js"></script> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <script> let stripe = null;

function showLoader() { $('#pay-btn') .prop('disabled', true) .html('<span class="btn-spinner"></span> Verwerken...'); }

function hideLoader() { $('#pay-btn') .prop('disabled', false) .html('<span class="btn-text">Betaling openen</span>'); }

function showError(message) { $('#error-message').text(message).removeClass('d-none'); }

function hideError() { $('#error-message').addClass('d-none'); }

$('#pay-btn').on('click', async function() { hideError(); showLoader();

const email = $('#email').val(); const amount = parseFloat($('#amount').val()); const currency = $('#currency').val();

if (!email || !amount) { showError('Vul alstublieft alle vereiste velden in.'); hideLoader(); return; }

try { const response = await fetch('/api/create-payment.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ customer_email: email, amount: amount, currency_code: currency, }), });

const data = await response.json();

if (data.status && data.data) { stripe = Stripe(data.data.publishable_key); $('#payment-form-container').addClass('d-none');

const checkout = await stripe.initEmbeddedCheckout({ clientSecret: data.data.client_secret, });

checkout.mount('#checkout-container'); } else { showError(data.message || 'Betaalsessie kon niet worden gemaakt.'); hideLoader(); } } catch (error) { console.error('Error:', error); showError('Er is een onverwachte fout opgetreden. Probeer alstublieft opnieuw.'); hideLoader(); } }); </script> </body> </html>

9. Betalingsstroom

Gebruiker klikt op "Betalen" ↓ Frontend roept de PHP API aan ↓ PHP roept Kayana API aan ↓ Kayana maakt Stripe Checkout-sessie aan ↓ Geeft als resultaat: client_secret publishable_key ↓ Frontend laadt Stripe ↓ Stripe Embedded Checkout verschijnt ↓ Gebruiker voert kaartgegevens in ↓ Stripe bevestigt betaling

10. Testen in Sandbox

Gebruik Stripe testkaarten:

10. Testen in Sandbox
KaartnummerMerkScenario
4242 4242 4242 4242VisaSuccesvol
4000 0025 0000 3155VisaVereist 3D Secure
4000 0000 0000 9995VisaGeweigerd

Aanvullende Details:

  • Vervaldatum → Elke toekomstige datum
  • CVC → Willekeurige 3 cijfers
  • ZIP → Elk geldig formaat

⚠️ Waarschuwing: Gebruik testkaarten nooit in productie.

11. Foutafhandeling

Alle reacties bevatten:

{ "status": false, "message": "Description of error" }

Veelvoorkomende fouten

Veelvoorkomende fouten
FoutOorzaakOplossing
Ongeldige API-sleutelOnjuiste x-api-keyVerificatie met Kayana
Ongeldige eigenschap-IDVerkeerde indelingMoet beginnen met Prop_*
Niet-ondersteunde valutaNiet ingeschakeldContact Kayana
Stripe-configuratie ontbreektPSP niet ingeschakeldContact Kayana

12. Webhook Handler (Optioneel)

api/webhook.php

<?php

$config = require_once __DIR__ . '/../config/config.php';

$payload = file_get_contents('php://input'); $sigHeader = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? ''; $endpointSecret = $config['stripe']['webhook_secret'] ?? '';

try { $event = json_decode($payload, true);

switch ($event['type']) { case 'checkout.session.completed': $session = $event['data']['object']; // Handle successful payment // Update order status in database error_log('Payment completed: ' . $session['id']); break;

case 'payment_intent.succeeded': $paymentIntent = $event['data']['object']; error_log('PaymentIntent succeeded: ' . $paymentIntent['id']); break;

case 'payment_intent.payment_failed': $paymentIntent = $event['data']['object']; error_log('PaymentIntent failed: ' . $paymentIntent['id']); break;

default: error_log('Unhandled event type: ' . $event['type']); }

http_response_code(200); echo json_encode(['received' => true]);

} catch (Exception $e) { http_response_code(400); echo json_encode(['error' => $e->getMessage()]); }

13. Going Live Checklist

Voor productie:

Verkrijg production x-api-key

Schakel over naar production base URL

Gebruik live Stripe publishable key

Test echte kaartransacties

Implementeer Stripe webhooks

Stel correct foutlogboek in

Schakel HTTPS in op uw server

Nooit:

  • Sandbox sleutels in productie gebruiken
  • Geheime sleutels in de frontend blootstellen
  • Gevoelige betalingsgegevens registreren

14. Beveiligingsbest practices

  1. API-sleutels veilig opslaan - Gebruik omgevingsvariabelen of veilige configuratiebestanden
  2. Alle invoer valideren - Desinfecteer en valideer gebruikersinvoer op de server
  3. Gebruik HTTPS - Serveer uw betalingspagina's altijd via HTTPS
  4. CSRF-bescherming implementeren - Voeg CSRF-tokens toe aan uw formulieren
  5. Snelheidsbeperking - Implementeer snelheidsbeperking op uw API-eindpunten

15. Ondersteuning

  • Technische ondersteuning: Kayana Technical Team
  • Productiereferenties: Neem contact op met de accountmanager van Kayana
  • Documentatie: Kayana Help Centre

Volgende stappen

Als u liever RYFT als uw Payment Service Provider (PSP) gebruikt, ondersteunt Kayana ook een volledige RYFT-integratieflow. Raadpleeg onze handleiding over Building an advanced Kayana integration in PHP.

Still need a hand?Contact support← All help
Chat met ons via WhatsApp