Appearance
Merchant API Redemption
Use this flow for server-to-server voucher redemption:
- Validate voucher
- Create claim and trigger OTP delivery
- Verify OTP to complete settlement
Required Headers
All merchant redemption endpoints require signed requests.
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Merchant API credential. |
X-Timestamp | Yes | ISO timestamp used in signature verification; allowed skew is 5 minutes. |
X-Signature | Yes | Base64 Ed25519 signature of the canonical request string. |
Idempotency-Key | Yes | Required for all merchant redemption POST endpoints. |
X-Correlation-Id | No | Optional correlation value for tracing. |
User-Agent | No | Optional client identifier. |
Flow
Validate Voucher
POST /merchant-api/vouchers/validate
Request Body
| Field | Type | Required | Rules |
|---|---|---|---|
voucherCode | string | Yes | Issued voucher code. API accepts up to 32 chars, strips -, then validates the normalized 16-digit code. |
Voucher Code Rules
- Use the 16-digit voucher code from issuance, for example
9876543210987654. - Hyphens in input are ignored before validation.
- Do not use the issuance
serialNumber(VCH-...) as a redemption code.
Example Request
bash
curl -X POST "$API_BASE_URL/merchant-api/vouchers/validate" \
-H "Content-Type: application/json" \
-H "X-API-Key: $MERCHANT_API_KEY" \
-H "X-Timestamp: 2026-04-29T12:00:00.000Z" \
-H "X-Signature: $MERCHANT_SIGNATURE" \
-H "Idempotency-Key: 5b1ee3c0-4b28-4f68-9be8-b86ec2b7d4a1" \
-H "X-Correlation-Id: red_01HWJ9S8E4Y9G7E4F6N5Q2P3Z8" \
-d '{
"voucherCode": "9876543210987654"
}'Example Response
json
{
"id": 123,
"code": "9876543210987654",
"ownerNumber": "+251911234567",
"ownerName": "Abebe Kebede",
"originalAmount": "500.00",
"remainingBalance": "350.00",
"totalRedeemed": "150.00",
"status": "PARTIALLY_REDEEMED",
"isRestricted": true,
"originatingMerchantId": 12,
"originatingMerchantName": "Abyssinia Market",
"expirationDate": "2026-07-27T23:59:59.000Z"
}Initiate Claim
POST /merchant-api/claims
Request Body
| Field | Type | Required | Rules |
|---|---|---|---|
voucherId | number | Yes | Integer, minimum 1. |
amount | string | Yes | Positive decimal amount to redeem. JSON numbers are accepted and normalized to string. |
Example Request
bash
curl -X POST "$API_BASE_URL/merchant-api/claims" \
-H "Content-Type: application/json" \
-H "X-API-Key: $MERCHANT_API_KEY" \
-H "X-Timestamp: 2026-04-29T12:00:00.000Z" \
-H "X-Signature: $MERCHANT_SIGNATURE" \
-H "Idempotency-Key: 7afc7c5f-4470-4a74-8a8f-f53ac9f2b81a" \
-H "X-Correlation-Id: red_01HWJ9S8E4Y9G7E4F6N5Q2P3Z8" \
-d '{
"voucherId": 123,
"amount": "50.00"
}'Example Response
json
{
"claimId": 7721,
"otpExpiresAt": "2026-04-27T08:05:00.000Z",
"maskedPhone": "+2519*****67"
}Verification Step
Use Claim Verification to submit OTP and finalize the claim.
Response Codes
| Code | Meaning |
|---|---|
200 | Voucher validation succeeded. |
201 | Claim created and OTP issued. |
400 | Invalid payload or missing/invalid required header (including Idempotency-Key). |
401 | Missing or invalid auth/signature headers. |
403 | Access forbidden (for example IP allowlist policy). |
404 | Voucher or claim not found. |
409 | Idempotency conflict or request with same key still in progress. |
429 | Retry limit or cooldown reached for voucher attempts. |
500 | Unexpected server error. |
Redemption Checks
| Field | Meaning |
|---|---|
remainingBalance | Maximum redeemable amount for the voucher. |
status | Voucher must be redeemable (ACTIVE or PARTIALLY_REDEEMED). |
isRestricted | When true, redemption is limited to the originating merchant. |
expirationDate | Voucher expiration timestamp when configured. |