navigation hamburger icon

API Documentation

Table of Contents

curl Ruby Python Javascript PHP C# Java

Widget Integration Instructions

const crypto = require("crypto");
const url = require("url");

const KEY = "sample-api-key";
const SECRET = "sample-secret";

const recipientEmail = "sample@recipient.com";
const recipientReferenceId = "sample@recipient.com";

const widgetBaseUrl = new url.URL("https://widget.trolley.com");
const querystring = new url.URLSearchParams({
  ts: Math.floor(new Date().getTime() / 1000),
  key: KEY,
  email: recipientEmail,
  refid: recipientReferenceId,
  hideEmail: "false", // optional parameter: if 'true', hides the email field
  roEmail: "false", // optional parameter: if 'true', renders the email field as Read Only
  // payoutMethods: "bank-transfer,paypal",   // optional parameter: filters the possible payout methods shown on the widget
  locale: "en", // optional parameter: ISO 639-1 language code, changes the language of the widget
  /*
  ** Adding address fields is optional, Used to easily populate
  ** the widget with default values.
  **
  'addr.firstName': 'firstName',
  'addr.lastName': 'lastName',
  'addr.governmentId': 'governmentId',
  'addr.street1': 'street1',
  'addr.street2': 'street2',
  'addr.city': 'city',
  'addr.postalCode': 'postalCode',
  'addr.region': 'AL',
  'addr.country': 'US',
  */
  /*
  ** Adding color fields is also optional, used to override the
  ** color settings set in the dashboard. Note that these overrides must
  ** be valid CSS compatible colors.
  **
  'colors.heading': '#111111',
  'colors.inputText': '#222222',
  'colors.inputBorder': '#333333',
  'colors.text': '#555555',
  'colors.subText': '#666666',
  'colors.background': '#777777',
  'colors.primary': 'red',
  'colors.border': 'blue',
  'colors.success': '#AAAAAA',
  'colors.error': '#BBBBBB',
  'colors.warning': '#CCCCCC',
  */
})
  .toString()
  .replace(/\+/g, "%20");

const hmac = crypto.createHmac("sha256", SECRET);
hmac.update(querystring);

// Signature is only valid for 30 seconds
const signature = hmac.digest("hex");
widgetBaseUrl.search = querystring + "&sign=" + signature;

// you can send the link to your view engine
const widgetLink = widgetBaseUrl.toString();
<?php
  $WIDGET_BASE_URL = "https://widget.trolley.com";
  $KEY = "sample-api-key";
  $SECRET = "sample-secret";

  $recipientEmail = "sample@recipient.com";
  $recipientReferenceId = "sample@recipient.com";

  $ts = time();

  $querystring = http_build_query([
    "refid" => $recipientReferenceId,
    "ts" => $ts,
    "key" => $KEY,
    "email" => $recipientEmail,
    "hideEmail" => "false",                       // optional parameter: if "true", hides the email field
    "roEmail" => "false",                         // optional parameter: if "true", renders the email field as Read Only
    // "payoutMethods" => "bank-transfer,paypal", // optional parameter: filters the possible payout methods shown on the widget
    "locale" => "en",                             // optional parameter: ISO 639-1 language code, changes the language of the widget

    /*
    ** Adding address fields is optional, Used to easily populate
    ** the widget with default values.
    **
    "addr.firstName" => "firstName",
    "addr.lastName" => "lastName",
    "addr.governmentId" => "governmentId",
    "addr.street1" => "street1",
    "addr.street2" => "street2",
    "addr.city" => "city",
    "addr.postalCode" => "postalCode",
    "addr.region" => "AL",
    "addr.country" => "US",
    */

    /*
    ** Adding color fields is also optional, used to override the
    ** color settings set in the dashboard. Note that these overrides must
    ** be valid CSS compatible colors.
    **
    "colors.heading" => "#111111",
    "colors.inputText" => "#222222",
    "colors.inputBorder" => "#333333",
    "colors.text" => "#555555",
    "colors.subText" => "#666666",
    "colors.background" => "#777777",
    "colors.primary" => "red",
    "colors.border" => "blue",
    "colors.success" => "#AAAAAA",
    "colors.error" => "#BBBBBB",
    "colors.warning" => "#CCCCCC",
    */
  ], null, "&", PHP_QUERY_RFC3986);

  # Signature is only valid for 30 seconds
  $signature = hash_hmac("sha256", $querystring, $SECRET);

  $widget_link = $WIDGET_BASE_URL."?". $querystring."&sign=".$signature
