YoqPay API

Documentation / API Reference

YoqPay Developer Portal

API documentation

Select an endpoint to see its description, request payload, and response.

REST API · v1

Start with your API keys. Create sandbox credentials from API Keys and use them from your server. Do not expose secret keys in browsers, mobile apps, or public repositories.

Authentication

Authenticate every endpoint with the API key and matching secret in the request headers. Use your sandbox pair while developing and your live pair in production.

HTTP headersRequired
X-API-KEY: YOUR_API_KEY
X-API-SECRET: YOUR_API_SECRET
Content-Type: application/json
Accept: application/json

SSO login · email or phone

Authenticate an existing YoqPay account from your server using its email address or phone number. This endpoint uses a timestamped HMAC signature instead of API key headers.

POST https://www.yoqpay.com/sso/loginSigned JSON · HMAC-SHA256200 · 400 · 401 · 403

Server-side only. Configure the same external_auth_shared_secret on both servers. Sign timestamp + "." + raw JSON body; send the exact same body you signed. Never expose the shared secret in browser or mobile client code.

Header / fieldRequiredDescription
X-External-TimestampYesUnix timestamp in seconds; requests expire after five minutes.
X-External-SignatureYesHex HMAC-SHA256 of timestamp.rawBody using the shared secret.
identifierYesYoqPay account email or phone, such as amina@example.com or +255712345678.
passwordYesThe account password.
PHP · cURLExample
<?php
$payload = ['identifier' => 'amina@example.com', 'password' => $password];
// For phone login, use '+255712345678' as identifier.
$body = json_encode($payload, JSON_UNESCAPED_SLASHES);
$timestamp = (string) time();
$signature = hash_hmac('sha256', $timestamp . '.' . $body, getenv('YOQPAY_SSO_SECRET'));
$ch = curl_init('https://www.yoqpay.com/sso/login');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-External-Timestamp: ' . $timestamp,
        'X-External-Signature: ' . $signature,
    ],
    CURLOPT_POSTFIELDS => $body,
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Node.js · fetchExample
import { createHmac } from 'node:crypto';

const payload = { identifier: '+255712345678', password };
const body = JSON.stringify(payload);
const timestamp = String(Math.floor(Date.now() / 1000));
const signature = createHmac('sha256', process.env.YOQPAY_SSO_SECRET)
  .update(`${timestamp}.${body}`).digest('hex');
const response = await fetch('https://www.yoqpay.com/sso/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-External-Timestamp': timestamp,
    'X-External-Signature': signature,
  },
  body,
});
console.log(response.status, await response.json());
Successful response200 JSON
{
  "success": true,
  "external_id": 123,
  "email": "amina@example.com",
  "phone_number": "+255712345678"
}

See the SSO integration guide for the full client examples and setup steps.

Requests & responses

Send JSON request bodies with the appropriate HTTP method. Successful calls return a status and a data object. Errors return a message and an HTTP error status.

Base URL: https://www.yoqpay.comContent type: application/json

API reference

All current merchant API endpoints are listed below. Use the language tabs on each endpoint for complete request examples.

GET/PaymentLinkApi/customers

Fetch customers saved in the authenticated merchant’s invoice customer directory. Results are scoped to the API key’s merchant account.

200 OKAuthentication required

Query parameters

ParameterTypeDefaultDescription
limitinteger20Results per page, from 1 to 100.
offsetinteger0Number of results to skip.
searchstring—Filter by customer name, email, or phone.
curl -X GET "https://www.yoqpay.com/PaymentLinkApi/customers?limit=20&offset=0" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-API-SECRET: YOUR_API_SECRET"
ResponseJSON
{
  "status": "success",
  "data": {
    "customers": [{"id": 42, "name": "Amina Example", "email": "amina@example.com", "phone": "+255700000000", "address": "Dar es Salaam"}],
    "total": 1,
    "limit": 20,
    "offset": 0
  }
}
POST/PaymentLinkApi/customers

Add a customer to the authenticated merchant’s directory. The saved customer can then be selected when creating invoices.

201 Created409 Email already existsAuthentication required

JSON request body

FieldTypeRequiredDescription
namestringYesCustomer or business name, up to 255 characters.
emailstringNoValid email address. Must be unique within the merchant account.
phonestringNoPhone number, up to 50 characters.
addressstringNoBilling address.
curl -X POST "https://www.yoqpay.com/PaymentLinkApi/customers" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-API-SECRET: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"name":"Amina Example","email":"amina@example.com","phone":"+255700000000","address":"Dar es Salaam"}'
ResponseJSON
{"status":"success","data":{"id":42,"name":"Amina Example","email":"amina@example.com","phone":"+255700000000","address":"Dar es Salaam","created_at":"2026-10-14 12:00:00"}}
GET/PaymentLinkApi/balance

Query all wallet balances for the authenticated merchant, including available, received, on-hold, and reserve amounts.

200 OKAuthentication required

Optional query parameter

ParameterTypeDescription
currencystringThree-letter ISO currency code such as TZS or USD. Omit it to get every currency.
curl -X GET "https://www.yoqpay.com/PaymentLinkApi/balance?currency=TZS" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-API-SECRET: YOUR_API_SECRET"
ResponseJSON
{
  "status": "success",
  "data": {"balances": [{"currency":"TZS","balance":1000,"received_balance":1000,"on_hold_balance":0,"reserve_balance":0,"last_updated_at":"2026-10-14 12:00:00"}]}
}
POST/PaymentLinkApi/cashout

