X
XylePay Docs
Xyle Payments — Developer Documentation

Build with Mobile Money.
Ship faster.

Complete integration guides for the Xyle Payments WordPress Plugin and REST API. Start by creating your account, then follow the guide for your integration type.

🚀

Before You Begin

Whether you're using the WordPress Plugin or the REST API, every Xyle Payments integration begins with the same two steps: creating your account and generating your API keys from your dashboard.

01
Account Setup

Create a Xyle Payments Account

You must have an active Xyle Payments account before using any of our services. Registration takes under two minutes.

1
Visit the registration page
Go to dashboard.xylepayments.com/register and fill in your name, email, and a strong password.
2
Verify your email address
Check your inbox for a verification email from Xyle Payments and click the confirmation link to activate your account.
3
Complete your business profile
After email verification you'll be prompted to enter your business name and country. This is required before generating live API keys.
4
Log in to your dashboard
Go to dashboard.xylepayments.com/login and sign in. You'll land on your Xyle Payments dashboard.
02
Account Setup

Dashboard & Generating API Keys

Your dashboard is where you manage API keys, view transactions, purchase plugin licenses, and monitor your integration status.

🔑
Sandbox vs Live. Use sandbox keys during development — no real money moves. Switch to live keys only when you're ready to accept real payments.
1
Open the API Keys section
From your dashboard sidebar, click API Keys. You'll see two tabs — Sandbox and Live.
2
Generate your keys
Click Generate New Key. You'll receive a public key (xk_pub_…) and a secret key (xk_sec_…).
3
Copy and store your secret key securely
The secret key is shown only once. Copy it immediately and store it in a password manager or secrets manager. Never expose it in client-side code or commit it to version control.
Key typePrefixUse for
xk_pub_…PublicClient-side identification (safe to expose)
xk_sec_…SecretServer-side API calls — keep private
xk_sb_pub_…Sandbox publicTesting — no real money
xk_sb_sec_…Sandbox secretSandbox server-side calls

🔌

WordPress Plugin

The Xyle Payments WordPress plugin lets you accept MTN MoMo and Airtel Money on any WordPress or WooCommerce site with zero backend code. You need both an active Xyle Payments account and a plugin license before you can activate the plugin.

01
WordPress Plugin

Purchase a Plugin License

The plugin requires a paid license key tied to your Xyle Payments account. Without it, the plugin will not activate.

⚠️
A valid license is required for the plugin to work. Complete account registration and log in to your dashboard before purchasing.
1
Log in to your dashboard
2
Navigate to Plugin Licenses
From the sidebar, click Plugins → WordPress Plugin to view available license tiers.
3
Purchase and pay via mobile money
Select your license tier and complete payment. Your license key is generated immediately after payment is confirmed.
4
Copy your license key
From the Licenses page, copy your license key — it looks like XP-XXXX-XXXX-XXXX-XXXX. You will need this during plugin setup.
Starter
1 site
UGX 80,000/yr
  • MTN MoMo
  • Airtel Money
  • Shortcode widget
  • Email support
Pro
Up to 5 sites
UGX 180,000/yr
  • Everything in Starter
  • WooCommerce integration
  • Cashout support
  • Transaction analytics
  • Priority support
02
WordPress Plugin

Installing the Plugin

Install directly from your WordPress admin — no FTP or command line required.

1
Download the plugin ZIP
From your dashboard Licenses page, click Download Plugin to get xyle-payments.zip.
2
Go to Plugins → Add New
In your WordPress admin, go to Plugins → Add New Plugin, then click Upload Plugin.
3
Upload and install
Click Choose File, select xyle-payments.zip, then click Install Now.
4
Activate the plugin
Click Activate Plugin. A new Xyle Payments item appears in your admin sidebar. The plugin creates the wp_xylep_transactions table automatically.
5
Verify activation
Go to Xyle Payments → Dashboard. You'll see the stats overview and your integration status. It will show "Not configured" until you complete the settings — that's expected.
📁
Alternatively, upload the unzipped xyle-payments folder to /wp-content/plugins/ via FTP, then activate from the Plugins list in wp-admin.
03
WordPress Plugin

Configuring the Plugin

