Developer Documentation
XPayLink API Integration
Use this when a merchant wants their own website, LMS, billing system, or store to accept GCash payments through XPayLink. The merchant site creates a payment session, redirects the customer to the hosted XPayLink payment page, then marks the local order paid only after receiving a valid signed webhook.
Step 1
Create session
Merchant backend calls XPayLink using Public Key.
Step 2
Redirect
Send customer to payment_url.
Step 3
Verify
XPayLink detects and verifies payment.
Step 4
Webhook
Merchant marks paid after signed webhook.
Before merchants integrate
Merchant dashboard setup
- Merchant account must be active.
- Merchant GCash receiving number must be saved.
- Merchant Android phone must be paired and Notification Access enabled.
- Merchant must copy Public Key and Secret Key.
- Merchant webhook URL should be public and not require login.
Safe payment rule
Do not mark an order paid after a redirect, button click, screenshot, or customer message. Mark paid only after X-PayLink-Signature is verified and the webhook payload is valid.
1. Create Payment Session
Call this from the merchant backend/server only. Do not call this directly from frontend JavaScript because the merchant controls order validation server-side.
POST https://synthwave.space/api/create-session.php
Headers:
Content-Type: application/json
X-PayLink-Key: pk_live_your_public_key
X-PayLink-Secret: sk_live_your_secret_key
Body:
{
"external_bill_id": "ORDER-1001",
"customer_name": "Juan Dela Cruz",
"amount": 200.00,
"callback_url": "https://merchantwebsite.com/xpaylink_merchant_sdk/webhook.php",
"success_url": "https://merchantwebsite.com/order-success.php?order=ORDER-1001"
}
Required fields
| Field | Meaning | Example |
|---|---|---|
external_bill_id | Merchant local order/bill ID. Use this to update the merchant database. | ORDER-1001 |
customer_name | Customer display name. | Juan Dela Cruz |
amount | Merchant amount before XPayLink identifier/admin fee. | 200.00 |
Optional fields
{
"callback_url": "https://merchantwebsite.com/xpaylink-webhook.php",
"success_url": "https://merchantwebsite.com/order-success.php?order=ORDER-1001",
"return_url": "https://merchantwebsite.com/order-success.php?order=ORDER-1001",
"failed_url": "https://merchantwebsite.com/order-failed.php?order=ORDER-1001",
"customer_gcash_number": "09123456789"
}
customer_gcash_number is optional. If not provided, the hosted XPayLink payment page will collect it from the customer.
Success response
{
"success": true,
"session_id": "PS-ABC123",
"merchant_amount": "200.00",
"paylink_admin_fee": "5.13",
"customer_should_pay": "205.13",
"final_amount": "205.13",
"gcash_number": "09xxxxxxxxx",
"customer_gcash_required": true,
"expires_at": "2026-05-24 10:00:00",
"status": "pending",
"payment_url": "https://synthwave.space/pay.php?sid=PS-ABC123"
}
2. Redirect Customer to payment_url
This is required. The hosted page shows the final payment amount, GCash receiver, payer details, and live status.
$payment = json_decode($apiResponse, true);
if (!empty($payment["success"])) {
header("Location: " . $payment["payment_url"]);
exit;
}
3. Check Session Status
Optional endpoint for status pages or debugging. The merchant should still rely on webhooks for final database updates.
GET https://synthwave.space/api/session-status.php?sid=PS-ABC123
{
"success": true,
"session_id": "PS-ABC123",
"status": "paid",
"is_paid": true,
"paid_at": "2026-05-24 10:05:00",
"final_amount": "205.13",
"gcash_number": "09xxxxxxxxx",
"customer_gcash_saved": true,
"business_name": "Merchant Store"
}
4. Webhook Receiver
When XPayLink verifies payment, it sends a signed POST request to the session callback_url. If no session callback URL was provided, XPayLink uses the merchant dashboard webhook URL.
POST https://merchantwebsite.com/xpaylink-webhook.php Headers: Content-Type: application/json X-PayLink-Signature: hmac_sha256_signature
Payload
{
"event": "payment.paid",
"status": "paid",
"session_id": "PS-ABC123",
"external_bill_id": "ORDER-1001",
"customer_name": "Juan Dela Cruz",
"customer_paid": "205.13",
"merchant_amount": "200.00",
"paylink_admin_fee": "5.13",
"amount": "205.13",
"sender_gcash_number_masked": "0912***6789",
"match_source": "auto_match",
"manual_review_note": null,
"matched_at": "2026-05-24 10:05:00"
}
PHP signature verification
$secretKey = 'sk_live_your_secret_key';
$raw = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PAYLINK_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $raw, $secretKey);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit('Invalid signature');
}
$payload = json_decode($raw, true);
if (($payload['status'] ?? '') === 'paid') {
// 1. Find local order by external_bill_id
// 2. Compare merchant_amount with local amount
// 3. Mark order PAID idempotently
// 4. Return HTTP 200 OK
}
5. Error Responses
| HTTP | Example | Fix |
|---|---|---|
| 401 | Invalid API key | Use the merchant Public Key and confirm merchant is active. |
| 422 | Amount is required / invalid URL / invalid GCash number | Validate request fields before calling API. |
| 503 | merchant_maintenance | Merchant gateway is disabled or temporarily locked. |
6. SDK / Drop-in Kits
1-File PHP Kit
Best for Hostinger/cPanel/plain PHP merchants. Upload one file, edit config, connect the Pay button.
Download 1-File PHP KitFull PHP SDK
Best for developers who want separate checkout, webhook, demo store, and reusable SDK class.
Download Full PHP SDKWooCommerce Plugin
Best for WordPress stores. Install plugin, enable gateway, enter API keys, and receive signed webhooks.
Download WooCommerce PluginProduction Checklist
- Webhook URL is public HTTPS and does not require login.
- Secret Key is stored server-side only.
- Merchant validates
merchant_amountbefore marking paid. - Webhook update is idempotent, so duplicate retries do not double-credit.
- Merchant saves webhook payload or audit log.
- XPayLink hosting runs
cron_retry_webhooks.phpif webhook retry is needed.