API Javascript SDK Implementation

The JavaScript SDK is a client-side initiated version of our Gateway API integration. It removes the need for a full-page redirect by managing the in-context rendering of the Zip checkout flow in a modal, the same way our Virtual Checkout solution does currently.

Zip takes care of the initial authorization API call through the openCheckout method, which is used with a custom DOM element, and will launch checkout in a popup window (or iframe depending on provided parameters). Read more below.

Zip communicates the results via a Webhook to a predefined endpoint on the merchant side, additionally to return the result on the client-side.

Each consecutive operation, such as void, capture, refund, or other, must be completed on the server side. Please refer to our API documentation.

Flow Diagrams


Depending on how the capture model works for an order, there may be no need to make additional calls to our API to complete an order.

Auto capture
This will enable minimal server-side integration, and the order will be completed after the consumer has completed the Zip checkout flow. This also means that the installment plan will start right away and the order will be captured immediately upon order placement. This is recommended for instant orders or digital goods.


Delayed capture
This use-case is targeted for payment with a delay between the initial authorization and the order capture. This can also be used if the order requires multiple captures on the same authorization. The installment plan will start on the initial authorization, not on the capture. Please refer to our API documentation.

Implementation Guide


Client-side

The client-side integration requires the following:

  1. A reference to our CDN-hosted JavaScript library see example .
  2. A signature that is computed server-side see example
  3. An HTML element to attach the click event that will trigger the openCheckout function. This element can be a custom HTML element, the Zip payment widget, or the Zip second chance widget.
  4. JavaScript to attach one or more callback functions to customize the payment flow and handle checkout completion, including any potential errors.

📘

Using a Zip widget to initiate checkout

Set the attribute integrationType='api'. Without this attribute, the payment flow defaults to a Virtual Checkout, and the window.quadpay.apiCheckout methods will not be available

Javascript Reference

There are two environments available, and you'll receive unique credentials for each:

  • Sandbox (Test) - US: https://cdn.sand.us.zip.co/v1/zip.js
  • Production - US: https://cdn.us.zip.co/v1/zip.js

Adding the sandbox script will automatically integrate with our sandbox services for testing. Importing the production script will result in real transactions.

The script can be loaded by adding a tag like:

<script src="https://cdn.us.zip.co/v1/zip.js" type="text/javascript"></script>

The script can be added anywhere in the body or head area and loaded asynchronously. If loaded asynchronously, be sure to wait for its load to complete before invoking any operations against the library.

Start Checkout

Start the Zip checkout by calling openCheckout, typically in response to events like click or keyDown on a DOM element.

Zip provides a Branded button asset by using:

<zip-button id="QPButton" integrationType="api></zip-button>

The below example is a button element, but this can be anything from radio buttons, drop-downs, or images.

<input type="button" id="ZipButton" value="Pay with Zip"/>

Open Checkout Function

The openCheckout function is attached to a DOM element and initiates the Zip checkout flow with the requestBody and signature input. An example is below:

const zipButton = document.getElementById('ZipButton')

zipButton.addEventListener('click', () => {
  window.quadpay.apiCheckout.openCheckout(requestBody, signature)
})
const handleClick = () => {
  window.quadpay.apiCheckout.openCheckout(requestBody, signature)
}

const handleKeyDown = () => {
  if (event.key === 'Enter') {
    window.quadpay.apiCheckout.openCheckout(requestBody, signature)
  }
}

<input 
  type="button"
  id="ZipButton"
  value="Pay with Zip"
  onClick={handleClick}
  onKeyDown={(event) =>  handleKeyDown(event)}
></input>

🚧

Potential Pitfall!

Be sure that the call to openCheckout(requestBody, signature) exists in the same context as the onClick handler. Calling openCheckout() in a callback or Promise might prevent the pop-up from appearing on some browsers.

SDK Methods

These methods handle events by passing them to their assigned callback functions, which may be called asynchronously.

onComplete

