navigation hamburger icon

API Documentation

Table of Contents

curl Ruby Python Javascript PHP C# Java

Introduction


API Endpoint

https://api.trolley.com/v1/

Trolley’s API allows businesses to send payments to their recipients globally. Recipients can be either an individual or a business, such as freelance workers, contractors, affiliates, developers, designers, hosts, drivers, or even business suppliers around the world.

Our mission is to give more choice of payout methods to merchants world wide. What works for someone in San Francisco, London or Melbourne, might not be the best option for someone else in Jakarta, Nairobi or Mumbai. PayPal doesn’t support all countries, in fact, 97.5% of the population doesn’t have a PayPal account, and over 2 billion people don’t have a bank account. So clearly multiple payout options are needed to support a global business. That is why we plan to support every major payout method, so your users have choice of what works best for them.

Trolley currently supports direct payments to via bank transfer (in 220+ countries) and PayPal. In the near future, we will also support payments by mobile money, cash pick-up, paper checks and to existing debit or credit cards.

If you have an existing e-wallet service you use to make payouts (like PayPal), you can plug-in your business’ PayPal or other e-wallet account to our platform, and push payments out through your existing account with no additional fees from us. This allows you to have one consolidated payout platform to handle all your payouts, through one API integration. It also means that you can start offering direct-to-bank account payouts to your users, while offering your users a seamless transition from your current payout options.

We will always be looking to add the fastest, least expensive, most popular and most convenient payout methods that people want to use. So your business only ever has to integrate with one partner (us), and we will ensure you and your users always get access to the latest and greatest payout methods available on the market, at the most competitive rates.


Please review our API Terms of Use.



Before you start

Here is a quick summary of some common terms we use:

Term ID # Format Description
Recipient R-1a2B3c4D5e6F7g8H9i0J1k A Recipient is the individual or business that you need to send a payment to.
Payment P-1a2B3c4D5e6F7g8H9i0J1k A Payment is an individual payout to a recipient.
Batch B-1a2B3c4D5e6F7g8H9i0J1k A Batch is a group of payments.
Transfer T-1a2B3c4D5e6F7g8H9i0J1k A Transfer is a deposit (or withdrawal) you make to your Trolley account from your company bank account, to fund your balance before sending payments.

Getting Started


Overview

Trolley helps businesses send payouts (and manage associated tax details) to vendors, suppliers, artists, and independent contractors worldwide. The Trolley API helps you embed Trolley features directly within your platforms, systems, and logic.

In this document, we’ll walk you through 3 easy steps to send payments to your users.

Getting Started with Trolley in 3 easy steps

Image 1: Getting Started with Trolley in 3 easy steps

Step 1 – API & Account Setup

You’ll need to set up a few things before you can get started with the Trolley API. Let’s review these details:

Get API Keys

The Trolley API uses a pair of keys to authenticate your requests. This pair contains an API Access Key and a corresponding API Secret Key.

To acquire the API Access Key and the API Secret Key, go to Trolley Dashboard > Settings > API Keys and generate the pair.

Image 2: A screencast showing how to navigate to API Keys section within the Trolley settings interface

Image 2: A screencast showing how to navigate to API Keys section within the Trolley settings interface.

If you have created API Keys before, only the API Access Keys will be listed here.

Click on the Create Key button on the top right to create a new API Access Key and API Secret Key. A dialog box will appear displaying the pair of keys.

Image 3: A screenshot of the API Key Creation dialog box showing sample API Keys

Image 3: A screenshot of the API Key Creation dialog box showing sample API Keys.

Note: The API Secret will be visible only in this dialog box, so make sure you copy the pair and save it somewhere safe.

You’ll need this API Key and API Secret pair to access the Trolley API, and with the Trolley SDKs.

Live and Sandbox modes

Your account includes access to a “sandbox” environment where you can test the API and other features without impacting your production environment or potentially transferring real funds. Consider this as a testing environment to test run your integrations.

API Keys differ for sandbox and live environments. You can switch between them easily from your dashboard.

To switch between Live and Sandbox environments, click your account avatar at the top right corner of the Trolley interface. In the dropdown, click on the account name with “sandbox” or “live” suffix.

Image 4: A screencast demonstrating how to switch between live and sandbox environments in Trolley.

Image 4: A screencast demonstrating how to switch between live and sandbox environments in Trolley.

You can add teammates to either environment and give them different roles in each.

Note that the developer role cannot create API keys in Live mode.

Request URL and Content type

The Request URL, the address where to send API requests, consists of two main parts: a base url and a version number.

Base url: https://api.trolley.com
API Version: v1

The corresponding Request URL would be written: https://api.trolley.com/v1/…

All resources that you need to access, will be appended to this request URL. Some examples:
Some examples:

Request Content Type: Content-type: application/json
All request types must provide the above header if they’re sending a JSON body in the request.

'Authorization': 'prsign AVaAj764JE7C:
ce1f667c9cfee7a9291c61f68ff98144cc08c0291bbdcc3d0'

Authentication

The API Authentication model expects you to provide an Authorization header.

Create the authorization header by sha256 encoding a combination of the current timestamp, request type, request path, and the body.

Any requests older than 30 seconds will be rejected. A typical authentication header will look like the one displayed in the example.

'X-PR-Timestamp': '1656393402'

Along with the Authorization header, you should also send a custom header X-PR-Timestamp with the current timestamp as its value.
An example of the X-PR-Timestamp is shown in the right pane.

To learn how to compute the Authentication header, please read through our Authentication guide: https://docs.trolley.com/api#authentication

curl 
-H "Authorization:prsign ALJVaAj4Z764JE7C:ce1f667913c9ca794cd89291c61f68ff98144291bbdcc3d0"
-H "X-PR-Timestamp:'1656393402'"
-L -X GET "https://api.trolley.com/v1/recipients/R-BawfevFF8oWx" \

Sample Request

With your API Access Key, API Secret Key, and Authentication processes in place, you’re ready to send requests to our APIs. You can use your preferred programming language to send HTTP requests to our APIs.

A sample cURL request to get details about a single recipient is shown in the example.

Step 2 - Add Recipient

Before you can send payments to recipients, they need to be added to your Trolley merchant account. You can use the Trolley Widget to add new recipients and their tax information. Alternatively, you can bulk upload recipients as a CSV file to import recipients from your previous system.

Using Trolley Widget to add recipients

The Trolley Widget is a handy way for your recipients to self-onboard their payment and tax information to your merchant account. Using the Widget, recipients can add multiple payment methods such as bank account, PayPal, or check. Using the same widget, the recipients can upload tax-related information and forms.

The Trolley Widget is integrated as an iframe and supports many configuration options. Supplying a recipient’s email address is the only requirement to initiate the recipient’s self-onboarding process.

To display the widget to a recipient, you should:

  1. Build a Widget URL with required configuration options.
  2. Host it on a webpage you own and control.
  3. Share that webpage’s URL with your recipients.

Once loaded, the iframe will look something like this:

Image 5: Screenshot of the Trolley Widget for a user with no payment method on file.

Image 5: Screenshot of the Trolley Widget for a user with no payment method on file.

Once the recipient fills in their information, the Trolley Widget looks like the following:

Image 6 Screenshot of the Trolley Widget for a user with payment methods on file.

Image 6 Screenshot of the Trolley Widget for a user with payment methods on file.

The Widget also emits multiple JS events when a payment method or a tax form is added. You can listen for these events to trigger any necessary actions (e.g. closing a mobile web browser window when a recipient is done adding payment details).

Every recipient will be assigned a new recipientId, a unique indicator which will look something like this: R-XgtzXghfxx4E4Y3R.

This recipientId is used across the Trolley API to recognize a recipient and take actions for them such as sending a payment, checking statuses, etc.

To learn more about how to create, modify, and use the Trolley Widget, visit the Widget documentation: https://docs.trolley.com/widget/

Import Recipients

If you have existing recipient information in a system you already use and maintain, you can import that information directly to your Trolley merchant dashboard as a mass import. You’ll need to upload a properly formatted CSV file to import these recipients’ information.

To do this, go to the Dashboard and click on the Recipients tab from the main menu. From the top right corner, click the drop-down arrow next to the “Add Recipient” button and select “Upload CSV File”.

Image 7: Screencast of the Add Recipient button options, to show where to find “upload CSV” option

Image 7: Screencast of the Add Recipient button options, to show where to find “upload CSV” option

This will open a dialog box where you can upload the CSV file containing the recipient information. From here you can also download the template demonstrating the correct CSV format required by the Trolley system to format your CSV file accordingly:

Image 8: Screenshot of the Upload CSV dialog box

Image 8: Screenshot of the Upload CSV dialog box

To learn more about how to add Recipients manually, either one by one or in bulk, check out the “How to Add a New Recipient” help article: https://help.trolley.com/en/articles/483504-how-to-add-a-new-recipient

You can also add recipients via the API, which is discussed here: https://docs.trolley.com/api/#create-a-recipient

Managing Recipients

Once recipients are added or uploaded, you can manage or edit individual recipient records via the dashboard or the API.
To learn more about how to manage recipients via the API, refer to our API documentation about recipients: https://docs.trolley.com/api#retrieve-a-recipient

Step 3 - Send Payment

Once recipients have been added and are active, you can send them payments. An active recipient must have a valid address, valid payment method, and a tax form uploaded (if applicable).

To send a payment to an active recipient, you use the Batches function.

Here’s a quick rundown of the steps required to send a payment to a recipient:

1. Create a Batch

In the Trolley ecosystem, all payments are sent as a part of a Batch. A batch can have 0 or multiple payments in it. One batch can have payments meant for multiple recipients, so a batch is not unique to a recipient. A payment cannot exist without a batch.

To create a Batch via the Trolley API, you’ll have to send a POST request to the https://api.trolley.com/v1/batches api endpoint.

After successful creation of a Batch, you’ll receive a batchId which looks like this: B-1a2B3c4D5e67g8H90J1k
This batchId will be used to access this batch for any future needs.

For full details on how to create a batch, please refer to this document: https://docs.trolley.com/api/#create-a-batch

2. Add Payments to the Batch

You can add a payment to a batch while creating the batch itself. But if needed, payments can be added to an existing batch before sending it.

To add a payment to an existing batch with a batchId, send a POST request to the https://api.trolley.com/v1/batches/:id/payments endpoint, where :id is the batchId of the batch you want to add this payment into.

For full details on how to add a payment to a batch, please refer to this document: https://docs.trolley.com/api/#create-a-payment

3. Send the batch to processing

Once a batch is ready, with all the payments that need to be sent, you can send the batch for processing. Once the batch is sent for processing, you cannot edit or delete it.

To send a batch for processing, you’ll have to send a POST request to the https://api.trolley.com/v1/batches/:batch-id/start-processing endpoint, with the appropriate batchId.

The batch will run through the validations and will be marked as processed if all the validations and requirements are met—validations include things like checking if you have a sufficient account balance. Until the validations are complete, the batch remains in a processing state. Once the validation is complete and the transaction is triggered, the batch will be marked as processed. Note that processing a batch may take some time.

You can see all potential statuses of batches and other objects here: https://docs.trolley.com/api/#list-of-statuses

To learn more about how to send a payment through a batch, refer to this documentation: https://docs.trolley.com/api/#payments

Invoices

If you have multiple payments for a single recipient in a pay-run, you can use Invoices for better management and reporting of those payments.
You can create an invoice, add line items to the invoice denoting the purpose of various payments, create an Invoice Payment, then send the associated batch to the created Payment for processing.

To learn more about Invoices, please refer to the Invoices documentation: https://docs.trolley.com/api/#invoices

Managing Payments

Like recipients, you can manage batches and payments via the API and perform CRUD operations on them (depending on which state they are in).

To learn more, you can explore different API endpoints pertaining to batches and payments further in our API documentation: https://docs.trolley.com/api#payments


We can’t wait to see the payment experiences you build with the Trolley API. For more details and in-depth documentation of all features, visit the remaining sections of this API document. Refer to the further reading section below for more suggested reading as you start building with Trolley.

Further Reading

  1. To get notified about updates to Payments, Recipients and more, subscribe to Webhooks

  2. See a definitive list of potential payments, recipients, and batches statuses in List of Statuses.

  3. Find answers to common questions, or contact us by visiting Support and FAQs.

Interacting with the API


Making requests

The Trolley API follows RESTful design principles. We use the following HTTP verbs:

When making requests, arguments can be passed as params or JSON with correct Content-Type header of application/json.

Success Codes

The Trolley API uses the following successful response codes:

Success Code Meaning
200 Ok – Request processed successfully

Error Codes

Example API response for object not found

{
  "ok": false,
  "errors": [
    {
      "code": "not_found",
      "message": "Object not found"
    }
  ]
}

Example API Failure for validation

{
  "ok": false,
  "errors": [
    {
      "code": "empty_field",
      "field": "type",
      "message": "Expected to have a non-null or non-empty value"
    },
    {
      "code": "empty_field",
      "field": "name",
      "message": "Expected to have a non-null or non-empty value"
    }
  ]
}

The Trolley API uses the following error codes:

Error Code HTTP Code Description
invalid_status 400 Status of an object is invalid
invalid_field 400 Field value is invalid
empty_field 400 Field value is required but not provided
expired_quote 400 Quote is expired
invalid_api_key 401 API key is invalid
not_authorized 403 Authentication not permitted to access resource
not_found 404 Object not found
rate_limit_exceeded 429 Rate limit exceeded
partner_integration_error 500 Error occured with one of our partners
internal_server_error 500 Internal server error


In the event that the API returns an error, the response body will contain the following information:

Response

Key Meaning
ok Boolean false – The API call failed
errors Array of descriptions, more detail on the failures, this may be multiple values for validation failures or a single value for other failures.

CORS

Trolley API supports cross-origin HTTP requests which is commonly referred to as CORS. This means that you can call API resources using Javascript from any browser. While this allows many interesting use cases, it’s important to remember that you should never expose private API keys to 3rd parties. CORS is mainly useful with unauthenticated endpoints and OAuth2 client side applications.

Fields

Type Description
string An arbitrary string value
integer Integer number
float Floating point number
date All dates are represented in in ISO 8601 format in the UTC (Z) timezone (e.g. “2015-07-01T00:55:47Z)
country All country codes are ISO ALPHA-2 country codes (e.g. “US”, “CA”, or “JP”)
amount All amounts are in string format in order to avoid rounding problems with floating point numbers. The only allowed formats are positive numeric values with either two decimal places or no decimal (e.g. “1.99” or “123”).
currency The type of currency is in ISO 4217 (e.g. “USD”, “CAD”, or “JPY”)


Rate limiting

The Trolley API is rate limited to prevent abuse that would degrade our ability to maintain consistent API performance for all users.

The rate limits are as follows:

If your requests are being rate limited, HTTP response code 429 will be returned with an rate_limit_exceeded error. Contact us to discuss rate limits at api@trolley.com.

Deprecation Policy

Technology evolves quickly and we are always looking for better ways to serve our customers. From time to time we need to make room for innovation by removing sections of code that are no longer necessary. We understand this can be disruptive and consequently we have designed a Deprecation Policy that protects our customers’ investment and that allows us to take advantage of modern tools, frameworks and practices in developing software.

Deprecation means that we discourage the use of a feature, design or practice because it has been superseded or is no longer considered efficient or safe but instead of removing it immediately, we mark it as Deprecated to provide backwards compatibility and time for you to update your projects. While the deprecated feature remains in the API and/or SDK for a period of time, we advise that you replace it with the recommended alternative which is explained in the relevant section of API documentation or the SDK code.

We remove deprecated features after 3 months from the time of announcement.

The security of our customers’ assets is of paramount importance to us and sometimes we have to deprecate features because they may pose a security threat or because new, more secure, ways are available. On such occasions we reserve the right to set a different deprecation period which may range from immediate removal to the standard 3 months.

Once a feature has been marked as deprecated, we no longer develop the code or implement bug fixes. We only do security fixes.

Authentication


All calls to the Trolley API require authentication. You will need to get an access key and secret key from the dashboard via the settings page.

Signing requests

API Key authentication requires each request to be signed, this ensures that your secret key is not part of the transmission.

Making a request

Example of generating Authorization header and sending API requests


# Bash sample only includes example of sending a request.
# For sample code of generating Trolley Authorization header please 
# view samples of other supported programming languages

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X POST 'https://api.trolley.com/v1/recipients' \
--data-raw '{
  "type": "individual", 
  "firstName": "Elon", 
  "lastName": "Mask", 
  "email": "elon@mask.com"
  }' 
# Requires python-requests. Install with pip:
#
#   pip install requests
#

import json, hmac, hashlib, time, requests
from requests.auth import AuthBase

# Your key and secret as obtained by the Dashboard UI
ACCESS_KEY = '<YOUR_ACCESS_KEY>'
SECRET_KEY = '<YOUR_SECRET_KEY>'

# Create custom authentication for Trolley API
class TrolleyAuth(AuthBase):
    def __init__(self, access_key, secret_key):
        self.access_key = access_key
        self.secret_key = secret_key

    def __call__(self, request):
        print "PATH", request.path_url
        timestamp = str(int(time.time()))
        # if non-empty, body should be a valid JSON in string format
        message = '\n'.join([timestamp, request.method, request.path_url, (request.body or ''), ''])
        signature = hmac.new(self.secret_key, message, digestmod=hashlib.sha256).hexdigest()

        request.headers.update({
            'Authorization': 'prsign %s:%s' % (self.access_key, signature),
            'X-PR-Timestamp': timestamp,
        })

        print request.headers
        return request

api_url = 'https://api.trolley.com/v1/'
auth = TrolleyAuth(ACCESS_KEY, SECRET_KEY)

# Get list of recipients
r = requests.get(api_url + 'recipients', auth=auth)
print r.json()

function getTrolleyAuthHeader(params){
  const timestamp = Math.round(Date.now()/1000);
  const message = 
    `${timestamp}\n
     ${params.method}\n
     ${params.requestPath}\n
     ${params.body}\n`; // if non-empty, body should be a valid JSON in string format
  const signature = crypto.createHmac("sha256", params.SECRET_KEY).update(message).digest("hex");

  var trolleyHeaders = {
    Authorization: `prsign ${params.ACCESS_KEY}:${signature}`,
    "X-PR-Timestamp": timestamp,
    "Content-Type": "application/json"
  }
  
  return trolleyHeaders;
}

...

const ACCESS_KEY = '<YOUR_ACCESS_KEY>';
const SECRET_KEY = '<YOUR_SECRET_KEY>';

fetch("https://api.trolley.com/v1/recipients", {
    method: 'get',
    headers: getTrolleyAuthHeader({
      method: 'get'.toUpperCase(),
      requestPath: '/v1/recipients',
      body: '', // if non-empty, body should be a valid JSON in string format
      ACCESS_KEY: ACCESS_KEY,
      SECRET_KEY: SECRET_KEY
    }),
  })
    .then(result => console.log(result))
    .catch(error => console.log('error', error));


function getTrolleyAuthHeaders($params){
    $timestamp = time();
    $message = join("\n", [$timestamp, $params["method"], $params["requestPath"], $params["body"]]);
    $signature = hash_hmac("sha256", $message, $params["accessSecret"]);

    $authHeader[] = "Authorization: prsign " . $params["accessKey"] . ":" . $signature;
    $authHeader[] = "X-PR-Timestamp: " . $timestamp;
    $authHeader[] = "Content-Type: application/json";
    $authHeader[] = "Accept: application/json";

    return $authHeader;
}

...

$accessKey = "<YOUR_ACCESS_KEY>";
$accessSecret = "<YOUR_SECRET_KEY>";

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://api.trolley.com/v1/recipients",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLINFO_HEADER_OUT => true,
  CURLOPT_HTTPHEADER => getTrolleyAuthHeaders(
      array(
          "method" => strtoupper("GET"),
          "requestPath" => "/v1/recipients",
          "body" => "", // if non-empty, body should be a valid JSON in string format
          "accessKey" => $accessKey,
          "accessSecret" => $accessSecret
          )
      ),
));

$response = curl_exec($curl);
curl_close($curl);

print_r($response);

require 'digest'
require 'net/http'
require 'openssl'
require 'uri'
require 'json'

def get_trolley_auth_header (params)
  timestamp = Time.now.to_i
  message = [timestamp, params[:method], params[:requestPath], params[:body]].join("\n") + "\n"
  signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), params[:secret_key], message)

  {'X-PR-Timestamp': timestamp.to_s,
    'Authorization': 'prsign ' + params[:access_key] + ':' + signature,
    'Content-Type': 'application/json'}
end

ACCESS_KEY = '<YOUR_ACCESS_KEY>';
SECRET_KEY = '<YOUR_SECRET_KEY>';

headers = get_trolley_auth_header ({method: 'GET', 
    requestPath: '/v1/recipients',
    body: '', # if non-empty, body should be a valid JSON in string format
    access_key: ACCESS_KEY,
    secret_key: SECRET_KEY
  })

...

uri = URI.parse('https://api.trolley.com/v1/recipients')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri, headers)
response = http.request(request)
puts response.body["ok"]
//This sample uses .Net Core

using System.Net;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;

void setTrolleyAuthHeaders(string method, string requestPath, string body, string accessKey, string secretKey, ref HttpClient httpClient)
{
    TimeSpan epochTicks = new TimeSpan(new DateTime(1970, 1, 1).Ticks);
    TimeSpan unixTicks = new TimeSpan(DateTime.UtcNow.Ticks) - epochTicks;
    int timeStamp = (int)unixTicks.TotalSeconds;

    string message = timeStamp + "\n" + method + "\n" + requestPath + "\n" + body + "\n";

    ASCIIEncoding encoding = new ASCIIEncoding();
    Byte[] messageBytes = encoding.GetBytes(message);
    Byte[] accessKeyBytes = encoding.GetBytes(secretKey);

    HMACSHA256 hash = new HMACSHA256(accessKeyBytes);
    Byte[] hashBytes = hash.ComputeHash(messageBytes);

    var signature = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
    var authHeader = "prsign " + accessKey + ":" + signature;

    httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);
    httpClient.DefaultRequestHeaders.Add("X-PR-Timestamp", timeStamp.ToString());
    httpClient.DefaultRequestHeaders
      .Accept
      .Add(new MediaTypeWithQualityHeaderValue("application/json"));

}

...

string ACCESS_KEY = "<YOUR_ACCESS_KEY>";
string SECRET_KEY = "<YOUR_ACCESS_SECRET>";

var httpClient = new HttpClient(
    new HttpClientHandler {
        AutomaticDecompression = DecompressionMethods.GZip
        | DecompressionMethods.Deflate });

setTrolleyAuthHeaders( 
    "get".ToUpper(),
    "/v1/recipients",
    "",  // if non-empty, body should be a valid JSON in string format
    ACCESS_KEY,
    SECRET_KEY,
    ref httpClient);

httpClient.BaseAddress = new Uri("https://api.trolley.com");
HttpResponseMessage response = httpClient.GetAsync("/v1/recipients").Result;
response.EnsureSuccessStatusCode();
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("Result: " + result);

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

...

HashMap<String, String> getTrolleyAuthHeaders(HashMap<String, String> params) 
    throws UnsupportedEncodingException, 
            InvalidKeyException, 
            NoSuchAlgorithmException{

    HashMap<String,String> headerValues = new HashMap<String, String>();
    
    int timeStamp = (int) (System.currentTimeMillis() / 1000L);

    String message = timeStamp + "\n" 
    + params.get("method") + "\n" 
    + params.get("requestPath") + "\n" 
    + params.get("body") 
    + "\n";

    String digest = null;
    final SecretKeySpec key = new SecretKeySpec((params.get("secretKey")).getBytes("UTF-8"), "HmacSHA256");
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(key);

    byte[] bytes = mac.doFinal(message.getBytes("ASCII"));

    StringBuffer hash = new StringBuffer();
    for (int i = 0; i < bytes.length; i++) {
        String hex = Integer.toHexString(0xFF & bytes[i]);
        if (hex.length() == 1) {
            hash.append('0');
        }
        hash.append(hex);
    }
    digest = hash.toString();

    headerValues.put("Authorization", "prsign " + params.get("accessKey").toString() + ":" + digest);
    headerValues.put("X-PR-Timestamp", ""+timeStamp);
    headerValues.put("Content-Type", "application/json");

    return headerValues;
}

...

String ACCESS_KEY = "<YOUR_ACCESS_KEY>";
String SECRET_KEY = "<YOUR_SECRET_KEY>";

try {
    URL obj = new URL("https://api.trolley.com/v1/recipients");
    HttpURLConnection con = (HttpURLConnection) obj.openConnection();
    con.setRequestMethod("GET");

    HashMap<String, String> headerValues = getTrolleyAuthHeaders(new HashMap<String,String>(){{
        put("method", "get".toUpperCase());
        put("requestPath", "/v1/recipients");
        put("body",""); // if non-empty, body should be a valid JSON in string format
        put("accessKey", ACCESS_KEY);
        put("secretKey", SECRET_KEY);
    }});

    //Setting header values
    for (String i : headerValues.keySet()) {
        con.setRequestProperty(i, headerValues.get(i));
    }

    BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
    String inputLine;
    StringBuffer response = new StringBuffer();

    while ((inputLine = in.readLine()) != null) {
        response.append(inputLine);
    }
    in.close();

    System.out.println(response.toString());

}catch (IOException e) {
    e.printStackTrace();
}


All REST requests must contain the following headers:

All request bodies should have a content type of application/json and be valid JSON.

The Authorization header will have the format of Authorization: prsign ACCESS_KEY:REQUEST_SIGNATURE

The REQUEST_SIGNATURE is computed by creating a sha256 HMAC using the secret key on the prehash string and timestamp + '\n' + method + '\n' + requestPath + '\n' + body + '\n'.

Additional Security for API Keys

For enhanced API Key security, we recommend that you whitelist IP addresses that are permitted to make requests. You can do this in ‘Settings’ section of the merchant dashboard under the ‘Security’ tab.

Recipients


A recipient is an individual or company that can receive payments, such as freelancers, contract workers, suppliers, marketplace sellers, employees, etc. Basically, anyone your business needs to pay.

Recipients can receive payouts directly to their Bank Account or their PayPal account (with more payout options coming soon, such as Mobile Money, and Debit/Credit Cards).

Recipients must be created prior to sending a payment to them. When you create a recipient, we automatically generate and assign a unique recipient Id. The format of all recipient IDs are “R-1a2B3c4D5e6F7g8H9i0J1k”, with the ‘R-’ prefix indicating Recipient.

Recipient Attributes

Example Recipient

{
  "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
  "referenceId": "U341553728",
  "email": "richard@example.com",
  "name": "",
  "lastName": "Richard",
  "firstName": "Hendricks",
  "status": "active",
  "complianceStatus": "review",
  "gravatarUrl": "https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50",
  "language": "en",
  "dob": "1991-12-23",
  "passport": "HA24123423",
  "ssn": "123-45-6789",
  "governmentIds":[
    {
        "country": "US",
        "type": "SSN",
        "value": "********1234"
    },
    {
        "country": "US",
        "type": "passport",
        "value": "********1234"
    }
  ],
  "routeType": "eft",
  "routeMinimum": 1,
}
Attribute Description
id
string
A system generated ID number assigned to the recipient by Trolley.
referenceId
string
Recipient reference ID as assigned by your business (your internal user reference number, e.g. ‘U1234556678’)
email
required
string
Email address of recipient (e.g. ‘john@email.com’)
name
required if type is Business
string
Name of Business (e.g. ABC Company Ltd). Required if Type is Business. (Note: If type is Individual, we will automatically populate this field with firstname and lastname of individual).
lastName
required if type is Individual
string
Recipient’s Last name (surname), (e.g. ‘Smith’). Required if Type is Individual. Optionally can provide contact persons last name if Type is Business.
firstName
required if Type is Individual
string
Recipient’s First name (e.g. ‘John’). Required if Type is Individual. Optionally can provide contact persons first name if Type is Business.
status
string
Status of a recipient in the system
complianceStatus
string
AML watchlist compliance screening status for the Recipient. A Recipient’s compliance review can either be pending (default), or ongoing (review), has passed (verified), or has been flagged for further review (blocked).
gravatarUrl
string
The gravatar url of recipient
language
string
2-letter ISO 639-1 language code and optional 2-letter ISO-3166 country code. (eg. “en” and “en-CA” both are acceptable) Supported Languages
dob
date
Date of Birth (YYYY-MM-DD)
passport
string
Passport number
governmentIds
array
Government IDs or Tax ID numbers (e.g. 123456798910). Required for bank transfer payout method. Each object in this array represents one government Id. Refer to the example in the response sample above. Some countries require specific IDs: If Individual: Argentina (CUIT, 11 digits), Azerbaijan (TIN, 10 digits), Brazil (CPF, 11 digits), Chile (RUT/RUN, 9 digits), Colombia (NIT, 10 digits), Costa Rica (Cedula Juridica, 9-12 digits), Guatemala (NIT, 8-12 digits), Kazakhstan (IIN, 12 digits), Paraguay (6-11 digits). If Business: Argentina (CUIT, 11 digits), Brazil (CNPJ, 14 digits). For more details, check Country Requirements Reference Doc.
address
object
Address details of recipient
routeType
string
The route that recipient will receive payout with. Depends on Recipient’s country and active payment method. Sample values are eft, ach, fps, sepa, wire, transfer etc.
routeMinimum
number or null
Minimum amount that you can send to this recipient. A null value indicates a recipient’s profile is not complete
accounts
object
Recipient Account information
tags
array
A collection of keywords to help identify the recipient.
contactEmails
array
A list of secondary email addresses that will be CC’d in all recipient emails (excluding Portal login code/authentication emails).

Address

Example Address

{
  "street1": "123 Main St",
  "street2": "",
  "city": "San Francisco",
  "region": "CA",
  "postalCode": "94131",
  "country": "US",
  "phone": "18005551212"
}
Field Description
street1
required
string
Recipient’s Street 1 Address. Please do not provide PO Box Address. (E.g. 123 Sample Street). Required for bank transfer payout method. Otherwise it is optional.
street2
optional
string
Recipient’s Street 2 Address (e.g. Apt 5).
city
required
string
Recipient’s address City (e.g. Miami). Required for bank transfer payout method. Otherwise it is Optional.
postalCode
optional
string
Recipient’s address Postal code or Zip code (e.g. 90210, M5X 2X1, 2000).
country
required
string
Recipient Country. Required for bank transfer payout method.Otherwise it is Optional. We accept ISO 3166-1 alpha-2 (e.g. ‘US’, ‘DE’)
region
optional
string
Region code Recipient’s address Region (state/ province / county). We accept both ISO 3166-2 code (e.g. FL), and full state/province name (e.g. Florida). ISO 3166-2 code is highly recommended.
phone
optional
string
Recipient’s phone number (e.g. 415-123-0000 or +14151230000). Required for bank transfer payout method for these countries only: Argentina, Bangladesh, Brazil, Chile, China, Colombia, Costa Rica, Ethiopia, Fiji, Guatemala, Jordan, Kazakhstan, Kiribati, Korea (South), Mongolia, Russia, South Africa, Taiwan, Thailand, Tuvalu, Togo, Tonga. Otherwise it is optional.

Payout Method

For further information read about the Payout Method Attributes

Create a recipient

