1Pay

SMS Charging


Các bước kết nối sms

1 End User gửi "tin nhắn đến" hệ thống 1pay

2 1pay chuyển tin nhắn đến cho Merchant

3 Merchant xử lý và trả "tin nhắn trả về" cho 1pay

4 1pay trả "tin nhắn trả về" cho End User

Mô tả chi tiết

Max request time out:

   -Viettel, Mobifone: 17 giây.

   -VinaPhone: 8 giây.

Sau khi tạo sản phẩm trên 1Pay, merchant cần xây dựng webservice xử lý tin nhắn đến do 1Pay gửi sang

Request do hệ thống 1Pay gửi sang sẽ ở dạng HTTP GET, với các tham số như sau:

Tham số Mô tả
access_key Đại diện cho sản phẩm của merchant khai báo trong hệ thống 1pay.vn
command Mã tin nhắn, là keyword đầu tiên trong tin nhắn của khách hàng, ví dụ tin nhắn có nội dung "DK Game" gửi 8038 thì command sẽ là DK
mo_message Nội dung tin nhắn của khách hàng
msisdn Số điện thoại của khách hàng, bắt đầu bằng 84, ví dụ 8498238193
request_id Id của tin nhắn, ở dạng String
request_time Thời gian đầu số nhận được tin nhắn, ở dạng iso, ví dụ: 2013-07-06T22:54:50Z
short_code Đầu số nhận tin nhắn, ví dụ tin nhắn có nội dung DK Game” gửi 8038 thì short_code sẽ là 8038
signature Chữ ký, merchant có thể sử dụng signature để kiểm soát an ninh
Signature là một chuỗi string access_key=$access_key&command=$command&mo_message=$mo_message&msisdn=$msisdn&request_id=$request_id&request_time=$request_time&short_code=$short_code được hmac bằng thuật toán SHA256

Response

Sau khi xử lý, webservice cần trả về nội dung ở dạng json với cấu trúc như sau:

{"status":status,"sms":"nội dung tin nhắn cần trả về cho khách hàng" ,"type" :"loại tin nhắn"}

Trong đó

Tham số Mô tả
status Trạng thái xử lý, nhận giá trị: 1- tính phí, user được cộng dịch vụ trong app/website, 0 – không bị tính phí, user không sử dụng được dịch vụ trong app/website. Các tin nhắn trả sai trạng thái tính cước. Ví dụ: “Giao dich khong thanh cong”, “Khong tim thay tai khoan”, “He thong dang bao tri”, … mà trả status 1 là tin trả sai trạng thái tính cước, 1Pay sẽ tự động chuyển thành status 0 và trả kết quả cho nhà mạng, Merchant không được tính doanh thu những tin này
sms Nội dung tin nhắn cần trả về cho khách hàng
type Loại tin nhắn, nhận giá trị: text, hoặc wap_push

Trong quá trình vận hành, có thể có những tính huống mà Hệ thống SMS của 1Pay sẽ gọi lại những request có cùng request_id. Do đó, hệ thống của đối tác cần đảm bảo nếu đã xử lý một request tương ứng với request_id A, thì những requests tiếp theo có cùng request_id là A sẽ không được xử lý.

2.Truy vấn lại kiểm tra kết quả giao dịch (Query Api)

Địa chỉ nhận Request Charging:

GET  http://merchant.1pay.vn/charging/service/logs

Giao thức truyền dữ liệu: HTTP
Max request time out: 20 giây

Tham số Mô tả
access_key Đại diện cho sản phẩm của merchant khai báo trong hệ thống 1pay.vn
request_id requestId của giao dịch muốn kiểm tra nhận được ở bước 1
charging_type Loại hình dịch vụ (Ở đây là “sms”)
signature Chữ ký, là một chuỗi string:
access_key=$access_key&charging_type=$charging_type&request_id=$request_id
được hmac bằng thuật toán SHA256

Response trả về có dạng json

{"message":"Thông báo từ 1pay","status":status,"sms":{"amount":[Mệnh giá tin nhắn],"request_id":"requestId của giao dịch", "status":"Trạng thái phí: 1 - Tính phí, 0 - Không tính phí","msisdn":" Số điện thoại","mo_message":"Nội dung tin nhắn của khách hàng","billing_status":" trạng thái thanh toán","mt_message":"tin nhắn trả về cho khách hàng","request_time":" Thời gian đầu số nhận được tin nhắn"},"type":"text"}

Trong đó

