Developer Documentation

Learn how to accept payments, manage transactions, and handle callbacks with YaYa Wallet's payment integration

← Back to Home

Introduction

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.

Important Notice:
  • For any technical support or assistance, please call 957 or email

System Architecture

Merchant YaYa Wallet Payer Bank System 1. Create Payment 2. Share Payment Link 3. Make Payment 4. Process Payment 5. Payment Notification YaYa Wallet Payment Flow

The YaYa Wallet Payment Integration consists of several key components and follows this payment flow:

  1. Create Payment: Merchant creates a payment request through the YaYa Wallet
  2. Share Payment Link: System generates a unique payment link and QR code for the payer
  3. Make Payment: Payer completes the payment using their preferred method (QR code, USSD, card, etc.)
  4. Process Payment: Bank system processes the payment and notifies the YaYa Wallet
  5. Payment Notification: Merchant receives real-time notification of successful payment

Key features of the system:

API Endpoints

OAuth2 Authentication

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

Merchant Endpoints

Create Payment Request

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"
}

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",
        "createdAt": "2025-06-01T09:27:32.070Z",
        "updatedAt": "2025-06-01T09:27:32.070Z"
    }
}
Important Note:

After creating a payment intent, you must share the paymentLink with the payer to receive payment. You can either:

  • Redirect the payer to the payment link immediately after creating the payment intent
  • Share the payment link through your preferred communication channel (email, SMS, etc.)

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.

Code Examples

List Payment Intents

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)

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 Payment Details

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"
    }
}

Cancel Payment Intent

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"
    }
}

Generate Merchant Reference

GET /api/payment-intent/generate-reference

Generates a unique merchant reference for new transactions. Requires OAuth2 authentication.

Note: You can use your own reference numbers. The merchant reference should be unique within your merchant account.
Response:
{
    "reference": "INV-123456"
}

Lookup Endpoints

List Banks

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"
    }
]

List Merchant Categories

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"
    }
]

Field Descriptions

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.
  • Currently only supports "YAYAETAA"
  • Required for payment routing
bankAccount Account identifier for receiving payments.
  • Must be a valid account identifier
  • Must match the specified BIC
amount Payment amount in ETB.
  • Must be a positive integer
  • No decimal places allowed
paymentReference Unique identifier for the payment.
  • Must be unique within your account
  • Used for reconciliation
feeOnMerchant Determines who pays the processing fee.
  • true: merchant pays the fee
  • false: payer pays the fee
callbackUrl URL for payment status updates.
  • Required for real-time updates
  • Must be HTTPS
Response Fields Important fields in the response:
urlSlug Short identifier for payment URLs.
  • Used in payment and thank you URLs
  • Same as paymentCode
processingFee Fee charged for processing the payment.
  • Fixed amount in ETB
  • Added to total if feeOnMerchant is false
qrCode QR code for mobile payment.
  • Contains payment details
  • Can be scanned by mobile apps
paymentLink URL for the payment page.
  • Direct link to payment page
  • Format: {baseUrl}/p/{urlSlug}

Integration Steps

  1. Start with Sandbox Mode:
    • Register and obtain your API credentials
    • Set your environment to sandbox mode
    • Test the integration using supported payment methods
  2. Test with Payment Simulation:
    • Use the sandbox payment simulator to create and process test payments
    • Verify that your callback endpoint receives payment notifications
    • Monitor the payment status updates in real-time
  3. Switch to Live Mode:
    • Once testing is complete, switch to live mode
    • Update your API credentials for live environment
    • Start processing real transactions
Note: The sandbox environment is designed for testing and development. Use this environment to thoroughly test your integration with all supported payment methods before switching to live mode.

Callback Implementation

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.

Callback Request Format

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"
}

Signature Validation

To ensure the callback is legitimate, validate the signature using the following process:

  1. Concatenate the paymentId, paymentReference, and amount in this order: paymentId + paymentReference + amount
  2. Generate an HMAC SHA-256 hash using your client secret as the key
  3. Compare the generated hash with the signature in the X-Payment-Signature header
Example 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 });
});
Important:
  • Always validate the signature before processing the callback
  • Use a unique callback URL for each payment intent to prevent confusion
  • Implement proper error handling and logging for failed callbacks
  • Respond with a 200 status code to acknowledge receipt of the callback
  • Our system may retry failed callbacks multiple times. Implement idempotency to prevent duplicate processing of the same payment status update
  • Use the paymentId and transactionId to track and deduplicate callbacks

Security Considerations