The onComplete method runs when a customer completes the Zip checkout. It receives the Zip Response. In the Express flow, the shippingAddress(Address) object will also be sent.

/**
 * @param {Object} result - The result object
 * @param {Object} result.customer - The Customer object
 * @param {Object} result.object - The Zip order object
 * @param {Object} [result.shippingAddress] - Address object (only on Express Checkout)
 */

window.quadpay.apiCheckout.onComplete((result) => {
  // your code goes here
});

onClose

onClose is an optional method that runs when a customer closes the Zip checkout window or their session times out. It receives a string describing why the checkout was closed.

/**
 * @param {string} message - A message explaining why checkout was closed
 */

window.quadpay.apiCheckout.onClose((message) => {
  // your code goes here
})

onError

onError is an optional method that runs if the requestBody passed to startCheckout() fails validation. It receives an array of strings describing which attributes failed validation.

/**
 * @param {string[]} errors - An array of error messages
 */

window.quadpay.apiCheckout.onError((errors) => {
  // your code goes here
})

Server-side

To enable secure communication between the SDK and our server, all operations are secured with an HMAC-SHA256 one-way hash that is performed using a shared secret key. The key is provided by Zip and will differ depending on the environment used. The Signatures are generated based on the requests to sign the entire Zip requestBody object.

JSON RequestBody example:

{
        "merchantId": "[Insert merchant Id]",
        "merchantReference": "your-unique-order-id",
        "order": {}, // Order object reference can be found below
        "callbackUrl": "your-url-for-callbacks",
        "capture": "true"
}
PropertiesTypeOptional/RequiredDescription
merchantIdGUIDRequiredYour identifier provided by Zip
merchantReferenceStringRequiredA unique order ID from the merchant
order (see model)Order objectRequiredA custom object representing the order. Example below.
callbackUrlStringOptionalA URL that will receive the webhook request about the result of this operation.
If capture is set to true, a callbackUrl is required to verify the order details.
captureBooleanRequired (default true)Indicated is the order will be auto-captured or additional operations for capture will be completed to capture.

Calculating the Signature — Code Examples

Implementing this is language specific. Here are examples that can generate these hashes for you:

/// Takes the secret key and the JSON in string format
public string Compute(string secretKey, string json)
{
    var bytes = Encoding.UTF8.GetBytes(json);
    return this.Compute(secretKey, bytes);
}

/// If your entire request body is passed in as bytes (e.g. POST JSON request), this will give you the correct hash
public string Compute(string secretKey, byte[] bytes)
{
    using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey)))
    {
        var hash = hmacsha256.ComputeHash(bytes);
        return Convert.ToBase64String(hash);
    }
}
$signature = base64_encode(hash_hmac('sha256', $data, $secret, true));
import crypto from 'crypto'

const data = JSON.stringify(requestBody);
const key = 'your_api_key_here';
const signature = crypto
	.createHmac('sha256', key)
	.update(data)
	.digest('base64');
import hmac
import hashlib
import base64
import json

request_body = {"key": "value"}  # Replace with actual data
data = json.dumps(request_body)
key = 'your_api_key_here'

signature = base64.b64encode(
    hmac.new(key.encode(), data.encode(), hashlib.sha256).digest()
).decode()

print(signature)

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "encoding/json"
    "fmt"
)

func main() {
    requestBody := map[string]interface{}{"key": "value"} // Replace with actual data
    data, _ := json.Marshal(requestBody)
    key := "your_api_key_here"

    h := hmac.New(sha256.New, []byte(key))
    h.Write(data)

    signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
}

require 'openssl'
require 'base64'
require 'json'

request_body = { key: 'value' } # Replace with actual data
data = request_body.to_json
key = 'your_api_key_here'

digest = OpenSSL::HMAC.digest('sha256', key, data)
signature = Base64.strict_encode64(digest)


Webhooks

Zip provides an async webhook message for events when a consumer completes the Zip checkout flow and when API calls are completed.