Enter your license key and Xyle API key in the plugin settings, then select your environment.

🌐
Base URLs. The plugin settings page has an environment toggle. The underlying endpoints are:Live: https://api.xyle-payments.comSandbox: https://sandbox.xyle-payments.com
1
Open Plugin Settings
In wp-admin, go to Xyle Payments → Settings.
2
Enter your License Key
Paste your license key (e.g. XP-XXXX-XXXX-XXXX-XXXX) and click Activate License.
3
Enter your Xyle API Secret Key
Paste your secret key from the dashboard. Use your sandbox key (xk_sb_sec_…) for development, live key (xk_sec_…) for production.
4
Select your environment
Toggle between Sandbox and Live. Sandbox routes to sandbox.xyle-payments.com; no real money moves. Switch to Live only when ready.
5
Save and verify
Click Save Settings, then check Xyle Payments → Dashboard — you should see a green Configured badge.
⚠️
Never commit your API key or license key to version control. Store them as server environment variables or in wp-config.php — both sit outside your web root and are excluded from most git setups.
04
WordPress Plugin

Shortcode Usage

Place the payment widget anywhere on your site using the shortcode.

shortcode
[xylep_payment_form amount="5000" theme="dark" title="Pay Now"]

In a PHP template

phpyour-template.php
// Static amount
echo do_shortcode( '[xylep_payment_form amount="5000"]' );

// Dynamic amount from post meta
$amount = get_post_meta( get_the_ID(), '_product_price', true );
echo do_shortcode( "[xylep_payment_form amount="{$amount}" theme="dark"]" );

Set amount via JavaScript

javascript
document.getElementById('xylep-amount').value = '25000';
05
WordPress Plugin

Shortcode Attribute Reference

Shortcode: [xylep_payment_form]

AttributeDefaultValuesDescription
amountemptyAny positive numberPre-fills the amount field. Leave empty to set via JavaScript.
themePlugin settinglight / darkWidget colour theme. Users can toggle in-widget.
titleMobile Money PaymentAny stringHeading shown at the top of the form.
currencyUGXISO 4217 codeCurrency shown to the user. Must match the provider's accepted currency.
06
WordPress Plugin

WooCommerce Integration Example

Accept mobile money at WooCommerce checkout with a complete polling flow.

🛒
Place the Xyle widget at checkout. Poll the status endpoint every few seconds, and on success call your server to mark the order as paid and redirect the customer.

Step 1 — Render the widget

phpcheckout.php
$order  = wc_get_order( $order_id );
$amount = (int) $order->get_total();
echo do_shortcode( "[xylep_payment_form amount="{$amount}"]" );

Step 2 — Poll and complete the order

javascriptcheckout.js
async function pollPaymentStatus(ref, orderId) {
  const iv = setInterval(async () => {
    const data = await (await fetch(`/wp-json/xylep/v1/status/${ref}`)).json();
    if (data.status === 'successful') {
      clearInterval(iv);
      await fetch('/wp-json/xylep/v1/order-paid', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ order_id: orderId, xyle_ref: ref })
      });
      window.location.href = `/checkout/order-received/${orderId}/`;
    }
  }, 3000);
}
07
WordPress Plugin

Cashout / Withdrawal Integration

Let users withdraw funds to mobile money — always validate eligibility server-side before rendering the widget.

💡
Validate server-side first. Only render the Xyle widget after confirming the user has sufficient balance. This prevents amount manipulation from the browser.
phppage-withdraw.php
if ( isset( $_POST['withdraw_amount'] ) ) {
    $amount  = absint( $_POST['withdraw_amount'] );
    $balance = (int) get_user_meta( get_current_user_id(), 'wallet_balance', true );

    if ( $amount > 500 && $amount <= $balance ) {
        echo do_shortcode( "[xylep_payment_form amount="{$amount}" title="Confirm Withdrawal"]" );
    } else {
        echo '<p class="error">Invalid amount or insufficient balance.</p>';
    }
}
08
WordPress Plugin

Transaction Tracking

Query the Xyle database table directly from PHP to check or display transaction history.

php
global $wpdb;
$table = $wpdb->prefix . 'xylep_transactions';

