Alipay+ DocsAlipay+ Docs

Call APIs

The following section introduces the process of making a payment by calling the API provided by Alipay+. The presented sample message contains no sensitive information, therefore, encryption is not required and only request signing and signature validation are illustrated.

Note:

The display of emoji is not mandatory for Partner. If Partner does not support emoji, remove emoji data first before calling an API to ensure a success call.

Before you begin

For more information about message structure, message fields, and message transmission, see API overview.

Call an API

Take the payment interface for example, assume that the Client-Id is TEST_5X0000000000**** and the gateway is https://open-na-sandbox.alipay.com/v1/payments/pay. Contact connect_support@service.alipay.com for the request URL to be used when you perform tests.

Sample request

Sample request message body: {

copy
{
 "order":{
    "orderId":"OrderID_010101****",
    "orderDescription":"sample_order",
    "orderAmount":{
       "value":"100",
       "currency":"JPY"
    },
    "subOrders":[{
       "merchant":{
          "merchantId":"M0000000****",
          "merchantMcc":"1405",
          "merchantName":"sample_merchant",
          "store":{
             "storeId":"S000000****",
             "storeName":"sample_store",
             "storeMcc":"1405"
          }
       }
    }]
 },
 "paymentId":"201811291907410100070000001****",
 "paymentAmount":{
    "value":"100",
    "currency":"JPY"
 },
"paymentMethod":{
      "paymentMethodType": "SAMPLE_WALLET",
      "paymentMethodSubType": "PAYMENT_CODE",
      "paymentMethodId": "28100602000000000012****"
  },
 "payToAmount":{
    "value":"100",
    "currency":"JPY"
 },
 "paymentFactor": {
     "isInStorePayment": "true"
 } 
}

Signing the request

  1. Obtain your private key to sign the request. For more information about obtaining keys, see Before you begin.
  2. Create the string to sign. In this example, the value of Request-Time is 2019-05-28T12:12:12+08:00. The content to be signed is:
copy
<HTTP-method> <HTTP-URI-with-query-string>
<Client-Id>.<Request-Time>.<http body>

The content to be signed:

copy
POST /openapi/v1/payments/pay
TEST_5X00000000000000.2019-05-28T12:12:12+08:00.{
"order":{
    "orderId":"OrderID_010101****",
    "orderDescription":"sample_order",
    "orderAmount":{
       "value":"100",
       "currency":"JPY"
    },
    "subOrders":[{
       "merchant":{
          "merchantId":"M0000000****",
          "merchantMcc":"1405",
          "merchantName":"sample_merchant",
          "store":{
             "storeId":"S000000****",
             "storeName":"sample_store",
             "storeMcc":"1405"
          }
       }
    }]
 },
 "paymentId":"201811291907410100070000001****",
 "paymentAmount":{
    "value":"100",
    "currency":"JPY"
 },
 "paymentMethod":{
      "paymentMethodType": "SAMPLE _WALLET",
      "paymentMethodSubType": "PAYMENT_CODE",
      "paymentMethodId": "28100602000000000012****"
  },
 "payToAmount":{
    "value":"100",
    "currency":"JPY"
 },
 "paymentFactor": {
     "isInStorePayment": "true"
 } 
}
  1. Generate the signature. Use the algorithm and private key obtained in step 1 to generate the signature. The following example assumes that RSA256 algorithm is used to generate the signature. In this example, the content to be signed is <unsignedContent>, the algorithm used is RSA 256, and the private key value is <privateKey>. Use the following code to generate the signature:
copy
base64UrlEncode(sha256withrsa(<unsignedContent>), <privateKey>))

The generated signature:

copy
KrwDE9tAPJYBb4cUZU6ALJxGIZgwDXn5UkFPMip09n%2FkYKPhEIII%2Fki2rYY2lPtuKVgMNz%2BtuCU%
2FjzRpohDbrOd8zYriiukpGAxBQDIVbatGI7WYOcc9YVQwdCR6ROuRQvr%2FD1AfdhHd6waAASu5Xugow9
w1OW7Ti93LTd0tcyEWQYd2S7c3A73sHOJNYl8DC1PjasiBozZ%2FADgb7ONsqHo%2B8fKHsLygX9cuMkQY
TGIRBQsvfgICnJhh%2BzXV8AQoecJBTrv6p%2B7MQC4VcqJGcoLE9aqNnPCX1O8G4stEPwspYwShsjhp5A
VjeCNvk0ar9JIqQ6VZ0nMQGwZoZ6gcFw%3D%3D
  1. Add the signature to header. Assemble the signature algorithm, the key version used for the signature, and the signature into Signature header. The following example shows a finished Signature header:
