This a start-to-finish guide on how to quickly get up to speed using the Wyre MassPay API.

What is MassPay?

MassPay is utilized by companies that are looking to transfer balances between local currencies. So when you're looking to transfer funds into a customer's bank account, MassPay is what you'll want to use! Note:

Contents:

  1. Setting up a Wyre Account
  2. Making API Requests
  3. Constructing your first Transfer Creation request
  4. Example Transfers
  5. Code Examples
  6. Links, Resources, and Contacts

1. Setting up a Wyre Account

First, create an account if you haven't already done so. Be sure to verify the email and phone attached to the account.

To get started transferring funds you'll need the following:

  • API Key
  • SECRET Key
  • ACCOUNT ID

These can be found in your account settings once you have logged in.

Once you have generated an API key, here's what you'll see:

615

The last piece is your AccountID. This can be found by clicking on the "details" of the key that you just generated.

641

Note
Don't include the "account:" when making your requests.
This - account:pm9ddj8jr8rrq53fsk9v4bfhunieu72t
Becomes this for your requests - pm9ddj8jr8rrq53fsk9v4bfhunieu72t

2. Making API Requests

The base Wyre API URL is at https://api.sendwyre.com/v2/. All responses are in JSON.

Wyre utilizes the following HTTP Headers as security measures:

Header FieldDescription
X-Api-KeyYour Wyre API key
X-Api-SignatureHMAC calculated with the secret key.

Calculate your API Signature HMAC as follows (code examples at bottom of page):

  1. Construct your Request URL and add a timestamp URL parameter in milliseconds. For example, to get your account details, the Request URL is https://api.sendwyre.com/v2/account?timestamp=1426252182534.
  2. Concatenate the Request URL with the body of the HTTP request into a UTF-8 String. Use an empty string for the HTTP body in GET requests.
  3. Compute the signature using HMAC using the SHA-256 algorithm and your API Secret Key.

Here are Wyre's MassPay API endpoints. Click on the name links for full documentation:

NameAPI EndpointHTTP MethodDescription
Account Detailshttps://api.sendwyre.com/v2/accountGETAccount details including contact info, balances in all currencies, KYC authorizations, and payment methods.
Live Exchange Rateshttps://api.sendwyre.com/v2/ratesGETA list of exchange rates for all currency pair combinations that Wyre currently supports.
Create Transferhttps://api.sendwyre.com/v2/transfersPOSTCreates a transfer between two currencies. The destination can be an email address, wallet address, or bank account. autoConfirm may be used but is not recommended.
Confirm Transferhttps://api.sendwyre.com/v2/transfer/:transferId/confirmPOSTThe transfer will normally only execute after you review the details and confirm at this endpoint within 30 seconds.
Transfer Statushttps://api.sendwyre.com/v2/transfer/:transferIdGETIf you don't use a callbackUrl when created the transfer, you can poll this endpoint until the order is filled. Different possible statuses are here.

Constructing your first Transfer

A Transfer request is a JSON POST request that may contain up to 7 fields:

  • sourceAmount - only include either sourceAmount or destAmount, not both. sourceAmount is the amount removed from your main account in order to send funds to the destination. In this case you specify the amount removed from your account, and the destAmount will be determined depending on the fees and exchange rate.
  • sourceCurrency - an ISO 3166-1 alpha-3 currency code that will be deducted from your account.
  • dest - a destination for the funds. This can be an email address, phone number, blockchain address, or bank account.
  • destAmount - only include either sourceAmount or destAmount, not both. destAmount is the exact amount that will be deposited into the dest. If destAmount is specified in the Transfer creation request the sourceAmount will be calculated from the destAmount, the exchange rate any fees on the Transfer
  • destCurrency - an ISO 3166-1 alpha-3 currency code that matches the dest type. The destCurrency can be the same or different from the sourceCurrency. If they are different, an exchange will automatically occur.
  • message - An optional log message to include with the transfer
  • callbackUrl - An optional url that Wyre will POST a status callback to (see Callbacks)
  • autoConfirm - An optional parameter to automatically confirm the transfer order. Not recommended.

Here is an example transfer creation request to convert BRL to USD and send it to our lead developer's bank account:

{
  "dest": {
    "paymentMethodType":"INTERNATIONAL_TRANSFER",
    "country": "US",
    "currency": "USD",
    "firstNameOnAccount": "Sam",
    "lastNameOnAccount":"Schlachter",
    "accountNumber": "1234dinosaur",
    "routingNumber": "0000000000",
    "accountType": "savings",
    "bankName": "Bank of 'murrrica",
    "bankStreet": "112 Brannan St",
    "bankCity": "San Francisco",
    "bankPostal": "94108",
    "accountHolderPhoneNumber": "+14102239203",
    "beneficiaryType": "INDIVIDUAL",
    "priority":"HIGH"
  },
  "sourceCurrency": "BRL",
  "destCurrency": "USD",
  "destAmount": 10,
  "message":"Here's your $10!"
}

The response will resemble this. The most important part of the response is the id field. This is what we'll use to confirm the transfer and poll its status.

