1Pay

SMSplus Charging


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

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

Merchant webservice: là hệ thống merchant xây dựng để nhận request(MO) từ 1Pay gửi sang.

Max request time out:

   -Mobifone: 17 giây.

   -VinaPhone: 8 giây.

   -Viettel: 5 giây/request (2 request).

I. Kiểm tra cú pháp MO. (NEW)

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
amount Số tiền trừ vào tài khoản khách hàng. Giá cước (1000,2000,3000,4000,5000,10000,20000,30000,50000,100000[*])
command_code Là mã dịch vụ của khách hàng. Đăng ký và khai báo trên hệ thống 1Pay. Ví dụ GAME1
mo_message Nội dung tin nhắn của khách hàng ở dạng String bắt đầu từ mã đăng ký.
Ví dụ gamecode là TEST:
- Viettel: MW 1000 TEST NAP dunglp => mo_message: TEST NAP dunglp
- Mobifone/ Vinaphone: MW TEST NAP1 dunglp => mo_message: TEST NAP1 dunglp
msisdn Số điện thoại nhắn tin của khách hàng, theo chuẩn international, bắt đầu bằng 84
telco Mã nhà mạng. Ví dụ: vnp(Vinaphone),vms(Mobifone),vtm(Viettel)
signature Chữ ký, merchant có thể sử dụng signature để kiểm soát an ninh.
access_key=$access_key&amount=$amount&command_code=$command_code&mo_message=$mo_message&msisdn=$msisdn&telco=$telco được hmac bằng thuật toán SHA256

Lưu ý:

