PayME SDK là bộ thư viện để các app có thể tương tác với PayME Platform. PayME SDK bao gồm các chức năng chính như sau:
- Hệ thống đăng nhập, eKYC thông qua tài khoản ví PayME
- Hỗ trợ app lấy thông tin số dư ví PayME
- Chức năng nạp rút từ ví PayME.
Một số thuật ngữ
Name | Giải thích | |
---|---|---|
1 | app | Là app mobile iOS/Android hoặc web sẽ tích hợp SDK vào để thực hiện chức năng thanh toán ví PayME. |
2 | SDK | Là bộ công cụ hỗ trợ tích hợp ví PayME vào hệ thống app. |
3 | backend | Là hệ thống tích hợp hỗ trợ cho app, server hoặc api hỗ trợ |
4 | AES | Hàm mã hóa dữ liệu AES256 PKCS5 . Tham khảo |
5 | RSA | Thuật toán mã hóa dữ liệu RSA. |
6 | IPN | Instant Payment Notification , dùng để thông báo giữa hệ thống backend của app và backend của PayME |
PayMESDK đang được lưu trữ trên nền tảng CocoaPods. Để cài đặt, đơn giản thêm dòng sau vào Podfile của bạn:
pod 'PayMESDK'
Sau đó chạy lệnh pod install
để hoàn tất cài dặt
Info.plist
Update file Info.plist của app với những key như sau (giá trị của string có thể thay đổi, đây là các message hiển thị khi yêu cầu người dùng cấp quyền tương ứng):
<key > NSCameraUsageDescription </ key>
<string > Need to access your camera to capture a photo add and update profile picture .</ string>
<key > NSPhotoLibraryAddUsageDescription </ key>
<string > Need to access your library to add a photo or videoo off kyc video </ string>
<key > NSPhotoLibraryUsageDescription </ key>
<string > Need to access your photo library to select a photo add and update profile picture </ string>
<key > NSContactsUsageDescription </ key>
<string > Need to access your contact </ string>
Nếu không sử dụng tính năng danh bạ thì thêm vào cuối podfile
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == 'PayMESDK'
target.build_configurations.each do |config|
config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] ||= '$(inherited)'
config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] << 'IGNORE_CONTACT'
end
end
end
end
Hệ thống PayME sẽ cung cấp cho app tích hợp các thông tin sau:
- PublicKey : Dùng để mã hóa dữ liệu, app tích hợp cần truyền cho SDK để mã hóa.
- AppToken : AppId cấp riêng định danh cho mỗi app, cần truyền cho SDK để mã hóa
- SecretKey : Dùng đã mã hóa và xác thực dữ liệu ở hệ thống backend cho app tích hợp.
Bên App sẽ cung cấp cho hệ thống PayME các thông tin sau:
- AppPublicKey : Sẽ gửi qua hệ thống backend của PayME dùng để mã hóa. (không truyền vào SDK này )
- AppPrivateKey: Sẽ truyền vào PayME SDK để thực hiện việc giải mã.
Chuẩn mã hóa: RSA-512bit. Có thể dùng tool sau để sinh ra tại đây
Trước khi sử dụng PayME SDK cần gọi phương thức khởi tạo một lần duy nhất để khởi tạo SDK.
let payme = PayME(appToken: "AppToken",
publicKey: "PublicKey",
connectToken: "ConnectToken",
appPrivateKey: "AppPrivateKey",
language: PayME.Language.VIETNAMESE,
configColor: ["#07A922"],
env: PayME.Env.SANDBOX
)
Trong đó các thông số có dạng:
-
appPrivateKey: là private key của app tự sinh ra như trên
-
publicKey: là public key được PayME cung cấp cho mỗi app riêng biệt.
-
configColor : là tham số màu để có thể thay đổi màu sắc giao dịch ví PayME, kiểu dữ liệu là chuỗi với định dạng
Cách tạo connectToken:
connectToken cần để truyền gọi api từ tới PayME và sẽ được tạo từ hệ thống backend của app tích hợp. Cấu trúc như sau:
connectToken = AES256("{ timestamp: "2021 - 01 - 20T06:53:07.621Z",
userId: "ABC",
phone: "0909998877" }"
+ secretKey )
Tham số | Bắt buộc | Giải thích |
---|---|---|
** | ||
timestamp** | Yes | Thời gian tạo ra connectToken theo định dạng iSO 8601 , Dùng để xác định thời gian timeout cùa connectToken. Ví dụ 2021-01-20T06:53:07.621Z |
*** | ||
userId*** | Yes | là giá trị cố định duy nhất tương ứng với mỗi tài khoản khách hàng ở dịch vụ, thường giá trị này do server hệ thống được tích hợp cấp cho PayME SDK |
*** | ||
phone*** | Yes | Số điện thoại của hệ thống tích hợp, nếu hệ thống không dùng số điện thoại thì có thể không cần truyền lên hoặc truyền null |
Trong đó AES là hàm mã hóa theo thuật toán AES. Tùy vào ngôn ngữ ở server mà bên hệ thống dùng thư viện tương ứng. Xem thêm tại đây https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
Cách tạo connectToken bao gồm thông tin KYC ( Dành cho các đối tác có thệ thống KYC riêng ):
// example
connectToken = AES256("{
userId: "ABC",
phone: "0909998877",
timestamp: "2021-01-20T06:53:07.621Z",
kycInfo: {
{
fullname: "Nguyen Van A",
gender: "MALE",
birthday: "1995-01-20T06:53:07.621Z",
address: "1 Nguyen Co Thach",
identifyType: "CMND",
identifyNumber: "123456789",
issuedAt: "2012-01-20T06:53:07.621Z",
placeOfIssue: "Hai Duong",
video: "https://..../202/Co-29vnK6.mp4",
face: "https://.../photo/2015/04/_480.jpg",
image: {
front: "https://.../photo/2015/04/_480.jpg",
back: "https://.../photo/2015/04/_480.jpg",
}
}
}
}" + secretKey )
Tham số kycInfo
Tham số | Bắt buộc | Giải thích |
---|---|---|
fullname | Yes | Họ tên |
gender | Yes | Giới tính ( MALE/FEMALE) |
address | Yes | Địa chỉ |
identifyType | Yes | Loại giấy tờ (CMND/CCCD) |
identifyNumber | Yes | Số giấy tờ |
issuedAt | Yes | Ngày đăng ký |
placeOfIssue | Yes | Nơi cấp |
video | No | đường dẫn tới video |
face | No | đường dẫn tới ảnh chụp khuôn mặt |
front | No | đường dẫn tới ảnh mặt trước giấy tờ |
back | No | đường dẫn tới ảnh mặt sau giấy tờ |
Hằng số | Mã lỗi | Giải thích |
---|---|---|
EXPIRED |
401 |
token hết hạn sử dụng |
DEACTIVATED_ACCOUNT |
405 |
Tài khoản đã bị vô hiệu hoá |
NETWORK |
-1 |
Kết nối mạng bị sự cố |
SYSTEM |
-2 |
Lỗi hệ thống |
LIMIT |
-3 |
Lỗi số dư không đủ để thực hiện giao dịch |
ACCOUNT_NOT_ACTIVATED |
-4 |
Lỗi tài khoản chưa kích hoạt |
ACCOUNT_NOT_KYC |
-5 |
Lỗi tài khoản chưa định danh |
PAYMENT_ERROR |
-6 |
Thanh toán thất bại |
ERROR_KEY_ENCODE |
-7 |
Lỗi mã hóa/giải mã dữ liệu |
USER_CANCELLED |
-8 |
Người dùng thao tác hủy |
ACCOUNT_NOT_LOGIN |
-9 |
Lỗi chưa đăng nhập tài khoản |
PAYMENT_PENDING |
-11 |
Thanh toán chờ xử lý |
ACCOUNT_ERROR |
-12 |
Lỗi tài khoản bị khóa |
Có 2 trường hợp
- Dùng để login lần đầu tiên ngay sau khi khởi tạo
PayME
. - Dùng khi
accessToken
hết hạn, khi gọi hàm của SDK mà trả về mã lỗiResponseCode.EXPIRED hoặc ResponseCode.DEACTIVATED_ACCOUNT
, lúc này app cần gọilogin
lại để lấyaccessToken
dùng cho các chức năng khác.
Sau khi gọi login()
thành công rồi thì mới gọi các chức năng khác của SDK ( openWallet
,
pay
... )
public func login(
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
Khi login thành công sẽ được trả về 1 enum KYCState
chứa thông tin như sau:
public enum KYCState {
case NOT_ACTIVATED
case NOT_KYC
case KYC_APPROVED
}
Các tính năng như nạp tiền, rút tiền, pay chỉ thực hiện được khi đã kích hoạt ví và gửi định danh thành công. Tức là khi
login sẽ được trả về enum KYCState
với case là KYC_APPROVED
.
public func logout()
Dùng để đăng xuất ra khỏi phiên làm việc trên SDK
Hàm này được dùng để app tích hợp đóng lại UI của SDK khi đang pay()
hoặc openWallet()
public func close() -> ()
public func openWallet(
currentVC: UIViewController,
action: Action,
amount: Int?,
description: String?,
extraData: String?,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
trong đó enum Action bao gồm:
enum Action: String {
case OPEN = "OPEN"
case DEPOSIT = "DEPOSIT"
case WITHDRAW = "WITHDRAW"
case TRANSFER = "TRANSFER"
}
Hàm này được gọi khi từ app tích hợp khi muốn gọi 1 chức năng PayME bằng cách truyền vào tham số Action
như
trên.
| Tham số | Bắt buộc | Giải thích
| | :----------------------------------------------------------- | :----------- | :
----------------------------------------------------------- | | currentVC
| Yes | ViewController để PayME
SDK dựa vào đó tự mở giao diện của PayME lên. | | action
| Yes |
- OPEN : Dùng để mở giao diện ví PayME WebView và không thực hiện hành động nào đặc biệt.
- DEPOSIT: Dùng để mở giao diện ví PayME và thực hiện chức năng nạp tiền PayME sẽ xử lý và có thông báo thành công thất bại trên UI của PayME. Ngoài ra sẽ trả về cho app tích hợp kết quả nếu muốn tự hiển thị và xử lý trên app.
- WITHDRAW: Dùng để mở giao diện ví PayME và thực hiện chức năng rút tiền PayME sẽ xử lý và có thông báo thành công thất bại trên UI của PayME. Ngoài ra sẽ trả về cho app tích hợp kết quả nếu muốn tự hiển thị và xử lý trên app.
amount
| No | Dùng trong trường hợp action là
Deposit/Withdraw thì truyền vào số tiền | | description
| No | Truyền mô tả của giao dịch nếu có | |
extraData
| No | Khi thực hiện Deposit hoặc Withdraw thì app tích hợp cần truyền thêm các dữ liệu khác nếu muốn
để hệ thông backend PayME có thể IBN lại hệ thống backend app tích hợp đối chiều. Ví dụ : transactionID của giao dịch
hay bất kỳ dữ liệu nào cần thiết đối với hệ thống app tích hợp. | | onSuccess
| Yes | Dùng để bắt callback
khi thực hiện giao dịch thành công từ PayME SDK | | onError
| Yes | Dùng để bắt callback khi có lỗi xảy ra
trong quá trình gọi PayME SDK |
Ví dụ :
import PayMESDK
class ViewController: UIViewController {
let payME: PayME
@IBAction func click(_ sender: Any) {
payME.openWallet(
currentVC: self,
action: Action.OPEN,
amount: nil,
description: nil,
extraData: nil
)
}
override func viewDidLoad() {
super.viewDidLoad()
payME = PayME(
appID: appID,
publicKey: self.PUBLIC_KEY,
connectToken: self.connectToken,
appPrivateKey: self.PRIVATE_KEY,
env: currentEnv,
configColor: ["#75255b", "#a81308"]
)
}
}
public func deposit(
currentVC: UIViewController,
amount: Int?,
description: String?,
extraData: String?,
closeWhenDone: Bool = false,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
Hàm này có ý nghĩa giống như khi gọi openWallet
với action Action.DEPOSIT
| Tham số | Mặc định | Giải thích
| | :----------------------------------------------------------- | :----------- | :
----------------------------------------------------------- | | closeWhenDone
| false
| true
: Đóng SDK khi hoàn tất giao dịch |
public func withdraw(
currentVC: UIViewController,
amount: Int?,
description: String?,
extraData: String?,
closeWhenDone: Bool = false,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
Hàm này có ý nghĩa giống như gọi openWallet
với action là Action.WITHDRAW
| Tham số | Mặc định | Giải thích
| | :----------------------------------------------------------- | :----------- | :
----------------------------------------------------------- | | closeWhenDone
| false
| true
: Đóng SDK khi hoàn tất giao dịch |
public func transfer(
currentVC: UIViewController,
amount: Int?,
description: String?,
extraData: String?,
closeWhenDone: Bool = false,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
Hàm này có ý nghĩa giống như gọi openWallet
với action là Action.TRANSFER
| Tham số | Mặc định | Giải thích
| | :----------------------------------------------------------- | :----------- | :
----------------------------------------------------------- | | closeWhenDone
| false
| true
: Đóng SDK khi hoàn tất giao dịch |
public func openHistory(
currentVC: UIViewController,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
Hàm này có ý nghĩa giống như gọi openWallet
với action là Action.OPEN_HISTORY
Hàm này được dùng khi app cần thanh toán 1 khoản tiền từ ví PayME đã được kích hoạt.
public func pay(
currentVC: UIViewController,
storeId: Int,
orderId: Int,
amount: Int,
note: String?,
paymentMethodID: Int?,
extraData: String?,
isShowResultUI: Bool = true,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
| Tham số | Bắt buộc | Giải thích | | :
----------------------------------------------------------- | :----------- | :
----------------------------------------------------------- | | currentVC
| Yes | ViewController để PayME
SDK dựa vào đó tự mở giao diện của PayME lên. | | amount
| Yes | Số tiền cần thanh toán bên app truyền qua
cho SDK | | extraData
| Yes | Khi thực hiện thanh toán thì app cần truyền thêm các dữ liệu khác nếu muốn để
hệ thông backend PayME có thể IPN lại hệ thống backend tích hợp đối chiều. Ví dụ : transactionID của giao dịch hay bất
kỳ dữ liệu nào cần thiết. | | storeId
| Yes | ID của store phía công thanh toán thực hiên giao dịch thanh
toán | | orderId
| Yes | Mã giao dịch của đối tác, cần duy nhất trên mỗi giao dịch (tối đa 22 kí tự) |
| note
| No | Mô tả giao dịch từ phía đối tác | | isShowResultUI
| No | Đã có giá trị default
là true
, với ý nghĩa là khi có kết quả thanh toán thì sẽ hiển thị màn hình thành công, thất bại. Khi truyền
giá trị là false thì sẽ không có màn hình thành công, thất bại. | | onSuccess
| Yes | Callback trả kết quả
khi thành công | | onError
| Yes | Callback trả kết quả khi thất bại |
Trong trường hợp app tích hợp cần lấy số dư để tự hiển thị lên UI trên app thì có thể dùng hàm
getWalletInfo()
, hàm này không hiển thị UI của PayME SDK
- Khi thanh toán bằng ví PayME thì yêu cầu tài khoản đã kích hoạt,định danh và số dư trong ví phải lớn hơn số tiền thanh toán
- Thông tin tài khoản lấy qua hàm
getAccountInfo()
- Thông tin số dư lấy qua hàm
getWalletInfo()
public func pay(
currentVC: UIViewController,
storeId: Int?,
userName: String?,
orderId: Int,
amount: Int,
note: String?,
payCode: String,
extraData: String?,
isShowResultUI: Bool = true,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
| Tham số | Bắt buộc | Giá trị | | :
----------------------------------------------------------- | :----------- | :
----------------------------------------------------------- | | payCode
| Yes
| Danh sách phương thức thanh toán | | userName
| No | Tên tài khoản
| | storeId
| No | ID của store phía công thanh toán thực hiên giao dịch thanh toán |
Lưu ý : Chỉ có userName hoặc storeId, nếu dùng userName thì để storeId = nil và ngược lại
public func scanQR(
currentVC: UIViewController,
payCode: String,
onSuccess: @escaping (Dictionary<String, AnyObject>) -> (),
onError: @escaping (Dictionary<String, AnyObject>) -> ()
) -> ()
Định dạng QR :
let qrString = "{$type}|${storeId?}|${action}|${amount}|${note}|${orderId}|${userName?}"
Ví dụ :
let qrString = "OPENEWALLET|54938607|PAYMENT|20000|Chuyentien|2445562323|DEMO)"
- action: loại giao dịch ( 'PAYMENT' => thanh toán)
- amount: số tiền thanh toán
- note: Mô tả giao dịch từ phía đối tác
- orderId: mã giao dịch của đối tác, cần duy nhất trên mỗi giao dịch
- storeId: ID của store phía hiện giao dịch thanh toán
- type:
OPENEWALLET
public func payQRCode(
currentVC: UIViewController,
qr: String,
payCode: String,
isShowResultUI: Bool,
onSuccess: @escaping (Dictionary<String, AnyObject>) -> (),
onError: @escaping (Dictionary<String, AnyObject>) -> ()
) -> ()
- qr: Mã QR để thanh toán ( Định dạng QR như hàm
scanQR()
) - isShowResultUI: Có muốn hiển thị UI kết quả giao dịch hay không
Hàm này được gọi khi từ app tích hợp khi muốn mở modal định danh tài khoản ( yêu cầu tài khoản phải chưa định danh )
public func openKYC(
currentVC: UIViewController,
onSuccess: ([Dictionary<String, AnyObject>]) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
public func getWalletInfo(
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
-
Trong trường hợp lỗi thì hàm sẽ trả về message lỗi tại hàm
onError
, khi đó app có thể hiển thịbalance
là 0. -
Trong trường hợp thành công SDK trả về thông tin như sau:
{
"walletBalance": {
"balance": 111,
"detail": {
"cash": 1,
"lockCash": 2
}
}
}
balance : App tích hợp có thể sử dụng giá trị trong key balance để hiển thị, các field khác hiện tại chưa dùng.
detail.cash : Tiền có thể dùng
detail.lockCash: tiền bị lock
App có thể dùng được tính này sau khi khởi tạo SDK để biết được trạng thái liên kết tới ví PayME.
public func getAccountInfo(
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
Dùng để xác định các dịch vụ có thể dùng SDK để thanh toán (điện, nước, học phí...).
public func getSupportedServices(
onSuccess: ([ServiceConfig]) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
class ServiceConfig {
...
public func getCode() -> String
public func getDescription() -> String
...
}
Mở WebSDK để thanh toán dịch vụ
public func openService(
currentVC: UIViewController,
amount: Int?,
description: String?,
extraData: String?,
service: ServiceConfig,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
Chuyển đổi ngôn ngữ của sdk
public func setLanguage(language: PayME.Language) -> ()
Lấy hạn mức giao dịch thanh toán
public func getRemainingQuota(
onSuccess: @escaping (Int) -> (),
onError: @escaping (Dictionary<String, AnyObject>) -> ()
) -> ()
payCode | Phương thức thanh toán |
---|---|
PAYME | Thanh toán ví PayME |
ATM | Thanh toán thẻ ATM Nội địa |
MANUAL_BANK | Thanh toán chuyển khoản ngân hàng |
CREDIT | Thanh toán thẻ tín dụng |
VIET_QR | Thanh toán VietQR |