API Implementation

Gateway API Endpoints

To build your integration, you will utilize the Orders endpoints listed below. Later sections cover how to receive requests and the format of the webhooks that you will use to get updates about Zip orders initiated through the gateway API.

Endpoints and Environments

You will be given unique credentials for the sandbox and production environments. It is best to build your integration against the sandbox environment and enable in production upon successful certification.

Production - US - https://gateway.us.zip.co/
Sandbox (Test) - US - https://gateway.sand.us.zip.co/

Production - CA - https://gateway.ca.zip.co/
Sandbox (Test) - CA - https://gateway.sand.ca.zip.co/

Sent from the user's browser via a form POST, will start a checkout session within Zip. It will automatically redirect the user to our Zip checkout. You need to ensure you provide your Merchant ID, Merchant Reference (the unique ID you use for the order in your system), confirm/cancel URLs, and the order amount. The order amount should include all shipping, tax, and discount charges. You do not need to provide the order ID as that will be generated for you. Passing as much customer information as possible will improve the user experience by pre-filling data fields and improving conversion.

Required fields are:

  • merchantId - Your identifier provided by Zip
  • merchantReference - Your unique order identifier for this order in your system
  • callbackUrl - A URL that will receive the webhook request about the result of this operation
  • amount - The total amount of the order, including cart value, shipping, tax, and all fees
  • redirectCancelUrl - Where the user should go upon abandoning their cart
  • redirectConfirmUrl - Where the user should go upon order completion (will include the aforementioned query parameters)

Example

Request URL: https://gateway.us.zip.co/orders/authorize
POST Body:

{
  "merchantId": "44444444-4444-4444-4444-444444444444",
  "merchantReference": "ref",
  "order": {
    "currency": "USD",
    "amount": 123.45,
  },
  "capture": true,
  "redirectCancelUrl": "https://www.bing.com",
  "redirectConfirmUrl": "https://www.google.com",
  "callbackUrl": "https://api.merchant.com"
}

📘

Use the test parameter and set it to "true" if you are using our bypass OTP in sandbox feature.

Same as the above endpoint but data is passed as query string parameters with a GET request.

Example

Request URL: https://gateway.us.zip.co/orders/authorize?merchantId=44444444-4444-4444-4444-444444444444&merchantReference=TH-20200707-1da6&order.firstName=Aaron&order.lastName=Smith&order.email=869765666.test%40quadpay.com&order.phone=5555555555&order.billingAddress.line1=123+Main+St&order.billingAddress.city=New+York&order.billingAddress.state=NY&order.billingAddress.postalCode=10003&order.billingAddress.country=US&order.amount=100.00&capture=True&callbackUrl=https%3a%2f%2fapi.merchant.com%2forder%2fcomplete&redirectCancelUrl=https%3a%2f%2fapi.merchant.com%2forder%2fcancel&redirectConfirmUrl=https%3a%2f%2fapi-ci.quadpay.com%2forder%2fcomplete&X-QP-Signature=3f3oc6tACuGIs%2fX7bhWP3PkstZ8UmI6fSZ%2buPQE8Wfo%3d

🚧

Warning

You should not reuse checkout URL when starting orders. A new URL should be created each time.

Use case #1 — If a customer at checkout decides to go back and edit their cart, a new session should be created. They should not reuse the same checkout link.

Use case #2 — If a customer has modified their checkout between navigating away (canceling) and coming back (starting same checkout), that difference won't be shown in our system if the checkout link is reused.

Will request a merchant refund to the supplied order and apply it to the customer's payment plan. If you are a pay-on-ship/DFC merchant, you can only apply up to your captured amount.

Required fields are:

  • orderId - Zip order ID to refund
  • merchantId - Your identifier provided by Zip
  • currency - The currency to issue the refund in
  • amount - The amount of the refund (not the amount of the order!)
  • merchantReference - An identifier in your system to reference this refund transaction
  • callbackUrl - A URL that will receive the webhook request about the result of this operation

Example

Request URL: https://gateway.us.zip.co/orders/11111111-1111-1111-1111-111111111111/refund
POST Body:

{
  "orderId": "11111111-1111-1111-1111-111111111111",
  "currency": "USD",
  "amount": 123.45,
  "merchantReference": "ref",
  "callbackUrl": "https://api.merchant.com"
}

