Installation

This document covers how to get started with saga pay


All API request must come through POST call. The base POST URL is:

https://app.sagapay.net/api/v2

API Rate limit: 5 Calls Per Second. It is scalable and will Increase automatically if your application demands more.


                      https://app.sagapay.net/api/v2
                
              

Deposit

This document covers how to receive payment from customers using a deposit address

POST /deposit

To deposit token (eg: USDT, BUSD) you wallet must have sufficient Gas fee to cover incoming transactions. Else your deposit may fail. For BEP-20: it is 0.005 BNB, for TRC-20: it is 40 TRX and for ERC-20, it is 0.017 ETH. However for native crypto transfer (eg: BNB, TRX, ETH) no gas fee required. Gas fee will be deducted from the incoming balance itself.
Description

Generate a new deposit address of the given token ID.

Request
Headers:
Content-Type: application/json

Parameters

  • api_key (required): Your API key with 'CREATE_WITHDRAWAL' permission.
  • amount (required): The amount to be withdrawn in crypto.
  • ipn_url (required): The IPN URL to be notified when the withdrawal is processed.
  • token_id (required): The token ID of the cryptocurrency to be withdrawn.
  • udf (optional): Any user-defined field for additional information.
Body:
{
  "api_key": "your_api_key",
  "amount": 100.0, // in crypto
  "ipn_url": "https://example.com/ipn",
  "token_id": "USDT.BEP20",
  "udf": "optional_user_defined_field" // will be sent back with IPN notification
}
Get the Token IDs here →
Response
Success:
{
  "status": true,
  "message": "receiving_address",
  "timeout": 86400, // in seconds
  "qrcodeurl": "https://qrcodeurl.com?address=receiving_address"
}
Error:
{
  "status": false,
  "message": "Error message"
}

Create Withdrawal

Use this API to create a new withdrawal request. The request will be processed, and the specified amount will be withdrawn from the user's account.

POST /withdraw

For withdrawals, your Main wallet (native wallet, for BEP-20 token, its BNB) must have sufficient fund to cover gas fee for outgoing transactions. Else withdrawals will be halted.
Headers:
Content-Type: application/json

Parameters

  • api_key (required): Your API key with 'CREATE_DEPOSIT' permission.
  • api_secret (required): Your API secret (This should never be exposed to the client side.).
  • amount (required): The amount to be withdrawn in crypto.
  • ipn_url (required): The IPN URL to be notified when the withdrawal is processed.
  • token_id (required): The token ID of the cryptocurrency to be withdrawn.
  • withdrawal_address (required): The withdrawal address to send the funds.
  • udf (optional): Any user-defined field for additional information.
              
                {
                  "api_key": "your_api_key_with_CREATE_WITHDRAWAL_permission",
                  "api_secret": "your_api_secret",
                  "amount": 100,
                  "ipn_url": "https://yourdomain.com/ipn",
                  "token_id": "your_token_id",
                  "withdrawal_address": "your_withdrawal_address",
                  "udf": "your_optional_additional_information"
              }
              
              
            
Get the Token IDs here →

Response

If the withdrawal request is successfully created, the API will return a JSON object with a "status" field set to "true" and a "message" field containing the withdrawal ID. If there is an error, the "status" field will be "false" and the "message" field will contain an error description.

{ "status": true, "message": "withdrawal_id" }

Check Balance

Check Balance in your Activated wallet. Balance will be fetched from Blockchain Directly.

POST /check-balance

Request
Headers:
Content-Type: application/json

Parameters

  • api_key (required): Your API key with 'READ_WALLET_BALANCE' permission.
  • token_id (required): The token ID of the cryptocurrency to be withdrawn.
Body:
{
  "api_key": "your_api_key",
  "token_id": "USDT.BEP20",
}
Get the Token IDs here →
Response
Success:
{
  "status": true,
  "message":1,
  "token": "BNB",
}

IPN Notification

This documentation describes how IPN notifications are sent to your specified IPN URL.

IPN Payload

When a deposit or withdrawal event occurs, an IPN notification will be sent as an HTTP POST request to the provided IPN URL. The payload will be in JSON format, with the following fields:

Field Type Description
txn_hash string The transaction hash for the deposit or withdrawal.
ipn_type string The type of event, either "deposit" or "withdrawal".
udf string Any user-defined field for additional information.
amount number The amount of cryptocurrency involved in the transaction.
network string The network on which the transaction occurred (e.g., BSC, ETH, TRX).
datetime string The date and time the event occurred.
ipnUrl string The IPN URL where the notification is being sent.
deposit_address string The deposit address (only included if ipn_type is "deposit").
withdrawal_address string The withdrawal address (only included if ipn_type is "withdrawal").