$tx = $wpdb->get_row( $wpdb->prepare(
    "SELECT * FROM {$table} WHERE transaction_ref = %s", $ref
) );

if ( $tx->status === 'successful' ) {
    // Fulfil the order
}

// Columns: id · transaction_ref · provider · phone · amount
//          currency · status (pending|successful|failed)
//          provider_ref · note · created_at · updated_at
09
WordPress Plugin

Troubleshooting

Plugin menu not appearing after activation

Go to Settings → Permalinks and click Save Changes to flush rewrite rules — this registers the plugin's REST routes.

License activation fails

Make sure your account is active and the key is copied exactly. If the error persists, check that your server can reach api.xyle-payments.com — some hosts block outbound HTTP from PHP.

Payments fail with provider error after setup

Check that your Xyle API secret key is correct and matches the selected environment (sandbox vs live). Verify in Xyle Payments → Dashboard that your account status shows as active.

Payment request returns 502

Common causes: wrong environment, expired token, or invalid phone format. Check your PHP error log for the full API response body.

Status always shows PENDING

In sandbox you must manually approve payments from the Xyle sandbox portal. In production the subscriber receives a USSD prompt — they must enter their PIN within 60–120 s.

Widget CSS not loading

The plugin only enqueues assets on pages containing the [xylep_payment_form] shortcode. Ensure it is in the page body and the template calls wp_head().

🛠
Still stuck? Email xyle-payments.com/support with your PHP error log and the transaction reference ID.

REST API

The Xyle Payments REST API lets you initiate and track mobile money payments from any language or platform. The request body is identical across all endpoints — only the base URL changes depending on your environment.

01
REST API

Overview & Base URLs

All requests are made over HTTPS. Only the base URL changes between sandbox and live — the paths and request bodies are identical.

🟡 Sandbox
https://sandbox.xyle-payments.com/sandbox/api/v1/client/
Development & testing. No real money moves. Use your sandbox API keys.
🟢 Live
https://api.xyle-payments.com/api/v1/client/
Production. Real transactions. Use your live API keys.
⚠️
Never mix environments. Sandbox and live keys are completely separate — using a live key in development initiates real transactions.
02
REST API

Authentication

Pass your Xyle Payments secret key as a Bearer token in the Authorization header on every request.

httpRequired headers
Authorization: Bearer xk_sec_your_secret_key_here
Content-Type: application/json

cURL example

bash
curl -X POST https://api.xyle-payments.com/api/v1/client/deposit \
  -H "Authorization: Bearer xk_sec_your_key" \
  -H "Content-Type: application/json" \
  -d '{"account":"256771234567","amount":25000,"provider":"MTN_UGANDA"}'

JavaScript example

javascript
const res = await fetch('https://api.xyle-payments.com/api/v1/client/deposit', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer xk_sec_your_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ account: '256771234567', amount: 25000, provider: 'MTN_UGANDA' }),
});
03
REST API

Initiate a Payment

Send a payment request to a subscriber's mobile money wallet. They receive a USSD prompt to confirm.

Sandbox
endpoint
POST https://sandbox.xyle-payments.com/sandbox/api/v1/client/deposit
Live
endpoint
POST https://api.xyle-payments.com/api/v1/client/deposit

Request body

json
{
  "account":     "256771234567",   // Required — international format, no +
  "amount":      25000,             // Required — smallest currency unit (UGX)
  "provider":    "MTN_UGANDA",    // Required — "MTN_UGANDA" or "AIRTEL_UGANDA"
}

Success response

json
{
  "success":        true,
  "message":         "Deposit processed successfully",
  "data":            {
    "id":             "transaction-uuid-456",
    "type":           "DEPOSIT",
    "amount":         50000,
    "provider":       "MTN_UGANDA",
    "reference":      "XYLE-DEP-20260219-001",
    "status":         "COMPLETED",
    "account":        "256700000000",
    "netAmount":      50000,
    "createdAt":      "2026-02-19T11:00:00Z",
    "completedAt":    "2026-02-19T11:00:30Z"
  }
}
FieldRequiredDescription
accountRequiredInternational format without + (e.g. 256771234567)
amountRequiredAmount in smallest currency unit (UGX has no decimals)
providerRequiredMTN_UGANDA or AIRTEL_UGANDA
04
REST API