?>

<iframe src="<?php echo $widget_link ?>"></iframe>
# -*- coding: iso-8859-15 -*-
import hashlib
import hmac
import time
try:
    import urllib.parse
    urlencode = urllib.parse.urlencode
except:
    import urllib
    urlencode = urllib.urlencode

WIDGET_BASE_URL = 'https://widget.trolley.com'
KEY = b'sample-api-key'
SECRET = 'sample-secret'
recipient_email = 'sample@recipient.com'
recipient_reference_id = 'sample@recipient.com'

query = urlencode({
  'ts': int(time.time()),
  'email': recipient_email,
  'refid': recipient_reference_id,
  'hideEmail': 'false',                       # optional parameter: if 'true', hides the email field
  'roEmail': 'false',                         # optional parameter: if 'true', renders the email field as Read Only
  # 'payoutMethods': 'bank-transfer,paypal',  # optional parameter: filters the possible payout methods shown on the widget
  'locale': 'en',                             # optional parameter: ISO 639-1 language code, changes the language of the widget

  # 'addr.firstName' : 'firstName',           # Adding addr. fields is optional. Used to easily populate
  # 'addr.lastName': 'lastName',              # the widget with default values.
  # 'addr.governmentId': 'governmentId',
  # 'addr.street1': 'street1',
  # 'addr.street2': 'street2',
  # 'addr.city': 'city',
  # 'addr.postalCode': 'postalCode',
  # 'addr.region': 'AL',
  # 'addr.country': 'US',

  # 'colors.heading': '#111111',              # Adding color fields is also optional, used to override the
  # 'colors.inputText': '#222222',            # color settings set in the dashboard. Note that these overrides must
  # 'colors.inputBorder': '#333333',          # be valid CSS compatible colors.
  # 'colors.text': '#555555',
  # 'colors.subText': '#666666',
  # 'colors.background': '#777777',
  # 'colors.primary': 'red',
  # 'colors.border': 'blue',
  # 'colors.success': '#AAAAAA',
  # 'colors.error': '#BBBBBB',
  # 'colors.warning': '#CCCCCC',

  'key': KEY,
}).replace("+", "%20").encode('utf8')

query = '%s&sign=%s' % (
  query,
  hmac.new(SECRET, query, digestmod=hashlib.sha256).hexdigest()
)
require "openssl"
require "ostruct"
require "uri"

WIDGET_BASE_URL = "https://widget.trolley.com"
API = "sample-api-key"
SECRET = "sample-secret"
recipient_email = "sample@recipient.com"
recipient_reference_id = "sample@recipient.com"

ts = Time.now.to_i

query = {
  'email' => recipient_email,
  'refid' => recipient_reference_id,
  'ts' => ts,
  'key' => API,
  'hideEmail' => false,                         # optional parameter: if 'true', hides the email field
  'roEmail' => false,                           # optional parameter: if 'true', renders the email field as Read Only
  # 'payoutMethods' => 'paypal',                # optional parameter: filters the possible payout methods shown on the widget
  'locale' => 'en'                              # optional parameter: ISO 639-1 language code, changes the language of the widget

  # 'addr.firstName' => 'firstName',            # Adding addr. fields is optional. Used to easily populate
  # 'addr.lastName' => 'lastName',              # the widget with default values.
  # 'addr.governmentId' => 'governmentId',
  # 'addr.street1' => 'street1',
  # 'addr.street2' => 'street2',
  # 'addr.city' => 'city',
  # 'addr.postalCode' => 'postalCode',
  # 'addr.region' => 'AL',
  # 'addr.country' => 'US',

  # 'colors.heading' => '#111111',               # Adding color fields is also optional, used to override the
  # 'colors.inputText' => '#222222',             # color settings set in the dashboard. Note that these overrides must
  # 'colors.inputBorder' => '#333333',           # be valid CSS compatible colors.
  # 'colors.text' => '#555555',
  # 'colors.subText' => '#666666',
  # 'colors.background' => '#777777',
  # 'colors.primary' => 'red',
  # 'colors.border' => 'blue',
  # 'colors.success' => '#AAAAAA',
  # 'colors.error' => '#BBBBBB',
  # 'colors.warning' => '#CCCCCC'
}

