Skip to main content

Payouts Signature Hash Generation

Algorithm used to generate signature_hash in API requests : HMAC-SHA256

Create Payouts#

Sample Request

API - https://api.portone.cloud/api/payout/transaction

Method - POST

{
"virtual_acc_no": "902000225690",
"key": "SglffyyZgojEdXWL",
"channel_key": "EPAY_PAYOUT",
"signature_hash": "{{signature_hash}}",
"txn_details": [
{
"txn_ref": "qwerty26",
"bank_details": {
"account_no": "288477738990000",
"account_type": "0",
"account_name": "Nguyen Van AA",
"bank_no": "970423",
"bank_name": "WOORIBANK"
},
"trigger_time": "2021-08-18T15:30:00Z",
"amount": 10000,
"currency": "VND",
"remarks": "Transfer new 1"
},
{
"txn_ref": "qwerty36",
"bank_details": {
"account_no": "288477738990000",
"account_type": "0",
"account_name": "Nguyen Van AA",
"bank_no": "970423",
"bank_name": "WOORIBANK"
},
"trigger_time": "2021-08-18T15:30:00Z",
"amount": 11000,
"currency": "VND",
"remarks": "Transfer new 2"
}
]
}

Sample Code

type Timestamp time.Time
func (t *Timestamp) UnmarshalJSON(src []byte) error {
strInput := strings.Trim(string(src), `"`)
ts, err := time.Parse(time.RFC3339, strInput)
//fmt.Println(ts, src)
*t = Timestamp(ts)
return err
}
type BankInfo struct {
AccountNo string `json:"account_no"`
AccountType string `json:"account_type"`
AccountName string `json:"account_name"`
BankNo string `json:"bank_no"`
BankName string `json:"bank_name"`
}
type TxnInfo struct {
BankDetails BankInfo `json:"bank_details"`
Amount float64 `json:"amount"`
Currency string `json:"currency"`
TxnRef string `json:"txn_ref"`
TriggerTime Timestamp `json:"trigger_time"`
Remarks string `json:"remarks"`
}
type CreateTxnReq struct {
VirtualAccNo string `json:"virtual_acc_no"`
Key string `json:"key"`
ChannelKey string `json:"channel_key"`
Env string `json:"env"`
TxnDetails []TxnInfo `json:"txn_details"`
}
func GenerateSignature(data CreateTxnReq, secretKey string){
txnLs := []string{}
for _, txnDetails := range data.TxnDetails {
txnLs = append(txnLs, txnDetails.TxnRef)
txnLs = append(txnLs, txnDetails.BankDetails.AccountNo)
txnLs = append(txnLs, strconv.FormatFloat(txnDetails.Amount, 'f', -1, 64))
txnLs = append(txnLs, txnDetails.Currency)
}
params := make(url.Values)
params.Add("virtual_acc_no", data.VirtualAccNo)
params.Add("key", data.Key)
params.Add("channel_key", data.ChannelKey)
params.Add("txn_details", strings.Join(txnLs, "|"))
encoded_str := params.Encode()
secret := []byte(secretKey)
message := []byte(encoded_str)
hash := hmac.New(sha256.New, secret)
hash.Write(message)
// to base64
hash_value := base64.StdEncoding.EncodeToString(hash.Sum(nil))
return hash_value
}

Approve Payouts#

API - https://api.portone.cloud/api/merchant/payout/approve

Method - POST

Sample Request

{
"approver_email":"teststaging1@gmail.com",
"otp":"052316",
"approver_name":"teststaging1",
"txn_refs":["PARTNERTEST021631134187971232347", "PARTNERTEST021631134187965732348"],
"signature_hash": "{{signature_hash}}"
}

Sample Code

type ApproveTxnReq struct {
OTP string `json:"otp"`
ApproverName string `json:"approver_name"`
TxnRefs []string `json:"txn_refs"`
ApproverEmail string `json:"approver_email"`
}
func GenerateSignature(data ApproveTxnReq, secretKey string){
params := make(url.Values)
params.Add("approver_email", data.ApproverEmail)
params.Add("otp", data.OTP)
params.Add("txn_refs", strings.Join(data.TxnRefs, "|"))
encoded_str := params.Encode()
secret := []byte(secretKey)
message := []byte(encoded_str)
hash := hmac.New(sha256.New, secret)
hash.Write(message)
// to base64
hash_value := base64.StdEncoding.EncodeToString(hash.Sum(nil))
return hash_value
}

Virtual Account Creation#

API - https://api.portone.cloud/api/merchant/{portone-client-key}/payout/va

Method - POST

Sample Request

{
"key":"SglffyyZgojEdXWL",
"map_id": "123423412312sadf3412234234123asd4",
"customer_name": "NGUYEN VAN A",
"channel_key": "EPAY_PAYOUT",
"bank_code": "WOORIBANK",
"personal_info": {
"phone": "0987654321",
"email": "abc@gmail.com",
"address": "Me Tri, Nam Tu Liem, Ha Noi",
"id": "1233211232sd3321"
},
"signature_hash":"{{signature_hash}}"
}

Sample Code

