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:
- Een betaalinstantie maken op je PHP server
- De Stripe publishable key ophalen
- Stripe initialiseren op de frontend
- Stripe's veilige Embedded Checkout capsule weergeven
- 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:
| Component | Beschrijving |
|---|---|
| Server-side (PHP) | Een betalingsinstantie maken met behulp van Kayana's API |
| Server ontvangt | client_secret en publishable_key |
| Client-side | Stripe initialiseren en Embedded Checkout renderen |
| Stripe | Verwerkt betalingsbevestiging veilig |
6. Serverinstallatie (PHP)
Basis-URL
| Omgeving | URL |
|---|---|
| Sandbox | https://integration.dev.kayana.co.uk |
| Productie | https://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
| Parameter | Type | Beschrijving |
|---|---|---|
| property_id | string | Indeling Prop_* |
| psp_code | string | STRIPE |
| currency_code | string | GBP, EUR, USD |
| amount | number | Decimaalbedrag (voorbeeld: 12.0) |
| customer_email | string | E-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
| Parameter | Beschrijving |
|---|---|
| instance_id | Unieke betalingsinstantie-ID |
| client_secret | Stripe Checkout-sessiesecret |
| publishable_key | Stripe openbare sleutel |
| transaction_id | Interne 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:
| Kaartnummer | Merk | Scenario |
|---|---|---|
| 4242 4242 4242 4242 | Visa | Succesvol |
| 4000 0025 0000 3155 | Visa | Vereist 3D Secure |
| 4000 0000 0000 9995 | Visa | Geweigerd |
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
| Fout | Oorzaak | Oplossing |
|---|---|---|
| Ongeldige API-sleutel | Onjuiste x-api-key | Verificatie met Kayana |
| Ongeldige eigenschap-ID | Verkeerde indeling | Moet beginnen met Prop_* |
| Niet-ondersteunde valuta | Niet ingeschakeld | Contact Kayana |
| Stripe-configuratie ontbreekt | PSP niet ingeschakeld | Contact 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
- API-sleutels veilig opslaan - Gebruik omgevingsvariabelen of veilige configuratiebestanden
- Alle invoer valideren - Desinfecteer en valideer gebruikersinvoer op de server
- Gebruik HTTPS - Serveer uw betalingspagina's altijd via HTTPS
- CSRF-bescherming implementeren - Voeg CSRF-tokens toe aan uw formulieren
- 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.
