Hosted Checkout Code Examples
Integrate DigetPay Hosted Checkout using your preferred programming language.
Your server creates a payment link, redirects the customer to the DigetPay Checkout page, then confirms the payment using the Status API or Webhooks.
Apple Pay, Mada, 3-D Secure, and PCI compliance are fully handled by the DigetPay Hosted Checkout page. Your application only creates the payment session and redirects the customer.
PrerequisitesBefore you begin, make sure you have completed:
- Sandbox Setup
- Staging
x-api-key- Merchant account
- One of the supported languages:
- PHP 8+
- Node.js 18+
- Python 3.10+
- Java 17+
ImportantThe Hosted Checkout endpoint is:
POST /payment/checkout/intiateThe path is intentionally spelled intiate and should be used exactly as documented.
Never trust the Success URLA customer arriving at your
successUrldoes not guarantee payment success.Always verify payment using:
- Transaction Status API
- Webhooks
Architecture
sequenceDiagram participant Browser as Customer Browser participant Merchant as Your Server participant API as DigetPay API participant Checkout as DigetPay Checkout Browser->>Merchant: Checkout Merchant->>API: Create Payment Link API-->>Merchant: redirectUrl Merchant->>Browser: HTTP Redirect Browser->>Checkout: Complete Payment Checkout->>Browser: successUrl / failureUrl Browser->>Merchant: Return Merchant->>API: Query Status API-->>Merchant: Transaction Status
Integration Steps
Step 1 — Configuration
<?php
return [
'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',
],
],
];.envDIGETPAY_ENV=staging
DIGETPAY_API_KEY=your_fin_staging_key.envDIGETPAY_ENV=staging
DIGETPAY_API_KEY=your_fin_staging_keyconst env = process.env.DIGETPAY_ENV || "staging";
const API_BASES = {
staging: "https://fin-api.digetpay.com/v1",
production: "https://api.digetpay.com/v1"
};
export const config = {
environment: env,
apiKey: process.env.DIGETPAY_API_KEY,
apiBase: API_BASES[env]
};.envDIGETPAY_ENV=staging
DIGETPAY_API_KEY=your_fin_staging_keyimport os
API_BASES = {
"staging": "https://fin-api.digetpay.com/v1",
"production": "https://api.digetpay.com/v1"
}
environment = os.getenv("DIGETPAY_ENV", "staging")
api_key = os.getenv("DIGETPAY_API_KEY")
api_base = API_BASES[environment]public final class DigetPayConfig {
private static final Map<String,String> API_BASES = Map.of(
"staging","https://fin-api.digetpay.com/v1",
"production","https://api.digetpay.com/v1"
);
public static String environment() {
return System.getenv().getOrDefault("DIGETPAY_ENV","staging");
}
public static String apiBase() {
return API_BASES.get(environment());
}
public static String apiKey() {
return System.getenv("DIGETPAY_API_KEY");
}
}Step 2 — API Client
$client = new DigetPayClient($config);The client should expose:
- createPaymentLink()
- getTransactionStatus()
- processRefund()
export function createPaymentLink(payload){
return request("POST","/payment/checkout/intiate",payload);
}
export function getTransactionStatus(id){
return request("GET",`/payment/checkout/status?id=${id}`);
}
export function processRefund(transactionId,amount){
return request("POST","/payment/refund",{
transactionId,
amount
});
}def create_payment_link(payload):
...
def get_transaction_status(id):
...
def process_refund(transaction_id, amount):
...client.createPaymentLink(payload);
client.getTransactionStatus(transactionId);
client.processRefund(transactionId, amount);Step 3 — Create Payment Link & Redirect
Create a payment session, save the returned session ID, then redirect the customer to the DigetPay Hosted Checkout page.
<?php
require_once __DIR__ . '/../src/DigetPayClient.php';
$config = require __DIR__ . '/../config/digetpay.php';
$client = new DigetPayClient($config);
$orderId = 'ORD-' . time();
$session = $client->createPaymentLink([
'merchantOrderId' => $orderId,
'amount' => 10.00,
'currency' => 'SAR',
'customerName' => 'Ahmed Ali',
'customerEmail' => '[email protected]',
'customerPhone' => '501223324',
'successUrl' => 'https://yourstore.com/checkout/success',
'failureUrl' => 'https://yourstore.com/checkout/failure'
]);
// Save session ID before redirecting
// saveSession($orderId, $session['id']);
header('Location: ' . $session['redirectUrl']);
exit;router.get("/checkout", async (req, res) => {
const session = await createPaymentLink({
merchantOrderId: `ORD-${Date.now()}`,
amount: 10,
currency: "SAR",
customerName: "Ahmed Ali",
customerEmail: "[email protected]",
customerPhone: "501223324",
successUrl: "https://yourstore.com/checkout/success",
failureUrl: "https://yourstore.com/checkout/failure"
});
// Store session.id before redirect
res.redirect(session.redirectUrl);
});@checkout.route("/checkout")
def checkout():
session = create_payment_link({
"merchantOrderId": f"ORD-{int(time.time())}",
"amount":10,
"currency":"SAR",
"customerName":"Ahmed Ali",
"customerEmail":"[email protected]",
"customerPhone":"501223324",
"successUrl":"https://yourstore.com/checkout/success",
"failureUrl":"https://yourstore.com/checkout/failure"
})
# Save session["id"]
return redirect(session["redirectUrl"])Map<String,Object> session = client.createPaymentLink(
Map.of(
"merchantOrderId","ORD-"+System.currentTimeMillis(),
"amount",10.00,
"currency","SAR",
"customerName","Ahmed Ali",
"customerEmail","[email protected]",
"customerPhone","501223324",
"successUrl","https://yourstore.com/checkout/success",
"failureUrl","https://yourstore.com/checkout/failure"
)
);
// Save session id
return ResponseEntity.status(HttpStatus.FOUND)
.location(URI.create((String)session.get("redirectUrl")))
.build();
Apple PayNo additional code is required.
Apple Pay automatically appears on the DigetPay Hosted Checkout page when:
- The customer's device supports Apple Pay.
- Safari is being used.
customerPhoneis included in the request.
Step 4 — Handle Return URL
After the customer completes payment, DigetPay redirects the browser back to your application.
Important: Returning to the Success URL does not confirm payment.
Always verify the transaction using either:
- Transaction Status API
- Webhooks
<?php
$sessionId = $_GET["sessionId"] ?? null;
if (!$sessionId) {
http_response_code(400);
exit("Missing sessionId");
}
// Retrieve your order using sessionId
// Call Status API
echo "Processing payment...";router.get("/checkout/success",(req,res)=>{
const sessionId = req.query.sessionId;
// Lookup order
// Query Status API
res.send("Processing payment...");
});@checkout.route("/checkout/success")
def success():
session_id = request.args.get("sessionId")
# Lookup order
# Query Status API
return "Processing payment..."@GetMapping("/checkout/success")
public String success(
@RequestParam(required=false)
String sessionId){
// Lookup order
// Query Status API
return "Processing payment...";
}
Never Trust the RedirectA customer reaching the Success URL only means they returned from the checkout page.
The payment might still be:
- Pending
- Failed
- Cancelled
- Expired
Only mark the order as paid after:
- A successful Status API response, or
- A valid Webhook notification.
Step 5 — Confirm Payment
After the customer returns to your website, verify the payment using the Transaction Status API.
Do not rely on the redirect URL alone.
<?php
require_once __DIR__ . '/../src/DigetPayClient.php';
$config = require __DIR__ . '/../config/digetpay.php';
$client = new DigetPayClient($config);
// Retrieve the session ID from your database
$sessionId = 'stored-session-id';
$response = $client->getTransactionStatus($sessionId);
$content = $response['data']['content'][0] ?? null;
if ($content && $content['transactionStatus'] === 'SUCCESS') {
$gatewayTransactionId = $content['id'];
// Mark order as paid
// Save gatewayTransactionId for refunds
} elseif ($content && $content['transactionStatus'] === 'PENDING') {
// Payment is still processing
} else {
// Payment failed
}const response = await getTransactionStatus(sessionId);
const transaction = response?.data?.content?.[0];
if (transaction?.transactionStatus === "SUCCESS") {
const gatewayTransactionId = transaction.id;
// Mark order as paid
}
else if (transaction?.transactionStatus === "PENDING"){
// Still processing
}
else{
// Failed
}response = get_transaction_status(session_id)
transaction = response.get("data",{}).get("content",[{}])[0]
if transaction.get("transactionStatus") == "SUCCESS":
gateway_transaction_id = transaction["id"]
# Mark order paid
elif transaction.get("transactionStatus") == "PENDING":
# Still processing
pass
else:
# Failed
passMap<String,Object> response =
client.getTransactionStatus(sessionId);
Map<String,Object> transaction =
(Map<String,Object>)
((List<?>)((Map<?,?>)response.get("data"))
.get("content")).get(0);
String status =
(String)transaction.get("transactionStatus");
if("SUCCESS".equals(status)){
String gatewayTransactionId =
(String)transaction.get("id");
// Mark order paid
}
Successful PaymentWhen the payment status is SUCCESS:
- Update the order status.
- Store the Gateway Transaction ID.
- Send the customer confirmation.
- Trigger fulfillment.
The Gateway Transaction ID is required later for refunds.
Step 6 — Receive Webhooks
Although the Status API confirms payments, Webhooks are the recommended way to receive payment events automatically.
DigetPay sends HTTP POST requests to your configured webhook endpoint whenever a payment status changes.
<?php
$raw = file_get_contents("php://input");
$payload = json_decode($raw,true);
http_response_code(200);
echo "OK";
$transactionId = $payload["transactionId"] ?? null;
$orderId = $payload["orderId"] ?? null;
$status = $payload["status"] ?? null;
// Verify signature
// Check idempotency
// Update orderapp.post(
"/webhooks/digetpay",
express.raw({type:"application/json"}),
(req,res)=>{
const payload = JSON.parse(req.body.toString());
res.status(200).send("OK");
const{
transactionId,
orderId,
status,
type
}=payload;
// Verify signature
// Check idempotency
// Update order
});@app.route("/webhooks/digetpay",methods=["POST"])
def webhook():
payload = request.get_json(force=True)
transaction_id = payload.get("transactionId")
order_id = payload.get("orderId")
status = payload.get("status")
event_type = payload.get("type")
# Verify signature
# Check idempotency
# Update order
return "OK",200@PostMapping("/webhooks/digetpay")
public ResponseEntity<String> webhook(
@RequestBody Map<String,Object> payload){
String transactionId =
(String)payload.get("transactionId");
String orderId =
(String)payload.get("orderId");
String status =
(String)payload.get("status");
String type =
(String)payload.get("type");
// Verify signature
// Check idempotency
// Update order
return ResponseEntity.ok("OK");
}Webhook Best Practices
Implement IdempotencyDigetPay may retry webhook delivery.
Always deduplicate events using:
transactionIdtypebefore updating your database.
Respond ImmediatelyReturn HTTP 200 OK within a few seconds.
Heavy processing such as:
- Sending emails
- Updating inventory
- ERP synchronization
- Invoice generation
should happen asynchronously.
Recommended Payment Flow
- Customer completes payment.
- Customer returns to your Success URL.
- Verify payment using the Status API.
- Receive the Webhook.
- Update your database.
- Complete order fulfillment.
This approach provides the highest reliability in production.
Step 7 — Process Refund
After a successful payment, you can issue either a full or partial refund using the Gateway Transaction ID returned by the Status API.
The Gateway Transaction ID is available in the payment confirmation response (
data.content[0].id). Store this value in your database for future refund requests.
<?php
require_once __DIR__ . '/../src/DigetPayClient.php';
$config = require __DIR__ . '/../config/digetpay.php';
$client = new DigetPayClient($config);
$gatewayTransactionId = "2232e99b-0257-47d5-bbfd-022c8951767f";
$amount = 5.00;
$result = $client->processRefund(
$gatewayTransactionId,
$amount
);
// Update your order statusimport { processRefund } from "../src/digetpayClient.js";
await processRefund(
"2232e99b-0257-47d5-bbfd-022c8951767f",
5.00
);
// Update your orderfrom digetpay_client import process_refund
process_refund(
"2232e99b-0257-47d5-bbfd-022c8951767f",
5.00
)
# Update your orderclient.processRefund(
"2232e99b-0257-47d5-bbfd-022c8951767f",
5.00
);
// Update your orderStaging vs Production
| Setting | Staging | Production |
|---|---|---|
| Environment | staging | production |
| API Base URL | https://fin-api.digetpay.com/v1 | https://api.digetpay.com/v1 |
| Dashboard | https://fin-admin.digetpay.com | https://admin.digetpay.com |
| API Key | Fin Staging Key | Production API Key |
Before switching to production, replace both the API Base URL and your API Key.
What DigetPay Handles
One of the main advantages of Hosted Checkout is that DigetPay manages all payment UI and PCI-sensitive functionality for you.
| Feature | Handled By |
|---|---|
| Payment Form | DigetPay Checkout |
| Card Validation | DigetPay Checkout |
| Apple Pay | DigetPay Checkout |
| Mada | DigetPay Checkout |
| 3-D Secure Authentication | DigetPay Checkout |
| PCI DSS Compliance | DigetPay Infrastructure |
| Card Data Storage | DigetPay Infrastructure |
Your application only needs to:
- Create the payment link.
- Redirect the customer.
- Verify payment.
- Handle webhooks.
- Process refunds.
Production Checklist
Before requesting Production access, verify the following:
- ✅ Production API Key received.
- ✅ Success URL configured.
- ✅ Failure URL configured.
- ✅ Webhook URL configured.
- ✅ Status API implemented.
- ✅ Webhook processing implemented.
- ✅ Duplicate webhook protection implemented.
- ✅ Refund flow tested.
- ✅ End-to-end payment tested.
- ✅ Error handling completed.
- ✅ Logging enabled.
Ready for ProductionOnce every item above has been completed successfully, your Hosted Checkout integration is ready for Production.
Integration Flow Summary
flowchart LR A[Create Payment Link] -->B[Redirect Customer] B-->C[Customer Pays] C-->D[Return to Success URL] D-->E[Query Status API] C-->F[Receive Webhook] E-->G[Verify Payment] F-->G G-->H[Mark Order Paid] H-->I[Future Refunds]
Related Documentation
Updated about 1 month ago
