How to Use DecodeHash Free API with an API Key

Learn how to decode Mpesa hashes using our Free API with an API Key.

Introduction

Welcome to the DecodeHash Free API user guide for signed up users.

Whether you're integrating Mpesa hash decoding into your application or exploring our API's capabilities, this guide will walk you through the process step-by-step.

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 Freemium 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

Here's how to start using the Free API to decode Mpesa hashes with an API Key:

  1. Sign up for a free account on DecodeHash.
  2. Once you've signed up, you will receive an email with a link to activate your account.
  3. Click the link in the email to activate your account. If you signed up using a Google account, you will not need to activate your account - your account will be automatically activated.
  4. You will be redirected to the Profile page.
  5. Click on the API Keys tab.
  6. Click on the Generate New API Key button.
  7. Enter a name for your API key. e.g Production API Key.
  8. Click on the Create API Key button.
  9. Your API key will be generated and displayed on the page.
  10. Copy the API key and save it somewhere safe.

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 (daily or annual).
  • X-RateLimit-Remaining: The number of requests you have left in the current time window.
  • X-RateLimit-Reset: The time when your daily 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 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/freemium/some-sha-hash" \
                  -H "Accept: application/json" \
                  -H "Authorization: Bearer YOUR_API_KEY"

                  # Sample Output (Successful):
                  # HTTP/2 200
                  # content-type: application/json
                  # x-ratelimit-limit: 50
                  # x-ratelimit-remaining: 49
                  # 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/freemium/"
                API_KEY = "YOUR_API_KEY" # Replace with your actual API key

                def get_msisdn(hash_str: str) -> DecodeHashResponseModel:
                    url = f"{SERVER}{DECODEHASH_END_POINT}{hash_str}"
                    headers = {"Accept": "application/json", "Authorization": f"Bearer {API_KEY}"}

                    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/freemium/";
                  const API_KEY = "YOUR_API_KEY"; // Replace with your actual API key

                  async function getMsisdn(hashStr) {
                      const url = `${SERVER}${DECODEHASH_END_POINT}${hashStr}`;
                      const headers = { "Accept": "application/json", "Authorization": `Bearer ${API_KEY}` };

                      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/freemium/"
                  APIKey           = "YOUR_API_KEY" // Replace with your actual API key
                )

                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")
                  req.Header.Set("Authorization", "Bearer "+APIKey)

                  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 50 requests per day.

If you would like to increase your daily limit, please contact us.

Last updated 1 month ago

Was this article helpful?