Code samples

Copy-paste starting points for common integration tasks. Replace placeholders with your credentials and business references.

Build the Authorization header

const crypto = require('crypto');

function lipachapAuthHeader(apiKey, apiSecret, requestPath, rawBody = '') {
  const digest = crypto
    .createHash('sha256')
    .update(apiSecret + requestPath + rawBody)
    .digest('hex');
  const token = Buffer.from(`${apiKey}:${digest}`).toString('base64');
  return `GATEWAY ${token}`;
}

// Example
const path = '/v1/walletcashin/process';
const body = JSON.stringify({
  transid: 'TXN-001',
  amount: 5000,
  msisdn: '255712345678',
  utilityref: 'ORDER-123',
  utilitycode: 'VMCASHIN',
  vendor: 'YOUR_VENDOR',
  pin: '0000',
});
const authorization = lipachapAuthHeader(process.env.LIPACHAP_API_KEY, process.env.LIPACHAP_API_SECRET, path, body);
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import org.apache.commons.codec.digest.DigestUtils;

public final class LipachapAuth {
  public static String authorizationHeader(String apiKey, String apiSecret, String path, String rawBody) {
    String signed = apiSecret + path + (rawBody == null ? "" : rawBody);
    String digest = DigestUtils.sha256Hex(signed);
    String credentials = apiKey + ":" + digest;
    return "GATEWAY " + Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8));
  }
}

// Usage
String path = "/v1/walletcashin/process";
String body = "{\"transid\":\"TXN-001\",\"amount\":5000,\"msisdn\":\"255712345678\"}";
String auth = LipachapAuth.authorizationHeader(apiKey, apiSecret, path, body);
<?php

function lipachap_auth_header(string $apiKey, string $apiSecret, string $path, string $rawBody = ''): string {
    $digest = hash('sha256', $apiSecret . $path . $rawBody);
    $token = base64_encode($apiKey . ':' . $digest);
    return 'GATEWAY ' . $token;
}

$path = '/v1/walletcashin/process';
$body = json_encode([
    'transid' => 'TXN-001',
    'amount' => 5000,
    'msisdn' => '255712345678',
    'utilityref' => 'ORDER-123',
], JSON_UNESCAPED_SLASHES);

$authorization = lipachap_auth_header(getenv('LIPACHAP_API_KEY'), getenv('LIPACHAP_API_SECRET'), $path, $body);
import base64
import hashlib
import json
import os

def lipachap_auth_header(api_key: str, api_secret: str, path: str, raw_body: str = "") -> str:
    digest = hashlib.sha256((api_secret + path + raw_body).encode("utf-8")).hexdigest()
    token = base64.b64encode(f"{api_key}:{digest}".encode("utf-8")).decode("ascii")
    return f"GATEWAY {token}"

path = "/v1/walletcashin/process"
body = json.dumps({
    "transid": "TXN-001",
    "amount": 5000,
    "msisdn": "255712345678",
    "utilityref": "ORDER-123",
    "utilitycode": "VMCASHIN",
    "vendor": "YOUR_VENDOR",
    "pin": "0000",
}, separators=(",", ":"))

authorization = lipachap_auth_header(
    os.environ["LIPACHAP_API_KEY"],
    os.environ["LIPACHAP_API_SECRET"],
    path,
    body,
)
package lipachap

import (
    "crypto/sha256"
    "encoding/base64"
    "encoding/hex"
    "fmt"
)

func AuthHeader(apiKey, apiSecret, path, rawBody string) string {
    sum := sha256.Sum256([]byte(apiSecret + path + rawBody))
    digest := hex.EncodeToString(sum[:])
    token := base64.StdEncoding.EncodeToString([]byte(apiKey + ":" + digest))
    return "GATEWAY " + token
}

// Usage in a handler:
// path := "/v1/walletcashin/process"
// body := `{"transid":"TXN-001","amount":5000,"msisdn":"255712345678"}`
// req.Header.Set("Authorization", AuthHeader(apiKey, apiSecret, path, body))

Collection (CASHIN)

const baseUrl = process.env.LIPACHAP_BASE_URL; // sandbox or live
const path = '/v1/walletcashin/process';
const body = JSON.stringify({
  transid: 'TXN-' + Date.now(),
  utilitycode: 'VMCASHIN',
  utilityref: 'ORDER-123',
  amount: 5000,
  msisdn: '255712345678',
  vendor: 'YOUR_VENDOR',
  pin: '0000',
});