Tham số Mô tả
status Trạng thái xử lý, nhận giá trị: 1 - Giao dịch thất bại, 0 - Giao dịch thành công
billing_status 0 - Giao dịch chưa bị trừ tiền, 1 - Giao dịch đã trừ tiền
Lên đầu trang


                                      
   package service;

   import java.io.UnsupportedEncodingException;
   import java.security.InvalidKeyException;
   import java.security.NoSuchAlgorithmException;
   import javax.crypto.Mac;
   import javax.crypto.spec.SecretKeySpec;
   import javax.ws.rs.DefaultValue;
   import javax.ws.rs.GET;
   import javax.ws.rs.Path;
   import javax.ws.rs.ProduceMime;
   import javax.ws.rs.QueryParam;
   import javax.ws.rs.core.Response;
   import org.json.JSONObject;

   @Path("/service/Charging")
   public class SmsCharging {
    @GET
    @Path("/SmsCharging")
    @ProduceMime({ "application/json" })
    public Response charging(
      @DefaultValue("0") @QueryParam("access_key") String access_key,
      @DefaultValue("0") @QueryParam("command") String command,
      @QueryParam("mo_message") String mo_message,
      @QueryParam("msisdn") String msisdn,
      @QueryParam("request_id") String request_id,
      @QueryParam("request_time") String request_time,
      @QueryParam("short_code") String short_code,
      @QueryParam("signature") String signature) {
     JSONObject rs = new JSONObject();
     StringBuffer response = new StringBuffer();
     try {
      String secret = ""; // require your secret key from 1pay
      String signatureGen = generateSignature(access_key, command,
        mo_message, msisdn, request_id, request_time, short_code,
        secret);
      if (signature.equalsIgnoreCase(signatureGen)) {
       //if sms content, amount, ... are ok. return success
       rs.put("status", 1);
       rs.put("sms", "Giao dich thanh cong ... Hotline ...");
      } else {
       //if not, return fail
       rs.put("status", 0);
       rs.put("sms", "Giao dich khong thanh cong. Tin nhan se duoc hoan cuoc sau 20 ngay. Hotline ...");
      }
      rs.put("type", "text");
     } catch (Exception localException1) {
      localException1.printStackTrace();
     }
     return Response.status(200).entity(rs.toString()).build();
    }

    public String generateSignature(String access_key, String command,
      String mo_message, String msisdn, String request_id,
      String request_time, String short_code, String secret) {
     String urlParameters = "";
     String signature = "";
     if ((command != null) && (mo_message != null) && (msisdn != null) 
       && (request_id != null) && (request_time != null)
       && (short_code != null) && (secret != null)) {
      urlParameters = "access_key=%access_key%&command=%command%"
        + "&mo_message=%mo_message%&msisdn=%msisdn%"
        + "&request_id=%request_id%&request_time=%request_time%"
        + "&short_code=%short_code%";
      urlParameters = urlParameters.replaceFirst("%access_key%", access_key);
      urlParameters = urlParameters.replaceFirst("%command%", command);
      urlParameters = urlParameters.replaceFirst("%mo_message%", mo_message);
      urlParameters = urlParameters.replaceFirst("%msisdn%", msisdn);
      urlParameters = urlParameters.replaceFirst("%request_id%", request_id);
      urlParameters = urlParameters.replaceFirst("%request_time%", request_time);
      urlParameters = urlParameters.replaceFirst("%short_code%", short_code);
      signature = hmacDigest(urlParameters, secret, "HmacSHA256");
     }
     return signature;
    }

    public static String hmacDigest(String msg, String keyString, String algo) {
     String digest = "";
     try {
      if (keyString != null && keyString.length() > 0) {
       SecretKeySpec key = new SecretKeySpec(
         (keyString).getBytes("UTF-8"), algo);
       Mac mac = Mac.getInstance(algo);
       mac.init(key);
       byte[] bytes = mac.doFinal(msg.getBytes("ASCII"));
       StringBuffer hash = new StringBuffer();
       for (int i = 0; i < bytes.length; i++) {
        String hex = Integer.toHexString(0xFF & bytes[i]);
        if (hex.length() == 1) {
         hash.append('0');
        }
        hash.append(hex);
       }
       digest = hash.toString();
      }
     } catch (UnsupportedEncodingException e) {
     } catch (InvalidKeyException e) {
     } catch (NoSuchAlgorithmException e) {
     }
     return digest;
    }
   }
                                    
                                          
   $arParams['access_key'] = $_GET['access_key'] ? $_GET['access_key'] : '';
   $arParams['command'] = $_GET['command'] ? $_GET['command'] : '';
   $arParams['mo_message'] = $_GET['mo_message'] ? $_GET['mo_message'] : '';
   $arParams['msisdn'] = $_GET['msisdn'] ? $_GET['msisdn'] : '';
   $arParams['request_id'] = $_GET['request_id'] ? $_GET['request_id'] : '';
   $arParams['request_time'] = $_GET['request_time'] ? $_GET['request_time'] : '';
   $arParams['short_code'] = $_GET['short_code'] ? $_GET['short_code'] : '';
   $arParams['signature'] = $_GET['signature'] ? $_GET['signature'] : '';
   $data = "access_key=" . $arParams['access_key'] . "&command=" . $arParams['command'] . "&mo_message=" . $arParams['mo_message'] . "&msisdn=" . $arParams['msisdn'] . "&request_id=" . $arParams['request_id'] . "&request_time=" . $arParams['request_time'] . "&short_code=" . $arParams['short_code'];
   $secret = 'u5knnd9kozex7sq8kmuhvx0ym5hvsfq8'; // serequire your secret key from 1pay
   $signature = hash_hmac("sha256", $data, $secret); 
   $arResponse['type'] = 'text';
   
   if ($arParams['signature'] == $signature) {
    //if sms content, amount,... are ok. return success
    $arResponse['status'] = 1;
    $arResponse['sms'] = 'Giao dich thanh cong ... Hotline...';
   }
   else {
    //if not, return unsuccess
    $arResponse['status'] = 0;
    $arResponse['sms'] = 'Giao dich khong thanh cong. Tin nhan se duoc hoan cuoc sau 20 ngay. Hotline...';
   }

   // return json for 1pay system
   echo json_encode($arResponse);
     Download 1pay.dll
                                                    
   using System.Web;
   using System.Web.Script.Serialization;
   using System.Web.Script.Services;
   using System.Web.Services;
   using _1Pay;

   namespace SmsChargingService
   {
    public class SmsService : System.Web.Services.WebService
    {
     [WebMethod]
     [ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
     public void smsChargingRequest(string access_key, string command, string mo_message, string msisdn, string request_id, string request_time, string short_code, string signature)
     {
      //create signature true with parameters
      string secretKey = ""; //require your secret key from 1pay
      My1Pay my1Pay = new My1Pay();
      string signatureTrue = my1Pay.generateSignature_Sms(access_key, command, mo_message, msisdn, request_id, request_time,
                 short_code, secretKey);

      string json = "";
      var serializer = new JavaScriptSerializer();

      //Security check at the merchant, not mandatory
      if (signature == signatureTrue)
      {
       //if sms content, amount, ... are ok. Return success, example:
       json = serializer.Serialize(new { status = 1, sms = "Giao dich thanh cong ... Hotline ...", type = "text"});
      }
      else
      {
       //if not. Return fail, ex:
       json = serializer.Serialize(new { status = 0, sms = "Giao dich khong thanh cong. Tin nhan se duoc hoan cuoc sau 20 ngay. Hotline...", type = "text"});
      }
      HttpContext.Current.Response.ContentType = "application/json; charset=utf-8";
      HttpContext.Current.Response.Write(json);
     }
    }
   }
   
     Download hmac-sha256.cpp

   #include <iostream>
   #include <cgicc/Cgidefs.h>
   #include <cgicc/Cgicc.h >
   #include <cgicc/Httphtmlheader.h>
   #include <cgicc/Htmlclasses.h>
   #include "hmac-sha256.cpp"
   using namespace std;
   using namespace cgicc;
    
   int main ()
   {
      Cgicc cgicc;

      cout  "Content-Type: application/json\r\n\r\n"; 
      string access_key = cgicc("access_key");
      string command = cgicc("command");
      string mo_message = cgicc("mo_message");
      string msisdn = cgicc("msisdn");
      string request_id = cgicc("request_id");
      string request_time = cgicc("requst_time");
      string short_code = cgicc("short_code");
      string signature = cgicc("signature");
     
      string secret_key="";//product's secret key (get value from 1Pay product detail)
      string data = "access_key=" +access_key+ "&command=" +command+ "&mo_message=" +mo_message+ "&msisdn=" +msisdn+ "&request_id=" +request_id+ "&request_time=" +request_time+ "&short_code=" +short_code;
      string sigGen = hmac(secret_key,data); 

   //   cout<< access_key+signature << endl;
   //   cout<< sigGen << endl;
   
    //processing data and return result for 1pay
      if (sigGen.compare(signature)==0){
       //if all sms content, amount... are ok. return success case
       cout <<  "{\"status\":1,\"type\":\"text\",\"sms\":\"Ban da duoc cong tien vao game thanh cong\"}" ;
       }
      else{
      //if not. return fail case
       cout <<  "{\"status\":0,\"type\":\"text\",\"sms\":\"Giao dich khong thanh cong, tin nhan se duoc hoan cuoc sau 20 ngay. HotLine:...\"}" ;
      }  
      return 0;
   }