digest = OpenSSL::Digest.new("sha256")

query_string = URI.encode_www_form(query).gsub("+", "%20")

# Signature is only valid for 30 seconds
signature = OpenSSL::HMAC.hexdigest(digest, SECRET, query_string)

# you can use the link in your templating engine
widget_link = "#{WIDGET_BASE_URL}?#{query_string}&sign=#{signature}"
using System;
using System.Text;
using System.Collections.Generic;
using System.Security.Cryptography;

class Program
{
  static void Main(string[] args)
  {
    var API = "sample-api-key";
    var SECRET = "sample-secret";
    var widgetBaseUrl = "https://widget.trolley.com";
    var recipientEmail = "sample@recipient.com";
    var recipientReferenceId = "sample@recipient.com";

    Dictionary<string, string> queryParams = new Dictionary<string, string>{
              { "ts", $"{(int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds}" },
              { "key", $"{API}" },
              { "email", $"{recipientEmail}" },
              { "refid", $"{recipientReferenceId}" },
              { "hideEmail", "false" },                 // optional parameter: if true, hides the email field
              { "roEmail", "false" },                   // optional parameter: if true, renders the email field as Read Only
              // { "payoutMethods", "bank-transfer" },  // optional parameter: filters the possible payout methods shown on the widget
              { "locale", "en" }                        // optional parameter: ISO 639-1 language code, changes the language of the widget
              /*
              ** Adding address fields is optional, Used to easily populate
              ** the widget with default values.
              **
              { "addr.firstName", "firstName" },
              { "addr.lastName", "lastName" },
              { "addr.governmentId", "governmentId" },
              { "addr.street1", "street1" },
              { "addr.street2", "street2" },
              { "addr.city", "city" },
              { "addr.postalCode", "postalCode" },
              { "addr.region", "AL" },
              { "addr.country", "US" },
              */

              /*
              ** Adding color fields is also optional, used to override the
              ** color settings set in the dashboard. Note that these overrides must
              ** be valid CSS compatible colors.
              **
              { "colors.heading", "#111111" }
              { "colors.inputText", "#222222" }
              { "colors.inputBorder", "#333333" }
              { "colors.text", "#555555" }
              { "colors.subText", "#666666" }
              { "colors.background", "#777777" }
              { "colors.primary", "red" }
              { "colors.border", "blue" }
              { "colors.success", "#AAAAAA" }
              { "colors.error", "#BBBBBB" }
              { "colors.warning", "#CCCCCC" }
              */
            };

    string query = "";

    foreach (var kvp in queryParams)
    {
      query += $"{kvp.Key}={Uri.EscapeDataString(kvp.Value)}&";
    }

    HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(SECRET));
    // Signature is only valid for 30 seconds
    var signature = (BitConverter.ToString(hmac.ComputeHash(Encoding.UTF8.GetBytes(query)))).Replace("-", "").ToLower();

    string returnUrl = ($"{widgetBaseUrl}?{query}&sign={signature}");
  }
}

// Created using Java 19
// Using org.apache.http.client.utils.URIBuilder;

import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

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

import org.apache.http.client.utils.URIBuilder;