[[thong_tin_khac] trong nội dung MO không được chứa khoảng trống và các kí tự '$', '_', có thể sử dụng kí tự a tới z, 0 tới 9, '/', '.', '-' để phân biệt các trường nếu muốn

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 - Hợp lệ, 0 - Không hợp lệ
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

Chú ý:

  +Bước 1 hiện tại chỉ hỗ trợ mạng viettel.

  +Khi trả về status là 1 thì khi đó 1pay mới gọi đến bước 2 của merchant.

  +Bước 1 là bước check Mo, merchant ko cần cộng tiền/item cho user.

II. Nhận request.

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
amount Số tiền trừ vào tài khoản khách hàng. Giá cước (1000,2000,3000,4000,5000,10000,20000,30000,50000,100000[*])
command_code Là mã dịch vụ của khách hàng. Đăng ký và khai báo trên hệ thống 1Pay ví dụ GAME1
error_code Là mã lỗi 1pay trả về cho khách hàng. Ví dụ (WCG-0000 :Giao dịch thành công) (WCG-0001:Thuê bao không hợp lệ) (WCG-0002: Dữ liệu CP gửi lên sai) ( WCG-0005 Tài khoản không đủ tiền)
error_message Thông báo lỗi 1Pay gửi về cho merchant
mo_message Nội dung tin nhắn của khách hàng ở dạng String bắt đầu từ mã đăng ký.
Ví dụ gamecode là TEST:
- Viettel: MW 1000 TEST NAP dunglp => mo_message: TEST NAP dunglp
- Mobifone/ Vinaphone: MW TEST NAP1 dunglp => mo_message: TEST NAP1 dunglp
msisdn Số điện thoại nhắn tin của khách hàng, theo chuẩn international, bắt đầu bằng 84
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
signature Chữ ký, merchant có thể sử dụng signature để kiểm soát an ninh.
access_key=$access_key&amount=$amount&command_code=$command_code&error_code=$error_code&error_message=$error_message&mo_message=$mo_message&msisdn=$msisdn&request_id=$request_id&request_time=$request_time được hmac bằng thuật toán SHA256

Lưu ý:

[[thong_tin_khac] trong nội dung MO không được chứa khoảng trống và các kí tự '$', '_', có thể sử dụng kí tự a tới z, 0 tới 9, '/', '.', '-' để phân biệt các trường nếu muốn

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í, 0 - Không tính phí giao dịch
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ý.

III.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à “iac”)
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,"iac":{"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

   public static String getCarrierCode(Context context) {
	TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    String mccmnc = telephonyManager.getSimOperator();
    if (mccmnc == null) {
        return null;
    }
    String code = null;
    if (mccmnc.equals("45204")) {
        code = "viettel";
    } else if (mccmnc.equals("45201")) {
        code = "mobifone";
    } else if (mccmnc.equals("45202")) {
        code = "vinaphone";
    } else if (mccmnc.equals("45205")) {
        code = "vietnamobile";
    } else if (mccmnc.equals("45203")) {
        code = "sfone";
    }
    return code;
}

#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <CoreTelephony/CTCarrier.h>
(void) OK_getcode_btnTapped:(UIGestureRecognizer*)recognizer
{
    [popup removeFromSuperview];
    //Country : 452 - mobifone: 01, vinaphone: 02, viettel: 04
    CTTelephonyNetworkInfo *networkInfo = [[CTTelephonyNetworkInfo alloc] init] ;
    CTCarrier *carrier = [networkInfo subscriberCellularProvider];
    NSLog(@"Carrier Name: %@ ", [carrier carrierName]);
    NSLog(@"Mobile Country Code: %@", carrier.mobileCountryCode);
    NSLog(@"Mobile Network Code: %@", carrier.mobileNetworkCode);
    if ([carrier.mobileCountryCode isEqualToString:@"452"]&&[carrier.mobileNetworkCode isEqualToString:@"01"]){
        [self send_sms:1];
    } else if ([carrier.mobileCountryCode isEqualToString:@"452"]&&[carrier.mobileNetworkCode isEqualToString:@"02"]) {
        [self send_sms:1];
    } else if ([carrier.mobileCountryCode isEqualToString:@"452"]&&[carrier.mobileNetworkCode isEqualToString:@"04"]) {
        [self send_sms:2];
    } else {
        NSLog(@"Can not call send sms method");
    }
}
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.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.json.JSONException;
import org.json.JSONObject;

@Path("/")
public class SMSPlus {
	
	@GET
	@Path("/SmsplusCharging")
	@Produces(MediaType.APPLICATION_JSON)
	public Response charging(
			@DefaultValue("0")@QueryParam("access_key")String accKey,
			@DefaultValue("0")@QueryParam("amount")String amount,
			@DefaultValue("0")@QueryParam("command_code")String commandCode,
			@DefaultValue("0")@QueryParam("error_code")String errorCode,
			@DefaultValue("0")@QueryParam("error_message")String errorMessage,
			@QueryParam("mo_message")String moMessage,
			@QueryParam("msisdn")String phone,
			@QueryParam("request_id")String requestId,
			@QueryParam("request_time")String requestTime,
			@QueryParam("signature")String signature){
		
		JSONObject json = new JSONObject();
		String secret = ""; // Secret Key do 1pay cung cap. thay bang Secret Key cua ban
		String sig = generateSignature(accKey, amount, commandCode, errorCode, errorMessage, moMessage, phone, requestId, requestTime, secret);
		try {
			if (signature.equalsIgnoreCase(sig)) {
				json.put("status", 1);
				json.put("sms", "Send sms thanh cong");
			}else {
				json.put("status", 0);
				json.put("sms", "tin nhan sai cu phap");
			}
			json.put("text", "text");
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return Response.status(200).entity(json.toString()).build();
	}
	
	public static String hmac(String msg, String keyString, String algo) {
		String digest = "";
		try {
			if (keyString != null && keyString.length() > 0) {
				SecretKeySpec keySpec = new SecretKeySpec(
						keyString.getBytes("UTF-8"), algo);
				Mac mac = Mac.getInstance(algo);
				mac.init(keySpec);
				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) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return digest;
	}

	public String generateSignature(String access_key, String amount,
			String command_code, String error_code, String error_message,
			String mo_message, String phone, String request_id,
			String request_time, String secret) {
		String urlParameters = "";
		String signature = "";
		if (access_key != null && amount != null && command_code != null
				&& error_code != null && error_message != null
				&& mo_message != null && phone != null && request_id != null
				&& request_time != null && secret != null) {
			urlParameters = "access_key=%access_key%&amount=%amount%&command_code=%command_code%"
					+ "&error_code=%error_code%&error_message=%error_message%&mo_message=%mo_message%"
					+ "&msisdn=%msisdn%&request_id=%request_id%&request_time=%request_time%";
			urlParameters = urlParameters.replaceFirst("%access_key%",access_key);
			urlParameters = urlParameters.replaceFirst("%amount%", amount);
			urlParameters = urlParameters.replaceFirst("%command_code%",command_code);
			urlParameters = urlParameters.replaceFirst("%error_code%",error_code);
			urlParameters = urlParameters.replaceFirst("%error_message%",error_message);
			urlParameters = urlParameters.replaceFirst("%mo_message%",mo_message);
			urlParameters = urlParameters.replaceFirst("%msisdn%", phone);
			urlParameters = urlParameters.replaceFirst("%request_id%",request_id);
			urlParameters = urlParameters.replaceFirst("%request_time%",request_time);
			signature = hmac(urlParameters, secret, "HmacSHA256");
			System.out.println("Signature:" + signature);
		}
		return signature;
	}
}
                                    

  File check_mo_smsplus.php

    $arParams['access_key'] = $_GET['access_key'] ? $_GET['access_key'] : '';
   $arParams['amount'] = $_GET['amount'] ? $_GET['amount'] : '';
   $arParams['command_code'] = $_GET['command_code'] ? $_GET['command_code'] : '';
   $arParams['mo_message'] = $_GET['mo_message'] ? $_GET['mo_message'] : '';
   $arParams['msisdn'] = $_GET['msisdn'] ? $_GET['msisdn'] : '';
   $arParams['telco'] = $_GET['telco'] ? $_GET['telco'] : '';
   $arParams['signature'] = $_GET['signature'] ? $_GET['signature'] : '';
   $data = "access_key=" . $arParams['access_key'] . "&amount=" . $arParams['amount'] . "&command_code=" . $arParams['command_code'] . "&mo_message=" . $arParams['mo_message'] . "&msisdn=" . $arParams['msisdn'] . "&telco=" . $arParams['telco'];
   $secret = ''; //product's secret key (get value from 1Pay product detail)
   $signature = hash_hmac("sha256", $data, $secret); // create signature to check
   $arResponse['type'] = 'text';
   // kiem tra signature neu can
   if ($arParams['signature'] == $signature) {
    //if sms content and amount and ... are ok. return success case
    $arResponse['status'] = 1;
    $arResponse['sms'] = 'Hop le';
   }
   else {
    //if not. return fail case
	$arResponse['status'] = 0;
    $arResponse['sms'] = 'Khong hop le';
   }
   // return json for 1pay system
   echo json_encode($arResponse);

  File smsplus1pay.php

    $arParams['access_key'] = $_GET['access_key'] ? $_GET['access_key'] : '';
   $arParams['command_code'] = $_GET['command_code'] ? $_GET['command_code'] : '';
   $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['amount'] = $_GET['amount'] ? $_GET['amount'] : '';
   $arParams['signature'] = $_GET['signature'] ? $_GET['signature'] : '';
   $arParams['error_code'] = $_GET['error_code'] ? $_GET['error_code'] : '';
   $arParams['error_message'] = $_GET['error_message'] ? $_GET['error_message'] : '';
   $data = "access_key=" . $arParams['access_key'] . "&amount=" . $arParams['amount'] . "&command_code=" . $arParams['command_code'] . "&error_code=" . $arParams['error_code'] . "&error_message=" . $arParams['error_message'] . "&mo_message=" . $arParams['mo_message'] . "&msisdn=" . $arParams['msisdn'] . "&request_id=" . $arParams['request_id'] . "&request_time=" . $arParams['request_time'];
   $secret = ''; //product's secret key (get value from 1Pay product detail)
   $signature = hash_hmac("sha256", $data, $secret); // create signature to check
   $arResponse['type'] = 'text';
   // kiem tra signature neu can
   if ($arParams['signature'] == $signature) {
    //if sms content and amount and ... are ok. return success case
    $arResponse['status'] = 1;
    $arResponse['sms'] = 'Giao dich thanh cong ... Lien he ... de biet them chi tiet';
   }
   else {
    //if not. return fail case
	$arResponse['status'] = 0;
    $arResponse['sms'] = 'Giao dich khong thanh cong. Lien he ... de biet them chi tiet.';
   }
   // 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 InAppChargingService
   {
    public class InAppService : System.Web.Services.WebService
    {
     [WebMethod]
     [ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
     public void inAppChargingRequest(string access_key, string amount, string command_code, string error_code, string error_message, string mo_message, string msisdn, string request_id, string request_time, string signature)
     {
      string secretKey = ""; //product's secret key (get value from 1Pay product detail)
      My1Pay my1Pay = new My1Pay();
      string signatureTrue = my1Pay.generateSignature_InApp(access_key, amount, command_code, error_code, error_message, mo_message, msisdn, request_id,
                 request_time, secretKey);
      string json = "";
      var serializer = new JavaScriptSerializer();
      //Security check at the merchant, not mandatory
      if (signature == signatureTrue)
      {
       //decode url mo, to do something with mo, return response to 1pay, example:
       json = serializer.Serialize(new { status = 1, sms = "mt success", type = "text" });
      }
      else
      {
       //to do something example:
       json = serializer.Serialize(new { status = 0, sms = "mt fail", 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"; // set json return
      string access_key = cgicc("access_key");
      string amount =cgicc("amount"); 
      string command_code = cgicc("command_code");
      string error_code = cgicc("error_code");
      string error_message = cgicc("error_message");
      string mo_messae = cgicc("mo_message");
      string msisdn = cgicc("msisdn");
      string request_id = cgicc("request_id");
      string request_time = cgicc("request_time");
      string signature = cgicc("signature");
      string secret_key=""; //product's secret key (get value from 1Pay product detail)
      string data = "access_key=" +access_key+ "&amount=" +amount+ "&command_code=" +command_code+ "&error_code=" +error_code+ "&error_message=" +error_message+ "&mo_message=" +mo_message+ "&msisdn=" +msisdn+ "&request_id=" +request_id+ "&request_time=" +request_time;
      string sigGen = hmac(secret_key,data); // create signatue
	  //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\":\"Giao dich thanh cong ... Lien he ... de biet them chi tiet\"}" ;
       }
      else{
	   //if not. return fail case
       cout <<  "{\"status\":0,\"type\":\"text\",\"sms\":\"Giao dich khong thanh cong. Lien he ... de biet them chi tiet.\"}" ;
      }  
      return 0;
   }