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.
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.
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.
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.
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://developers.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. There are a few ways you can add recipients:
- You can use the Trolley APIs to add a recipient programmatically.
- Use the Trolley Widget to onboard new recipients and their tax information.
- Bulk upload recipients as a CSV file to import recipients from your previous system.
1. Add Recipients with Create a Recipient API
To add a recipient programmatically, you can use the Create a Recipient API, or the equivalent method/function in any of the available SDKs.
Learn more about the Create a Recipient API here: https://developers.trolley.com/api/#create-a-recipient
2. Onboard recipients with the Trolley Widget
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:
- Build a Widget URL with required configuration options.
- Host it on a webpage you own and control.
- 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.
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.
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://developers.trolley.com/widget/
3. Import Recipients with a CSV file
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
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
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://support.trolley.com/s/article/Adding-a-New-Recipient
You can also add recipients via the API, which is discussed here: https://developers.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://developers.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://developers.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://developers.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://developers.trolley.com/api/#list-of-statuses
To learn more about how to send a payment through a batch, refer to this documentation: https://developers.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://developers.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://developers.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
-
To get notified about updates to Payments, Recipients and more, subscribe to Webhooks
-
See a definitive list of potential payments, recipients, and batches statuses in List of Statuses.
-
Find answers to common questions, or contact us by visiting Support and FAQs.
Concepts
Trolley Authentication
The Trolley API uses a custom Authentication Scheme to authenticate the API requests, where you have to generate and send a hashed signature in the request header.
To understand how to generate the hashed signature for Authentication, refer to the Authentication section of this documentation.
To learn more about how Trolley Authentication works, you can also check out this blog post: How Does Trolley’s API Authentication Work?
Since our SDKs are based on the APIs, they also depend on this custom Authentication, but handle the hashing behind the scenes.
API Components
The Trolley API exposes different objects through multiple components that work together to provide the functionality that you can integrate with your system.
The objects are:
- Recipient
- RecipientAccount
- Batch
- Payment
- Verification
- Invoice
- Invoice Payment
- Balance
Recipients and Recipient Accounts
An individual or business or more generally a user is a Recipient in Trolley.
A Recipient can have many statuses, based on factors such as their profile information, payout information, tax forms, verifications results, and compliance status.
Only an active
Recipient can be sent a payment.
A Recipient is a standalone object within the Trolley ecosystem.
A RecipientAccount represents a payout method of a Recipient.
It is another object within the Trolley ecosystem, but it is dependent on a Recipient object.
A RecipientAccount can only exist within a Recipient object, but all CRUD operations can be performed on a RecipientAccount object.
Check out more about Recipient and RecipientAccount in their respective sections.
Batches and Payments
In Trolley, A Batch is a logical group that holds Payments. The payments can only exist within a batch.
To be able to create Payments, you have to create a Batch first.
You can create a Batch and add payments to it in the same API call, or you can add payments to an existing Batch.
Batch and Payment, both, are treated as individual objects within the Trolley ecosystem, with a conceptual relationship defined as above.
To learn more about Batches and Payments, please refer to the Payments section.
To learn more about the journey of Payments and Batches, have a look at our developer blog post explaining that: Understanding the Payment Journey at Trolley.
Categorization with Tags
Many of the objects in the Trolley ecosystem support tags, where you can assign attributes to these objects which are recognizable internally to you or to your business logic.
These tags are not visible to the recipient, and can be used in search as well.
You can assign one or many tags to an object.
Whenever you update a set of tags, the old tags are deleted and new ones are added.
To delete a tag, you update an object with an empty array as tag’s value.
The objects that support Tags is as follows, along with the links to more details about them:
Using Tags, you can categorize different objects and can even search for them based on Tags.
List and Search
Many objects within the Trolley ecosystem support Indexing or “List All” operations, where you can fetch all the objects within the system.
Most of these List All operations support providing search parameters and filtering capabilities, so you can narrow down the result-set of the Indexing operation.
Look at the details in the relevant “List All” operation to learn more about how to use these search filters.
Pagination
Example Request
...?page=2&pageSize=100...
All the Index or “List All” operations support pagination parameters.
In the query parameters, you can provide page
and pageSize
parameters to specify pagination options:
Query Parameters for specifying page information
Parameter | Values | Description |
---|---|---|
page |
integer | Optional. Specifies which page you want to fetch. Defaults to 1 . |
pageSize |
integer | Optional. Specifies how many items you want each page to have. Defaults to 10 , maximum 1000 |
The code area shows a sample of a cURL request with pagination options.
Example Response
...
{
"ok": true,
"payments": [
...
],
"meta": {
"page": 1,
"pages": 1,
"records": 2
}
}
...
Index/List All operations that support pagination have a meta
field that contains pagination information that you can use to go through pages.
Definition of Response Parameters
Parameter | Values | Description |
---|---|---|
page |
integer | Which page this response represents. |
pages |
integer | Total number of pages in the result set. |
records |
integer | Total number of items in the result set. |
Interacting with the API
Making requests
The Trolley API follows RESTful design principles. We use the following HTTP verbs:
GET
- Read resourcesPOST
- Create new resourcesPATCH
- Update an existing resourceDELETE
- Remove resources
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 occurred 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:
- 200 requests per minute from any single IP address
- 100 requests per minute for any regular merchant
- 50 requests per minute for any sandbox merchant
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:
Authorization
Where your signed request information will be transmittedX-PR-Timestamp
The timestamp of your request
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'
.
timestamp
This is the same value as transmitted in theX-PR-Timestamp
header and is the seconds past 1970 (Unix Epoch) in UTC time.method
The request method in all upper case.requestPath
The full request path including all query parameters (e.g./v1/recipients/?search=bob
)body
The JSON body of the request.
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 |
Tags in Recipients
Create a Recipient with Tags
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": "Leonardo",
"lastName": "da Vinci",
"email": "leonardo@davinci.it",
"tags":[
"tag1",
"tag2"
]
}'
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',
tags: [
"tag1",
"tag2"
]
})
print response;
// 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",
tags: [
"tag1",
"tag2"
]
}
);
console.log(recipient.id);
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",
"tags":[
"tag1",
"tag2"
]
}
response = client.recipient.create(payload)
print(response)
<?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',
'tags' => [
"tag1",
"tag2"
],
]);
print_r($recipient);
?>
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";
recipient.tags = new List<string> { "Tag1", "Tag2" };
Recipient recipient = gateway.recipient.Create(recipientRequest);
Console.WriteLine(recipient.id);
...
...
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");
recipientRequest.setTags(Arrays.asList("Tag1", "Tag2"));
Recipient recipient = client.recipient.create(recipientRequest);
System.out.println(recipient.getId());
...
Add Tags using “Update a Recipient”
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 '{
"tags":[
"tag1",
"tag2"
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.recipient.update(
tags: [
"tag1",
"tag2"
])
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
response = client.recipient.update(
"tags":[
"tag1",
"tag2"
])
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.recipient.update(
tags: [
"tag1",
"tag2"
]
);
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$response = Trolley\Recipient::update($recipient->id, [
'tags' => [
"tag1",
"tag2"
]
]);
print_r($response);
?>
using Trolley.Types;
using Trolley;
...
Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");
string recipientId = GetRecipientId();
Recipient recipientRequest = new Recipient();
recipientRequest.tags = new List<string> { "Tag1", "Tag2" };
Recipient recipient = gateway.recipient.Update(recipientId, recipientRequest);
Console.WriteLine(recipient.id);
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
String recipientId = getRecipientId();
// Update a recipient
Recipient updateRequest = new Recipient();;
recipientRequest.setTags(Arrays.asList("Tag1", "Tag2"));
boolean response = client.recipient.update(recipientId, updateRequest);
System.out.println(response);
// Look at Recipient.Create request sample to learn how to set different fields
...
You can add and manage Tags with Recipients primarily with Create, List, and Update API calls.
Following sections talk in detail about how to use tags with Recipient, with sample code.
Add Tags to a Recipient
You can add tags to a Recipient either while creating the Recipient or by Updating a Recipient.
To do that, provide the key as tags
, and a string array as the values, with the Create or Update request.
Search Recipients Based on Tags
You can use additional parameters in the List all Recipients operation to fetch Recipients based on tags.
Using the tags
query parameter, you can specify what tags you want to search for.
The API performs an AND
query based on all the query parameters you provide.
Search Recipients who have all the provided tags
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?
tags=tag1,tag2&
search=Jane' \
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
# Search for recipients by tags
response = client.recipient.search(
1, # page number
10, # items per page
"", # search term
{
'tags':[
'tag1', 'tag2' # tags
]
})
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)
// 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);
<?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);
}
?>
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);
}
...
...
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());
}
...
Update Tags of a Recipient
To update the tags of a Recipient, use the Update a Recipient API to replace the existing tags with new tags.
Please keep in mind that every time you update the tags, the old tags are deleted and new ones are added.
If you wish to just add a new tag, you should copy all the existing tags, and send an ‘Update a Recipient’ request with existing and new tags.
Update tags of a Recipient
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 '{
"tags":[
"old-tag",
"new-tag"
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.recipient.update(
tags: [
"old-tag",
"new-tag"
])
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
response = client.recipient.update(
"tags":[
"old-tag",
"new-tag"
])
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.recipient.update(
tags: [
"old-tag",
"new-tag"
]
);
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$response = Trolley\Recipient::update($recipient->id, [
'tags' => [
"old-tag",
"new-tag"
]
]);
print_r($response);
?>
using Trolley.Types;
using Trolley;
...
Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");
string recipientId = GetRecipientId();
Recipient recipientRequest = new Recipient();
recipientRequest.tags = new List<string> { "old-tag", "new-tag" };
Recipient recipient = gateway.recipient.Update(recipientId, recipientRequest);
Console.WriteLine(recipient.id);
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
String recipientId = getRecipientId();
Recipient updateRequest = new Recipient();;
recipientRequest.setTags(Arrays.asList("old-tag", "new-tag"));
boolean response = client.recipient.update(recipientId, updateRequest);
System.out.println(response);
...
Delete Tags of a Recipient
To delete Tags from a Recipient, use the ‘Update a Recipient’ API call with an empty tags
parameter.
Delete Tags of a Recipient
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 '{
"tags":[]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.recipient.update(
tags: [])
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
response = client.recipient.update(
"tags":[])
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.recipient.update(
tags: []
);
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$response = Trolley\Recipient::update($recipient->id, [
'tags' => []
]);
print_r($response);
?>
using Trolley.Types;
using Trolley;
...
Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");
string recipientId = GetRecipientId();
Recipient recipientRequest = new Recipient();
recipientRequest.tags = new List<string>();
Recipient recipient = gateway.recipient.Update(recipientId, recipientRequest);
Console.WriteLine(recipient.id);
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
String recipientId = getRecipientId();
Recipient updateRequest = new Recipient();;
recipientRequest.setTags(new List<String>());
boolean response = client.recipient.update(recipientId, updateRequest);
System.out.println(response);
...
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",
"bankAccountType": "checking",
"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 |
bankAccountType string |
Required for certain countries - Argentina, Brazil, Bolivia, Chile, Ecuador, Peru, Paraguay, Uruguay, USA, and India. Accepted values are: checking or savings . Defaults to checking . |
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 visible to the recipient. Max 1024 characters. |
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 |
Tags in a Batch
Create a Batch with Tags
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",
"tags":[
"tag1",
"tag2"
],
"payments": [...]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.batch.create({
currency: "USD",
description: "Month end payout",
tags: [
"tag1",
"tag2"
],
payments: [...]
})
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
payload = {
"currency": "USD",
"description": "Month end payout",
"tags": [
"tag1",
"tag2"
],
"payments": [...]
}
response = client.batch.create(payload)
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.batch.create(
{
currency: "USD",
description: "Month end payout",
tags: [
"tag1",
"tag2"
],
payments: [...]
});
console.log(response.batch.id);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$batch = Trolley\Batch::create(
[ // Batch description
"sourceCurrency" => "USD",
"description" => "Month end payout",
"tags" => [
"tag1",
"tag2"
]
],
[...]);
print_r($batch);
?>
using Trolley.Types;
using Trolley;
...
Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");
Batch batchRequest = new Batch("Month end payout", null, "USD", 0);
batchRequest.tags = new List<string> { "tag1", "tag2" };
Batch batch = gateway.batch.Create(batchRequest);
Console.WriteLine(batch.id);
...
...
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("USD");
batchRequest.setDescription("Month end payout");
batchRequest.setTags(Arrays.asList("tag1", "tag2"));
Batch batch = client.batch.create(batchRequest);
System.out.println(batch.getId());
...
Get Batches which have all the provided tags
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&
tags=tag1,tag2&
status=open' \
// Coming soon to the Ruby SDK
// Coming soon to the Python SDK
// Coming soon to the Javascript SDK
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
// Search in batches
$searchResults = Trolley\Batch::search([
"tags" => ["tag1", "tag2"],
"page" => 1,
"pageSize" => 5
]);
foreach ($searchResults as $batch){
print_r($batch);
}
?>
// Coming soon to the C#/dotnet SDK
// Coming soon to the Java SDK
You can add and use Tags with Batches with Create and List API calls.
Following sections talk in detail about how to use tags with Batches, with sample code.
Add Tags to a Batch
You can add tags to a Batch either while creating it.
To do that, provide the key as tags
, and a string array as the values, with the Create request.
Search Batches Based on Tags
You can use additional parameters in the List all Batches request to fetch Batches based on tags.
Using the tags
query parameter, you can specify what tags you want to search for.
The API performs an AND
query based on all the query parameters you provide.
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": "memo",
"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. Our APIs limit memo to 1024 characters. The number of characters ultimately displayed depends on the recipient’s bank, so it’s best to keep it short to under 30 characters, otherwise, the end may get cut off. Special characters are not supported on bank statements so they will be stripped out by the bank. The memo field is good for referring to an invoice or reference number. We also strongly suggest including 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": "memo",
"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. Our APIs limit memo to 1024 characters. The number of characters ultimately displayed depends on the recipient’s bank, so it’s best to keep it short to under 30 characters, otherwise, the end may get cut off. Special characters are not supported on bank statements so they will be stripped out by the bank. The memo field is good for referring to an invoice or reference number. We also strongly suggest including 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 |
Tags in a Payment
Add a new Payment with Tags to 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/payments/' \
--data-raw '{
"recipient" : {
"id":"R-1a2B3c4D5e6F7g8H9i0J1k"
},
"amount": "150",
"currency": "USD",
"tags":[
"tag1",
"tag2"
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.payment.create(
batch.id,
{
sourceAmount: '150.00',
currency: 'USD',
recipient: {
id: recipient.id
},
tags: ["tag1", "tag2"]
})
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
payload = {
"sourceAmount": "150.10",
"currency": "USD",
"recipient":{
"id": recipient_id
},
"tags": ["tag1", "tag2"]
}
response = client.payment.create(payload, batch.id)
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.payment.create(
batch.id,
{
sourceAmount: "150.10",
currency: "USD",
recipient:{
id: recipient.id
},
tags: ["tag1", "tag2"]
});
console.log(response.batch.id);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$payment = Trolley\Batch::createPayment($batch->id, [
"sourceAmount" => "150.10",
"currency" => "USD",
"recipient" => [ "id" => $recipient->id ],
"tags" => ["tag1", "tag2"]
]);
print_r($payment);
?>
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, 150.10, "USD");
payment.tags = new List<string> { "tag1", "tag2" };
payment.batchId = batchId;
payment = gateway.payment.Create(payment);
Console.WriteLine(payment.id);
...
...
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("150.10");
paymentRequest.setRecipient(recipient);
paymentRequest.setTags(Arrays.asList("tag1", "tag2"));
Payment payment = client.payment.create(paymentRequest, batchId);
System.out.println(payment.getId());
...
Add Tags to a Payment while creating a new 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",
"tags":[
"tag1",
"tag2"
]
}
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.batch.create({
currency: "USD",
description: "Month end payout",
payments: [
{
recipient: {
id: recipient.id
},
amount: "100",
currency: "USD",
tags:[
"tag1",
"tag2"
]
}
]
})
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
payload = {
"currency": "USD",
"description": "Month end payout",
"payments": [
{
"recipient": {
"id": recipient.id
},
"sourceAmount": "100",
"sourceCurrency": "USD",
"tags":[
"tag1",
"tag2"
]
}
]
}
response = client.batch.create(payload)
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.batch.create(
{
currency: "USD",
description: "Month end payout",
payments: [
{
sourceAmount: "150.10",
currency: "USD",
recipient:{
id: recipient.id
},
tags: ["tag1", "tag2"]
}
]
});
console.log(response.batch.id);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$batch = Trolley\Batch::create(
[ // Batch description
"sourceCurrency" => "USD",
"description" => "Month end payout"
],
[ // Payments (optional)
[
"sourceAmount" => "150.10",
"currency" => "USD",
"recipient" => [ "id" => $recipient->id ],
"tags" => ["tag1", "tag2"]
]
]);
print_r($batch);
?>
using Trolley.Types;
using Trolley;
...
Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");
Recipient recipient = GetRecipient();
Payment payment = new Payment(recipient, 150.10, "USD");
payment.tags = new List<string> { "tag1", "tag2" };
// Creating a Batch with payments
List<Payment> payments = new List<Payment>{payment};
Batch batchRequest = new Batch("Month end payout", payments, "USD", 0);
Batch batch = gateway.batch.Create(batchRequest);
Console.WriteLine(batch.id);
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
Recipient recipient = getRecipient();
// Or, create a batch with payments
Payment payment = new Payment();
payment.setAmount("150.10");
payment.setCurrency("USD");
payment.setRecipient(recipient);
payment.setTags(Arrays.asList("tag1", "tag2"));
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());
...
Add Tags to a Payment by Updating it
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",
"tags":[
"tag1",
"tag2"
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.payment.update(
batch.id,
payment.id,
{
tags:[
"tag1",
"tag2"
]
})
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
payload = {
tags:[
"tag1",
"tag2"
]
}
response = client.payment.update(payment.id, payload, batch.id)
print(response.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.payment.update(
payment.id,
batch.id,
{
tags:[
"tag1",
"tag2"
]
}
);
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$response = Trolley\Batch::updatePayment($batch->id, $payment->id,
[
"tags" => ["tag1", "tag2"]
]);
print_r($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;
updatePaymentRequest.tags = new List<string> { "tag1", "tag2" };
bool response = gateway.payment.Update(updatePaymentRequest);
Console.WriteLine(response);
...
...
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.setTags(Arrays.asList("tag`", "tag2"));
boolean response = client.payment.update(paymentId, paymentUpdateRequest, batchId);
System.out.println(response);
...
You can add and manage Tags with Payments with Add, List, and Update Payment API calls.
Following sections talk in detail about how to use tags with Payments, with sample code.
Add Tags to a Payment
You can add tags to a Payment either while creating it or by Updating a Payment.
Provide the key as tags
, and a string array as the values, with the Add or Update request.
You can also add tags to a Payment the same way when it is being created with a ‘Create a Batch’ API call.
Payment Tags through InvoicePayment
You can also add tags to payments while working with InvoicePayments API as well.
For more details, refer to the InvoicePayment API section.
Search Payments Based on Tags
You can use additional parameters in the List all Payments operation to fetch Payments based on tags.
Using the tags
query parameter, you can specify what tags you want to search for.
The API performs an AND
query based on all the query parameters you provide.
Search Payments which have all the provided Tags
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&
tags=tag1,tag2' \
// Coming soon to the Ruby SDK
// Coming soon to the Python SDK
// Coming soon to the Javascript SDK
// Coming soon to PHP SDK
// Coming soon to the C# SDK
// Coming soon to the Java SDK
Update Tags of a Payment
To update the tags of a Payment, use the Update a Payment API to replace the existing tags with new tags.
Please keep in mind that every time you update the tags, the old tags are deleted and new ones are added.
If you wish to append a new tag, you should copy all the existing tags, and send an ‘Update a Payment’ request with existing and new tags.
Update tags of 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 '{
"tags":[
"old-tag",
"new-tag"
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.payment.update(
batch.id,
payment.id,
{
tags:[
"old-tag",
"new-tag"
]
})
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
payload = {
tags:[
"old-tag",
"new-tag"
]
}
response = client.payment.update(payment.id, payload, batch.id)
print(response.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.payment.update(
payment.id,
batch.id,
{
tags:[
"old-tag",
"new-tag"
]
}
);
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$response = Trolley\Batch::updatePayment($batch->id, $payment->id,
[
"tags" => ["old-tag", "new-tag"]
]);
print_r($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;
updatePaymentRequest.tags = new List<string> { "tag1", "tag2" };
bool response = gateway.payment.Update(updatePaymentRequest);
Console.WriteLine(response);
...
...
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.setTags(Arrays.asList("old-tag", "new-tag"));
boolean response = client.payment.update(paymentId, paymentUpdateRequest, batchId);
System.out.println(response);
...
Delete Tags of a Payment
To delete Tags from a Payment, use the ‘Update a Payment’ API call with an empty tags
parameter.
Delete Tags of 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 '{
"tags":[]'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.payment.update(
batch.id,
payment.id,
{
tags:[]
})
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
payload = {
tags:[]
}
response = client.payment.update(payment.id, payload, batch.id)
print(response.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.payment.update(
payment.id,
batch.id,
{
tags:[]
}
);
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$response = Trolley\Batch::updatePayment($batch->id, $payment->id,
[
"tags" => []
]);
print_r($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;
updatePaymentRequest.tags = new List<string>();
bool response = gateway.payment.Update(updatePaymentRequest);
Console.WriteLine(response);
...
...
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.setTags(new ArrayList<String>());
boolean response = client.payment.update(paymentId, paymentUpdateRequest, batchId);
System.out.println(response);
...
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.batch.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. Max 1024 characters. |
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. Max 1024 characters. |
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>' \
-L -X POST 'https://api.trolley.com/v1/invoices/create' \
--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.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. Max 500 lines per 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. Max 500 lines per invoice. |
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. |
Tags and External ID of Invoice Lines
Please note that the field tags
and externalId
in the context of Invoice Lines are different from the fields with the same name in the context of Payments.
The tags and externalId associated with an Invoice Line are only for searching and Indexing purposes, and will not transfer to a payment created with InvoicePayment API.
However, you can add tags, externalID, and other payment related fields to an Invoice Payment by using the Create Invoice Payment API.
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.invoice.find(invoiceId: invoice.id)
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 '{
"invoiceIds": [
"I-HEG4x7Pb8VRkYZnu8Ja"
],
"paymentIds": [
"P-G4x7Pb8VYYYnu8JaHA"
],
"page": 1,
"pageSize": 5
}'
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$searchResults = Trolley\Invoice::search(
[
"invoiceIds" => [
$invoice_id1,
$invoice_id2
],
"paymentIds" => [
$payment_id1,
$payment_id2
],
"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
],
paymentIds: [
payment1.id,
payment2.id
]
page: 1,
pageSize: 5
});
console.log(response);
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.search({
invoiceIds: [
invoice1.id,
invoice2.id
],
paymentIds: [
payment1.id,
payment2.id
]
page: 1,
pageSize: 5
})
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(
{
"invoiceIds": [
f"{invoice1.id}",
f"{invoice2.id}",
],
"paymentIds": [
f"{payment1.id}",
f"{payment22.id}",
]
})
# Iterate through the generator with auto pagination
for invoice in response:
print(invoice)
# OR, search page by page
response = client.invoice.search_by_page(
{
"invoiceIds": [
f"{invoice1.id}"
f"{invoice2.id}"
]
}, 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
InvoicesIterator invoices = client.invoice.search(
Invoice.SearchBy.RECIPIENT_ID, // Search by recipientId
recipientIds, // list of recipientIds to search
null // Any search parameters, none provided here
);
while(invoices.hasNext()){
System.out.println(invoices.next().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(invoices.get(0).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. |
paymentIds[] optional array |
List of paymentIDs. Either invoiceIDs or paymentIDs must be provided. |
recipientId[] optional array |
List of recipientIDs. |
invoiceNumber[] optional array |
List of invoiceNumbers. |
invoiceDate optional string |
The date the invoice was issued. |
externalId optional array |
external IDs to search by. |
tags[] optional array |
List of tags to search by. |
memo optional string |
Search the payments by memo. |
coverFees optional boolean |
Search the payments based on whether they are covering fees. |
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.invoice.update(
invoiceId: invoice.id,
description: 'Updated Invoice'
)
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 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.invoice.create_line(
invoiceId: invoice.id,
lines: [
{
invoiceLineId: invoiceLine.id,
unitAmount: {
value: '2000',
currency: 'USD'
}
}
])
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();
String idOfLineToUpdate = getInvoiceLineId();
//Create request object
InvoiceLine lineToUpdate = new InvoiceLine();
lineToUpdate.setInvoiceLineId(idOfLineToUpdate);
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 |
Tags in an Invoice
Add Tags to an Invoice while creating it
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/create' \
--data-raw '{
"recipientId": "R-XgtzXghfxx4Z2E4Y3R",
"description": "Invoice for artwork payment",
"externalId": "acme-inv-1001",
"tags": [
"tag1",
"tag2"
],
"lines": [ ... ]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.create(
recipientId: recipient.id,
description: 'Invoice for artwork payment',
invoiceNumber: "inv-number-1001",
dueDate: "2023-02-01"
tags: [
"tag1",
"tag2"
]
lines: [ ... ]
)
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 for artwork payment",
"invoiceNumber": "inv-number-1001",
"dueDate": "2023-02-01",
"tags": [
"tag1",
"tag2"
]
"lines": [ ... ]
})
print(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.create(
{
recipientId: recipient.id,
description: "Invoice for artwork payment",
invoiceNumber: "inv-number-1001",
dueDate: "2023-02-01",
tags: [
"tag1",
"tag2"
]
lines: [ ... ]
});
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$newInvoice = Trolley\Invoice::create(
[
"recipientId" => $recipient_id,
"description" => "Invoice for artwork payment",
"invoiceNumber" => "inv-number-1001",
"dueDate" => "2023-02-01",
"tags" => ["tag1", "tag2"]
"lines" => [ ... ]
]);
print_r($newInvoice);
?>
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 = "Invoice for artwork payment";
invoiceRequest.invoiceNumber = "inv-number-1001";
invoiceRequest.dueDate = "2023-02-01";
invoiceRequest.tags = new List<string> { "tag1", "tag2"};
Invoice invoice = gateway.invoice.Create(invoiceRequest);
Console.WriteLine(invoice.id);
...
...
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("inv-number-1001");
invoice.setDescription("Invoice for artwork payment");
invoice.setExternalId("ext-id-123");
invoice.setDueDate("2023-02-01");
invoice.setTags(Arrays.asList("tag1", "tag2"));
//Making network request and collecting response
Invoice invoiceResponse = client.invoice.create(invoice);
System.out.println(invoice.getCreatedAt());
...
Add Tags to an Invoice by Updating it
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",
"tags":[
"tag1",
"tag2"
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.update(
invoiceId: invoice.id,
tags:[
"tag1",
"tag2"
])
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
response = client.invoice.update(
invoice.id,
{
"tags":[
"tag1",
"tag2"
]
})
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.invoice.update(
invoice.id,
{
tags:[
"tag1",
"tag2"
]
});
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$updateInvoice = Trolley\Invoice::update([
"invoiceId" => $invoice->id,
"tags" => ["tag1", "tag2"]
]);
print_r($updateInvoice);
?>
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.tags = new List<string> {"tag1", "tag2"};
invoice = gateway.invoice.Update(invoiceRequest);
Console.WriteLine(invoice.description);
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
String invoiceId = getInvoiceId();
Invoice invoice = new Invoice();
invoice.setTags(Arrays.asList("tag1", "tag2"));
Invoice updatedInvoice = client.invoice.update(
invoiceId,
invoice
);
System.out.println(invoice.getExternalId());
You can use Tags with Invoices through Add, Search, and Update Invoice API calls.
Following sections talk in detail about how to use tags with Invoices, with sample code.
Add Tags to an Invoice
You can add tags to an Invoice either while creating it or by Updating an Invoice.
Provide the key as tags
, and a string array as the values, with the Add or Update request.
Search Invoices Based on Tags
You can use additional parameters in the Search Invoices operation to fetch Invoices based on tags.
Using the tags
query parameter, you can specify what tags you want to search for.
The API performs an AND
query based on all the query parameters you provide.
Search Invoices which have all the provided tags
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 '{
"invoiceIds": [
"I-HEG4x7Pb8VRkYZnu8Ja"
]
"page": 1,
"pageSize": 5,
"tags": [
"tag1",
"tag2"
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.search({
invoiceIds: [
invoice.id,
],
page: 1,
pageSize: 5,
tags: [
"tag1",
"tag2"
]
})
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(
{
"invoiceIds": [
f"{invoice1.id}",
f"{invoice2.id}",
],
"tags": [
"tag1",
"tag2"
]
})
# Iterate through the returned list
for invoice in response:
print(invoice)
# Manual pagination with tags works the same way as usual search
// 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
],
tags: [
"tag1",
"tag2"
]
page: 1,
pageSize: 5
});
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$searchResults = Trolley\Invoice::search(
[
"invoiceIds" => [
$invoice_id1,
$invoice_id2
],
"tags" => [
"tag1",
"tag2"
],
"page" => 1,
"pageSize" => 5
]);
print_r($searchResults);
?>
using Trolley.Types;
using Trolley;
...
Gateway gateway = new Trolley.Gateway("<ACCESS_KEY>", "<SECRET_KEY>");
// Or, Search for an Invoice with auto-pagination
var invoices = gateway.invoice.Search(
SearchBy.Tags, // Search by recipientId
"",
"tag1", "tag2" // list of tags to search by
);
foreach (Invoice invoice in invoices)
{
Console.WriteLine(invoice.description);
}
// Refer to Invoice.Search for manually paginated search
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
ArrayList<String> recipientIds = getRecipientIds();
// Search for Invoices by multiple recipientIds
InvoicesIterator invoices = client.invoice.search(
Invoice.SearchBy.TAGS, // Search by recipientId
Arrays.asList("tag1", "tag2"), // list of tags to search by
null
);
while(invoices.hasNext()){
System.out.println(invoices.next().getDescription());
}
// Available 'searchBy' filters
enum SearchBy {
INVOICE_ID,
RECIPIENT_ID,
INVOICE_NUMBER,
INVOICE_DATE,
EXTERNAL_ID,
TAGS;
}
...
Update Tags of an Invoice
To update the tags of an Invoice, use the Update an Invoice API to replace the existing tags with new tags.
Please keep in mind that every time you update the tags, the old tags are deleted and new ones are added.
If you wish to append a new tag, you should copy all the existing tags, and send an ‘Update an Invoice’ request with existing and new tags.
Update Tags of an Invoice
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",
"tags":[
"old-tag",
"new-tag"
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.update(
invoiceId: invoice.id,
tags:[
"old-tag",
"new-tag"
])
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
response = client.invoice.update(
invoice.id,
{
"tags":[
"old-tag",
"new-tag"
]
})
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.invoice.update(
invoice.id,
{
tags:[
"old-tag",
"new-tag"
]
});
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$updateInvoice = Trolley\Invoice::update([
"invoiceId" => $invoice->id,
"tags" => ["old-tag", "new-tag"]
]);
print_r($updateInvoice);
?>
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.tags = new List<string> {"old-tag", "new-tag"};
invoice = gateway.invoice.Update(invoiceRequest);
Console.WriteLine(invoice.description);
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
String invoiceId = getInvoiceId();
Invoice invoice = new Invoice();
invoice.setTags(Arrays.asList("old-tag", "new-tag"));
Invoice updatedInvoice = client.invoice.update(
invoiceId,
invoice
);
System.out.println(invoice.getExternalId());
Delete Tags of an Invoice
To delete Tags from an Invoice, use the ‘Update an Invoice’ API call with an empty tags
parameter.
Delete Tags of an Invoice
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",
"tags":[]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.update(
invoiceId: invoice.id,
tags:[])
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
response = client.invoice.update(
invoice.id,
{
"tags":[]
})
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.invoice.update(
invoice.id,
{
tags:[]
});
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$updateInvoice = Trolley\Invoice::update([
"invoiceId" => $invoice->id,
"tags" => []
]);
print_r($updateInvoice);
?>
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.tags = new List<string>();
invoice = gateway.invoice.Update(invoiceRequest);
Console.WriteLine(invoice.description);
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
String invoiceId = getInvoiceId();
Invoice invoice = new Invoice();
invoice.setTags(new ArrayList<String>());
Invoice updatedInvoice = client.invoice.update(
invoiceId,
invoice
);
System.out.println(invoice.getExternalId());
Tags in an Invoice Line
Add Tags to an InvoiceLine while adding it to an Invoice
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"
},
"tags":[
"tag1",
"tag1"
]
}
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.create_line(
invoiceId: invoice.id,
lines: [
{
unitAmount: {
value: '200',
currency: 'EUR'
},
tags:[
"tag1",
"tag1"
]
}
])
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" : "200.00",
"currency" : "EUR"
},
"tags":[
"tag1",
"tag1"
]
}
])
print(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.create(
{
invoice: {
id: invoice.id
},
unitAmount: {
value: "50.00",
currency: "EUR"
},
tags:[
"tag1",
"tag1"
]
});
console.log(response);
<?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"
],
"tags" => ["tag1", "tag2"]
]
]);
print_r($invoiceWithLines);
?>
// Coming soon to the C# SDK
...
...
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);
invoiceLine.setTags(Arrays.asList("tag1", "tag2"));
//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
}
...
Add Tags to an InvoiceLine while creating it with a new Invoice
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/create' \
--data-raw '{
"recipientId": "R-XgtzXghfxx4Z2E4Y3R",
"lines": [
{
"unitAmount": {
"value": "100",
"currency": "EUR"
},
"tags":[
"tag1",
"tag1"
]
}
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.create(
recipientId: recipient.id,
lines: [
{
unitAmount: {
value: '200',
currency: 'EUR'
},
tags:[
"tag1",
"tag1"
]
}
]
)
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"
},
"tags":[
"tag1",
"tag1"
]
}
])
print(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.create(
{
recipientId: recipient.id,
lines: [
{
unitAmount: {
value: '200',
currency: 'EUR'
},
tags:[
"tag1",
"tag1"
]
}
]
});
console.log(response);
<?php
use Trolley;
Trolley\Configuration::publicKey('YOUR_ACCESS_KEY');
Trolley\Configuration::privateKey('YOUR_SECRET_KEY');
$newInvoice = Trolley\Invoice::create(
[
"recipientId" => $recipient_id,
"lines" => [
[
"unitAmount" =>[
"value" => "50.00",
"currency" => "EUR"
],
"tags" => ["tag1", "tag2"]
]
]
]);
print_r($newInvoice);
?>
// Coming soon to the C# SDK
...
...
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("inv-number-1001");
invoice.setDescription("Invoice for artwork payment");
invoice.setExternalId("ext-id-123");
invoice.setDueDate("2023-02-01");
InvoiceLine invoiceLine = new InvoiceLine();
invoiceLine.setTags(Arrays.asList("tag1", "tag2"));
invoice.setLines(Arrays.asList(invoiceLine));
Invoice invoiceResponse = client.invoice.create(invoice);
System.out.println(invoice.getCreatedAt());
...
Add Tags to an InvoiceLine by updating it
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",
"unitAmount": {
"value": "250",
"currency": "EUR"
},
"tags":[
"tag1",
"tag1"
]
}
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.create_line(
invoiceId: invoice.id,
lines: [
{
invoiceLineId: invoiceLine.id,
tags:[
"tag1",
"tag1"
]
}
])
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'],
"tags":[
"tag1",
"tag1"
]
}
])
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.invoiceLine.update(
invoice.id,
{
lines: [
{
invoiceLineId: invoiceLine.id,
tags:[
"tag1",
"tag1"
]
}
]
});
console.log(response);
<?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,
"tags" => [
"tag1",
"tag1"
]
]
]);
print_r($updatedInvoice);
?>
// Coming soon to the C# SDK
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
String invoiceId = getInvoiceId();
String idOfLineToUpdate = getInvoiceLineId();
//Create request object
InvoiceLine lineToUpdate = new InvoiceLine();
lineToUpdate.setInvoiceLineId(idOfLineToUpdate);
lineToUpdate.setTags(Arrays.asList("tag1", "tag2"));
//Update an invoice line
Invoice invoice = client.invoiceLine.update(
invoiceId,
lineToUpdate);
System.out.println(invoice.getLines().get(0).getId());
...
You can use Tags with InvoiceLines through Add and Update InvoiceLines API calls.
Following sections talk in detail about how to use tags with InvoiceLines, with sample code.
Add Tags to an InvoiceLine
You can add tags to an InvoiceLine either while adding it to an Invoice or by updating an existing InvoiceLine.
Provide the key as tags
, and a string array as the values, with the Add or Update request.
You can also add tags to InvoiceLines while adding them during Create an Invoice API call.
Update Tags of an InvoiceLine
To update the tags of an InvoiceLine, use the Update an InvoiceLine API to replace the existing tags with new tags.
Please keep in mind that every time you update the tags, the old tags are deleted and new ones are added.
If you wish to append a new tag, you should copy all the existing tags, and send an ‘Update an InvoiceLine’ API call.
Update tags of an InvoiceLine
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",
"tags":[
"old-tag",
"new-tag"
]
}
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.create_line(
invoiceId: invoice.id,
lines: [
{
invoiceLineId: invoiceLine.id,
tags:[
"old-tag",
"new-tag"
]
}
])
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'],
"tags":[
"old-tag",
"new-tag"
]
}
])
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.invoiceLine.update(
invoice.id,
{
lines: [
{
invoiceLineId: invoiceLine.id,
tags:[
"old-tag",
"new-tag"
]
}
]
});
console.log(response);
<?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,
"tags" => [
"old-tag",
"new-tag"
]
]
]);
print_r($updatedInvoice);
?>
// Coming soon to the C# SDK
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
String invoiceId = getInvoiceId();
String idOfLineToUpdate = getInvoiceLineId();
//Create request object
InvoiceLine lineToUpdate = new InvoiceLine();
lineToUpdate.setInvoiceLineId(idOfLineToUpdate);
lineToUpdate.setTags(Arrays.asList("old-tag", "new-tag"));
//Update an invoice line
Invoice invoice = client.invoiceLine.update(
invoiceId,
lineToUpdate);
System.out.println(invoice.getLines().get(0).getId());
...
Delete Tags of an InvoiceLine
To delete Tags from an InvoiceLine, use the ‘Update an InvoiceLine’ API call with an empty tags
parameter.
Delete Tags of an InvoiceLine
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",
"tags":[ ]
}
]
}'
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice.create_line(
invoiceId: invoice.id,
lines: [
{
invoiceLineId: invoiceLine.id,
tags:[]
}
])
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'],
"tags":[]
}
])
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.invoiceLine.update(
invoice.id,
{
lines: [
{
invoiceLineId: invoiceLine.id,
tags:[]
}
]
});
console.log(response);
<?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,
"tags" => [ ]
]
]);
print_r($updatedInvoice);
?>
// Coming soon to the C# SDK
...
...
Configuration config = new Configuration("<ACCESS_KEY>","<SECRET_KEY>");
Gateway client = new Gateway(config);
String invoiceId = getInvoiceId();
String idOfLineToUpdate = getInvoiceLineId();
//Create request object
InvoiceLine lineToUpdate = new InvoiceLine();
lineToUpdate.setInvoiceLineId(idOfLineToUpdate);
lineToUpdate.setTags(new List<String>());
//Update an invoice line
Invoice invoice = client.invoiceLine.update(
invoiceId,
lineToUpdate);
System.out.println(invoice.getLines().get(0).getTags().size());
...
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",
"memo": "payment memo",
"externalId": "payment-external-id_123",
"tags": [
"invoice_payment",
"royalty invoice"
],
"coverFees": true,
"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([
[
"memo" => "payment memo",
"externalId" => "payment-external-id_123",
"tags" => [
"invoice_payment",
"royalty invoice"
],
"coverFees"=> true,
"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(
{
memo: "payment memo",
externalId: "payment-external-id_123",
tags: [
"invoice_payment",
"royalty invoice"
],
coverFees: true,
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(
{
memo: "payment memo",
externalId: "payment-external-id_123",
tags: [
"invoice_payment",
"royalty invoice"
],
coverFees: true,
invoiceId: invoice.id,
amount: {
currency: "USD",
value: "100"
}
})
print response
from trolley.configuration import Configuration
client = Configuration.gateway(f'{ACCESS_KEY}', f'{SECRET_KEY}')
invoice_payment = client.invoice_payment.create([
{
"memo": "payment memo",
"externalId": "payment-external-id_123",
"tags": [
"invoice_payment",
"royalty invoice"
],
"coverFees": true,
"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"));
String[] tags = {"tag1", "tag2"};
InvoicePaymentRequest invoicePaymentRequest = new InvoicePaymentRequest(
"optional-batch-id", // If set to null, a new batch will be created
false, // coverFees parameter to add to the payment
"Created Payment's Memo", // Memo to add to the payment
"payment-external-id", // Created payment's external-id
tags, // Tags to add to the created payment
paymentPart);
// Create an InvoicePayment as per the request above
InvoicePayment invoicePayment = client.invoicePayment.create(invoicePaymentRequest);
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 invoicePaymentPart = new InvoicePaymentPart();
invoicePaymentPart.invoiceId = invoiceId;
invoicePaymentPart.invoiceLineId = invoiceLineId;
invoicePaymentPart.amount = new Amount("100.00", "USD");
InvoicePaymentRequest invoicePaymentRequest = new InvoicePaymentRequest(
new InvoicePaymentPart[]{invoicePaymentPart}, // Amounts, IDs of invoices and invoiceLines
null, // BatchID (String. Optional.)
false, // Should Payment coverFees?
"payment-memo", // Payment Memo
"payment-external-id", // Payment External ID
new string[]{"payment-tag1", "payment-tag2"}); // Payment Tags
InvoicePayment invoicePayment = gateway.invoicePayment.Create(invoicePaymentRequest);
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"
},
"status": "pending",
"memo": "payment memo",
"externalId": "payment-external-id_123",
"tags": [
"invoice_payment",
"royalty invoice"
],
"coverFees": true
}
]
}
}
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.
Add Payment Fields to Invoice Payments
While creating an Invoice Payment, you can optionally send payment related information to add to the payment that will be created. This information can include the External ID of the payment, any associated Memo (visible to the Recipient), any Tags (internal to the Merchant), and whether you’d want to cover the fees.
You can send this information by setting the values of the fields externalId
, memo
, tags
, and coverFees
.
The following section details the query parameters, and the sample code in cURL shows how to send these parameters in the API requests.
HTTP Request
POST https://api.trolley.com/v1/invoices/payment/create
Fields | Description |
---|---|
batchId optional string |
Batch to add the payments to. |
externalId optional string |
External ID to assign to the Payment. |
memo optional string |
Memo to add to the Payment. This will be visible to the Recipient. Max 1024 characters. |
tags[] optional array |
A JSON String array where each element is the tag that you want to add to the Payment. |
coverFees optional boolean |
Set this to true if you want to cover the fees. |
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 '{
"invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
"invoiceLineId": "IL-EtrPXL9aytREz2vdVgk",
"paymentId": "P-BCZR5HYHKPRpvfSKYKetsY",
"amount": {
"value": "150.00",
"currency": "EUR"
},
"memo": "payment memo",
"externalId": "payment-external-id_123",
"tags": [
"invoice_payment",
"royalty invoice"
],
"coverFees": false
}'
<?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"]
],
"memo" => "payment memo",
"externalId" => "payment-external-id_123",
"tags" => [
"invoice_payment",
"royalty invoice"
],
"coverFees" => false
]);
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"
},
memo: "payment memo",
externalId: "payment-external-id_123",
tags: [
"invoice_payment",
"royalty invoice"
],
coverFees: false
});
console.log(response);
require 'trolley'
client = Trolley.client('YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY')
response = client.invoice_payment.update(
paymentId: paymentId,
invoiceLineId: invoiceLineId,
amount: {
value: '5000',
currency: 'USD'
},
memo: "payment memo",
externalId: "payment-external-id_123",
tags: [
"invoice_payment",
"royalty invoice"
],
coverFees: false
)
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"
},
"memo": "payment memo",
"externalId": "payment-external-id_123",
"tags": [
"invoice_payment",
"royalty invoice"
],
"coverFees": false
}
)
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);
// Payment Fields related updates are coming soon to the Java SDK.
...
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);
// Payment Fields related updates are coming soon to the C# SDK.
...
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"
}
]
}
Update an already existing Invoice Payment’s details.
HTTP Request
POST https://api.trolley.com/v1/invoices/payment/update
Fields | Description |
---|---|
invoiceId required string |
ID of the Invoice whose payment needs to be updated. |
invoiceLineId required string |
ID of the Invoice Line whose payment needs to be updated. |
paymentId required string |
ID of the Payment that needs to be updated. |
amount.value required string |
The value (e.g. “100.00”) to pay. Note if the value is provided, currency must be provided. |
amount.currency required string |
Currency to pay in - must match the invoice currency. |
externalId optional string |
External ID to assign to the Payment. |
memo optional string |
Memo to add to the Payment. This will be visible to the Recipient. Max 1024 characters. |
tags[] optional array |
A JSON String array where each element is the tag that you want to add to the Payment. |
coverFees optional boolean |
Set this to true if you want to cover the fees. |
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.invoice_payment.search(invoiceIds: [invoice.id])
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());
}
...
// Payment Fields related updates are coming soon to the Java SDK.
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);
}
...
// Payment Fields related updates are coming soon to the C# SDK.
Example Response (200 Ok)
{
"ok": true,
"invoicePayments": [
{
"invoiceId": "I-HEG4x7Pb8VRkYZnu8Ja",
"invoiceLineId": "IL-EtrPXL9aytREz2vdVgk",
"paymentId": "P-BCZR5HYHKPRpvfSKYKetsY",
"amount": {
"value": "150.00",
"currency": "EUR"
},
"memo": "payment memo",
"externalId": "payment-external-id_123",
"tags": [
"invoice_payment",
"royalty invoice"
],
"coverFees": true
}
],
"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 |
Tax
Overview
Our Tax product enables you to collect tax information from your recipients via the Trolley Widget.
We support US and DAC7 Tax information collection, with more jurisdictions planned.
You can find the Tax product in Settings > Tax Compliance in the Merchant Dashboard.
To use Tax in production, your subscription plan should include Tax. However, it is available to everybody in the sandbox mode.
Tax Module in Widget
You can use Trolley Widget to collect tax information from the recipients.
For more information on how to setup the Widget for this, head over to the Widget Module documentation in the Widget Section.
Tax Webhook
You can subscribe to Tax Webhooks to receive a notification on your servers from us whenever the status of a tax form - whether provided or uploaded - is updated.
You can use these updates to manage logic on your end.
Please refer to the Webhooks documentation, specifically the Tax Form Model and it’s actions.
Tax API
The Tax product doesn’t have API access available yet, if you’re interested in using Tax product through the APIs, we’ll love to hear your use cases. Please write to us on developers@trolley.com or let your Customer Success Manager know.
Trust
The Trust offering from Trolley enables you to verify recipients right from within Trolley.
The recipient facing section of Trust is accessible via Widget or Portal.
In this section we’ll discuss the APIs that enable you to view details around the verification attempts of recipients.
Get Verifications
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/verifications?
verificationType=individual&
recipientIds[]=R-ASC2387123aa21xx&
recipientIds[]=R-VAC2387123aa21DD&
startDate=2024-01-10&
endDate=2024-01-20&
status[]=pending&
status[]=rejected&
page=1&
pageSize=10'
Example Response (200 Ok)
{
"ok": true,
"verifications": [
{
"id": "IV-XYZCzvuNJFPmFCJpz",
"recipientId": "R-XXXXX",
"type": "individual",
"status": "retry",
"createdAt": "2024-01-12T20:24:29.954Z",
"updatedAt": "2024-01-15T20:26:29.954Z",
"submittedAt": "2024-01-12T20:24:29.954Z",
"decisionAt": "2024-01-15T20:24:29.954Z",
"reasonType": "invalid",
"verifiedData":
{
"...multiple values possible, see below..."
}
}
],
"meta": {
"page": 1,
"pages": 1,
"records": 1
}
}
verifiedData
value for verification typephone
{
...
"verifiedData": {
"phone": "+1 416 123 4567",
"channel": "sms"
}
...
}
verifiedData
value for verification typeindividual
{
...
"verifiedData": {
"documentIssuingCountry": "US",
"documentType": "PASSPORT",
"documentValidFrom": "2024-07-01T00:00:00.000Z",
"documentValidUntil": "2029-07-03T00:00:00.000Z",
"firstName": "Jane",
"lastName": "Smith",
"dob": "1980-01-15",
"address": {
"street1": "123 Main St",
"street2": "",
"city": "San Francisco",
"postalCode": "94131",
"country": "US",
"region": "CA"
}
}
...
}
verifiedData
value for verification typebusiness
{
...
"verifiedData": {
"businessRegistrationNumber": "BRN1234-5678",
"name": "Acme Inc.",
"address": {
"street1": "123 Main St",
"street2": "",
"city": "San Francisco",
"postalCode": "94131",
"country": "US",
"region": "CA"
}
}
...
}
The Get Verifications API returns verification status of a given recipient.
HTTP Request
GET https://api.trolley.com/v1/verifications/
Request Parameters
Fields | Description |
---|---|
verificationType required string |
What kind of verification you want to fetch. Pass any one of these allowed values: individual , business , or phone . |
recipientId[] optional string[] |
List of recipientIds you want to fetch verification statuses for. |
startDate optional date |
Start date of result set. Ignore records older than this date. |
endDate optional date |
End date of result set. Ignore records newer than this date. |
status optional string[] |
Which verification record you want to fetch. You can supply a string array containing multiple values from the allowed list: pending , submitted , retry , approved , or rejected . |
page optional int |
The page you’ll want to fetch. Used for pagination. Default is 1. |
pageSize optional int |
Items per page. Used for pagination. Default is 10. |
HTTP Response
The response contains many standard attributes across verification types (id
, recipientId
, type
, status
, decisionAt
, createdAt
, updatedAt
).
Details specific to a verification type are presented within verifiedData
attribute.
Look at the examples in the code sample section for more details.
HTTP Response codes
HTTP Code | Description |
---|---|
200 | Request successful |
400 | One or more fields failed validation, see errors[] in response body |
401 | Invalid API key |
500 | Internal error |
Response Attribute Breakdown
Here’s a breakdown of allowed values in some attributes and what they mean:
Address and special cases
The address
fields for individual and business user types are populated based on what was available on the document uploaded for verification.
So, sometimes the address may not have country
populated.
As a fallback, if country
is not populated you can take following measures:
- For
individual
recipients, fallback todocumentIssuingCountry
. - For
business
recipients, fallback to the recipient’s profile country.
Type
The type
attribute represents the type of verification record. Based on your subscription plan, it can have either of the following 3 values:
Type | Description |
---|---|
individual | Verifying an individual with a government issued document including face-match. |
business | Verification of a business entity with government documentation. |
phone | The verification record represents a phone number verification. |
Status
The status
attribute denotes the status of the verification, and can have either of the following values:
Value | Description |
---|---|
pending | Attempt has started but recipient is still required to submit required information. |
submitted | Recipient has submitted required information. |
retry | The information recipient submitted was unable to be processed and can be retried within the same attempt. |
approved | Submitted information was verified successfully. |
rejected | Submitted data could not be verified and was rejected, see reason for more details (for individual/business). |
Reason Type
The reasonType
attribute denotes why the verification failed. The following table details these different reasons, and how to fix them:
Type | Description | Example | Remediation |
---|---|---|---|
unprocessable | Asset provided is not processable for extraction, either due to lack of text or filetype. | Uploading a photo that lacks reference to a document (ie a random screen shot or blank). | Provide an upload with the proper file type with the document clearly in-view. |
invalid | Asset does not meet the type of asset required to be validated. | A self-created document such as a W8 or Invoice. | Provide a document issued or certified by a government entity. |
missing_requirements | Asset doesn’t match or contain all the details provided. | A proper document that lacks required data points or is misaligned with the provided details. | Ensure the details provided in your profile match those on the document, with the required data points present. |
fraudulent | Asset has signs of being tampered with to deceive the verification process. | Self-edited documents that are issued by third-party entities. | Provide original documentation. |
null | Verification did not fail. | Not Applicable | Not Applicable |
Verified Data values breakdown
Here’s a description of some attributes which can have a set of different values:
For phone
Verification
Type | Description |
---|---|
channel |
Shows which channel was used to perform phone number verification - SMS Text or a Phone Call. Can have sms or phone as values. |
For individual
Verification
Type | Description |
---|---|
documentType |
Shows which document type was used to complete verification. Allowed values are PASSPORT , ID_CARD , DRIVERS_LICENSE , RESIDENCE_PERMIT , VISA , OTHER , or null if no document was provided. |
documentIssuingCountry |
Contains the ISO ALPHA-2 code of the issuing country of the document used for verification. E.g. US, CA, UK etc. |
Data Extraction on Verification Failure
On verification failure, we include any data that could be extracted in the verification attempt.
This data will be available in the response of Get Verifications API call.
Errors
When the Trust API can not process your request and sends a non-200 HTTP response, an accompanying errors[]
array will explain the reasons why the request could not be fulfilled.
Refer to the code sample area to see samples of common errors you may encounter.
{
"ok": false,
"errors": [
{
"code": "forbidden",
"message": "Cannot fetch business verifications. User unauthorized"
}
]
}
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
Opening Webhooks Section
To add a new Webhook in sandbox or live environment:
- Go to Dashboard > Settings > Webhooks.
- Click on New Webhook Button on the top right.
- 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).
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 a table listing all Models that Webhooks offer, along with their respective Actions that you can listen to.
Each individual action name is also linked to a sample json body that you’ll receive when this Webhook is fired. Click on the link to download it.
Models | Actions & Samples |
---|---|
All Models | All Actions |
User |
1. All Actions 2. Updated 3. Deleted 4. Created |
Recipient |
1. All Actions 2. Created 3. Updated 4. Deleted |
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.1. Processed (Action: Complete) 6.2. Completed (Action: Complete) 7. Failed (Action: Complete) |
Tax Form |
1. All Updates 2. Status Changed |
Recipient Verification |
1. All Actions 1. Created 2. Status Changed |
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:
-
X-PaymentRails-Signature
– This contains a timestamp and a unique HMAC 256 signature to help verify the sender of the event. -
X-PaymentRails-Delivery
– This is a unique id that allows your service to know if a Webhook has already been delivered. If Trolley does not receive a 200 response from your service when sending a Webhook it will retry with the same ID. -
X-PaymentRails-Created
– This is when the event was created at Trolley, we attempt to deliver all Webhooks in order, it’s not guaranteed due to network issues so this allows you to ignore older events if necessary.
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
...
$post_body_payload = json_encode(json_decode(file_get_contents("php://input")), JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
$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, false);
if($digest == $v1){
echo "Webhook valid";
}
...
To verify the request, follow these steps:
- Extract values of
t
andv1
from theX-PaymentRails-Signature
header. - Concatenate timestamp value found in
t
with the raw POST body that you received with the request. - Calculate the sha256 hash of the concatenated value using the
hmac
key you get for each Webhook from Dashboard.
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
We send out Webhooks as soon as the respective events occur, but the deliveries can’t be guaranteed to be instantaneous.
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.
Webhook Source IPs
The Webhook requests to your servers will be sent from one of the following two IPs addresses that you can whitelist on your end:
IP Address |
---|
54.80.45.38 |
3.217.196.153 |
References
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 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"
}
}
}
Payout Methods by Country
Trolley supports various payout methods per country to deliver the payouts to recipients.
Our website hosts this interactive tool to find out what methods and what routes are supported per country.
You can find what’s available for each region of our network here: https://trolley.com/platform/global-payout-network/
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 returned 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 occurring. |
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 "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. |
partially_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 . |
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 Identity 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:
- A Payment is added to a Batch, and
- 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
How to use Trolley API’s Postman Collection
- Click on the “Run in Postman” button below.
- Fork it into your own Postman account.
- Setup your fork according to the setup instructions below.
- 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
- Add the above Global Variables in Postman.
- Get API
ACCESS KEY
and APISECRET KEY
from you Trolley Dashboard. - Put these keys in the above-mentioned Postman Global Variables.
- Fill the
trolley_api_base_url
value. - Start sending requests!
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 |