public class Widget
{
    public String getTrolleyWidgetUrl() throws URISyntaxException, NoSuchAlgorithmException, InvalidKeyException
    {

        // Setup values
        String SCHEME = "https";
        String WIDGET_HOST = "widget.trolley.com";

        String ACCESS_KEY = "<YOUR_ACCESS_KEY>";
        String ACCESS_SECRET = "<YOUR_ACCESS_KEY>";
        
        int timestamp = (int)(System.currentTimeMillis() / 1000L);

        String recipientEmail = "sample@recipient.com";
        String recipientReferenceId = "sample@recipient.com";

        // Adding query parameters
        URIBuilder uriBuilder = new URIBuilder();

        uriBuilder.addParameter("ts", String.format("%d",timestamp));
        uriBuilder.addParameter("key", ACCESS_KEY);
        uriBuilder.addParameter("refid", recipientReferenceId);
        uriBuilder.addParameter("email", recipientEmail);

        /* 
         * Adding the following fields is optional, Used to easily populate
         * the widget with default values.
         */

        // uriBuilder.addParameter("hideEmail", "true");
        // uriBuilder.addParameter("roEmail", "false");
        // uriBuilder.addParameter("locale", "en");

        // uriBuilder.addParameter("payoutMethods", "bank-transfer,paypal");
        // uriBuilder.addParameter("addr.firstName", "John");
        // uriBuilder.addParameter("addr.lastName", "Smith");
        // uriBuilder.addParameter("addr.governmentId", "ABCD123");
        // uriBuilder.addParameter("addr.street1", "120 Some Street");
        // uriBuilder.addParameter("addr.street2", "Block 123");
        // uriBuilder.addParameter("addr.city", "Montreal");
        // uriBuilder.addParameter("addr.postalCode", "A0A B0B");
        // uriBuilder.addParameter("addr.region", "QC");
        // uriBuilder.addParameter("addr.country", "CA");

        /* 
         * Adding color fields is also optional, used to override the
         * color settings set in the dashboard. Note that these overrides must
         * be valid CSS compatible colors.
         */
        
        // uriBuilder.addParameter("addr.country", "CA");
        // uriBuilder.addParameter("colors.heading", "#111111");
        // uriBuilder.addParameter("colors.inputText", "#222222");
        // uriBuilder.addParameter("colors.inputBorder", "#333333");
        // uriBuilder.addParameter("colors.text", "#555555");
        // uriBuilder.addParameter("colors.subText", "#666666");
        // uriBuilder.addParameter("colors.background", "#FFFFFF");
        // uriBuilder.addParameter("colors.primary", "red");
        // uriBuilder.addParameter("colors.border", "blue");
        // uriBuilder.addParameter("colors.success", "#AAAAAA");
        // uriBuilder.addParameter("colors.error", "#BBBBBB");
        // uriBuilder.addParameter("colors.warning", "#CCCCCC");

        // Preparing to create hash
        String encodedParams = uriBuilder.build().toString().substring(1);

        final SecretKeySpec encodedSecretKey = new SecretKeySpec(ACCESS_SECRET.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        
        final Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(encodedSecretKey);

        final byte[] paramBytes = mac.doFinal(encodedParams.getBytes(StandardCharsets.UTF_8));

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

        // Create signed hash
        String digest = hash.toString();

        // Add hashed value to query parameter
        uriBuilder.addParameter("sign", digest);

        // Set scheme and host
        uriBuilder.setScheme(SCHEME);
        uriBuilder.setHost(WIDGET_HOST);

        // Create Widget URI String to load into an iframe
        return uriBuilder.build().toString();
    }
}

Step 1

Copy the block of code below into your application, usually under your recipient profile page where you wish to display the Recipient payout preferences screen.

Step 2

Replace the following fields in the code with the appropriate values for your account and the recipient you will create or update:

API Keys:

API Keys can be created on the dashboard in the Settings > API Keys section

SECRET:

Secrets can be created on the dashboard in the Settings > API Keys section

RECIPIENT_EMAIL:

Email address of the recipient you will create or edit. Using an email address that is not yet linked to a recipient in your Trolley account will create a new recipient with that email address in your Trolley account. All email addresses are unique.

RECIPIENT_REFERENCEID:

Your internal recipient Reference ID for the recipient you will create or edit. If no Reference ID is provided Trolley will create a default value.

RECIPIENT_ADDRESS:

A set of optional fields which will be used as default values in the recipient information section of the Widget.

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)

