Change Log
2020-01-31
- Added missing screenshots
- Updated notes on “fingerprint” stating that it is only potentially useful for completely static payment forms.
- Added example of raw HTTP post-back to integrator
- Miscellaneous spelling and grammar fixes
What is Hosted Payments?
Hosted Payments is a secure checkout service provided by PayJunction which allows merchants and integrators to collect card payments without directly touching the sensitive card information. This allows merchants and integrators to drastically lower the PCI-DSS audit requirements for their business or software on Card-Not-Present channels.
How It Works
Hosted Payments works by redirecting the end user’s browser to the secure checkout page provided by PayJunction. As the software is completely hosted and controlled by PayJunction, the sensitive card information never passes through the merchant or integrator’s software and servers. Arbitrary data can be passed through from initiation of the redirect to a custom URL allowing the automation of the payment workflow.
HTML Forms vs URL Links
A common question is, should I use an HTML form or a link? The short answer is that it depends on what your platform allows and what information you are collecting from the card holder. If you are taking payments for a specific, invariable amount and with an invariable quantity, a link is often the best choice. Otherwise an HTML form might be the better option.
The Basics
Sandbox vs Production Domains
For security, PayJunction completely separates the sandbox and production systems, including different URL domains. All test transactions during initial development should be sent to the sandbox domain, payjunctionlabs.com while production transactions must go to the payjunction.com domain. In this guide, all examples will use the payjunctionlabs.com sandbox domain. To use the production server, simply change the domain to payjunction.com along with the Shop Name used to identify the specific merchant’s account.
Example
Sandbox
HTML Form
<form method="POST" action="https://www.payjunctionlabs.com/trinity/quickshop/add_to_cart_snap.action"> <input type="hidden" name="store" value="mySandboxShopName"> <input type="hidden" name="description" value="Widget Cleaning Service"> <input type="hidden" name="price" value="100.00"> <input type="hidden" name="quantity" value="1"> <input type="hidden" name="need_to_tax" value="no"> <input type="hidden" name="need_to_ship" value="no"> <input type="submit" name="submit"value="Purchase Now"> </form>
Hyper Link / URL
https://www.payjunctionlabs.com/trinity/quickshop/add_to_cart_snap.action?store=mySandboxShopName&description=Widget+Cleaning+Service&price=100.00&quantity=1&need_to_tax=no&need_to_ship=no
Production
HTML Form
<form method="POST" action="https://www.payjunction.com/trinity/quickshop/add_to_cart_snap.action"> <input type="hidden" name="store" value="mySandboxShopName"> <input type="hidden" name="description" value="Widget Cleaning Service"> <input type="hidden" name="price" value="100.00"> <input type="hidden" name="quantity" value="1"> <input type="hidden" name="need_to_tax" value="no"> <input type="hidden" name="need_to_ship" value="no"> <input type="submit" name="submit"value="Purchase Now"> </form>
Hyper Link / URL
https://www.payjunction.com/trinity/quickshop/add_to_cart_snap.action?store=mySandboxShopName&description=Widget+Cleaning+Service&price=100.00&quantity=1&need_to_tax=no&need_to_ship=no
Invoice Mode & Shopping Cart Mode
Depending on which endpoint is used in the URL, Hosted Payments can be used in either “Invoice Mode” or “Shopping Cart Mode”. The primary difference between these two modes is whether the end user is immediately sent to the checkout page upon clicking the link or button, or if they are taken to a cart to confirm the item and quantity of products/services they are purchasing.
Invoice Mode |
https://www.payjunctionlabs.com/trinity/quickshop/add_to_cart_snap.action |
Shopping Cart Mode |
https://www.payjunctionlabs.com/trinity/quickshop/add_to_cart.action |
When using Hosted Payments in Shopping Cart mode, the Hosted Payment shop must have the method set to POST in the Shop Settings in order to receive the details on the individual line items added to the cart.
Additional URLs for Shopping Cart Mode
View Shopping Cart |
https://www.payjunctionlabs.com/trinity/quickshop/view_cart_init.action |
Go to Checkout |
https://www.payjunctionlabs.com/trinity/quickshop/check_out_init.action |
These two endpoints do not change the contents of the cart.
Required Fields
In order to initiate a Hosted Payments transaction, five fields with values are required:
- Hosted Payments Shop name
- Description of the item or service
- Amount to charge per unit
- Unit quantity
- Tax indicator
- Shipping indicator
Based on the above, the simple example of a Hosted Payments form might be:
<label>Widget Cleaning Service - $100</label> <form method="POST" action="https://www.payjunction.com/trinity/quickshop/add_to_cart_snap.action"> <input type="hidden" name="store" value="myShopName"> <input type="hidden" name="description" value="Widget Cleaning Service"> <input type="hidden" name="price" value="100.00"> <input type="hidden" name="quantity" value="1"> <input type="hidden" name="need_to_tax" value="no"> <input type="hidden" name="need_to_ship" value="no"> <input type="submit" name="submit" value="Purchase Now"> </form>
Without additional styling, the above will look similar to the following:
Or as a link:
If using a link, the values will need to be URL encoded. Web browsers automatically convert the values from an HTML form into URL encoded data before submission.
Field |
Format |
Description |
store |
String (Case-sensitive) |
Sets the Hosted Payments Shop to use. This tells the service which PayJunction account to process through. |
description |
String |
A description of the item or service being paid for. |
price |
Number |
Sets the amount to charge per unit. If submitted as a float value both the tenths and hundredths must be present. Valid: “1”, “1.00” NOT valid: “1.0” |
quantity |
Number |
An integer value indicating the number of units to charge for. |
need_to_tax |
“yes” or “no” |
Indicates if tax needs to be applied to the transaction total. |
need_to_ship |
“yes” or “no” |
Indicates if a shipping amount needs to be applied to the transaction total. |
A full listing of reserved fields and expected data format for each reserved parameter is included in the Reserved Fields section of this guide.
Including User Input
Sometimes our form is mostly static but we need some additional input from the user. This could be the amount to pay, the account/location to make the payment to, or the quantity. Thankfully, HTML forms make this task easy.
To allow the user to specify the quantity of an item we could simply update our previous example and change the “quantity” input element from type “hidden” to “text” and add a label element so the user knows what to put in the field*:
<label>Widget Cleaning Service - $100</label> <form method="POST" action="https://www.payjunction.com/trinity/quickshop/add_to_cart_snap.action"> <input type="hidden" name="store" value="myShopName"> <input type="hidden" name="description" value="Widget Cleaning Service"> <input type="hidden" name="price" value="100.00"> <label> <span>Quantity:</span> <input type="text" name="quantity" value="1"> </label> <input type="hidden" name="need_to_tax" value="no"> <input type="hidden" name="need_to_ship" value="no"> <input type="submit" name="submit" value="Purchase Now"> </form>
Our example now looks like the following:
Perhaps we have more than one location and we want the user to specify. By using multiple Hosted Payment Shops we can give the user a drop-down selection to choose from:
<div style="padding:10px; border:1px solid; border-radius:5px; width: 220px;"> <label>Widget Cleaning Service - $100</label> <br></br> <div style="display: block; width: 200px; margin: 5px;"> <form method="POST" action="https://www.payjunction.com/trinity/quickshop/add_to_cart_snap.action"> <label> <span>Select Your Service Location:</span> <select name="store"> <option value="mySBShop">Santa Barbara</option> <option value="myGoletaShop">Goleta</option> </select> </label> <br></br> <input type="hidden" name="description" value="Widget Cleaning Service"> <input type="hidden" name="price" value="100.00"> <label> <span>Quantity:</span> <input type="text" name="quantity" value="1"> </label> <input type="hidden" name="need_to_tax" value="no"> <input type="hidden" name="need_to_ship" value="no"> <input type="submit" name="submit" value="Purchase Now"> </form> </div>
</div>
</div>
Our minimally styled form now looks like this:
Reserved Fields
Note: In order for reserved fields to record data in PayJunction, instead of just passing them through to the relay, the fields must be set to either Display or Required in the Hosted Payments Shop Field settings.
NOTE: Instructions for accessing and updating Shop Field settings for Hosted Payments: https://support.payjunction.com/hc/en-us/articles/115000259913-How-to-update-fields-on-checkout-page-for-Hosted-Payment-Shops
The following fields will cause data to be validated and saved in PayJunction. If field validation fails, the data for that field will not be passed through to the third party server. If certain data must get through to the third party server, use a custom field name instead or make sure the field is set to Required in the Shop Field settings to force the value to be corrected at checkout by the card holder.
Name |
Validation |
Additional Notes |
invoice |
ASCII |
|
purchaseOrderNumber |
ASCII |
Purchase order number. If you would like to mark this transaction with your own PO for accounting. |
custom1 |
ASCII |
Non-ASCII characters automatically stripped. Max length 32 characters, additional characters automatically stripped. |
billingFirstName |
ASCII |
|
billingMiddleName |
ASCII |
|
billingLastName |
ASCII |
|
billingPhone |
ASCII |
|
billingFax |
ASCII |
|
billingEmail |
Valid Email Address |
RFC 2822 |
billingWebsite |
Max Length 128 |
Billing website. |
billingCustomerId |
ASCII |
|
billingCompany |
ASCII |
|
billingJobTitle |
Max Length 32 |
Billing job title. (President, Director, etc.) |
billingCountry |
ASCII |
|
billingStreetAddress |
ASCII |
|
billingCity |
ASCII |
|
billingTerritory |
Two letter state abbreviation. |
The state for the credit card’s billing address. |
shippingFirstName |
ASCII |
|
shippingMiddleName |
ASCII |
|
shippingLastName |
ASCII |
|
shippingStreetAddress |
ASCII |
|
shippingCity |
ASCII |
|
shippingTerritory |
ASCII |
|
shippingCountry |
ASCII |
|
shippingZip |
ASCII |
|
shippingCustomerId |
ASCII |
|
shippingCompany |
ASCII |
|
shippingDepartment |
ASCII |
|
shippingOccupation |
ASCII |
|
shippingJobTitle |
Max Length 32 |
Shipping job title. (President, Director, etc.) |
shippingTitle |
ASCII |
|
shippingEmail |
ASCII |
|
shippingWebsite |
Max Length 128 |
Shipping website. |
shippingPhone |
ASCII |
|
shippingFax |
ASCII |
|
relay |
HTTPS URL |
|
echo |
None |
Passing Data to a Third Party Server
New as of December 4th, 2020:
The custom1 field is now a reserved field for passing information and saving it in the transaction details. Read below for further details.
The Hosted Payments service can be configured to send data about the transaction, along with arbitrary data, by setting the “relay” field to a valid HTTPS address. This will cause Hosted Payments to redirect the user’s browser to the provided address, using the HTTP method (GET or POST) set in the Shop Settings configuration, after the payment has been collected.
There is currently no way to detect and handle declined transactions on Hosted Payments without logging into the PayJunction Virtual Terminal (VT) web interface to view the declined transaction. The redirect will only occur when the transaction is approved by the card issuing bank and PayJunction.
The HTTP method must be set to POST in the Shop Settings if multiple items will be added to the cart.
Custom Fields - Passing Arbitrary Data
There are two fields that can be used to pass data not included in the fields presented to the end user when checking out: custom1 and echo.
The primary difference between the two fields is that custom1 values will be saved into the transaction data accessible by the REST API. The echo field value is not saved in the transaction data and is only sent by the end user browser once it is redirected to the third party server after the transaction is approved.
The custom1 Field
The custom1 field will never be displayed during checkout through Hosted Payments so that end users cannot change the value. The value is then saved in the transaction details accessible by the REST API. Because this field is hidden and is not validated during checkout, the value will be automatically modified to conform to the following constraints:
Constraint | Action | Example |
---|---|---|
Max length of 32 characters | Values are trimmed to 32 characters | Value supplied: "A long string over the max length allowed" Value saved: "A long string over the max lengt" |
ASCII characters only | Non-ASCII characters are stripped out | Value supplied: "Anders Jonas Ångström" Value saved: "Anders Jonas ngstrm" |
Due to the constraints above, it is recommended to use values that will always conform such as a UUID without hyphens, e.g. "88888888444444444444cccccccccccc". Otherwise it is up to the integrator to perform their own validations to maintain data consistency.
While an end user making a payment through Hosted Payments cannot see or edit the custom1 field, merchants logged into the PayJunction Virtual Terminal (VT) will be able to edit this field, with the same constraints. This allows merchants to fix a value if needed, such as updating the example name above to "Anders Jonas Angstrom".
Additionally, the merchant can edit the field name displayed to them in the PayJunction VT when viewing a transaction's details. The default value is "Custom Label". Changing the displayed field name in the VT will not affect the field name used by the integration; it will always be "custom1".
The echo Field
The “echo” field can be used to create your own keywords and values to be passed to the third party server. To do so, simply provide a URL encoded string with the keywords and values, separated by an ampersand.
Example:
Original Data
{ "myCustomField1": "Some arbitrary data.", "myCustomField2": "Data! With~Lots+of&Symbols" }
Formatted and URL Encoded Values
myCustomerField1=Some%20arbitrary%20data.&myCustomField2=Data%21%20With~Lots%2Bof%26Symbols
Web Form
<input type=”hidden” name=”echo” value=”myCustomerField1=Some%20arbitrary%20data.&myCustomField2=Data%21%20With~Lots%2Bof%26Symbols”>
The browser should take care of the encoding before sending to the server. For a payment link however...
Payment Link
Note that in order to include it directly in the link, we had to URL encode the entire string before assigning it to the echo parameter.
Code Examples
PHP
$custom_data = http_build_query( array( "myCustomField1" => "Some arbitrary data.", "myCustomField2" => "Data! With~Lots+of&Symbols" ) ); echo '<input type="hidden" name="echo" value="$custom_data">';
Javascript
let raw_data = {myCustomField1: "Some arbitrary data.", myCustomField2: "Data! With~Lots+of&Symbols"}, custom_data = Object.keys(raw_data) .map(fieldName => `${fieldName}=${encodeURIComponent(raw_data[fieldName])}`) .join('&') ;
Receiving the Data Passed to a Third-Party Server
Data Response Format
When the end-user’s browser performs the post back to the relay URL it will set the Content-Type header to application/x-www-form-urlencoded
Whether or not this will automatically be converted into an object or associative array for consumption in your code will depend on the HTTP library used.
Data Response Keys and Value Descriptions
Other than the custom field names supplied by you, the following table shows the standard fields sent to the server:
transaction_code |
“00” & “85” are Approved values |
tracking_code |
PayJunction generated tracking_code for this order. In the REST API, this is referenced as transactionId |
fingerprint |
The fingerprint code that was generated for payment button. This is only useful for payment buttons/forms that are completely static and do not use arbitrary values of any kind (such as a variable amount). |
store |
The store id for the payment button |
qs_total |
The total dollar amount charged to the customer's card. |
qs_total_shipping |
The total shipping amount for the order |
qs_total_tax |
The total tax amount for the order |
qs_total_surcharge |
Present only if surcharge is enabled on the account. Click here to learn how to use PayJunction's surcharge feature. |
qs_surcharge_status |
Present only if surcharge is enabled on the account. Possible values:
|
qs_surcharge_percentage |
Present only if surcharge is enabled on the account. Percentage of the total amount used to calculate the surcharge. |
qs_number_last_four_digits |
The last four digits of the credit card the customer used to make a purchase. |
qs_cc_name |
The name on the credit card. |
qs_cc_city |
The credit card billing statement city. |
qs_cc_state |
The credit card billing statement state. |
qs_cc_street |
The credit card billing statement street. |
qs_cc_zip |
The credit card billing zip code. |
qs_cc_country |
The credit card billing statement country. |
qs_cc_email |
The email address as set by billingEmail |
qs_o_name |
The name of the person to ship this order to. |
qs_o_street |
The street of the shipping address. |
qs_o_city |
The city of the shipping address. |
qs_o_state |
The state of the shipping address. |
qs_o_zip |
The zip code of the shipping address. |
qs_o_e_mail |
The e-mail address as set by shippingEmail. |
qs_o_day_phone |
A daytime phone number extension |
qs_o_day_phone_extension |
The daytime phone number extension. |
qs_o_night_phone |
A nighttime phone number for the customer. |
qs_o_night_phone_extension |
A nighttime phone number extension. |
invoice |
The invoice number that was entered for the transaction. |
qs_o_notes |
Any special notes relevant to the order. |
In addition, for each product the customer has in his shopping cart, the following fields will be populated, with x representing the product index:
qs_identifier_x |
The short product description. |
qs_description_x |
A brief description of the product. |
qs_quantity_x |
The quantity to add to the cart. |
qs_price_x |
Cost for each item. |
qs_need_to_ship_x |
A value of “Yes” means that this item needs to be shipped. |
qs_s_h_amount_x |
The shipping & handling cost for each item. |
qs_need_to_tax_x |
A value of “Yes” means that this item was taxed. |
qs_tax_amount_x |
The amount to tax for each item. |
Error: For the above breakout of individual cart items, the Shop Settings must have POST selected for the Method. Instructions for accessing Hosted Payments Shop Settings: https://support.payjunction.com/hc/en-us/articles/115000089613-How-Do-I-Manage-My-Hosted-Payment-Shops-
Each product/line item added to the cart will be given an index number, starting from 1. There is no limit to the number of products/line items you can add to the cart.
Hosted Payments will not combine line items added to the cart, even if they share the same price and identifier. Each request sent to either add_to_cart.action or add_to_cart_snap.action will create a new line item in the cart, even if the same line item already exists in the cart.
Example Raw HTTP Post-Back sent to the URL relay
The following example is with the HTTP Method in Shop Settings set to POST which is the recommended setting.
POST /test HTTP/1.1 Host: pjtest.requestcatcher.com Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Cache-Control: max-age=0 Connection: keep-alive Content-Type: application/x-www-form-urlencoded Cookie: _ga=GA1.2.640822999.1580432561; _gid=GA1.2.1102145283.1580520970 Origin: https://d1.www.payjunctionlabs.com Referer: https://d1.www.payjunctionlabs.com/trinity/quick-shop/receipt Sec-Fetch-Mode: nested-navigate Sec-Fetch-Site: cross-site Sec-Fetch-User: ?1 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36 relay=https%3A%2F%2Fpjtest.requestcatcher.com%2Ftest&store=REDACTED&billingLastName=Doe&billingEmail=no-email%40payjunction.com&billingFirstName=John&invoice=1&myCustomField2=Data%21+With%7ELots%2Bof%26Symbols&myCustomerField1=Some+arbitrary+data.&qs_tracking_code=8571&response_code=00&transaction_code=00&tracking_code=8571&qs_number_last_four_digits=4444&number_last_four_digits=4444&qs_total=200.00&qs_total_shipping=&qs_total_tax=&qs_cc_name=John+Doe&qs_cc_street=1903&qs_cc_city=&qs_cc_state=&qs_cc_zip=93101&qs_cc_country=&qs_cc_email=no-email%40payjunction.com&qs_cc_day_phone=&qs_cc_day_phone_extension=&qs_cc_night_phone=&qs_cc_night_phone_extension=&qs_o_name=&qs_o_street=&qs_o_city=&qs_o_state=&qs_o_zip=&qs_o_country=&qs_o_e_mail=&e_mail=&qs_o_day_phone=&qs_o_day_phone_extension=&qs_o_night_phone=&qs_o_night_phone_extension=&qs_o_notes=&qs_identifier_1=&qs_description_1=Widget+Cleaning+Service&qs_quantity_1=2&qs_price_1=100.00&qs_need_to_ship_1=no&qs_s_h_amount_1=&qs_need_to_tax_1=no&qs_tax_amount_1=
Validating and Updating Transaction Details
As mentioned above, if a field is not set to either Display or Required in the Shop Fields configuration, that data will not be saved in the transaction details. So how do we handle the situation where we want to hide one or more fields, but still have the data saved for subsequent use? Or what if the field was displayed, but the end user changed it at checkout?
While the relay webhook will echo back what was originally sent to the checkout form, so that integrations receive the data expected, this is not true when fetching the transaction details at a later date with the REST API or by logging into the Virtual Terminal web portal. If we want to make sure the information is accurate, or update local records based on changes made by the user during checkout, we need to use the REST API. Such corrections could include the name, address, or other billing information for the customer.
It is also strongly encouraged to validate transaction details with the REST API. Due to the asynchronous nature of using a secure checkout with webhooks, it is theoretically possible for a malicious user to try and trick a platform into thinking that a transaction has been paid. To protect against this type of fraud and hacking, an integrated platform should always leverage the REST API to verify the transaction exists and for the correct amount in the PayJunction account.