# Introduction

Use the Pyvio API to collect funds from online platforms and B2B buyers into global collection accounts in local currencies. You can withdraw funds to your own bank account, or pay third-party suppliers.

# SDK Download

Java SDK (opens new window)

PHP SDK (opens new window)

# Application Access

# Get App ID and App Secret

Contact the Pyvio Dev Team to obtain the app_id and app_secret for your application.

Note:

app_id identifies the developer application.

app_secret is the application secret. Keep it on your server.

# Public Key

Two RSA public keys are used.

Submit your merchant public key to Pyvio. Pyvio uses it to verify the signature on your API requests.

Pyvio provides its public key to you. Use that key to verify webhook notifications.

# IP Whitelist

Send Pyvio the IP addresses that will call the API or upload files to SFTP. Calls and uploads from other addresses are rejected.

Do not block webhook requests by source IP. Pyvio may be unable to deliver notifications if the receiver allows only a fixed address.

# API Integration Guide

# Host

  1. Sandbox: https://sandbox-api.pyvio.com

  2. Production: https://api.pyvio.com

# Http Method

Use GET to read data and POST to create or update data. Every POST request must be signed.

# Common Header

HEADER PARAMETERS
Request-Id
required
string(32)
Unique among requests in the past 7 days. A duplicate request is rejected.
Authorization
conditional
text
Bearer access token. Required on business APIs after you obtain a token.
Sign
conditional
text
RSA signature. Required on every POST request. See Request Signing.
X-Timestamp
conditional
long(ms)
Unix time in milliseconds. Required on every POST request and included in the signature.
Content-Type
conditional
enum
Required on POST requests.
One Of
application/json
X-Unit-Id
conditional
string(32)
Required when operating a sub-merchant account. Omit it for a direct merchant account. On a list query, ALL returns the current merchant and all of its sub-merchants.

# Request Signing

Every POST request must be signed. Pyvio also signs webhook notifications. The algorithm is SHA256withRSA.

Build the string to sign by concatenating app_id, X-Timestamp, and the raw HTTP body, with no separator. Sign that string, Base64-encode the result, and send it in the Sign header.

  1. When you call Pyvio, sign with your RSA private key. Pyvio verifies the signature with the merchant public key you submitted.
  2. When Pyvio sends a notification, Pyvio signs with its RSA private key. Verify that signature with the Pyvio public key.
  3. Escape emoji and non-Latin characters in the body before signing. Otherwise verification fails.
  4. Generate a 2048-bit key pair. The private key uses PKCS#8. The public key uses X.509. Tool (opens new window)
  5. Put the Base64 signature in the Sign header.