Request a Yas mobile-money cashout from the authenticated merchant wallet. The account’s admin-configured minimum, maximum, and fee percentage are applied. The cashout fee is charged in addition to the requested amount and recorded as YoqPay fee earnings.

201 CreatedTZS onlyAuthentication required

Headers

Send X-API-KEY, X-API-SECRET, and Content-Type: application/json. Include a unique Idempotency-Key header or idempotency_key body field for each new cashout. Reuse the key to safely retry the same request.

JSON request body

FieldTypeRequiredDescription
amountnumberYesAmount to send. Must meet the configured account limits and available balance including the cashout fee.
currencystringYesUse TZS.
mobilestringYesTanzanian mobile number; use 9 digits after the country code, such as 712345678.
mobile_operatorstringNoCurrently Yas (default).
idempotency_keystringYes, if the header is omittedUnique 8-128 character key. Reusing it returns the original result and prevents duplicate payouts.
curl -X POST "https://www.yoqpay.com/PaymentLinkApi/cashout" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-API-SECRET: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"amount":50000,"currency":"TZS","mobile":"712345678","mobile_operator":"Yas","idempotency_key":"cashout-order-20261020-001"}'
ResponseJSON · 201
{
  "status": "success",
  "data": {
    "transaction_id": "CO261020123456A1B2C3D4",
    "provider_reference": "provider-reference",
    "amount_sent": 50000,
    "fee_percentage": 2,
    "fee_deducted": 1000,
    "total_debit": 51000,
    "currency": "TZS"
  }
}

Failed provider requests are recorded as failed and the wallet debit is restored. Check the response status before retrying to avoid duplicate requests.

POST/PaymentLinkApi/invoice

Create a draft invoice for the authenticated merchant.

201 CreatedAuthentication required

Request body

FieldTypeRequiredDescription
amountnumberYesPositive invoice amount.
currencystringYesThree-letter ISO currency code.
descriptionstringYesInvoice description.
invoice_numberstringNoMerchant invoice number; generated if omitted.
client_name, client_email, client_phonestringNoCustomer contact details.
due_datedateNoDefaults to seven days from creation.
itemsarrayNoInvoice line items.
notes, subtotal, tax_amount, discount_amount, shipping_amount, total_amountstring / numberNoOptional invoice details and totals.
curl -X POST "https://www.yoqpay.com/PaymentLinkApi/invoice" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-API-SECRET: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"amount":125000,"currency":"TZS","description":"Consulting services","invoice_number":"INV-1042","client_name":"Amina Example","client_email":"amina@example.com","due_date":"2026-11-12","items":[{"description":"Consulting","quantity":5,"unit_price":25000}],"notes":"Thank you for your business"}'
POST/PaymentLinkApi/ussd_push

Request a mobile money USSD prompt. Authenticate with your YoqPay application credentials in the X-API-KEY and X-API-SECRET headers. The credentials identify your YoqPay merchant account; do not send provider secrets in the request body.

Provider availability: Airtel is currently connected. Yas, M-Pesa, and Halotel are accepted provider names but return 501 until their merchant-scoped integrations are configured. The request returns a pending status; the customer must approve the prompt and the payment result is asynchronous.

202 Accepted400 Invalid request501 Provider unavailable

JSON request body

FieldTypeRequiredDescription
providerstringYesairtel, yas, mpesa, or halotel.
referencestringYesYour unique reference, up to 25 characters.
amountnumberYesPositive amount. Airtel currently accepts TZS only.
mobilestringYesCustomer phone number, with or without country prefix.
currencystringNoThree-letter ISO code; defaults to TZS.
customer_name, customer_emailstringNoOptional customer details.
curl -X POST "https://www.yoqpay.com/PaymentLinkApi/ussd_push" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-API-SECRET: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"provider":"airtel","reference":"ORDER-1001","amount":1000,"currency":"TZS","mobile":"712345678","customer_name":"Amina Example","customer_email":"amina@example.com"}'
Accepted responseJSON · 202
{
  "status": "success",
  "data": {
    "provider": "airtel",
    "reference": "ORDER-1001",
    "transaction_id": "ORDER-1001",
    "status": "pending",
    "message": "USSD push sent. Customer must approve it on their phone."
  }
}
POST/PaymentLinkApi/webhook

Register a webhook endpoint and choose the payment events it should receive. The signing secret is returned once; store it securely.

201 CreatedAuthentication required

Supported events

payment.completed, payment.failed, payment.updated, and invoice.created.

curl -X POST "https://www.yoqpay.com/PaymentLinkApi/webhook" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "X-API-SECRET: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://merchant.example/webhooks/yoqpay","events":["payment.completed","payment.failed","invoice.created"]}'

Verify webhook signatures

YoqPay signs the exact raw JSON request body with HMAC-SHA256. Compare the lowercase hexadecimal signature from X-Yoqpay-Signature using a constant-time comparison before processing the event.

PHPWebhook validation
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_YOQPAY_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $rawBody, $webhookSigningSecret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$event = json_decode($rawBody, true);

Event name is also sent in X-Yoqpay-Event. Return a 2xx response after accepting an event. Failed deliveries are logged; automatic retries are not currently provided.

Errors & status codes

API errors include a machine-readable status and a message that describes the invalid request or failed operation.

HTTP statusMeaning
400Missing or invalid request field.
401Missing or invalid API credentials, or an unverified merchant account.
409Duplicate payment-link reference.
500Unexpected server-side failure.
ExampleJSON
{
  "status": "error",
  "message": "amount is required"
}