Webhook message format
Authorization (at user completion of Zip checkout)


Example code

// retrieve server-side computed signature
const signature = await fetch('/calculate-signature')

// format order object
const order = {
  amount: 123.45,
  curency: 'USD',
  shippingAmount: 10,
  taxAmount: 13.45,
  email: '[email protected]',
  firstName: 'John',
  lastName: 'Doe',
  phoneNumber: '+15555555555',
  billingAddress: {
    line1: '123 street',
    address2: '',
    city: 'New York',
    state: 'NY',
    postalCode: '10001',
    country: 'US'
  },
  lineItems: [
    {
      name: 'Item Name',
      description: 'Item description',
      quantity: 1,
      price: 123.45,
      sku: '12345678',
    },
  ]
}

// format Zip checkout request body
const requestBody = {
  merchantId: '[Insert merchant Id]',
  merchantReference: 'merchant-order-id', // Unique order id from Merchant
  order,
  callbackUrl: 'http://merchant-url',
  capture: true,
  checkoutFlow: 'standard'
}

// initiate checkout method
window.quadpay.apiCheckout.openCheckout(requestBody, signature)

// runs when Zip checkout completes
window.quadpay.apiCheckout.onComplete((result) => {
  // your code goes here
})

// runs when Zip checkout popup is closed or session times out
window.quadpay.apiCheckout.onClose((message) => {
  // your code goes here
})

// runs when requestBody validation fails in openCheckout()
window.quadpay.apiCheckout.onError((errors) => {
  // your code goes here
})

Functions


focusCheckout

This method allows you to programmatically bring focus to the pop-up window once checkout has been opened.

window.quadpay.apiCheckout.focusCheckout()

closeCheckout

This method force-closes the Zip checkout window and ends the user's Zip session.

window.quadpay.apiCheckout.closeCheckout()

Object Models


Order

API Documentation
currency (required) · string
The currency code the order is in
amount (required) · number
The amount of the order. It should include all fees, taxes, shipping, and discount codes calculated in its value.
firstName · string
Customer's first name.
lastName · string
Customer's last name.
email · string
Customer's email address
phone · string
Customer's 11-digit phone number
shippingAddress · Address
Customer's shipping address information in the form of an Address object
Show properties
  • line1: (required) Primary billing address information
  • line2: Secondary billing address information
  • city: (required) City of customer's billing address
  • state: (required) State of customer's billing address in ISO 3166-2: US format
  • country: (required) Country of customer's billing address in ISO3166-2 (two letter country code)
  • postalCode: (required) 5 digit state postal/zip code
billingAddress · Address
Customer's billing address information in the form of an Address object
Show properties
  • line1: (required) Primary shipping address information
  • line2: Secondary shipping address information
  • city: (required) City of customer's shipping address
  • state: (required) State of customer's shipping address in ISO 3166-2: US format
  • country: (required) Country of customer's shipping address in ISO3166-2 (two letter country code)
  • postalCode: (required) 5 digit state postal/zip code
taxAmount · number
The tax amount of the order.
shippingAmount · number
The shipping amount of the order.
lineItems · array of LineItem
The amount of the order. It should include all fees, taxes, shipping, and discount codes calculated in its value.
Show properties
  • name: The name of the item
  • description: The description of the item (max character length 100)
  • quantity: The quantity of the item in the order
  • price: The price of 1 item
  • sku: The Stock Keeping Unit number
  • isPreOrder: Whether the item is a pre-order item
  • releaseDate: The anticipated shipment date of the item
description · string
The description of the order
{ amount: 25.50, currency: "USD", firstName: "John", lastName: "Doe", email: "[email protected]", phone: "123-456-7889", shippingAddress: { line1: "101 Test Street", line2: "Unit 101", city: "New York City", state: "NY", country: "USA", postalCode: "10001" }, billingAddress: { line1: "101 Test Street", line2: "Unit 101", city: "New York City", state: "NY", country: "USA", postalCode: "10001" }, taxAmount: 0.00, shippingAmount: 10.00, lineItems: [ { name: "T-Shirt", description: "Item description", quantity: 1, price: 25.50, sku: "SKU123", isPreOrder: false, releaseDate: null } ], description: "Order description" }