# Sample code

    package com.pyvio.developer.sdk.aop;
    
    import org.apache.commons.codec.binary.Base64;
    
    import java.security.KeyFactory;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.Signature;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    public class SignTest {
    
        /**
         * 参数签名(${appId}${timestamp}${requestBody})
         * @param content
         * @param privateKey
         * @return
         * @throws Exception
         */
        public static String sign(String content,String privateKey) throws Exception {
            Signature signature = Signature.getInstance("SHA256WithRSA");
            PrivateKey prk = getPrivateKeyFromPKCS8("RSA",privateKey);
            signature.initSign(prk);
            byte[] bytes = content.getBytes("UTF-8");
            signature.update(bytes);
            byte[] signed = signature.sign();
            return Base64.encodeBase64String(signed);
        }
    
        public static boolean signCheck(String content,String sign, String publicKey) {
            try {
                PublicKey pubKey = getPublicKeyFromX509("RSA", publicKey);
                java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
                signature.initVerify(pubKey);
                signature.update(content.getBytes("UTF-8"));
                return signature.verify(Base64.decodeBase64(sign.getBytes()));
            } catch (Exception e) {
                return false;
            }
        }
    
        private static PrivateKey getPrivateKeyFromPKCS8(String algorithm, String privateKey) throws Exception {
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            byte[] encodedKey = privateKey.getBytes();
            encodedKey = Base64.decodeBase64(encodedKey);
            return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
        }
    
        private static PublicKey getPublicKeyFromX509(String algorithm, String publicKey) throws Exception {
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            byte[] encodedKey = publicKey.getBytes();
            encodedKey = Base64.decodeBase64(encodedKey);
            return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
        }
    
        public static void main(String[] args) throws Exception {
            //partner app id
            String appId = "1569641270953589504";
            //request time
            Long timestamp = 1666332361000L;
            //partner rsa private key
            String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALxGyg3/boLT2I8dQnC3Njc2XIDJgZM/G4wqsDDUVoy/PQ2THA39sKHiLsTg71zVbQZ4+UYWm1aTlms7KuBuOmvmdIzKuI04NbSuDeAbAtnraizhELSOpVQFNom2tIGHw4/46VuF3bE0rgFjKGqrRI9xOVEcDGZlP4h9JatQEgytAgMBAAECgYADZ1dX9Awy+A+NlAFm4BQrcXFy1xt7GIGUHaSUCe3N7sxY45uB+F+vyVh6aJm74QlCaJvmQv62Lg5t1HOQ2pcHD6/r7G0lykjYJ3JEAmF3KKm/FgPqX9MGqZCBNHp3oQaHMf8WwRfjxr/EBT1QfdItCGjiENJ4bjSJo9qzEPtjSQJBAMx/r6clsTUdpeskw60UMJG17Af5Fc/SNCsq8hdmCqva0QtT1l/vprmwEH1hKXlA9au9cIESp0ceABH86jE9Vu8CQQDrsTt/S6iiWAiJKA8eYWSEcPyQXoB+tveg4ZoKUwG+fT5t9tXOuPZGmC7CWsAATfO88/ySGqNyIlFgSDvTM3YjAkB+c9JdLCyI6L1pSwGIq/xgjbrXL0oyiQvjSZoLp/ifTh6Hv57HEfzpw5pevU8VAHspaGoCFlPD4SQv+1GhgwmXAkAd6grBJ1sp7751mg4BLx9Q5/5GXJg2fQaE9t1UPiDUipTn5BJTAIrRfvNAW8BOyZYL/3OpH5RrIgvuCnz9W2S9AkB19MQtKSc3Ba36Jo3C0kvTdeSDBR4o+ah+bzhwg/Hj8EKYp4IoyW8mx32WXtSLGp8OjupPlZ65PUkzy838Eo8v";
            //partner rsa public key
            String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8RsoN/26C09iPHUJwtzY3NlyAyYGTPxuMKrAw1FaMvz0NkxwN/bCh4i7E4O9c1W0GePlGFptWk5ZrOyrgbjpr5nSMyriNODW0rg3gGwLZ62os4RC0jqVUBTaJtrSBh8OP+Olbhd2xNK4BYyhqq0SPcTlRHAxmZT+IfSWrUBIMrQIDAQAB";
            // post request json body,read from request stream
            String requestBody = "{\"grant_type\":\"client_credentials\",\"app_id\":\"1569641270953589505\",\"app_secret\":\"bc2ead7739f447c49032b4aef7818c47\"}";
    
            //generate rule
            String signContent = appId + timestamp + requestBody;
            String sign = sign(signContent,privateKey);
            System.out.println(sign);
            System.out.println(signCheck(signContent,sign,publicKey));
        }
    }
    
    
    // Make sure to add code blocks to your code group

    # Error Codes

    If a request fails, we will respond with error details. If the response is not received, it may mean that the network has timed out, and please try again.

    Response code Description
    B_XXXX Bad request. The request is invalid because a parameter is missing, the structure is wrong, or another validation failed.
    S_XXXX The request was interrupted by an unknown exception or a business rule. Read message for the reason, or contact the Pyvio Dev Team.

    # Common error codes

    Response code Description
    S_Common_SystemError The request may have encountered an unknown exception, leading to a disruption in the process. Please contact the Pyvio Dev Team for assistance.
    S_Common_DivError A business rule rejected the request. The message field explains the reason.
    B_Common_AuthError Unauthorized. Provide a valid access token.
    B_Auth_TokenInvalidError Unauthorized. Request a new access token.
    B_Common_NotFound Not found. The requested endpoint does not exist.
    B_Common_ParamError A parameter has the wrong type or failed validation.

    # Failed Example Response

    {
      "code": "S_Common_DivError",
      "message": "The provided app_id is invalid."
    }
    

    # Success Example Response

    {
      "code": "SUCCESS",
      "message": null,
      "data": {}
    }