Step 3

widgetLink is the URL that needs to be returned by your application, to be either used in an iFrame or in a browser address bar. Typically, the URL would be used in a page related to a recipients account profile or their payout preferences.

Note: The hmac signature is only valid for 30 seconds.

Refid and email

This is the complete rules for what happens when you use the refid and email parameter as argument to the widget url.

If we assume that we have a system which already has two registered users:

Calling the widget with the following parameters will result in the following behaviors:

joe@example.com tom@example.com bob@example.com (new email) (blank)
1234 Return widget for joe Error 403: mismatch change email to bob Return widget for joe
5678 change refid to 5678 change refid to 5678 create new recipient Error 403
7777 Error 403: mismatch Return widget for tom change email to bob Return widget for tom
(blank) Return widget for joe Return widget for tom create new recipient Error 403

As a reminder the Trolley treats email adress as a unique key across the system.

Widget events emitter (beta)

(function() {
  window.addEventListener("message", function(e) {
    var widgetEvent = e.data;

    if (widgetEvent.event === "document.height") {
      //Document's height changed
      console.debug('Changed Height', widgetEvent.document.height);

      //Example Action: setting iframe height as per data received
      var iframeElement = document.getElementById("payment-rails-widget");

      if (iframeElement) {
        iframeElement.style.height = widgetEvent.document.height;
      }
    }else if(widgetEvent.event === 'payment.created'){

      // A new payment method was added, take any action
      console.debug('Account ID', widgetEvent.account.id);

    }else if(widgetEvent.event === 'payment.deleted'){
      
      // A new payment method was deleted, take any action
      console.debug('Account ID', widgetEvent.account.id);

    }else if(widgetEvent.event === 'taxForm.submitted'){
      
      // A tax form was submitted, take any action
      console.debug('TaxForm ID', widgetEvent.taxForm.id);

    }
  });
})();

Widget emits events upon successful completion of some selected activities, so that your web page can take any actions when these activies happen.
This is how the event emitter also enables cross-origin communication between the page and the embedded iframe.

To listen to these Widget events, you need to implement an event listener using window.addEventListener("message", function(e) {...}) in your webpage that hosts the widget iframe. The events object contains some additional data which you can make use of.
Switch to the JavaScript view in the code viewer to see an example.

The following events will be available:

List of events:

Event Name Event Object Format Description
document.height data.document.height number The height of the iframe content
payment.created data.account.id string The account id whose payout was created
payment.deleted data.account.id string The account id whose payout was deleted
taxForm.submitted data.taxForm.id string The id of the taxform submitted

Responding to events on mobile devices

If you’re loading the widget inside a webview on your Android/iOS apps, you can use the native bindings that Android and iOS provide, to listen to these events.
Follow these simple steps for this:

  1. Prepare a webpage which contains the widget iframe, along with your JavaScript code. This code will listen to the widget events.
  2. Load this webpage in the webview, and setup your native code binding (see blow for Android/iOS platform documentation).
  3. Setup your JavaScript code to call the native callback methods, whenever it receives any widget event.

For Android, here’s the official Android documentation detailing how to Bind JavaScript to Android code.

For iOS, here’s the official iOS documentation that details how to use WKUserContentController to bind with JavaScript.

Debugging Integration Errors

Not every integration goes right the first time. If you see the message

To assist you in debugging these issues, we’ve appended error messages into the HTML. If you Inspect the page, you will see a block of code similar to the following:

The ERROR HTML comment should help you debug the issue, common values are:

Here are some extra tips:

Tickets in Widget

Tickets are created by the Trolley team when we need additional information from a recipient regarding a payment. They can be automatically sent directly to your recipients for prompt response to facilitate their payment without you having to individually contact them

When a Ticket is created to request for information from a recipient, the widget automatically shows a notice and requests the recipients for the information.

Example of tickets in Widget

No Dev Setup Required

The tickets flow doesn’t require any coding to setup. However, you may need to do configuration in the Trolley Dashboard.

To find out how to do that, please refer to our product documentation: Getting Started with Tickets





×