Embedded Integration — PHP
Build your own checkout in PHP — hash, direct sale, 3DS, capture, webhooks.
Embedded Integration lets you collect card data on your website and charge via DigetPay from your PHP backend. You build the checkout UI — including Apple Pay if needed (separate guide).
PCI DSS: Embedded Integration requires secure handling of card data (SAQ D or equivalent). Prefer Hosted Checkout unless compliance approves embedded card collection.
Never send card data from browser JavaScript directly to DigetPay. Post card fields to your server first, then your server calls the embedded sale APIs.
Prerequisites: Embedded Integration Overview, Sandbox Setup, staging
x-api-key, PHP 8.0+ with cURL.
Architecture
sequenceDiagram participant Browser as Customer Browser participant Shop as Your PHP Backend participant API as DigetPay API Browser->>Shop: POST checkout form (card fields) Shop->>Shop: Compute MD5 hash Shop->>API: POST /payment/s2s/sale API-->>Shop: status + html (3DS if needed) Shop->>Browser: Render 3DS or success page API->>Shop: Webhook notification
Step 1 — Configuration
Same pattern as hosted checkout — see Environments Overview:
<?php
$config = [
'environment' => getenv('DIGETPAY_ENV') ?: 'staging',
'api_key' => getenv('DIGETPAY_API_KEY') ?: '',
'environments' => [
'staging' => ['api_base' => 'https://fin-api.digetpay.com/v1'],
'production' => ['api_base' => 'https://api.digetpay.com/v1'],
],
];Step 2 — Hash helper
Required for every direct sale. Logic matches DigetPay backend — uppercase the concatenated string before MD5:
<?php
declare(strict_types=1);
function digetpayEmbeddedHash(string $email, string $cardNumber, string $apiKey): string
{
$card = preg_replace('/\s+/', '', $cardNumber);
$reversedEmail = strrev($email);
$reversedCard = strrev(substr($card, 0, 6) . substr($card, -4));
$raw = strtoupper($reversedEmail . $apiKey . $reversedCard);
return md5($raw);
}Full explanation: Request Hash (MD5).
Step 3 — Embedded client
<?php
declare(strict_types=1);
require_once __DIR__ . '/digetpay-hash.php';
final class DigetPayEmbeddedClient
{
private string $apiBase;
private string $apiKey;
public function __construct(array $config)
{
$env = $config['environment'] ?? 'staging';
$this->apiBase = rtrim($config['environments'][$env]['api_base'], '/');
$this->apiKey = $config['api_key'] ?? '';
}
/** @return array<string, mixed> */
public function directSale(array $order, array $card, array $customer, string $successUrl, string $failureUrl): array
{
$hash = digetpayEmbeddedHash($customer['email'], $card['cardNumber'], $this->apiKey);
$body = [
'orderId' => $order['orderId'],
'amount' => $order['amount'],
'currency' => $order['currency'] ?? 'SAR',
'paymentMethod' => 'card',
'auth' => $order['auth'] ?? 'N',
'card' => [
'cardNumber' => preg_replace('/\s+/', '', $card['cardNumber']),
'cardExpiryMonth' => $card['cardExpiryMonth'],
'cardExpiryYear' => $card['cardExpiryYear'],
'cardCvv' => $card['cardCvv'],
'cardHolder' => $card['cardHolder'],
],
'customer' => $customer,
'successUrl' => $successUrl,
'failureUrl' => $failureUrl,
'hash' => $hash,
];
return $this->request('POST', '/payment/s2s/sale', $body);
}
/** @return array<string, mixed> */
public function capture(string $transactionId, float $amount): array
{
return $this->request('POST', '/payment/s2s/capture', [
'transactionId' => $transactionId,
'amount' => $amount,
]);
}
/** @return array<string, mixed> */
public function voidTransaction(string $transactionId): array
{
return $this->request('POST', '/payment/s2s/void', [
'transactionId' => $transactionId,
]);
}
/** @return array<string, mixed> */
public function getStatus(string $transactionId): array
{
return $this->request('POST', '/payment/s2s/status/' . urlencode($transactionId));
}
/** @return array<string, mixed> */
private function request(string $method, string $path, ?array $body = null): array
{
$ch = curl_init($this->apiBase . $path);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-api-key: ' . $this->apiKey,
],
CURLOPT_TIMEOUT => 60,
]);
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body, JSON_THROW_ON_ERROR));
}
$raw = curl_exec($ch);
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($raw === false || $code >= 400) {
throw new RuntimeException("Embedded HTTP $code: $raw");
}
return json_decode($raw, true) ?: [];
}
}Step 4 — Checkout form (your site)
public/checkout-form.php — card fields post to your server:
<form method="post" action="/process-payment.php" autocomplete="off">
<input name="order_id" value="ORD-1001" type="hidden" />
<input name="amount" value="10.00" type="hidden" />
<label>Card number <input name="card_number" required /></label>
<label>Expiry MM <input name="exp_month" maxlength="2" required /></label>
<label>Expiry YY <input name="exp_year" maxlength="4" required /></label>
<label>CVV <input name="cvv" maxlength="4" required /></label>
<label>Name <input name="card_holder" required /></label>
<label>Email <input name="email" type="email" required /></label>
<label>Phone <input name="phone" required /></label>
<button type="submit">Pay</button>
</form>For Apple Pay, use a separate button and server flow — Apple Pay Embedded. See also Apple Pay Code (PHP).
Step 5 — Process payment
public/process-payment.php:
<?php
declare(strict_types=1);
require_once __DIR__ . '/../src/DigetPayEmbeddedClient.php';
$config = require __DIR__ . '/../config/digetpay.php';
$client = new DigetPayEmbeddedClient($config);
try {
$result = $client->directSale(
order: [
'orderId' => $_POST['order_id'],
'amount' => (float) $_POST['amount'],
'currency' => 'SAR',
'auth' => 'N',
],
card: [
'cardNumber' => $_POST['card_number'],
'cardExpiryMonth' => $_POST['exp_month'],
'cardExpiryYear' => $_POST['exp_year'],
'cardCvv' => $_POST['cvv'],
'cardHolder' => $_POST['card_holder'],
],
customer: [
'name' => $_POST['card_holder'],
'email' => $_POST['email'],
'phone' => $_POST['phone'],
],
successUrl: 'https://yourstore.com/payment/3ds-return',
failureUrl: 'https://yourstore.com/payment/failed'
);
$data = $result['data'] ?? $result;
$html = $data['html'] ?? $data['htmlContent'] ?? null;
if ($html) {
echo $html;
exit;
}
if (($data['status'] ?? '') === 'APPROVED') {
header('Location: /order/complete?paymentId=' . urlencode($data['paymentId'] ?? ''));
exit;
}
header('Location: /payment/failed');
} catch (Throwable $e) {
error_log($e->getMessage());
http_response_code(500);
echo 'Payment failed';
}Step 6 — Handle 3-D Secure
When data.html is returned, the gateway provides an HTML document (usually auto-posting form). Echo it to the browser so the customer completes issuer authentication.
After 3DS, the customer returns to your successUrl and DigetPay sends a webhook — confirm before fulfilling.
Step 7 — Capture and void
// After auth-only sale (auth: Y)
$client->capture($transactionId, 10.00);
// Or void before capture
$client->voidTransaction($transactionId);Step 8 — Webhook handler
<?php
declare(strict_types=1);
$payload = json_decode(file_get_contents('php://input') ?: '', true);
http_response_code(200);
$transactionId = $payload['transactionId'] ?? null;
$status = $payload['status'] ?? null;
$type = $payload['type'] ?? null;
// Idempotent: skip if already processed
error_log('Embedded webhook: ' . json_encode($payload));Event mapping: Webhook Events.
Hosted vs Embedded — Apple Pay
| Integration | Who builds Apple Pay |
|---|---|
| Hosted Checkout | DigetPay checkout page — Hosted Checkout Code (PHP) |
| Embedded Integration | You — Apple Pay Embedded |
Next steps
Updated about 1 month ago