copy
key: Signature;
value: algorithm=<algorithm>, keyVersion=<key-version>, signature=<signature>

Constructing the request

In this example, the request is sent by using cURL. Add Client-Id, Request-Time, and Signature to the request header:

copy
curl -X POST \
  https://open-na-sandbox.alipay.com/v1/payments/pay \
  -H 'Content-Type: application/json' \
  -H 'Client-Id: TEST_5X0000000000****' \
  -H 'Request-Time: 2019-05-28T12:12:12+08:00' \
  -H 'Signature: algorithm=RSA256, keyVersion=0, signature=KrwDE9tAPJYBb4cUZU6ALJxGIZgwDXn5UkFPMip09n%2FkYKPhEIII%2Fki2rYY2lPtuKVgMNz%2BtuCU%2FjzRpohDbrOd8zYriiukpGAxBQDIVbatGI7WYOcc9YVQwdCR6ROuRQvr%2FD1AfdhHd6waAASu5Xugow9w1OW7Ti93LTd0tcyEWQYd2S7c3A73sHOJNYl8DC1PjasiBozZ%2FADgb7ONsqHo%2B8fKHsLygX9cuMkQYTGIRBQsvfgICnJhh%2BzXV8AQoecJBTrv6p%2B7MQC4VcqJGcoLE9aqNnPCX1O8G4stEPwspYwShsjhp5AVjeCNvk0ar9JIqQ6VZ0nMQGwZoZ6gcFw%3D%3D' \
  -d '{
 "order":{
    "orderId":"OrderID_010101****",
    "orderDescription":"sample_order",
    "orderAmount":{
       "value":"100",
       "currency":"JPY"
    },
    "subOrders":[{
       "merchant":{
          "merchantId":"M0000000****",
          "merchantMcc":"1405",
          "merchantName":"sample_merchant",
          "store":{
             "storeId":"S000000****",
             "storeName":"sample_store",
             "storeMcc":"1405"
          }
       }
    }]
 },
 "paymentId":"201811291907410100070000001****",
 "paymentAmount":{
    "value":"100",
    "currency":"JPY"
 },
 "paymentMethod":{
      "paymentMethodType": "SAMPLE _WALLET",
      "paymentMethodSubType": "PAYMENT_CODE",
      "paymentMethodId": "28100602000000000012****"
  },
 "payToAmount":{
    "value":"100",
    "currency":"JPY"
 },
 "paymentFactor": {
     "isInStorePayment": "true"
 } 
}'

Handle response

After you receive a response, you need to validate the signature of the response.

Receiving the response

The response consists of response header and response body.

Sample response header:

copy
Client-Id: 5X0000000000****
Response-Time: 2019-05-28T12:12:14+08:00
signature: algorithm=RSA256, keyVersion=0,
signature=p9T2hXxIjek0UOLw3fwlthNsV6ATaioIvu8X1uFx8a9tE87d2XEhqylnf0KjifJ3WhCoMokl
GwwlDS3tsSenwnL0Ha6BsXbJvUHRC5qcVlNy5Oq%2FpNqx2%2BKdwbw4eY7tZBDQhMKoaMVSbqbCb3eRBX
sw9ZwOO%2FFCyq1zICzllOd4pbhpvES3gcw2X%2B0Ye4hQJBghcLCJxCizSv9lMyTmV%2BYA39B9gRouha
N0dM2aeAXMlVJAWtJdcL%2Bdub%2F3LrzxBnY%2B8IZ06tDOIKx7ukNvopYuhclRRtn2ls9xd%2F%2FlAZ
Twec0Z21Dq0NfrM9GrKHlzQ6C8WQBW2JuZ7FGPndGqBw%3D%3D
Trace-Id: 0ba604b4155861560080137195****.0