If the transfer response is of the amount and at the rate we wanted, we must confirm the order by posting to the Confirm Transfer endpoint (or by using autoConfirm in the original request).

The last step is to poll the status of the order from the Transfer Status endpoint until the transfer object reaches an end state- either COMPLETED, EXPIRED, or FAILED. Alternatively, you can pass in a URL to the callbackUrl field to the original transfer creation request, which will cause wyre to send an HTTP POST transfer status response to the URL.

Below are examples of transfers involving bank accounts.

Example Transfers

USA 🇺🇸 → 🇧🇷 BRAZIL

{
  "dest": {
    "paymentMethodType":"INTERNATIONAL_TRANSFER",
    "country": "BR",
    "currency": "BRL",
    "firstNameOnAccount": "Robert",
    "lastNameOnAccount": "Baratheon",
    "accountNumber": "1234dinosaur",
    "bankName": "Mordor Credit Union",
    "cpfCnpj": "943759353",
    "accountType": "poupanca",
    "branchCode": "Artichoke",
    "accountHolderEmail": "[email protected]",
    "accountHolderPhoneNumber": "+14102239203",
    "swift": "DEUTUS00000",
    "beneficiaryType": "INDIVIDUAL",
        "priority":"HIGH"
  },
  "sourceCurrency": "USD",
  "destCurrency": "BRL",
  "destAmount": 10,
  "message":"A Lannister always pays his debts "
}

BRAZIL 🇧🇷 → 🇺🇸 USA

{
  "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", // LOCAL_BANK_WIRE or ACH
    "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"
}

USA 🇺🇸 → 🇨🇳 CHINA

{
  "dest": {
    "paymentMethodType":"INTERNATIONAL_TRANSFER",
    "country": "CN",
    "currency": "CNY",
    "nameOnAccount": "成龍",
    "accountNumber": "1234dinosaur",
    "bankName": "招商银行",
    "accountType": "金卡",
    "branchCode": "光华路支行",
    "accountHolderEmail": "[email protected]",
    "accountHolderPhoneNumber": "+14102239203",
    "swift": "DEUTUS00000",
    "beneficiaryType": "INDIVIDUAL",
    "priority":"HIGH"
  },
  "sourceCurrency": "USD",
  "destCurrency": "CNY",
  "destAmount": 10,
  "message":""
}

CHINA 🇨🇳 → 🇺🇸 USA

{
  "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", // LOCAL_BANK_WIRE or ACH
    "firstNameOnAccount": "Billy-Bob",
    "lastNameOnAccount":"Jones",
    "accountNumber": "0000000000000",
    "routingNumber": "0000000000",
    "accountType": "CHECKING", //CHECKING or SAVINGS
    "bankName": "Bank of America"
  },
  "sourceCurrency": "CNY",
  "destCurrency": "USD",
  "destAmount": 10,
  "message":"USD Personal example"
}

Code Examples

You can simply put your API Key, API Secret Key, and Account ID into these scripts, alter the example transfer request objects, and get started right away making MassPay transfers!

#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.sendwyre.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, destination, message, autoConfirm):
        url = self.api_url + '/transfers'
        method = 'POST'
        #ONLY use either sourceAmount or destAmount, see documentation
        body = {'sourceCurrency':sourceCurrency,
                'dest':destination, #email, wallet, or bank transfer dict
                '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)

#get exchange rate info
http_code, rate_result = wyre.retrieve_exchange_rates()
print(rate_result)

#BTC to CNY rate
btc_cny = rate_result.get("BTCCNY")

#amount of source (withdrawal) BTC we want to sent to Euro
amount = 50

#calculate destination (deposit) amount in CNY
final_amount = amount * btc_cny

#example bank transfer dictionary that we will pass in as the destination
bank_transfer =   {
                "paymentMethodType":"INTERNATIONAL_TRANSFER",
                "country": "CN",
                "currency": "CNY",
                "nameOnAccount": "成龍",
                "accountNumber": "1234dinosaur",
                "bankName": "招商银行",
                "accountType": "金卡",
                "branchCode": "光华路支行",
                "accountHolderEmail": "[email protected]",
                "accountHolderPhoneNumber": "+14102239203",
                "swift": "DEUTUS00000",
                "beneficiaryType": "INDIVIDUAL",
                "priority":"HIGH"
                }

#send transfer and print result
http_code, transfer_result = wyre.create_transfer(
                                amount, 
                                "BTC", 
                                None, #final_amount
                                "CNY", 
                                bank_transfer, #may also be an email or SRN
                                "sending wyre developers pizza money",
																False)
print(transfer_result)
tx_id = transfer_result['id'] #grab our transfer id

#confirm transfer
http_code, confirmation = wyre.confirm_transfer(tx_id)
print(confirmation)

#check status
http_code, status = wyre.status_transfer(tx_id)
print(status)
require 'uri'
require 'net/http'
require 'digest/hmac'
require 'json'

class WyreApi
  ACCOUNT_ID = 'ue5hsnusf8gene87asdf4es23bt9d7ak'
  API_KEY = '9idihi38o18mrm1234ipa1k9ooiifgts'
  SEC_KEY = '5e3kcoogptge6s5fh2qwertyb6g368dm'
  API_URL = 'https://api.sendwyre.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'=>'[email protected]', 'destCurrency'=>'EUR', 'message'=>'buy sam pizza')
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 apiKey = "fll36l3t35udalcqlh4ng6bm4qpbgher";
		String secretKey = "tr3epinbk3maist0n3ijk18bm6dikrq6";

    //retrieve account details and balance
		String url = "https://api.sendwyre.com/account";
		String method = "GET";
		String data = "";

		String result = executewyreRequest(url, "", method, apiKey, secretKey);
		System.out.println(result);

    //example transfer
		url = "https://api.sendwyre.com/transfers";
		method = "POST";
		data = "{" +
				"  \"dest\": \"[email protected]\"," +
				"  \"destCurrency\": \"BTC\"," +
				"  \"sourceCurrency\" : \"USD\"," +
				"  \"sourceAmount\" : \"50\"," +
				"  \"message\": \"$50 worth of bitcoin! Food please!\"" +
				"}";
		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 = null;
    	if (connection.getResponseCode() >= 400) {
      	is = connection.getErrorStream();
    	}  
    	else {
      	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 "";
		}
	}
}
using System;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;

