Get Started with ShopeePay
Get Started
An overview of the steps to start accepting payments using ShopeePay
- Start by contacting ShopeePay team to sign the NDA (Non-Disclosure Agreement) and commercial agreement.
- Choose your integration to match your business needs:
- In-Person Payments
- Online Payments
- Please refer to the ShopeePay/SPayLater Branding Guideline for Online and In-Person Payment here to showcase the use of ShopeePay/SPayLater during payment flow
- You will be assigned onboarding credentials to start integration testing purposes.
- Develop according to the stated API rules to interact with ShopeePay Payment APIs.
- Follow the Signature Generation steps to create a signature that ShopeePay uses to verify its merchants.
- Visit API Documentations to understand the structure of each API and follow the instructions to send request to the API.
Prerequisite
Merchant should fulfill the following requirements to interact with ShopeePay APIs:
- To be compatible with OAuth 2.0 protocol and HMAC used by ShopeePay to authorize calls.
- Merchants should use TLSv1.2 or TLSv1.3 for TLS handshake.
- Merchants should integrate directly with ShopeePay endpoints without the use of a SDK.
Onboarding
Each merchant will be assigned the following credentials for integration testing purposes.
Name | Description |
---|---|
Client ID | Client refers to the party that integrate with ShopeePay APIs. Each client is assigned a unique identifier known as the ClientID, and this Client ID must be included in the request header of every API call made to ShopeePay’s services. |
Client Secret | Secret key for signature generation on transaction API. Client secret will be shared offline. |
Public Key | ShopeePay’s public key which is used by the Client to verify API response/callback. Public key will be shared offline.
|
Merchant will also be required to prepare the following information.
Name | Description |
---|---|
Callback URL | URL to receive payment success notification from ShopeePay.
|
Private Key | Client's private key which is used by the Client to sign API request.
|
Public Key | Client's public key which is used by ShopeePay to verify API request.
Generate public key in PKIX format: openssl rsa -in privatekey.pem -pubout -out public_key.pem |
API Protocol Rules
This specifies the rules for calling APIs in this document.
Component | Format/Method |
---|---|
Transfer Mode | HTTPS |
Submit Mode | POST/GET Method |
Date Format | String - ISO 8601 (yyyy-MM-ddTHH:mm:ssZ , e.g. 2022-07-20T07:15:00+07:00) |
Char Encoding | UTF-8 |
Signature | Asymmetric SHA-256withRSA, symmetric HMACSHA-512 |
Request and Response Parameter
Each API documentation includes a mandatory column for both request and response parameters. Here's what the column indicators mean:
- M - Mandatory: These parameters must be included in every request.
- O - Optional: These parameters can be omitted if not needed.
- C - Conditional: These parameters are required only under specific circumstances.
API Parameter Specification
Access Token API
Access Token API Request Header
API header format of Access Token API will require these parameters.
Field | Type | Mandatory | Description |
---|---|---|---|
Content-Type | String | M | Media type of the resource, i.e. application/json |
X-TIMESTAMP | String | M | Client’s current local time in yyyy-MM-ddTHH:mm:ss.TZD format |
X-CLIENT-KEY | String | M | ClientID issued by ShopeePay |
X-SIGNATURE | String | M | X-SIGNATURE: created using asymmetric signature SHA256withRSA algorithm (Private_Key, stringToSign) stringToSign = X-CLIENT-KEY + “|” + X-TIMESTAMP |
Access Token API Response Header
API header format of Access Token API will return these parameters.
Field | Type | Mandatory | Description |
---|---|---|---|
X-TIMESTAMP | String | M | Client’s current local time in yyyy-MM-ddTHH:mm:ss.TZD format |
X-CLIENT-KEY | String | M | ClientID issued by ShopeePay |
Transactional API
Transaction API Request Header
Each transaction request will require the following parameters in the header
Field | Type | Mandatory | Description |
---|---|---|---|
Content-Type | String | M | Media type of the resource, i.e. application/json |
X-TIMESTAMP | String | M | Client’s current local time in yyyy-MM-ddTHH:mm:ss.TZD format |
Authorization | String | C | Represents accessToken of a request, starts with keyword “Bearer” and followed by accessToken |
X-SIGNATURE | String | M | Refer to Signature Generation and Signature Generation > Transaction Request API for details. |
X-PARTNER-ID | String | M | Refers to Client ID issued by ShopeePay
|
X-EXTERNAL-ID | String (36) | M | Numeric string. Reference number that should be unique in the same day under the same ClientID |
ORIGIN | String | O | Origin domain e.g. www.domain.com |
CHANNEL-ID | String (5) | M | PJP's channel id. Sample:
|
Signature Generation
A signature is required to authenticate the request. There are 2 types of signature that merchant needs to generate:
- Signature for Access Token
- Signature for Payment API Request
Access Token API
Signature for Access Token API is generated using the asymmetricSHA256withRSA cryptographic function and merchant’s private key
The following steps outline the process for generating signature for AccessToken Request:
1. Prepare the data to do signature, the data are:
EXAMPLE
-----BEGIN PRIVATE KEY-----MIIEowIBAAKCAQEAycIMIjJ6J7Y9/X1yh19qQTmAmyVg0nYznVNwq8eykY7LjUrAY8PcdJqGZqkvu7cOE/jtuDnvv6g28w8GaaOj+cI60V/CnsbvDhW5C4DrW7/HL8coLx9xuiSSgxZy+khCY7v4IcO4L0KWP3iJysgoelW7wpTnfEEYtyDbwamOGO9R4ZX4O6nKqyolp00odSHwVB4kI1mjs7LliX/1o/EK9keWsUKzcKQVBjC3zV1xv036UkLs0Q8iYwpb3FbRlHQs9bG1H5Or6XdsQtwvfUHDWWpXRVu7ttvk//vsHRupocoV5ExJEmFuZMAKBw6cEcawAZIHuObXHhmDPmnlAxWLOwIDAQABAoIBAEPNOlajr/l4fQybA8oKfqK8uENrJEaWAnJ0gAC6c4AHBNDOtijQwV1OMKx/XtMuiUSc+wZWMgOufAjim70UiR5971Y9YCILqHqLQkxjXrTOlhmwTAjKAGYVtEbpXGpPrj/mA1UVeOgo8GUUFPpYmYHDHf4eHEzdc3jXSgKjAGXQLhZEXGBBaksR2A9f3eAUGzsVXVJAzUf+yvpj1ACV8iyPt8dz545it79vO9S4miNP2jxChqr13NrPGPOGboxRLysXTTIUZj582fquzLHD1wcUzcEL1zNINJYmEMKPgAkEWLILSpMPtIINTbdLkUGocP5WKCyAS8LDmHARkPk1WsECgYEA8tV5XAKOUZrvnfDMkW3lrq9qXmopj/rOTzecXxHbrfqbdbUMPOkRFQj9mLNKsPojnOkMrcZPQ0uUTqVsfa8n3/VTyI1jNFK986JNSadzN91ntDSgcbsAX9Tk6M2xRZ7AxTrD4lplu0xI95ZotnCiQZ3XGvb9HnYq7Upys3j/tTUCgYEA1LJxA5LeKcjDvwcIM1gc+TbIIeFhjYd32RKTuploL0vOq6RjS6KDxXlCbUKQrIvEkeb4pzgrLvY3zEcCexr0wdbpT94kp1oPM7o22BDxILLUXXD1CFfsie4O17Ddkw77KSkRaf4SHXSA7n4d2NRES7f9DsK+kjc8eUUHdF3XfK8CgYAR0ZpTJxjcYhsdItNQBJlrBRIwFWgxWX0UEQeXbk8JaC9KJtvcCFopifxZ3SYo8GH2nJ9CjR+512ztjHP2kQjDBVR9jepup3eqzgkP04q/2a5HaekwD0HKxmt5rcZJTonkrxg6ntmCMenUySOr533whK2JHACc4Jzrxp++Da3t1QKBgGMw0FmNTYQI95iHjAB90A08yfpa5CafjXmzGyfDUP31iW0sXY4xPOiD00Gm8Fc3WzV7lGxPWnwtIPpoBzUn7grT0byIaWmOK1bBOcBrrjfEjhsBiZQZhNsSJOPbvIlPTDv2xgM7FHGeGl6efAbZfvwc0qvmj/8aOV6InaBb/xlLAoGBAITXH4/7guOJWflLQhDYzuzCHFE2q+n3hJnS6TyuErezwDoDCFsXH4CJg+N/vzfduFu2fGXC8pqiXdyEX1BL6HhY1HQ3q5btD8iTRY7oIxc61T3hLKSl4njHS6+Ern1+aAJ9mNFnSPxTCs1swuKtnSQZlFNUoXa/Miw62Fek5Prb-----END PRIVATE KEY-----
Copy
Data | Description | Example |
---|---|---|
X-CLIENT-KEY | ClientID issued by ShopeePay | sample-client-id |
X-TIMESTAMP | Client’s current local time in yyyy-MM-ddTHH:mm:ss.TZD format | 2022-08-11T11:13:43+08:00 |
2. Generate the stringToSign (X-SIGNATURE) using:
EXAMPLE
<X-CLIENT-KEY> + ”|” + <X-TIMESTAMP>
Copy
Sample: sample-client-id|2022-08-11T11:13:43+08:00
3. Generate the signature by using merchant’s private key to encrypt the value using SHA256withRSA function. Sample codes in multiple programming languages are listed below step 4:
EXAMPLE
SYaKdVb4sB3Lq19TA7yDr/aH15xjteF2k1bbtWBAEOA/gIxKuSscCpZu5H5IKhPWnIweQtMBKgtUWdVncdOHOCVNRQ+SzUvHHQ7GHJTPtsedkbd3OnBHwCeh3tLPIQ5MOtHe/0WVcYwIPnZ8dj5Xa3afoUdfmFPEiK4Fb2nbc+5B9zaC+PkRtK6en1Hux4AqS9TUgdr7dR6Vat1vofe7hM7gzotjN0bHaCoH34S4WAJfPl79paZksAvl7I/E36ShgLGy2E/SOv9zChW/sOQxPLmJP8TgnM2cuKzDZBHD8Gn7ne5DGov13/N3++K/r0kU1i9kwTEZHzareSE+ObIOkQ==
Copy
4. Put the signature into Access Token HTTP header: "X-SIGNATURE"
EXAMPLE
X-SIGNATURE:SYaKdVb4sB3Lq19TA7yDr/aH15xjteF2k1bbtWBAEOA/gIxKuSscCpZu5H5IKhPWnIweQtMBKgtUWdVncdOHOCVNRQ+SzUvHHQ7GHJTPtsedkbd3OnBHwCeh3tLPIQ5MOtHe/0WVcYwIPnZ8dj5Xa3afoUdfmFPEiK4Fb2nbc+5B9zaC+PkRtK6en1Hux4AqS9TUgdr7dR6Vat1vofe7hM7gzotjN0bHaCoH34S4WAJfPl79paZksAvl7I/E36ShgLGy2E/SOv9zChW/sOQxPLmJP8TgnM2cuKzDZBHD8Gn7ne5DGov13/N3++K/r0kU1i9kwTEZHzareSE+ObIOkQ==
Copy
Go
GO EXAMPLE
import ("crypto""crypto/rand""crypto/rsa""crypto/sha256""encoding/base64")// OpenAPISha256WithRSA - sign the `payload` with `private key`func OpenAPISha256WithRSA(key *rsa.PrivateKey, payload []byte) (string, error) {h := sha256.New()h.Write(payload)hash := h.Sum(nil)signature, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hash)if err != nil {return "", err}return base64.StdEncoding.EncodeToString(signature), nil}
Copy
Transactional API
Signature for Transactional API is generated using the symmetric HMACSHA-512 cryptographic function using an access token.
The following steps outline the process for generating signature for Payment API Request:
1. Prepare the data to do signature, the data are:
Data | Description | Example |
---|---|---|
HTTP Method | Method on each API for instance: GET, POST | POST |
EndpointURL |
| /v1.0/qr/qr-mpm-generate |
AccessToken | An authorization issued to the client that used to access protected resources | AccessToken obtained by calling Access Token endpoint |
HTTP BODY | Raw body of the HTTP | { "partnerReferenceNo": "F03B527114E9G0C7FG494", "amount": { "value": "17.00", "currency": "IDR" }, "feeAmount": { "value": "0.00", "currency": "IDR" }, "merchantId": "1209121278", "terminalId": "", "validityPeriod": "2022-07-22T10:45:58+08:00", "additionalInfo": { "externalStoreId": "2233", "convenienceFeeIndicator": "01", "promoIds": "" }} |
X-TIMESTAMP | 2022-08-02T19:16:20+08:00 |
2. Minify the request body
Before Minify:
REQUEST
{"partnerReferenceNo": "F03B527114E9G0C7FG494","amount": {"value": "17.00","currency": "IDR"},"feeAmount": {"value": "0.00","currency": "IDR"},"merchantId": "1209121278","terminalId": "","validityPeriod": "2022-07-22T10:45:58+08:00","additionalInfo": {"externalStoreId": "2233","convenienceFeeIndicator": "01","promoIds": ""}}
Copy
After Minify:
REQUEST
{"partnerReferenceNo":"F03B527114E9G0C7FG494","amount":{"value":"17.00","currency":"IDR"},"feeAmount":{"value":"0.00","currency":"IDR"},"merchantId":"1209121278","terminalId":"","validityPeriod":"2022-07-22T10:45:58+08:00","additionalInfo":{"externalStoreId":"2233","convenienceFeeIndicator":"01","promoIds":""}}
Copy
3. Generate body hash: Lowercase(HexEncode(SHA-256(RequestBody))). The hex encoded SHA-256 hash of the request body should look like this:
EXAMPLE
3fb04055423bc3a488c923b134d1c9ca9de68132aef7535d3b97f614a165df8c
Copy
4. Generate the final payload by composing the stringToSig
EXAMPLE
HTTP METHOD + ":" + EndpointURL + ":" + AccessToken + ":" Lowercase(HexEncode(SHA-256(RequestBody))) ":" + <X-TIMESTAMP>
Copy
This is how the stringToSign look like:
EXAMPLE
POST:/v1.0/qr/qr-mpm-generate:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJDbGllbnRJRCI6Ik1IMjAyMjA3MDhCIiwiZXhwIjoxNjU4NzIwOTk5NjY5LCJpYXQiOjE2NTg3MTczOTk2NjksImlzcyI6Ik1IMjAyMjA3MDhCIiwibmJmIjoxNjU4NzE3Mzk5NjY5fQ.hv0dubKQTeTR4n2VK_qzf8N3MPUv1wEc8LiMa1eglVc:3fb04055423bc3a488c923b134d1c9ca9de68132aef7535d3b97f614a165df8c:2022-08-02T19:16:20+08:00
Copy
5. Generate signature using the final payload. The symmetric HMAC_SHA512 (clientSecret, stringToSign) should look like this. Sample codes in multiple programming languages are listed below step 6:
EXAMPLE
3ZcDuB8ZBJBqN+jWdoH1nmGg+z+n1hkE6JOGQ3ziWTgX+vU4+CdypOFwBNbT1SZ7zRryIFqQr5/eLHIFGO//EA==
Copy
6. Put the signature into Transactional API Request HTTP header: "X-SIGNATURE"
EXAMPLE
X-SIGNATURE: 3ZcDuB8ZBJBqN+jWdoH1nmGg+z+n1hkE6JOGQ3ziWTgX+vU4+CdypOFwBNbT1SZ7zRryIFqQr5/eLHIFGO//EA==
Copy
Note:
- EndpointURL consists of a relative path including the request parameters. For example: /1.0/get-auth-code/test?uid=1234&order_id=1234
- EndpointURL must be escaped. For example, an unescaped url looks like this/1.0/get-auth-code/test?uid=1234&order_id=1234. You need to escape the whole request parameters to /1.0/get-auth-code/test?uid%3D1234%26order_id%3D1234. You can refer here for the escape function. We suggest you to unescape first before escaping the EndpointURL. Below is a javascript example
EXAMPLE
escapedParameters = encodeURIComponent(unescape(pm.request.url.query))
Copy
- If does not have minify(Request Body), then can use empty string.
Go
GO EXAMPLE
import ("bytes""crypto/hmac""crypto/sha256""crypto/sha512""encoding/base64""encoding/hex""encoding/json""errors""fmt""io/ioutil""strings")func HmacSha512(body []byte, token string, timestamp string, method string, url string, clientSecret string) (string, error) {//1. firstly, minify your request body, remove `\n`, whitespace and so onminiBody, err := Minify(body)if err != nil {return "", err}//2. generate body hash, hash = hex.Encode(sha256(body))bodyHash := BodySha256WithHexEncode(miniBody)//3. generate final payload//noted: url will contain Request Parameters, like /base/v1/openapi_test?uid=4//noted: if body is empty, will use an empty string to generatepayload := GenPayload(method, url, token, bodyHash, timestamp)//4. use payload to generate signaturehmacsha512Hash := hmac.New(sha512.New, []byte(clientSecret))hmacsha512Hash.Write(payload)finalSign := base64.StdEncoding.EncodeToString(hmacsha512Hash.Sum(nil))fmt.Println("finalSign", finalSign)fmt.Println(payload)return finalSign, errors.New("body param error")}func BodySha256WithHexEncode(body []byte) string {hash := sha256.New()hash.Write(body)return strings.ToLower(hex.EncodeToString(hash.Sum(nil)))}func Minify(body []byte) ([]byte, error) {if len(body) == 0 {return []byte{}, errors.New("body is empty")}buff := new(bytes.Buffer)errCompact := json.Compact(buff, body)if errCompact != nil {newErr := fmt.Errorf("failure encountered compacting json := %v", errCompact)return nil, newErr}b, err := ioutil.ReadAll(buff)if err != nil {readErr := fmt.Errorf("read buffer error encountered := %v", err)return nil, readErr}return b, nil}func GenPayload(method string, url string, token string, bodyHash string, timestamp string) []byte {return []byte(fmt.Sprintf("%s:%s:%s:%s:%s", method, url, token, bodyHash, timestamp))}
Copy
Callback Signature Validation
Upon receiving the API callback, Client should verify the signature of the callback in the following ways.
1. Take the signature from HTTP header "X-SIGNATURE" in the callback request from ShopeePay
Example signature:
JS EXAMPLE
hnha4pl/3qPxBlAoRLvxzQzCt3wWqBHDTQfRkvI9o7ZDkwsM9NI0YxZVkb/TyDu7wrkv7EVubMihyt4Kn1cjpXoU9MRQ2MHFAsN9tm3R7Qj0kQwvmhCsjOSp9zPhBfT99Syg4TdjHpLPMnxPHEmarZKHPzCdcJCtdz1ohZ6ilamyjLazICXpsezf4V3bZSiXMTS1CB7r3Nc0FFq6x2dMTCV0FU0/rJT7TVtntpgHee2xtcJIPpAqb+zyEAeyBaC5oGtTqlgd5D/bmAbi+t8wPdMTWC0xVpzoHdALOPoStwaxooMiGBsuGYz5xEgCFYGPOYN5dkPS/QJHvd+DhxhbGA==
Copy
2. Generate stringToSign based on this following format:
Format:
JS EXAMPLE
HTTPMethod + ":" + callbackURL + ":" + Hex(SHA256(requestBody)) + ":" + timestamp
Copy
Note:
- The SHA256 sum needs to be formatted using hexadecimal integer.
- The value of timestamp is taken from the HTTP header "X-TIMESTAMP" in the callback request.
- ShopeePay uses full path including the domain for merhant’s callbackURL
Example:
JS EXAMPLE
POST:https://example.callback.com/Shopee/v1.0/debit/notify:2ae8474e00b1a65fc67cba1b4f6446b94bb50a0fc9f575ae10d545a2ddc98068:2024-03-04T08:44:30+07:00
Copy
3. Verify the correctness of the signature based on Asymmetric SHA-256withRSA encryption using ShopeePay public key.
Sample Codes to verify the signature:
Go
GO EXAMPLE
package mainimport ("crypto""crypto/rsa""crypto/sha256""crypto/x509""encoding/base64""encoding/pem""fmt""net/http""strings")var shopeePubkey = `-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----`// callbackURL - callback url of merchant// reqPayload - the HTTP request payload// timestamp - the value of HTTP request header X-TIMESTAMP// signToVerify - the value of HTTP request header X-SIGNATUREfunc verifySignature(callbackURL string, reqPayload string, timestamp string, signToVerify string) error {//compute string to signstringToSign := strings.Join([]string{http.MethodPost,callbackURL,fmt.Sprintf("%x", sha256.Sum256([]byte(reqPayload))),timestamp,}, ":")fmt.Println("string to sign:", stringToSign)//compute hash of string to signhashedMsg := sha256.Sum256([]byte(stringToSign))//load shopeepay public keyblock, _ := pem.Decode([]byte(shopeePubkey))var pubKey *rsa.PublicKeypubInterface, _ := x509.ParsePKIXPublicKey(block.Bytes)pubKey = pubInterface.(*rsa.PublicKey)//base64 decode the signaturesignatureByte, _ := base64.StdEncoding.DecodeString(signToVerify)//verify the signature by shopeepay public keyreturn rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, hashedMsg[:], signatureByte)}func main() {fmt.Println(verifySignature(merchantCallback, body, headers["X-TIMESTAMP"], headers["X-SIGNATURE"]))}
Copy
Response Body
The ShopeePay API response body is in JSON format.
- Parameters can be returned in random sequence.
- Additional parameters may be returned in future without advance notice from ShopeePay.
- Empty parameters may be returned in the following format by default, unless stated otherwise.
Type | Empty Response |
---|---|
Integer | 0 |
String | Empty string, or "0" if the field represents a numerical value )e.g: amount, timestamp) |
Object | Null |
Array | Empty array |
Boolean | False |
Client system’s logic should not assume that the order of arrangement of response parameters or the total number of parameters returned will remain constant throughout time.
Access Nodes
ShopeePay access nodes are country specific, each country will have their own API domains to be called.
Region Domain Suffix
Region | Abbreviation | Code |
---|---|---|
Indonesia | ID | co.id |
Append the region code to the end of the domain.
Environment | Domain |
---|---|
sandbox | api.snap.uat.airpay.co.id |
live | api.snap.airpay.co.id |
Backward Compatible Changes
Backward compatible or non-breaking changes refer to API changes that allow the integration to continue using the API without any additional changes required at Merchant’s side. ShopeePay may make such changes on their sole discretion without informing the existing Merchants in advance, as such changes are deemed to not break any integration implemented by the Merchant.
ShopeePay considers the following changes as non-breaking:
- Add new API resource or new types of server callback to a new endpoint.
- Add new or remove optional field to existing API Request Parameters.
- Add new fields to existing API response/server callback parameters.
- Increase or decrease the max length limit of existing fields on existing API response / server callback parameters.
- Change the order of fields in existing API responses or server callback parameters.
- Increase the max length limit of request fields on existing API Request Parameters.
IMPORTANT:
ShopeePay may introduce new parameters in future updates. Merchants should avoid enforcing strict validation on the response body and callback parameters to ensure seamless compatibility.