How to Use DecodeHash Free API
Learn how to decode Mpesa hashes using our Free API.
Introduction
Welcome to the DecodeHash Free API user guide.
Whether you're a developer integrating Mpesa hash decoding into your application, an analyst exploring how to decode hashed MSISDN, or simply curious about how the process works, this guide will provide you with step-by-step instructions for effective API usage.
Decoding M-Pesa Till or Paybill Customer Numbers
When receiving payments to your M-Pesa till or paybill, Safaricom now provides a hashed version of the customer's phone number instead of the actual number. To decode or reveal the customer number from these mpesa till or paybill transactions, our Free API can help. You can easily query the original phone number by providing the hash from the transaction notification.
(Please note: If you integrate your till or paybill directly with our portal, manual decoding is unnecessary. Our system automatically handles the decoding of customer phone numbers for you.)
Getting Started
DecodeHash's Free API offers a simple and efficient way to decode Mpesa hashes.
Follow the steps below to get started decoding Mpesa hashes today!
Here's how to start using the Free API to decode Mpesa hashes:
-
On Windows, you can use the command shell and execute the following command:
curl -X GET "https://decodehash.com/app/api/v1/decode-hash/free/some-sha-hash" -H "Accept: application/json" -
In Windows, you can use powershell to execute the following command:
Invoke-RestMethod -Uri "https://decodehash.com/app/api/v1/decode-hash/free/some-sha-hash" -Headers @{"Accept" = "application/json"} -
In macOs or Linux, you can use the terminal to execute the following command:
curl -X GET "https://decodehash.com/app/api/v1/decode-hash/free/some-sha-hash" -H "Accept: application/json" -
In Postman, you can decode the MSISDN using the following steps:
- Create a new GET request.
- Enter the URL as
https://decodehash.com/app/api/v1/decode-hash/free/some-sha-hash -
Click on Headers tab and add the following headers:
- Key: Accept
- Value: application/json
- Click Send.
Understanding the Response
Each API call returns a JSON body with the decoded data and important headers that provide information about your current usage quota. If you exceed your quota, you will receive an `HTTP 429 Too Many Requests` error along with a `Retry-After` header indicating how many seconds to wait before trying again.
Response Headers
The following headers are included with every API response to help you track your usage:
X-RateLimit-Limit: The total number of requests allowed in the current time window (10 for the free tier).X-RateLimit-Remaining: The number of requests you have left in the current time window.X-RateLimit-Reset: The time when your quota will reset, provided as a UNIX timestamp.-
X-Warning: This header will appear with a warning message when your remaining request balance drops to 20% or less of your total quota.
Examples for Developers
Below are examples of sending a request to the API and accessing the response headers in various popular languages:
# Use the -i flag to include response headers in the output
curl -i -X GET "https://decodehash.com/app/api/v1/decode-hash/free/some-sha-hash" \
-H "Accept: application/json"
# Sample Output (Successful):
# HTTP/2 200
# content-type: application/json
# x-ratelimit-limit: 10
# x-ratelimit-remaining: 9
# x-ratelimit-reset: 1731888000
# ...
#
# {"hash":"some-sha-hash","msisdn":"254700123456"}
# Sample Output (Rate Limited):
# HTTP/2 429 Too Many Requests
# retry-after: 3600
# ...
import requests
import json
import time
from typing import Optional
from pydantic import BaseModel
class DecodeHashResponseModel(BaseModel):
msisdn: Optional[str] = None
hash: Optional[str] = None
success: Optional[bool] = False
detail: Optional[str] = None
SERVER = "https://decodehash.com"
DECODEHASH_END_POINT = "/app/api/v1/decode-hash/free/"
def get_msisdn(hash_str: str) -> DecodeHashResponseModel:
url = f"{SERVER}{DECODEHASH_END_POINT}{hash_str}"
headers = {"Accept": "application/json"}
try:
response = requests.get(url, headers=headers)
# Access and print rate limit headers
print("--- Rate Limit Headers ---")
print(f"Limit: {response.headers.get('X-RateLimit-Limit')}")
print(f"Remaining: {response.headers.get('X-RateLimit-Remaining')}")
print(f"Reset: {response.headers.get('X-RateLimit-Reset')}")
print("--------------------------")
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
print(f"Rate limit exceeded. Retrying in {retry_after} seconds.")
time.sleep(retry_after)
return get_msisdn(hash_str) # Retry the request
response.raise_for_status() # Raise an exception for bad status codes
data = response.json()
return DecodeHashResponseModel(
msisdn=data.get("msisdn"),
hash=data.get("hash"),
success=True
)
except requests.exceptions.RequestException as e:
print(f"Error fetching data: {e}")
return DecodeHashResponseModel(success=False, detail=str(e))
# Test the function
if __name__ == "__main__":
hash_str = "some-sha-hash"
get_msisdn_response = get_msisdn(hash_str)
print(f"Response model: {get_msisdn_response}")
const axios = require('axios');
const SERVER = "https://decodehash.com";
const DECODEHASH_END_POINT = "/app/api/v1/decode-hash/free/";
async function getMsisdn(hashStr) {
const url = `${SERVER}${DECODEHASH_END_POINT}${hashStr}`;
const headers = { "Accept": "application/json" };
try {
const response = await axios.get(url, { headers });
// Access and print rate limit headers
console.log("--- Rate Limit Headers ---");
console.log(`Limit: ${response.headers['x-ratelimit-limit']}`);
console.log(`Remaining: ${response.headers['x-ratelimit-remaining']}`);
console.log(`Reset: ${response.headers['x-ratelimit-reset']}`);
console.log("--------------------------");
return { ...response.data, success: true };
} catch (error) {
if (error.response && error.response.status === 429) {
const retryAfter = parseInt(error.response.headers['retry-after'] || '60', 10);
console.log(`Rate limit exceeded. Retrying in ${retryAfter} seconds.`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
return getMsisdn(hashStr); // Retry the request
}
console.error(`Error fetching data: ${error.message}`);
return { success: false, detail: error.message };
}
}
// Test the function
(async () => {
const hashStr = "some-sha-hash";
const getMsisdnResponse = await getMsisdn(hashStr);
console.log(`Response: ${JSON.stringify(getMsisdnResponse)}`);
})();
package main
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
)
type DecodeHashResponse struct {
Msisdn *string `json:"msisdn"`
Hash *string `json:"hash"`
Success bool `json:"success"`
Detail *string `json:"detail"`
}
const (
Server = "https://decodehash.com"
DecodeHashEndPoint = "/app/api/v1/decode-hash/free/"
)
func getMsisdn(hashStr string) (DecodeHashResponse, error) {
url := Server + DecodeHashEndPoint + hashStr
client := &http.Client{Timeout: 10 * time.Second}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Accept", "application/json")
resp, err := client.Do(req)
if err != nil {
return DecodeHashResponse{Success: false}, err
}
defer resp.Body.Close()
// Access and print rate limit headers
fmt.Println("--- Rate Limit Headers ---")
fmt.Printf("Limit: %s\n", resp.Header.Get("X-RateLimit-Limit"))
fmt.Printf("Remaining: %s\n", resp.Header.Get("X-RateLimit-Remaining"))
fmt.Printf("Reset: %s\n", resp.Header.Get("X-RateLimit-Reset"))
fmt.Println("--------------------------")
if resp.StatusCode == http.StatusTooManyRequests {
retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After"))
if retryAfter == 0 {
retryAfter = 60
}
fmt.Printf("Rate limit exceeded. Retrying in %d seconds.\n", retryAfter)
time.Sleep(time.Duration(retryAfter) * time.Second)
return getMsisdn(hashStr) // Retry
}
if resp.StatusCode != http.StatusOK {
return DecodeHashResponse{Success: false}, fmt.Errorf("bad status: %s", resp.Status)
}
var result DecodeHashResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return DecodeHashResponse{Success: false}, err
}
result.Success = true
return result, nil
}
func main() {
hashStr := "some-sha-hash"
getMsisdnResponse, err := getMsisdn(hashStr)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
responseJSON, _ := json.MarshalIndent(getMsisdnResponse, "", " ")
fmt.Printf("Response: %s\n", string(responseJSON))
}
Notes
The free API has a limit of 10 requests per day.
If you would like to increase your daily limit, please sign up for a free account.