Only for pay-on-ship/defer funds capture (DFC) merchants. This captures funds to reflect a fulfilled item in an order.

Required fields are:

  • orderId - Zip order ID to capture
  • merchantId - Your identifier provided by Zip
  • currency - The currency to issue the capture in
  • amount - The amount of the capture (not the amount of the order!)
  • merchantReference - An identifier in your system to reference this capture transaction
  • callbackUrl - A URL that will receive the webhook request about the result of this operation
  • singleCapture - True if this will be the only capture for the order and you want the rest to automatically be voided.

Example

Request URL: https://gateway.us.zip.co/orders/11111111-1111-1111-1111-111111111111/capture
POST Body:

{
  "orderId": "11111111-1111-1111-1111-111111111111",
  "currency": "USD",
  "amount": 123.45,
  "merchantReference": "ref",
  "callbackUrl": "https://api.merchant.com",
  "singleCapture": false
}

Only for pay-on-ship/DFC merchants. This voids funds to reflect a cancelled item in an order.

Required fields are:

  • orderId - Zip order ID to void
  • merchantId - Your identifier provided by Zip
  • currency - The currency to issue the void in
  • amount - The amount of the void (not the amount of the order!)
  • merchantReference - An identifier in your system to reference this void transaction
  • callbackUrl - A URL that will receive the webhook request about the result of this operation

Example

Request URL: https://gateway.us.zip.co/orders/11111111-1111-1111-1111-111111111111/void
POST Body:

{
  "orderId": "11111111-1111-1111-1111-111111111111",
  "currency": "USD",
  "amount": 123.45,
  "merchantReference": "ref",
  "callbackUrl": "https://api.merchant.com"
}

Merchants using the Standard Checkout with the mobile SDK will allow customers to use the Zip checkout without starting an order until this API call is made by the merchant. This same feature can be leveraged for standard online checkouts as well. The payment plan for the customer will not begin until a successful callback is received by the merchant for this operation. This operation does allow merchants to add shipping/taxes after the Zip checkout for the order. This will be processed with the currency of the original order. This functionality is enabled upon request. Please work with the integration team during onboarding if this is needed in your implementation.

Required fields are:

  • orderId - Zip order ID to confirm
  • merchantReference - An identifier in your system to reference this confirm transaction
  • callbackUrl - A URL that will receive the webhook request about the result of this operation

Optionally, you can provide the following:

  • amount - The new total order amount, including all shipping/tax amounts added in
  • shippingAmount - The final calculated shipping amount
  • taxAmount - The final calculated tax amount

Example

Request URL: https://gateway.us.zip.co/orders/11111111-1111-1111-1111-111111111111/confirm
POST Body:

{
  "orderId": "11111111-1111-1111-1111-111111111111",
  "merchantReference": "ref",
  "callbackUrl": "https://api.merchant.com"
}

Merchants with a merchant fee for payment plan (i.e. MFPP) agreement can use this endpoint to determine the fee amount for a given order. The state/country for the customer should come from the customer's shipping address. When $0 is returned, then there is no fee and does not need to display within the merchant's UX. Required fields are:

  • amount - The total order amount including shipping/tax amounts added in.
  • currency - Defaults to USD if not provided.
  • customerState- The state of the customer's shipping address.
  • customerCountry - The country of the customer's shipping address. Defaults to "US".
  • merchantId - The Merchant ID that fees need to be calculated for.

Example

Request URL: https://gateway.us.zip.co/orders/calculate-merchant-fees
POST Body:

{
  "customerState": "NY",
  "customerCountry": "US",
  "currency": "USD",
  "amount": 123.45,
  "merchantId": "44444444-4444-4444-4444-444444444444"
}

Sample response:

{
  "merchantFeeForPaymentPlan": 1.00,
  "currency": "USD"
}

Signing Requests

All operations are secured with an HMAC-SHA256 one-way hash that is performed using a shared secret key between Zip and the merchant. This secret key will be provided to you.

Signatures are generated based on the request type.

  • POST JSON Requests sign the entire request body contents.
  • POST Form Requests sign all the keys + values contained in the form request in alphabetical order except for the signature.
  • GET Requests sign all the keys + values contained in the query string in alphabetical order except for the signature.

The header or query parameter name is always X-QP-Signature.