const res = await fetch(baseUrl + path, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: lipachapAuthHeader(apiKey, apiSecret, path, body),
    'X-Request-Id': crypto.randomUUID(),
  },
  body,
});

const data = await res.json();
// { resultcode: '000', result: 'SUCCESS', reference, transid, status, ... }
String path = "/v1/walletcashin/process";
JsonObject payload = new JsonObject();
payload.addProperty("transid", "TXN-" + System.currentTimeMillis());
payload.addProperty("utilitycode", "VMCASHIN");
payload.addProperty("utilityref", "ORDER-123");
payload.addProperty("amount", 5000);
payload.addProperty("msisdn", "255712345678");
payload.addProperty("vendor", "YOUR_VENDOR");
payload.addProperty("pin", "0000");

String body = payload.toString();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", LipachapAuth.authorizationHeader(apiKey, apiSecret, path, body));

ResponseEntity<String> response = restTemplate.exchange(
    baseUrl + path, HttpMethod.POST, new HttpEntity<>(body, headers), String.class);
$path = '/v1/walletcashin/process';
$payload = [
    'transid' => 'TXN-' . time(),
    'utilitycode' => 'VMCASHIN',
    'utilityref' => 'ORDER-123',
    'amount' => 5000,
    'msisdn' => '255712345678',
    'vendor' => 'YOUR_VENDOR',
    'pin' => '0000',
];
$body = json_encode($payload, JSON_UNESCAPED_SLASHES);

$ch = curl_init(getenv('LIPACHAP_BASE_URL') . $path);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $body,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: ' . lipachap_auth_header(getenv('LIPACHAP_API_KEY'), getenv('LIPACHAP_API_SECRET'), $path, $body),
    ],
]);
$response = curl_exec($ch);
import requests

path = "/v1/walletcashin/process"
payload = {
    "transid": f"TXN-{int(time.time())}",
    "utilitycode": "VMCASHIN",
    "utilityref": "ORDER-123",
    "amount": 5000,
    "msisdn": "255712345678",
    "vendor": "YOUR_VENDOR",
    "pin": "0000",
}
body = json.dumps(payload, separators=(",", ":"))

response = requests.post(
    os.environ["LIPACHAP_BASE_URL"] + path,
    data=body,
    headers={
        "Content-Type": "application/json",
        "Authorization": lipachap_auth_header(api_key, api_secret, path, body),
    },
    timeout=30,
)
data = response.json()
path := "/v1/walletcashin/process"
body := `{"transid":"TXN-001","utilitycode":"VMCASHIN","utilityref":"ORDER-123","amount":5000,"msisdn":"255712345678","vendor":"YOUR_VENDOR","pin":"0000"}`

req, _ := http.NewRequest(http.MethodPost, baseURL+path, strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", AuthHeader(apiKey, apiSecret, path, body))

resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

Disbursement (CASHOUT)

const path = '/v1/gateway/cashin';
const body = JSON.stringify({
  transid: 'PAYOUT-' + Date.now(),
  utilityref: 'DISB-456',
  amount: 10000,
  msisdn: '255712345678',
  vendor: 'YOUR_VENDOR',
  pin: '0000',
  providerFee: 0,
  platformFee: 150,
  totalFee: 150,
  totalCharged: 10150,
});

const res = await fetch(baseUrl + path, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: lipachapAuthHeader(apiKey, apiSecret, path, body),
  },
  body,
});
String path = "/v1/gateway/cashin";
JsonObject payload = new JsonObject();
payload.addProperty("transid", "PAYOUT-" + System.currentTimeMillis());
payload.addProperty("utilityref", "DISB-456");
payload.addProperty("amount", 10000);
payload.addProperty("msisdn", "255712345678");
payload.addProperty("vendor", "YOUR_VENDOR");
payload.addProperty("pin", "0000");
payload.addProperty("providerFee", 0);
payload.addProperty("platformFee", 150);
payload.addProperty("totalFee", 150);
payload.addProperty("totalCharged", 10150);