Example request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X POST 'https://api.trolley.com/v1/recipients/' \
--data-raw '{
    "referenceId": "A-104",
    "type": "individual",
    "firstName": "Leonardo",
    "lastName": "da Vinci",
    "email": "leonardo@davinci.it",
    "dob": "1902-04-15",
    "address": {
        "street1": "191,  Royal Library of Turin",
        "street2": "P.za Castello",
        "city": "Torin TO",
        "postalCode": "10122",
        "country": "IT"
    },
    "governmentIds":[
        {
            "country":"IT",
            "type":"other",
            "value":"ABCD123123"
        }
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$recipient = Trolley\Recipient::create([
    'type' => "individual",
    'firstName' => 'Tom',
    'lastName' => 'Jones',
    'email' => 'jsmith@example.com',
    'address' => [
      "city" => "Montréal",
      "country" => "CA",
      "phone" => "+15141111111",
      "postalCode" => "A1A 1A1",
      "region" => "BC",
      "street1" => "Toad Street",
      "street2" => "Avenue Rock",
    ],
]);

print_r($recipient);

?>

// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const recipient = await client.recipient.create(
  {
    type: "individual",
    firstName: "John",
    lastName: "Smith",
    email: "jsmith@example.com",
    address: {
      city: "Montréal",
      country: "CA",
      phone: "+15141111111",
      postalCode: "A1A 1A1",
      region: "BC",
      street1: "Toad Street",
      street2: "Avenue Rock"
    }
  }
);

console.log(recipient.id);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient.create(
  {
    type:"individual",
    firstName: 'John',
    lastName: 'Smith',
    email: 'jsmith@example.com',
    address: {
      city: "Montréal",
      country: "CA",
      phone: "+15141111111",
      postalCode: "A1A 1A1",
      region: "BC",
      street1: "Toad Street",
      street2: "Avenue Rock"
    }
    account: {
      type: 'paypal',
      emailAddress: 'jsmithpaypal@example.com'
    }
  })

print response;


from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

payload = {
    "type": "individual", 
    "firstName": "Tom", 
    "lastName": "Jones",
    "email": "tom.jones@example.com"
}

response = client.recipient.create(payload)

print(response)

...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

// Create a new Recipient request object
Recipient recipientRequest = new Recipient();
recipientRequest.setType("individual");
recipientRequest.setFirstName("John");
recipientRequest.setLastName("Smith");
recipientRequest.setEmail("john.smith@example.com");

// Create and add an Address
Address address = new Address();
address.setStreet1("123 Main St");
address.setCity("San Francisco");
address.setRegion("CA");
address.setPostalCode("94131");
address.setCountry("US");
address.setPhone("18005551212");
recipientRequest.setAddress(address);

// Create and add government ID
GovernmentId govtId = new GovernmentId("US", "SSN", "ABCD123456");
ArrayList<GovernmentId> govtIds = new ArrayList<GovernmentId>();
govtIds.add(govtId);

recipientRequest.setGovernmentIds(govtIds);

Recipient recipient = client.recipient.create(recipientRequest);