Withdraw Funds

Send funds from your wallet to a subscriber's mobile money account. The transfer is processed immediately.

Sandbox
endpoint
POST https://sandbox.xyle-payments.com/sandbox/api/v1/client/withdrawal
Live
endpoint
POST https://api.xyle-payments.com/api/v1/client/withdrawal

Request body

json
{
  "account":     "256700000000",   // Required — international format, no +
  "amount":      25000,             // Required — smallest currency unit (UGX)
  "provider":    "AIRTEL_UGANDA",  // Required — "MTN_UGANDA" or "AIRTEL_UGANDA"
}

Success response

json
{
  "success":        true,
  "message":        "Withdrawal processed successfully",
  "data":           {
    "transactionId": "transaction-uuid-789",
    "reference":     "XYLE-WD-20260219-001",
    "amount":        25000,
    "platformFee":   500,
    "netAmount":     24500,
    "status":        "PENDING"
  }
}

Error response

json
{
  "success":   false,
  "message":   "Insufficient balance. Required: 25500, Available: 15000"
}
FieldRequiredDescription
accountRequiredInternational format without + (e.g. 256700000000)
amountRequiredAmount in smallest currency unit (UGX has no decimals)
providerRequiredMTN_UGANDA or AIRTEL_UGANDA
05
REST API

Get Transactions

Retrieve a paginated list of all transactions associated with your account.

Sandbox
endpoint
GET https://sandbox.xyle-payments.com/sandbox/api/v1/client/transactions
Live
endpoint
GET https://api.xyle-payments.com/api/v1/client/transactions

Query parameters

ParameterRequiredDescription
pageOptionalPage number — defaults to 1
limitOptionalItems per page — defaults to 10

Success response

json
{
  "success":  true,
  "data":     {
    "transactions": [
      {
        "id":          "transaction-uuid-456",
        "type":        "DEPOSIT",
        "amount":      50000,
        "provider":    "MTN_UGANDA",
        "reference":   "XYLE-DEP-20260219-001",
        "status":      "COMPLETED",
        "platformFee": 0,
        "netAmount":   50000,
        "createdAt":   "2026-02-19T11:00:00Z"
      },
      {
        "id":          "transaction-uuid-789",
        "type":        "WITHDRAWAL",
        "amount":      25000,
        "provider":    "AIRTEL_UGANDA",
        "reference":   "XYLE-WD-20260219-001",
        "status":      "PENDING",
        "platformFee": 500,
        "netAmount":   24500,
        "createdAt":   "2026-02-19T10:45:00Z"
      }
    ],
    "pagination": {
      "page":   1,
      "limit":  10,
      "total":  25,
      "pages":  3
    }
  }
}
06
REST API

Check Payment Status

Poll this endpoint after initiating a payment. Recommended interval: every 3–5 seconds for up to 2 minutes.

Sandbox
endpoint
GET https://sandbox.xyle-payments.com/v1/payments/{ref}
Live
endpoint
GET https://api.xyle-payments.com/v1/payments/{ref}

Response

json
{
  "transaction_ref": "xp_2025_abc123def456",
  "status":          "successful",  // pending | successful | failed
  "provider_ref":    "MTN_REF_XYZ789",
  "phone":           "256771234567",
  "amount":          25000,
  "currency":        "UGX",
  "provider":        "mtn",
  "reference":       "order-1234",
  "created_at":      "2025-02-15T10:32:00Z"
}
07
REST API

Error Reference

All errors return JSON with a machine-readable code and a human-readable message.

jsonError shape
{
  "success": false,
  "code":    "invalid_phone",
  "message": "The phone number is not a valid Ugandan mobile number."
}
HTTPCodeDescription
401unauthorizedMissing or invalid Authorization header or secret key
402insufficient_fundsSubscriber's mobile money balance is too low
422invalid_phonePhone number format is not valid
422invalid_amountAmount is zero, negative, or exceeds provider limits
422invalid_providerProvider must be mtn or airtel
429rate_limitedToo many requests — retry after the Retry-After header value
502provider_errorProvider API error — check environment and credentials
503service_unavailableXyle Payments temporarily unavailable — retry with exponential backoff