Learn how to accept payments, manage transactions, and handle callbacks with YaYa Wallet's payment integration
Welcome to the YaYa Wallet Payment Integration documentation. This guide will help you integrate our payment processing system into your application. Our API is RESTful and uses JSON for request and response bodies.
Get started quickly with our Postman collection:
The YaYa Wallet Payment Integration consists of several key components and follows this payment flow:
Key features of the system:
POST /api/auth/token
Obtain an access token for API authentication.
Request:
{
"client_id": "your_client_id",
"client_secret": "your_client_secret",
"grant_type": "client_credentials"
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "user"
}
Include the access token in the Authorization header for all authenticated requests:
Authorization: Bearer your_access_token
POST /api/payment-intent
Creates a new payment intent. Requires OAuth2 authentication.
Request:
{
"bankBic": "YAYAETAA",
"bankAccount": "antenehgebey",
"amount": 1000,
"paymentReference": "INV-005",
"description": "June bill",
"feeOnMerchant": true,
"returnUrl": "https://yourwebsite.com/thank-you",
"callbackUrl": "https://6833e09e464b499636008b3e.mockapi.io/callback",
"meta_data": {
"customer_id": "1234",
"customer_name": "Abebe Kebede",
"customer_phone": "0911059599"
}
}
Response:
{
"success": true,
"data": {
"id": "0ec6005f-820c-4ab4-84aa-2311fb8262f7",
"urlSlug": "92AE1D227EE1",
"paymentCode": "92AE1D227EE1",
"paymentReference": "INV-0895",
"amount": 1000,
"currency": "ETB",
"processingFee": 20,
"total": 1020,
"bankBic": "YAYAETAA",
"bankAccount": "antenehgebey",
"feeOnMerchant": true,
"status": "pending",
"qrCode": "00020101021228630032ee5b47b18b3544a0960673b04df2c0b70108YAYAETAA0211911655619_s52045411530323054071000.005802ET5926SUNRISE FOOD COMPLEX P L C6011Addis Abeba62430108INV-08950211911655619_s0612yayacheckout6304B01D",
"description": "June bill",
"cardPaymentUrl": null,
"paymentLink": "http://localhost:8080/p/92AE1D227EE1",
"thankYouUrl": "https://env-url/ty/92AE1D227EE1",
"returnUrl": "https://yourwebsite.com/thank-you",
"callbackUrl": "https://6833e09e464b499636008b3e.mockapi.io/callback",
"metaData": {
"customer_id": "1234",
"customer_name": "Abebe Kebede",
"customer_phone": "0911059599"
},
"createdAt": "2025-06-01T09:27:32.070Z",
"updatedAt": "2025-06-01T09:27:32.070Z"
}
}
After creating a payment intent, you must share the paymentLink with the payer to receive payment. You can either:
The payment link is the primary way for payers to complete their payment. Without sharing this link, the payer won't be able to make the payment.
Alternative Payment Method: You may also share the payment code with the payer, who can then make a direct bank transfer to YaYa Wallet account 7777. The payer must include the payment code in the transfer reason/message field for proper payment matching.
GET /api/payment-intents
Retrieves paginated list of payment intents for the authenticated merchant. Requires OAuth2 authentication.
Headers:
Authorization: Bearer your_access_token
Query Parameters:
- page: Page number (default: 1)
- limit: Items per page (default: 10)
- status: Filter by status (pending, paid, failed)
- startDate: Filter by start date (YYYY-MM-DD)
- endDate: Filter by end date (YYYY-MM-DD)
- sortBy: Sort field (created_at, updated_at, amount, status)
- sortOrder: Sort order (asc, desc)
- customerId: Filter by customer_id from meta_data
Response:
{
"draw": 1,
"recordsTotal": 100,
"recordsFiltered": 100,
"data": [
{
"id": "uuid",
"amount": 1000.00,
"processingFee": 25.00,
"total": 1025.00,
"status": "paid",
"merchantName": "Example Store",
"paymentReference": "INV-001",
"transactionReference": "TRX123456",
"urlSlug": "example-store",
"createdAt": "2024-03-20T10:00:00Z",
"updatedAt": "2024-03-20T10:05:00Z",
"paymentLink": "https://env-url/p/example-store",
"thankYouUrl": "https://env-url/ty/example-store",
"localization": {
"formattedAmount": "ETB 1,000.00",
"formattedProcessingFee": "ETB 25.00",
"formattedTotal": "ETB 1,025.00",
"createdAt": "Mar 20, 2024 10:00 AM",
"updatedAt": "Mar 20, 2024 10:05 AM"
},
"urlSlug": "example-store"
}
]
}
GET /api/payment-info/:urlSlug
Retrieves detailed information about a specific payment intent using the URL slug. Requires OAuth2 authentication.
Headers:
Authorization: Bearer your_access_token
Response:
{
"id": "uuid",
"amount": 1000.00,
"processingFee": 25.00,
"total": 1025.00,
"status": "paid",
"merchantName": "Example Store",
"paymentReference": "INV-001",
"transactionReference": "TRX123456",
"urlSlug": "example-store",
"createdAt": "2024-03-20T10:00:00Z",
"updatedAt": "2024-03-20T10:05:00Z",
"paymentLink": "https://env-url/p/example-store",
"thankYouUrl": "https://env-url/ty/example-store",
"localization": {
"formattedAmount": "ETB 1,000.00",
"formattedProcessingFee": "ETB 25.00",
"formattedTotal": "ETB 1,025.00",
"createdAt": "Mar 20, 2024 10:00 AM",
"updatedAt": "Mar 20, 2024 10:05 AM"
},
"beneficiaryAccountDetails": {
"bankBic": "YAYAETAA",
"bankAccount": "1234567890",
"accountHolderName": "Example Store"
}
}
DELETE /api/payment-intent/:paymentId/cancel
Cancels a pending payment intent by payment ID. Requires OAuth2 authentication.
Headers:
Authorization: Bearer your_access_token
Response:
{
"success": true,
"message": "Payment intent cancelled successfully",
"data": {
"paymentIntentId": "uuid",
"paymentId": "uuid",
"uniqueRef": "string"
}
}
GET /api/payment-intent/generate-reference
Generates a unique merchant reference for new transactions. Requires OAuth2 authentication.
Response:
{
"reference": "INV-123456"
}
GET /api/banks
Retrieves a list of all supported banks and their details. Requires OAuth2 authentication.
Response:
[
{
"bic": "CBEETAA",
"name": "Commercial Bank of Ethiopia",
"logo": "https://env-url/images/banks/cbe.png"
},
{
"bic": "YAYAETAA",
"name": "YaYa Wallet",
"logo": "https://env-url/images/banks/yaya.png"
}
]
GET /api/merchant-categories
Retrieves a list of all supported merchant categories (MCC codes) and their descriptions. Requires OAuth2 authentication.
Response:
[
{
"code": "5411",
"description": "Retail stores primarily selling food and household items"
},
{
"code": "5812",
"description": "Establishments primarily engaged in preparing and serving meals"
},
{
"code": "5311",
"description": "Retail stores selling a wide variety of merchandise"
}
]
Below is a comprehensive list of all fields used in the payment system, their purposes, and important notes about their usage.
| Field | Description | Notes |
|---|---|---|
| Request Fields | Required fields in the request payload: | |
| bankBic | Bank Identifier Code for routing payments. |
|
| bankAccount | Account identifier for receiving payments. |
|
| amount | Payment amount in ETB. |
|
| paymentReference | Unique identifier for the payment. |
|
| feeOnMerchant | Determines who pays the processing fee. |
⚠️ Warning: Based on specific agreements arranged with YaYa Wallet, the
fee_on_merchant setting can be enforced at the account level. In such cases, whatever value is passed in the payload will be overridden by the enforced setting from your account configuration.
|
| callbackUrl | URL for payment status updates. |
|
| meta_data | Optional JSON object containing additional metadata. |
|
| Response Fields | Important fields in the response: | |
| urlSlug | Short identifier for payment URLs. |
|
| processingFee | Fee charged for processing the payment. |
|
| qrCode | QR code for mobile payment. |
|
| paymentLink | URL for the payment page. |
|
The payment intent system supports optional metadata that can be used to store additional information about the payment, such as customer details, order information, or any other relevant data.
The meta_data field accepts a JSON object with any key-value pairs. Here are some common use cases:
{
"customer_id": "1234",
"customer_name": "Abebe Kebede",
"customer_phone": "0911059599",
"order_id": "ORD-001",
"invoice_number": "INV-2024-001",
"notes": "Special delivery instructions"
}
Certain fields in the meta_data have special functionality:
Used for filtering payment intents in the list API. You can retrieve all payments for a specific customer by including the customerId query parameter.
GET /api/payment-intents?customerId=1234
When present, this phone number will be automatically prefilled in the USSD payment form, making it easier for customers to complete their payment.
All meta_data fields are displayed in the payment intent details page under the "Additional Information" section, making it easy to view all associated data for a payment.
Our system sends payment status updates to your callback URL. It's recommended to use a unique callback URL for each payment intent to better track and manage payments.
POST your_callback_url
Headers:
Content-Type: application/json
X-Payment-Signature: generated_signature
Request Body:
{
"paymentId": "7d31bd3f-6223-4b14-b174-584913f39323",
"paymentReference": "INV-005",
"amount": 1000,
"isFeeOnMerchant": true,
"processingFee": "20.00",
"status": "paid",
"bankBic": "YAYAETAA",
"bankAccount": "antenehgebey",
"paymentCode": "CAE8CD8E4901",
"transactionId": "TXN-7497B30295A1D9AD",
"paymentLink": "https://pay.yayawallet.com/p/CAE8CD8E4901",
"thankYouUrl": "https://env-url/ty/CAE8CD8E4901",
"returnUrl": "https://yourwebsite.com/thank-you",
"timestamp": "2025-06-01T08:31:46.091Z",
"createdAt": "2025-06-01T08:30:08.046Z",
"updatedAt": "2025-06-01T08:31:46.088Z"
}
To ensure the callback is legitimate, validate the signature using the following process:
paymentId + paymentReference + amountExample validation in Node.js:
const crypto = require('crypto');
function validateSignature(paymentId, paymentReference, amount, signature, clientSecret) {
const data = `${paymentId}${paymentReference}${amount}`;
const expectedSignature = crypto.createHmac('sha256', clientSecret)
.update(data)
.digest('hex');
return signature === expectedSignature;
}
// Example usage in Express middleware
app.post('/payment-callback', (req, res) => {
const signature = req.headers['x-payment-signature'];
const { paymentId, paymentReference, amount } = req.body;
if (!validateSignature(paymentId, paymentReference, amount, signature, process.env.CLIENT_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the payment notification
// ...
res.status(200).json({ received: true });
});