System.out.println(recipient.getId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

Recipient recipientRequest = new Recipient();
recipientRequest.type = "individual";
recipientRequest.email = "tom.jones@example.com";
recipientRequest.firstName = "Tom";
recipientRequest.lastName = "Jones";
recipientRequest.dob = "1990-01-01";
recipientRequest.address = new Address("street1", "city", "US", "AL", "12345");

Recipient recipient = gateway.recipient.Create(recipientRequest);

Console.WriteLine(recipient.id);

...

Example response (200 Ok)

{
  "ok": true,
  "recipient": {
    "id": "R-1a3B3c4D5e6F7g8H9i0J1k",
    "referenceId": "jsmith11@example.com",
    "email": "jsmith11@example.com",
    "name": "John Smith",
    "lastName": "John",
    "firstName": "Smith",
    "type": "individual",
    "status": "incomplete",
    "language": "en",
    "complianceStatus": "verified",
    "dob": null,
    "updatedAt": "2017-03-20T19:06:40.937Z",
    "createdAt": "2017-03-17T20:10:45.818Z",
    "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
    "placeOfBirth": null,
    "ssn": null,
    "tags": [],
    "passport": "",
    "payoutMethod": "bank-transfer",
    "compliance": {
      "status": "verified",
      "checkedAt": "2017-03-20T19:06:23.916Z"
    },
    "routeType": "ach",
    "routeMinimum": "1",
    "estimatedFees": "1.25",
    "accounts": [],
    "address": {
      "street1": "",
      "street2": null,
      "city": "",
      "postalCode": "",
      "phone": "",
      "country": null,
      "region": null
    },
    "primaryCurrency": "CAD"
  }
}

Example response of Recipient with address (200 Ok)

{
  "ok": true,
  "recipient": {
    "id": "R-1a3B3c4D5e6F7g8H9i0J1k",
    "referenceId": "jsmith11@example.com",
    "email": "jsmith11@example.com",
    "name": "John Smith",
    "lastName": "John",
    "firstName": "Smith",
    "type": "individual",
    "status": "incomplete",
    "language": "en",
    "complianceStatus": "verified",
    "dob": null,
    "updatedAt": "2017-03-20T19:06:40.937Z",
    "createdAt": "2017-03-17T20:10:45.818Z",
    "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
    "placeOfBirth": null,
    "ssn": null,
    "tags": [],
    "passport": "",
    "payoutMethod": "bank-transfer",
    "compliance": {
      "status": "verified",
      "checkedAt": "2017-03-20T19:06:23.916Z"
    },
    "routeType": "ach",
    "routeMinimum": "1",
    "estimatedFees": "1.25",
    "accounts": [],
    "address": {
      "street1": "Apt# 14",
      "street2": null,
      "city": "",
      "postalCode": "H3WXXX",
      "phone": "",
      "country": "CA",
      "region": "QC"
    },
    "primaryCurrency": "CAD"
  }
}

To create a Recipient, send a POST request to the /recipients endpoint and include the user details in JSON format in the request body. Each recipient will be assigned and represented by an auto-generated ID (recipientId) which can be used to retrieve or update recipient details at a later time.

HTTP Request

POST https://api.trolley.com/v1/recipients/

Fields Description
referenceId
optional
string
Recipient reference ID as assigned by your business (your internal user reference number, e.g. U1234556678)
type
required
string
Recipient type, either: business or individual
name
conditional
string
Name of Business (e.g. ABC Company Ltd). Required if Type is business. (Note: If type is individual, we will automatically populate this field with firstName and lastName of individual).
firstName
conditional
string
Recipient’s First name (e.g. John). Required if Type is individual. Optionally can provide contact persons first name if Type is business.
lastName
conditional
string
Recipient’s Last name (surname), (e.g. Smith). Required if Type is individual. Optionally can provide contact persons last name if Type is business.
email
required
string
Email address of recipient (e.g. john@email.com)
address
optional
address
Address object. Please read the documentation
passport
optional
string
Recipients valid passport number
dob
optional
date
Recipient’s date of birth. The format should be YYYY-MM-DD, ie 1990-04-29
phone
optional
string
Recipient’s phone number (e.g. 415-123-0000 or +14151230000). Required for bank transfer payout method for these countries only: Argentina, Bangladesh, Brazil, Chile, China, Colombia, Costa Rica, Ethiopia, Fiji, Guatemala, Jordan, Kazakhstan, Kiribati, Korea (South), Mongolia, Russia, South Africa, Taiwan, Thailand, Tuvalu, Togo, Tonga. Otherwise it is optional.

HTTP Response codes

HTTP Code Description
200 Recipient successfully created
400 One or more fields failed validation, see errors[] in response body
401 Invalid API key
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
empty_field A field is required
invalid_field A field failed a validation check
invalid_api_key Invalid API key
internal_server_error Internal server errors

Errors Example

If there is a validation error creating a recipients, the API will respond with an error. For example:

Response (406 Not Acceptable)

{
  "ok": false,
  "errors": [
    {
      "code": "invalid_field",
      "field": "email",
      "message": "Email is already exists"
    },
    {
      "code": "empty_field",
      "field": "name",
      "message": "Expected to have a non-null or non-empty value"
    }
  ]
}

Retrieve a recipient

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/recipients/R-1a2B3c4D5e6F7g8H9i0J1k' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$recipient = Trolley\Recipient::find($recipient_id);

print_r($recipient);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.recipient.find(recipient.id);

console.log(recipient.id);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient.find(recipient.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.recipient.find(recipient_id)

print(response)

...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();

// Get a recipient by ID
Recipient recipient = client.recipient.find(recipientId);

System.out.println(recipient.getId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();

Recipient recipient = gateway.recipient.Get(recipientId);

Console.WriteLine(recipient.id);

...

You can retrieve details of a recipient account by sending a GET request to the /recipients/:id endpoint.

HTTP Request

GET https://api.trolley.com/v1/recipients/:id

Fields Description
id
required
string
Recipient ID

Example Response (200 Ok)

{
  "ok": true,
  "recipient": {
    "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
    "referenceId": "jsmith11@example.com",
    "email": "jsmith11@example.com",
    "name": "Richard Hendricks",
    "lastName": "Hendricks",
    "firstName": "Richard",
    "type": "individual",
    "status": "active",
    "language": "en",
    "complianceStatus": "verified",
    "dob": null,
    "updatedAt": "2017-03-20T19:06:40.937Z",
    "createdAt": "2017-03-17T20:10:45.818Z",
    "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
    "placeOfBirth": null,
    "ssn": null,
    "tags": [],
    "passport": "",
    "payoutMethod": "bank-transfer",
    "compliance": {
      "status": "verified",
      "checkedAt": "2017-03-20T19:06:23.916Z"
    },
    "routeType": "ach",
    "routeMinimum": "1", 
    "estimatedFees": "1.25",
    "accounts": [
      {
        "accountHolderName": "Richard Hendricks",
        "bankId": "123",
        "currency": "CAD",
        "country": "CA",
        "bankName": "TD CANADA TRUST",
        "branchId": "47261",
        "accountNum": "*****47"
      }
    ],
    "address": {
      "street1": "Apt# 14",
      "street2": null,
      "city": "",
      "postalCode": "H3WXXX",
      "phone": "",
      "country": "CA",
      "region": "QC"
    },
    "primaryCurrency": "CAD"
  }
}
HTTP Code Description
200 Recipient Object
401 Invalid API key
404 Recipient not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Errors Example

If recipient doesn’t exist, the API will respond with an error. For example:

Response (404 Not Found)

{
  "ok": false,
  "errors": [
    {
      "code": "not_found",
      "message": "Object not found"
    }
  ]
}

Update a recipient

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X PATCH 'https://api.trolley.com/v1/recipients/R-1a3B3c4D5e6F7g8H9i0J1k' \
--data-raw '{
    "firstName": "tom"
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\Recipient::update($recipient->id, [
    "firstName" => "Mark",
]);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.recipient.update(
  recipient.id,
  { 
    firstName: "John"
  }
);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient.update(
  recipient.id,
  { 
    firstName: 'Mark'
  })

print response
from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.recipient.update(
  recipient_id,  
  {
    "firstName": "Jon"
  })

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();

// Update a recipient
Recipient updateRequest = new Recipient();;
updateRequest.setFirstName("Bob");

boolean response = client.recipient.update(recipientId, updateRequest);

System.out.println(response);

// Look at Recipient.Create request sample to learn how to set different fields

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();

Recipient recipientRequest = new Recipient();
recipientRequest.firstName = "Bób";

Recipient recipient = gateway.recipient.Update(recipientId, recipientRequest);

Console.WriteLine(recipient.id);

...

Response (200 Ok)

{
  "ok": true,
  "recipient": {
    "id": "R-1a3B3c4D5e6F7g8H9i0J1k",
    "referenceId": "jsmith11@example.com",
    "email": "jsmith11@example.com",
    "name": "tom Smith",
    "lastName": "Smith",
    "firstName": "tom",
    "type": "individual",
    "status": "incomplete",
    "language": "en",
    "complianceStatus": "verified",
    "dob": null,
    "updatedAt": "2017-03-20T19:06:40.937Z",
    "createdAt": "2017-03-17T20:10:45.818Z",
    "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
    "placeOfBirth": null,
    "ssn": null,
    "tags": [],
    "passport": "",
    "payoutMethod": "bank-transfer",
    "compliance": {
      "status": "verified",
      "checkedAt": "2017-03-20T19:06:23.916Z"
    },
    "routeType": "ach",
    "routeMinimum": "1", 
    "estimatedFees": "1.25",
    "accounts": [],
    "address": {
      "street1": "Apt# 14",
      "street2": null,
      "city": "",
      "postalCode": "H3WXXX",
      "phone": "",
      "country": "CA",
      "region": "QC"
    },
    "primaryCurrency": "CAD"
  }
}

You can update the information of an existing recipient by sending a PATCH request to the /recipients/:id endpoint.

Examples of this would be: recipient has a new street address, new payout method, or new payout method details such as a different bank account number, etc. You can also change the status of a recipient such as to active or suspended.

Note: Account cannot be updated via this interface. Refer to Recipient Account for more information

HTTP Request

PATCH https://api.trolley.com/v1/recipients/:id

Fields Description
id
required
string
Recipient ID

HTTP Response codes

HTTP Code Description
200 Recipient successfully updated
400 One or more fields failed validation, see errors[] in response body
401 Invalid API key
500 Internal error

Errors

This table lists the expected errors that this request could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
empty_field A field is required
invalid_field A field failed a validation check
invalid_api_key Invalid API key
not_found Object doesn’t exist
internal_server_error Internal server errors

Errors Example

If there is a validation error updating a recipient, the API will respond with an error. For example:

Response (406 Not Acceptable)

{
  "ok": false,
  "errors": [
    {
      "code": "invalid_field",
      "field": "type",
      "message": "Expected to have a non-null or non-empty value"
    }
  ]
}

Delete a recipient

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X DELETE 'https://api.trolley.com/v1/recipients/R-1a3B3c4D5e6F7g8H9i0J1k'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\Recipient::delete($recipient->id);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.recipient.remove(recipient.id);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient.delete(recipient.id)

print response
from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.recipient.delete(recipient_id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();

// Delete one recipient
boolean response = client.recipient.delete(recipientId);
System.out.println(response);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();

bool delResult = gateway.recipient.Delete(recipientId);

Console.WriteLine(delResult);

...

To delete a Recipient, send a DELETE request to the /recipients endpoint with the recipientID. This places the recipient in archived state and can be un-archived.

HTTP Request

DELETE https://api.trolley.com/v1/recipients/:id

Fields Description
id
required
string
Recipient ID

Response (200 Ok)

{
  "ok": true,
}
HTTP Code Description
200 Recipient successfully deleted
401 Invalid API key
404 Recipient not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Errors Example

If recipient does not exist, the API will respond with an error. For example:

Response (404 Not Found)

{
  "ok": false,
  "errors": [
    {
      "code": "not_found",
      "message": "Object not found"
    }
  ]
}

Delete multiple recipients

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X DELETE 'https://api.trolley.com/v1/recipients' \
--data-raw '{
  "ids": [
    "R-1a2B3c4D5e6F7g8H9i0J1k", 
    "R-1a2B3c4D5e6F7g8H9i0J1k"
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$deleteResult = Trolley\Recipient::deleteMultiple(
  [
    $recipientOne->id, 
    $recipientTwo->id
  ]);

print_r($deleteResult);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const recipient = await client.recipient.create(
  [
    recipient1.id, 
    recipient2.id
  ]);

console.log(recipient.id);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient.delete(
  [
    recipient1.id, 
    recipient2.id
  ])

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

payload = {
    "ids": [
        recipient1.id,
        recipient2.id
        ]
    }
response = client.recipient.delete_multiple(payload)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

// Delete multiple recipients
List<Recipient> recipients = getRecipients();

boolean response = client.recipient.delete(recipients);
System.out.println(response);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId1 = GetFirstRecipientId();
string recipientId2 = GetSecondRecipientId();

bool delResult = gateway.recipient.Delete(recipientId1, recipientId2);

Console.WriteLine(delResult);

...

Response (200 Ok)

{
  "ok": true,
}

You can delete multiple recipients by sending a DELETE request to the /recipients endpoint.

HTTP Request

DELETE https://api.trolley.com/v1/recipients/

Fields Description
ids
required
array of strings
Recipient IDs to delete
HTTP Code Description
200 All recipients successfully deleted
401 Invalid API key
404 Recipient not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Errors Example

If any of the recipients do not exist, the API will respond with an error.

Response (404 Not Found)

{
  "ok": false,
  "errors": [
    {
      "code": "not_found",
      "message": "Object not found"
    }
  ]
}

List all recipients

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/recipients/' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

// Get all recipients
$recipients = Trolley\Recipient::all();
foreach ($recipients as $recipient) {
    print_r($recipient);
}

// Search for recipients
$searchResults = Trolley\Recipient::search(
        [
            "name"      =>  "Tom",
            "page"      =>  1,
            "pageSize"  =>  2
        ]
    );

foreach($searchResults as $recipients){
  print_r($recipients);
}

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.recipient.search(1, 10, "John");

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

# List all recipients
response = client.recipient.search
print response

# Search for recipients
response = client.recipient.search(
  1,        # page number
  10,       # items per page
  "John")   # search term
  
print response
from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

# Searching recipients without any search term lists all recipients
recipients = client.recipient.search()

# Iterate through the generator to go through ALL the recipients with auto pagination
for recipient in recipients:
  print(recipient)

# OR, get the recipients manually page-by-page
recipients = client.recipient.search_by_page(2,20)

# Iterate through the returned list for the requested page
for recipient in recipients:
  print(recipient)

...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

int page = 1;
int pageSize = 10;

// Get all recipients with an optional search term and manual pagination
Recipients allRecipients = client.recipient.search(page, pageSize, "<search_term>");
List<Recipient> recipients = allRecipients.getRecipients();

for (Recipient recipient : recipients) {
  System.out.println(recipient.getId());
}

...

// Or, with auto-pagination
RecipientsIterator recipients = client.recipient.search("<search_term>");

while(recipients.hasNext()) {
    System.out.println(recipients.next().getId());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
int page = 1;
int pageSize = 10;

// List all recipients with manual pagination and an optional search term
Recipients allRecipients = gateway.recipient.ListAllRecipients("<search_term>", page, pageSize);

// Get a List of Recipient objects to iterate over
List<Recipient> recipients = allRecipients.recipients;

// And get the Meta object to access pagination information
Meta meta = allRecipients.meta;

// Or, get all recipients with auto-pagination and an optional search term
var recipients = gateway.recipient.ListAllRecipients("<search_term>");

foreach (Recipient recipient in recipients)
{
  Console.WriteLine(recipient.id);
}

...

Response (200 Ok)

{
  "ok": true,
  "recipients": [
    {
      "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
      "referenceId": "rhendricks@example.com",
      "email": "rhendricks@example.com",
      "name": "Richard Hendricks",
      "lastName": "Hendricks",
      "firstName": "Richard",
      "type": "individual",
      "status": "active",
      "language": "en",
      "complianceStatus": "verified",
      "dob": null,
      "updatedAt": "2017-03-20T19:06:40.937Z",
      "createdAt": "2017-03-17T20:10:45.818Z",
      "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
      "placeOfBirth": null,
      "ssn": null,
      "tags": [],
      "passport": "",
      "payoutMethod": "bank-transfer",
      "compliance": {
        "status": "verified",
        "checkedAt": "2017-03-20T19:06:23.916Z"
      },
      "routeType": "ach",
      "routeMinimum": "1", 
      "estimatedFees": "1.25",
      "accounts": [
        {
          "accountHolderName": "Richard Hendricks",
          "bankId": "123",
          "currency": "CAD",
          "country": "CA",
          "bankName": "TD CANADA TRUST",
          "branchId": "47261",
          "accountNum": "*****47"
        }
      ],
      "address": {
        "street1": "Apt# 14",
        "street2": null,
        "city": "",
        "postalCode": "H3WXXX",
        "phone": "",
        "country": "CA",
        "region": "QC"
      },
      "primaryCurrency": "CAD"
    },
    {
      "id": "R-1a3B3c4D5e6F7g8H9i0J1k",
      "referenceId": "jsmith11@example.com",
      "email": "jsmith11@example.com",
      "name": "John Smith",
      "lastName": "John",
      "firstName": "Smith",
      "type": "individual",
      "status": "active",
      "language": "en",
      "complianceStatus": "verified",
      "dob": null,
      "updatedAt": "2017-03-20T19:06:40.937Z",
      "createdAt": "2017-03-17T20:10:45.818Z",
      "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
      "placeOfBirth": null,
      "ssn": null,
      "tags": [],
      "passport": "",
      "payoutMethod": "bank-transfer",
      "compliance": {
        "status": "verified",
        "checkedAt": "2017-03-20T19:06:23.916Z"
      },
      "routeType": "ach",
      "routeMinimum": "1", 
      "estimatedFees": "1.25",
      "accounts": [
        {
          "accountHolderName": "John Smith",
          "bankId": "123",
          "currency": "CAD",
          "country": "CA",
          "bankName": "TD CANADA TRUST",
          "branchId": "47261",
          "accountNum": "*****47"
        }
      ],
      "address": {
        "street1": "Apt# 14",
        "street2": null,
        "city": "",
        "postalCode": "H3WXXX",
        "phone": "",
        "country": "CA",
        "region": "QC"
      },
      "primaryCurrency": "CAD"
    }
  ],
  "meta": {
    "page": 1,
    "pages": 1,
    "records": 2
  }
}

You can retrieve details of your recipients by sending a GET request to the /recipients endpoint. Query parameters can be used in the request to sort, filter or paginate the result set as intended.

For example, use this API to retrieve a list of all active recipients who live in New Zealand.

HTTP Request

GET https://api.trolley.com/v1/recipients

Query Param Description
page
optional
int
The page number (default: 1)
pageSize
optional
int
Number of records in a page (default: 10)
search
optional
string
Prefix search of the name, email (username and domain-name) and referenceId
name
optional
string
Prefix search of the name, firstName, lastName
email
optional
string
Exact search of the email address
referenceId
optional
string
Exact search of the referenceId
startDate
optional
date
Ignore older records (based on update date)
endDate
optional
date
Ignore newer records (based on update date)
status
optional
string
Filter by recipient statuses
complianceStatus
optional
string
Filter by pending, verified, blocked
country
optional
string
Filter by ISO2 country code (comma separated list if multiple)
payoutMethod
optional
string
Filter by paypal, bank-transfer, check
currency
optional
string
Currency of recipient’s bank account. Required for bank transfer payout method. We support 3 letter ISO 4217 codes (e.g. EUR). Not required for PayPal.
orderBy
optional
string
Field name: name, email, referenceId, payoutMethod, createdAt, updatedAt
sortBy
optional
string
Sorting direction asc or desc (default: desc)
HTTP Code Description
200 List of Recipient
401 Invalid API key
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Retrieve all logs

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/recipients/R-4QoXiSPjbnLuUmQR2bgb8C/logs' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$recipientLogs = Trolley\Recipient::getAllLogs($recipient->id);
foreach ($recipientLogs as $activity) {
    print_r($activity);
}

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.recipient.findLogs(recipient.id);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient.find_logs(recipient.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

offline_payments = client.recipient.retrieve_logs(recipient_id)

# Iterate through the returned offline payments list
for payment in offline_payments:
  print(payment)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();

int page = 1;
int pageSize = 10;

// Get Recipient Logs with manual pagination
Logs allLogs = client.recipient.getAllLogs(recipientId, page, pageSize);
List<Log> logs = allLogs.getLogs();

for (Log log : logs) {
    System.out.println(log.getVia());
}

...

// Or, with auto-pagination
LogsIterator logs = client.recipient.getAllLogs(recipientId);

while(logs.hasNext()) {
    System.out.println(logs.next().getVia());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();

// Get all logs with manual pagination
Logs allLogs = gateway.recipient.GetAllLogs(recipientId, 1, 10);
List<Log> logs = allLogs.logs;

// Or, get all logs with auto-pagination
var logs = gateway.recipient.GetAllLogs(recipientId);

foreach (Log log in logs)
{
    Console.WriteLine(log.createdAt);
}

...

Response (200 Ok)

{
  "ok": true,
  "activities": [
    {
      "ip": "::ffff:10.0.2.2",
      "url": "/v1/recipients/R-91XNW81D85DMG/log",
      "method": "GET",
      "headers": {
        "host": "api.local.dev:3000",
        "connection": "keep-alive",
        "postman-token": "47cad157-855e-49fe-45d6-d61a02ffa802",
        "cache-control": "no-cache",
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
        "x-api-key": "pk_live_*********************************",
        "content-type": "application/json",
        "accept": "*/*",
        "accept-encoding": "gzip, deflate, sdch",
        "accept-language": "en-US,en;q=0.8"
      },
      "request": "",
      "response": "{\"ok\":false,\"errors\":[{\"code\":\"not_found\",\"message\":\"Object not found\"}]}",
      "code": 404,
      "source": "api",
      "testMode": false,
      "createdAt": "2017-03-22T17:57:32.786Z"
    }
  ],
  "meta": {
    "page": 1,
    "pages": 1,
    "records": 2
  }
}

You can retrieve a list of all activity related to a recipient by sending a GET request to the /recipients/:id/logs endpoint.

HTTP Request

GET https://api.trolley.com/v1/recipients/:id/logs

Fields Description
id
required
string
Recipient ID
HTTP Code Description
200 All recipients
401 Invalid API key
404 Recipient not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Errors Example

If the recipient does not exist, the API will respond with an error. For example:

Response (404 Not Found)

{
  "ok": false,
  "errors": [
    {
      "code": "not_found",
      "message": "Object not found"
    }
  ]
}

Retrieve all payments

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/recipients/R-4QoXiSPjbnLuUmQR2bgb8C/payments' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$allPayments = Trolley\Recipient::getAllPayments($recipient->id);
foreach ($allPayments as $payment) {
  print_r($payment);
}

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.payment.search(
  {
    recipientId: recipient.id
  });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient.find_payments(recipient.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

payments = client.recipient.get_all_payments(recipient_id)

# Iterate through the returned payments list
for payment in payments:
  print(payment)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();

// Get all payments of the recipient
List<Payment> payments = client.recipient.findPayments(recipientId);

for (Payment payment : payments) {
    System.out.println(payment.getId());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
int page = 1;
int pageSize = 10;

// List all recipient payments with manual pagination
Payments allPayments = gateway.recipient.GetAllPayments(recipientId, page, pageSize);

// Get a List of Recipient's Payment objects to iterate over
List<Payment> payments = allPayments.payments;

// And get the Meta object to access pagination information
Meta meta = allPayments.meta;

// Or, get all recipient's payments with auto-pagination
var payments = gateway.recipient.GetAllPayments(recipientId);
foreach (Payment payment in payments)
{
    Console.WriteLine(payment.id);
}

...

Retrieve payments to this recipient

HTTP Request

GET https://api.trolley.com/v1/recipients/:id/payments

Fields Description
id
required
string
Recipient ID

Response (200 Ok)

{
  "ok": true,
  "payments": [
    {
      "id": "P-1a2B3c4D5e6F7g8H9i0J1k",
      "recipient": {
        "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
        "referenceId": "jsmith11@example.com",
        "email": "jsmith11@example.com",
        "name": "Richard Hendricks",
        "lastName": "Hendricks",
        "firstName": "Richard",
        "type": "individual",
        "status": "active",
        "language": "en",
        "complianceStatus": "verified",
        "dob": null,
        "updatedAt": "2017-03-20T19:06:40.937Z",
        "createdAt": "2017-03-17T20:10:45.818Z",
        "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
        "placeOfBirth": null,
        "ssn": null,
        "tags": [],
        "passport": "",
        "payoutMethod": "bank-transfer",
        "compliance": {
          "status": "verified",
          "checkedAt": "2017-03-20T19:06:23.916Z"
        },
        "accounts": [
          {
            "accountHolderName": "Richard Hendricks",
            "bankId": "123",
            "currency": "CAD",
            "country": "CA",
            "bankName": "TD CANADA TRUST",
            "branchId": "47261",
            "accountNum": "*****47"
          }
        ],
        "address": {
          "street1": "Apt# 14",
          "street2": null,
          "city": "",
          "postalCode": "H3WXXX",
          "phone": "",
          "country": "CA",
          "region": "QC"
        },
        "primaryCurrency": "CAD"
      },
      "status": "pending",
      "sourceAmount": "100.10",
      "exchangeRate": "1.0000",
      "fees": "1.25",
      "recipientFees": "1.25",
      "targetAmount": "98.85",
      "fxRate": "2.000000",
      "memo": "memo",
      "processedAt": null,
      "createdAt": "2017-03-21T20:56:43.714Z",
      "updatedAt": "2017-03-21T21:10:05.874Z",
      "merchantFees": "0.00",
      "compliance": {
        "status": "pending",
        "checkedAt": null
      },
      "sourceCurrency": "CAD",
      "sourceCurrencyName": "Canadian Dollar",
      "targetCurrency": "CAD",
      "targetCurrencyName": "Canadian Dollar",
      "batch": {
        "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
        "createdAt": "2017-03-21T20:56:43.690Z",
        "updatedAt": "2017-03-21T21:10:05.890Z",
        "sentAt": null,
        "completedAt": null
      }
    },
    {
      "id": "P-1a2B3c4D5e6F7g8H9i0J1k",
      "recipient": {
        "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
        "referenceId": "jsmith11@example.com",
        "email": "jsmith11@example.com",
        "name": "Richard Hendricks",
        "lastName": "Hendricks",
        "firstName": "Richard",
        "type": "individual",
        "status": "active",
        "language": "en",
        "complianceStatus": "verified",
        "dob": null,
        "updatedAt": "2017-03-20T19:06:40.937Z",
        "createdAt": "2017-03-17T20:10:45.818Z",
        "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
        "placeOfBirth": null,
        "ssn": null,
        "tags": [],
        "passport": "",
        "payoutMethod": "bank-transfer",
        "compliance": {
          "status": "verified",
          "checkedAt": "2017-03-20T19:06:23.916Z"
        },
        "accounts": [
          {
            "accountHolderName": "Richard Hendricks",
            "bankId": "123",
            "currency": "CAD",
            "country": "CA",
            "bankName": "TD CANADA TRUST",
            "branchId": "47261",
            "accountNum": "*****47"
          }
        ],
        "address": {
          "street1": "Apt# 14",
          "street2": null,
          "city": "",
          "postalCode": "H3WXXX",
          "phone": "",
          "country": "CA",
          "region": "QC"
        },
        "primaryCurrency": "CAD"
      },
      "status": "pending",
      "sourceAmount": "100.10",
      "exchangeRate": "1.0000",
      "fees": "1.25",
      "recipientFees": "1.25",
      "targetAmount": "0.00",
      "fxRate": "2.000000",
      "memo": "memo",
      "processedAt": null,
      "createdAt": "2017-03-20T15:11:18.517Z",
      "updatedAt": "2017-03-20T15:11:18.517Z",
      "merchantFees": "0.00",
      "compliance": {
        "status": "pending",
        "checkedAt": null
      },
      "sourceCurrency": "CAD",
      "sourceCurrencyName": "Canadian Dollar",
      "targetCurrency": "CAD",
      "targetCurrencyName": "Canadian Dollar",
      "batch": {
        "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
        "createdAt": "2017-03-20T15:11:18.486Z",
        "updatedAt": "2017-03-20T15:11:18.582Z",
        "sentAt": null,
        "completedAt": null
      }
    }
  ],
  "meta": {
    "page": 1,
    "pages": 1,
    "records": 2
  }
}
HTTP Code Description
200 Recipient’s payments
401 Invalid API key
404 Recipient not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Errors Example

If recipient doesn’t exist, the API will respond with an error. For example:

Response (404 Not Found)

{
  "ok": false,
  "errors": [
    {
      "code": "not_found",
      "message": "Object not found"
    }
  ]
}

Retrieve recipient’s offline payments

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/recipients/R-4QoXiSPjbnLXXXR2bgb8C/offlinePayments' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$offlinePayments = Trolley\OfflinePayments::search(
  [
    "recipientId" => $recipient->id
  ]);
  
foreach ($offlinePayments as $offlinePayment) {
  print_r($offlinePayment);
}

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.offlinePayment.search(
  {
    recipientId: recipient.id
  });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

# Get all offline payment of a recipient
response = client.offline_payment.search(recipient.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

offline_payments = client.recipient.get_all_offline_payments(recipient_id)

# Iterate through the returned offline payments list
for payment in offline_payments:
  print(payment)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();

int page = 1;
int pageSize = 10;

// Get All Offline Payments of a recipient with manual pagination and an optional search term
OfflinePayments allOfflinePayments = getAllOfflinePayments(recipientId, page, pageSize, "<search_term>");
List<OfflinePayment> offlinePayments = allOfflinePayments.getOfflinePayments();

for (OfflinePayment offlinePayment : offlinePayments) {
    System.out.println(offlinePayment.getId());
}

...

// Or, with auto-pagination
OfflinePaymentsIterator offlinePayments = client.recipient.getAllOfflinePayments(recipientId, "<search_term>");
while(offlinePayments.hasNext()) {
    System.out.println(offlinePayments.next().getId());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
int page = 1;
int pageSize = 10;

// List all offline payments of a recipient with manual pagination and an optional search term
OfflinePayments allOfflinePayments = gateway.recipient.GetAllOfflinePayments(recipientId, "<search_term>", page, pageSize);

// Get a List of OfflinePayment objects to iterate over
List<OfflinePayment> offlinePayments = allOfflinePayments.offlinePayments;

// And get the Meta object to access pagination information
Meta meta = allOfflinePayments.meta;

// Or, get all offline payments of a recipients with auto-pagination and an optional search term
var offlinePayments = gateway.recipient.GetAllOfflinePayments(recipientId, "<search_term>");

foreach (OfflinePayment offlinePayment in offlinePayments)
{
  Console.WriteLine(offlinePayment.id);
}

...

Retrieve a recipient’s offline payments

HTTP Request

GET https://api.trolley.com/v1/recipients/:id/offlinePayments

Fields Description
id
required
string
Recipient ID

Response (200 Ok)

{
  "ok": true,
  "offlinePayments": [
    {
      "amount": "100.00",
      "category": "services",
      "createdAt": "2019-10-31T20:24:29.954Z",
      "currency": "USD",
      "deletedAt": null,
      "equivalentWithholdingAmount": "24.00",
      "equivalentWithholdingCurrency": "USD",
      "externalId": "id-123",
      "id": "OP-3xghXMEcedrjPEo3KedqsR",
      "memo": "A memo",
      "processedAt": "2019-08-15T20:23:59.000Z",
      "recipientId": "R-4321c356vrcerc54js",
      "tags": [],
      "taxReportable": true,
      "updatedAt": "2019-10-31T20:24:29.954Z",
      "withholdingAmount": "24.00",
      "withholdingCurrency": "USD"
    },
    {
      "amount": "100.00",
      "category": "services",
      "createdAt": "2019-10-31T20:24:29.954Z",
      "currency": "USD",
      "deletedAt": null,
      "equivalentWithholdingAmount": "24.00",
      "equivalentWithholdingCurrency": "USD",
      "externalId": "id-123",
      "id": "OP-4xghXMEcedrjPEo3KedqsR",
      "memo": "A memo",
      "processedAt": "2019-08-15T20:23:59.000Z",
      "recipientId": "R-4321c356vrcerc54js",
      "tags": [],
      "taxReportable": true,
      "updatedAt": "2019-10-31T20:24:29.954Z",
      "withholdingAmount": "24.00",
      "withholdingCurrency": "USD"
    }
  ]
}
HTTP Code Description
200 Recipient’s payments
401 Invalid API key
404 Recipient not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Errors Example

If recipient doesn’t exist, the API will respond with an error. For example:

Response (404 Not Found)

{
  "ok": false,
  "errors": [
    {
      "code": "not_found",
      "message": "Object not found"
    }
  ]
}

Recipient Account


Our philosophy is to give more choice of payout methods to users. What works for someone in San Francisco, London or Melbourne, might not be the best option for someone else in Jakarta, Nairobi or Mumbai. PayPal doesn’t support all countries, in fact, 97.5% of the worldwide population don’t have a PayPal account, and over 2 billion people don’t have a bank account. So clearly multiple payment options are needed to support a global business. That is why we plan to support every major payout method, so your users have choice of what works best for them.

Multiple Account Available

By POST-ing an account method for a recipient, you are adding a new payment method (such as their bank account, their PayPal account, mobile money account, prepaid card, etc) to the recipient.

A recipient can have multiple accounts with different payout methods assigned, however only one (1) account can be their selected (“primary”) account at any time.

Account Attributes

Below is a list of currently active (live) payout type, and those that are on our future roadmap.

Payout Method Type Status Description Method
bank-transfer live Bank Transfers to 210+ countries and territories (includes local bank transfers to 60+ countries, and bank wires to all other countries)
paypal live PayPal account
check live USD Checks printed and mailed to US based recipients
venmo live Venmo transfers (for USA only)
mobile-money coming soon Mobile Money
debit-card coming soon Debit and Credit Cards (VISA and MasterCard branded)

Sample Account Objects

// Bank Account
  {
    "recipientAccountId": "A-UnukXDTbLtxtDLXVZGE9re",
    "primary": true,
    "currency": "CAD",
    "country": "CA",
    "iban": "",
    "type": "bank-transfer",
    "accountNum": "*****2847",
    "accountHolderName": "John Smith",
    "bankId": "123",
    "branchId": "47261",
    "bankName": "TD bank",
    "bankAddress": "123 Nice Street",
    "bankCity": "Toronto",
    "bankRegionCode": "ON",
    "bankPostalCode": "M6A 0B1"
  }

// Check (US only)
  {
    "recipientAccountId": "A-UnukXDTbLtxtDLXVZGE9re",
    "primary": true,
    "currency": "USD",
    "country": "US",
    "type": "check",
    "mailing": {
        "name": "Leonardo Davinci",
        "street1": "123 Some Street",
        "street2": "",
        "city": "NYC",
        "region": "NY",
        "country": "US",
        "postal": "12345"
    }
  }

// Paypal
  {
    "recipientAccountId": "A-UnukXDTbLtxtDLXVZGE9re",
    "primary": true,
    "currency": "CAD",
    "type": "paypal",
    "emailAddress": "leonardo@example.com"
  }
  
// Venmo (US only)
  {
    "recipientAccountId": "A-UnukXDTbLtxtDLXVZGE9re",
    "primary": true,
    "currency": "USD",
    "type": "venmo",
    "phoneNumber": "+1 416 123 4567"
  }

Bank Account Fields

Fields Description
Id
string
An unique system generated Recipient identifier
type
string
Accepted types are: bank-transfer or paypal or check
currency
string
ISO3 currency code (e.g. USD)
primary
boolean
Set recipient account(payout method) as primary (active)
country
string
ISO ALPHA-2 country code (e.g. US)
accountHolderName
string
Exact name of account owner/holder on their bank account, e.g. John S Sample
accountNum
string
Recipient bank account number, (e.g. 123456789). Required for bank transfer payout method. Also use this field for Mexico CLABE account number (e.g. 032180000118359719), and Argentina CBU account number (e.g. 1234567890123456789098). IBAN does not go in this field, use the IBAN field instead. It is also masked so only the last two digits are shown.
bankId
string
Bank ID number. Required for bank transfer payout method in: Canada (Institution Code, 3 digits, e.g. 003).
branchId
string
Bank branch number. Required for bank transfer payout method in: US (Routing Number, 9 digits, e.g. 123456789), Australia (BSB, 6 digits, e.g. 123456), UK/GB (Sort Code, 6 digits, e.g. 123456), Canada (Transit Number, 5 digits, e.g. 12345), New Zealand (Bank/Branch Number, 6 digits, e.g. 030001), India (IFSC Code, 11 digits, e.g. 12345678910)
iban
string
IBAN international bank account number (common in Europe and about 30 other countries). Required for bank transfer payout method if the country uses IBAN bank account number format. (E.g. DE893704004405320130006). It is also masked so only the last two digits are shown.
swiftBic
string
SWIFT-BIC bank code, must be either 8 or 11 characters (e.g. BNBOBOLXPOI). Required for bank transfer payout method, depending on country. Required for most countries we send by Swift Wire as well as some other countries
bankName
string
The bank name, auto-populated by Trolley based on bank info provided
bankAddress
string
Recipient’s bank branch address (can include branch name, Address line 1 and Address line 2 in this field. E.g. 123 Wellington Road, Suite 100). Required if adding a bank transfer payout method for countries requiring SWIFT-BIC
bankCity
string
Recipient’s bank branch address City. (E.g. London). Required if adding a bank transfer payout method for countries requiring SWIFT-BIC
bankRegion
string
Recipient’s bank branch address region /state /province/ county. Free text field. (e.g. Kent). Optional if adding a bank transfer payout method for countries requiring SWIFT-BIC

PayPal fields

In addition to some relevant fields shared with bank-transfer type (refer to the sample), PayPal type expects an emailAddress:

Fields Description
emailAddress
string
A valid email address associated with recipient’s PayPal account (e.g. johnsample@email.com)

Venmo fields

In addition to some relevant fields shared with bank-transfer type (refer to the sample), Venmo type expects a phoneNumber field:

Fields Description
phone
string
For Venmo, the phone number associated with the Venmo account.

Mailing Field (for Checks)

Example Mailing attributes

{
    "name": "Leonardo Davinci",
    "street1": "123 Some Street",
    "street2": "",
    "city": "NYC",
    "region": "NY",
    "country": "US",
    "postal": "12345"
}
Field Description
name
required
string
Name of individual or business to be written on the check (Pay to the order of).
street1
required
string
Mailing Street 1 Address. PO Box addresses are acceptable.
street2
optional
string
Mailing Street 2 Address (e.g. Apt 5).
city
required
string
Mailing address City (e.g. Miami).
region
required
string
Region code Mailing address State / County. We accept both ISO 3166-2 code (e.g. FL), and full state/province name (e.g. Florida). ISO 3166-2 code is highly recommended.
country
required
string
Mailing Country. Must be US
postal
required
string
Mailing address Zip code (e.g. 90210 or 90210-1234).

Create Account

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X POST 'https://api.trolley.com/v1/recipients/R-4625iLug2GKqKZG2WzAf3e/accounts/' \
--data-raw '{
    "type": "bank-transfer",
    "primary": true, 
    "country": "CA", 
    "currency": "CAD",
    "accountNum": "604622847", 
    "bankId": "123", 
    "branchId": "47261",
    "accountHolderName": "John Smith"
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$recipient_id = 'R-PuzPJLVYQXBbPSMQKwmJ5G';

$account = Trolley\RecipientAccount::create($recipient_id, [
    "type" => "bank-transfer",
    "primary" => "true",
    "country" => "CA",
    "currency" => "CAD",
    "accountNum" => "012345678",
    "bankId" => "004",
    "branchId" => "47261",
    "accountHolderName" => "John Smith"
]);


// Example of code for `paypal` type account
$account = Trolley\RecipientAccount::create($recipient_id, [
    "type" => "paypal",
    "emailAddress": "jsmithpaypal@example.com",
]);

print_r($account);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.recipientAccount.create(
  recipient.id,
  {
    type: "bank-transfer",
    primary: "true",
    country: "CA",
    currency: "CAD",
    accountNum: "012345678",
    bankId: "004",
    branchId: "47261",
    accountHolderName: "John Smith"
  }
);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient_account.create(
  recipient.id, 
  {
    "type": "bank-transfer",
    "primary": "true",
    "country": "CA",
    "currency": "CAD",
    "accountNum": "012345678",
    "bankId": "004",
    "branchId": "47261",
    "accountHolderName": "John Smith"
  })

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

payload = {
  "type": "bank-transfer", 
  "primary": "true", 
  "country": "CA", 
  "currency": "CAD",
  "accountNum": "604622847", 
  "bankId": "123", 
  "branchId": "47261",  
  "accountHolderName": "John Smith"}

response = client.recipient_account.create(recipient_id, payload)

print(response.id)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();

//Create a new Recipient Account
RecipientAccount recipientAccountRequest = new RecipientAccount();
recipientAccountRequest.setType("bank-transfer");
recipientAccountRequest.setPrimary(true);
recipientAccountRequest.setCountry("DE");
recipientAccountRequest.setCurrency("EUR");
recipientAccountRequest.setIban("DE89 3704 0044 0532 0130 00");
recipientAccountRequest.setAccountHolderName("Tom Jones");

RecipientAccount recipientAccount = client.recipientAccount.create(recipientId, recipientAccountRequest);

System.out.println(recipientAccount.getId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
RecipientAccount accountRequest = new RecipientAccount("bank-transfer", "CAD", null, true, "CA");
accountRequest.accountNum = "1234567";
accountRequest.bankId = "003";
accountRequest.branchId = "47261";
RecipientAccount account = gateway.recipientAccount.create(recipientId, accountRequest);

Console.WriteLine(account.id);

...

Example response (200 Ok)

{
  "ok": true
  "account": {
       "recipientAccountId": "A-UnukXDTbLtxtDLXVZGE9re",
       "primary": true,
       "currency": "CAD",
       "country": "CA",
       "type": "bank-transfer",
       "accountNum": "*****2847",
       "accountHolderName": "John Smith",
       "bankId": "123",
       "branchId": "47261",
       "bankName": "TD bank"
   }
}


// response for `paypal` account
{
  "ok": true,
  "account": {
    "type": "paypal",
    "emailAddress": "jsmithpaypal@example.com",
    "recipientAccountId": "A-7ccjKkGNyQRXRnEAfqTd7d",
    "primary": true,
    "currency": "CAD"
  }
}

To add a Recipient Account (ie payout method) such as a bank account or a PayPal account, to a Recipient, POST the following HTTP Request relevant to the Recipient’s payout method type.

A recipient can have multiple accounts with different payout methods assigned, however, only one (1) payout method can be their selected “primary” (active) account at any time. If you add the Recipient Account (payout method) when creating the Recipient, you do not need to add it again. The first account that is added to a recipient will be considered primary.

HTTP Request

POST https://api.trolley.com/v1/recipients/:id/accounts

Trolley currently supports two types of payout methods: paypal (PayPal) and bank-transfer (Bank Transfers).

Based on the payout method type (ie: paypal or bank-transfer), apply the appropriate fields below.

Bank Transfer

Fields Description
id
required
string
Recipient ID
type
required
string
Payout method, bank-transfer
currency
required
string
ISO3 currency code (ie: ‘USD’)
primary
optional
boolean
Set recipient account(payout method) as primary (active)
country
required
string
ISO ALPHA-2 country codes (ie: ‘US’)
accountHolderName
required
string
Exact name of account owner/holder on their bank account.
accountNum
required
string
Bank account number, includes Mexico CLABE, Argentina CBU. Does not include IBAN.
bankId
conditional
string
Bank ID, only required in Canada (Institution Code).
branchId
conditional
string
Bank’s branch number, only required in US (Routing Number), Australia (BSB), UK (Sort Code), Canada (Transit Number), India (IFSC Code)
iban
conditional
string
IBAN international bank account number, required for IBAN countries
swiftBic
conditional
string
SWIFT-BIC bank code, required for SWIFT countries (8 or 11 characters)


PayPal

Fields Description
id
required
string
Recipient ID
type
required
string
Payout method, paypal
primary
optional
boolean
Set recipient account(payout method) as primary (active)
emailAddress
required
string
Recipients PayPal account email address


HTTP Code Description
200 Payment successfully updated
401 Invalid API key
404 Object not found
406 One or more fields failed validation, see errors[] in response body
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
empty_field A field is required
invalid_field A field failed a validation check
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Delete Account

Delete a recipient’s payout method

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X DELETE 'https://api.trolley.com/v1/recipients/R-PuzPJLVYQXBbPSMQKwmJ5G/accounts/A-KKHb8MpFvju6vDMBLPmtej' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$recipient_id = 'R-PuzPJLVYQXBbPSMQKwmJ5G';
$account_id = 'A-KKHb8MpFvju6vDMBLPmtej';

$response = Trolley\RecipientAccount::delete($recipient_id, $account_id);

print_r($response);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.recipientAccount.remove(
  recipient.id, 
  account.id
);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient_account.delete(
      recipient.id, recipient_account.id
    )

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.recipient_account.delete(recipient.id, account.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();
String accountId = getRecipientId();

//Delete an account
boolean response = client.recipientAccount.delete(recipientId, accountId);

System.out.println(response);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
string recipientAccountId = GetRecipientAccountId();

bool deleteResponse = gateway.recipientAccount.delete(recipientId, recipientAccountId);

Console.WriteLine(deleteResponse);

...

Example response (200 Ok)

{
  "ok": true,
  "object": "deleted"
}

HTTP Request

DELETE https://api.trolley.com/v1/recipients/:id/accounts/:recipientAccountId

Fields Description
id
required
string
recipientId
recipientAccountId
required
string
recipientAccountId
HTTP Code Description
200 Payment successfully updated
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Retrieve Account

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/recipients/R-PuzPJLVYQXBbPSMQKwmJ5G/accounts/A-KKHb8MpFvju6vDMBLPmtej' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$recipient_id = 'R-PuzPJLVYQXBbPSMQKwmJ5G';
$account_id = 'A-KKHb8MpFvju6vDMBLPmtej';

$response = Trolley\RecipientAccount::find($recipient_id, $account_id);

print_r($response);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.recipientAccount.find(
  recipient.id, 
  account.id
);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

# Get one account
response = client.recipient_account.find(
      recipient.id, recipient_account.id
    )

print response

# Get all accounts of a recipient
response = client.recipient_account.all(recipient.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.recipient_account.find(recipient.id, account.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();
String accountId = getAccountId();

//Fetch a recipient account
RecipientAccount account = client.recipientAccount.find(recipientId, accountId);

System.out.println(account.getId());

// Or Fetch all accounts of a recipient
List<RecipientAccount> recipientAccounts = client.recipientAccount.findAll(recipientId);

for (RecipientAccount account : recipientAccounts) {
  System.out.println(account.getId());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
string recipientAccountId = GetRecipientAccountId();

// Find one account of the Recipient
RecipientAccount account = gateway.recipientAccount.find(recipientId, recipientAccountId);

Console.WriteLine(account.accountHolderName);

// Or, get all accounts of a Recipient
List<RecipientAccount> recipientAccounts = gateway.recipientAccount.findAll(recipientId);
foreach (RecipientAccount account in recipientAccounts){
      Console.WriteLine(account.bankName);
  }
...

Example response (200 Ok)

{
  "ok": true,
  "account": {
    "type": "paypal",
    "emailAddress": "rain123@gmail.com",
    "recipientAccountId": "A-7ccjKkGNyQRXRnEAfqTd7d",
    "primary": false,
    "currency": "CAD"
  }
}

Retrieve a recipient’s payout method

HTTP Request

GET https://api.trolley.com/v1/recipients/:id/accounts/:recipientAccountId

Fields Description
id
required
string
recipientId
recipientAccountId
required
string
recipientAccountId
HTTP Code Description
200 Payment successfully updated
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Update Account

Update Recipient Account

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X PATCH 'https://api.trolley.com/v1/recipients/R-PuzPJLVYQXBbPSMQKwmJ5G/accounts/A-KKHb8MpFvju6vDMBLPmtej' \
--data-raw '{
    "primary": true
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$recipient_id = 'R-PuzPJLVYQXBbPSMQKwmJ5G';
$account_id = 'A-KKHb8MpFvju6vDMBLPmtej';

$response = Trolley\RecipientAccount::update($recipient_id, $account_id, [
    "primary" => false,
]);

print_r($response);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.recipientAccount.update(
  recipient.id, 
  account.id, 
  {
      primary: "false"
  }
);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.recipient_account.update(
      recipient.id, 
      recipient_account.id,
      {
        "primary": "true"
      }
    )

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.recipient_account.update(recipient.id, account.id, {"primary": True})

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

//Update a recipient account
RecipientAccount updateAccountRequest = new RecipientAccount();
updateAccountRequest.setIban("DE89 3704 0044 0532 0130 00");
updateAccountRequest.setAccountHolderName("Tom Smith");

RecipientAccount updatedAccount = client.recipientAccount.update(recipientId, accountId, updateAccountRequest);

System.out.println(updatedAccount.getId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
string recipientAccountId = GetRecipientAccountId();

RecipientAccount accountRequest = new RecipientAccount("bank-transfer", "CAD", null, true, "CA");
accountRequest.id = recipientAccountId;
accountRequest.branchId = "47261";

RecipientAccount account = gateway.recipientAccount.update(recipientId, accountRequest);

Console.WriteLine(account.branchId);

...

Example responses (200 Ok)

Bank Account

// Bank Account
{
  "ok": true,
  "account": {
    "recipientAccountId": "A-UnukXDTbLtxtDLXVZGE9re",
    "primary": true,
    "currency": "CAD",
    "country": "CA",
    "iban": "",
    "type": "bank-transfer",
    "accountNum": "*****2847",
    "accountHolderName": "John Smith",
    "bankId": "123",
    "branchId": "47261",
    "bankName": "TD bank",
    "bankAddress": "123 Nice Street",
    "bankCity": "Toronto",
    "bankRegionCode": "ON",
    "bankPostalCode": "M6A 0B1"
  }
}

// Check (US only)
{
  "ok": true,
  "account": {
    "recipientAccountId": "A-UnukXDTbLtxtDLXVZGE9re",
    "primary": true,
    "currency": "USD",
    "country": "US",
    "type": "check",
    "mailing": {
        "name": "Leonardo Davinci",
        "street1": "123 Some Street",
        "street2": "",
        "city": "NYC",
        "region": "NY",
        "country": "US",
        "postal": "12345"
    }
  }
}

// Paypal  
{
  "ok": true,
  "account": {
    "recipientAccountId": "A-UnukXDTbLtxtDLXVZGE9re",
    "primary": true,
    "currency": "CAD",
    "type": "paypal",
    "emailAddress": "leonardo@example.com"
  }
}

// Venmo (US only)
{
  "ok": true,
  "account": {
    "recipientAccountId": "A-UnukXDTbLtxtDLXVZGE9re",
    "primary": true,
    "currency": "USD",
    "type": "venmo",
    "phoneNumber": "+1 416 123 4567"
  }
}

Update a payout method for a recipient. You can update existing primary method. When an account is updated, a new account id is generated.

HTTP Request

PATCH https://api.trolley.com/v1/recipients/:id/accounts/:recipientAccountId

Fields Description
id
required
string
recipientId
recipientAccountId
required
string
recipientAccountId
HTTP Code Description
200 Payment successfully updated
401 Invalid API key
404 Object not found
406 One or more fields failed validation, see errors[] in response body
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
empty_field A field is required
invalid_field A field failed a validation check
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Payments


The payment object describes a payment. Payments are sent to a recipient via the recipient’s chosen payout method, such as: bank account, PayPal, mobile money, or credit/debit card. If no payment method is setup, the payment will not be processed.

A Batch is a group of Payments. Payments are added to a batch prior to being processed. If your business does regularly scheduled payouts, such as once per day, once per week, every 2 weeks, or even monthly, then using batches will be great for you.

A batch can be made up of just 1 payment, or 100 payments, or hundreds of thousands of payments (there are no upper limits).

Batches also allow you to manually review and approve your payments before processing, if you prefer. This is handy if you conduct some additional fraud reviews on your payouts before processing, or if your company CFO or a senior manager is responsible for approving payouts before they go out.

There are 4 main steps for handling a batch:

Step 1: Create a batch

Firstly, when you Create a batch, the system will automatically open a new batch and assign a unique batchId which is generated by our system. The format of all Batch IDs are “B-1a2B3c4D5e6F7g8H9i0J1k”, with the ‘B-’ prefix indicating Batch, followed by 22 alphanumeric digits.

When you create a batch, you will also send us the details for your payments. This includes at a minimum the recipientId, amount and currency for all the payments for that batch.

Note: You can also use our online Dashboard portal to manually create a batch of payments by uploading a file of payments in .csv file format, or manually adding payments into a batch.

Payment Minimums

While adding payments to a batch, keep in mind there are limits to the minimum amount within a payment you can send through a bank transfer.
If you add payment amounts to a batch which are below the minimum amount allowed, the batch will not be processed. To avoid this, you should query /recipients/:recipientId API to find out the payment minimum for a recipient, before adding the payments to the batch.

For more information on how to work with Payment Minimums, and a suggested flow of this operation, have a look at this article: How to get ready for using Bank Transfer Minimums

Step 2: Generate Quote of FX rates

After creating the batch, you will need to send a POST request to the /batches/:id/generate-quote API to get the live exchange rates for payments that involve a currency conversion.

The system will update the exchange rate for all payments with bank-transfer type payout method. (Note that PayPal payments will not be updated, as PayPal handles the FX rates). You can generate a quote multiple times to get the latest live exchange rates, up until the batch has started processing.

Step 3: Check account balance

When the batch is created, the system will automatically check the balance of your account to see if it is sufficient to cover the costs of the payouts plus any transaction fees. If your account balance is not sufficient, the batch will remain pending (open) until your account is funded. You can see your account balance in the Dashboard under the ‘Transfers’ tab, which is updated in real time. You can also get your account balance by sending a GET request to the /balance endpoint.

Step 4: Process the batch

Once the batch is created, and there is sufficient funds in your account balance to cover the batch, then the batch can be processed. You will need to send a POST request to the /batches/:id/start-processing API to commence processing of the batch of payments.

Step 5: Summary of the batch

You can retrieve a summary of the batch, including the status and details of all the payments in the batch, by sending a GET request to the /batch/:id/summary endpoint.

If you wish to get the details of a specific payment within the batch, you can send a GET request to the /payments/:id endpoint.

Create a batch

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X POST 'https://api.trolley.com/v1/batches' \
--data-raw '{
    "currency": "USD",
    "description": "Month end payout",
    "payments": [
        {
            "recipient": {
                "id": "R-1a2B3c4D5e6F7g8H9i0J1k"
            },
            "amount": "150",
            "currency": "USD"
        }
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$batch = Trolley\Batch::create(
        [   // Batch description
            "sourceCurrency" => "USD",
            "description" => "PHP SDK Batch Creation"
        ],
        [   // Payments (optional)
            [
                "targetAmount" => "10.00",
                "targetCurrency" => "EUR",
                "recipient" => [ "id" => $recipient->id ]
            ]
        ]);

print_r($batch);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.batch.create(
{
  payments: [
    {
      recipient: {
        id: recipient.id
      },
      amount: "65",
      currency: "CAD"
    }
  ]
});

console.log(response.batch.id);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.batch.create({
  description: "New batch with Ruby SDK",
  currency: "USD",
  payments: [
    { 
      recipient: { 
        id: recipient1.id 
      }, 
      amount: "100", 
      currency: "USD" 
    },
    { 
      recipient: { 
        id: recipient2.reference_id 
      }, 
      amount: "200", 
      currency: "USD", 
    }
  ]
})

print response
from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

payload = {
  "payments": [
      {
          "recipient": {
              "id": recipient.id
          }, 
          "sourceAmount": "65",
          "sourceCurrency": "EUR"
          }
      ]
  }

response = client.batch.create(payload)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

Recipient recipient = getRecipient();

// Create an empty batch
Batch batchRequest = new Batch();
batchRequest.setCurrency("GBP");
batchRequest.setDescription("Batch created from Java SDK");
Batch batch = client.batch.create(batchRequest);

System.out.println(batch.getId());

...

// Or, create a batch with payments
Payment payment = new Payment();
payment.setAmount("15");
payment.setCurrency("GBP");
payment.setRecipient(recipient);

List<Payment> paymentList = new ArrayList<Payment>();
paymentList.add(payment);

Batch batchRequest = new Batch();
batchRequest.setPayments(paymentList);

Batch batch = client.batch.create(batchRequest);

System.out.println(batch.getId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

// Creating a Batch without payments
Batch batchRequest = new Batch("Batch from .Net SDK", null, "USD", 0);

// Creating a Batch with payments
List<Payment> payments = GetPayments();
Batch batchRequest = new Batch("Batch from .Net SDK", payments, "USD", 0);

Batch batch = gateway.batch.Create(batchRequest);

Console.WriteLine(batch.id);

...

Example response (200 Ok)

{
  "ok": true,
  "batch": {
    "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
    "status": "open",
    "tags": [],
    "amount": "8.75",
    "totalPayments": 2,
    "currency": "CAD",
    "description": "Weekly Payouts on 2017-2-27",
    "sentAt": null,
    "completedAt": null,
    "createdAt": "2017-03-27T20:19:47.378Z",
    "updatedAt": "2017-03-27T20:19:47.518Z",
    "quoteExpiredAt": "2017-03-28T04:08:52.634Z"
  }
}

To create a Batch send a POST request to the /batches endpoint and include the payments details in the request body. The Batch and each Payment within the batch will be assigned and represented by an auto-generated ID (batchId and paymentId) which can be used to retrieve or update payment or batch details at a later time.

HTTP Request

POST https://api.trolley.com/v1/batches

Fields Description
currency
optional
string
ISO3 currency code (ie: ‘USD’). The currency will default to your merchant accounts default currency. Or the sourceCurrency of the first payment.
description
optional
string
A description of the batch that you would like to add for internal reference
payments
optional
array
Array of payments
payments[].recipient
required
object
Specific Recipient within the Payment. One of id, email or referenceId must be provided
payments[].recipient.id
conditional
string
Recipient ID, only required if no other recipient identifier is provided
payments[].recipient.email
conditional
string
Valid Email associated with the Recipient, only required if no other recipient identifier is provided
payments[].amount
required
string
The amount in the specified currency
payments[].currency
required
string
The amount’s ISO3 currency code (ie: ‘USD’)
payments[].memo optional
_string_
Description of payment
HTTP Code Description
200 Batch successfully updated
400 One or more fields failed validation, see errors[] in response body
401 Invalid API key
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
empty_field A field is required
invalid_field A field failed a validation check
invalid_status Invalid Status
invalid_api_key Invalid API key
internal_server_error Internal server errors

More details about what kind of errors you can encounter while creating or processing a payment can be found in the reference document for Payment and Batch Errors.

Retrieve a batch

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/batches/B-1a2B3c4D5e6F7g8H9i0J1k/' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\Batch::find($batch->id);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.batch.find(batch.id);

console.log(response.batch.id);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

batch = client.batch.find(batch.id)

print batch

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.batch.find(batch.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();

// Get a batch with ID
Batch batch = client.batch.find(batchId);

System.out.println(batch.getId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string batchId = GetBatchId();

Batch batch = gateway.batch.Get(batchId);

Console.WriteLine(batch.id);

...

Example response (200 Ok)

{
  "ok": true,
  "batch": {
    "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
    "status": "open",
    "tags": [],
    "amount": "98.75",
    "totalPayments": 2,
    "currency": "CAD",
    "description": "Weekly Payouts on 2017-2-23",
    "sentAt": null,
    "completedAt": null,
    "createdAt": "2017-03-23T15:21:51.171Z",
    "updatedAt": "2017-03-23T15:21:51.254Z",
    "quoteExpiredAt": "2017-03-29T04:08:52.634Z",
    "payments": {
      "payments": [
        {
          "id": "P-1a2B3c4D5e6F7g8H9i0J1k",
          "recipient": {
            "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
            "referenceId": "jsmith11@example.com",
            "email": "jsmith11@example.com",
            "name": "John Smith",
            "status": "active",
            "country": "Canada"
          },
          "method": "bank",
          "methodDisplay": "Bank Transfer",
          "status": "pending",
          "sourceAmount": "0.00",
          "targetAmount": "100.00",
          "isSupplyPayment": true,
          "memo": "memo",
          "fees": "1.25",
          "recipientFees": "0.00",
          "exchangeRate": "1.0000",
          "processedAt": null,
          "merchantFees": "1.25",
          "sourceCurrency": "CAD",
          "sourceCurrencyName": "Canadian Dollar",
          "targetCurrency": "CAD",
          "targetCurrencyName": "Canadian Dollar",
          "compliance": {
            "status": "pending",
            "checkedAt": null
          }
        },
        {
          "id": "P-1a2B3c4D5e6F7g8H9i0J1k",
          "recipient": {
            "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
            "referenceId": "jsmith11@example.com",
            "email": "jsmith11@example.com",
            "name": "Richard Hendricks",
            "status": "active",
            "country": "Canada"
          },
          "method": "bank",
          "methodDisplay": "Bank Transfer",
          "status": "pending",
          "sourceAmount": "100.00",
          "targetAmount": "0.00",
          "isSupplyPayment": false,
          "memo": "memo",
          "fees": "1.25",
          "recipientFees": "1.25",
          "exchangeRate": "1.0000",
          "processedAt": null,
          "merchantFees": "0.00",
          "sourceCurrency": "CAD",
          "sourceCurrencyName": "Canadian Dollar",
          "targetCurrency": "CAD",
          "targetCurrencyName": "Canadian Dollar",
          "compliance": {
            "status": "pending",
            "checkedAt": null
          }
        }
      ],
      "meta": {
        "page": 1,
        "pages": 1,
        "records": 2
      }
    }
  }
}

You can retrieve details of a Batch of payments by sending a GET request to the /batches/:id endpoint.

HTTP Request

GET https://api.trolley.com/v1/batches/:id

Fields Description
id
required
string
Batch ID
HTTP Code Description
200 Batch object
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Delete a batch

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X DELETE 'https://api.trolley.com/v1/batches/B-1a2b3c4d5e6f7g8h9i0jk1/' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\Batch::delete($batch->id);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.batch.remove(batch.id);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.batch.delete(batch.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.batch.delete(batch.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();

// Delete one batch
boolean batchDelResult = client.batch.delete(batchId);

System.out.println(batchDelResult);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string batchId = GetBatchId();

bool batchDelResult = gateway.batch.Delete(batchId);

Console.WriteLine(batchDelResult);

...

Expected Response (204 No Content)

You can delete an existing batch by sending a DELETE request to the /batches/:id endpoint.

Note that you can only delete a batch that is in a pending status and has not yet been processed. Once a batch is processed, you are unable to delete the batch. If you processed a batch in error and wish to stop it, please contact support immediately and we will assist as best we can.

HTTP Request

DELETE https://api.trolley.com/v1/batches/:id

{
  "ok": true
}
Fields Description
id
required
string
Batch ID
HTTP Code Description
200 Batch successfully deleted
400 Invalid status
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_status Invalid Status
invalid_api_key Invalid API key
internal_server_error Internal server errors

Delete multiple batches

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X DELETE 'https://api.trolley.com/v1/batches/' \
--data-raw '{
    "ids": [
      "B-1a2b3c4d5e6f7g8h9i0jk1",
      "B-3c4d5e6f7g8h9i0jk11a2b"
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\Batch::deleteMultiple(
    [
      $batchOne->id, 
      $batchTwo->id
    ]);

print_r($response);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.batch.remove(
  [
    batch1.id,
    batch2.id
  ]);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.batch.delete(
  [
    batch1.id, 
    batch2.id
  ])

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.batch.delete_multiple({
      "ids":[
          batch1.id,
          batch2.id
  ]})

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

// Or, Delete multiple batches
List<Batch> batches = getBatchesToDelete();

boolean batchDelResult = client.batch.delete(batches);

System.out.println(batchDelResult);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string batchId1 = GetFirstBatchId();
string batchId2 = GetSecondBatchId();

bool batchDelResult = gateway.batch.Delete(batchId1, batchId2);

Console.WriteLine(batchDelResult);

...

Expected Response (204 No Content)

You can delete multiple batches by sending a DELETE request to the /batches endpoint with a list of batch ids in the request body.

Note that you can only delete batches those are in pending status and has not yet been processed. Once a batch is processed, you are unable to delete the batch. If you processed a batch in error and wish to stop it, please contact support immediately and we will assist as best we can.

HTTP Request

DELETE https://api.trolley.com/v1/batches

{
  "ok": true
}
Fields Description
ids
required
array
Batch IDs
HTTP Code Description
200 Batch successfully deleted
400 Invalid status
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_status Invalid Status
invalid_api_key Invalid API key
internal_server_error Internal server errors

List all batches

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/batches?page=1&pageSize=10' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

// List all batches
$allBatches = Trolley\Batch::all();
foreach ($allBatches as $batch) {
  print_r($batch);
}

// Search in batches
$searchResults = Trolley\Batch::search([
        "search"    => "Tom",
        "page"      => 1,
        "pageSize"  => 5
    ]);
foreach ($searchResults as $batch){
    print_r($batch);
}

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.batch.search(1, 10, "John");

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.batch.all

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

batches = client.batch.list_all_batches()

# iterate through the batches generator
for batch in batches:
   print(batch)

# OR, get batches page by page. Optionally provide a search term
batches = client.batch.search_by_page("",2, 20)

for batch in batches:
   print(batch)

# You could also search without specifying pagination and use the returned generator
batches = client.batch.search("<search term>")

for batch in batches:
   print(batch)

...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();
int page = 1;
int pageSize = 10;

// Get all batches with an optional search term and manual pagination
Batches allBatches = client.batch.search(page, pageSize, "<search_term>");
List<Batch> batches = allBatches.getBatches();

for (Batch batch : batches){
  System.out.println(batch.getId());
}

...

// Or, with auto-pagination
BatchesIterator batches = client.batch.search("<search_term>");

while(batches.hasNext()){
    System.out.println(batches.next().getId());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
int page = 1;
int pageSize = 10;

// List all batches with manual pagination, with optional search term
Batches allBatches = gateway.batch.ListAllBatches("<search_term>", page, pageSize);

// Get a List of Batch objects to iterate through
List<Batch> batches = allBatches.batches;

// And get a Meta object to access page information
Meta meta = allBatches.meta;

// Or, list all batches with auto-pagination, with optional search term
var batches = gateway.batch.ListAllBatches("<search_term>");

foreach (Batch batch in batches)
{
    Console.WriteLine(batch.id);
}

...

Expected response (200 Ok)

{
  "ok": true,
  "batches": [
    {
      "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
      "status": "accepted",
      "tags": [],
      "amount": "109.75",
      "totalPayments": 1,
      "currency": "CAD",
      "description": "Weekly Payouts on 2017-0-11",
      "sentAt": null,
      "completedAt": null,
      "createdAt": "2017-01-11T23:30:52.974Z",
      "updatedAt": "2017-01-11T23:31:38.954Z",
      "quoteExpiredAt": "2017-01-12T04:08:52.634Z"
    },
    {
      "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
      "status": "complete",
      "tags": [],
      "amount": "109.75",
      "totalPayments": 1,
      "currency": "CAD",
      "description": "Weekly Payouts on 2017-0-11",
      "sentAt": "2017-01-11T23:18:48.091Z",
      "completedAt": "2017-01-11T23:18:49.222Z",
      "createdAt": "2017-01-11T23:18:37.976Z",
      "updatedAt": "2017-01-11T23:18:49.222Z",
      "quoteExpiredAt": "2017-01-12T04:08:52.634Z"
    }
  ]
}

You can retrieve all batches by sending a GET request to the /batches endpoint.

HTTP Request

GET https://api.trolley.com/v1/batches?page=1&pageSize=10

Query Param Description
page
required
int
The page number (default: 1)
pageSize
required
int
Number of records in a page (default: 10)
search
optional
string
Wildcard search across batches
HTTP Code Description
200 List of batches
401 Invalid API key
500 Internal error
Error Code Description
invalid_api_key Invalid API key
internal_server_error Internal server errors

Create a payment

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X POST 'https://api.trolley.com/v1/batches/B-1a2B3c4D5e6F7g8H9i0J1k/payments/' \
--data-raw '{
    "recipient" : {
        "id":"R-1a2B3c4D5e6F7g8H9i0J1k"
    },
    "amount": "150",
    "currency": "USD"
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$payment = Trolley\Batch::createPayment($batch->id, [
            "sourceAmount" => "10.00",
            "recipient" => [ "id" => $recipient->id ]
        ]);

print_r($payment);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.payment.create(
  batch.id,
  {
  recipient: {
    id: recipient.id
  },
  sourceAmount: "100.10",
  sourceCurrency: "CAD",
  memo: "Freelance payment"
});

console.log(response.batch.id);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.payment.create(
  batch.id, 
  {
    sourceAmount: '10.00', 
    recipient: { 
      id: recipient.id 
    }
  })

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

payload = {
    "recipient":{
        "id": recipient_id
    },
    "sourceAmount":"100.10",
    "memo":"Freelance payment"
}

response = client.payment.create(payload, batch.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

Recipient recipient = getRecipientObject();
String batchId = getBatchId();

// Create a new payment inside a batch
Payment paymentRequest = new Payment();
paymentRequest.setSourceAmount("10.00");
paymentRequest.setRecipient(recipient);

Payment payment = client.payment.create(paymentRequest, batchId);

System.out.println(payment.getId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

Recipient recipient = GetRecipient();
string batchId = GetBatchId();

Payment payment = new Payment(recipient, 1.20, "USD");
payment.batchId = batchId;
payment = gateway.payment.Create(payment);

Console.WriteLine(payment.id);

...

To create a payment under a batch send a POST request to the /batches/:id/payments endpoint and include the payments details in the request body. A payment will be created and added to the batch. An auto-generated ID (paymentId) will be generated which can be used to retrieve or update payment or batch details at a later time.

Example response (200 Ok)

{
  "ok": true,
  "payment": {
    "id": "	P-1a2B3c4D5e6F7g8H9i0J1k",
    "recipient": {
      "id": "R-1a3B3c4D5e6F7g8H9i0J1k",
      "referenceId": "jsmith11@example.com",
      "email": "jsmith11@example.com",
      "name": "John Smith",
      "lastName": "John",
      "firstName": "Smith",
      "type": "individual",
      "status": "active",
      "language": "en",
      "complianceStatus": "verified",
      "dob": null,
      "updatedAt": "2017-03-20T19:06:40.937Z",
      "createdAt": "2017-03-17T20:10:45.818Z",
      "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
      "placeOfBirth": null,
      "ssn": null,
      "tags": [],
      "passport": "",
      "payoutMethod": "bank-transfer",
      "compliance": {
        "status": "verified",
        "checkedAt": "2017-03-20T19:06:23.916Z"
      },
      "accounts": [
        {
          "accountHolderName": "John Smith",
          "bankId": "123",
          "currency": "CAD",
          "country": "CA",
          "bankName": "TD CANADA TRUST",
          "branchId": "47261",
          "accountNum": "*****47"
        }
      ],
      "address": {
        "street1": "Apt# 14",
        "street2": null,
        "city": "",
        "postalCode": "H3WXXX",
        "phone": "",
        "country": "CA",
        "region": "QC"
      },
      "primaryCurrency": "CAD"
    },
    "status": "pending",
    "sourceAmount": "100.10",
    "exchangeRate": "1.0000",
    "fees": "1.25",
    "recipientFees": "1.25",
    "targetAmount": "0.00",
    "fxRate": "2.000000",
    "memo": "momo",
    "processedAt": null,
    "createdAt": "2017-03-27T20:51:39.567Z",
    "updatedAt": "2017-03-27T20:51:39.567Z",
    "merchantFees": "0.00",
    "compliance": {
      "status": "pending",
      "checkedAt": null
    },
    "batch": {
      "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
      "createdAt": "2017-03-21T20:56:43.690Z",
      "updatedAt": "2017-03-28T04:09:02.966Z",
      "sentAt": "2017-03-28T04:08:52.634Z",
      "completedAt": "2017-03-28T04:08:54.353Z"
    },
    "sourceCurrency": "CAD",
    "sourceCurrencyName": "Canadian Dollar",
    "targetCurrency": "CAD",
    "targetCurrencyName": "Canadian Dollar",
    "category": "services",
    "coverFees": false,
    "currency": "CAD",
    "equivalentWithholdingAmount": "0.00",
    "equivalentWithholdingCurrency": "CAD",
    "estimatedDeliveryAt": null,
    "externalId": "",
    "failureMessage": null,
    "initiatedAt": null,
    "isSupplyPayment": false,
    "merchantId": "M-Osg3dh2b0m1cRg9b8Shd2d",
    "methodDisplay": "Bank Transfer",
    "returnedAmount": "0.00",
    "returnedAt": null,
    "returnedNote": null,
    "returnedReason": [],
    "settledAt": null,
    "tags": [],
    "taxBasisAmount": "0.00",
    "taxBasisCurrency": "CAD",
    "taxReportable": true,
    "withholdingAmount": "0.00",
    "withholdingCurrency": "CAD"
  }
}

HTTP Request

POST https://api.trolley.com/v1/batches/:id/payments

Fields Description
recipient
required
object
Information about the recipient of the payment. One identifier must be provided.
recipient.id
conditional
string
Recipient ID assigned by Trolley, e.g. R-12Ga2s31aH2233sa993HgsGs. Used to identify the correct recipient to pay. You must provide at least one of: Email, Reference ID, or Recipient ID.
recipient.email
conditional
string
Recipient’s email address (e.g. john@email.com). Used to identify the correct recipient to pay. You must provide at least one of: Email, Reference ID, or Recipient ID.
recipient.referenceId
conditional
string
Recipient reference ID as assigned by your business (your internal user reference number, e.g. ‘U1234556678’). Used to identify the correct recipient to pay. You must provide at least one of: Email, Reference ID, or Recipient ID).
amount
conditional
string
Amount you wish to send, e.g. 100.00 USD, in your own currency.
currency
conditional
string
Currency of the amount you wish to send, e.g. 100.00 USD.
coverFees
optional
boolean
If the merchant should cover the network fees for this payment (default: false).
sourceAmount
conditional
string
deprecated
Amount you wish to send, e.g. 100.00 USD, in your own currency. Required only if sending a “sourceAmount”.
sourceCurrency
conditional
string
deprecated
Currency of the amount you wish to send, e.g. 100.00 USD. Required only if sending a “sourceAmount”.
targetAmount
conditional
string
deprecated
Amount you wish the recipient to receive, e.g. 85.00 EUR, in the recipient’s currency. Required only if sending a “Receive Amount”.
targetCurrency
conditional
string
deprecated
Currency of the amount you wish the recipient to receive, e.g. 85.00 EUR, in the recipient’s currency. Required only if sending a “Receive Amount”.
memo
optional
string
A short note which will be sent along with the payment to the recipient’s bank, as well as on the payment confirmation email if enabled. This memo will be displayed on the recipient’s bank statement descriptor to help them identify who the payment is from. The number of display characters depends on the recipient’s bank, so its best to keep short to less than 30 characters, otherwise the end may get cut off. Special characters are not supported on bank statement so will be stripped out by the bank. The memo field is good for referring to an invoice or reference number. We also strongly suggest to include your (short) business name at the start, as some banks globally don’t support displaying your business as the sender name. A good sample memo for an invoice payment from Airbnb would be: “AIRBNB INV 12345678”.
externalId
optional
string/null
Storage for your internal reference ID for this payment, if present it must be unique.
taxReportable
optional
boolean
If the merchant should apply tax withholding on the payment, and in turn adding it to the tax reporting (default: true).
forceUsTaxActivity
optional
boolean
Set this to true ONLY when the tax reporting system is enabled AND the payment is taxReportable AND you intend to override the recipient’s W8’s “certify no us activities” to assert that the payment definitely DOES involve US activities. (default: false).
category
conditional
string
Income type if the payment is Tax Reportable, either services, royalties, rent, royalties_film or prizes, otherwise education and refunds are supported for non Tax Reportable payments.
HTTP Code Description
200 Batch successfully deleted
401 Invalid API key
404 Object not found
406 Validation error
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Retrieve a payment

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/batches/B-1a2B3c4D5e6F7g8H9i0J1k/payments/P-1a2B3c4D5e6F7g8H9i0J1k' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\Batch::findPayment($batch->id, $payment->id);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.payment.find(payment.id);

console.log(response.payment.id);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.payment.find(batch.id, payment.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.payment.find(payment.id,batch.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();
String paymentId = getPaymentId();

// Generate Quote of payments in the batch
Payment payment = client.payment.find(paymentId, batchId);

System.out.println(payment.getId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string paymentId = GetPaymentId();

Payment payment = gateway.payment.Get(paymentId);

Console.WriteLine(payment.amount);

...

Expected response (200 Ok)

{
  "ok": true,
  "payment": {
    "id": "P-1a2B3c4D5e6F7g8H9i0J1k",
    "recipient": {
      "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
      "referenceId": "jsmith11@example.com",
      "email": "jsmith11@example.com",
      "name": "Richard Hendricks",
      "lastName": "Hendricks",
      "firstName": "Richard",
      "type": "individual",
      "status": "active",
      "language": "en",
      "complianceStatus": "verified",
      "dob": null,
      "updatedAt": "2017-03-20T19:06:40.937Z",
      "createdAt": "2017-03-17T20:10:45.818Z",
      "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
      "placeOfBirth": null,
      "ssn": null,
      "tags": [],
      "passport": "",
      "payoutMethod": "bank-transfer",
      "compliance": {
        "status": "verified",
        "checkedAt": "2017-03-20T19:06:23.916Z"
      },
      "routeType": "ach",
      "routeMinimum": "1", 
      "estimatedFees": "1.25",
      "accounts": [
        {
          "accountHolderName": "Richard Hendricks",
          "bankId": "123",
          "currency": "CAD",
          "country": "CA",
          "bankName": "TD CANADA TRUST",
          "branchId": "47261",
          "accountNum": "*****47"
        }
      ],
      "address": {
        "street1": "Apt# 14",
        "street2": null,
        "city": "",
        "postalCode": "H3WXXX",
        "phone": "",
        "country": "CA",
        "region": "QC"
      },
      "primaryCurrency": "CAD"
    },
    "status": "processed",
    "sourceAmount": "100.10",
    "exchangeRate": "1.0000",
    "fees": "1.25",
    "recipientFees": "1.25",
    "targetAmount": "98.85",
    "fxRate": "2.000000",
    "memo": "memo",
    "processedAt": "2017-03-28T04:09:02.955Z",
    "createdAt": "2017-03-21T20:56:43.714Z",
    "updatedAt": "2017-03-28T04:09:02.955Z",
    "merchantFees": "0.00",
    "compliance": {
      "status": "verified",
      "checkedAt": "2017-03-28T04:08:53.297Z"
    },
    "sourceCurrency": "CAD",
    "sourceCurrencyName": "Canadian Dollar",
    "targetCurrency": "CAD",
    "targetCurrencyName": "Canadian Dollar",
    "batch": {
      "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
      "createdAt": "2017-03-21T20:56:43.690Z",
      "updatedAt": "2017-03-28T04:09:02.966Z",
      "sentAt": "2017-03-28T04:08:52.634Z",
      "completedAt": "2017-03-28T04:08:54.353Z"
    },
    "checkNumber": "ABC123", // Only populated in case of Check payment (US Only)
    "category": "services",
    "coverFees": false,
    "currency": "CAD",
    "equivalentWithholdingAmount": "0.00",
    "equivalentWithholdingCurrency": "CAD",
    "estimatedDeliveryAt": null,
    "externalId": "",
    "failureMessage": null,
    "initiatedAt": null,
    "isSupplyPayment": false,
    "merchantId": "M-Osg3dh2b0m1cRg9b8Shd2d",
    "methodDisplay": "Bank Transfer",
    "returnedAmount": "0.00",
    "returnedAt": null,
    "returnedNote": null,
    "returnedReason": [],
    "settledAt": null,
    "tags": [],
    "taxBasisAmount": "0.00",
    "taxBasisCurrency": "CAD",
    "taxReportable": true,
    "withholdingAmount": "0.00",
    "withholdingCurrency": "CAD"
  }
}

You can retrieve a single payment by sending a GET request to the batches/:batch-id/payments/:id endpoint. It will return the details of that payment under a batch.

HTTP Request

GET https://api.trolley.com/v1/batches/:batch-id/payments/:payment-id

Fields Description
batch-id
required
string
Batch ID
payment-id
required
string
Payment ID
HTTP Code Description
200 Payment object
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Update a payment

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X PATCH 'https://api.trolley.com/v1/batches/B-1a2B3c4D5e6F7g8H9i0J1k/payments/P-1a2B3c4D5e6F7g8H9i0J1k' \
--data-raw '{
    "amount": "100",
    "currency": "USD",
    "memo": "correcting payment amount"
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\Batch::updatePayment($batch->id, $payment->id, 
      [
          "sourceAmount" => "20.00",
      ]);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.payment.update(
  payment.id,
  batch.id,
  { 
    sourceAmount: "900.90"
  }
);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.payment.update(
  batch.id, 
  payment.id, 
  {
    sourceAmount: '20.00'
  })

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

payload = {
              "sourceAmount":"200.10",
          }
response = client.payment.update(payment.id, payload, batch.id)

print(response.id)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();
String paymentId = getPaymentId();

// Update a Payment
Payment paymentUpdateRequest = new Payment();
paymentUpdateRequest.setSourceAmount("20.00");

boolean response = client.payment.update(paymentId, paymentUpdateRequest, batchId);

System.out.println(response);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

Recipient recipient = GetRecipient();
string batchId = GetBatchId();
string paymentId = GetPaymentId();

Payment updatePaymentRequest = new Payment(recipient, 20.00, "EUR");
updatePaymentRequest.batchId = batchId;
updatePaymentRequest.id = paymentId;

bool response = gateway.payment.Update(updatePaymentRequest);

Console.WriteLine(response);

...

Response (200 Ok)

{
  "ok": true,
  "payment": {
    "id": "P-1a2B3c4D5e6F7g8H9i0J1k",
    "recipient": {
      "id": "R-1a3B3c4D5e6F7g8H9i0J1k",
      "referenceId": "jsmith11@example.com",
      "email": "jsmith11@example.com",
      "name": "John Smith",
      "lastName": "John",
      "firstName": "Smith",
      "type": "individual",
      "status": "active",
      "language": "en",
      "complianceStatus": "verified",
      "dob": null,
      "updatedAt": "2017-03-20T19:06:40.937Z",
      "createdAt": "2017-03-17T20:10:45.818Z",
      "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
      "placeOfBirth": null,
      "ssn": null,
      "tags": [],
      "passport": "",
      "payoutMethod": "bank-transfer",
      "compliance": {
        "status": "verified",
        "checkedAt": "2017-03-20T19:06:23.916Z"
      },
      "accounts": [
        {
          "accountHolderName": "John Smith",
          "bankId": "123",
          "currency": "CAD",
          "country": "CA",
          "bankName": "TD CANADA TRUST",
          "branchId": "47261",
          "accountNum": "*****47"
        }
      ],
      "address": {
        "street1": "Apt# 14",
        "street2": null,
        "city": "",
        "postalCode": "H3WXXX",
        "phone": "",
        "country": "CA",
        "region": "QC"
      },
      "primaryCurrency": "CAD"
    },
    "status": "pending",
    "sourceAmount": "100.10",
    "exchangeRate": "1.0000",
    "fees": "1.25",
    "recipientFees": "1.25",
    "targetAmount": "0.00",
    "fxRate": "2.000000",
    "memo": "momo",
    "processedAt": null,
    "createdAt": "2017-03-27T20:51:39.567Z",
    "updatedAt": "2017-03-27T20:51:39.567Z",
    "merchantFees": "0.00",
    "compliance": {
      "status": "pending",
      "checkedAt": null
    },
    "batch": {
      "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
      "createdAt": "2017-03-21T20:56:43.690Z",
      "updatedAt": "2017-03-28T04:09:02.966Z",
      "sentAt": "2017-03-28T04:08:52.634Z",
      "completedAt": "2017-03-28T04:08:54.353Z"
    },
    "sourceCurrency": "CAD",
    "sourceCurrencyName": "Canadian Dollar",
    "targetCurrency": "CAD",
    "targetCurrencyName": "Canadian Dollar",
    "category": "services",
    "coverFees": false,
    "currency": "CAD",
    "equivalentWithholdingAmount": "0.00",
    "equivalentWithholdingCurrency": "CAD",
    "estimatedDeliveryAt": null,
    "externalId": "",
    "failureMessage": null,
    "initiatedAt": null,
    "isSupplyPayment": false,
    "merchantId": "M-Osg3dh2b0m1cRg9b8Shd2d",
    "methodDisplay": "Bank Transfer",
    "returnedAmount": "0.00",
    "returnedAt": null,
    "returnedNote": null,
    "returnedReason": [],
    "settledAt": null,
    "tags": [],
    "taxBasisAmount": "0.00",
    "taxBasisCurrency": "CAD",
    "taxReportable": true,
    "withholdingAmount": "0.00",
    "withholdingCurrency": "CAD"
  }
}

To update a payment under a batch send a PATCH request to the /batches/:id/payments/:payment-id endpoint and include the payments details in the request body.

HTTP Request

PATCH https://api.trolley.com/v1/batches/:batch-id/payments/:payment-id

Fields Description
batch-id
required
string
Batch ID
payment-id
required
string
Payment ID
amount
conditional
string
Amount you wish to send, e.g. 100.00 USD, in your own currency.
currency
conditional
string
Currency of the amount you wish to send, e.g. 100.00 USD.
coverFees
optional
boolean
If the merchant should cover the network fees for this payment (default: false).
sourceAmount
conditional
string
deprecated
Amount you wish to send, e.g. 100.00 USD, in your own currency. Required only if sending a “sourceAmount”.
sourceCurrency
conditional
string
deprecated
Currency of the amount you wish to send, e.g. 100.00 USD. Required only if sending a “sourceAmount”.
targetAmount
conditional
string
deprecated
Amount you wish the recipient to receive, e.g. 85.00 EUR, in the recipient’s currency. Required only if sending a “Receive Amount”.
targetCurrency
conditional
string
deprecated
Currency of the amount you wish the recipient to receive, e.g. 85.00 EUR, in the recipient’s currency. Required only if sending a “Receive Amount”.
memo
optional
string
A short note which will be sent along with the payment to the recipient’s bank, as well as on the payment confirmation email if enabled. This memo will be displayed on the recipient’s bank statement descriptor to help them identify who the payment is from. The number of display characters depends on the recipient’s bank, so its best to keep short to less than 30 characters, otherwise the end may get cut off. Special characters are not supported on bank statement so will be stripped out by the bank. The memo field is good for referring to an invoice or reference number. We also strongly suggest to include your (short) business name at the start, as some banks globally don’t support displaying your business as the sender name. A good sample memo for an invoice payment from Airbnb would be: “AIRBNB INV 12345678”.
externalId
optional
string/null
Storage for your internal reference ID for this payment, if present it must be unique.
taxReportable
optional
boolean
If the merchant should apply tax withholding on the payment, and in turn adding it to the tax reporting (default: true).
category
conditional
string
Income type if the payment is Tax Reportable, either services, royalties, rent or goods.
HTTP Code Description
200 Payment successfully updated
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_status Invalid Status
invalid_api_key Invalid API key
internal_server_error Internal server errors

Delete a payment

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X DELETE 'https://api.trolley.com/v1/batches/B-CpkdteGqQCzKwNU8nRcCzL/payments/P-Nsg5wNqaTaqVRj5Gq4saYK' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\Batch::deletePayment($batch->id, $payment->id);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.payment.remove(
    payment.id,
    batch.id
  );

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.payment.delete(batch.id, payment.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.payment.delete(payment.id, batch.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();
String paymentId = getPaymentId();

boolean delPaymentResult = client.payment.delete(paymentId, batchId);

System.out.println(delPaymentResult);

...



...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

Recipient recipient = GetRecipient();
string batchId = GetBatchId();
string paymentId = GetPaymentId();

Payment paymentRequest = new Payment(null, null, null);
paymentRequest.batchId = batchId;
paymentRequest.id = paymentId;

response = gateway.payment.Delete(paymentRequest);

Console.WriteLine(response);

...

Response (200 Ok)

{
  "ok": true
}

To delete a payment under a batch send a DELETE request to the /batches/:batch-id/payments/:payment-id endpoint.

HTTP Request

DELETE https://api.trolley.com/v1/batches/:batch-id/payments/:payment-id

Fields Description
batch-id
required
string
Batch ID
payment-id
required
string
Payment ID
HTTP Code Description
200 Payment successfully deleted
401 Invalid API key
404 Object not found
406 invalid status
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_status Invalid Status
invalid_api_key Invalid API key
internal_server_error Internal server errors

List all payments

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/batches/B-1a2B3c4D5e6F7g8H9i0J1k/payments?page=1&pageSize=10' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$payments = Trolley\Batch::payments($batch->id);
foreach ($payments as $payment) {
    print_r($payment);
}

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.payment.search(1, 10, "John");

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.payment.search(batch.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

payments = client.payment.list_all_payments(batch.id)

# iterate through the payments generator
for payment in payments:
   print(payment)

# OR, get payments page by page. Optionally provide a search term
payments = client.payment.search_by_page(batch.id,"",2, 10)

for payment in payments:
   print(payment)

# You could also search without specifying pagination and use the returned generator
payments = client.payment.search(batch.id,"<search term>")

for payment in payments:
   print(payment)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();

int page = 1;
int pageSize = 10;

// Get all payments in a batch with an optional search term and manual pagination
Payments allPayments = client.payment.search(batchId, page, pageSize, "<search_term>");
List<Payment> payments = allPayments.getPayments();

for (Payment payment : payments){
  System.out.println(payment.getId());
}

...

// Or, with auto-pagination
PaymentsIterator payments = client.payment.search("<search_term>");

while(payments.hasNext()){
    System.out.println(payments.next().getId());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
int page = 1;
int pageSize = 10;

// List all payments with manual pagination, with optional search term and batch id
Payments allPayments = trolley.payment.Search("<search-term>", page, pageSize, "<batch-id>");

// Get a List of Payment objects to iterate through
List<Payment> payments = allPayments.payments;

// And get a Meta object to access page information
Meta meta = allPayments.meta;

// Or, list all payments with auto-pagination, with optional search term and batch id
var payments = trolley.payment.ListAllPayments("<search-term>", "<batch-id>");

foreach (Payment payment in payments)
{
  Console.WriteLine(payment.id);
}

...

Expected response (200 Ok)

{
   "ok":true,
   "payments":[
      {
         "id": "P-1a2B3c4D5e6F7g8H9i0J1k",
         "recipient": {
            "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
            "referenceId": "jsmith11@example.com",
            "email": "jsmith11@example.com",
            "name": "Richard Hendricks",
            "lastName": "Hendricks",
            "firstName": "Richard",
            "type": "individual",
            "status": "active",
            "language": "en",
            "complianceStatus": "verified",
            "dob": null,
            "updatedAt": "2017-03-20T19:06:40.937Z",
            "createdAt": "2017-03-17T20:10:45.818Z",
            "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
            "placeOfBirth": null,
            "ssn": null,
            "tags": [],
            "passport": "",
            "payoutMethod": "bank-transfer",
            "compliance": {
            "status": "verified",
            "checkedAt": "2017-03-20T19:06:23.916Z"
            },
            "accounts": [
            {
               "accountHolderName": "Richard Hendricks",
               "bankId": "123",
               "currency": "CAD",
               "country": "CA",
               "bankName": "TD CANADA TRUST",
               "branchId": "47261",
               "accountNum": "*****47"
            }
            ],
            "address": {
            "street1": "Apt# 14",
            "street2": null,
            "city": "",
            "postalCode": "H3WXXX",
            "phone": "",
            "country": "CA",
            "region": "QC"
            },
            "primaryCurrency": "CAD"
         },
         "status": "processed",
         "sourceAmount": "100.10",
         "exchangeRate": "1.0000",
         "fees": "1.25",
         "recipientFees": "1.25",
         "targetAmount": "98.85",
         "fxRate": "2.000000",
         "memo": "memo",
         "processedAt": "2017-03-28T04:09:02.955Z",
         "createdAt": "2017-03-21T20:56:43.714Z",
         "updatedAt": "2017-03-28T04:09:02.955Z",
         "merchantFees": "0.00",
         "compliance": {
            "status": "verified",
            "checkedAt": "2017-03-28T04:08:53.297Z"
         },
         "sourceCurrency": "CAD",
         "sourceCurrencyName": "Canadian Dollar",
         "targetCurrency": "CAD",
         "targetCurrencyName": "Canadian Dollar",
         "batch": {
            "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
            "createdAt": "2017-03-21T20:56:43.690Z",
            "updatedAt": "2017-03-28T04:09:02.966Z",
            "sentAt": "2017-03-28T04:08:52.634Z",
            "completedAt": "2017-03-28T04:08:54.353Z"
         },
         "category": "services",
         "coverFees": false,
         "currency": "CAD",
         "equivalentWithholdingAmount": "0.00",
         "equivalentWithholdingCurrency": "CAD",
         "estimatedDeliveryAt": null,
         "externalId": "",
         "failureMessage": null,
         "initiatedAt": null,
         "isSupplyPayment": false,
         "merchantId": "M-Osg3dh2b0m1cRg9b8Shd2d",
         "methodDisplay": "Bank Transfer",
         "returnedAmount": "0.00",
         "returnedAt": null,
         "returnedNote": null,
         "returnedReason": [],
         "settledAt": null,
         "tags": [],
         "taxBasisAmount": "0.00",
         "taxBasisCurrency": "CAD",
         "taxReportable": true,
         "withholdingAmount": "0.00",
         "withholdingCurrency": "CAD"
      },
      {
         "id": "P-1a2B3c4D5e6F7g8H9i0J1k",
         "recipient": {
            "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
            "referenceId": "jsmith11@example.com",
            "email": "jsmith11@example.com",
            "name": "Richard Hendricks",
            "lastName": "Hendricks",
            "firstName": "Richard",
            "type": "individual",
            "status": "active",
            "language": "en",
            "complianceStatus": "verified",
            "dob": null,
            "updatedAt": "2017-03-20T19:06:40.937Z",
            "createdAt": "2017-03-17T20:10:45.818Z",
            "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
            "placeOfBirth": null,
            "ssn": null,
            "tags": [],
            "passport": "",
            "payoutMethod": "bank-transfer",
            "compliance": {
            "status": "verified",
            "checkedAt": "2017-03-20T19:06:23.916Z"
            },
            "accounts": [
            {
               "accountHolderName": "Richard Hendricks",
               "bankId": "123",
               "currency": "CAD",
               "country": "CA",
               "bankName": "TD CANADA TRUST",
               "branchId": "47261",
               "accountNum": "*****47"
            }
            ],
            "address": {
            "street1": "Apt# 14",
            "street2": null,
            "city": "",
            "postalCode": "H3WXXX",
            "phone": "",
            "country": "CA",
            "region": "QC"
            },
            "primaryCurrency": "CAD"
         },
         "status": "processed",
         "sourceAmount": "100.10",
         "exchangeRate": "1.0000",
         "fees": "1.25",
         "recipientFees": "1.25",
         "targetAmount": "98.85",
         "fxRate": "2.000000",
         "memo": "memo",
         "processedAt": "2017-03-28T04:09:02.955Z",
         "createdAt": "2017-03-21T20:56:43.714Z",
         "updatedAt": "2017-03-28T04:09:02.955Z",
         "merchantFees": "0.00",
         "compliance": {
            "status": "verified",
            "checkedAt": "2017-03-28T04:08:53.297Z"
         },
         "sourceCurrency": "CAD",
         "sourceCurrencyName": "Canadian Dollar",
         "targetCurrency": "CAD",
         "targetCurrencyName": "Canadian Dollar",
         "batch": {
            "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
            "createdAt": "2017-03-21T20:56:43.690Z",
            "updatedAt": "2017-03-28T04:09:02.966Z",
            "sentAt": "2017-03-28T04:08:52.634Z",
            "completedAt": "2017-03-28T04:08:54.353Z"
         },
         "category": "services",
         "coverFees": false,
         "currency": "CAD",
         "equivalentWithholdingAmount": "0.00",
         "equivalentWithholdingCurrency": "CAD",
         "estimatedDeliveryAt": null,
         "externalId": "",
         "failureMessage": null,
         "initiatedAt": null,
         "isSupplyPayment": false,
         "merchantId": "M-Osg3dh2b0m1cRg9b8Shd2d",
         "methodDisplay": "Bank Transfer",
         "returnedAmount": "0.00",
         "returnedAt": null,
         "returnedNote": null,
         "returnedReason": [],
         "settledAt": null,
         "tags": [],
         "taxBasisAmount": "0.00",
         "taxBasisCurrency": "CAD",
         "taxReportable": true,
         "withholdingAmount": "0.00",
         "withholdingCurrency": "CAD"
      }
   ],
   "meta":{
      "page":1,
      "pages":1,
      "records":2
   }
}

You can retrieve all payments from an existing batch by sending a GET request to the /batches/:batch-id/payments endpoint.

HTTP Request

GET https://api.trolley.com/v1/batches/:batch-id/payments?page=1&pageSize=10

Fields Description
batch-id
required
string
Batch ID
Query Param Description
page
required
int
The page number (default: 1)
pageSize
required
int
Number of records in a page (default: 10)
search
optional
string
Wildcard search across payments
status
optional
string
Filter by payment statuses. Comma separate list if multiple.
HTTP Code Description
200 List of payments
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Generate quote

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X POST 'https://api.trolley.com/v1/batches/B-1a2b3c4d5e6f7g8h9i0jk1/generate-quote' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$quote = Trolley\Batch::generateQuote($batch->id);

print_r($quote);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.batch.generateQuote(batch.id);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.batch.generate_quote(batch.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.batch.generate_quote(batch.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();

// Generate Quote of payments in the batch
String response = client.batch.generateQuote(batchId);

System.out.println(response);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string batchId = GetBatchId();

Batch batch = gateway.batch.GenerateQuote(batchId);

Console.WriteLine(batch.id);

...

Example response (200 Ok)

{
  "ok": true,
  "batch": {
    "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
    "status": "open",
    "tags": [],
    "amount": "8.75",
    "totalPayments": 2,
    "currency": "CAD",
    "description": "Weekly Payouts on 2017-2-27",
    "sentAt": null,
    "completedAt": null,
    "createdAt": "2017-03-27T20:19:47.378Z",
    "updatedAt": "2017-03-27T20:19:47.518Z",
    "quoteExpiredAt": "2017-03-28T04:08:52.634Z"
  }
}

To generate a quote of a Batch send a POST request to the /batches/:id/generate-quote endpoint. It will update all the exchangeRate and amounts in all the payments which incur a currency conversion, i.e. you are sending to a different currency.

HTTP Request

POST https://api.trolley.com/v1/batches/:batch-id/generate-quote

Fields Description
batch-id
required
string
Batch ID
HTTP Code Description
200 Batch successfully updated
401 Invalid API key
404 Object not found
406 Quote is expired or batch’s status is incorrect, see errors[] in response body
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object not found
expired_quote Quote is expired
invalid_status Invalid Status
invalid_api_key Invalid API key
internal_server_error Internal server errors

Batch summary

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/batches/B-1a2b3c4d5e6f7g8h9i0jk1/summary' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$summary = Trolley\Batch::summary($batch->id);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.batch.summary(batch.id);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.batch.summary(batch.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.batch.summary(batch.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();

// Get a Batch's summary
BatchSummary batchSummary = client.batch.summary(batchId);

System.out.println(batchSummary.detail.bankTransfer.debitAmount);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string batchId = GetBatchId();

string summary = gateway.batch.Get(batchId);

Console.WriteLine(summary);

...

Example response (200 Ok)

{
  "ok": true,
  "batchSummary": {
    "detail": {
      "bank-transfer": {
        "count": 1,
        "totalFees": "1.00",
        "merchantFees": "1.00",
        "debitAmount": "11.00",
        "sendingAmount": "10.00",
        "totalWithheld": "0.00"
      },
      "paypal": {
        "count": 1,
        "totalFees": "1.00",
        "merchantFees": "1.00",
        "debitAmount": "11.00",
        "sendingAmount": "10.00",
        "totalWithheld": "0.00"
      }
    },
    "total": {
      "count": 1,
      "totalFees": "2.00",
      "merchantFees": "2",
      "debitAmount": "22.00",
      "sendingAmount": "20.00",
      "totalWithheld": "0.00"
    }
  }
}

You can retrieve a summary of a batch, including the details of all the payments in the batch, by sending a GET request to the /batch/:batch-id/summary endpoint.

HTTP Request

GET https://api.trolley.com/v1/batches/:batch-id/summary

Fields Description
batch-id
required
string
Batch ID
HTTP Code Description
200 Batch successfully updated
401 Invalid API key
404 Object not found
406 One or more fields failed validation, see errors[] in response body
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object not found
expired_quote Quote is expired
invalid_status Invalid Status

Process a batch

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X POST 'https://api.trolley.com/v1/batches/B-1a2B3c4D5e6F7g8H9i0J1k/start-processing' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\Batch::startProcessing($batch->id);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.batch.startProcessing(batch.id);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.batches.start_processing(batch.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.batch.process_batch(batch.id)

print(response.id)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String batchId = getBatchId();

// Process a batch
String response = client.batch.processBatch(batchId);

System.out.println(response);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string batchId = GetBatchId();

Batch batch = gateway.batch.ProcessBatch(batchId);

Console.WriteLine(batch.status);

...

Example response (200 Ok)

{
  "ok": true,
  "batch": {
    "id": "B-1a2B3c4D5e6F7g8H9i0J1k",
    "status": "processing",
    "tags": [],
    "amount": "8.75",
    "totalPayments": 2,
    "currency": "CAD",
    "description": "Weekly Payouts on 2017-2-27",
    "sentAt": "2017-03-28T04:08:52.634Z",
    "completedAt": null,
    "createdAt": "2017-03-27T20:19:47.378Z",
    "updatedAt": "2017-03-28T04:08:52.634Z",
    "quoteExpiredAt": "2017-03-29T04:08:52.634Z"
  }
}

To start processing a specific batch, send a POST request to the /batches/:batch-id/start-processing endpoint.

HTTP Request

POST https://api.trolley.com/v1/batches/:batch-id/start-processing

Fields Description
batch-id
required
string
Batch ID
HTTP Code Description
200 Batch successfully processed
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object not found
invalid_status Invalid Status
invalid_api_key Invalid API key
internal_server_error Internal server errors
non_sufficient_funds Insufficient funds

Offline Payments


An Offline Payment represents a payment that was made outside of the Trolley platform, such as a manual check payment or made with another payouts provider. There are two primary reason you would want to pass this information to us: 1.) to allow those payments to be included in your end of year US tax reporting statements (Forms 1099-MISC, 1099-NEC, 1042-S) and E-filing return, and 2.) to display those payments to your recipients in the Payments History page on the Recipient Widget or Portal, so recipients can see all their payments, even those that weren’t processed with Trolley or were processed before your migrated to Trolley.

Create an offline payment

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X POST 'https://api.trolley.com/v1/recipients/R-4321c356vrcerc54js/offlinePayments' \
--data-raw '{
    "currency": "CAD",
    "amount": "100.00",
    "payoutMethod": "bitcoin",
    "category": "services",
    "memo": "Bitcoin Payment",
    "processedAt": "2022-06-22T01:10:17.571Z"
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\OfflinePayment::create($recipient_id, [
    'amount' => "100.00",
    'category' => "services",
    'currency' => "USD",
    'externalId' => "id-123",
    'memo' => "A memo",
    'processedAt' => "2019-08-15T20:23:59.000Z",
    'tags' => [],
    'payoutMethod' => "bank-transfer",
    'taxReportable' => true,
    'withholdingAmount' => "24.00",
    'withholdingCurrency' => "USD"
]);

print_r($response);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.offlinePayment.create(
  recipient.id,
  {
    amount: "100.00",
    category: "services",
    currency: "USD",
    externalId: "id-123",
    memo: "A memo",
    processedAt: "2019-08-15T20:23:59.000Z",
    tags: [],
    payoutMethod: "paypal",
    taxReportable: true,
    withholdingAmount: "24.00",
    withholdingCurrency: "USD"
  });

console.log(response.offlinePayment);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.offline_payment.create(
  recipient.id,
  {
    amount: "100.00",
    category: "services",
    currency: "USD",
    externalId: "id-123",
    memo: "A memo",
    processedAt: "2019-08-15T20:23:59.000Z",
    payoutMethod: "other",
    taxReportable: true,
    withholdingAmount: "24.00",
    withholdingCurrency: "USD"
  })

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

offline_payment = client.offline_payment.create(
  recipient.id, 
  {
    "currency":"CAD",
    "amount":"10.00",
    "payoutMethod":"paypal",
    "category":"services",
    "memo":"Offline Payment for services",
    "processedAt":"2023-06-22T01:10:17.571Z"
  })

print(response.id)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();

// Create an Offline Payment
OfflinePayment opRequest = new OfflinePayment();
opRequest.setCurrency("CAD");
opRequest.setAmount("10.00");
opRequest.setMemo("Offline Payment from Java SDK");

OfflinePayment offlinePayment = client.offlinePayment.create(recipientId, opRequest);

System.out.println(offlinePayment.getId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();

OfflinePayment opRequest = new OfflinePayment();
opRequest.amount = 20;
opRequest.currency = "CAD";
opRequest.memo = "Offline Payment through .Net SDK";
OfflinePayment opResponse = gateway.offlinePayment.Create(recipientId, opRequest);

Console.WriteLine(opResponse.id);

...

To create an offline payment for a recipient send a POST request to the /recipients/:id/offlinePayments endpoint and include the offline payments details in the request body. An auto-generated ID (id) will be generated which can be used to retrieve or update the offline payment details at a later time.

HTTP Request

POST https://api.trolley.com/v1/recipients/:id/offlinePayments

Fields Description
externalId
optional
string
The payment identifier used on your external platform.
memo
optional
string
A short note which may help in identifying or detailing the payment.
taxReportable
conditional
boolean
Should be true if the payment needs to be included in end of year tax reporting of earnings, and false if it should not be reportable as earnings for tax purposes.
category
conditional
string
Income type if the payment is Tax Reportable, either services, royalties, royalties_film, rent or prizes.
processedAt
optional
string
The date that the payment was made to the recipient - used to report in the correct tax year, and also to convert amounts in another currency to USD equivalent, based on the mid-market FX rate of this date.
amount
required
string
The payment amount.
currency
optional
boolean
The payment’s currency. (If it is not in USD, and it is Tax Reportable, we will convert the amount to USD equivalent based on the mid-market FX rate of the date of the payment).
tags
optional
string
Tags or keywords which may help identifying the payment.
payoutMethod
optional
string
The payout method used off platform for this payment, either bank-transfer, paypal, interac, check, bitcoin, mobile-money or other.
withholdingAmount
required
string
The amount withheld from the payment for tax purposes.
withholdingCurrency
optional
string
The currency associated to the withholdingAmount.

Example response (200 Ok)

{
  "ok": true,
  "offlinePayments": {
    "amount": "100.00",
    "category": "services",
    "createdAt": "2019-10-31T20:24:29.954Z",
    "currency": "USD",
    "deletedAt": null,
    "equivalentWithholdingAmount": "24.00",
    "equivalentWithholdingCurrency": "USD",
    "externalId": "id-123",
    "id": "OP-3xghXMEcedrjPEo3KedqsR",
    "memo": "A memo",
    "processedAt": "2019-08-15T20:23:59.000Z",
    "recipientId": "R-4321c356vrcerc54js",
    "tags": [],
    "taxReportable": true,
    "updatedAt": "2019-10-31T20:24:29.954Z",
    "withholdingAmount": "24.00",
    "withholdingCurrency": "USD"
  }
}
HTTP Code Description
200 Offline payment successfully added
401 Invalid API key
404 Object not found
400 Validation error
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

List all offline payments

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/offline-payments?page=1&pageSize=10' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$offlinePayments = Trolley\OfflinePayments::all();

foreach ($offlinePayments as $offlinePayment) {
  print_r($offlinePayment);
}
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.offlinePayments.search();

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.offline_payment.search

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

# Get a generator to go through all the offline payments sequentially
offline_payments = client.offline_payment.get_all()

# Iterate through the generator
for payment in offline_payments:
  print(payment)

# OR, get Offline Payments by page:
offline_payments = client.offline_payment.get_all_by_page(2, 10)

# iterate through the items return on the page
for payment in offline_payments:
  print(payment)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

//Get all Offline Payments, with an optional search term and manual pagination
OfflinePayments allOfflinePayments = client.offlinePayment.listAllOfflinePayments();
List<OfflinePayment> offlinePayments = allOfflinePayments.getOfflinePayments();

for (OfflinePayment offlinePayment : offlinePayments) {
    System.out.println(offlinePayment.getId());
}

...

// Or, get all payments with optional search term with auto-pagination
OfflinePaymentsIterator offlinePayments = client.offlinePayment.listAllOfflinePayments("<search_term>");

while(offlinePayments.hasNext()){
    System.out.println(offlinePayments.next().getId());
}

...

// Similarly, get all payments with auto-pagination with no search
OfflinePaymentsIterator offlinePayments = client.offlinePayment.listAllOfflinePayments();

while(offlinePayments.hasNext()){
    System.out.println(offlinePayments.next().getId());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();

// Get all OfflinePayments with manual pagination and optional search term
OfflinePayments allOfflinePayments = gateway.offlinePayment.ListAllOfflinePayments("<search_term>", 1, 10);
List<OfflinePayment> allOfflinePayments.offlinePayments;
foreach (OfflinePayment offlinePayment in offlinePayments)
{
    Console.WriteLine(offlinePayment.id);
}

// Or, get all OfflinePayments with auto-pagination and optional search term
var offlinePayments = gateway.offlinePayment.ListAllOfflinePayments("<search_term>");
foreach (OfflinePayment offlinePayment in offlinePayments)
{
    Console.WriteLine(offlinePayment.id);
}

...

Expected response (200 Ok)

{
  "ok": true,
  "offlinePayments": [
    {
      "amount": "100.00",
      "category": "services",
      "createdAt": "2019-10-31T20:24:29.954Z",
      "currency": "USD",
      "deletedAt": null,
      "equivalentWithholdingAmount": "24.00",
      "equivalentWithholdingCurrency": "USD",
      "externalId": "id-123",
      "id": "OP-3xghXMEcedrjPEo3KedqsR",
      "memo": "A memo",
      "processedAt": "2019-08-15T20:23:59.000Z",
      "recipientId": "R-4321c356vrcerc54js",
      "tags": [],
      "taxReportable": true,
      "updatedAt": "2019-10-31T20:24:29.954Z",
      "withholdingAmount": "24.00",
      "withholdingCurrency": "USD"
    },
    {
      "amount": "100.00",
      "category": "services",
      "createdAt": "2019-10-31T20:24:29.954Z",
      "currency": "USD",
      "deletedAt": null,
      "equivalentWithholdingAmount": "24.00",
      "equivalentWithholdingCurrency": "USD",
      "externalId": "id-123",
      "id": "OP-4xghXMEcedrjPEo3KedqsR",
      "memo": "A memo",
      "processedAt": "2019-08-15T20:23:59.000Z",
      "recipientId": "R-4321c356vrcerc54js",
      "tags": [],
      "taxReportable": true,
      "updatedAt": "2019-10-31T20:24:29.954Z",
      "withholdingAmount": "24.00",
      "withholdingCurrency": "USD"
    }
  ],
  "meta": {
        "page": 1,
        "pages": 0,
        "records": 0
    }
}

You can retrieve all offline payments by sending a GET request to the /offline-payments endpoint.

HTTP Request

GET https://api.trolley.com/v1/offline-payments?page=1&pageSize=10

Query Param Description
page
required
int
The page number (default: 1)
pageSize
required
int
Number of records in a page (default: 10)
search
required
string
Wildcard search of the batch-id
HTTP Code Description
200 List of batches
401 Invalid API key
500 Internal error
Error Code Description
invalid_api_key Invalid API key
internal_server_error Internal server errors

Update an offline payment

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X PATCH 'https://api.trolley.com/v1/recipients/R-4321c356vrcerc54js/offlinePayments/OP-3xghXMEcedrjPEo3KedqsR' \
--data-raw '{
    "amount": "100.00",
    "category": "services",
    "currency": "USD",
    "externalId": "id-123",
    "memo": "A memo",
    "processedAt": "2019-08-15T20:23:59.000Z",
    "payoutMethod": "check",
    "taxReportable": true,
    "withholdingAmount": "24.00",
    "withholdingCurrency": "USD"
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\OfflinePayment::update($recipient_id, $offline_payment_id, [
    'amount' => "100.00",
    'category' => "services",
    'currency' => "USD",
    'externalId' => "id-123",
    'memo' => "A memo",
    'processedAt' => "2019-08-15T20:23:59.000Z",
    'tags' => [],
    'payoutMethod' => "mobile-money",
    'taxReportable' => true,
    'withholdingAmount' => "24.00",
    'withholdingCurrency' => "USD"
]);

print_r($response);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.offlinePayment.update(
  recipient.id,
  offlinePayment.id,
  {
    amount: "100.00",
    category: "services",
    currency: "USD",
    externalId: "id-123",
    memo: "A memo",
    processedAt: "2019-08-15T20:23:59.000Z",
    tags: [],
    payoutMethod: "check",
    taxReportable: true,
    withholdingAmount: "24.00",
    withholdingCurrency: "USD"
  });
  
console.log(response.offlinePayment);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.offlinePayment.create(
  recipient.id, 
  offline_payment.id, 
  {
    amount: "100.00",
    category: "services",
    currency: "USD",
    externalId: "id-123",
    memo: "A memo",
    processedAt: "2019-08-15T20:23:59.000Z",
    tags: [],
    payoutMethod: "interac",
    taxReportable: true,
    withholdingAmount: "24.00",
    withholdingCurrency: "USD"
  })

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

offline_payment = client.offline_payment.update(
  offline_payment.id,
  recipient.id, 
  {
    "currency":"CAD",
    "amount":"20.00"
  })

print(offline_payment)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();
String offlinePaymentId = getOfflinePaymentId();

// Update an Offline Payment
OfflinePayment opRequest = new OfflinePayment();
opRequest.setMemo("Offline Payment Update from Java SDK");

boolean updateResult = client.offlinePayment.update(recipientId, offlinePaymentId, opRequest);

System.out.println("Update Result: "+updateResult);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
string offlinePaymentId = GetOfflinePaymentId();

OfflinePayment opRequest = new OfflinePayment();
opRequest.amount = 50;
bool updateResult = gateway.offlinePayment.Update(recipientId, offlinePaymentId, opRequest);

Console.WriteLine(updateResult);

...

To update an offline payment for a recipient send a PATCH request to the /recipients/:recipientId/offlinePayments/:offlinePaymentId endpoint and include the offline payments details in the request body.

HTTP Request

PATCH https://api.trolley.com/v1/recipients/:recipientId/offlinePayments/:offlinePaymentId

Fields Description
externalId
optional
string
The payment identifier used on your external platform.
memo
optional
string
A short note which may help in identifying or detailing the payment.
taxReportable
conditional
boolean
Should be true if the an amount has been withheld from the payment for tax withholding purposes, in other words if withholdingAmount is greater than 0.00.
category
conditional
string
Either services, royalties, royalties_film, rent or prizes, to help contextualize the withholdingAmount if it is greater than 0.00.
processedAt
optional
string
The date that the payment was made to the recipient.
amount
required
string
The payment amount.
currency
optional
boolean
The payment’s currency.
tags
optional
string
Keywords which may help identifying or detailing the payment.
payoutMethod
optional
string
The payout method used off platform for this payment, either bank-transfer, paypal, interac, check, bitcoin, mobile-money or other.
withholdingAmount
required
string
The amount withheld from the payment for tax purposes.
withholdingCurrency
optional
string
The currency associated to the withholdingAmount.

Example response (200 Ok)

{
  "ok": true,
  "offlinePayments": {
    "amount": "100.00",
    "category": "services",
    "createdAt": "2019-10-31T20:24:29.954Z",
    "currency": "USD",
    "deletedAt": null,
    "equivalentWithholdingAmount": "24.00",
    "equivalentWithholdingCurrency": "USD",
    "externalId": "id-123",
    "id": "OP-3xghXMEcedrjPEo3KedqsR",
    "memo": "A memo",
    "processedAt": "2019-08-15T20:23:59.000Z",
    "recipientId": "R-4321c356vrcerc54js",
    "tags": [],
    "taxReportable": true,
    "updatedAt": "2019-10-31T20:24:29.954Z",
    "withholdingAmount": "24.00",
    "withholdingCurrency": "USD"
  }
}
HTTP Code Description
200 Offline payment successfully added
401 Invalid API key
404 Object not found
400 Validation error
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Delete an offline payment

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \ 
-X DELETE 'https://api.trolley.com/v1/recipients/R-PuzPJLVYQXBbPSMQKwmJ5G/offlinePayments/OP-KKHb8MpFvju6vDMBLPmtej' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$response = Trolley\OfflinePayment::delete($recipient_id, $offline_payment_id);

print_r($response);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.offlinePayment.remove(
  recipient.id,
  offlinePayment.id
);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.offline_payment.delete(recipient.id, offline_payment.id)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.offline_payment.delete(recipient.id, offline_payment.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();
String offlinePaymentId = getOfflinePaymentId();

//Delete an Offline Payment
boolean opDelResult = client.offlinePayment.delete(recipientId, offlinePaymentId);

System.out.println("Delete Result: "+opDelResult);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
string offlinePaymentId = GetOfflinePaymentId();

bool delResult = gateway.offlinePayment.Delete(recipientId, offlinePaymentId);

Console.WriteLine(delResult);

...

Example response (200 Ok)

{
  "ok": true
}

Delete a recipient’s offline payment

HTTP Request

DELETE https://api.trolley.com/v1/recipients/:recipientId/offlinePayments/:offlinePaymentId

Fields Description
recipientId
required
string
The recipient’s id.
offlinePaymentId
required
string
The offlinePayment’s id.
HTTP Code Description
200 Payment successfully updated
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Invoices


The invoices object is designed to handle an accounts payable bill. Invoices are a collection of header information about who the bill is from and when it’s due along with some total information about the individual lines on the bill.

Invoices will have one or more line items with a maximum of 500 lines per invoice. Each line item can have distinct tax treatments but must all be in the same currency.

Payments can be associated with the Invoice / Invoice Line to indicate that payments have been made against this invoice. This will cause the appropriate tax handling to be updated for these payments for accounting purposes. In the event that you’re modifying invoice payments after the payment has been processed the underlying payment will not be updated, since it’s money movement, but the tax handling will be updated.

Create an invoice

Sample Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
--data-raw '{
    "recipientId": "R-XgtzXghfxx4Z2E4Y3R",
    "description": "Invoice for artwork payment",
    "externalId": "acme-inv-1001",
    "invoiceNumber": "inv-number-1001",
    "dueDate": "2023-02-01"
    "lines": [
        {
            "unitAmount": {
                "value": "100",
                "currency": "EUR"
            }
        }
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$newInvoice = Trolley\Invoice::create(
    [
        "recipientId" 	=> $recipient_id,
        "description" 	=> "New Invoice sample code for PHP SDK",
        "invoiceNumber" => "inv-number-1001",
        "dueDate"       => "2023-02-01"
    ]);

print_r($newInvoice);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoice.create(
    {
        recipientId: recipient.id, 
        description: "New invoice from Javascript SDK",
        externalId: "invoice-101",
        invoiceDate: "2023-01-01",
        invoiceNumber: "inv-number-1001",
        dueDate: "2023-02-01"
    });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.invoice.create(
    recipientId: recipient.id, 
    description: 'New Invoice from Ruby SDK',
    invoiceNumber: "inv-number-1001",
    dueDate: "2023-02-01"
)

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

invoice = client.invoice.create({
    "recipientId": recipient.id,
    "description": "Invoice description",
    "invoiceNumber": "inv-number-1001",
    "dueDate": "2023-02-01"
    })

print(invoice)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String recipientId = getRecipientId();
//Create a request object
Invoice invoice = new Invoice();

//Set request values
invoice.setRecipientId(recipientId);
invoice.setInvoiceNumber("invoice-123");
invoice.setDescription("invoice-java-sdk");
invoice.setExternalId("ext-id-123");
invoice.setInvoiceNumber("inv-number-1001");
invoice.setDueDate("2023-02-01");

//Making network request and collecting response
Invoice invoiceResponse = client.invoice.create(invoice);

System.out.println(invoice.getCreatedAt());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();

Invoice invoiceRequest = new Invoice();
invoiceRequest.recipientId = recipientId;
invoiceRequest.description = "New Invoice with .Net SDK";
Invoice invoice = gateway.invoice.Create(invoiceRequest);

Console.WriteLine(invoice.id);

...

To create an invoice for a recipient send a POST request to the /invoices/create endpoint and include the recipientId for the given recipient. You can also add additional details and the invoice lines when you create the invoice.

Note: Invoices are limited to 500 instances of lines.

HTTP Request

POST https://api.trolley.com/v1/invoices/create

Fields Description
recipientId
required
string
The ID of the recipient which this invoice is for.
description
optional
string
A description of the invoice that you would like to add for internal reference.
externalId
optional
string
The invoice identifier used on your external platform.
invoiceDate
optional
string
The date the invoice was issued.
dueDate
optional
string
The date the invoice is due
lines
optional
lines[]
The invoice lines for this invoice - see Create Invoice Line for details

Example response (200 Ok)

{
  "ok": true,
  "invoice": {
        "id": "I-HEG4x7Pb8VRkYZnu8Ja",
        "invoiceNumber": "",
        "description": "Payment for artwork to Leonardo da Vinci",
        "status": "open",
        "externalId": "acme-inv-1002",
        "invoiceDate": "2022-05-12T15:27:55.818Z",
        "dueDate": null,
        "createdAt": "2022-05-12T15:27:55.817Z",
        "updatedAt": "2022-05-12T15:27:55.825Z",
        "totalAmount": {
            "value": "200.00",
            "currency": "EUR"
        },
        "paidAmount": {
            "value": "0.00",
            "currency": "EUR"
        },
        "dueAmount": {
            "value": "200.00",
            "currency": "EUR"
        },
        "tags": [],
        "lines": [
            {
                "id": "<line-id>",
                "status": "open",
                "description": "",
                "unitAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "quantity": "1",
                "discountAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "taxAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "totalAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "dueAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "paidAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "externalId": null,
                "taxReportable": true,
                "tags": [],
                "category": "services",
                "forceUsTaxActivity": false
            }
        ],
        "recipientId": "R-XgtzXghfxx4Z2E4Y3R"
    }
}

Example Response (400 Bad Request - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "invalid_field",
            "message": "Value is invalid",
            "field": "lines.unitAmount"
        }
    ]
}
HTTP Code Description
200 Invoice successfully created
401 Invalid API key
404 Object not found
400 Validation error
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Create an invoice line

To create an invoice line for a given recipient send a POST request to the /invoices/create-lines endpoint and include a list of lines in the request body. You will get back the updated invoice in the response.

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X POST 'https://api.trolley.com/v1/invoices/create-lines' \
--data-raw '{
    "invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
    "lines": [
        {
            "unitAmount": {
                "value": "200",
                "currency": "EUR"
            },
            "category":"royalties",
            "description":"Royalties for Mona Lisa painting museum viewing",
            "externalId":"acme-inv-royalties-1002",
            "taxReportable": true,
            "forceUsTaxActivity": false,
            "tags":["da vinci", "it"]
        }
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$invoiceWithLines = Trolley\InvoiceLine::create($invoice_id, [
    [
        "unitAmount" =>[
            "value" => "50.00",
            "currency" => "EUR"
        ],
        "description" 	=> "first invoice line",
        "category"		=> Trolley\InvoiceLine::$categories["services"]
    ]
]);

print_r($invoiceWithLines);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoiceLine.create(
    {   
        invoice: { 
            id: invoice.id 
        },
        unitAmount: {
            value: "50.00",
            currency: "EUR"
        },
        category: InvoiceLineCategory.services,
        description: "First Invoice Line",
        externalId: "invoice-line-101",
        taxReportable: true
    });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.invoice.create_line(
    invoiceId: invoice.id, 
    lines: [
        {
            unitAmount: { 
                value: '2000', 
                currency: 'USD'
            } 
        }
    ])

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

invoice = client.invoice_line.create(invoice_id,[
    {
        "unitAmount" :{
            "value" : "250.00",
            "currency" : "EUR"
        },
        "description": "invoice line 1",
        "category": InvoiceLine.categories.education
    }
])

print(invoice)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String invoiceId = invoice.getId();

//Create a request object and set request values
InvoiceLine invoiceLine = new InvoiceLine();
invoiceLine.setUnitAmount(new Amount("100", "USD"));
invoiceLine.setCategory(InvoiceCategories.SERVICES);

//Making network request and receiving response
Invoice invoiceWithLines = client.invoiceLine.create(
    invoiceId, 
    invoiceLine
);

// Iterate through the lines of this invoice
for(InvoiceLine invoiceLine : invoiceWithLines.getLines()){
    System.out.println(invoiceLine.getId());
}

...

// Available values for InvoiceCategories
enum InvoiceCategories{
    SERVICES,
    RENT,
    ROYALTIES,
    ROYALTIES_FILM,
    PRIZES,
    EDUCATION,
    REFUNDS
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoiceId = GetInvoiceId();

InvoiceLine invoiceLineRequest = new InvoiceLine();
invoiceLineRequest.description = "Invoice Line with .Net SDK";
invoiceLineRequest.unitAmount = new Amount("120.00", "USD");
Invoice invoice = gateway.invoiceLine.Create(invoiceId, invoiceLineRequest);

Console.WriteLine(invoice.id);

...

Example response (200 Ok)

{
    "ok": true,
    "invoice": {
        "id": "I-HEG4x7Pb8VRkYZnu8Ja",
        "invoiceNumber": "101",
        "description": "",
        "status": "open",
        "externalId": null,
        "invoiceDate": "2021-10-13T00:00:00.000Z",
        "dueDate": "2021-11-12T00:00:00.000Z",
        "createdAt": "2021-10-13T14:26:21.053Z",
        "updatedAt": "2022-05-13T04:57:20.978Z",
        "totalAmount": {
            "value": "200.00",
            "currency": "EUR"
        },
        "paidAmount": {
            "value": "0.00",
            "currency": "EUR"
        },
        "dueAmount": {
            "value": "200.00",
            "currency": "EUR"
        },
        "tags": [],
        "lines": [
            {
                "id": "IL-EtrPXL9aytREz2vdVgk",
                "status": "open",
                "description": "Royalties for Mona Lisa painting museum viewing",
                "unitAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "quantity": "1",
                "discountAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "taxAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "totalAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "dueAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "paidAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "externalId": "acme-inv-royalties-1002",
                "taxReportable": true,
                "tags": [
                    "royalties",
                    "da vinci",
                    "it"
                ],
                "category": "royalties",
                "forceUsTaxActivity": false
            }
        ],
        "recipientId": "R-XgtzXghfxx4Z2E4Y3R"
    }
}

Example Response (404 Not Found - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "not_found",
            "message": "unable to find invoice"
        }
    ]
}

HTTP Request

POST https://api.trolley.com/v1/invoices/create-lines

Fields Description
invoiceId
required
string
The invoice that these lines will be added to.
lines[]
required
string
Array of lines
lines[].unitAmount.value
required
string
The amount of this line item. This supports negative values too.
lines[].unitAmount.currency
required
string
The currency code of this line item
lines[].category
optional
string
The payment category for this line item (see Category List)
lines[].description
optional
string
Item description
lines[].externalId
optional
string
Reference for this line in your system
lines[].taxReportable
optional
boolean
Is this line item subject to EOY tax reporting
lines[].forceUsTaxActivity
optional
boolean
Is this line item subject to US withholding for EOY tax reporting
lines[].tags
optional
string[]
Tags that are associated with this line

Get invoice

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/get' \
--data-raw '{
    "invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja"
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$invoice = Trolley\Invoice::fetch($invoice_id);

print_r($invoice);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoice.find(invoice.id);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.balance.find("paypal")

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.invoice.get(invoice.id)

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String invoiceId = getInvoiceId();

//Fetch an Invoice
Invoice invoice = client.invoice.fetch(invoiceId);

System.out.println(invoice.getDescription());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoiceId = GetInvoiceId();

Invoice invoice = gateway.invoice.Get(invoiceId);

Console.WriteLine(invoice.description);

...

You can retrieve an invoice by sending POST /v1/invoices/get

HTTP Request

POST https://api.trolley.com/v1/invoices/get

Query Param Description
invoiceId
required
string
The id of the invoice to fetch

Example Response (200 Ok)

{
    "ok": true,
    "invoice": {
        "id": "I-HEG4x7Pb8VRkYZnu8Ja",
        "invoiceNumber": "101",
        "description": "",
        "status": "open",
        "externalId": null,
        "invoiceDate": "2021-10-13T00:00:00.000Z",
        "dueDate": "2021-11-12T00:00:00.000Z",
        "createdAt": "2021-10-13T14:26:21.053Z",
        "updatedAt": "2021-10-13T14:26:21.053Z",
        "totalAmount": {
            "value": "0.00",
            "currency": "CAD"
        },
        "paidAmount": {
            "value": "0.00",
            "currency": "CAD"
        },
        "dueAmount": {
            "value": "0.00",
            "currency": "CAD"
        },
        "tags": [],
        "lines": [],
        "recipientId": "R-XgtzXghfxx4Z2E4Y3R"
    }
}

Example Response (400 Bad Request - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "invalid_field",
            "message": "Value is invalid",
            "field": "invoiceId"
        }
    ]
}
HTTP Code Description
200 Successfully fetched the invoice
401 Invalid API key
500 Internal error
Error Code Description
invalid_api_key Invalid API key
internal_server_error Internal server errors

Search invoices

You can retrieve a list of invoices using the search API. If you send no search parameters, all the invoices in your merchant account will be returned.

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/search' \
--data-raw '{
    "recipientId": [
        "R-XgtzXghfxx4Z2E4Y3R"
        ],
    "page": 1,
    "pageSize": 5
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$searchResults = Trolley\Invoice::search(
    [
        "recipientId" 	=> [$recipient_id],
        "page" => 1,
        "pageSize" => 5
    ]);

print_r($searchResults);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoice.search(
    {
        invoiceIds: [
            invoice1.id,
            invoice2.id
        ]
    });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.balance.find("paypal")

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

# Search for invoices, receive a generator
response = client.invoice.search(
    {
        "externalIds": [
            f"{invoice.externalId}"
        ]
    })

# Iterate through the generator with auto pagination
for invoice in response:
    print(invoice)

# OR, search page by page
response = client.invoice.search_by_page(
    {
        "externalIds": [
            f"{invoice.externalId}"
        ]
    }, 2, 20)

# Iterate through the returned list
for invoice in response:
    print(invoice)
    
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

ArrayList<String> recipientIds = getRecipientIds();

// Search for Invoices by multiple recipientIds
Invoices invoices = client.invoice.search(
    Invoice.SearchBy.RECIPIENT_ID,  // Search by recipientId
    recipientIds,                   // list of recipientIds to search
    null                           // Any search parameters, none provided here
);

System.out.println(invoice.getDescription());

...

// Search for Invoices by multiple recipientIds, with pagination
Invoices invoices = client.invoice.search(
    Invoice.SearchBy.RECIPIENT_ID,  // Search by recipientId
    recipientIds,                   // list of recipientIds to search
    null,                           // Any search parameters, none provided here
    1,                              // Page number to fetch
    2                               // Items per page
);

System.out.println(invoice.getDescription());

...

// Available 'searchBy' filters
enum SearchBy {
    INVOICE_ID,
    RECIPIENT_ID,
    INVOICE_NUMBER,
    INVOICE_DATE,
    EXTERNAL_ID,
    TAGS;
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string recipientId = GetRecipientId();
string recipientId2 = GetAnotherRecipientId();

int page = 1;
int pageSize = 10;

// Search for invoices with manual pagination and optional search term
Invoices allInvoices = gateway.invoice.Search(
    SearchBy.RecipientId,       // Search by recipientId
    page,                          // Page number to fetch
    pageSize,                         // Items per page
    "<search_term>",            // Any search parameters
    recipientId1, recipientId2  // list of recipientIds to search
    );

// Get a List<> of Invoice to iterate over
List<Invoice> invoices = allInvoices.invoices;

// Use the Meta object to obtain page or index information
Meta meta = allInvoices.meta;

// Or, Search for an Invoice with auto-pagination
var invoices = gateway.invoice.Search(
    SearchBy.RecipientId,       // Search by recipientId
    "<search_term>",            // Items per page
    recipientId1, recipientId2  // list of recipientIds to search
    );

foreach (Invoice invoice in invoices)
{
    Console.WriteLine(invoice.description);
}

// Allowed values of SearchBy filters
enum SearchBy
{
    InvoiceId,
    Tags,
    ExternalId,
    RecipientId,
    InvoiceNumber,
    InvoiceDate
}

...

Example Response (200 Ok)

{
    "ok": true,
    "invoices": [
        {
            "id": "I-HEG4x7Pb8VRkYZnu8Ja",
            "invoiceNumber": "",
            "description": "Payment for artwork to Leonardo da Vinci",
            "status": "open",
            "externalId": "acme-inv-1002",
            "invoiceDate": "2022-06-07T03:20:01.870Z",
            "dueDate": null,
            "createdAt": "2022-06-07T03:20:01.860Z",
            "updatedAt": "2022-06-07T03:21:16.831Z",
            "totalAmount": {
                "value": "400.00",
                "currency": "EUR"
            },
            "paidAmount": {
                "value": "0.00",
                "currency": "EUR"
            },
            "dueAmount": {
                "value": "400.00",
                "currency": "EUR"
            },
            "tags": [],
            "lines": [
                {
                    "id": "IL-EtrPXL9aytREz2vdVgk",
                    "status": "open",
                    "itemUrl": null,
                    "description": "",
                    "unitAmount": {
                        "value": "200.00",
                        "currency": "EUR"
                    },
                    "quantity": "1",
                    "discountAmount": {
                        "value": "0.00",
                        "currency": "EUR"
                    },
                    "taxAmount": {
                        "value": "0.00",
                        "currency": "EUR"
                    },
                    "totalAmount": {
                        "value": "200.00",
                        "currency": "EUR"
                    },
                    "dueAmount": {
                        "value": "200.00",
                        "currency": "EUR"
                    },
                    "paidAmount": {
                        "value": "0.00",
                        "currency": "EUR"
                    },
                    "externalId": null,
                    "taxReportable": true,
                    "tags": [],
                    "category": "services",
                    "forceUsTaxActivity": false
                },
                {
                    "id": "IL-KUc9K2JsJ7Kuz5uVAH",
                    "status": "open",
                    "itemUrl": null,
                    "description": "Royalties for museum usage",
                    "unitAmount": {
                        "value": "200.00",
                        "currency": "EUR"
                    },
                    "quantity": "1",
                    "discountAmount": {
                        "value": "0.00",
                        "currency": "EUR"
                    },
                    "taxAmount": {
                        "value": "0.00",
                        "currency": "EUR"
                    },
                    "totalAmount": {
                        "value": "200.00",
                        "currency": "EUR"
                    },
                    "dueAmount": {
                        "value": "200.00",
                        "currency": "EUR"
                    },
                    "paidAmount": {
                        "value": "0.00",
                        "currency": "EUR"
                    },
                    "externalId": "acme-inv-royalties-1002",
                    "taxReportable": true,
                    "tags": [
                        "royalties",
                        "da vinci",
                        "it"
                    ],
                    "category": "royalties",
                    "forceUsTaxActivity": false
                }
            ],
            "recipientId": "R-XgtzXghfxx4Z2E4Y3R"
        }
    ],
    "meta": {
        "page": 1,
        "pages": 1,
        "records": 1
    }
}

Example Response (400 Bad Request - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "invalid_field",
            "message": "Value is invalid",
            "field": "invoiceId"
        }
    ]
}

HTTP Request

POST https://api.trolley.com/v1/invoices/search

Search Query Params Description
invoiceIds[]
optional
array
List of invoiceIDs
recipientId[]
optional
array
List of recipientIDs
invoiceNumber[]
optional
array
List of invoiceNumbers
invoiceDate
optional
string
The date the invoice was issued.
externalId
optional
array
List of external IDs
tags[]
optional
array
List of tags
page
optional
int
The page number (default: 1)
pageSize
optional
int
Number of records in a page (default: 10)
HTTP Code Description
200 List of Invoices as per the search terms supplied.
401 Invalid API key
500 Internal error
Error Code Description
invalid_api_key Invalid API key
internal_server_error Internal server errors

Update an invoice

To update an invoice for a recipient send a POST request to the /invoices/update endpoint and include the invoice details in the request body.

invoiceId is the required field in this request, to identify which invoice you want to update. Whatever other fields are sent with this request, will replace their old values for the invoiceId sent.

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/update' \
--data-raw '{
    "invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
    "description": "Payment to Leonardo da Vinci for artwork and other services"
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$updateInvoice = Trolley\Invoice::update([
    "invoiceId" 	=> $invoice->id,
    "description" 	=> "Update invoice through PHP SDK",
]);

print_r($updateInvoice);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoice.update(
    invoice.id,
    {
        description: "Updated Invoice",
        dueDate: "2022-01-01"
    });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.balance.find("paypal")

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.invoice.update(
    invoice.id, 
    {
        "description": "Updated Invoice description"
    })

print(response)

...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String invoiceId = getInvoiceId();

//Create a request object
Invoice invoice = new Invoice();

//Set request values
invoice.setExternalId("ext-id-456");

//Making network request and collecting response
Invoice invoiceResponse = client.invoice.create(invoice);
Invoice updatedInvoice = client.invoice.update(
            invoiceId,
            invoice
    );

System.out.println(invoice.getExternalId());

using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoiceId = GetInvoiceId();

Invoice invoiceRequest = new Invoice();
invoiceRequest.invoiceId = invoiceId;
invoiceRequest.description = "Update Invoice through .Net SDK";
invoice = gateway.invoice.Update(invoiceRequest);

Console.WriteLine(invoice.description);

...

Example Response (200 Ok)

{
    "ok": true,
    "invoice": {
        "id": "I-HEG4x7Pb8VRkYZnu8Ja",
        "invoiceNumber": "",
        "description": "Payment to Leonardo da Vinci for artwork and other services",
        "status": "open",
        "externalId": "acme-inv-1002",
        "invoiceDate": "2022-06-07T03:20:01.870Z",
        "dueDate": null,
        "createdAt": "2022-06-07T03:20:01.860Z",
        "updatedAt": "2022-06-07T03:45:40.615Z",
        "totalAmount": {
            "value": "400.00",
            "currency": "EUR"
        },
        "paidAmount": {
            "value": "0.00",
            "currency": "EUR"
        },
        "dueAmount": {
            "value": "400.00",
            "currency": "EUR"
        },
        "tags": [],
        "lines": [
            {
                "id": "IL-EtrPXL9aytREz2vdVgk",
                "status": "open",
                "description": "",
                "unitAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "quantity": "1",
                "discountAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "taxAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "totalAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "dueAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "paidAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "externalId": null,
                "taxReportable": true,
                "tags": [],
                "category": "services",
                "forceUsTaxActivity": false
            },
            {
                "id": "IL-KUc9K2JsJ7Kuz5uVAH",
                "status": "open",
                "description": "Royalties for Mona Lisa painting museum viewing",
                "unitAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "quantity": "1",
                "discountAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "taxAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "totalAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "dueAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "paidAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "externalId": "acme-inv-royalties-1002",
                "taxReportable": true,
                "tags": [
                    "royalties",
                    "da vinci",
                    "it"
                ],
                "category": "royalties",
                "forceUsTaxActivity": false
            }
        ],
        "recipientId": "R-XgtzXghfxx4Z2E4Y3R"
    }
}

Example Response (400 Bad Request - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "invalid_field",
            "message": "Value is invalid",
            "field": "invoiceId"
        }
    ]
}

HTTP Request

POST https://api.trolley.com/v1/invoices/update

Fields Description
invoiceId
required
string
The invoice ID
description
optional
string
A description of the invoice that you would like to add for internal reference.
externalId
optional
string
The invoice identifier used on your external platform.
invoiceDate
optional
string
The date the invoice was issued.
dueDate
optional
string
The date the invoice is due
tags
optional
array
List of tags associated with this invoice
HTTP Code Description
200 Invoice successfully updated
401 Invalid API key
404 Object not found
400 Validation error
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Update invoice lines

Update invoice line items for a given invoiceLineId inside an invoiceId. If the request is successful, the response contains the updated invoice with the remaining lines.

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/update-lines' \
--data-raw '{
    "invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
    "lines": [
        {
            "invoiceLineId": "IL-EtrPXL9aytREz2vdVgk",
            "description":"Payment for consultancy services",
            "unitAmount": {
                "value": "250",
                "currency": "EUR"
            }
        }
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$updatedInvoice = Trolley\InvoiceLine::update($newInvoice->id, [
    [
        "invoiceLineId" => $invoice_line_id,
        "description"	=> "updated invoice line",
        "unitAmount"    =>[
                "value"     => "150.00",
                "currency"  => "EUR"
        ]
    ]
]);

print_r($updatedInvoice);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoiceLine.update(
    invoice.id,
    {
        lines: [
            {
                invoiceLineId: invoiceLine.id,
                description: "updated line description"
            }
        ]
    });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.balance.find("paypal")

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.invoice_line.update(
    invoice.id,[
        {
            "invoiceLineId": invoice.lines[1]['id'],
            "unitAmount" :{
                "value" : "151.00",
                "currency" : "EUR"
            },
            "category": InvoiceLine.categories.refunds
        }
    ])

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String invoiceId = getInvoiceId();

//Create request object
InvoiceLine lineToUpdate = new InvoiceLine();
lineToUpdate.setInvoiceLineId(lineToUpdate.getId());
lineToUpdate.setUnitAmount(new Amount("500","USD"));

//Update an invoice line
Invoice invoice = client.invoiceLine.update(
    invoiceId, 
    lineToUpdate);

System.out.println(invoice.getLines().get(0).getAmount().getValue());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoiceId = GetInvoiceId();
string invoiceLineId = GetInvoiceLineId();

InvoiceLine invoiceLineRequest = new InvoiceLine();
invoiceLineRequest.invoiceLineId = invoiceLineId;
invoiceLineRequest.unitAmount = new Amount("150.00", "USD");
Invoice invoice = gateway.invoiceLine.Update(invoiceId, invoiceLineRequest);

Console.WriteLine(invoice.id);

...

Example Response (200 Ok)

{
    "ok": true,
    "invoice": {
        "id": "I-HEG4x7Pb8VRkYZnu8Ja",
        "invoiceNumber": "",
        "description": "Payment to Leonardo da Vinci for artwork and other services",
        "status": "open",
        "externalId": "acme-inv-1002",
        "invoiceDate": "2022-06-07T03:20:01.870Z",
        "dueDate": null,
        "createdAt": "2022-06-07T03:20:01.860Z",
        "updatedAt": "2022-06-07T04:15:37.039Z",
        "totalAmount": {
            "value": "450.00",
            "currency": "EUR"
        },
        "paidAmount": {
            "value": "0.00",
            "currency": "EUR"
        },
        "dueAmount": {
            "value": "450.00",
            "currency": "EUR"
        },
        "tags": [],
        "lines": [
            {
                "id": "IL-EtrPXL9aytREz2vdVgk",
                "status": "open",
                "description": "Payment for consultancy services",
                "unitAmount": {
                    "value": "250.00",
                    "currency": "EUR"
                },
                "quantity": "1",
                "discountAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "taxAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "totalAmount": {
                    "value": "250.00",
                    "currency": "EUR"
                },
                "dueAmount": {
                    "value": "250.00",
                    "currency": "EUR"
                },
                "paidAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "externalId": null,
                "taxReportable": true,
                "tags": [],
                "category": "services",
                "forceUsTaxActivity": false
            },
            {
                "id": "IL-KUc9K2JsJ7Kuz5uVAH",
                "status": "open",
                "description": "Royalties for Mona Lisa painting museum viewing",
                "unitAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "quantity": "1",
                "discountAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "taxAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "totalAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "dueAmount": {
                    "value": "200.00",
                    "currency": "EUR"
                },
                "paidAmount": {
                    "value": "0.00",
                    "currency": "EUR"
                },
                "externalId": "acme-inv-royalties-1002",
                "taxReportable": true,
                "tags": [
                    "royalties",
                    "da vinci",
                    "it"
                ],
                "category": "royalties",
                "forceUsTaxActivity": false
            }
        ],
        "recipientId": "R-XgtzXghfxx4Z2E4Y3R"
    }
}

Example Response (400 Bad Request - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "invalid_field",
            "message": "Value is invalid",
            "field": "invoiceId"
        }
    ]
}

HTTP Request

POST https://api.trolley.com/v1/invoices/update-lines

Fields Description
invoiceId
required
string
id of invoice whose lines need to be updated.
lines[]
required
array
Array of line updates
lines[].invoiceLineId
required
array
Line identifier
lines[].unitAmount.value
required
string
The new unit amount (both value and currency must be provided)
lines[].unitAmount.currency
required
string
The new unit amount (both value and currency must be provided)
lines[].quantity
optional
string
Quantity
lines[].description
optional
string
Line item description
lines[].externalId
optional
string
External ID in your system
lines[].taxReportable
optional
boolean
Is US Tax activity reporting
lines[].forceUsTaxActivity
optional
boolean
Is US Tax activity for US reporting
lines[].tags
optional
[]string
list of string tags
lines[].category
optional
string
Payment category
HTTP Code Description
200 Invoice Line updated successfully
401 Invalid API key
404 Object not found
400 Validation error
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Delete an invoice

Delete a list of invoices whose IDs are supplied. If you supply an invoiceIds value which doesn’t exist, it will be ignored.

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/delete' \
--data-raw '{
    "invoiceIds": [
        "I-HEG4x7Pb8VRkYZnu8Ja",
        "I-S2rFVepQpg4T2Ew3hhB"
        ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$deleteInvoice = Trolley\Invoice::delete($invoice_id);

print_r($deleteInvoice);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoice.remove(invoice.id);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.invoice.delete(invoiceIds: [
    invoice1.id,
    invoice2.id
])

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.invoice.delete(
    [
        f'{invoice1.id}',
        f'{invoice2.id}'
    ])

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String invoiceId = getInvoiceId();

//Delete an Invoice
boolean deleteResult = client.invoice.delete(invoiceId);

System.out.println("Delete Result: "+deleteResult);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoiceId = GetInvoiceId();

bool delResult = gateway.invoice.Delete(invoiceId);

Console.WriteLine(delResult);

...

Example Response (200 Ok)

{
    "ok": true
}

Example Response (400 Bad Request - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "invalid_field",
            "message": "Value is invalid",
            "field": "invoiceId"
        }
    ]
}

HTTP Request

POST https://api.trolley.com/v1/invoices/delete

Fields Description
invoiceIds[]
required
[]string
List of invoice IDs
HTTP Code Description
200 Invoices successfully deleted (invoice IDs that are not found will be ignored)
401 Invalid API key
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
invalid_api_key Invalid API key
internal_server_error Internal server errors

Delete an invoice line

Delete multiple lines, represented by invoiceLineIds from a given invoice. Any invoiceLineId which is not found will be ignored.

After a successful delete operation, the remaining invoice object is returned.

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/delete-lines' \
--data-raw '{
    "invoiceId": "I-S2rFVepQpg4T2DGzEw3hhB",
    "invoiceLineIds": [
        "IL-EtrPXL9aytREz2vdVgk",
        "IL-KUc9K2JsJ7Kuz5uVAH"
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$invoice = Trolley\InvoiceLine::delete($invoice_id,
    [
        $invoice_line_id_1,
        $invoice_line_id_2
    ]);

print_r($invoice);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoiceLine.delete(invoice.id, [invoiceLine.id]);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.invoice.delete_line(
    invoiceId: invoice.id, 
    invoiceLineIds: [
        invoice_line.id
        ])

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.invoice_line.delete(
            invoice.id, 
            [
                invoice.lines[0]['id']
            ])

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String invoiceId = getInvoiceId();
String invoiceLineId = getInvoiceLineId();

//Delete an invoice line
boolean deleteResult = client.invoiceLine.delete(invoiceId, invoiceLineId);

System.out.println("Delete result: "+deleteResult);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoiceId = GetInvoiceId();
string invoiceLineId1 = GetFirstInvoiceLineId();
string invoiceLineId2 = GetSecondInvoiceLineId();

//Delete one or multiple invoice lines
Invoice invoice = gateway.invoiceLine.Delete(invoiceId,
                invoiceLineId1,
                invoiceLineId2);

Console.WriteLine(invoice.id);

...

Example Response (200 Ok)

{
    "ok": true,
    "invoice": {
        "id": "I-HEG4x7Pb8VRkYZnu8Ja",
        "invoiceNumber": "",
        "description": "Payment for artwork to Leonardo da Vinci",
        "status": "open",
        "externalId": "acme-inv-1002",
        "invoiceDate": "2022-06-07T04:36:23.737Z",
        "dueDate": null,
        "createdAt": "2022-06-07T04:36:23.733Z",
        "updatedAt": "2022-06-07T04:41:53.830Z",
        "totalAmount": {
            "value": "0.00",
            "currency": "USD"
        },
        "paidAmount": {
            "value": "0.00",
            "currency": "USD"
        },
        "dueAmount": {
            "value": "0.00",
            "currency": "USD"
        },
        "tags": [],
        "lines": [],
        "recipientId": "R-XgtzXghfxx4Z2E4Y3R"
    }
}

Example Response (404 Not Found - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "not_found",
            "message": "unable to find invoice"
        }
    ]
}

HTTP Request

POST https://api.trolley.com/v1/invoices/delete-lines

Fields Description
invoiceId
required
string
The invoice ID whose lines need to be deleted.
invoiceLineIds[]
required
[]string
List of invoice line IDs to delete
HTTP Code Description
200 Invoice lines successfully deleted (Invoice line IDs that are not found by the given invoice will be ignored)
401 Invalid API key
404 Invoice not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Create an invoice payment

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/payment/create' \
--data-raw '{
    "batchId": "B-TRk943e5osL1t4ipwsT",
    "ids":[
        {
            "invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
            "invoiceLineId":"IL-EtrPXL9aytREz2vdVgk",
            "amount":{
                "value":"200.00",
                "currency":"EUR"
            }
        }
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$invoicePayment = Trolley\InvoicePayment::create([
    [
        "invoiceId" => $invoice_id,
        "invoiceLineId" => $invoice->lines[0]->id,
        "amount" => [
            "value" => $invoice->lines[0]->unitAmount["value"],
            "currency" => $invoice->lines[0]->unitAmount["currency"]
        ]
    ]
]);

print_r($invoicePayment);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoicePayment.create(
    {
        ids: [
            {
                invoiceId: invoice.id,
                amount: {
                    currency: "USD",
                    value: "100"
                }
            },
        ],
    });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.invoice_payment.create(
    ids: [
        invoiceId: invoice.id
        ])

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

invoice_payment = client.invoice_payment.create([
        {
            "invoiceId": invoice.id,
            "amount":{
                "value":"11.00",
                "currency":"EUR"
            }
        }
    ])

print(invoice_payment)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String invoiceId = invoice.getId();
String invoiceLineId = invoice.getLines().get(0).getId();

//Create a new Invoice Payment
InvoicePaymentPart paymentPart = new InvoicePaymentPart();
paymentPart.setInvoiceId(invoiceId);
paymentPart.setInvoiceLineId(invoiceLineId);
paymentPart.setAmount(new Amount("50", "USD"));

// Create a new Invoice payment
InvoicePayment invoicePayment = client.invoicePayment.create(null, paymentPart);

// Or, Create a new Invoice payment and add it to a batch (optional)
InvoicePayment invoicePayment = client.invoicePayment.create(batchId, paymentPart);

System.out.println(invoicePayment.getPaymentId());

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoiceId = GetInvoiceId();
string invoiceLineId = GetInvoiceLineId();

InvoicePaymentPart invoicePaymentPartRequest = new InvoicePaymentPart();
invoicePaymentPartRequest.invoiceId = invoiceId;
invoicePaymentPartRequest.invoiceLineId = invoiceLineId;
invoicePaymentPartRequest.amount = new Amount("100.00", "USD");

// Create an Invoice Payment in a new batch
InvoicePayment invoicePayment = gateway.invoicePayment.Create(null, invoicePaymentPartRequest);

// Create an Invoice Payment in an existing batch
string batchId = GetBatchId();
InvoicePayment invoicePayment = gateway.invoicePayment.Create(batchId, invoicePaymentPartRequest);

Console.WriteLine(invoicePayment.id);

...

Example Response (200 Ok)

{
    "ok": true,
    "invoicePayment": {
        "batchId": "B-TRk943e5osL1t4ipwsT",
        "paymentId": "P-BCZR5HYHKPRpvfSKYKetsY",
        "invoicePayments": [
            {
                "invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
                "invoiceLineId": "IL-EtrPXL9aytREz2vdVgk",
                "paymentId": "P-BCZR5HYHKPRpvfSKYKetsY",
                "amount": {
                    "value": "200.00",
                    "currency": "EUR"
                }
            }
        ]
    }
}

Example Response (404 Not Found - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "not_found",
            "message": "invoiceId=I-KSb9qn3WwCEgjTLJmf"
        }
    ]
}

To create an invoice payment for an invoice send a POST request to the /invoices/payment/create endpoint and include the invoice details in the request body.

If you already have a batch open, you can provide it’s batchId to add payments related to this invoice, to this batch.

If you don’t provide a batchId, this API call will create a new batch and add a payment to it. The batch’s batchId will be returned in the response.

You should process the batch after this call for the payments to start processing.

HTTP Request

POST https://api.trolley.com/v1/invoices/payment/create

Fields Description
batchId
optional
string
Batch to add the payments to
ids[]
required
array
A list of invoiceId or invoiceLineIds to make payment against
ids[].invoiceId
conditional
string
Either the invoiceId or invoiceLineId must be provided
ids[].invoiceLineId
conditional
string
Either the invoiceId or invoiceLineId must be provided
ids[].amount.value
optional
string
The value (e.g. “100.00”) to pay. Note if the value is provided, currency must be provided
ids[].amount.currency
optional
string
Currency to pay in - must match the invoice currency
HTTP Code Description
200 Payment successfully initiated
401 Invalid API key
404 Object not found
400 Validation error
500 Internal error

Invoice Statuses

When you create an invoice or create a payment to clear it, depending on circumstances the invoice and invoice lines can have different statuses. Here’s a list of those statuses and what they mean:

Status Description
open The invoice is open, no payment has been initiated.
pending The invoice line items have been added to a batch, or a payment is currently processing, but not completed.
partially_paid Some line items have been paid completely, while others are still pending, or partially paid. Invoice status will also be partially_paid.
paid All line items have been paid completely. Invoice and Invoice Lines, both, are marked as paid.
void Sent payments were returned.

After the invoice has been marked as paid, you won’t be able to edit the invoice line items.

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Update an invoice payment

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/payment/update' \
--data-raw '{
    "ids": [
        {
            "invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
            "invoiceLineId": "IL-EtrPXL9aytREz2vdVgk",
            "paymentId": "P-BCZR5HYHKPRpvfSKYKetsY",
            "amount": {
                "value": "150.00",
                "currency": "EUR"
            }
        }
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$updatedInvoicePayment = Trolley\InvoicePayment::update([
    "invoiceLineId" => $invoice->lines[0]->id,
    "paymentId"     => $invoicePayment[0]->paymentId,
    "amount"        => [
            "value"     => "102.10",
            "currency"  => $invoice->lines[0]->unitAmount["currency"]
    ]
]);

print_r($updatedInvoicePayment);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoicePayment.update(
    {
    paymentId: payment.id,
    invoiceLineId: invoiceLine.id,
    amount: {
        currency: "USD",
        value: "200"
        }
    });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.balance.find("paypal")

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.invoice_payment.update(
    {
        "invoiceId": invoice.id,
        "invoiceLineId": invoice.lines[0]['id'],
        "paymentId": invoice_payment.paymentId,
        "amount":{
            "value":"21.00",
            "currency":"EUR"
        }
    }
)

print(response)

...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String invoiceId = getInvoiceId();
String invoiceLineId = getInvoiceLineId();
String invoicePaymentId = getInvoicePaymentId();

//Create request object
InvoicePaymentPart paymentPart = new InvoicePaymentPart();

paymentPart.setInvoiceId(invoiceId);
paymentPart.setInvoiceLineId(invoiceLineId);
paymentPart.setPaymentId(invoicePaymentId);
paymentPart.setAmount(new Amount("10","USD"));

// Update an invoice payment
boolean paymentUpdateResult = client.invoicePayment.update(paymentPart);

System.out.println("Payment Update Result: "+paymentUpdateResult);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoiceId = GetInvoiceId();
string invoiceLineId = GetInvoiceLineId();
string invoicePaymentId = GetInvoicePaymentId();

InvoicePaymentPart invoicePaymentPartRequest = new InvoicePaymentPart();
invoicePaymentPartRequest.invoiceId = invoiceId;
invoicePaymentPartRequest.paymentId = invoicePaymentId;
invoicePaymentPartRequest.invoiceLineId = invoiceLineId;
invoicePaymentPartRequest.amount = new Amount("100.00", "USD");

// Update an invoice payment whose id has been set in the request object
InvoicePayment invoicePayment = gateway.invoicePayment.Update(invoicePaymentPartRequest);

Console.WriteLine(invoicePayment.amount);

...

Example Response (200 Ok)

{
    "ok": true,
    "invoicePayment": {
        "batchId": "B-TRk943e5osL1t4ipwsT",
        "paymentId": "P-BCZR5HYHKPRpvfSKYKetsY",
        "invoicePayments": [
            {
                "invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
                "invoiceLineId": "IL-EtrPXL9aytREz2vdVgk",
                "paymentId": "P-BCZR5HYHKPRpvfSKYKetsY",
                "amount": {
                    "value": "150.00",
                    "currency": "EUR"
                }
            }
        ]
    }
}

Example Response (400 Bad Request - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "invalid_field",
            "message": "Value is invalid",
            "field": "invoiceId"
        }
    ]
}

Update an already existing Payment’s value.

HTTP Request

POST https://api.trolley.com/v1/invoices/payment/update

Fields Description
ids[]
required
array
A list of invoiceId or invoiceLineIds to make payment against
ids[].invoiceId
required
string
Either the invoiceId or invoiceLineId must be provided
ids[].invoiceLineId
required
string
Either the invoiceId or invoiceLineId must be provided
ids[].amount.value
required
string
The value (e.g. “100.00”) to pay. Note if the value is provided, currency must be provided
ids[].amount.currency
required
string
Currency to pay in - must match the invoice currency
HTTP Code Description
200 Payment successfully updated
401 Invalid API key
404 Object not found
400 Validation error
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Search invoice payments

Find all invoice and payment combinations.

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/payment/search' \
--data-raw '{
    "paymentIds": [
        "P-BCZR5HYHKPRpvfSKYKetsY",
        "P-54aV1FuFtAx9VKpPNFz"
    ],
    "invoiceIds": [
        "I-HEG4x7Pb8VRkYZnu8Ja",
        "I-S2rFVepQpg4T2Ew3hhB"
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$searchResults = Trolley\InvoicePayment::search(
    [
        $invoice_payment_id
    ], 
    [
        $invoice_id
    ]);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoicePayment.search(
    { 
    invoiceIds: [
            invoice1.id,
            invoice2.id
        ]
    });

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.balance.find("paypal")

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

# Search for invoice payments
invoice_payments = client.invoice_payment.search(
    [
        invoice_payment.paymentId
    ])

# Iterate through the returned list
for payment in invoice_payments:
    print(payment)

...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

List<String> paymentIds = getInvoicePaymentIds();
List<String> invoiceIds = getInvoiceIds();

InvoicePayments invoicePayments = client.invoicePayment.search(
    paymentIds, invoiceIds);

for(InvoicePaymentPart invoicePaymentPart : invoicePayments.getInvoicePaymentParts()){
    System.out.println(invoicePaymentPart.getPaymentId());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoiceId = GetInvoiceId();
string paymentId = GetPaymentId();

int page = 1;
int pageSize = 10;

// Search for Invoice Payments with manual pagination
InvoicePayments allInvoicePayments = gateway.invoicePayment.Search(
    new string[] { invoiceId }, 
    new string[] { paymentId }, 
    page, 
    pageSize);

// Get a List<> of InvoicePayment to iterate over
List<InvoicePayment> invoicePayments = allInvoicePayments.invoicePayments;

// Use the Meta object to obtain page or index information
Meta meta = allInvoicePayment.meta;

// Or, search for Invoice Payments with auto-pagination
var invoicePayments = gateway.invoicePayment.Search(
    new string[] { invoiceId }, 
    new string[] { paymentId });

foreach(InvoicePayment invoicePayment in invoicePayments)
{
    Console.WriteLine(invoicePayment.paymentId);
}

...

Example Response (200 Ok)

{
    "ok": true,
    "invoicePayments": [
        {
            "invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
            "invoiceLineId": "IL-EtrPXL9aytREz2vdVgk",
            "paymentId": "P-BCZR5HYHKPRpvfSKYKetsY",
            "amount": {
                "value": "150.00",
                "currency": "EUR"
            }
        }
    ],
    "meta": {
        "page": 1,
        "pages": 1,
        "records": 1
    }
}

Example Response (400 Bad Request - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "invalid_field",
            "message": "Value is invalid",
            "field": "invoiceId"
        }
    ]
}

HTTP Request

POST https://api.trolley.com/v1/invoices/payment/search

Fields Description
paymentIds
optional
[]string
List of payment identifiers
invoiceIds
optional
[]string
List of invoice identifiers
HTTP Code Description
200 Search request successful
401 Invalid API key
404 Object not found
400 Validation error
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Delete an invoice payment

Remove the association between a payment and an invoice. Note: if the payment is processed then this will not change the value of the payment.

Example Request

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-L -X POST 'https://api.trolley.com/v1/invoices/payment/delete' \
--data-raw '{
    "paymentId": "P-BCZR5HYHKPRpvfSKYKetsY",
    "invoiceLineIds": [
        "IL-EtrPXL9aytREz2vdVgk"
    ]
}'
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$deletedInvoicePayments = Trolley\InvoicePayment::delete($invoice_payment_id,
    [
        $invoice_line_id_1,
        $invoice_line_id_2
    ]);

print_r($deletedInvoicePayments);
?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.invoicePayment.delete(
    { 
        paymentId: payment.id,
        invoiceLineIds: [
            lineId1,
            lineId2
        ]
    }
);

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.invoice_payment.delete(
    paymentId: invoice_payment.paymentId, 
    invoiceLineIds: [
            invoice_line1.id,
            invoice_line2.id
        ])

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

response = client.invoice_payment.delete(
    invoice_payment.paymentId, 
    [
        invoice.lines[0]['id']
    ])

print(response)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

String invoicePaymentId = getInvoicePaymentId();
String invoiceLineId = getInvoiceLineId();

//Delete an Invoice Payment
boolean deleteResult = client.invoicePayment.delete(
            invoicePaymentId, 
            invoiceLineId
        );

System.out.println("Delete result: "+deleteResult);

// Or, Delete multiple Invoice Payments
List<String> invoiceLineIds = getInvoiceLineIds();

boolean deleteResult = client.invoicePayment.delete(
            invoicePaymentId, 
            invoiceLineIds
        );

System.out.println("Delete result: "+deleteResult);

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

string invoicePaymentId = GetInvoicePaymentId();
string invoiceLineId = GetInvoiceLineId();

bool paymentDelResult = gateway.invoicePayment.Delete(invoicePaymentId, invoiceLineId);

Console.WriteLine(paymentDelResult);

...

Example Response (200 Ok)

{
    "ok": true
}

Example Response (404 Not Found - error code)

{
    "ok": false,
    "errors": [
        {
            "code": "not_found",
            "message": "payment not found"
        }
    ]
}

HTTP Request

POST https://api.trolley.com/v1/invoices/payment/delete

Fields Description
paymentId
required
string
The payment identifier
invoiceLineIds
required
[]string
List of payment line identifiers

Example response (200 Ok)

{
  "ok": true
}
HTTP Code Description
200 Invoice payment(s) successfully deleted (Invoice line IDs that are not found by the given payment will be ignored)
401 Invalid API key
404 Payment/Invoice not found
400 Validation error
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object doesn’t exist
invalid_api_key Invalid API key
internal_server_error Internal server errors

Balances


Balances relates to your business (merchant) account balance. You can retrieve the current balances of your (merchant) Trolley accounts, as well as your business PayPal account if it has been added. Balances are displayed with their associated currency.

Note that Trolley does not hold balances for individual recipients. Balance always refers to the merchant’s funding account balances. In the situation where a payment that was sent to a recipient is returned as an error, such as a mis-match of the name on the recipient’s bank account, then the returned funds will be added back to your merchant account balance. It would not be added to a recipient account balance/wallet balance. (We would also flag that payment as a returned payment so you can resolve it).

Retrieve all account balances

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/balances' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$allBalances = Trolley\Balance::all();

print_r($allBalances);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.balances.all();

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.balance.find("all")

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

balances = client.balances.get_all_balances()

print(balances)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

// Get All Account Balances
List<Balances> balances = client.balances.getAllBalances();

for (Balances balance : balances) {
    System.out.println(balance.getType());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

List<Balance> balances = gateway.balances.GetAllBalances();
foreach (Balance balance in balances){
      Console.WriteLine(balance.amount);
  }

...

Example response (200 Ok)

{
  "ok": true,
  "balances": {
    "paypal": {
      "primary": false,
      "amount": "1000.00",
      "currency": "USD",
      "type": "paypal",
      "accountNumber": null
    },
    "GBP": {
      "primary": false,
      "amount": "761316.01",
      "currency": "GBP",
      "type": "paymentrails",
      "accountNumber": "0000846"
    },
    "EUR": {
      "primary": false,
      "amount": "790473.12",
      "currency": "EUR",
      "type": "paymentrails",
      "accountNumber": "0000847"
    },
    "USD": {
      "primary": true,
      "amount": "1463430.27",
      "currency": "USD",
      "type": "paymentrails",
      "accountNumber": "0000848"
    },
    "CAD": {
      "primary": false,
      "amount": "10000.89",
      "currency": "CAD",
      "type": "paymentrails",
      "accountNumber": "0000867"
    }
  }
}

Retrieves the balances of your (merchant) Trolley account as well as your PayPal account, if setup.

HTTP Request

GET https://api.trolley.com/v1/balances

HTTP Code Description
200 Batch successfully updated
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object not found
internal_server_error Internal server errors

Retrieve Trolley account balance

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/balances/paymentrails' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$trolleyBalance = Trolley\Balance::getTrolleyAccountBalance();

print_r($trolleyBalance);

?>
require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.balance.find("paymentrails")

print response

// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.balances.find("paymentrails");

console.log(response);

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

balances = client.balances.get_trolley_balance()

print(balances)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

// Get Trolley Account Balances
List<Balances> balances = client.balances.getTrolleyAccountBalances();

for (Balances balance : balances) {
    System.out.println(balance.getType());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

List<Balance> balances = gateway.balances.GetTrolleyBalances();
foreach (Balance balance in balances){
      Console.WriteLine(balance.amount);
  }

...

Example response (200 Ok)

{
  "ok": true,
  "balances": {
    "GBP": {
      "primary": false,
      "amount": "761316.01",
      "currency": "GBP",
      "type": "paymentrails",
      "accountNumber": "0000846"
    },
    "EUR": {
      "primary": false,
      "amount": "790473.12",
      "currency": "EUR",
      "type": "paymentrails",
      "accountNumber": "0000847"
    },
    "USD": {
      "primary": true,
      "amount": "1463430.27",
      "currency": "USD",
      "type": "paymentrails",
      "accountNumber": "0000848"
    },
    "CAD": {
      "primary": false,
      "amount": "10000.89",
      "currency": "CAD",
      "type": "paymentrails",
      "accountNumber": "0000867"
    }
  }
}

Retrieves the balances of your (merchant) Trolley accounts.

HTTP Request

GET https://api.trolley.com/v1/balances/paymentrails

HTTP Code Description
200 Batch successfully updated
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object not found
internal_server_error Internal server errors

Retrieve PayPal account balance

curl \
-H 'Authorization: prsign <ACCESS-KEY>:<SIGNATURE>' \
-H 'Content-Type: application/json' \
-H 'X-PR-Timestamp: <timestamp>' \
-X GET 'https://api.trolley.com/v1/balances/paypal' \
<?php
use Trolley;

Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');

$paypalBalance = Trolley\Balance::getPaypalAccountBalance();

print_r($paypalBalance);

?>
// Running in Node.js environment

const trolley = require("trolley");

const client = trolley.connect({
  key: "YOUR_ACCESS_KEY",
  secret: "YOUR_SECRET_KEY"
});

const response = await client.balances.find("paypal");

console.log(response);

require 'trolley'

client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')

response = client.balance.find("paypal")

print response

from trolley.configuration import Configuration

client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')

balances = client.balances.get_paypal_balance()

print(balances)
...

Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);

// Get PayPal Account Balances
List<Balances> balances = client.balances.getPaypalAccountBalances();

for (Balances balance : balances) {
    System.out.println(balance.getType());
}

...
using Trolley.Types;
using Trolley;

...

Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");

List<Balance> balances = gateway.balances.GetPaypalBalances();
foreach (Balance balance in balances){
      Console.WriteLine(balance.amount);
  }

...

Example response (200 Ok)

{
  "ok": true,
  "balances": {
    "paypal": {
      "primary": false,
      "amount": "1000.00",
      "currency": "USD",
      "type": "paypal",
      "accountNumber": null
    }
  }
}

Retrieves the balances of your (merchant) PayPal accounts. You must first setup PayPal as a payout method.

HTTP Request

GET https://api.trolley.com/v1/balances/paypal

HTTP Code Description
200 Batch successfully updated
401 Invalid API key
404 Object not found
500 Internal error

Errors

This table lists the expected errors that this method could return. However, other errors can be returned in the case where the service is down or other unexpected factors affect processing. Callers should always check the value of the ok params in the response.

Error Code Description
not_found Object not found
internal_server_error Internal server errors

Webhooks


Overview & Setup

Example Webhook Payload

{
  "model": "recipient",
  "action": "updated",
  "body": {
    "recipient": {
      "id": "R-1a2B3c4D5e6F7g8H9i0J1k",
      "referenceId": "jsmith11@example.com",
      "email": "jsmith11@example.com",
      "name": "Richard Hendricks",
      "lastName": "Hendricks",
      "firstName": "Richard",
      "type": "individual",
      "status": "active",
      "language": "en",
      "complianceStatus": "verified",
      "dob": null,
      "updatedAt": "2017-03-20T19:06:40.937Z",
      "createdAt": "2017-03-17T20:10:45.818Z",
      "gravatarUrl": "https://s3.amazonaws.com/static.api.trolley.com/icon_user.svg",
      "placeOfBirth": null,
      "ssn": null,
      "tags": [],
      "passport": "",
      "payoutMethod": "bank-transfer",
      "compliance": {
        "status": "verified",
        "checkedAt": "2017-03-20T19:06:23.916Z"
      },
      "accounts": [
        {
          "accountHolderName": "Richard Hendricks",
          "bankId": "123",
          "currency": "CAD",
          "country": "CA",
          "bankName": "TD CANADA TRUST",
          "branchId": "47261",
          "accountNum": "*****47"
        }
      ],
      "address": {
        "street1": "Apt# 14",
        "street2": null,
        "city": "",
        "postalCode": "H3WXXX",
        "phone": "",
        "country": "CA",
        "region": "QC"
      },
      "primaryCurrency": "CAD"
    }
  }
}

While most connections in the web world are from you to a server, webhooks are the rare type of connection that server makes towards you!

We use webhooks to communicate to your servers events or updates that happen to different objects, for example payment is processed or returned. We do this by sending HTTP POST calls to your services hosted on your servers.

Adding a Webhook

A GIF showing the flow of going to Webhooks in Dashboard

Opening Webhooks Section

To add a new webhook in sandbox or live environment:

  1. Go to Dashboard > Settings > Webhooks.
  2. Click on New Webhook Button on the top right.
  3. Provide the URL of the service which will listen to these webhooks, and select the Models and their respective Actions you want to listen to.

The service whose URL you’ll provide will start receiving HTTP POST requests whenever the selected action(s) occurs on the model you selected.
Make sure your service is accessible at the URL you provide, and can handle HTTP POST requests.

Workings of a Webhook

Trolley webhooks will callback on urls, that you provide during configuration, with a POST request and a payload similar to the example.
In this case the webhook is to signal that a new payment has been created. The payload contains the “model” and “action” objects, telling you the type of object and actions that fired the event.

It also contains a body object which specified the affected model instance(s). Inside the body you will find the model object. The model object is serialized in the same format as the other endpoints so refer to documentation for that model for the full format.

View details of a Webhook

When you go to Dashboard > Settings > Webhooks , you see all your existing webhooks, if any, for the selected mode (sandbox or live).

A GIF showing the flow of viewing all webhooks

Viewing details of a Webhook and Webhook logs

Click on any existing webhook to view/change it’s details.

You can also go to Dashboard > Settings > Webhooks > Webhooks Logs to check logs of all the webhooks sent to your service so far, along with the request body, HTTP codes, and responses to a particular webhook call.

Types of Actions

Here is the list of Models and their respective Actions that you can listen to:

Models Actions
All Models All Actions
User 1. All Actions
2. Updated
3. Deleted
4. Created
5. Password Reset
Recipient 1. All Actions
2. Created
3. Updated
4. Deleted
5. Screened for Compliance
Recipient Account 1. All Actions
2. Created
3. Updated
4. Deleted
Payment 1. All Actions
2. Created
3. Updated
4. Deleted
5. Processed
6. Failed
7. Returned
Batch 1. All Actions
2. Created
3. Updated
4. Deleted
5. Processing
6. Processed
7. Failed
Funds 1. All Actions
2. Deposited

Verifying Webhooks

While processing the incoming webhook requests, you can use the different headers found in a webhook call to verify different aspects of a particular webhook request.

Webhook Headers

To make it easy for your service to have both security and robustness we provide three additional headers for you:

Verification of requests

To verify the incoming webhook request and make sure it’s from Trolley servers, you can use the value of the X-PaymentRails-Signature header to compare the hash of the request.

As you can see in the sample of the header, it contains a string formatted with comma , separated values where the t=1613397437 value will contain the current timestamp of when the webhook was sent and the v1 value will contain the signature you can compare the hash of the request with.

# Sample webhook headers

  X-PaymentRails-Created: 2021-02-15T13:55:15.690Z
  X-PaymentRails-Delivery: 33e72212-ba53-4a22-bce0-3cb09077e87c
  X-PaymentRails-Signature: t=1613397437,v1=29814ed539eedd76ef776fc9d3827591ba9e4ed8eb326525b3e2e8233b6a90d7
import hmac

...
header_signature_values = header['X-PaymentRails-Signature'].split(',')
t = header_signature_values[0].split('=')[1]
v1 = header_signature_values[1].split('=')[1]
digest = hmac.new(your_hmac_key, t + post_body_payload, hashlib.sha256).hexdigest()
if digest === v1:
 print("webhook valid")
...
//C# on .Net Core
using System.Security.Cryptography;

...
string[] headerSignatureValues = context.Request.Headers["X-Paymentrails-Signature"].ToString().Split(",");

var t = headerSignatureValues[0].Split('=')[1];
var v1 = headerSignatureValues[1].Split('=')[1];

var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(yourHmacKey));
var digest = BitConverter.ToString(hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(t + postBodyPayload)));
digest = digest.Replace("-", "").ToLower();

if (digest.Equals(v1))
    return "webhook valid";
...
# Ruby on Rails
require 'digest'
require 'openssl'

...
headerSignatureValues = headers["X-Paymentrails-Signature"].split(",")

t = headerSignatureValues[0].split('=')[1];
v1 = headerSignatureValues[1].split('=')[1];

digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), your_hmac_key, t + postBodyPayload)

if digest == v1
  puts "webhook valid"
end
...
// nodejs environment
const crypto = require("crypto");

...
headerSignatureValues = req.headers['X-Paymentrails-Signature'].split(","); 

t = headerSignatureValues[0].split('=')[1];
v1 = headerSignatureValues[1].split('=')[1];

const hmac = crypto.createHmac("sha256", yourHmacKey);
hmac.update(`${t}${postBodyPayload}`);
const digest = hmac.digest("hex");

if (digest === v1)
  console.log("webhook valid");
...
// PHP 7.4.x on Apache
...
$header_signature_values = explode(",",$_SERVER['HTTP_X_PAYMENTRAILS_SIGNATURE']); 

$t = explode("=",$header_signature_values[0])[1];
$v1 = explode("=",$header_signature_values[1])[1];

$digest = hash_hmac("sha256", $t.$post_body_payload, $your_hmac_key);

if($digest == $v1){
    echo "webhook valid";
}
...

To verify the request, follow these steps:

  1. Extract values of t and v1 from the X-PaymentRails-Signature header.
  2. Concatenate timestamp value found in t with the raw POST body that you received with the request.
  3. Calculate the sha256 hash of the concatenated value using the hmac key you get for each webhook from Dashboard.

A GIF showing the flow of adding a new webhook

Get the HMAC key for a webhook

Compare the calculated hash with the signature you received in the header (v1). If they match then the request is verified.

Some simple code to verify the values is demonstrated:

Webhook Uniqueness

Webhooks may be delivered multiple times for the same object. If you need to check the idempotency of a webhook we provide a X-PaymentRails-Delivery delivery header which contains an unique ID that can be used to check for unique delivery.

Note: It is possible to receive more than one webhook callback for one action. For instance, it’s possible that a single payment update on the UI or API may trigger two “payment update” events for a receiver of the webhook.

Retries after Failure

If a webhook delivery fails with a non-200 HTTP response, we will retry sending it again multiple times using an exponential backoff mechanism.

The max number of tries are:

Sandbox Live
4 retries 10 retries

With an exponential backoff strategy our first webhook retry is 8 minutes after a webhook call fails, second is after 16 minutes of first retry, third is after 32 minutes of second retry, and so on.

This is further detailed below where you can view the delay timing per attempt.

Retry attempt Delay Minutes
1 8
2 16
3 32
4 64
5 128
6 256
7 480
8 480
9 480
10 480

Testing Webhooks

To test webhooks during development you can receive web hooks using tools such as Webhook Inbox. Webhook inbox provides you with a webhook URL that you can use to watch web hook callbacks as they come in. This can be useful when trying to understand how webhook callbacks are formatted.

Once you’ve written your code you can get webhook callbacks on your workstation using tools such as Ultrahook. Ultrahook will allow your workstation or laptop to receive web hooks even it’s behind firewalls or NATs. Ultrahook can’t help you if your machine is off, so remember to plug it in and turn it on.

References


List of Countries and Territories

Trolley uses ISO 3166 standard ALPHA-2 codes to represent countries. The following is the list of supported countries.

Country Name Country ISO 3166-2
Afghanistan AF
Albania AL
Algeria DZ
American Samoa AS
Andorra AD
Angola AO
Anguilla AI
Antigua & Barbuda AG
Argentina AR
Armenia AM
Aruba AW
Australia AU
Austria AT
Azerbaijan AZ
Bahamas BS
Bahrain BH
Bangladesh BD
Barbados BB
Belarus BY
Belgium BE
Belize BZ
Benin BJ
Bermuda BM
Bhutan BT
Bolivia BO
Bonaire, Sint Eustatius & Saba BQ
Bosnia & Herzegovina BA
Botswana BW
Brazil BR
Brunei BN
Bulgaria BG
Burkina Faso BF
Burundi BI
Cambodia KH
Cameroon CM
Canada CA
Cayman Islands KY
Central African Republic CF
Chad TD
Chile CL
China CN
Christmas Island CX
Colombia CO
Comoros KM
Congo (Brazzaville) CG
Congo (Kinshasa) CD
Cook Islands CK
Costa Rica CR
Croatia HR
Curacao CW
Cyprus CY
Czech Republic CZ
Denmark DK
Djibouti DJ
Dominica DM
Dominican Republic DO
Ecuador EC
Egypt EG
El Salvador SV
Equatorial Guinea GQ
Eritrea ER
Estonia EE
Ethiopia ET
Falkland Islands (Malvinas) FK
Faroe Islands FO
Fiji FJ
Finland FI
France FR
French Guiana GF
French Polynesia PF
French Southern Territories TF
Gabon GA
Gambia GM
Georgia GE
Germany DE
Ghana GH
Gibraltar GI
Greece GR
Greenland GL
Grenada GD
Guadeloupe GP
Guam GU
Guatemala GT
Guernsey GG
Guinea GN
Guinea-Bissau GW
Guyana GY
Haiti HT
Honduras HN
Hong Kong HK
Hungary HU
Iceland IS
India IN
Indonesia ID
Ireland IE
Isle of Man IM
Iraq IQ
Israel IL
Italy IT
Jamaica JM
Japan JP
Jersey JE
Jordan JO
Kazakhstan KZ
Kenya KE
Kiribati KI
Korea (South) KR
Kosovo XK
Kuwait KW
Kyrgyzstan KG
Laos LA
Latvia LV
Lebanon LB
Lesotho LS
Liechtenstein LI
Lithuania LT
Luxembourg LU
Macau MO
Macedonia MK
Madagascar MG
Malawi MW
Malaysia MY
Maldives MV
Mali ML
Malta MT
Marshall Islands MH
Martinique MQ
Mauritania MR
Mauritius MU
Mayotte YT
Mexico MX
Micronesia (Federated States of) FM
Moldova MD
Monaco MC
Mongolia MN
Montenegro ME
Montserrat MS
Morocco MA
Mozambique MZ
Myanmar (Burma) MM
Namibia NA
Nepal NP
Netherlands NL
New Caledonia NC
New Zealand NZ
Nicaragua NI
Niger NE
Nigeria NG
Niue NU
Norfolk Island NF
Northern Mariana Islands MP
Norway NO
Oman OM
Pakistan PK
Palau PW
Panama PA
Papua New Guinea PG
Paraguay PY
Peru PE
Philippines PH
Pitcairn PN
Poland PL
Portugal PT
Puerto Rico PR
Qatar QA
Reunion RE
Romania RO
Russia RU
Rwanda RW
Saint Barthelemy BL
Saint Martin (French part) MF
Saint Pierre and Miquelon PM
Samoa WS
San Marino SM
Sao Tome & Principe ST
Saudi Arabia SA
Senegal SN
Serbia RS
Seychelles SC
Sierra Leone SL
Singapore SG
Sint Maarten (Dutch part) SX
Slovakia SK
Slovenia SI
Solomon Islands SB
South Africa ZA
South Georgia & the South Sandwich Islands GS
Spain ES
Sri Lanka LK
St Helena SH
St Kitts & Nevis KN
St Lucia LC
St Vincent & the Grenadines VC
Suriname SR
Svalbard & Jan Mayen SJ
Swaziland SZ
Sweden SE
Switzerland CH
Taiwan TW
Tajikistan TJ
Tanzania TZ
Thailand TH
Timor-Leste TL
Togo TG
Tokelau TK
Tonga TO
Trinidad & Tobago TT
Tunisia TN
Turkey TR
Turkmenistan TM
Turks & Caicos Island TC
Tuvalu TV
Uganda UG
Ukraine UA
United Arab Emirates AE
United Kingdom GB
United States of America US
Uruguay UY
Uzbekistan UZ
Vanuatu VU
Vatican City VA
Vietnam VN
Virgin Islands (British) VG
Virgin Islands (US) VI
Wallis & Futuna WF
Zambia ZM
Zimbabwe ZW

PayPal Supported Countries

The following countries are ONLY supported for PayPal payments.

Country Name Country ISO 3166-2
Ivory Coast CI
Cuba CU
Liberia LR
Libya LY
Sudan SD
Somalia SO
South Sudan SS
Syria SY
Venezuela VE
Yemen YE

Sanctioned Countries

The following countries are NOT supported due to UN or other sanctions:

Country Name Country ISO 3166-2
Iran IR
Korea (North) KP

Retrieve a country

You can retrieve a country by the country code. For example:

curl \
  -H "Content-Type: application/json" \
  -X GET \
  https://api.trolley.com/v1/geography/countries/CA

Response (200 Ok)

{
  "ok": true,
  "country": {
    "name": "Canada",
    "code": "CA",
    "currency": {
      "code": "CAD",
      "name": "Canadian Dollar"
    },
    "regions": {
      "NT": "Northwest Territories",
      "NU": "Nunavut",
      "NS": "Nova Scotia",
      "MB": "Manitoba",
      "SK": "Saskatchewan",
      "QC": "Quebec",
      "PE": "Prince Edward Island",
      "BC": "British Columbia",
      "YT": "Yukon",
      "NB": "New Brunswick",
      "NL": "Newfoundland and Labrador",
      "ON": "Ontario",
      "AB": "Alberta"
    }
  }
}

List of Regions

Example response (200 Ok)

{
  "name": "Canada",
  "code": "CA",
  "currency": {
    "code": "CAD",
    "name": "Canadian Dollar"
  },
  "regions": {
    "AB": "Alberta",
    "BC": "British Columbia",
    "MB": "Manitoba",
    "NB": "New Brunswick",
    "NL": "Newfoundland and Labrador",
    "NT": "Northwest Territories",
    "NS": "Nova Scotia",
    "NU": "Nunavut",
    "ON": "Ontario",
    "PE": "Prince Edward Island",
    "QC": "Quebec",
    "SK": "Saskatchewan",
    "YT": "Yukon"
  }
}
-H "Content-Type: application/json" \
-X GET \
https://api.trolley.com/v1/geography/countries/CA

List of regions, states or provinces supported

HTTP Request

GET https://api.trolley.com/v1/geography/countries/:code

Fields Description
code
required
string
ISO ALPHA-2 country code

List of Supported Languages

Trolley accepts 2-letter ISO 639-1 language code and optional 2-letter ISO-3166 country code as recipient language preferences. Currently we support the following list of languages in our out-bounding recipient emails and widget portal experience.

Supported ISO 639-1 language codes:

Code Language
bg Bulgarian
bn Bengali
cs Czech
da Danish
de Deutsch
el Greek
en English
es Spanish
fi Finnish
fr French
hr Croatian
hu Hungarian
id Indonesian
it Italian
ja Japanese
ko Korean
lt Lithuanian
lv Latvian
mk Macedonian
ms Malay
nl Dutch
no Norwegian
pl Polish
pt Portuguese
pt-BR Brazilian Portuguese
ro Romanian
ru Russian
sk Slovakian
sl Slovenian
sv Swedish
th Thai
tr Turkish
uk Ukrainian
vi Vietnamese
zh Chinese (Traditional)
zh-CN Chinese (Simplified)

List of Categories

Category Details
services Services
rent Rent
royalties Royalties
royalties_film Royalties Film & TV
prizes Prize payment
education Education
refunds Refunds

List of Statuses

Recipient Status

Status Details
active An Active recipient is able to receive a payment. Each recipient must have a minimum amount of profile information to become active and eligible to send payments to. This minimum info includes having an Address, and a Payout Method setup. Please note that an Address is not required to become active when PayPal is the primary payout method for the recipient.
incomplete An Incomplete recipient does not yet have the minimum required profile information to become active. An incomplete recipient cannot be sent a payment. The minimum amount of profile info required is an Address, and a Payout Method setup. Please note that an Address is not required to become active when PayPal is the primary payout method for the recipient.
disabled This status is used to temporarily disable a recipient so they cannot be sent a payment. It is used when a recipient’s account appears to be compromised or hacked. There are two ways a recipient’s status can become Disabled: 1.) The merchant (you or your staff) manually updates the recipient as Disabled through the dashboard or via API; or 2.) Trolley has identified suspicious activity on the recipient’s profile, such as changes to the payment account info from an IP address in a different country (contact us for specific risk rules). The Disabled status is a temporary status, and is usually updated to either Suspended or Active status based on a risk review conducted by the merchant.
archived This status is used to classify recipients that are deleted. Once a recipient is deleted, it becomes archived. Archived recipients are NOT deleted, they can also be un-archived.
suspended The Recipient has been suspended by you (the merchant). The email address can no longer be used with another recipient. The Suspended status is used for flagging fraudulent or bad recipients. These recipients cannot receive payments, but their profile details are editable. Suspended recipient information (email, IP address, etc) may also be used to identify and flag other potential bad users (e.g. the same bad user with multiple accounts) within your list of recipients. Contact support if you need to un-suspend a recipient due to an error.
blocked The recipient has been blocked by Trolley’s compliance team. The email address can no longer be used with another recipient. These recipients cannot receive payments, but their profile details are editable.

Payment Status

Status Details
pending A payment’s status is automatically updated to Pending when a payment is created inside a batch. The payment will remain in Pending status until it is Processed. It is possible to Delete (DELETE) or update (PATCH) a payment in Pending status.
failed A payment’s status will automatically be updated to ‘Failed’ if after an attempt to process it fails for any reason, such as a technical issue. You cannot delete (DELETE) or update (PATCH) a payment in ‘Failed’ status. A new payment would need to be created to attempt to process it again.
processed A payment’s status will be automatically updated to Processed after it is attempted to be processed, and is successful. You cannot delete (DELETE) or update (PATCH) a payment in Processed status.
returned A payment’s status will be automatically updated to Returned if it was successfully Processed, but was retured as not deliverable at a later time (from minutes up to weeks later). This mostly occurs when the bank account number that was provided was found to be invalid, or there was a beneficiary mis-match (the name provided does not match with the name on the bank account). You cannot delete (DELETE) or update (PATCH) a payment in Returned status. Payments with returned status should be actioned by the merchant by requesting the recipient confirm their bank account or payout method details. Once updated, create a new payment to send to the recipients using an updated payout method. If a Recipient has a payment ‘Returned’, their payout method might be temporarily disabled until the payout method is updated by either the merchant or recipient. We recommend subscribing to the recipient update webhooks to keep track of this occuring.
processing A payment’s status becomes processing once a user attempts to process a payment.

Batch Status

Status Details
open A new batch is assigned a status of Open when it is first created. You can Delete (DELETE) or update (PATCH) any batch with an Open status. Usually you will update a batch by adding payments to it.
initiating A batch processing has been initiated, and is currently underway. A Batch.Updated webhook with "action": "initiating" will also be sent out at this stage. This is an transient status, and will appear for only as long as it takes to validate all the payments to make them ready for the next step.
awaiting_approval A batch in the the approval process if it is configured. You can update a batch, but this will reset the batch to the open state.
accepted A batch is moved to Accepted status when it involves at least two currencies and a currency conversion needs to take place. If you accept the foreign exchange rate quotation provided, you will lock in that rate by accepting the quote. You cannot Delete (DELETE) or update (PATCH) a batch once it is in Accepted.
processing When you initiate a batch to start processing, the status is updated to Processing. This status is temporary, and the status will automatically update once processing is completed. You cannot Delete (DELETE) or update (PATCH) a batch once it is in Processing status.
complete Once all payments in a batch have been processed, failed or returned, it will be updated as Complete. You cannot Delete (DELETE) or update (PATCH) a batch once it is in Complete status.
failed All payment in the batch have failed to be processed. You cannot Delete (DELETE) or update (PATCH) a batch once it is in failed status.

Invoice and Invoice Line Status

Status Details
open A new invoice is assigned a status of Open when it is first created. As line items are added, it will retain this status until an InvoicePayment is created.
paritally_paid A invoice that has at least one payment against it, but still has a pending balance. The payment status must be pending, awaiting_approval, processing, or processed.
paid When there is no balance remaining with at least one invoice payment. The payment status must be pending, awaiting_approval, processing, or processed.

Payout Methods by Country

Local Bank Transfers

Country Currency Received by Recipient Daily cut off
United States USD Next business day 3:00pm EST
Canada CAD, USD Same or next business day 4:00pm EST
United Kingdom GBP, EUR Same or next business day 2:00pm EST
Argentina * ARS 1-2 business days 2:00pm EST
Australia AUD 1-2 business days 2:00pm EST
Austria EUR Next business day 2:00pm EST
Belgium EUR Next business day 2:00pm EST
Brazil BRL 1-2 business days 2:00pm EST
Bulgaria BGN, EUR 1-2, Next business day 2:00pm EST
Chile * CLP 1-2 business days 2:00pm EST
China * CNY, USD 1-2, 3-5 business days 2:00pm EST
Colombia * COP 1-2 business days 2:00pm EST
Croatia EUR Next business day 2:00pm EST
Cyprus EUR Next business day 2:00pm EST
Czech Republic CZK, EUR 1-2, Next business day 2:00pm EST
Denmark DKK, EUR 1-2, Next business day 2:00pm EST
Estonia EUR Next business day 2:00pm EST
Finland EUR Next business day 2:00pm EST
France EUR Next business day 2:00pm EST
French Guiana EUR Next business day 2:00pm EST
Germany EUR Next business day 2:00pm EST
Gibraltar EUR, GIP Next, 3-5 business days 2:00pm EST
Greece EUR Next business day 2:00pm EST
Guadeloupe EUR Next business days 2:00pm EST
Guernsey EUR, GBP Next, 2-3 business days 2:00pm EST
Hong Kong HKD 1-2 business days 2:00pm EST
Hungary HUF, EUR 1-2, Next business days 2:00pm EST
Iceland EUR, ISK 1-2, 3-5 business days 2:00pm EST
India INR 1-2 business days 2:00pm EST
Indonesia IDR 1-2 business days 2:00pm EST
Ireland EUR Next business day 2:00pm EST
Isle of Man EUR, GBP 1-2, 3-5 business days 2:00pm EST
Italy EUR Next business day 2:00pm EST
Jersey EUR, GBP Next, 3-5 business days 2:00pm EST
Kenya * KES 1-2 business days 2:00pm EST
Latvia EUR Next business day 2:00pm EST
Liechtenstein EUR, CHF Next, 3-5 business days 2:00pm EST
Lithuania EUR Next business day 2:00pm EST
Luxembourg EUR Next business day 2:00pm EST
Malaysia MYR 1-2 business days 2:00pm EST
Malta EUR Next business day 2:00pm EST
Martinique EUR Next business days 2:00pm EST
Mayotte EUR Next business days 2:00pm EST
Mexico * MXN 1-2 business days 2:00pm EST
Monaco EUR Next business day 2:00pm EST
Morocco * MAD 1-2 business days 2:00pm EST
Netherlands EUR Next business day 2:00pm EST
Norway NOK, EUR 1-2, Next business day 2:00pm EST
Paraguay * PYG 1-2 business days 2:00pm EST
Peru * PEN 1-2 business days 2:00pm EST
Philippines PHP 1-2 business days 2:00pm EST
Poland PLN, EUR 1-2, Next business day 2:00pm EST
Portugal EUR Next business day 2:00pm EST
Reunion EUR Next business days 2:00pm EST
Romania RON, EUR 1-2, Next business day 2:00pm EST
Saint Martin (French part) EUR Next business day 2:00pm EST
San Marino EUR Next business day 2:00pm EST
Singapore SGD 1-2 business days 2:00pm EST
Slovakia EUR Next business day 2:00pm EST
Slovenia EUR Next business day 2:00pm EST
Spain EUR Next business day 2:00pm EST
St Barthelemy EUR Next business days 2:00pm EST
St Pierre & Miquelon EUR Next business day 2:00pm EST
Sweden SEK, EUR 1-2, Next business day 2:00pm EST
Switzerland CHF, EUR 1-2, Next business days 2:00pm EST
Thailand THB 1-2 business days 2:00pm EST
Uruguay * UYU 1-2 business days 2:00pm EST
Vatican City EUR Next business day 2:00pm EST
Vietnam VND 1-2 business days 2:00pm EST


SWIFT Bank Wires

Country Currency Received by Recipient Daily cut off
Albania ALB 3-5 business days 2:00pm EST
Algeria DZD 3-5 business days 2:00pm EST
American Samoa USD 3-5 business days 2:00pm EST
Andorra EUR 3-5 business days 2:00pm EST
Angola AOA 3-5 business days 2:00pm EST
Anguilla XCD 3-5 business days 2:00pm EST
Antigua & Barbuda XCD 3-5 business days 2:00pm EST
Armenia AMD 3-5 business days 2:00pm EST
Aruba AWG 3-5 business days 2:00pm EST
Azerbaijan AZN 3-5 business days 2:00pm EST
Bahamas BSD 3-5 business days 2:00pm EST
Bahrain BHD 3-5 business days 2:00pm EST
Bangladesh BDT 3-5 business days 2:00pm EST
Barbados BBD 3-5 business days 2:00pm EST
Belize BZD 3-5 business days 2:00pm EST
Benin XOF 3-5 business days 2:00pm EST
Bermuda BMD 3-5 business days 2:00pm EST
Bhutan BTN 3-5 business days 2:00pm EST
Bolivia BOB 3-5 business days 2:00pm EST
Bonaire, Sint Eustatius & Saba USD 3-5 business days 2:00pm EST
Bosnia & Herzegovina BAM 3-5 business days 2:00pm EST
Botswana BWP 3-5 business days 2:00pm EST
Brunei BND 3-5 business days 2:00pm EST
Burkina Faso XOF 3-5 business days 2:00pm EST
Burundi BIF 3-5 business days 2:00pm EST
Cambodia KHR 3-5 business days 2:00pm EST
Cameroon XAF 3-5 business days 2:00pm EST
Cayman Islands KYD 3-5 business days 2:00pm EST
Central African Republic XAF 3-5 business days 2:00pm EST
Chad XAF 3-5 business days 2:00pm EST
Christmas Island AUD 3-5 business days 2:00pm EST
Comoros KMF 3-5 business days 2:00pm EST
Congo (Brazzaville) XAF 3-5 business days 2:00pm EST
Cook Islands NZD 3-5 business days 2:00pm EST
Costa Rica CRC 3-5 business days 2:00pm EST
Curacao ANG 3-5 business days 2:00pm EST
Djibouti DJF 3-5 business days 2:00pm EST
Dominica XCD 3-5 business days 2:00pm EST
Dominican Republic DOP 3-5 business days 2:00pm EST
Ecuador USD 3-5 business days 2:00pm EST
Egypt * EGP 3-5 business days 2:00pm EST
El Salvador USD 3-5 business days 2:00pm EST
Equatorial Guinea XAF 3-5 business days 2:00pm EST
Falkland Islands (Malvinas) FKP 3-5 business days 2:00pm EST
Faroe Islands DKK 3-5 business days 2:00pm EST
Fiji FJD 3-5 business days 2:00pm EST
French Polynesia XPF 3-5 business days 2:00pm EST
French Southern Territories EUR 3-5 business days 2:00pm EST
Gabon XAF 3-5 business days 2:00pm EST
Gambia GMD 3-5 business days 2:00pm EST
Georgia GEL 3-5 business days 2:00pm EST
Ghana GHS 3-5 business days 2:00pm EST
Greenland DKK 3-5 business days 2:00pm EST
Grenada XCD 3-5 business days 2:00pm EST
Guam USD 3-5 business days 2:00pm EST
Guatemala GTQ 3-5 business days 2:00pm EST
Guinea GNF 3-5 business days 2:00pm EST
Guinea-Bissau XOF 3-5 business days 2:00pm EST
Guyana GYD 3-5 business days 2:00pm EST
Haiti HTG 3-5 business days 2:00pm EST
Honduras HNL 3-5 business days 2:00pm EST
Israel ILS 3-5 business days 2:00pm EST
Jamaica JMD 3-5 business days 2:00pm EST
Japan JPY 2-3 business days 2:00pm EST
Jordan JOD 3-5 business days 2:00pm EST
Kazakhstan KZT 3-5 business days 2:00pm EST
Kiribati AUD 3-5 business days 2:00pm EST
Korea (South) KRW 3-5 business days 2:00pm EST
Kosovo EUR 3-5 business days 2:00pm EST
Kuwait KWD 3-5 business days 2:00pm EST
Kyrgyzstan KGS 3-5 business days 2:00pm EST
Laos LAK 3-5 business days 2:00pm EST
Lesotho LSL 3-5 business days 2:00pm EST
Macau MOP 3-5 business days 2:00pm EST
Macedonia MKD 3-5 business days 2:00pm EST
Madagascar MGA 3-5 business days 2:00pm EST
Malawi MWK 3-5 business days 2:00pm EST
Maldives MVR 3-5 business days 2:00pm EST
Mali USD 3-5 business days 2:00pm EST
Marshall Islands USD 3-5 business days 2:00pm EST
Mauritania MRO 3-5 business days 2:00pm EST
Mauritius MUR 3-5 business days 2:00pm EST
Micronesia (Federated States of) USD 3-5 business days 2:00pm EST
Moldova MDL 3-5 business days 2:00pm EST
Mongolia MNT 3-5 business days 2:00pm EST
Montenegro EUR 3-5 business days 2:00pm EST
Montserrat XCD 3-5 business days 2:00pm EST
Mozambique MZN 3-5 business days 2:00pm EST
Namibia NAD 3-5 business days 2:00pm EST
Nepal NPR 3-5 business days 2:00pm EST
New Caledonia XPF 3-5 business days 2:00pm EST
New Zealand * NZD 3-5 business days 2:00pm EST
Nicaragua NIO 3-5 business days 2:00pm EST
Niger XOF 3-5 business days 2:00pm EST
Nigeria NGN 3-5 business days 2:00pm EST
Niue NZD 3-5 business days 2:00pm EST
Norfolk Island AUD 3-5 business days 2:00pm EST
Northern Mariana Islands USD 3-5 business days 2:00pm EST
Oman OMR 3-5 business days 2:00pm EST
Pakistan * PKR 3-5 business days 2:00pm EST
Palau USD 3-5 business days 2:00pm EST
Panama PAB 3-5 business days 2:00pm EST
Papua New Guinea PGK 3-5 business days 2:00pm EST
Pitcairn NZD 3-5 business days 2:00pm EST
Puerto Rico USD 3-5 business days 2:00pm EST
Qatar QAR 3-5 business days 2:00pm EST
Russia RUB 3-5 business days 2:00pm EST
Rwanda RWF 3-5 business days 2:00pm EST
Samoa WST 3-5 business days 2:00pm EST
Sao Tome & Principe STD 3-5 business days 2:00pm EST
Saudi Arabia SAR 3-5 business days 2:00pm EST
Senegal XOF 3-5 business days 2:00pm EST
Serbia RSD 3-5 business days 2:00pm EST
Seychelles SCR 3-5 business days 2:00pm EST
Sierra Leone SLL 3-5 business days 2:00pm EST
Sint Maarten (Dutch part) ANG 3-5 business days 2:00pm EST
Solomon Islands SBD 3-5 business days 2:00pm EST
South Africa ZAR 3-5 business days 2:00pm EST
South Georgia & the South Sandwich Islands GBP 3-5 business days 2:00pm EST
Sri Lanka * LKR 3-5 business days 2:00pm EST
St Helena SHP 3-5 business days 2:00pm EST
St Kitts & Nevis XCD 3-5 business days 2:00pm EST
St Lucia XCD 3-5 business days 2:00pm EST
St Vincent & the Grenadines XCD 3-5 business days 2:00pm EST
Suriname SRD 3-5 business days 2:00pm EST
Svalbard & Jan Mayen NOK 3-5 business days 2:00pm EST
Swaziland SZL 3-5 business days 2:00pm EST
Taiwan TWD 3-5 business days 2:00pm EST
Tajikistan TJS 3-5 business days 2:00pm EST
Tanzania TZS 3-5 business days 2:00pm EST
Timor-Leste USD 3-5 business days 2:00pm EST
Togo XOF 3-5 business days 2:00pm EST
Tokelau NZD 3-5 business days 2:00pm EST
Tonga TOP 3-5 business days 2:00pm EST
Trinidad & Tobago TTD 3-5 business days 2:00pm EST
Tunisia TND 3-5 business days 2:00pm EST
Turkey TRY 3-4 business days 2:00pm EST
Turkmenistan TMT 3-5 business days 2:00pm EST
Turks & Caicos Islands USD 3-5 business days 2:00pm EST
Tuvalu USD 3-5 business days 2:00pm EST
Trinidad & Tobago TTD 3-5 business days 2:00pm EST
Uganda UGX 3-5 business days 2:00pm EST
Ukraine UAH, USD 3-5, 3-5 business days 2:00pm EST
United Arab Emirates AED 3-5 business days 2:00pm EST
Uzbekistan UZS 3-5 business days 2:00pm EST
Vanuatu VUV 3-5 business days 2:00pm EST
Virgin Islands (British) USD 3-5 business days 2:00pm EST
Virgin Islands (US) USD 3-5 business days 2:00pm EST
Wallis & Futuna XPF 3-5 business days 2:00pm EST
Zambia ZMW 3-5 business days 2:00pm EST

Country Requirements

Recipient Government ID Number

Some countries have special requirements to provide a Government ID or Tax ID number for recipients you send money to in that country. Below is a list of the countries that have this special requirement. We ask recipients for this information when providing their payout method account details. A recipient from these countries will need a government ID or tax ID on their profile to become active, they will be in incomplete status otherwise.

Country Individual or Business Government ID / Tax ID Length of Number
Argentina Individual CUIT (Código Único de Identificación Tributaria) 11
Argentina Business CUIT (Código Único de Identificación Tributaria) 11
Azerbaijan Individual TIN (Taxpayer Identification Number) 10
Brazil Individual CPF (Cadastro de Pessoas Físicas) 11
Brazil Business CNPJ (Cadastro Nacional de Pessoas Jurídicas) 14
Chile Individual RUN (Rol Único Nacional) 8 or 9
Chile Business RUT (Rol Único Tributario) 8 or 9
China Individual NIDN (National ID Number) 15 or 18
China Business BRN (Business Registration Number) 18
Colombia Individual NIT (Número de Identificación Tributaria) 10
Costa Rica Individual Cedula Juridica 9 to 12
Dominican Republic Individual Cédula de Residencia 11
Dominican Republic Business RNC (Dominican Republic tax number) 9
Dominican Republic Business NCF (\Dominican Republic receipt number) 11 or 13 or 19
Guatemala Individual CUI (Código Único de Identificación) 13
Guatemala Business NIT (Número de Identificación Tributaria) 8 to 12
Kazakhstan Individual IIN (Individual identification number) 12
Korea Individual RRN (South Korean resident registration number) 13
Korea Business BRN (South Korea Business Registration Number) 10
Mexico Individual CURP (Mexican personal ID) 18
Mexico Individual RFC (Mexican tax number) 13
Mexico Business RFC (Mexican tax number) 12
Nepal Individual PAN (Permanent account number) 9
Nepal Business PAN (Permanent account number) 9
Pakistan Individual CNIC (Pakastan Computerize National Identiy Card) 11
Pakistan Business NTT (Pakastan Tax Identification Number) 11
Paraguay Individual RUC number (Paraguay tax number) 8 or 9
Paraguay Business RUC number (Paraguay tax number). 8 or 9
Peru Individual CUI (Peruvian identity number) 8
Peru Individual CE (Peruvian ID card for foreigners) 9
Peru Business RUC (Peruvian company tax number) 11
Russia Individual ИНН (Russian tax identifier) 12
Russia Business ИНН (Russian tax identifier) 10
Tajikistan Individual National ID 9
Tajikistan Business National ID 9
Uruguay Individual Cedula (Urugual Person number) 9
Uruguay Individual NIE (Uruguay Foreigners Identification Number) 9
Uruguay Business RUT (Uruguay tax number) 9

Additional Requirements

Select countries have special requirements to provide additional information for recipients you send money to in that country. Below is a list of the countries that have these special requirement. A recipient in one of these countries will need this information on their profile to become active, they will be in incomplete status otherwise.

Country Phone Number First Name Last Name Date of Birth Postal Code Region Code
Argentina
Bangladesh
Brazil
Canada
Chile
China
Columbia
Dominican Republic
Egypt
Ethopia
Fiji
Guatemala
India
Israel
Jordan
Khazakhstan
Mongolia
Russia
South Africa
Taiwan
Thailand
Togo
Tonga
Tuvalu
United States

Payment and Batch errors

Overview

When you add a payment to a batch, or when a batch is sent for processing, we run a set of validations on Payments.

Since a batch and payment can have multiple errors, all of these are returned in an error array. When the validations fail, we return an errors array containing error messages explaining what happened.

This reference document explains how to understand these error messages and how to fix them.

Validation Process

Validation of payments and batches is done when:

  1. A Payment is added to a Batch, and
  2. A Batch is sent to processing.

If any errors are found, they are returned as the API response.

Here’s an example of how a typical errors array might look like

{
    "errors": [
        {
            "code": "batch_failed_validation",
            "message": "Zero or Negative amount sourceAmount: 0.00 USD, recipientFees: 0",
            "field": "payment.<sourceAmount-recipientFee>",
            "paymentId": "P-1a2B3c4D5e6F7g8H9i0J1k"
        },
        {
            "code": "batch_failed_validation",
            "message": "Payment is missing quote",
            "field": "payment.fxQuote",
            "paymentId": "P-1a2B3c4D5e6F7g8H9i0J1k"
        },
        {
            "code": "non_sufficient_funds",
            "message": "balance=100.21 need=107.00 currency=USD"
        }
    ]
}

When the validations fail, the HTTP status code is returned HTTP 400 - Bad Request.

The following table explains what these fields mean:

Field Name Purpose
code Denotes what kind of error it is. E.g. Batch Validation related errors, or merchant account related errors.
message Human readable message explaining what happened, in a UI friendly manner.
field Denotes which payment related field the error is concerned with.
paymentId ID of the erroneous payment

A batch wouldn’t be sent for processing unless are the errors are resolved.

Understanding the Errors

In each element of the error array, you should first look at code object to differentiate whether the error is related to a payment/batch or a merchant account related problem.

After that, look at the field object to understand the kind of error it is. In some cases the field object may not be present.

The following table shows possible errors, when they’re raised, values of code and field objects, and how to fix those errors:

Error Type Raised At code Value field Value Suggested Fix
Negative amount of payment Payment Creation invalid_field payments.amount Include a non-negative payment amount greater than 0.
Payment amount is Zero Batch Validation batch_failed_validation payment.<sourceAmount-recipientFee> Include a payment amount greater than 0.
Missing Quote Batch Validation batch_failed_validation payment.fxQuote Generate a quote before sending the batch for processing
Recipient is missing a payout method Batch Validation batch_failed_validation payment.recipient.account Have an account added for the recipient
Merchant Payout Method is not enabled Batch Validation batch_failed_validation payment.payoutMethod Merchant should have at least one active payout method.
Merchant Payout Method is not enabled for the country Batch Validation batch_failed_validation payment.payoutMethod.enabledCountry Merchant should have an enabled payout method that works for recipient’s country.
Lower than routeMinimum Batch Validation batch_failed_validation payment.<sourceAmount-recipientFee> < routeMin Include an amount higher than the minimum amount allowed for the route. See Payment Minimums.
Recipient not active Batch Validation batch_failed_validation payment.recipient.status Add payments for an active recipient.
Insufficient account balance Batch Validation non_sufficient_funds Add enough funds in your to carry out this transaction.

Using the code and field objects, you can write logic in your code to handle the errors.

Tools


Postman Collection

To help you play around with Trolley APIs without writing code, we have published a Postman Collection that you can fork and use.

This collection comes pre-setup with Authentication header generation, so all you need to do is put your keys and start using.

You can also find Trolley Developers page on Postman here: https://www.postman.com/trolley-developers

What is Postman

Postman is one of the most popular API Platforms out there, using which you can build and test APIs. You can use Postman to use REST APIs, consume responses, and even generate code in many languages.

Screenshot of Trolley Developer's Postman homepage

Screenshot of Trolley Developer's Postman homepage

How to use Trolley API’s Postman Collection

  1. Click on the “Run in Postman” button below.
  2. Fork it into your own Postman account.
  3. Setup your fork according to the setup instructions below.
  4. Start sending API calls.

The Postman collection uses a pre-request script to compute the Authorization header before sending each request. This script accesses and sets multiple global variables, some of them are used by the requests.

Global Variables

Here’s the list of global variables that our collection uses:

Variable Name Description Default Value
trolley_api_base_url API Base URL https://api.trolley.com
trolley_access_key The ACCESS_KEY from Trolley dashboard. Accessed by the script. Your ACCESS_KEY
trolley_secret_key The SECRET_KEY from Trolley dashboard. Accessed by the script. Your SECRET_KEY
trolley_auth_signature Trolley’s Authorization header. Setup by the script. leave this blank
trolley_timestamp Timestamp for trolley X-PR-Timestamp header. Setup by the script. leave this blank

NOTE: These are global variables, not environment specific, and are case sensitive.

Although our collection contains all these global variables, Postman doesn’t copy them across forks. So when you’ll fork this collection in your workspace, you’ll have to recreate them.

Setup Instructions

  1. Add the above Global Variables in Postman.
  2. Get API ACCESS KEY and API SECRET KEY from you Trolley Dashboard.
  3. Put these keys in the above-mentioned Postman Global Variables.
  4. Fill the trolley_api_base_url value.
  5. Start sending requests!

Button saying Run in Postman

If you’re new to Postman, find out What is Postman and How to use Postman Collection.

Let us know if you find a bug in the collection or if have any feedback at developers@trolley.com

SDK


Trolley SDK

API clients in: Node.js (Javascript), PHP, Ruby, Java, C#, and Python.

We want to make integrating with our APIs as easy as possible for developers. That is why we have developed SDKs for the most common languages, which you will find links to below, all hosted on GitHub.

If we don’t have a client for the language you need, please reach out to us on developers@trolley.com, and we will see what we can do to add that language.

Language GitHub Repository
Python https://github.com/trolley/python-sdk
PHP https://github.com/trolley/php-sdk
Javascript https://github.com/trolley/javascript-sdk
C# https://github.com/trolley/dotnet-sdk
Ruby https://github.com/trolley/ruby-sdk
Java https://github.com/trolley/java-sdk
×