namespace test
{
	class MainClass
	{
		public static void Main(string[] args)
		{
			wyreApi wyreApi = new wyreApi();

			string balance = wyreApi.getAccount();
			Console.WriteLine(balance);

			string transferData = "{" +
				"\"sourceCurrency\": \"USD\"," +
				"\"dest\": \"[email protected]\"," +
				"\"sourceAmount\": \"0.01\"," +
				"\"destCurrency\": \"BTC\"" +
				"}";
			string authResponse = wyreApi.transfer(transferData);
			Console.WriteLine(authResponse);
		}
	}

	public class wyreApi {
		private const string domain = "https://api.sendwyre.com";
		private const string apiKey = "xxxxxx";
		private const string secKey = "xxxxxx";

		public string getAccount() 
		{
			return MakeGetReq("/account");
		}

		public string transfer(string jsonString)
		{
			return MakePostReq("/transfers", jsonString);
		}

		private string MakeGetReq(string apiRoute)
		{
			WebRequest req = AssembleWebRequest(apiRoute);
			req.Method = "GET";
			WebResponse response = req.GetResponse();
			string responseString = ParseWebResponse(response);
			return responseString;
		}

		private string MakePostReq(string apiRoute, string jsonData)
		{
			WebRequest req = AssembleWebRequest(apiRoute, jsonData);
			req.Method = "POST";
			WriteJsonToRequest(req, jsonData);


			WebResponse response = req.GetResponse();
			string responseString = ParseWebResponse(response);
			return responseString;
		}

		private WebRequest AssembleWebRequest(string apiRoute, string jsonData = "")
		{
			string url = domain + apiRoute + (apiRoute.Contains("?")?"&":"?") + "timestamp="+DateTime.Now.Ticks; 
			WebRequest request = WebRequest.Create(url);
			string authSig = CalcAuthSigHash(secKey, url + jsonData);

			request.ContentType = "application/json";
			request.Headers["X-Api-Key"] = apiKey;
			request.Headers["X-Api-Signature"] = authSig;
			request.Headers["X-Api-Version"] = "2";
			return request;
		}

		private void WriteJsonToRequest(WebRequest req, string jsonData)
		{
			var streamWriter = new StreamWriter(req.GetRequestStream ());
			streamWriter.Write(jsonData);
			streamWriter.Close();
		}

		private byte[] GetBytes(string str)
		{
			return Encoding.UTF8.GetBytes(str);
		}

		private string GetString(byte[] bytes)
		{
			return BitConverter.ToString(bytes);
		}

		private string CalcAuthSigHash(string key, string value)
		{
			HMACSHA256 hmac = new HMACSHA256(GetBytes(key));
			string hash = GetString(hmac.ComputeHash(GetBytes(value)));
			hash = hash.Replace("-", "");
			return hash;
		}

		private string ParseWebResponse(WebResponse response)
		{
			StreamReader streamReader = new StreamReader(response.GetResponseStream());
			string result = streamReader.ReadToEnd();
			streamReader.Close();
			return result;
		}
	}
}
<?php
    function make_authenticated_request($endpoint, $method, $body) {
        $url = 'https://api.sendwyre.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;
    }

    echo make_authenticated_request("/account", "GET", array());
		$transfer = array(
      "sourceCurrency"=>"USD",
      "dest"=>"[email protected]",
      "destAmount"=> 55.05,
      "destCurrency"=>"EUR",
      "message"=> "buy sam pizza"
      );
		echo make_authenticated_request("/transfers", "POST", $transfer);
?>

Links, Resources, and Contacts

Resources

Github

Blockchain Tech Introduction

Company Information

Contact

[email protected]
415-374-7356
1550 Bryant St, Ste 750
San Francisco, CA 94107

OR

Use our Intercom support located on the lower right of the frontpage