Navbar
java ruby python php csharp cURL json
  • 概述
  • 开始之前
  • 概述
  • 操作指南
  • 账户
  • 子钱包
  • 转账
  • 收款方式
  • 更新日志
  • 概述

    epiapi是一家专注于企业级即插即用跨境金融服务产品的科技公司,在母公司Wyre的平台基础上,epiapi开发的REST API产品,可以为全球客户提供方便快捷的虚拟银行服务。

    我们的api使用HTTPS建立交互,JSON返回错误请求。为了更好地帮助您探索API产品,我们在生产环境之外额外设置了测试环境,任何在测试环境下的转账请求均不会被执行。测试及生产环境下,皆需要api key进行验签。

    开始之前

    此api标准执行手册乃针对在美国亚马逊平台使用虚拟银行服务进行收款的api产品。按照指引,开发者在通过必要的KYC信息收集后,可以通过api执行创建虚拟银行账户,接收银行账号信息,监测入账,申请提现到国内银行账户等操作。在开始之前,请确保您已就此项业务合作与epiapi公司签署纸质协议,如若未签署协议或有其他问题,请通过 contact@epiapi.com联系我们。

    Check the English Version.

    开始

    1.阅读此文档

    如果看到这里,恭喜您已经完成第一步,(记得看完)。

    2.注册测试用账户

    点击这里注册一个在测试环境下的账户。测试环境下无需上传任何文件。

    3.验证你的账户

    通过support@epiapi.com联系我们,我们可以为您验证测试账户并添加测试用款项。

    4.寻求帮助

    在账户验证通过后,我们将发送给您Slack或其他聊天工具(如钉钉、QQ)的加入邀请链接,方便您随时联系我们。

    5.注册生产环境账户

    在所有测试通过后,您可以点击这里创建一个真实账户。生产环境下,您必须填写真实信息并上传需要的文件才能通过账户验证。

    6.上线!

    完成所有步骤,可以上线啦!

    概述

    支持国家(持续更新)

    我们的虚拟银行服务目前支持通过ACH接收美元到美国银行账户。

    国家

    epiapi一直积极地在全球开展业务,如有更新,我们将以邮件形式通知您。

    货币

    请求方法

    我们提供REST风格的api,以JSON响应。

    调试时请留意,若您收到的异常响应不是以上格式,请检查您使用的服务器。

    For successful API calls:
    <!--成功的API请求示例如下-->:
    
    {
            "parameter": "en",
            "parameter": "ABCDEF"
    
    }
    
    For unsuccessful API calls:
    <!--失败的API请求示例如下-->:
    {
            "language":"en",
            "exceptionId":"ABCDEF",
            "compositeType":"",
            "subType":"",
            "message":"Error Message",
            "type":"ErrorTypeException",
            "transient":false
    }
    

    生产/测试环境下的终端节点

    我们使用生产、测试两种环境,testwyre用于测试环境,sendwyre用于生产环境。

    环境 终端节点
    测试 https://api.testwyre.com
    生产 https://api.sendwyre.com

    分页机制

    我们将返回数设定为25项/页,在任何请求中, 您都可以通过使用下面的参数进行调整。

    参数 描述
    offset 返回记录开始位置 (默认: 0).
    limit 每页返回记录数量 (默认: 25).
    from 查询范围内首条记录的创建时间,UNIX毫秒单位。(默认:0)
    to 查询范围内首条记录的创建时间,UNIX毫秒单位。(默认:现在时间)

    验签

    require 'uri'
    require 'net/http'
    require 'digest/hmac'
    require 'json'
    
    class WyreApi
      ACCOUNT_ID = 'YOUR_ACCOUNT_ID_HERE'
      API_KEY = 'YOUR_API_KEY_HERE'
      SEC_KEY = 'YOUR_SECRET_KEY_HERE'
      API_URL = 'https://api.testwyre.com'
    
      def create_transfer options
        api_post '/transfers', options
      end
    
      private
    
      def api_post path, post_data = {}
        params = {
          'timestamp' => (Time.now.to_i * 1000).to_s
        }
    
        url = API_URL + path + '?' + URI.encode_www_form(params)
    
        headers = {
          'X-Api-Key' => API_KEY,
          'X-Api-Signature' => calc_auth_sig_hash(url + post_data.to_json.to_s),
          'X-Api-Version' => '2'
        }
    
        uri = URI API_URL
        Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
          http.request_post(url, post_data.to_json.to_s, headers) do |res|
            response = JSON.parse res.body
            raise response['message'] if res.code != '200'
            return response
          end
        end
      end
    
      def calc_auth_sig_hash url_body
        return Digest::HMAC.hexdigest url_body, SEC_KEY, Digest::SHA256
      end
    end
    
    api = WyreApi.new
    api.create_transfer({'sourceAmount'=>50,'sourceCurrency'=>'USD','dest'=>'richard@epiapi.com', 'destCurrency'=>'USD', 'message'=>'buy Richard pizza')
    
    #dependencies:
    #python3
    #pip3 install requests
    
    import json
    import hmac
    import time
    from requests import request
    
    class MassPay_API(object):
        def __init__(self, account_id, api_version, api_key, api_secret):
            self.account_id = account_id
            self.api_url = 'https://api.testwyre.com/{}'.format(api_version)
            self.api_version = api_version
            self.api_key = api_key
            self.api_secret = api_secret
    
        #authentication decorator. May raise ValueError if no json content is returned
        def authenticate_request(func):
            def wrap(self, *args, **kwargs):
                url, method, body = func(self, *args, **kwargs)
                params = {}
                timestamp = int(time.time() * 1000)
                url += '?timestamp={}'.format(timestamp)
                bodyJson = json.dumps(body) if body != '' else ''
                headers = {}
                headers['Content-Type'] = 'application/json'
                headers['X-Api-Version'] = self.api_version
                headers['X-Api-Key'] = self.api_key
                headers['X-Api-Signature'] = hmac.new(self.api_secret.encode('utf-8'), (url + bodyJson).encode('utf-8'), 'SHA256').hexdigest()
                print(headers['X-Api-Signature'])
                resp = request(method=method, url=url, params=params, data=(json.dumps(body) if body != '' else None), json=None, headers=headers)
                if resp.text is not None: #Wyre will always try to give an err body
                    return resp.status_code, resp.json()
                return 404, {}
            return wrap
    
        @authenticate_request
        def retrieve_exchange_rates(self):
            url = self.api_url + '/rates'
            method = 'GET'
            body = ''
            return url, method, body
    
        @authenticate_request
        def retrieve_account(self):
            url = self.api_url + '/account'
            method = 'GET'
            body = ''
            return url, method, body
    
        @authenticate_request
        def create_transfer(self, sourceAmount, sourceCurrency, destAmount, destCurrency, destAddress, message, autoConfirm):
            url = self.api_url + '/transfers'
            method = 'POST'
            #ONLY use either sourceAmount or destAmount, see documentation
            body = {'sourceCurrency':sourceCurrency,
                    'dest':destAddress,
                    'destCurrency':destCurrency,
                    'message':message}
            if sourceAmount:
                body["sourceAmount"] = sourceAmount
            elif destAmount:
                body["destAmount"] = destAmount
            if autoConfirm:
                body['autoConfirm'] = True
            return url, method, body
    
        @authenticate_request
        def confirm_transfer(self, transfer_id):
            url = self.api_url + '/transfer/{}/confirm'.format(transfer_id)
            method = 'POST'
            body = ''
            return url, method, body  
    
        @authenticate_request
        def status_transfer(self, transfer_id):
            url = self.api_url + '/transfer/{}'.format(transfer_id)
            method = 'GET'
            body = ''
            return url, method, body  
    
    #USAGE Example
    account_id = "YOUR_ACCOUNT_ID_HERE" #optional
    api_key = "YOUR_API_KEY_HERE"
    secret_key = "YOUR_SECRET_KEY_HERE"
    api_version = "2"
    
    #create Wyre MassPay API object
    Wyre = MassPay_API(account_id, api_version, api_key, secret_key)
    
    #get account info
    http_code, account = Wyre.retrieve_account()
    print(account)
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import java.io.BufferedReader;
    import java.io.DataOutputStream;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.lang.Integer;
    import java.lang.String;
    import java.lang.StringBuffer;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class TestAuth {
      public static void main(String[] args) {
        String apiKey = "YOUR_API_KEY_HERE";
        String secretKey = "YOUR_SECRET_KEY_HERE";
    
        String url = "https://api.testwyre.com/account";
        String method = "GET";
        String data = "";
    
        String result = executeWyreRequest(url, "", method, apiKey, secretKey);
        System.out.println(result);
    
        url = "https://api.testwyre.com/transfers";
        method = "POST";
        data = "{" +
            "  \"dest\": \"richard@epiaapi.com\"," +
            "  \"destCurrency\": \"USD\"," +
            "  \"sourceCurrency\" : \"USD\"," +
            "  \"sourceAmount\" : \"50\"," +
            "  \"message\": \"buy Richard pizza\"" +
            "}";
        result = executeWyreRequest(url, data, method, apiKey, secretKey);
    
        System.out.println(result);
      }
    
      public static String executeWyreRequest(String targetURL, String requestBody, String method, String apiKey, String secretKey) {
        URL url;
        HttpURLConnection connection = null;
        try {
    
          targetURL += ((targetURL.indexOf("?")>0)?"&":"?") + "timestamp=" + System.currentTimeMillis();
    
          //Create connection
          url = new URL(targetURL);
          connection = (HttpURLConnection)url.openConnection();
          connection.setRequestMethod(method);
          System.out.println(connection.getRequestMethod());
    
          connection.setRequestProperty("Content-Type", "application/json");
          connection.setRequestProperty("Content-Length", Integer.toString(requestBody.getBytes().length));
    
          //Specify API v2
          connection.setRequestProperty("X-Api-Version","2");
    
          // Provide API key and signature
          connection.setRequestProperty("X-Api-Key", apiKey);
          connection.setRequestProperty("X-Api-Signature",computeSignature(secretKey,targetURL,requestBody));
    
          //Send request
          if(method.equals("POST")) {
            connection.setDoOutput(true);
            connection.setRequestMethod(method);
    
            DataOutputStream wr = new DataOutputStream(
                connection.getOutputStream());
    
            wr.write(requestBody.getBytes("UTF-8"));
            wr.flush();
            wr.close();
          }
    
          //Get Response
          InputStream is;
          if (connection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
            is = connection.getInputStream();
          } else {
    
            is = connection.getErrorStream();
          }
    
          BufferedReader rd = new BufferedReader(new InputStreamReader(is));
          String line;
          StringBuffer response = new StringBuffer();
          while((line = rd.readLine()) != null) {
            response.append(line);
            response.append('\r');
          }
          rd.close();
          return response.toString();
    
        } catch (Exception e) {
    
          e.printStackTrace();
          return null;
    
        } finally {
    
          if(connection != null) {
            connection.disconnect();
          }
        }
      }
    
      public static String computeSignature(String secretKey, String url, String reqData) {
    
        String data = url + reqData;
    
        System.out.println(data);
    
        try {
          Mac sha256Hmac = Mac.getInstance("HmacSHA256");
          SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
          sha256Hmac.init(key);
    
          byte[] macData = sha256Hmac.doFinal(data.getBytes("UTF-8"));
    
          String result = "";
          for (final byte element : macData){
            result += Integer.toString((element & 0xff) + 0x100, 16).substring(1);
          }
          return result;
    
        } catch (Exception e) {
          e.printStackTrace();
          return "";
        }
      }
    }
    
    <?php
        function make_authenticated_request($endpoint, $method, $body) {
            $url = 'https://api.testwyre.com';
            $api_key = "YOUR_API_KEY_HERE";
            $secret_key = "YOUR_SECRET_KEY_HERE";
    
            $timestamp = floor(microtime(true)*1000);
            $request_url = $url . $endpoint;
    
            if(strpos($request_url,"?"))
                $request_url .= '&timestamp=' . $timestamp;
            else
                $request_url .= '?timestamp=' . $timestamp;
    
            if(!empty($body))
                $body = json_encode($body, JSON_FORCE_OBJECT);
            else
                $body = '';
    
            $headers = array(
                "Content-Type: application/json",
                "X-Api-Key: ". $api_key,
                "X-Api-Signature: ". calc_auth_sig_hash($secret_key, $request_url . $body),
                "X-Api-Version: 2"
            );
            $curl = curl_init();
    
            if($method=="POST"){
              $options = array(
                CURLOPT_URL             => $request_url,
                CURLOPT_POST            =>  true,
                CURLOPT_POSTFIELDS      => $body,
                CURLOPT_RETURNTRANSFER  => true);
            }else {
              $options = array(
                CURLOPT_URL             => $request_url,
                CURLOPT_RETURNTRANSFER  => true);
            }
            curl_setopt_array($curl, $options);
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
            $result = curl_exec($curl);
            curl_close($curl);
            var_dump($result);
            return json_decode($result, true);
        }
    
        function calc_auth_sig_hash($seckey, $val) {
            $hash = hash_hmac('sha256', $val, $seckey);
            return $hash;
        }
    
        echo make_authenticated_request("/account", "GET", array());
        $transfer = array(
          "sourceCurrency"=>"USD",
          "dest"=>"richard@epiapi.com",
          "sourceAmount"=> 50,
          "destCurrency"=>"USD",
          "amountIncludesFees"=>True
          "message"=> "buy Richard pizza"
          );
        echo make_authenticated_request("/transfers", "POST", $transfer);
        ?>
    
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Security.Cryptography;
    using System.Text;
    using System.Linq;
    using Newtonsoft.Json.Linq;
    using Newtonsoft.Json;
    namespace testauthwyre
    {
        class MainClass
        {
            public static void Main(string[] args)
            {
                WyreApi wyre = new WyreApi();
                Console.WriteLine(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
                Console.WriteLine((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds);
                HttpWebResponse accountResponse = wyre.Get("/account");
                Console.WriteLine(GetResponseBody(accountResponse));
                Dictionary<string, object> body = new Dictionary<string, object>();
                body.Add("sourceCurrency", "USD");
                body.Add("sourceAmount", "50");
                body.Add("dest", "richard@epiapi.com");
                HttpWebResponse transferResponse = wyre.Post("/transfers", body);
                Console.WriteLine(GetResponseBody(transferResponse));
            }
            private static string GetResponseBody(HttpWebResponse response)
            {
                return JObject.Parse(new StreamReader(response.GetResponseStream()).ReadToEnd()).ToString(Formatting.Indented);
            }
        }
        public class WyreApi
        {
            private const String domain = "https://api.testwyre.com";
            private const String apiKey = "YOUR_API_KEY_HERE";
            private const String secKey = "YOUR_SECRET_KEY_HERE";
            public HttpWebResponse Get(string path)
            {
                return Get(path, new Dictionary<string, object>());
            }
            public HttpWebResponse Get(string path, Dictionary<string, object> queryParams)
            {
                return Request("GET", path, queryParams);
            }
            public HttpWebResponse Post(string path, Dictionary<string, object> body)
            {
                return Request("POST", path, body);
            }
            private HttpWebResponse Request(string method, string path, Dictionary<string, object> body)
            {
                Dictionary<string, object> queryParams = new Dictionary<string, object>();
                if (method.Equals("GET"))
                    queryParams = body;
                queryParams.Add("timestamp", GetTimestamp());
                string queryString = queryParams.Aggregate("", (previous, current) => previous + "&" + current.Key + "=" + current.Value).Remove(0, 1);
                string url = domain + path + "?" + queryString;
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = method;
                request.ContentType = "application/json";
                request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
                if (!method.Equals("GET"))
                {
                    url += JsonConvert.SerializeObject(body);
                    using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
                        writer.Write(JsonConvert.SerializeObject(body));
                }
                request.Headers["X-Api-Key"] = apiKey;
                request.Headers["X-Api-Signature"] = CalcAuthSigHash(secKey, url);
                request.Headers["X-Api-Version"] = "2";
                try
                {
                    return (HttpWebResponse)request.GetResponse();
                }
                catch(WebException e)
                {
                    string msg = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
                    Console.WriteLine(msg);
                    throw new SystemException(msg);
                }
            }
            private byte[] GetBytes(string str)
            {
                return Encoding.UTF8.GetBytes(str);
            }
            private string GetString(byte[] bytes)
            {
                return BitConverter.ToString(bytes);
            }
            private long GetTimestamp()
            {
                // return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() // .NET 4.6
                return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            }
            private String CalcAuthSigHash(string key, string value)
            {
                HMACSHA256 hmac = new HMACSHA256(GetBytes(key));
                string hash = GetString(hmac.ComputeHash(GetBytes(value))).Replace("-", "");
                return hash;
            }
        }
    }
    

    我们采用一系列加密机制来确保您发送请求的安全性。以下是关于如何发送安全的带验签请求的指南。

    发送带验签请求时,您需要将一系列值放入HTTP的请求头。

    HTTP 请求头 描述
    X-Api-Key 您的 API key, 点击 这里
    X-Api-Signature 用于验证的签名,由账户持有者发送。具体请查看下一步计算签名

    除此以外,您应在发送请求时将包含GET参数的时间戳放在Url之后,UNIX毫秒单位。我们会通过时间戳来避免重复请求攻击。

    计算签名

    如果发送GET请求,请将此Url计算入签名:https://api.testwyre.com/v2/rates?timestamp=1426252182534

    如果发送POST请求,请将此Url计算入签名:https://api.testwyre.com/v2/transfers?timestamp=1426252182534

    请留意发送POST请求时,必须将请求体(request body)加在URL字符串之后。请求体必须按原样发送,不得修改。服务器会据此计算其内容。

    计算签名步骤:

    1.request URL 加 HTTP 请求体,串联生成 UTF-8 编码字符串。GET的请求体则创建空白字符串。

    2.使用HMAC-SHA256协议,以及您的API密钥计算签名。

    资源名称

    SRN是我们平台约定的,调用库内各项数据时使用的资源名称。许多我们的API交互和数据库框架都需要用到SRN,它大大增加了集成开发的灵活性,也为后续隔离开发其他服务提供便利。所有资源名称皆遵照如下格式:

    类型 描述
    contact 联系人识别号 (contact:CO-123123123)
    paymentmethod 收款方式 (paymentMethod:PA-123123123)
    email 邮箱地址 (email:test@epiapi.com)
    cellphone 手机号码 (cellphone:+8615555555555)
    account 平台账户号 (account:AC-123123123)
    wallet 子钱包 (wallet:WA-123123123)
    transfer 转账 (可能包含结汇) (transfer:TF-123123123)

    费用

    我们将根据双方签署的纸质协议计算费用。VBA+每日结算的标准服务收费为0.25%。

    错误处理

    请求成功后,返回值为HTTP 200,请求体具体格式取决于终端节点。

    如果出现错误,返回值为4XX或5XX的状态码,具体描述参见下表:

    错误 描述 HTTPs状态码
    ValidationException 请求执行失败 400
    UnknownException 系统内部错误,极少出现 500
    InsufficientFundsException 账户内没有足够余额来执行请求 400
    RateLimitException 请求受限,请联系客服增加请求次数 429
    AccessDeniedException 没有权限执行相关请求 401
    TransferException 转账请求出现问题 400
    NotFoundException 请求中有相关内容未能查找到 400
    ValidationException 请求中有相关内容未能通过验证 400
    CustomerSupportException 请通过 support@epiapi.com 联系客服来解决此问题 400
    MFARequiredException 需要多重验证来执行请求,通常在使用API密钥的情况下不会出现此类情况 400

    所有错误描述都会附带子类型参数来解释该错误的详细信息。除此之外,一些验证失败返回值会带有两个字段,问题字段和问题值,详细指出错误位置。

    一些常见的验证失败子类:

    FIELD_REQUIRED 字段未填写

    INVALID_VALUE 无效值

    TRANSACTION_AMOUNT_TOO_SMALL 交易值过小

    UNSUPPORTED_SOURCE_CURRENCY 非支持货币种类

    CANNOT_SEND_SELF_FUNDS 自账户不能转账

    INVALID_PAYMENT_METHOD 收款方无效

    PAYMENT_METHOD_INACTIVE 收款方未激活

    PAYMENT_METHOD_UNSUPPORTED_CHARGE_CURRENCY 不支持该币种转账

    PAYMENT_METHOD_UNCHARGEABLE 不支持此付款方式充值

    PAYMENT_METHOD_UNSUPPORTED_DEPOSIT_CURRENCY 不支持该币种充值

    操作指南

    以下指南将为您详细解读通过api交互创建美元收款产品的全部步骤。

    虚拟银行

    在epiapi平台搭建自己的美元收款产品

    epiapi提供多种api集成方式,帮助您按需求搭建不同类型收款产品。为了帮助开发者更好地理解我们的系统如何运行,以下将为您提供一个典型的使用案例。

    这是一家在线平台如何利用epiapi搭建产品,从而为其用户提供独立账号的美元收款服务的整个流程,包括创建虚拟银行子钱包,接收款项,并结算至用户账户等。

    1.使用KYC数据创建子钱包

    epiapi使用子钱包(wallet)这一概念来描述个人商家的账户,子钱包统一创建在您的母账户(account)之下。创建后,每一个子钱包都具有独立的收款功能。请注意在Type字段必须为type=VBA,否则将无法收到虚拟银行服务账号的银行信息。

    POST https://api.testwyre.com/v2/wallets

    {
      "name":"youruniquename",
      "type":"VBA",
      "callbackUrl":"https://your.website.io/callback",
      "vbaVerificationData":{
        "entityType":"CORP",
        "entityScope":"Shopping/Retail",
        "email":"test+merchant@epiapi.com",
        "phoneNumber":"13111111111",
        "ip": "127.0.0.1",
        "nameCn":"法人姓名",
        "nameEn":"Legal Rep",
        "dateOfBirth":1514736000,
        "address":{
          "city":"北京",
          "country":"CN",
          "postalCode":"210000",
          "street1":"东四北大街107号",
          "street2":"克林大厦107室"},
        "idNumber":"432524199902287897",
        "idDoc":null,
        "merchantIds":[{
        "merchantId":"AAAAAAAAAAA",
        "merchantType":"Amazon"}],
        "expectedMonthlySales":40000,
        "shopName":"MyBrand",
        "website":"https://merchant.website.com",
        "repAaddress":{
          "city":"北京",
          "country":"CN",
          "postalCode":"210000",
          "street1":"东四北大街107号",
          "street2":"克林大厦107室"},
        "companyNameCn":"ABC有限责任公司",
        "companyNameEn":"ABC Company Limited",
        "registrationNumber":"123456789",
        "coiDoc":null,
        "salesDoc":null,
        "dateOfEstablishment":1514736000,
        "beneficialOwners":[{
          "fullName":"Richard",
          "idNumber":"1231321312",
          "idDoc":null}]
          }
    }
    


    KYC 资料

    字段(* 代表必填) 描述
    "entityType" * 可填"CORP"、“M”、“F”
    "entityScope" * "Shopping/Retail"
    "email" * "test+merchant@epiapi.com"
    "phoneNumber" * "13111111111"
    "ip" * “登陆店铺常用IP地址”
    "nameCn" * "法人姓名"
    "nameEn" * "Legal Rep" 拼音,全大写
    "dateOfBirth" * UNIX毫秒单位
    "address" * (street 2 可以不填)
    "street1" "东四北大街107号"
    "street2" "克林大厦107室"
    "city" "beijing"
    "state" "beijing"
    "country" "CN"
    "postalCode" "100007"
    "idNumber" * "432524199902287897"
    "idDoc" * null
    "merchantId" "A00000"
    "merchantType" "Amazon"
    "expectedMonthlySales" 40000
    "shopName" "MyBrand"
    "website" "https://merchant.website.com"
    "repAaddress"(* 限企业) (street 2 可以不填)
    "street1" "东四北大街107号"
    "street2" "克林大厦107室"
    "city" "beijing"
    "state" "beijing"
    "country" "CN"
    "postalCode" "100007"
    "companyNameCn"(* 限企业) "ABC有限责任公司"
    "companyNameEn"( * 限企业) "ABC Company Limited"
    "registrationNumber"(* 限企业) "123456789"
    "coiDoc"(* 限企业) null
    "salesDoc"(流水额高的商户可能需要提供) null
    "dateOfEstablishment" * UNIX毫秒单位
    "beneficialOwners"(仅限香港注册企业)
    "fullName" "Richard"
    "idNumber" "1231321312"
    "idDoc" null
    curl -v -XPOST 'https://api.testwyre.com/v2/wallets' \
      -H "Content-Type: application/json" \
      -H "X-Api-Key: {api-key}" \
      -H "X-Api-Signature: {signature}" \
      -d '{"type":"VBA","name":"{your-unique-identifier}"
    
    {
      "callbackUrl":"https://your.website.io/callback",
      "name":"12345678977897800",
      "type":"VBA",
      "vbaVerificationData":{
        "entityType":"CORP",
        "entityScope":"Shopping/Retail",
        "email":"test+merchant@epiapi.com",
        "phoneNumber":"13111111111",
        "ip":"127.0.0.1",
        "nameCn":"法人姓名",
        "nameEn":"Legal Rep",
        "dateOfBirth":1514736000,
        "address":{
          "city":"北京",
          "country":"CN",
          "postalCode":"210000",
          "street1":"东四北大街107号",
          "street2":"克林大厦107室"},
        "idNumber":"432524199902287897",
        "idDoc":null,
        "merchantIds":[{
        "merchantId":"AAAAAAAAAAA",
        "merchantType":"Amazon"}],
        "expectedMonthlySales":40000,
        "shopName":"MyBrand",
        "website":"https://merchant.website.com",
        "repAaddress":{
          "city":"北京",
          "country":"CN",
          "postalCode":"210000",
          "street1":"东四北大街107号",
          "street2":"克林大厦107室"},
        "companyNameCn":"ABC有限责任公司",
        "companyNameEn":"ABC Company Limited",
        "registrationNumber":"123456789",
        "coiDoc":null,
        "salesDoc":null,
        "dateOfEstablishment":1514736000,
        "beneficialOwners":[{
          "fullName":"Richard",
          "idNumber":"1231321312",
          "idDoc":null}]
          }
        }
    

    平台用户申请使用VBA服务时,为这个用户创建钱包

    注:

    1.根据相关法规要求,为了给用户开通虚拟银行服务,您需要从用户处收集必要的KYC信息并将其通过终端节点传送给我们。钱包会立即开通,相关的银行信息将在之后该账户被银行批准时提供。(步骤3)

    2.每个子钱包将在创建时自动生成一个子钱包id。

    3.请将返回记录中的walletId记录下来,稍后将会用到。

    2.上传KYC文件

    POST https://api.testwyre.com/v2/documents

    创建VBA子钱包需要提供以下文件来通过KYC审查,通过后才能获得accountNumber。通过此终端节点上传完文件后,返回记录中将包含步骤3所需的documentId

    更新时请在Url之后加入如下参数:

    字段 |描述 --------- | ownerSrn: |"wallet:[WALLET_ID]" filename |文件名,(可填): "coiDoc.pdf"

    示例 POST https://api.testwyre.com/v2/documents?ownerSrn=wallet:WA-123123123&filename=coiDoc.pdf

    在请求体中包含原始字节文件上传。

    public static String computeSignature2(String secretKey,String url, byte[] reqData) throws UnsupportedEncodingException {
    
           byte[] urlBytes = url.getBytes("UTF-8");
    
           byte[] data = new byte[urlBytes.length+reqData.length];
    
           System.arraycopy(urlBytes,0,data,0,urlBytes.length);
           System.arraycopy(reqData,0,data,urlBytes.length,reqData.length);
    
           try {
               Mac sha256Hmac = Mac.getInstance("HmacSHA256");
               SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
               sha256Hmac.init(key);
    
               byte[] macData = sha256Hmac.doFinal(data);
    
               StringBuffer result = new StringBuffer();
               for (final byte element : macData){
                   result.append(Integer.toString((element & 0xff) + 0x100, 16).substring(1));
               }
               return result.toString();
    
           } catch (Exception e) {
               e.printStackTrace();
               return "";
           }
       }
    

    最后,请求头中应反映文件类型,允许上传的文件类型有:

    文件类型
    "application/msword"
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
    "application/pdf"
    "image/jpg"
    "image/jpeg"
    "image/png"


    文件上传成功后,返回将接收到名为"document"的对象。将每一项的文件id( 如DO-123123123 )记录下来,填入创建钱包请求体的相关字段中。

    字段 描述
    idDoc 身份证明(中国大陆居民此项必须提供二代身份证)
    coiDoc 企业营业执照
    salesDoc 网店销售流水*

    对于亚马逊商户-请使用ListFinancialEventsGroup接口获取并上传内容为近三个月销售记录的xml文件。

    3. 填入KYC数据

    一旦文件上传成功后,将生成与子钱包关联的资源名称。为了区别每个文件,请将Id一一对应填入vbaVerificationData字段的相关字段:

    {
      "vbaVerificationData":{
        "coiDoc":"DO-123123123",
        "idDoc":"DO-123123124",
        "salesDoc":"DO-123123125"
      }
    }
    


    4. 查询银行信息

    银行信息将作为object添加到子钱包里的vbaData字段下。

    {   
      "vbaData": {
        "bankName":"Evolve Bank & Trust",
        "bankAddress": "6070 Poplar Ave #100, Memphis TN 38119",
        "beneficiaryName":"Zhang San",
        "bankAccountNumber":"123123123",
        "routingNumber":"084106768"}
      }
    


    使用 GET https://api.testwyre.com/v2/wallet/[walletID] 查询子钱包的银行信息。将查询请求发送次数限制为每小时1次,查询到信息后即停止查询请求。稍后我们将为此类场景单独创建一个回调。

    一旦收到信息后,您可以将银行信息发给用户,让用户在自己的店铺后台进行收款信息更新。

    5.接收款项与回调

    如果提前设置了callbackUrl,当用户的accountNumber接收到一笔款项,且款项成功入账后(从非合作平台打入的款项将被拒绝),您将收到入账的返回信息。

    查看回调

    如果需要验证回调,可以使用IdGET必要的信息。epiapi系统内每笔转账都有独立的id (如 TF-123123123) 来供查询,查看: https://api.testwyre.com/v2/transfer/[id]

    外部入账如亚马逊款项入账的情况,则会创建交易id (如 TR-123123123) 来供查询,查看: https://api.testwyre.com/v2//transaction/[id]


    Result Format

    {
      "createdAt":1531445525097,
      "id":"TR-F3947W8C2C6",
      "source":"transfer:TF-HP4A42EC6DX",
      "dest":"wallet:WA-CF9RFZ7QU6W",
      "currency":"USD",
      "amount":5005.00,
      "status":"CONFIRMED",
      "confirmedAt":1531445525097,
      "cancelledAt":null,
      "reversedAt":null,
      "message":"Deposit for transfer TF-HP4A42EC6DX",
      "allowOverdraft":true,
      "authorizer":"account:AC-XXXXXXXXX",
      "senderProvidedId":null,
      "reversedBy":null,
      "fees":0,
      "feesDest":null,
      "metadata":{
        "Description":"Pending: Transfer of $5005.00 to wallet:WA-CF9RFZ7QU6W",
        "transferId":"TF-HP4A42EC6DX"},
        "tags":[],
        "sourceFees":null,
        "destFees":null
      }
    


    6. 将美元从子钱包转至母账户

    POST https://api.testwyre.com/v2/transfers

    {
    "source": "wallet:walletId",
    "dest": "account:accountId",
    "sourceCurrency": "USD",
    "destCurrency": "USD",
    "destAmount": 1000,
    "autoConfirm": "true",
    "message":"Merchant Test"
    }
    

    点击这里查询母账户id。

    然后将美元款项转账至事先准备好的结算账户(注:账户创建时,epiapi默认将结算账户创建为paymentMethod)。

    {
    "source": "account:accountId",
    "dest": "paymentMethod:paymentMethodId",
    "sourceCurrency": "USD",
    "destCurrency": "USD",
    "sourceAmount": 1000,
    "amountIncludesFees": "true",
    "autoConfirm": "true",
    "message":"Merchant Test"
    }
    

    autoConfirm(自动确认)的值设置为‘true’,来自动确认转账。

    账户

    账户信息

    此终端节点将用于取回您账户的相关信息

    定义

    GET https://api.testwyre.com/v2/account

    查询availableBalance(可用余额)来获取账户余额信息,此项将返回按照目的币种汇率换算后可转账金额。

    字段 描述
    ID 账户内部识别号
    createdAt 账户创建时间
    updatedAt 账户最后更新时间
    loginAt 账户最后登录时间
    rank 账户排名,主要用于识别账户权限,例如购买外汇上限
    profile 账户信息,一组用户有权限更改的字段
    paymentMethods 账户收款方式
    identities 一组关联账户个人身份信息的数组,如电话邮箱等,此处包含的信息需与账户创建验证时一致
    depositAddresses 账户下储存货币地址
    totalBalances 账户下所有余额,包括处理中和可用余额
    availableBalances 账户下目前可用余额,如果需要查询账户内有多少余额可供提现操作,请查询此项
    email 绑定的邮箱
    cellphone 绑定的手机号


    Result Format

    {
      "id": "121pd02kt0rnb24nclsg4bglanimurqp",
      "createdAt": 1404177262332,
      "updatedAt": 1404177262332,
      "loginAt": 1404177262332,
      "rank": 0,
      "profile": {
        "firstName": "",
        "lastName": "",
        "locale": "EN_us",
        "address": {
          "street1": null,
          "street2": null,
          "city": null,
          "state": null,
          "postalCode": null,
          "country": "USA"
        },
        "businessAccount": true,
        "taxId": null,
        "doingBusinessAs": null,
        "website": null,
        "dateOfBirth": 1404177262332,
        "notifyEmail": true,
        "notifyCellphone": true,
        "notifyApnsDevice": true,
        "mfaRequiredForPwChange": false,
        "mfaRequiredForDcPurchase": false,
        "mfaRequiredForSendingFunds": false,
        "authyPhoneNumber": null
      },
      "paymentMethods": [],
      "identities": [
        {
          "srn": "email:richard@apiepi.com",
          "createdAt": 1404177262332,
          "verifiedAt": 1404177262332
        }
      ],
      "depositAddresses": {
        "BTC": "1H9K67J9NcYtzmFGojR9cgM5ybxEddySwu"
      },
      "totalBalances": {
        "USD": 11.8934023
      },
      "availableBalances": {
        "USD": 10.8934023,
      },
      "email": "richard@apiepi.com",
      "cellphone": "+12312313112"
    }
    

    子钱包

    epiapi使用子钱包来指代每个商户的独立收款账户。在使用VBA进行跨境收款时,所有子钱包创建类型均为type=VBA。以下图表显示了一组典型的收款流程。

    Flow-Zh.png

    创建子钱包

    curl -v -XPOST 'https://api.testwyre.com/v2/wallets' \
      -H "Content-Type: application/json" \
      -H "X-Api-Key: {api-key}" \
      -H "X-Api-Signature: {signature}" \
      -d '{"type":"ENTERPRISE","name":"{your-unique-identifier}",
      "callbackUrl":"https://your.website.io/callback",
      "notes":"Notes about the sub account"}'
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import java.io.BufferedReader;
    import java.io.DataOutputStream;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.lang.Integer;
    import java.lang.String;
    import java.lang.StringBuffer;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class Main {
      public static void main(String[] args) {
        String accountId = "k3f48j0rb2rp65c0sdog67vi43u80jas";
        String apiKey = "fll36l3t35udalcqlh4ng6bm4qpbgher";
        String secretKey = "tr3epinbk3maist0n3ijk18bm6dikrq6";
    
        String url = "https://api.testwyre.com/v2/wallets";
        String method = "POST";
        String data = "";
    
        String result = excuteWyereRequest(url, "", method, apiKey, secretKey);
        System.out.println(result);
    
        data = "{" +
            "  \"type\":\"ENTERPRISE\"," +
            "  \"name\":\"{your-unique-identifier}\"," +
            "  \"callbackUrl\":\"https://your.website.io/callback\"," +
            "  \"notes\":\"Notes about the user\"," +
            "  \"verificationData\": {" +
            "      \"firstName\":\"{users-first-name}\"," +
            "      \"middleName\":\"{users-middle-name}\"," +
            "      \"lastName\":\"{users-last-name}\"," +
            "      \"ssn\":\"0000\"," +
            "      \"passport\":\"123456\"," +
            "      \"birthDay\":\"1\"," +
            "      \"birthMonth\":\"1\"," +
            "      \"birthYear\":\"1970\"," +
            "      \"phoneNumber\":\"+15555555555\"," +
            "      \"address\": {" +
            "          \"street1\":\"1 Market Street\"," +
            "          \"street2\":\"Suit 420\"," +
            "          \"city\":\"San Francisco\"," +
            "          \"state\":\"CA\"," +
            "          \"postalCode\":\"94105\"," +
            "          \"country\":\"US\"" +
            "      }" +
            "  }" +
            "}";
        result = excuteWyreRequest(url, data, method, apiKey, secretKey);
    
        System.out.println(result);
      }
    
      public static String excuteWyreRequest(String targetURL, String requestBody, String method, String apiKey, String secretKey) {
        URL url;
        HttpURLConnection connection = null;
        try {
    
          targetURL += ((targetURL.indexOf("?")>0)?"&":"?") + "timestamp=" + System.currentTimeMillis();
    
          //Create connection
          url = new URL(targetURL);
          connection = (HttpURLConnection)url.openConnection();
          connection.setRequestMethod(method);
          System.out.println(connection.getRequestMethod());
    
          connection.setRequestProperty("Content-Type", "application/json");
          connection.setRequestProperty("Content-Length", Integer.toString(requestBody.getBytes().length));
    
          //Specify API v2
          connection.setRequestProperty("X-Api-Version","2");
    
          // Provide API key and signature
          connection.setRequestProperty("X-Api-Key", apiKey);
          connection.setRequestProperty("X-Api-Signature",computeSignature(secretKey,targetURL,requestBody));
    
          //Send request
          if(method.equals("POST")) {
            connection.setDoOutput(true);
            connection.setRequestMethod(method);
    
            DataOutputStream wr = new DataOutputStream(
                connection.getOutputStream());
    
            wr.writeBytes(requestBody);
            wr.flush();
            wr.close();
          }
    
          //Get Response
          InputStream is = connection.getInputStream();
          BufferedReader rd = new BufferedReader(new InputStreamReader(is));
          String line;
          StringBuffer response = new StringBuffer();
          while((line = rd.readLine()) != null) {
            response.append(line);
            response.append('\r');
          }
          rd.close();
          return response.toString();
    
        } catch (Exception e) {
    
          e.printStackTrace();
          return null;
    
        } finally {
    
          if(connection != null) {
            connection.disconnect();
          }
        }
      }
    
      public static String computeSignature(String secretKey, String url, String reqData) {
    
        String data = url + reqData;
    
        System.out.println(data);
    
        try {
          Mac sha256Hmac = Mac.getInstance("HmacSHA256");
          SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
          sha256Hmac.init(key);
    
          byte[] macData = sha256Hmac.doFinal(data.getBytes());
    
          String result = "";
          for (final byte element : macData){
            result += Integer.toString((element & 0xff) + 0x100, 16).substring(1);
          }
          return result;
    
        } catch (Exception e) {
          e.printStackTrace();
          return "";
        }
      }
    }
    
    #dependencies:
    #python3
    #pip3 install requests
    
    import json
    import hmac
    import time
    from requests import request
    
    class MassPay_API(object):
        def __init__(self, account_id, api_version, api_key, api_secret):
            self.account_id = account_id
            self.api_url = 'https://api.testwyre.com/{}'.format(api_version)
            self.api_version = api_version
            self.api_key = api_key
            self.api_secret = api_secret
    
        #authentication decorator. May raise ValueError if no json content is returned
        def authenticate_request(func):
            def wrap(self, *args, **kwargs):
                url, method, body = func(self, *args, **kwargs)
                params = {}
                timestamp = int(time.time() * 1000)
                url += '?timestamp={}'.format(timestamp)
                bodyJson = json.dumps(body) if body != '' else ''
                headers = {}
                headers['Content-Type'] = 'application/json'
                headers['X-Api-Version'] = self.api_version
                headers['X-Api-Key'] = self.api_key
                headers['X-Api-Signature'] = hmac.new(self.api_secret.encode('utf-8'), (url + bodyJson).encode('utf-8'), 'SHA256').hexdigest()
                print(headers['X-Api-Signature'])
                resp = request(method=method, url=url, params=params, data=(json.dumps(body) if body != '' else None), json=None, headers=headers)
                if resp.text is not None: #Wyre will always try to give an err body
                    return resp.status_code, resp.json()
                return 404, {}
            return wrap
    
        @authenticate_request
        def create_user(self, name, callbackUrl, notes, verificationData):
            url = self.api_url + '/wallets'
            method = 'POST'
            body = {'name':name,
                    'verificationData':verificationData,
                    'type':'ENTERPRISE'}
            if callbackUrl:
                body["callbackUrl"] = callbackUrl
            if notes:
                body['notes'] = notes
            return url, method, body
    
    #USAGE Example
    account_id = "YOUR_ACCOUNT_ID_HERE" #optional
    api_key = "YOUR_API_KEY_HERE"
    secret_key = "YOUR_SECRET_KEY_HERE"
    api_version = "2"
    
    #create Wyre MassPay API object
    Wyre = MassPay_API(account_id, api_version, api_key, secret_key)
    
    #create user and print result
    http_code, result = Wyre.create_user(
                                    "{your-unique-identifier}",
                                    "https://your.website.io/callback",
                                    None, #notes
                                    {
                                      "firstName": "{users-first-name}",
                                      "middleName": "{users-middle-name}",
                                      "lastName": "{users-last-name}",
                                      "ssn": "0000",
                                      "passport": "123456",
                                      "birthDay": "1",
                                      "birthMonth": "1",
                                      "birthYear": "1970",
                                      "phoneNumber": "+15555555555",
                                      "address": {
                                        "street1":"1 Market Street",
                                        "street2":"Suite 420",
                                        "city":"San Francisco",
                                        "state":"CA",
                                        "postalCode":"94105",
                                        "country":"US"
                                      }
                                    })
    print(result)
    users_srn = result['srn'] #grab our srn identifier for the user
    '''
    
    '''php
    <?php
        function make_authenticated_request($endpoint, $method, $body) {
            $url = 'https://api.testwyre.com';
            $api_key = "bh405n7stsuo5ut30iftrsl71b4iqjnv";
            $secret_key = "a19cvrchgja82urvn47kirrlrrb7stgg";
    
            $timestamp = floor(microtime(true)*1000);
            $request_url = $url . $endpoint;
    
            if(strpos($request_url,"?"))
                $request_url .= '&timestamp=' . $timestamp;
            else
                $request_url .= '?timestamp=' . $timestamp;
    
            if(!empty($body))
                $body = json_encode($body, JSON_FORCE_OBJECT);
            else
                $body = '';
    
            $headers = array(
                "Content-Type: application/json",
                "X-Api-Key: ". $api_key,
                "X-Api-Signature: ". calc_auth_sig_hash($secret_key, $request_url . $body),
                "X-Api-Version: 2"
            );
            $curl = curl_init();
    
            if($method=="POST"){
              $options = array(
                CURLOPT_URL             => $request_url,
                CURLOPT_POST            =>  true,
                CURLOPT_POSTFIELDS      => $body,
                CURLOPT_RETURNTRANSFER  => true);
            }else {
              $options = array(
                CURLOPT_URL             => $request_url,
                CURLOPT_RETURNTRANSFER  => true);
            }
            curl_setopt_array($curl, $options);
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
            $result = curl_exec($curl);
            curl_close($curl);
            var_dump($result);
            return json_decode($result, true);
        }
    
        function calc_auth_sig_hash($seckey, $val) {
            $hash = hash_hmac('sha256', $val, $seckey);
            return $hash;
        }
    
        $userData = array(
          "type"=>"ENTERPRISE",
          "name"=>"{your-unique-identifier}",
          "callbackUrl"=>"https://your.website.io/callback",
          "notes"=> "Notes about the user",
          "verificationData"=> array(
              "firstName"=> "{users-first-name}",
              "middleName"=> "{users-middle-name}",
              "lastName"=> "{users-last-name}",
              "ssn"=> "0000",
              "passport"=> "12345",
              "birthDay"=> "1",
              "birthMonth"=> "1",
              "birthYear"=> "1970",
              "phoneNumber"=> "+15555555555",
              "address"=> array(
                "street1":"1 Market Street",
                "street2":"Suite 420",
                "city":"San Francisco",
                "state":"CA",
                "postalCode":"94105",
                "country":"US"
              )
            )
          );
        echo make_authenticated_request("/wallets", "POST", $userData);
    ?>
    

    定义

    POST https://api.testwyre.com/v2/wallets

    参数

    参数 类型 描述 是否需要
    name string 用户名 yes
    callbackUrl string 钱包数据或信息更新时将通过callbackUrl发送回传 no
    type string 创建钱包类型,默认为 DEFAULT no
    notes string 关于此用户的附注 no


    Result Format

    {
      "name" : "{your-unique-identifier}",
      "id" : "WA-AYBNA3lBiWAM4l3",
      "depositAddresses" : {
        "BTC" : "2ShL7kzSNNxedit6hC2fjSQhVcAucTeS1m7"
      },
      "totalBalances" : {
        "BTC" : 0
      },
      "availableBalances" : {
        "BTC" : 0
      },
      "srn" : "wallet:AYBNA3lBiWAM4l3",
      "balances" : {
        "BTC" : 0
      },
      "callbackUrl" : "https://your.website.io/callback",
      "notes" : "Notes about the user"
    }
    


    创建多个子钱包

    
    curl -XPOST 'https://api.testwyre.com/v2/wallets/batch?pretty' \
    -H 'Content-Type:application/json' \
    -d '{
      "wallets":[
        {"name":"walletOne"},
        {"name":"walletTwo"},
        {"name":"walletThree"}
      ]
    }'
    

    此终端节点允许通过一个请求创建多个子钱包(每用户一个)。

    定义

    POST https://api.testwyre.com/v2/wallets/batch

    参数

    参数 类型 描述 是否需要
    wallets array 每个子钱包对象的数组 yes


    Result Format

    {
      "name" : "walletOne",
      "id" : "AxVA57edP0H33x3",
      "notes" : null,
      "srn" : "wallet:AxVA57edP0H33x3",
      "callbackUrl" : null,
      "verificationData" : null,
      "depositAddresses" : {
        "BTC" : "2ShKKFb9gEP5uvRXtMbs7ykJAMPgoSSnSWB"
      },
      "totalBalances" : {
        "BTC" : 0
      },
      "availableBalances" : {
        "BTC" : 0
      },
      "balances" : {
        "BTC" : 0
      }
    }, {
      "name" : "walletTwo",
      "id" : "AtEhoXje3C1V5zq",
      "notes" : null,
      "srn" : "wallet:AtEhoXje3C1V5zq",
      "callbackUrl" : null,
      "verificationData" : null,
      "depositAddresses" : {
        "BTC" : "2ShKndBJNHvzABhBzLxvfzzD2vt64C36dPc"
      },
      "totalBalances" : {
        "BTC" : 0
      },
      "availableBalances" : {
        "BTC" : 0
      },
      "balances" : {
        "BTC" : 0
      }
    }, {
      "name" : "walletThree",
      "id" : "U07tSKMvofeMmx0",
      "notes" : null,
      "srn" : "wallet:U07tSKMvofeMmx0",
      "callbackUrl" : null,
      "verificationData" : null,
      "depositAddresses" : {
        "BTC" : "2ShJsBPUb4HrNtgaNZk3YQSi2ynpZ5YY7sT"
      },
      "totalBalances" : {
        "BTC" : 0
    
      },
      "availableBalances" : {
        "BTC" : 0
      },
      "balances" : {
        "BTC" : 0
      }
    }
    

    查询子钱包

    通过user ID查询子钱包:

    curl -v -XGET 'https://api.testwyre.com/v2/wallet/{wallet-id}' \
      -H "X-Api-Key: {api-key}" \
      -H "X-Api-Signature: {signature}" \
    

    通过用户名查询子钱包:

    curl -v -XGET 'https://api.testwyre.com/v2/wallet' \
      -H "X-Api-Key: {api-key}" \
      -H "X-Api-Signature: {signature}" \
      -d name={your-identifier}
    

    此终端节点允许通过id或名字查询子钱包余额。

    定义

    GET https://api.testwyre.com/v2/wallet/{walletId}

    参数

    参数 类型 描述 是否需要
    walletId string 子钱包所属用户id yes


    定义

    GET https://api.testwyre.com/v2/wallet/

    参数

    参数 类型 描述 是否需要
    name string 子钱包所属用户名 yes


    Results Format

    {
       "owner": "account:[account-ID]",
       "callbackUrl": null,
       "depositAddresses": {
           "BTC": "1FNAkNVt3gXdS3PZ1tDvetbcafKPsJPQTG"
       },
       "totalBalances": {
           "USD": 4.96
       },
       "availableBalances": {
           "USD": 4.96
       },
       "verificationData": null,
       "balances": {
           "USD": 4.96
       },
       "srn": "wallet:[Wallet-ID]",
       "createdAt": 1497861843000,
       "notes": "test1",
       "name": "richard",
       "id": "[Wallet-ID]"
    }
    


    编辑钱包

    curl -v -XPOST 'https://api.testwyre.com/v2/wallet/{wallet-id}/update' \
      -H "Content-Type: application/json" \
      -H "X-Api-Key: {api-key}" \
      -H "X-Api-Signature: {signature}" \
      -d '{"name":"{your-unique-identifier}","notes":"Updated notes about the sub account"}'
    
    #dependencies:
    #python3
    #pip3 install requests
    
    import json
    import hmac
    import time
    from requests import request
    
    class MassPay_API(object):
        def __init__(self, account_id, api_version, api_key, api_secret):
            self.account_id = account_id
            self.api_url = 'https://api.testwyre.com/{}'.format(api_version)
            self.api_version = api_version
            self.api_key = api_key
            self.api_secret = api_secret
    
        #authentication decorator. May raise ValueError if no json content is returned
        def authenticate_request(func):
            def wrap(self, *args, **kwargs):
                url, method, body = func(self, *args, **kwargs)
                params = {}
                timestamp = int(time.time() * 1000)
                url += '?timestamp={}'.format(timestamp)
                bodyJson = json.dumps(body) if body != '' else ''
                headers = {}
                headers['Content-Type'] = 'application/json'
                headers['X-Api-Version'] = self.api_version
                headers['X-Api-Key'] = self.api_key
                headers['X-Api-Signature'] = hmac.new(self.api_secret.encode('utf-8'), (url + bodyJson).encode('utf-8'), 'SHA256').hexdigest()
                print(headers['X-Api-Signature'])
                resp = request(method=method, url=url, params=params, data=(json.dumps(body) if body != '' else None), json=None, headers=headers)
                if resp.text is not None: #Wyre will always try to give an err body
                    return resp.status_code, resp.json()
                return 404, {}
            return wrap
    
        @authenticate_request
        def update_user(self, walletId, name, callbackUrl, notes, verificationData):
            url = self.api_url + '/wallet/' + walletId + '/update'
            method = 'POST'
            body = {'name':name}
            if callbackUrl:
                body["callbackUrl"] = callbackUrl
            if notes:
                body['notes'] = notes
            if verificationData:
                body['verificationData'] = verificationData
            return url, method, body
    
    #USAGE Example
    account_id = "YOUR_ACCOUNT_ID_HERE" #optional
    api_key = "YOUR_API_KEY_HERE"
    secret_key = "YOUR_SECRET_KEY_HERE"
    api_version = "2"
    
    #create Wyre MassPay API object
    Wyre = MassPay_API(account_id, api_version, api_key, secret_key)
    
    #create user and print result
    http_code, result = Wyre.update_user(
                                    "{wallet-id}",
                                    "{your-unique-identifier}",
                                    None, #callbackUrl
                                    "Updated notes for user",
                                    None #verification data
                                    )
    print(result)
    users_srn = result['srn'] #grab our srn identifier for the user
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import java.io.BufferedReader;
    import java.io.DataOutputStream;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.lang.Integer;
    import java.lang.String;
    import java.lang.StringBuffer;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class Main {
      public static void main(String[] args) {
        String accountId = "k3f48j0rb2rp65c0sdog67vi43u80jas";
        String apiKey = "fll36l3t35udalcqlh4ng6bm4qpbgher";
        String secretKey = "tr3epinbk3maist0n3ijk18bm6dikrq6";
    
        String walletId = "{wallet-id}";
    
        String url = "https://api.testwyre.com/v2/wallet/"+ walletId +"/update";
        String method = "POST";
        String data = "";
    
        String result = excuteWyreRequest(url, "", method, apiKey, secretKey);
        System.out.println(result);
    
        data = "{" +
            "  \"name\":\"{your-unique-identifier}\"," +
            "  \"notes\":\"Updated notes about the user\"" +
            "}";
        result = excuteWyreRequest(url, data, method, apiKey, secretKey);
    
        System.out.println(result);
      }
    
      public static String excuteWyreRequest(String targetURL, String requestBody, String method, String apiKey, String secretKey) {
        URL url;
        HttpURLConnection connection = null;
        try {
    
          targetURL += ((targetURL.indexOf("?")>0)?"&":"?") + "timestamp=" + System.currentTimeMillis();
    
          //Create connection
          url = new URL(targetURL);
          connection = (HttpURLConnection)url.openConnection();
          connection.setRequestMethod(method);
          System.out.println(connection.getRequestMethod());
    
          connection.setRequestProperty("Content-Type", "application/json");
          connection.setRequestProperty("Content-Length", Integer.toString(requestBody.getBytes().length));
    
          //Specify API v2
          connection.setRequestProperty("X-Api-Version","2");
    
          // Provide API key and signature
          connection.setRequestProperty("X-Api-Key", apiKey);
          connection.setRequestProperty("X-Api-Signature",computeSignature(secretKey,targetURL,requestBody));
    
          //Send request
          if(method.equals("POST")) {
            connection.setDoOutput(true);
            connection.setRequestMethod(method);
    
            DataOutputStream wr = new DataOutputStream(
                connection.getOutputStream());
    
            wr.writeBytes(requestBody);
            wr.flush();
            wr.close();
          }
    
          //Get Response
          InputStream is = connection.getInputStream();
          BufferedReader rd = new BufferedReader(new InputStreamReader(is));
          String line;
          StringBuffer response = new StringBuffer();
          while((line = rd.readLine()) != null) {
            response.append(line);
            response.append('\r');
          }
          rd.close();
          return response.toString();
    
        } catch (Exception e) {
    
          e.printStackTrace();
          return null;
    
        } finally {
    
          if(connection != null) {
            connection.disconnect();
          }
        }
      }
    
      public static String computeSignature(String secretKey, String url, String reqData) {
    
        String data = url + reqData;
    
        System.out.println(data);
    
        try {
          Mac sha256Hmac = Mac.getInstance("HmacSHA256");
          SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
          sha256Hmac.init(key);
    
          byte[] macData = sha256Hmac.doFinal(data.getBytes());
    
          String result = "";
          for (final byte element : macData){
            result += Integer.toString((element & 0xff) + 0x100, 16).substring(1);
          }
          return result;
    
        } catch (Exception e) {
          e.printStackTrace();
          return "";
        }
      }
    }
    

    此终端节点允许更新母账户下子钱包的信息。

    定义

    POST https://api.testwyre.com/v2/wallet/{walletId}

    删除钱包

    
    curl -v -XDELETE 'https://api.testwyre.com/v2/wallet/{wallet-id}' \
      -H "X-Api-Key: {api-key}" \
      -H "X-Api-Signature: {signature}"
    

    此终端节点用于删除母账户下子钱包。请知悉出于合规考虑,子钱包的相关数据仍会储存在我们的系统后台。子钱包删除后,关联的收款虚拟银行账户也将被关闭,不能再用于收款。

    定义

    DELETE https://api.testwyre.com/v2/wallet/{walletId}

    参数

    参数 类型 描述 是否需要
    walletId string 子钱包id yes

    列出子钱包

    此终端节点用于列出母账户下已创建的所有子钱包。

    定义

    GET https://api.testwyre.com/v2/wallets

    参数

    参数 类型 描述 是否需要
    limit string 返回记录数 yes
    offset string 跳过记录数 yes


    Result Format

    {
      "data": {
          "owner": "account:XAV3CRAC94P",
          "balances": {},
          "srn": "wallet:WA-XM4L3JMUQGF",
          "createdAt": 1508433396000,
          "callbackUrl": "https://shake.webscript.io/callback",
          "depositAddresses": {
            "BTC": "1Q9TqsVwuZf6bYqtxxjqdataXx81x3Q1h7"
          },
          "totalBalances": {},
          "availableBalances": {},
          "notes": "nope",
          "name": "Person A",
          "id": "WA-XM4L3JMUQGF"
         }
      }
    

    转账

    介绍

    转账是Epi API中最重要的操作之一,我们的转账API功能强大,非常灵活,除外部转账,内部的资金移动也同样支持,母账户管理、子钱包间交易等渠道皆可。除此之外,您可指定不同的来源和目的币种,资金将在后台自动完成处理。

    任何在平台上的资金移动都被视为交易操作,所以过程中款项将会呈现不同的处理状态,直至操作完成,款项被转入您指定的收入方。

    创建转账

    定义

    POST https://api.testwyre.com/v2/transfer/

    此终端节点用于创建一笔新转账。

    {  
       "source":"account:AC-123123123",
       "sourceCurrency":"USD",
       "sourceAmount":"5",
       "dest":"email:sam@testwyre.com",
       "destCurrency":"CNY",
       "message": ""
    }
    

    参数

    参数 类型 描述 是否需要
    source string 识别转出账户的系统资源名称 no
    sourceAmount double 来源币种转出金额,与 sourceCurrency成对. 只写 sourceAmountdestAmount,不要都写 yes
    sourceCurrency string 来源币种的ISO 3166-1三位字母代码 yes
    dest string 收入方的收款银行信息或子钱包信息,请留意此处手机号码默认为美国手机号,国际号码请加‘+’和国家码 yes
    destAmount double 目的币种收入金额,只写sourceAmount OR destAmount,不要都写 yes
    destCurrency string 目的币种的ISO 3166-1三位字母代码,来源币种可与目的币种相同或不同,不同时将自动进行兑换 yes
    message string 用户可见的附言,此处非必填 no
    callbackUrl string 状态返回时的回调url,此处非必填 no
    autoConfirm boolean 自动确认转账,此处非必填 no
    customId string 用户的内部识别号码或标签,必须唯一,否则转账将失败,此处非必填 no
    amountIncludesFees boolean 此处的值若为true,则默认填入的转出/收入金额包含了需扣除的手续费,不会再产生其他费用,此处非必填 no
    preview boolean 此处的值若为true,将会生成转账信息的预览,而不实际操作转账 no
    muteMessages boolean 此处的值若为true,将禁用邮件、信息等通知款项收入方 no


    转账创建后状态为UNCONFIRMED(未确认)有30秒的时间用来检查并确认请求,过时无效。无效时请重新创建转账请求,然后确认,也可以设置autoConfirm的值为true来自动确认。

    检查一笔转账请求时请注意以下几项:

    exchangeRate - 转账交易时的汇率,汇率将以来源货币为基准表示,如需转换为目的货币,用汇率乘以来源货币即可,此项包含epiapi扣除的手续费及按需产生的其他费用。

    sourceAmount/destAmount - 转出金额/收入金额,请仔细检查此处的金额是否符合预计转出/收入的款项金额,此处的值取决于amountIncludesFees参数。


    Result Format

    {
        "id": "TF-VWGF3WW6JU4",
        "status": "PENDING",
        "failureReason": null,
        "language": "en",
        "createdAt": 1525196883000,
        "updatedAt": 1525196883000,
        "completedAt": 1525196884000,
        "cancelledAt": null,
        "expiresAt": 1525456083000,
        "owner": "account:AC-PJZEFT7JP6J",
        "source": "service:Fiat Credits",
        "dest": "wallet:WA-AFFGZJJ7X82",
        "sourceCurrency": "USD",
        "sourceAmount": 10,
        "destCurrency": "USD",
        "destAmount": 10,
        "exchangeRate": null,
        "message": null,
        "totalFees": 0,
        "fees": {
            "USD": 0
        },
        "customId": null,
        "reversingSubStatus": null,
        "reversalReason": null,
        "pendingSubStatus": null,
        "destName": "amandawallet",
        "sourceName": "Wyre",
        "blockchainTx": null,
        "statusHistories": [
            {
                "id": "HNUBAMZ4YQQ",
                "createdAt": 1525196884000,
                "statusDetail": "Initiating Transfer",
                "state": "INITIATED",
                "failedState": null
            },
            {
                "id": "V8L2MJNPF6D",
                "createdAt": 1525196884000,
                "statusDetail": "Transfer Pending",
                "state": "PENDING",
                "failedState": null
            }
        ]
    }
    

    确认转账

    此终端节点用于确认款项划转。成功创建一笔转账后会受到200回调,此时有30秒时间来确认。请留意创建转账后生成的transferId,如果需要在创建转账后自动确认,创建时请设置参数autoConfirm的值为‘true’。

    定义

    POST https://api.testwyre.com/v2/transfer/transferId:/confirm

    参数

    参数 类型 描述
    transferId string 需确认的transferId


    Result Format

    {
        "id": "TF-VWGF3WW6JU4",
        "status": "COMPLETED",
        "failureReason": null,
        "language": "en",
        "createdAt": 1525196883000,
        "updatedAt": 1525196883000,
        "completedAt": 1525196884000,
        "cancelledAt": null,
        "expiresAt": 1525456083000,
        "owner": "account:AC-PJZEFT7JP6J",
        "source": "service:Fiat Credits",
        "dest": "wallet:WA-AFFGZJJ7X82",
        "sourceCurrency": "USD",
        "sourceAmount": 10,
        "destCurrency": "USD",
        "destAmount": 10,
        "exchangeRate": null,
        "message": null,
        "totalFees": 0,
        "fees": {
            "USD": 0
        },
        "customId": null,
        "reversingSubStatus": null,
        "reversalReason": null,
        "pendingSubStatus": null,
        "destName": "amandawallet",
        "sourceName": "Wyre",
        "blockchainTx": null,
        "statusHistories": [
            {
                "id": "HNUBAMZ4YQQ",
                "createdAt": 1525196884000,
                "statusDetail": "Initiating Transfer",
                "state": "INITIATED",
                "failedState": null
            },
            {
                "id": "V8L2MJNPF6D",
                "createdAt": 1525196884000,
                "statusDetail": "Transfer Completed",
                "state": "COMPLETED",
                "failedState": null
            }
        ]
    }
    

    查询转账

    此终端节点用于查询已创建的某笔转账的详细信息。

    定义

    GET https://api.testwyre.com/v2/transfer?customId=

    参数

    参数 类型 描述
    customId string 创建转账时提供的识别号


    Result Format

    {
        "id": "TF-VWGF3WW6JU4",
        "status": "COMPLETED",
        "failureReason": null,
        "language": "en",
        "createdAt": 1525196883000,
        "updatedAt": 1525196883000,
        "completedAt": 1525196884000,
        "cancelledAt": null,
        "expiresAt": 1525456083000,
        "owner": "account:AC-PJZEFT7JP6J",
        "source": "service:Fiat Credits",
        "dest": "wallet:WA-AFFGZJJ7X82",
        "sourceCurrency": "USD",
        "sourceAmount": 10,
        "destCurrency": "USD",
        "destAmount": 10,
        "exchangeRate": null,
        "message": null,
        "totalFees": 0,
        "fees": {
            "USD": 0
        },
        "customId": null,
        "reversingSubStatus": null,
        "reversalReason": null,
        "pendingSubStatus": null,
        "destName": "amandawallet",
        "sourceName": "Wyre",
        "blockchainTx": null,
        "statusHistories": [
            {
                "id": "HNUBAMZ4YQQ",
                "createdAt": 1525196884000,
                "statusDetail": "Initiating Transfer",
                "state": "INITIATED",
                "failedState": null
            },
            {
                "id": "V8L2MJNPF6D",
                "createdAt": 1525196884000,
                "statusDetail": "Transfer Completed",
                "state": "COMPLETED",
                "failedState": null
            }
        ]
    }
    

    转账状态

    定义

    GET https://api.testwyre.com/v2/transfer/:transferId

    参数

    参数 类型 描述
    transferId string 生成的transferId


    Result Format

    {
        "id": "TF-VWGF3WW6JU4",
        "status": "COMPLETED",
        "failureReason": null,
        "language": "en",
        "createdAt": 1525196883000,
        "updatedAt": 1525196883000,
        "completedAt": 1525196884000,
        "cancelledAt": null,
        "expiresAt": 1525456083000,
        "owner": "account:AC-PJZEFT7JP6J",
        "source": "service:Fiat Credits",
        "dest": "wallet:WA-AFFGZJJ7X82",
        "sourceCurrency": "USD",
        "sourceAmount": 10,
        "destCurrency": "USD",
        "destAmount": 10,
        "exchangeRate": null,
        "message": null,
        "totalFees": 0,
        "fees": {
            "USD": 0
        },
        "customId": null,
        "reversingSubStatus": null,
        "reversalReason": null,
        "pendingSubStatus": null,
        "destName": "amandawallet",
        "sourceName": "Wyre",
        "blockchainTx": null,
        "statusHistories": [
            {
                "id": "HNUBAMZ4YQQ",
                "createdAt": 1525196884000,
                "statusDetail": "Initiating Transfer",
                "state": "INITIATED",
                "failedState": null
            },
            {
                "id": "V8L2MJNPF6D",
                "createdAt": 1525196884000,
                "statusDetail": "Transfer Completed",
                "state": "COMPLETED",
                "failedState": null
            }
        ]
    }
    


    转账显示为PENDING(处理中)状态后,我们将开始转移款项至收款方。在此之后该笔转账会根据情况显示为COMPLETE(完成)或FAILED(失败)状态。

    回调

    我们提供一系列HTTP回调来方便您通知您的用户存款及转账状态。

    回调发出

    任何影响账户余额的操作都会导致发出回调,例如:

    可能会出现一笔转账收到两次回调的情况,尤其是区块链上的相关操作,此时将在交易第一次被监测到和交易确认后分别收到两次回调。

    接收回调和重试

    您的系统应以HTTP 200响应回调请求,我们仅会尝试发送一次,此处将在稍后更新时转为自动重试。目前我们可以手动重新发送。


    Result Format

    {
        "id": "TF-VWGF3WW6JU4",
        "status": "COMPLETED",
        "failureReason": null,
        "language": "en",
        "createdAt": 1525196883000,
        "updatedAt": 1525196883000,
        "completedAt": 1525196884000,
        "cancelledAt": null,
        "expiresAt": 1525456083000,
        "owner": "account:AC-PJZEFT7JP6J",
        "source": "service:Fiat Credits",
        "dest": "wallet:WA-AFFGZJJ7X82",
        "sourceCurrency": "USD",
        "sourceAmount": 10,
        "destCurrency": "USD",
        "destAmount": 10,
        "exchangeRate": null,
        "message": null,
        "totalFees": 0,
        "fees": {
            "USD": 0
        },
        "customId": null,
        "reversingSubStatus": null,
        "reversalReason": null,
        "pendingSubStatus": null,
        "destName": "amandawallet",
        "sourceName": "Wyre",
        "blockchainTx": null,
        "statusHistories": [
            {
                "id": "HNUBAMZ4YQQ",
                "createdAt": 1525196884000,
                "statusDetail": "Initiating Transfer",
                "state": "INITIATED",
                "failedState": null
            },
            {
                "id": "V8L2MJNPF6D",
                "createdAt": 1525196884000,
                "statusDetail": "Transfer Completed",
                "state": "COMPLETED",
                "failedState": null
            }
        ]
    }
    


    回调载荷为JSON格式,内容标示了触发该次回调的操作。

    收款方式

    添加银行信息

    {
        "paymentMethodType":"INTERNATIONAL_TRANSFER",
        "country": "US",
        "currency": "USD",
        "beneficiaryType": "INDIVIDUAL",
        "beneficiaryAddress": "112 Brannan St",
        "beneficiaryAddress2": "", //Optional
        "beneficiaryCity": "San Francisco",
        "beneficiaryState": "CA",
        "beneficiaryPostal": "94108",
        "beneficiaryPhoneNumber": "+14102239203",
        "beneficiaryDobDay": "15",
        "beneficiaryDobMonth":"12",
        "beneficiaryDobYear":"1989",
        "paymentType" : "LOCAL_BANK_WIRE", // LOCAL_BANK_WIRE
        "firstNameOnAccount": "Billy-Bob",
        "lastNameOnAccount":"Jones",
        "accountNumber": "0000000000000",
        "routingNumber": "0000000000",
        "accountType": "CHECKING", //CHECKING or SAVINGS
        "chargeablePM": "true"
    }
    

    这里需填写您账户汇出款项银行的信息。 我们将通过此字段来确认款项的汇出方,这将帮助我们了解款项的来源。

    {
        "paymentMethodType":"INTERNATIONAL_TRANSFER",
        "country": "US",
        "currency": "USD",
        "beneficiaryType": "CORPORATE",
        "beneficiaryCompanyName":"",
        "beneficiaryAddress": "112 Brannan St",
        "beneficiaryAddress2": "", //Optional
        "beneficiaryCity": "San Francisco",
        "beneficiaryState": "CA",
        "beneficiaryPostal": "94108",
        "beneficiaryLandlineNumber":"+123464542947",
        "beneficiaryEmailAddress":"tes@testwyre.com",
        "beneficiaryEinTin":"00000000",
        "beneficiaryDobDay": "15", //Date of Incorporation
        "beneficiaryDobMonth":"12", //Date of Incorporation
        "beneficiaryDobYear":"1989", //Date of Incorporation
        "paymentType" : "LOCAL_BANK_WIRE", // LOCAL_BANK_WIRE
        "accountType": "CHECKING", //CHECKING or SAVINGS
        "accountNumber": "0000000000000",
        "routingNumber": "0000000000",
        "chargeablePM": "true"
      }
    

    此终端节点用于创建银行账户。

    查询收款方式

    此终端节点用于查询收款方式下的银行账户信息。

    定义

    GET https://api.testwyre.com/v2/paymentMethod/:paymentMethodId


    Result Format

    {
        "id": "TestPaymentMethod",
        "owner": "account:ABCDEFG",
        "createdAt": 1230940800000,
        "name": "TEST PAYMENT METHOD",
        "defaultCurrency": "USD",
        "status": "ACTIVE",
        "statusMessage": null,
        "waitingPrompts": [],
        "linkType": "TEST",
        "supportsDeposit": true,
        "nameOnMethod": null,
        "last4Digits": null,
        "brand": null,
        "expirationDisplay": null,
        "countryCode": null,
        "nickname": null,
        "rejectionMessage": null,
        "disabled": false,
        "supportsPayment": true,
        "chargeableCurrencies": [
            "GBP",
            "MXN",
            "HKD",
            "USD",
            "CNY",
            "BRL",
            "EUR",
        ],
        "depositableCurrencies": [
            "USD"
        ],
        "chargeFeeSchedule": null,
        "depositFeeSchedule": null,
        "minCharge": null,
        "maxCharge": null,
        "minDeposit": null,
        "maxDeposit": null,
        "documents": [],
        "srn": "paymentmethod:TestPaymentMethod"
    }
    

    美元付款

    美元付款由我们在当地的银行之一发起,与收入款项国家相对应。需注意美元付款每笔最低限额为5美金。

    定义

    POST https://api.testwyre.com/v2/transfers

    {
      "dest": {
        "paymentMethodType":"INTERNATIONAL_TRANSFER",
        "country": "US",
        "currency": "USD",
        "beneficiaryType": "INDIVIDUAL",
        "beneficiaryAddress": "112 Brannan St",
        "beneficiaryAddress2": "", //Optional
        "beneficiaryCity": "San Francisco",
        "beneficiaryState": "CA",
        "beneficiaryPostal": "94108",
        "beneficiaryPhoneNumber": "+14102239203",
        "beneficiaryDobDay": "15",
        "beneficiaryDobMonth":"12",
        "beneficiaryDobYear":"1989",
        "paymentType" : "LOCAL_BANK_WIRE",
        "firstNameOnAccount": "Billy-Bob",
        "lastNameOnAccount":"Jones",
        "accountNumber": "0000000000000",
        "routingNumber": "0000000000",
        "accountType": "CHECKING", // CHECKING or SAVINGS
        "bankName": "Bank of America"
      },
      "sourceCurrency": "BRL",
      "destCurrency": "USD",
      "destAmount": 10,
      "message":"USD Personal example"
    }
    

    美元付款字段

    参数 描述
    dest object
    dest.paymentMethodType INTERNATIONAL_TRANSFER
    dest.country US
    dest.currency USD
    dest.beneficiaryType INDIVIDUAL or CORPORATE
    dest.beneficiaryPhoneNumber 个人账户需填写
    dest.beneficiaryLandlineNumber 公司账户需填写
    dest.beneficiaryEinTin 公司账户需填写
    dest.beneficiaryEmailAddress 公司账户需填写
    dest.beneficiaryCompanyName 公司账户需填写
    dest.firstNameOnAccount 法人名(不包括姓)
    dest.lastNameOnAccount 法人姓
    dest.accountNumber 法人银行账号
    dest.routingNumber 法人银行账户 routing number
    dest.accountType CHECKING or SAVINGS
    destAmount 存入收方金额,从用户账户减除的款项将自动计算汇率和手续费
    destCurrency 存入收方币种,若汇出存入币种不一致将自动进行兑换
    sourceCurrency 账户原币种

    到账时间

    美国银行结算时间为美国中部标准时间下午四点。

    若在当日下午四点前提交转账提现请求,当日处理到账,当天下午四点后提交则下一个工作日到账。

    更新日志

    更新日期 2018/11/30

    1. 测试环境
    - 测试环境域名更新,新测试环境域名为 test.epiapi.com,停止使用原环境下所有功能

    2. 澳大利亚虚拟银行收款(VBA)
    - 添加澳大利亚 VBA 相关功能

    3. 子钱包更新
    - 添加“countries” 字段,允许在一个子钱包下添加多个国家 VBA(不填写此字段将默认为美国VBA)
    — 更新子钱包字段内容有效性验证

    4. 子钱包回传
    — 添加 vbaData 状态变更的回传,用于更方便地监视账户创建进展

    5. 内部服务
    - 针对自动开户和检查状态更新内部服务流程