Sample response body:

copy
{
"result": {
	"resultCode":"SUCCESS",
	"resultStatus":"S",
	"resultMessage":"success"
},
"paymentTime": "2019-05-28T12:12:13+08:00",
"customerId":"123****"
}

Validating the signature

Use the following information to validate the signature:

  • Platform public key is: <serverPublicKey>
  • Algorithm: sha256withrsa_verify(base64UrlDecode(<signature>), <content_to_be_verified>, <serverPublicKey>)

The signature verification process consists of the following steps:

1. Retrieve the public key. Obtain Client-Id, keyVersion, and algorithm from header. If key version is not specified, the latest version is used by default. With Client-Id and keyVersion, you can then retrieve the public key for validating the signature.

2. Create the string to sign.

3. Use the algorithm obtained in step 1 to calculate a digest of the string you created in step 2. Then, decrypt the signature by using the public key to get a digest. Compare two digests, if the digests match, the signature is verified.

For example, the content to be verified is:

copy
<HTTP-method> <HTTP-URI-with-query-string>
<Client-Id>.<Request-Time|Response-Time>.<HTTP BODY>

Handle notifications

You must configure the server address to receive notifications from Alipay+ and be able to correctly response the notification. The notification information is listed in contract, and you can configure the access point for each notification accordingly.

If you use HTTPS to receive notifications, server certificates must be configured according to the authentication requirements.

About request signing and signature validation

Alipay+ provides some resources and solutions to help you sign the request and verify the signature successfully.

Resources

You can use the following library that's provided by Alipay+ to sign the request and verify the signature:

copy
<!-- https://github.com/alipay/global-open-sdk-java/ -->
<dependency>
    <groupId>com.alipay.global.sdk</groupId>
    <artifactId>global-open-sdk-java</artifactId>
    <version>1.0.6</version>
</dependency>

Sample:

copy
import org.apache.commons.io.IOUtils;
import org.apache.tomcat.util.codec.binary.Base64;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author change
 *
 * @version : OpenApiV2.java, v 0.1 November 14, 2019 15:19 change Exp $
 */
public class OpenApiV2Utils {

    public static final String SHA_256_WITH_RSA = "SHA256withRSA";

    private static String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsfeawSUF3ry2m6Mk0gzBW5xk9gDYhksds4dYDzU2aK/bUqY1cjOUn+LHGUTatyzhlKxmbw8+M4+LIGfDqYUoa73+joSa8nW4n2hx2FhPMETGeI279PCpqyIe/zwmHp55sCn7iAVd0UjEWMn4pSgzdQuChRreSGKY1iG4riebwAyzPyr41D9e4t9yl2u98fkoIMaRj2vJUqWySpL+43Up+NnXNIivTiVeZKdqj7lhyuO7ISNLraWQ0sHvu8XGxkJCt1hje0TysMXiihByAR5HppK3lKBk8Xs9mwmdl36p4x5Gv8Vvof0KdSEyyAxuExqFywl8zMp0PZ6I1WgXjQeS9QID****";

    public static void main(String[] args) throws SignatureException, UnsupportedEncodingException {

        String httpMethod = "POST";
        String uriWithQueryString = "/aps/v1/payments/inquiryForeignExchangeQuote";
        String clientId = "305Y013USG0TSD0****";
        String timeString = "2020-02-26T10:51:06+01:00";
        String content = "{\"quoteCurrencyPair\":\"EUR/GBP\",\"paymentFactor\":{\"isInStorePayment\":\"true\"},\"buyCurrency\":\"GBP\",\"sellCurrency\":\"EUR\"}";
        String payload = httpMethod + " " + uriWithQueryString + "\n" + clientId + "." + timeString + "." + content;
        String signature = "Rhspm7ETRWN1FqlZ4tXlCz9JvsK7kQsqQxvJktYc4bn245bXrHRCGGIyRE3yi20ciTrsCYe1oaWqdZNFDkSPcTfE1uWzTxdER4bEowXLiF2VUdGBsEzGaKoMZNKZt98olBmhsUKUeG%2B799ZMlVXA2Tn3yk2E7xyv2CLut37W7HhfBpmtLMls0FsCqzwfZol%2BZftdZylb3blMmGf%2B4KFrnB4Lt%2FYnA6VlvFcTHTgBryBPMKmNR9%2BcBE%2FdBk6IqbfqEjrU8dotSDpudWARIsOaYTATL%2FDsQ684H432Yzdo1Wajxbel1E0MUCIzLlm7Fu6FMBDgZwDGKhQZv%2Fckq1fHAQ%3D%3D";
        String enc = "UTF-8";

        System.out.println("verify request result : " + OpenApiV2Utils.doCheck(payload, URLDecoder.decode(signature, enc), publicKey, enc));

    }