Implementing this is language specific. Here are examples using C#, PHP, and Node.js that can generate these hashes for you:

public class HmacSha256Signature
    {
        private static Encoding encoding = Encoding.UTF8;

        /// 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.GetBytes(secretKey)))
            {
                var hash = hmacsha256.ComputeHash(bytes);

                return Convert.ToBase64String(hash);
            }
        }

        /// Given a dictionary that contains all the values from a GET or form POST request, this will return your correct hash
        public string Compute(string secretKey, IDictionary<string, string> values)
        {
            var builder = new StringBuilder();

            // Form Keys Sorted Alphabetically
            foreach (var item in values.OrderBy(i => i.Key))
            {
                if (!item.Key.Equals(Constants.SignatureKey, StringComparison.OrdinalIgnoreCase))
                {
                    builder.Append(item.Key);
                    builder.Append(item.Value);
                }
            }

            var message = builder.ToString();

            return this.Compute(secretKey, encoding.GetBytes(message));
        }

        public string Compute(string secretKey, string json)
        {
            var bytes = encoding.GetBytes(json);

            return this.Compute(secretKey, bytes);
        }

        /// This can take any object and turn it into a dictionary to be used for hash creation
        public IDictionary<string, string> GenerateKeyValues(object model)
        {
            var jsonObject = JObject.FromObject(model, JsonSerializer.Create(Constants.KeyGenSerializerSettings));
            var jTokens = jsonObject.Descendants().Where(p => p.Count() == 0);
            var keyValues = jTokens.Aggregate(
                new Dictionary<string, string>(),
                (
                    properties,
                    jToken) =>
                {
                    properties.Add(jToken.Path, jToken.ToString());
                    return properties;
                });

            return keyValues;
        }
    }
$signature = base64_encode(hash_hmac('sha256', $data, $secret, true));
// Calculate signature
const data = JSON.stringify(requestBody);
const key = 'your_api_key_here';
const signature = crypto
	.createHmac('sha256', key)
	.update(data)
	.digest('base64');

Callbacks

All of the endpoints listed above include a callbackUrl parameter. This URL will be used by Zip to update you on the result of each of these operations. The content of this webhook is as follows:

{
    "timestamp": "2020-04-27T12:34:56.000000Z",
    "merchantId": "44444444-4444-4444-4444-444444444444",
    "orderId": "11111111-1111-1111-1111-111111111111",
    "currency": "USD",
    "amount": 123.45,
    "merchantReference": "1234-abc",
    "success": true,
    "metadata": {
      "property1": "value1"
    }

The merchantReference value will match the value you provided for the original operation. You also may pass metadata properties to add other important attributes you may need to use to identify your order.

Each of these callbacks will have a X-QP-Signature header that contains the signature that you can use to verify and trust the HTTP request.

These callbacks are issued for every operation (order authorization, refund, void, and capture transactions).

Important! This data will also be provided to you as query string parameters on your supplied confirm URL when creating an order. You can use this to verify order completion within your system by verifying the signature and utilizing the other parameters to store the Zip order ID. Here is a sample URL showing how this information is added. Also note that we pass you the Zip customer information as part authorize order callbacks:

https://yoursite.com/order/complete?timestamp=04%2F27%2F2020%2023%3A27%3A22&merchantId=44444444-4444-4444-4444-444444444444&orderId=11111111-1111-1111-1111-111111111111&currency=USD&amount=123.45&merchantReference=1234-abc&test=False&success=True&customer.firstName=Test&customer.lastName=Test&[email protected]&customer.phone=%2B15555555555&customer.address.line1=123%20Main%20St&customer.address.city=New%20York&customer.address.state=NY&customer.address.postalCode=10000&customer.address.country=US&X-QP-Signature=PdkC29bSMbRG5DR6E0xQt781AgvaZa6Ov9V26Ez2OHU%3D

Test Data

You may use the below testing data while working with the Zip checkout in your development environment.

FieldTest Data
PhoneA US-based mobile phone number. You may use VOIP services for development if needed.
EmailCan be real or fake valid email address (‘@example.com’ for fake)
Verification CodeCode received via SMS
NameAnything
AddressAnything valid
BirthdateAnything 22+ years old
Billing AddressAnything valid
Card Holder NameAnything
Card Number4242 4242 4242 4242
Expiration date02 / 25
CVC222