Address

API Documentation
line1 (required) · string
Primary address information
line2 · string
Secondary address information
city (required) · string
City of address
state (required) · string
State of address in ISO3166-2 (US) format
country (required) · string
Country of address in ISO3166-2 (two letter country code)
postalCode (required) · string
5 digit state postal code
{ line1: "101 Test Street", line2: "Unit 101", city: "New York City", state: "NY", country: "USA", postalCode: "10001" }

LineItem

API Documentation
name · string
The name of the item
description · string
The description of the item (max character length 100)
quantity · number
The quantity of the item in the order
price · number
The price of one item
sku · string
The Stock Keeping Unit number
isPreOrder · boolean
Whether the item is a pre-order item
releaseDate · Date
The anticipated shipment date of the item
{ name: "T-Shirt", description: "Item description", quantity: 1, price: 25.50, sku: "SKU123", isPreOrder: false, releaseDate: null }

requestBody

API Documentation
merchantId (required) · string
The merchant ID provided by Zip
merchantReference (required) · string
The order ID on the merchant's platform.
order (required) · Order
The order object
callbackUrl (required) · string
The URL that Zip will send event webhooks too. These webhooks are the result of API requests made to Zip.
capture [default: true] · boolean
This boolean tells Zip whether the order should be treated as Auto or Delayed capture.
checkoutFlow (required) · "standard" | "express"
This string tells Zip whether the transaction should be opened in our Standard or Express checkout flow
{ merchantId: "xxxx-xxxx-xxxx-xxxx", merchantReference: "123ABC", order: {} as Order, callbackUrl: "my-merchant.com/zip-callback", capture: true, checkoutFlow: "standard" }

Zip Checkout Response

API Documentation
customer · Customer
The Customer object sent from Zip
Show properties
  • address1: Primary shipping address information
  • address2: Secondary shipping address information
  • city: City of customer's shipping address
  • country: Country of customer's shipping address in ISO3166-2 (two letter country code)
  • email: Customer's email address
  • fistName: Customer's first name
  • lastName: Customer's last name
  • phoneNumber: Customer's 10 digit phone number
  • postalCode: 5 digit state postal/zip code
  • state: State of customer's shipping address in ISO 3166-2: US format
order · OrderResponse
The Order object sent from Zip
Show properties
  • amount: The order amount
  • currency: The currency code
  • isSuccess: Whether Zip successfully captured the order
  • isTest: Whether the order was captured in sandbox or production
  • merchantId: Merchant's Zip ID
  • merchantReference: Merchant's order ID
  • orderId: Zip's order ID
  • timestamp: Timestamp when order was processed
shippingAddress (If Express checkout) · Address
The shipping Address sent from Zip
Show properties
  • line1: Primary shipping address information
  • line2: Secondary shipping address information
  • city: City of customer's shipping address
  • state: State of customer's shipping address in ISO 3166-2: US format
  • postalCode: 5 digit state postal/zip code
  • country: Country of customer's shipping address in ISO3166-2 (two letter country code)
success · boolean
Signifies whether Zip successfully processed the order
{ customer: { address1: "101 N Test Street", address2: undefined, city: "New York City", country: "US", email: "[email protected]", firstName: "John" lastName: "Doe" phoneNumber: "(123)123-1234" postalCode: "12345" state: "NY } order: { amount: 149.99, currency: "USD", isSuccess: true, isTest: false, merchantId: 1234-1234-1234-1234, merchantReference: "XYZ123" orderId: "XYZABC-123-5432" timestamp: 2024-05-25T12:30:00 } shippingAddress: { line1: "101 N Test Street", line2: "Unit 101", city: "New York City", state: "NY postalCode: "12345" country: "US" }, success: true }