    public static boolean doCheck(String content, String sign, String publicKey, String charset) throws SignatureException {
        try {
            PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(
                    publicKey.getBytes()));

            Signature signature = Signature
                    .getInstance(SHA_256_WITH_RSA);

            signature.initVerify(pubKey);
            signature.update(content.getBytes(charset));

            return signature.verify(Base64.decodeBase64(sign.getBytes()));
        } catch (Exception e) {
            throw new SignatureException("RSA signature validation[content = " + content + "; charset = " + charset
                    + "; signature = " + sign + "]An exception occurs!", e);
        }
    }

    public static String doSign(String content, String privateKey, String charset) throws SignatureException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(
                    privateKey.getBytes()));

            Signature signature = Signature.getInstance(SHA_256_WITH_RSA);

            signature.initSign(priKey);
            signature.update(content.getBytes(charset));

            byte[] signed = signature.sign();

            return new String(Base64.encodeBase64(signed));
        } catch (Exception e) {
            throw new SignatureException("RSA request signing[content = " + content + "; charset = " + charset
                    + "]An exception occurs!", e);
        }
    }

    private static PrivateKey getPrivateKeyFromPKCS8(String algorithm, ByteArrayInputStream ins) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            byte[] encodedKey = IOUtils.toByteArray(ins);
            encodedKey = Base64.decodeBase64(encodedKey);
            return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
        } catch (IOException var4) {
        } catch (InvalidKeySpecException var5) {
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return null;
    }

    private static PublicKey getPublicKeyFromX509(String algorithm, ByteArrayInputStream ins) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            byte[] encodedKey = IOUtils.toByteArray(ins);
            encodedKey = Base64.decodeBase64(encodedKey);
            return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
        } catch (IOException var5) {
            var5.printStackTrace();
        } catch (InvalidKeySpecException var6) {
            var6.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return null;
    }

Solutions

You might encounter problems when you sign the request or validate the signature. The following table lists typical exceptional cases that might be encountered and corresponding resolutions:

Problem

Description

Solution

Inconsistent character encodings

Different character encodings used in the request signing and signature validation might result in the failed signature validation.

Verify whether the failure is caused by the inconsistent Chinese character encodings. Sign the request with and without Chinese characters respectively and validate the signatures. Find the reasons based on the verification results. 

Line breaks and spaces included in the request message

The message in the request is constructed in a format. If the line breaks and spaces are included in the request message, the message might be inconsistent with the data in the signature, which might cause the failure of the signature validation.

Check whether line breaks and spaces are included in the request message by signing the request for a simple string and validating the signature.

Inconsistent signature and request message

The inconsistent data in the signature and request message results in the failure of the signature validation.

Print the signature and request message, and check the consistency.

Unremoved beginning and ending words

When Mobile Payment Provider uploads the public key, the beginning and ending words, which are BEGIN PUBLIC KEY and END PUBLIC KEY, are not removed.

Remove line breaks and the beginning and ending words.

Unmatched private key and public key

The public key does not match the private key.

Use the tools downloaded at the Alipay Developer Center to compare the private key and the public key.

Inconsistent algorithms and processing logics 

The algorithms and processing logics used in the request signing and signature validation are different. 

Currently the algorithm used by Alipay+ is RSA256. Check whether the value of signature in the request header is algorithm=RSA256, keyVersion=0.

Inconsistent processing rules of special characters

The base64 algorithms that are used to encode the data are inconsistent.

Use the same base64 algorithm.

Unmatched keys and the environment

The correct public keys are not used in the development environment, production environment, and the system integration testing.

Check whether the correct public key is used in the corresponding environment.

More information

Test

Go live