Example IPN Payload

Here is an example of an IPN payload for a deposit:

{
    "txn_hash": "0x12345...",
    "ipn_type": "deposit",
    "udf": "extra-info",
    "amount": 1.234,
    "network": "ETH",
    "datetime": "2023-05-10T12:34:56.789Z",
    "ipnUrl": "https://example.com/ipn-handler",
    "deposit_address": "0x6789..."
}
    

And an example of an IPN payload for a withdrawal:

      {
          "txn_hash": "0x12345...",
          "ipn_type": "withdrawal",
          "udf": "extra-info",
          "amount": 1.234,
          "network": "ETH",
          "datetime": "2023-05-10T12:34:56.789Z",
          "ipnUrl": "https://example.com/ipn-handler",
          "withdrawal_address": "0x6789..."
      }
          

IPN Notification Handling

Upon receiving the IPN notification at the specified IPN URL, your server should handle the incoming request and process the payload accordingly. The payload will be in POST data format, so you can parse the post data and extract the relevant information. Also before accepting the IPN notification, you should check if IPN data is genuine or not using below API:

Validating IPN notifications

To validate the received IPN notifications, perform the following steps:

  1. Extract the signature from the X-Sagapay-IPN header.
  2. Recompute the signature using the shared secret key and the received payload.
  3. Compare the recomputed signature with the signature extracted from the header. If they match, the IPN notification is considered genuine.

IPN Validation Demo

Node.js

      const crypto = require('crypto');
      const express = require('express');
      const app = express();
      
      const secretKey = 'api secret key';
      
      app.use(express.json());
      
      app.post('/ipn', (req, res) => {
          const receivedSignature = req.header('X-Sagapay-IPN');
          const payload = JSON.stringify(req.body);
      
          const hmac = crypto.createHmac('sha256', secretKey);
          hmac.update(payload);
          const computedSignature = hmac.digest('hex');
      
          if (receivedSignature === computedSignature) {
              console.log('Valid IPN:', req.body);
              res.status(200).send('OK');
          } else {
              console.log('Invalid IPN signature');
              res.status(401).send('Unauthorized');
          }
      });
      
      app.listen(3000, () => {
          console.log('Listening on port 3000');
      });
                      

PHP

      <?php
      
      $secretKey = 'api secret key';
      
      $headers = getallheaders();
      $receivedSignature = $headers['X-Sagapay-IPN'];
      $payload = file_get_contents('php://input');
      
      $computedSignature = hash_hmac('sha256', $payload, $secretKey);
      
      if ($receivedSignature === $computedSignature) {
          echo 'Valid IPN';
          http_response_code(200);
      } else {
          echo 'Invalid IPN signature';
          http_response_code(401);
      }
      
      ?>
                      

Go

                    // go get -u golang.org/x/crypto
                    
                    package main

                    import (
                      "crypto/hmac"
                      "crypto/sha256"
                      "encoding/hex"
                      "fmt"
                      "io/ioutil"
                      "net/http"
                    )
                    
                    func main() {
                      http.HandleFunc("/ipn", ipnHandler)
                      http.ListenAndServe(":8080", nil)
                    }
                    
                    func ipnHandler(w http.ResponseWriter, r *http.Request) {
                      // Read request body
                      body, err := ioutil.ReadAll(r.Body)
                      if err != nil {
                        http.Error(w, "Error reading request body", http.StatusInternalServerError)
                        return
                      }
                    
                      // Replace with the secret key provided by the payment gateway
                      secretKey := "api secret key"
                    
                      // Get the signature from the header
                      sentSignature := r.Header.Get("X-Sagapay-IPN")
                    
                      // Calculate the expected signature
                      expectedSignature := calculateHMAC(secretKey, string(body))
                    
                      // Compare the sent signature with the expected signature
                      if sentSignature == expectedSignature {
                        fmt.Println("IPN signature is valid")
                      } else {
                        fmt.Println("IPN signature is invalid")
                      }
                    }
                    
                    func calculateHMAC(secretKey, data string) string {
                      h := hmac.New(sha256.New, []byte(secretKey))
                      h.Write([]byte(data))
                      return hex.EncodeToString(h.Sum(nil))
                    }