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.paymentrails.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.paymentrails.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.paymentrails.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.paymentrails.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.paymentrails.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}");
}
}
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:
- joe@example.com with referenceId = 1234
- tom@example.com with referenceId = 7777
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:
- Prepare a webpage which contains the widget iframe, along with your JavaScript code. This code will listen to the widget events.
- Load this webpage in the webview, and setup your native code binding (see blow for Android/iOS platform documentation).
- 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
- Something went wrong…
Contact your administrator if the problem persists.
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:
-
...
<!--ERRORS: invalid_api_key Timestamp is more than 30 seconds off of server time -->
</body>
The ERROR HTML comment should help you debug the issue, common values are:
- Invalid API Key – The Public key is not found
- Timestamp is more than 30 seconds off of server time – You need to syncronize your clock’s UTC time
- Invalid token: bad hash – Your computation of the signed value is incorrect
- Invalid email – Your email is incorrectly formatted
Here are some extra tips:
-
- Make sure to generate a new URL everytime the widget is loaded.
-
- Ensure that your API key and secret aren’t disabled, and that they point to the appropriate environment for you integration (live or sandbox)