# Hosted Payment Page

## Overview

Zapper Hosted Payment Page is a quick set-up, PCI DSS compliant service that enables customers to complete transactions on a secure payment page hosted by Zapper.

## How it works

{% hint style="info" %}
All encryption is handled internally and cardholder data will not be transmitted between Zapper and the merchant sites.
{% endhint %}

1. **Create Session and Receive RedirectUrl**&#x20;

   The merchant initiates the payment process by [creating a session](#create-a-new-session) using Zapper's API. The merchant receives a redirectUrl, which is used to redirect user to the Hosted Payment Page for payment processing.
2. **Redirect User to Zapper's Hosted Payment Page**&#x20;

   The merchant is required to redirect the user to the Hosted Payment Page, where they are presented with payment options, such as QR code or card payment.
3. **User Completes the Payment**

   The user completes the payment process on the Hosted Payment Page.
4. **Zapper Notifies Merchant via Webhook**

   After payment, Zapper sends a [payment notification](#payment-notification-webhook-model) to the merchant's notificationUrl (provided by the merchant when the session is created). The merchant is required to implement a webhook endpoint to receive these payment notifications. It is recommended that the merchant[ validate the signature](#validate-the-signature).
5. **Zapper Redirects User Back to Merchant's Store**

   Upon completing the payment process, Zapper redirects the user back to the merchant's store.

**Integration Workflow**

<figure><img src="https://2041825562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgCw1395nVhCz7oPwWE%2Fuploads%2FNtboPRpITzKF5VlqRDrf%2Fimage.png?alt=media&#x26;token=37022e7d-b550-4fd3-8d3a-f361858980e4" alt=""><figcaption></figcaption></figure>

## API Reference

## Create a new session

<mark style="color:green;">`POST`</mark> `https://gateway.zapper.com/api/v3.1/sessions`

#### Headers

| Name                                             | Type   | Description                 |
| ------------------------------------------------ | ------ | --------------------------- |
| merchantId<mark style="color:red;">\*</mark>     | String | The Zapper merchant ID      |
| merchantSiteId<mark style="color:red;">\*</mark> | String | The Zapper merchant site ID |

#### Request Body

| Name                                              | Type    | Description                                                                                                                                                                |
| ------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| requestId<mark style="color:red;">\*</mark>       | String  | The unique identifier for a given request.                                                                                                                                 |
| merchantOrderId<mark style="color:red;">\*</mark> | String  | The identifier or reference of the order generated by the merchant. It provides a way to link the session to a specific order or transaction within the merchant's system. |
| amount<mark style="color:red;">\*</mark>          | Integer | The total value of the transaction in the smallest unit of the currency specified (eg in cents).                                                                           |
| currencyISOCode<mark style="color:red;">\*</mark> | String  | The 3 letter currency code as per ISO 4217. Currently only 'ZAR' is supported.                                                                                             |
| notificationUrl<mark style="color:red;">\*</mark> | String  | [Payment notifications](#payment-notification-webhook-model) are sent to the provided notificationUrl.                                                                     |
| returnUrl<mark style="color:red;">\*</mark>       | String  | On completing a successful payment, the user is redirected to the provided returnUrl.                                                                                      |
| cancelUrl<mark style="color:red;">\*</mark>       | String  | On clicking the back-to-store button, the user is redirected to the cancelUrl.                                                                                             |
| origin<mark style="color:red;">\*</mark>          | String  | The site or domain that the request originated from.                                                                                                                       |
| siteName                                          | String  | The name or identifier of the site associated with the request.                                                                                                            |
| customFields                                      | Array   | Additional information that is needed by the merchant in the payment details. See the model below.                                                                         |

{% tabs %}
{% tab title="200: OK OK" %}

<pre class="language-json"><code class="lang-json">{
    "sessionId": "9a1e2b26-d9c3-4b2a-9fe1-e6a3cd97af06",
    "redirectUrl": "https://zapper.zmsa-tech.com/pay?sessionId={guid}",
<strong>    "status": "Success",
</strong>    "errors": []
}
</code></pre>

{% endtab %}

{% tab title="400: Bad Request Bad Request" %}

```json
{
    "status": "Bad Request",
    "errors": ["Message": "Bad Request"]
}
```

{% endtab %}

{% tab title="403: Forbidden Forbidden" %}

<pre class="language-json"><code class="lang-json">{
<strong>    "status": "Forbidden",
</strong>    "errors": ["Message": "Forbidden"]
}
</code></pre>

{% endtab %}

{% tab title="500: Internal Server Error Internal Server Error" %}

```json
{
    "status": "Internal Server Error",
    "errors": ["Message": "Internal Server Error"]
}
```

{% endtab %}
{% endtabs %}

#### Create Session Request Example:

```javascript
curl --location 'https://gateway.zapper.com/api/v3.1/sessions' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'merchantId: 1234' \
--header 'merchantSiteId: 1234' \
--header 'x-api-key: cb67xxxxxx0546f68806b62a36xxxxxx' \
--data '{
  "merchantOrderId": "c93d99c8-20e1-4fc6-95b8-10d50eb9a90e",
  "amount": 1000,
  "currencyISOCode": "ZAR",
  "notificationUrl": "https://merchantstore.com/somePaymentNotificationPath",
  "returnUrl": "https://merchantstore.com/someReturnPath",
  "cancelUrl": "https://merchantstore.com/someCancelPath",
  "requestId": "ad7234d5-4e6b-4acf-8e29-451c056b2bdc",
  "origin": "https://merchantstore.com",
  "customFields":[
      {
          "key": "FieldLabel",
          "value": "FieldValue"
      }
  ]
}'
```

## Get payments by sessionId

<mark style="color:blue;">`GET`</mark> `https://gateway.zapper.com/api/v3.1/payments`

#### Query Parameters

| Name                                        | Type   | Description                                     |
| ------------------------------------------- | ------ | ----------------------------------------------- |
| sessionId<mark style="color:red;">\*</mark> | String | The unique identifier for the ecommerce session |

#### Headers

| Name                                             | Type   | Description                 |
| ------------------------------------------------ | ------ | --------------------------- |
| merchantSiteId<mark style="color:red;">\*</mark> | String | The Zapper Merchant Site ID |
| merchantId<mark style="color:red;">\*</mark>     | String | The Zapper Merchant ID      |

{% tabs %}
{% tab title="200: OK OK" %}

```json
{
  "status": "Success",
  "errors": [],
  "merchantOrderId": "dea3d7a0-5e11-497a-8fa8-c3987623bce4",
  "paymentReference": "NN7WE7WXXDNR4925PW",
  "amount": 500,
  "currencyISOCode": "ZAR",
  "paymentStatus": "Failed",
  "userMessage": "Declined",
  "sessionId": "9a1e2b26-d9c3-4b2a-9fe1-e6a3cd97af06",
  "paymentUTCDate": "2023-06-20T12:29:11.6664948Z"
}
```

{% endtab %}

{% tab title="400: Bad Request Bad Request" %}

```json
{
    "status": "Bad Request",
    "errors": ["Message": "Bad Request"]
}
```

{% endtab %}

{% tab title="403: Forbidden Forbidden" %}

```json
{
    "status": "Forbidden",
    "errors": ["Message": "Forbidden"]
}
```

{% endtab %}

{% tab title="404: Not Found Not Found" %}

```json
{
    "status": "Not Found",
    "errors": ["Message": "Not Found"]
}
```

{% endtab %}

{% tab title="500: Internal Server Error Unexpected Error" %}

```json
{
    "status": "Success",
    "errors": []
}
```

{% endtab %}
{% endtabs %}

#### Get Payments by SessionId Request Example:

```javascript
curl --location 'https://gateway.zapper.com/api/v3.1/payments?sessionId=20908573-a1ea-412d-8a25-26e48e58c548' \
--header 'Accept: application/json' \
--header 'merchantId: 8712' \
--header 'merchantSiteId: 8727' \
--header 'x-api-key: cb67xxxxxx0546f68806b62a36xxxxxx'
```

## Get payment by paymentReference

<mark style="color:blue;">`GET`</mark> `https://gateway.zapper.com/api/v3.1/payments/{paymentReference}`

#### Path Parameters

| Name                                               | Type   | Description                          |
| -------------------------------------------------- | ------ | ------------------------------------ |
| paymentReference<mark style="color:red;">\*</mark> | String | The unique identifier of the payment |

#### Headers

| Name                                             | Type   | Description                 |
| ------------------------------------------------ | ------ | --------------------------- |
| merchantId<mark style="color:red;">\*</mark>     | String | The Zapper Merchant ID      |
| merchantSiteId<mark style="color:red;">\*</mark> | String | The Zapper Merchant Site ID |

{% tabs %}
{% tab title="200: OK OK" %}

```json
{
  "status": "Success",
  "errors": [],
  "merchantOrderId": "dea3d7a0-5e11-497a-8fa8-c3987623bce4",
  "paymentReference": "NN7WE7WXXDNR4925PW",
  "amount": 500,
  "currencyISOCode": "ZAR",
  "paymentStatus": "Failed",
  "userMessage": "Declined",
  "sessionId": "9a1e2b26-d9c3-4b2a-9fe1-e6a3cd97af06",
  "paymentUTCDate": "2023-06-20T12:29:11.6664948Z"
}
```

{% endtab %}

{% tab title="400: Bad Request Bad Request" %}

```json
{
  "status": "Success",
  "errors": []
}
```

{% endtab %}

{% tab title="403: Forbidden Forbidden" %}

```json
{
  "status": "Success",
  "errors": []
}
```

{% endtab %}

{% tab title="404: Not Found Not Found" %}

```json
{
  "status": "Success",
  "errors": []
}
```

{% endtab %}

{% tab title="500: Internal Server Error Unexpected Error" %}

```json
{
  "status": "Success",
  "errors": []
}
```

{% endtab %}
{% endtabs %}

#### Get Payments by PaymentReference Request Example:

```javascript
curl --location 'https://gateway.zapper.com/api/v3.1/payments/XZR8K9QKWVYE2E159L' \
--header 'Accept: application/json' \
--header 'merchantId: 8712' \
--header 'merchantSiteId: 8727' \
--header 'x-api-key: cb67xxxxxx0546f68806b62a36xxxxxx'
```

## Models

### Payment Notification Webhook Model

<table data-header-hidden><thead><tr><th width="282.3333333333333">Field</th><th>DataType</th><th>Description</th></tr></thead><tbody><tr><td>signature</td><td>string</td><td>The signature property represents a cryptographic value or digital signature associated with a payment notification webhook.</td></tr><tr><td>sessionId</td><td>string</td><td>The unique identifier for the sessionreference</td></tr><tr><td>amount</td><td>integer</td><td>The total value of the transaction in the smallest unit of the currency specified (eg in cents)</td></tr><tr><td>currencyISOCode</td><td>string</td><td>The 3 letter currency code as per ISO 4217. Currently only 'ZAR' is supported.</td></tr><tr><td>merchantOrderId</td><td>string</td><td>The identifier or reference of the order generated by the merchant. It provides a way to link the session to a specific order or transaction within the merchant's system.</td></tr><tr><td>paymentReference</td><td>string</td><td>A unique identifier assigned to a specific payment.</td></tr><tr><td>paymentStatus</td><td><a href="#paymentstatus">PaymentStatus</a></td><td>The status or outcome of a payment transaction</td></tr><tr><td>userMessage</td><td>string</td><td>A user friendly message. Only populated when paymentStatus is not 'Success'.</td></tr><tr><td>paymentUTCDate</td><td>string</td><td>The UTC date and time of the payment.</td></tr><tr><td>status</td><td><a href="#responsestatus">ResponseStatus</a></td><td>The API response status. A response other than 'Success' indicates that there was an error on the API level (such as request validation, or errors interpreting the gateway response). Refer to the 'errors' list for more information.</td></tr><tr><td>errors</td><td><a href="#error">Error</a></td><td>The list of errors if the status is not 'Success'.</td></tr></tbody></table>

### PaymentStatus

<table data-header-hidden><thead><tr><th width="365">Value</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>Value</td><td>Type</td><td>Description</td></tr><tr><td>1</td><td>string</td><td>Success</td></tr><tr><td>2</td><td>string</td><td>Failed</td></tr></tbody></table>

### ResponseStatus

<table data-header-hidden><thead><tr><th width="333">Value</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>Value</td><td>Type</td><td>Description</td></tr><tr><td>1</td><td>string</td><td>Success</td></tr><tr><td>2</td><td>string</td><td>BadRequest</td></tr><tr><td>3</td><td>string</td><td>NotFound</td></tr><tr><td>4</td><td>string</td><td>Unauthorized</td></tr><tr><td>5</td><td>string</td><td>InternalServer</td></tr></tbody></table>

### Error

<table data-header-hidden><thead><tr><th width="365">Value</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>Value</td><td>Type</td><td>Description</td></tr><tr><td>message</td><td>string</td><td>A human readable error message</td></tr></tbody></table>

### Custom Fields

Additional information that is needed by the merchant in the payment details.

<table data-header-hidden><thead><tr><th width="128"></th><th width="148"></th><th width="111"></th><th></th></tr></thead><tbody><tr><td>Field</td><td>Datatype</td><td>Required</td><td>Description</td></tr><tr><td>key</td><td>String</td><td>Yes</td><td>Label or Title of the additional custom field</td></tr><tr><td>value</td><td>String</td><td>Yes</td><td>Value of the additional custom field</td></tr></tbody></table>

## Signature Validation

To ensure the authenticity and integrity of the payment notification data, validating the signature is recommended.&#x20;

**V3.1 -** The PaymentNotificationWebhook is used along with the **Merchant Site API Key** when creating a SHA256 signature hash.&#x20;

<figure><img src="https://2041825562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgCw1395nVhCz7oPwWE%2Fuploads%2FfpkH6lyTFuJKM7QRGlWv%2FZapper%20-%20Merchant%20Portal%20-%20Merchant%20Site%20API%20Key%20-%20Settings%20%3E%20Integrations%20-%20cropped.png?alt=media&#x26;token=b8b0db79-e4c8-47da-9011-3f8233a548ae" alt=""><figcaption></figcaption></figure>

**V3 -** The PaymentNotificationWebhook is used along with the **Merchant API Key** when creating a SHA256 signature hash.&#x20;

<figure><img src="https://2041825562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgCw1395nVhCz7oPwWE%2Fuploads%2F7RUVINGNcBfs631kqMnc%2FZapper%20-%20Merchant%20Portal%20-%20Merchant%20API%20Key%20-%20Settings%20%3E%20Integrations%20-%20cropped.png?alt=media&#x26;token=8edaabea-9df9-44e1-9e8e-1f3fefddebbe" alt=""><figcaption></figcaption></figure>

The following are an examples of signature validation:&#x20;

**C#**

```csharp
private bool IsSignatureValid(string signature, ZapperEcomAPIV3Client.PaymentNotificationWebhook paymentNotificationWebhook, string x-api-key)
{
    string signatureInput = $"{x-api-key}|{paymentNotificationWebhook.SessionId}|{paymentNotificationWebhook.Amount}|{paymentNotificationWebhook.CurrencyISOCode}|{paymentNotificationWebhook.MerchantOrderId}|{paymentNotificationWebhook.PaymentReference}|{paymentNotificationWebhook.paymentStatus}|{paymentNotificationWebhook.PaymentUTCDate}|{paymentNotificationWebhook.UserMessage}";

    using (SHA256 sha = SHA256.Create())
    {
        byte[] hashBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(signatureInput));
        StringBuilder builder = new StringBuilder();

        foreach (byte b in hashBytes)
        {
            builder.Append(b.ToString("x2"));
        }

        string generatedSignature = builder.ToString();

        return generatedSignature.Equals(signature, StringComparison.OrdinalIgnoreCase);
    }
}
```

**JavaScript:**

```javascript
const crypto = require('crypto');

function isSignatureValid(signature, paymentNotificationWebhook, x-api-key) {
  const signatureInput = `${x-api-key}|${paymentNotificationWebhook.sessionId}|${paymentNotificationWebhook.amount}|${paymentNotificationWebhook.currencyISOCode}|${paymentNotificationWebhook.merchantOrderId}|${paymentNotificationWebhook.paymentReference}|${paymentNotificationWebhook.paymentStatus}|${paymentNotificationWebhook.paymentUTCDate}|${paymentNotificationWebhook.userMessage || ""}`;
  const generatedSignature = sha256Hash(signatureInput);
  return generatedSignature.toLowerCase() === signature.toLowerCase();
}

function sha256Hash(value) {
  const hash = crypto.createHash('sha256');
  const hashBytes = hash.update(value, 'utf-8').digest();
  return hashBytes.toString('hex');
}
```

**Java:**

```java
private static boolean isSignatureValid(String signature, PaymentNotificationWebhook paymentNotificationWebhook, String x-api-key) {
       String signatureInput = x-api-key + "|" +
                paymentNotificationWebhook.getSessionId() + "|" +
                paymentNotificationWebhook.getAmount() + "|" +
                paymentNotificationWebhook.getCurrencyISOCode() + "|" +
                paymentNotificationWebhook.getMerchantOrderId() + "|" +
                paymentNotificationWebhook.getPaymentReference() + "|" +
                paymentNotificationWebhook.getPaymentStatus() + "|" +
                paymentNotificationWebhook.getPaymentUTCDate() + "|" +
                paymentNotificationWebhook.getUserMessage();

        String generatedSignature = sha256Hash(signatureInput);
        return generatedSignature.equalsIgnoreCase(signature);
  }

 private static String sha256Hash(String value) {
       
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    byte[] hashBytes = digest.digest(value.getBytes(StandardCharsets.UTF_8));

    StringBuilder builder = new StringBuilder();
    for (byte b : hashBytes) {
        builder.append(String.format("%02x", b));
    }
    return builder.toString();
 }
```

**Payments:**\
\
The payment process is as follows:

1. When the user selects the Zapper payment option on checkout and proceeds to finalize their order, they will be presented with Zapper Hosted Payment page.
2. If the user prefers the familiar convenience of our dynamic QR code solution, they can proceed by using the Zapper mobile app to effortlessly scan the on-screen QR Code. For users accessing the store from a mobile device, the QR Code is seamlessly replaced with a deep-link button, ensuring a smooth transition to the Zapper application.
3. However, if the user prefers to use their credit or debit card for payment, they can now opt for the new card payment option. This straightforward method allows users to directly input their card details and complete the payment process right on the spot.
4. Once the payment is successfully processed – whether through QR code scanning or card payment – users will receive a confirmation in the form of a checkmark symbol. With this assurance of payment, they will then be seamlessly redirected back to the store's default payment confirmation page.

<figure><img src="https://2041825562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgCw1395nVhCz7oPwWE%2Fuploads%2FaFQQwfJLC656TF4pdmkD%2FDesktop%20Card%20Payment.jpg?alt=media&#x26;token=697df72c-627b-4e7b-9927-f351de604687" alt=""><figcaption><p>Zapper Payment Gateway - Desktop Card Payment</p></figcaption></figure>

<figure><img src="https://2041825562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgCw1395nVhCz7oPwWE%2Fuploads%2FKUecpYtDIBkoTEsPHdGQ%2FDesktop%20QR%20Payment.jpg?alt=media&#x26;token=0b703bf6-cb3d-40f1-84f3-9596ace9032a" alt=""><figcaption><p>Zapper Payment Gateway - Desktop QR Payment </p></figcaption></figure>

<figure><img src="https://2041825562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgCw1395nVhCz7oPwWE%2Fuploads%2Fn3jQQiikPaaabpXtJ6Kg%2FDesktop%20Successfull.jpg?alt=media&#x26;token=483c1a2e-43ec-446a-a4a1-4edae6bb735d" alt=""><figcaption><p>Zapper Payment Gateway - Desktop Success </p></figcaption></figure>

<figure><img src="https://2041825562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgCw1395nVhCz7oPwWE%2Fuploads%2FMAaRq5KzBRlD9bMSo8vY%2FMobile%20Payment%20Methods.jpg?alt=media&#x26;token=2e6ff448-a213-4f7b-95c3-5a56e33ef2bb" alt="" width="375"><figcaption><p>Zapper Payment Gateway - Mobile Payment Methods</p></figcaption></figure>

<figure><img src="https://2041825562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgCw1395nVhCz7oPwWE%2Fuploads%2FqWJcDQ6XthH6V8Sk1IgO%2FMobile%20card%20Payment.jpg?alt=media&#x26;token=77822872-32df-4297-9052-17100433067c" alt="" width="375"><figcaption><p>Zapper Payment Gateway - Mobile Card Payment</p></figcaption></figure>

{% hint style="info" %}
The order on the merchants store will automatically be updated with payment complete.
{% endhint %}