String body = payload.toString();
// POST with Authorization header (same as cash-in)
$path = '/v1/gateway/cashin';
$body = json_encode([
    'transid' => 'PAYOUT-' . time(),
    'utilityref' => 'DISB-456',
    'amount' => 10000,
    'msisdn' => '255712345678',
    'vendor' => 'YOUR_VENDOR',
    'pin' => '0000',
    'providerFee' => 0,
    'platformFee' => 150,
    'totalFee' => 150,
    'totalCharged' => 10150,
], JSON_UNESCAPED_SLASHES);
path = "/v1/gateway/cashin"
body = json.dumps({
    "transid": f"PAYOUT-{int(time.time())}",
    "utilityref": "DISB-456",
    "amount": 10000,
    "msisdn": "255712345678",
    "vendor": "YOUR_VENDOR",
    "pin": "0000",
    "providerFee": 0,
    "platformFee": 150,
    "totalFee": 150,
    "totalCharged": 10150,
}, separators=(",", ":"))
path := "/v1/gateway/cashin"
body := `{"transid":"PAYOUT-001","utilityref":"DISB-456","amount":10000,"msisdn":"255712345678","vendor":"YOUR_VENDOR","pin":"0000","totalCharged":10150}`
req.Header.Set("Authorization", AuthHeader(apiKey, apiSecret, path, body))

Transaction status

const path = '/v1/checkout/status';
const body = JSON.stringify({ transid: 'TXN-001' });

const res = await fetch(baseUrl + path, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: lipachapAuthHeader(apiKey, apiSecret, path, body),
  },
  body,
});

const txn = await res.json();
// status: PENDING | SUCCESS | FAILED
String path = "/v1/checkout/status";
JsonObject payload = new JsonObject();
payload.addProperty("transid", "TXN-001");
String body = payload.toString();
// POST with signed Authorization header
$path = '/v1/checkout/status';
$body = json_encode(['transid' => 'TXN-001'], JSON_UNESCAPED_SLASHES);
path = "/v1/checkout/status"
body = json.dumps({"transid": "TXN-001"}, separators=(",", ":"))
path := "/v1/checkout/status"
body := `{"transid":"TXN-001"}`

Verify webhooks

const crypto = require('crypto');

function verifyWebhook(rawBody, timestamp, signature, secret, maxSkewSec = 300) {
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - Number(timestamp)) > maxSkewSec) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex');

  const received = signature.replace(/^sha256=/, '');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}

// Express example
app.post('/webhooks/lipachap', express.raw({ type: 'application/json' }), (req, res) => {
  const rawBody = req.body.toString('utf8');
  const ok = verifyWebhook(
    rawBody,
    req.get('X-Gateway-Timestamp'),
    req.get('X-Gateway-Signature'),
    process.env.LIPACHAP_WEBHOOK_SECRET,
  );
  if (!ok) return res.sendStatus(401);

  const event = JSON.parse(rawBody);
  // event.transid, event.status, event.amount, ...
  res.sendStatus(200);
});
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public boolean verifyWebhook(String rawBody, String timestamp, String signature, String secret) {
    String payload = timestamp + "." + rawBody;
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
    String expected = HexFormat.of().formatHex(mac.doFinal(payload.getBytes(StandardCharsets.UTF_8)));
    String received = signature.replace("sha256=", "");
    return MessageDigest.isEqual(expected.getBytes(), received.getBytes());
}
function verify_lipachap_webhook(string $rawBody, string $timestamp, string $signature, string $secret): bool {
    $expected = hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);
    $received = preg_replace('/^sha256=/', '', $signature);
    return hash_equals($expected, $received);
}

$rawBody = file_get_contents('php://input');
$ok = verify_lipachap_webhook(
    $rawBody,
    $_SERVER['HTTP_X_GATEWAY_TIMESTAMP'] ?? '',
    $_SERVER['HTTP_X_GATEWAY_SIGNATURE'] ?? '',
    getenv('LIPACHAP_WEBHOOK_SECRET'),
);
import hmac
import hashlib
import time

def verify_webhook(raw_body: bytes, timestamp: str, signature: str, secret: str, max_skew: int = 300) -> bool:
    if abs(int(time.time()) - int(timestamp)) > max_skew:
        return False
    expected = hmac.new(secret.encode(), f"{timestamp}.{raw_body.decode()}".encode(), hashlib.sha256).hexdigest()
    received = signature.removeprefix("sha256=")
    return hmac.compare_digest(expected, received)
func VerifyWebhook(rawBody []byte, timestamp, signature, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(timestamp + "." + string(rawBody)))
    expected := hex.EncodeToString(mac.Sum(nil))
    received := strings.TrimPrefix(signature, "sha256=")
    return hmac.Equal([]byte(expected), []byte(received))
}