type PersonalInf struct {
Phone string `json:"phone"`
Email string `json:"email"`
Address string `json:"address"`
Id string `json:"id"`
}
type CreateVAReq struct {
MapId string `json:"map_id"`
ChannelKey string `json:"channel_key"`
CustomerName string `json:"customer_name"`
BankCode string `json:"bank_code"`
PersonalInfo PersonalInf `json:"personal_info"`
Env string `json:"env"`
Key string `json:"key"`
}
func GenerateSignature(data CreateVAReq, secretKey string){
params := make(url.Values)
params.Add("map_id", data.MapId)
params.Add("channel_key", data.ChannelKey)
params.Add("bank_code", data.BankCode)
params.Add("phone", data.PersonalInfo.Phone)
params.Add("email", data.PersonalInfo.Email)
params.Add("key", data.Key)
encoded_str := params.Encode()
secret := []byte(secretKey)
message := []byte(encoded_str)
hash := hmac.New(sha256.New, secret)
hash.Write(message)
// to base64
hash_value := base64.StdEncoding.EncodeToString(hash.Sum(nil))
return hash_value
}

Create Beneficiary/Vendor#

API - https://api.portone.cloud/api/merchant/{portone-client-key}/payout/vendors

Method - POST

Sample Request

{
"name": "Test",
"email": "test11@abc.com",
"phone": "+9112344567810",
"address": "Test Address",
"bank_account_number":"13210013240020",
"bank_account_name":"Nguyen Van A",
"bank_name":"WOORIBANK",
"bank_account_type": "0",
"bank_no":"970423",
"signature_hash":"{{signature_hash}}"
}

Sample Code

type CreateVendorReq struct {
Name string `json:"name"`
Email string `json:"email"`
Phone string `json:"phone"`
Address string `json:"address"`
BankAccountNumber string `json:"bank_account_number"`
BankNo string `json:"bank_no"`
BankName string `json:"bank_name"`
BankAccountName string `json:"bank_account_name"`
AccountType string `json:"bank_account_type"`
}
func GenerateSignature(data CreateVendorReq, secretKey string, portoneClientKey string){
params := make(url.Values)
params.Add("key", portoneClientKey) // It is same as key SglffyyZgojEdXWL in api url.
params.Add("email", data.Email)
params.Add("phone", data.Phone)
params.Add("bank_account_number", data.BankAccountNumber)
params.Add("bank_name", data.BankName)
params.Add("bank_no", data.BankNo)
encoded_str := params.Encode()
secret := []byte(secretKey)
message := []byte(encoded_str)
hash := hmac.New(sha256.New, secret)
hash.Write(message)
// to base64
hash_value := base64.StdEncoding.EncodeToString(hash.Sum(nil))
return hash_value
}

Beneficiary/Vendor Account Verification#

API - https://api.portone.cloud/api/merchant/{portone-client-key}/payout/vendors

Method - POST

Sample Request

{
"chaipay_key":"SglffyyZgojEdXWL",
"channel_key":"EPAY_PAYOUT",
"bank_number":"970423",
"account_number":"13210013240000",
"account_name":"Nguyen Van A",
"request_id":"1234",
"type":"account",
"signature_hash":"{{signature_hash}}"
}

Sample Code in GoLang →

type VerifyAccountReqDto struct {
ChaiPayKey string `json:"chaipay_key"`
ChannelKey string `json:"channel_key"`
BankNumber string `json:"bank_number"`
AccountNumber string `json:"account_number"`
AccountName string `json:"account_name"`
RequestId string `json:"request_id"`
Type string `json:"type"`
}
func GenerateSignature(data VerifyAccountReqDto, secretKey string){
params := make(url.Values)
params.Add("channel_key", data.ChaiPayKey) // It is same as key SglffyyZgojEdXWL in api url.
params.Add("bank_number", data.BankNumber)
params.Add("channel_key", data.ChannelKey)
params.Add("account_number", data.AccountNumber)
params.Add("request_id", data.RequestId)
encoded_str := params.Encode()
secret := []byte(secretKey)
message := []byte(encoded_str)
hash := hmac.New(sha256.New, secret)
hash.Write(message)
// to base64
hash_value := base64.StdEncoding.EncodeToString(hash.Sum(nil))
return hash_value
}

Add Beneficiary Bank Account#

API - https://api.portone.cloud/api/merchant/{portone-client-key}/payout/vendors/{beneficiary-uuid}/bank-accounts

Method - PUT

Sample Request

{
"bank_name": "WOORIBANK",
"bank_no": "970423",
"account_no": "13210013240010",
"account_type": "0",
"account_name": "Nguyen Van A",
"signature_hash":"{{signature_hash}}"
}

Sample Code

type BankInfo struct {
AccountNo string `json:"account_no"`
AccountType string `json:"account_type"`
AccountName string `json:"account_name"`
BankNo string `json:"bank_no"`
BankName string `json:"bank_name"`
}
func GenerateSignature(data BankInfo, secretKey string, portoneClientKey string, vuid string ){
params := make(url.Values)
params.Add("bank_name", data.BankName) // It is same as key SglffyyZgojEdXWL in api url.
params.Add("bank_no", data.BankNo)
params.Add("account_no", data.AccountNo)
params.Add("key", portoneClientKey)
params.Add("uuid", vuid) // It is same as key aeee4466-8b50-47a0-9258-4528ff9aae07 in api url.
encoded_str := params.Encode()
secret := []byte(secretKey)
message := []byte(encoded_str)
hash := hmac.New(sha256.New, secret)
hash.Write(message)
// to base64
hash_value := base64.StdEncoding.EncodeToString(hash.Sum(nil))
return hash_value
}