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);

Capture & Void guide →


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

IntegrationWho builds Apple Pay
Hosted CheckoutDigetPay checkout page — Hosted Checkout Code (PHP)
Embedded IntegrationYouApple Pay Embedded

Next steps



Did this page help you?