# Home

Welcome to the **Kitegateway** APIs! You can use our APIs to send and receive money, through major mobile money providers, visa and banks.

Kitegateway API is fully based on [REST](http://en.wikipedia.org/wiki/Representational_State_Transfer) API (Application Programming Interfaces). This implies that the API uses standard HTTP verbs which are understood by most HTTP clients. You can view code examples in the dark area, and you can switch the programming language of the examples with the tabs.

Kitegateway API is a payment platform powerhouse. Behind these APIs is a software layer connecting and optimising payments services around the world to allow businesses to send and receive money, globally.


# Introduction

We assign an account manage who set ups your account at  [https://kitegateway.com ](https://kitegateway.com/). Our team will get back to you within 24 hours. If you have a merchant account already, go to the next step and sign in <https://kitegaway.com/signin>.

Once you sign in, you can now create a business account. You can then select an business merchant so that you manage its users, mids and charge configurations. To make a payment request, you will generate your business account [`API KEY`](/dashboard/api-credentials#api_key) and [`API SECRET`](/dashboard/api-credentials#api_secret)from you business account profile page&#x20;

{% hint style="warning" %}
&#x20;Protect your `API KEY` and `API SECRET` at all times including but not limited to avoiding saving them to source code repositories.
{% endhint %}

You can always re-generate the `API KEY` and `API SECRET` if compromised or need to change it.

In as much as you can test on the sandbox as you wish, once you are ready to go into production contact us to inform us that you are ready. We shall go through your sandbox test cases to confirm that  every use case has been covered and do other background checks to make sure that you are fully set. This is to get your admin user account and business accounts verified. Once verified then you can start to receive and send payments for that particular merchant account.


# Request/Response Format

The default response format is JSON. Requests with a message-body use plain JSON to set or update resource attributes. Successful requests will return a `200 OK` HTTP status.

Some general information about responses:

* Dates are returned in ISO8601 format: `YYYY-MM-DDTHH:MM:SS`
* Resource IDs are returned as integers.
* Any decimal monetary amount, such as prices or totals, will be returned as strings with two decimal places.
* Other amounts, such as item counts, are returned as integers.
* Blank fields are generally included as `null` or \`empty string\` instead of being omitted.


# Errors

Occasionally you might encounter errors when accessing the REST API. There are four possible types:

| Error Code                  | Error Type                                                 |
| --------------------------- | ---------------------------------------------------------- |
| `400 Bad Request`           | Invalid request, e.g. using an unsupported HTTP method     |
| `401 Unauthorized`          | Authentication or permission error, e.g. incorrect API-KEY |
| `404 Not Found`             | Requests to resources that don't exist or are missing      |
| `500 Internal Server Error` | Server error                                               |

> Kitegateway REST API error example:

```javascript
{
  "code": "kitegateway_rest_term_invalid",
  "status": "indicate if request was successfull",
  "message": "Resource doesn't exist.",
  "data": {
    "...": ...
  }
}
```

Errors return both an appropriate HTTP status code and response object which contains a `code`, `message`, `status` and `data` attribute.


# Parameters

Almost all endpoints accept optional parameters which can be passed as a HTTP query string parameter, e.g. `GET /collections?status=completed`. All parameters are documented along each endpoint.


# Pagination

Requests that return multiple items will be paginated to 10 items by default. This default can be changed by the site administrator by changing the `posts_per_page` option. Alternatively the items per page can be specified with the `?per_page` parameter:

`GET /collections?per_page=15`

You can specify further pages with the `?page` parameter:

`GET /collections?page=2`

You may also specify the offset from the first resource using the `?offset` parameter:

`GET /collections?offset=5`

Page number is 1-based and omitting the `?page` parameter will return the first page.

The total number of resources and pages are always included in the `X-PH-Total` and `X-PH-TotalPages` HTTP headers.

#### Link Header

Pagination info is included in the [Link Header](http://tools.ietf.org/html/rfc5988). It's recommended that you follow these values instead of building your own URLs where possible.

```
Link: <https://www.example.com/wp-json/wc/v1/products?page=2>; rel="next",
<https://www.example.com/wp-json/wc/v1/products?page=3>; rel="last"`
```

The possible `rel` values are:

| Value   | Description                                              |
| ------- | -------------------------------------------------------- |
| `next`  | Shows the URL of the immediate next page of results.     |
| `last`  | Shows the URL of the last page of results.               |
| `first` | Shows the URL of the first page of results.              |
| `prev`  | Shows the URL of the immediate previous page of results. |


# Registration

1\. Normally you submit your details to us via other channels of communication established or via email.&#x20;

{% hint style="danger" %}
Email <sales@kitegateway.com>
{% endhint %}

2\. You will be required to submit the different relevant KYC documents. These documents are required by our legal to ascertain your business authenticity. Some times we are acting as intermediaries for payment service providers or fintechs and in that we create accounts as authorised.

3\. We use your details to set up the main admin account that you can use to sign in to start to explore our platform.

4\. If everything is okay with the submitted KYC, it should take two (2) business days to verify your account

5\. You can go ahead to create a business account


# Environments

Once you are on the dashboard. You can sign in from here <https://kitegateway.com/signin> for **live** environment or <https://sandbox.kitegateway.com/signin> for sandbox environment.

The **sandbox** is a testing environment that isolates untested code changes and outright experimentation from the **live** environment. When using this environment. No actual payments will be made.

The **live** environment is used to effect actual payments across our different payment providers.

{% hint style="success" %}
After you are sure that everything is working well in the sandbox, you can consult our support to take your business live.
{% endhint %}


# API Tokens

Each business account can create up-to 2 API Tokens at a given time. The token has two important values; the **api\_key** and the **api\_secret**

### api\_key

Uniquely identifies the merchant it is associated with. Every request must include this key

### api\_secret

This key is also unique to the merchant account. It is required for every authenticated request. In an authenticated request, the **api\_secret** and **api\_key** are mandatory.

### Creating the keys

From the dashboard and from the let navigation of your screen, navigate to the specific business account you want to manage. Once selected, navigate to api tokens page and generate the API tokens.&#x20;

### Viewing the keys

{% hint style="danger" %}
**NOTE**\
\
Your **api\_key** and the **api\_secret** are displayed once upon generation. However we store the encrypted version of the **api\_secret**. None of us knows your secret so you have to store and use it in the safest way.&#x20;
{% endhint %}


# Step by Step Guide

## 1. Create merchant account

A **business account** is a business that is ready to accept payments in multiple ways, typically mobile money, crypto, debit or credit cards. From the left side bar menu, choose business accounts and then tap the `Add business account` button in order to create business accounts. Part of the information included in the merchant account comprise:

<div><figure><img src="https://1651461756-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1osqKR2tRm8OtrtXF4OJ%2Fuploads%2FfDe99cXpWYNNlEft8XzA%2FScreenshot%202025-04-12%20at%2015.46.15.png?alt=media&amp;token=618c08cc-cbeb-4f54-8170-58229ed90b98" alt=""><figcaption></figcaption></figure> <figure><img src="https://1651461756-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1osqKR2tRm8OtrtXF4OJ%2Fuploads%2FDUqYkXA1q6ECnCxDC7CI%2FScreenshot%202025-04-12%20at%2015.48.07.png?alt=media&amp;token=8e8eb3c1-e271-4111-b46b-99cc25fb571a" alt=""><figcaption></figcaption></figure></div>

#### Name

A business name is your business's legal name. It is the official name of the person or entity that owns a company. And, it's the name you use on your government forms and business paperwork

#### RR

This is the rolling reserve percentage as specified by the acquirer

#### RR(Months)

The number of months the rolling reserve will take to expire

#### Card T+ (Days)

The settlement time of the funds&#x20;

## 2. Create MID/PSP

Mids are terminals that are used to route traffic. You will need to set up a mid before you can start transacting

<figure><img src="https://1651461756-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1osqKR2tRm8OtrtXF4OJ%2Fuploads%2FQ9fxCETYYHqqm1Jv8ycp%2FScreenshot%202025-04-12%20at%2015.51.26.png?alt=media&amp;token=233700b9-df8c-438f-820a-8fea87c80da9" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1651461756-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1osqKR2tRm8OtrtXF4OJ%2Fuploads%2FpJL5C4tdKodZH29wgm4e%2FScreenshot%202025-04-12%20at%2015.53.42.png?alt=media&amp;token=9df9b247-c28d-4647-90c3-a088d87fe707" alt=""><figcaption></figcaption></figure>

**Mid Business Name**

This is the business name as registered at the acquirer. We recommend  postfixing the Mid name with the acquirer name for easier management but this is entirely optional. For example a mid name will be like **your-mid-name-acquirer-name**

**Service Type**

This defines the payment processor who is going to transact eg `vcs - for cybersource`, `mpgs - for mastercard`, etc

**Payment Method**

This is the means of transacting that is being used eg **CARD** [see](/appendix/payment-methods)&#x20;

**Currency**

The currency being used to transact see

**Allowed traffic**

The kind of traffic that is being used to traffic. This helps to keep afloat with the relevant MCC codes and is route traffic to appropriately.

**Merchant Operator**

The operator that is being used at the acquirers processor

**Merchant Username**

The username that is being used at the acquirers processor terminal

**Merchant Password**

The password to the processor terminal being used

**Processing Rank**

This determines the priority in which the mid should be selected. The algorithm for selection is based on round robin. 1 for is for highest ranking.

**Reject First Time Depositors**

This option is one of our fraud detection option in our algorithm. New cards are notorious for fraud. When this option is selected, only cards that have been issued after one year are used for transacting.

**Active**

Used to make the mid live for processing otherwise the mid wont be selected to be used in the pool as an option for processing

## 3. Generate API Tokens

**API Tokens** include a **key** that identifies the merchant responsible for the **API** service request. This **key** is not a **secret**, and must be included in each request. **API Token** includes a confidential **secret key** used for authentication, which is only known to the merchant and to the **API** service.&#x20;

<figure><img src="https://1651461756-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1osqKR2tRm8OtrtXF4OJ%2Fuploads%2FVWUE4e3PaNEFBuedcSuI%2FScreenshot%202025-04-12%20at%2015.57.14.png?alt=media&amp;token=32a9d8d7-621d-43ac-8d4a-826ce4f5d5a7" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
From the left sidebar, navigate to business accounts and create a business account or choose an existing one. After that select the business account you have created then navigate to the Api Keys tab to generate API token. Incase you have lost your secret, you can regenerate a new one
{% endhint %}

{% hint style="danger" %}
Every collection action requires only the **api\_key**. However all disbursements must include the **api\_secret**
{% endhint %}

Besides the API KEY and API SECRET. The API token includes the following;

#### **Notification Email**

This is the email that will receive any payment related notifications at the start and then the summaries at the end.

#### **Webhook URL**

This is used by kitegateway to send real time payment status updates.&#x20;

#### Webhook Hash

With just the webhook URL alone, any services on the internet can possibly send request to it so in order to protect against that, the hash comes into play. The hash helps to identify that the request actually came from **Kitegateway** thus providing an extra layer of security.

{% hint style="info" %}
You have to generate at least 16 character hash
{% endhint %}

**Email Merchant**

Specifies if the merchant should receive payment notifications

**Email User**

Specifies if the user making the payment request should receive payment notifications

## 4. Make a request

Once you have set up the crucial details above, you can now start making transactions to collect and disburse money in the form of mobile money, card and crypto.

{% hint style="success" %}
Horray! :)
{% endhint %}


# Test numbers

The sandbox environment behaves like the real environment except for the fact that no real transactions are performed. You will need the following parameters for use in sandbox.


# Mobile Money Test Numbers

| phone                           | Description                          |
| ------------------------------- | ------------------------------------ |
| `256777111786` , `256752000123` | Getting successful requests response |
| `256777000456` , `256752000456` | Getting failure requests response    |


# Card Test Numbers

### Test Card 3D Success

> **Card number:** `4024 0071 9269 0864`\
> **cvv:** 334\
> **Expiry:** 02/29\
> **Pin:** 6620\
> **OTP:** 12345

### Test Card 3D Failure

> **Card number:** `4024 0071 4508 7440`\
> **cvv:** 334\
> **Expiry:** 02/29\
> **Pin:** 6620\
> **OTP:** 12345


# Access Token

All request must have an **Access token**. Access tokens are used to make API requests on behalf of your merchant account. It is used for **Authorization**.

Access tokens must be kept confidential in transit and in storage. The only parties that should ever see the access token are Kitegateway APIs and your servers. Your application should ensure the storage of the access token is not accessible to other applications

## How to get an access token

You have to use your merchant [**api\_key**](/dashboard/api-credentials#api_key) and [**api\_secret**](/dashboard/api-credentials#api_secret) in order to get an access token by making a request as below

#### Live

```typescript
POST  https://kitegateway.com/v1/auth/token
```

**Sandbox**

```
POST  https://sandbox.kitegateway.com/v1/auth/token
```

{% tabs %}
{% tab title="Headers" %}

#### Request Headers

| Header           | Value                  | Required |
| ---------------- | ---------------------- | -------- |
| **Content-Type** | **`application/json`** | YES      |
| **Accept**       | **`application/json`** | YES      |
| **Secret-Key**   | **`YOUR_SECRET`**      | YES      |
| {% endtab %}     |                        |          |

{% tab title="Request" %}

#### Request Body

| Parameter       | Type    | Description                                       | Required                      |
| --------------- | ------- | ------------------------------------------------- | ----------------------------- |
| **api\_key**    | string  | Obtained from merchant profile account            | YES                           |
| **expires\_in** | integer | The time taken for the token to expire in seconds | Optional. Default 900 seconds |
| {% endtab %}    |         |                                                   |                               |

{% tab title="Response" %}

#### &#x20;Response body

| Parameters   | Type    | Description                                                                  |
| ------------ | ------- | ---------------------------------------------------------------------------- |
| token        | string  | The access token that can be used to make a request on any of the end points |
| expires      | integer | The timestamp of when the token will expire                                  |
| {% endtab %} |         |                                                                              |

{% tab title="Sample Request" %}

```typescript
{ 
    "api_key": "2882jj2hh288282jj2", // Obtain from your merchant profile" 
    "expires_in": 300
}
```

{% endtab %}

{% tab title="Sample Response" %}

```typescript
{
  "code": 200,
  "status": "success",
  "message": "Token generated",
  "data": {
    "token": "JWT eyJ0eXAiOiBBV1QzI1NiJ9.eTAW0InJvbGUi2YifQ.f6FPyTxzchGD7ed55Rw7ruqe6P_Go",
    "expires": 1622197906
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}

#### Header: Authorization

All Requests to whatever Kitegateway end point must contain an authorization header that contains the token generated. This provides another layer of security. To even strengthen the security further, this token should be as short lived as much as possible based on the specified scenario.

**`e.g`"Authorization: JWT eyJ0ejjsjjdjjjjsjjs.eTThhhshhshhhs.88asd998sads..."**
{% endhint %}


# Steps

Allows your merchant account to get paid in a way that works for you using the various options we provide. You can receive funds from anyone, anywhere directly into your wallet through our payment methods that support; `mobile` `money`, `card` and `crypto`&#x20;

### Steps for receiving money

1. Create your request data as a JSON
2. Set the relevant request headers;&#x20;

   a) **`Content-Type`: `application/json`**\
   b) **`Accept`**:  **`application/json`**

   c) [**`Authorization`**](/authorization/access-token#how-to-get-an-access-token)

   &#x20;   The access token that was generated on the authorization `API`
3. `POST` the composed data to the collections `API`.
4. Process the response returned by the `API`&#x20;

   In-case the response contains a `payment_url` that is required to complete a transaction, we expect your application to redirect the customer to the payment `URL`
5. As the payment is being processed on our side,  any change in payment status will be sent to the respective [`webhook URL`](/appendix/webhook) of the merchant account.


# Collection Post Request

You can make the payment using any of the URLs below&#x20;

#### Live

```typescript
POST  https://kitegateway.com/v1/collections/request-to-pay
```

**Sandbox**

```
POST  https://sandbox.kitegateway.com/v1/collections/request-to-pay
```

{% tabs %}
{% tab title="Headers" %}

#### Request Headers

| Header           | Value                  | Required |
| ---------------- | ---------------------- | -------- |
| **Content-Type** | **`application/json`** | YES      |
| Accept           | **`application/json`** | YES      |
| Authorization    | **`JWT ***`**          | YES      |
| {% endtab %}     |                        |          |

{% tab title="Request" %}

#### Request Body

| Parameter           | Type   | Description                                                                                                                                                                                                                                                                                                                                                                                                                        | Required                                               |
| ------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| currency            | string | <p>The medium of exchange for goods and services. e.g USD, UGX, KES</p><p>In case the currency is different from the merchant wallet where the money is supposed to go, the funds will be exchanged based on the market rate</p>                                                                                                                                                                                                   | YES                                                    |
| amount              | double | 2 decimal places                                                                                                                                                                                                                                                                                                                                                                                                                   | YES                                                    |
| payment\_method     | string | <p>The means through which the money will be transacted.</p><p><code>MOBILE\_MONEY</code>, <code>CARD</code>, <code>BANK</code>, <code>CRYPTO</code></p>                                                                                                                                                                                                                                                                           | YES                                                    |
| account\_number     | string | The unique identifier on the providers' network where the money will originate from. For mobile money ie if the **payment\_method** is`MOBILE_MONEY`, you should provide an internationally formatted `phone_number` i.e 2567041111111                                                                                                                                                                                             | Not Required for `CARD`                                |
| merchant\_reference | string | The **UNIQUE** Identification for a transaction generated by your merchant application                                                                                                                                                                                                                                                                                                                                             | <p>YES,</p><p><code>UUID4 9 to 36 character</code></p> |
| narration           | string | A brief description of the transaction                                                                                                                                                                                                                                                                                                                                                                                             | required, `9 to 64` characters max                     |
| redirect\_url       | string | <p>When a payment is initiated, sometimes a payment link is returned in the response if the payment must be completed by the customer via the <strong>payment\_url</strong></p><p></p><p>The payment methods that return a payment\_url link include, online banking methods, visa 3d</p><p></p><p>So the redirect\_url is used to redirect the customer after payment has been completed or canceled via the payment\_url<br></p> | Required for `BANK`, `CARD` and `CRYPTO` collections.  |
| account\_name       | string | The name of your customer who is making the payment request                                                                                                                                                                                                                                                                                                                                                                        | Required for CARD                                      |
| account\_email      | string | The email of your customer who is making the request                                                                                                                                                                                                                                                                                                                                                                               | Required for CARD                                      |
| {% endtab %}        |        |                                                                                                                                                                                                                                                                                                                                                                                                                                    |                                                        |

{% tab title="Response" %}

#### &#x20;Response body

| Parameters             | Type    | Description                                                                                                                                                                                                                                                                                            |
| ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| request\_amount        | double  | Amount requested for collection                                                                                                                                                                                                                                                                        |
| request\_currency      | string  | The currency of the requested amount                                                                                                                                                                                                                                                                   |
| account\_amount        | double  | The converted amount from request\_currency to wallet\_currency at market rate.                                                                                                                                                                                                                        |
| account\_currency      | string  | <p>The wallet currency where the amount paid by the customer will be deposited.<br><br>The currency of the amount paid by the customer is determined by the <strong>provider</strong> used to pay.</p>                                                                                                 |
| transaction\_fee       | double  | This is the fee charged based on the paid amount.                                                                                                                                                                                                                                                      |
| total\_credit          | double  | This is the amount less the transaction\_fee deposited in your account wallet                                                                                                                                                                                                                          |
| merchant\_reference    | string  | This is the reference that was specified at the start of the transaction                                                                                                                                                                                                                               |
| kitegateway\_reference | string  | This is the unique id of the transaction on the Kitegateway network. You are advised to store it because it is used to track transaction-related queries.                                                                                                                                              |
| transaction\_status    | string  | The stage of the transaction                                                                                                                                                                                                                                                                           |
| customer\_charged      | boolean | It indicates whether if the merchant customer was charged instead                                                                                                                                                                                                                                      |
| payment\_url           | string  | <p><code>Optional</code> The URL where the customer is redirected to complete the payment.<br><br>It's only returned if the payment has to be completed from a web browser.</p>                                                                                                                        |
| instructions           | string  | <p><code>Optional</code> It contains instructions that advise the customer about what they should next.<br><br>It is always present on mobile money transactions and requests that do not contain <code>payment\_url</code>.<br><br>We recommend that you display the instructions to the customer</p> |
| {% endtab %}           |         |                                                                                                                                                                                                                                                                                                        |

{% tab title="Sample Request" %}

```typescript
{ 
    "currency": "USD", // OR KES or TZS or RWF or USD or EUR ..etc
    "amount": 200,
    "account_number": "256775123123",
    "payment_method": "CARD", // OR CARD or BANK or CRYPTO, 
    "merchant_reference": "Your unique payment reference", 
    "narration": "Reason for payment",
    "redirect_url": "optional.For payments completed via payment_url ",
    "account_name": "Ankunda Ruth",
    "account_email": "ankunda99ruth@gmail.com"
}
```

{% endtab %}

{% tab title="Sample Response" %}

```javascript
{
  "code": 200,
  "status": "accepted",
  "message": "Transaction Initiated",
  "data": {
    "id": "8823887277266266662662662",
    "request_amount": 20000,
    "request_currency": "UGX",
    "account_amount": 20000,
    "account_currency": "UGX",
    "transaction_fee": 3000,
    "total_credit": 15000,
    "merchant_reference": "3CC383-3A673-8392-AF883-99AKJ",
    "kitegateway_reference": "WPC405GZM1G5JXGA71IK",
    "transaction_status": "PENDING",
    "transaction_type": "collection",
    "message": "Transaction started",
    "account_name": "Ankunda Ruth",
    "account_email": "ankunda99ruth@gmail.com",
    "customer_charged": false,
    "payment_url": "Exists if web browser shold be used to complete payments",
    "instructions": [
      {
        "step": "1",
        "description": "Ensure that you have enough money on your Airtel Money account"
      },
      {
        "step": "2",
        "description": "When the USSD screen appears with the specified amount, approve the payment"
      }
    ]
  }
}
```

{% endtab %}

{% tab title="Sample IPN" %}

```javascript
{
    "id": "888237273723723772377232323",
    "request_amount": 20000,
    "request_currency": "UGX",
    "account_amount": 20000,
    "account_currency": "UGX",
    "transaction_fee": 3000,
    "total_credit": 15000,
    "customer_charged": false,
    "merchant_reference": "3CC383-3A673-8392-AF883-99AKJ",
    "kitegateway_reference": "KG405GZM1G5JXGA71IK",
    "transaction_status": "COMPLETED",
    "transaction_type": "collection",
    "message": "Transaction Completed Successfully",
    "account_name": "Ankunda Ruth",
    "account_email": "ankunda99ruth@gmail.com",
    "institution_name": "Optional eg: Aritel Money Uganda"
}
```

{% endtab %}
{% endtabs %}

###


# Mobile Money Payment

### Set Payment Method

When the payment transaction is to be completed using mobile money, The **`payment_method`** field should be set to **`MOBILE_MONEY`** in the post request collection body.

{% tabs %}
{% tab title="Sample Request Body" %}

```javascript
{
  ...
  "method": "MOBILE_MONEY",
  ...
}
```

{% endtab %}
{% endtabs %}

### Instructions

Directions about how the payment will be completed will be sent in the response body

{% tabs %}
{% tab title="Sample Response Body" %}

```javascript
{
  ...
  "instructions": [
    {
      "step": "1",
      "description": "Ensure that you have enough money on your Airtel Money account"
    },
    {
      "step": "2",
      "description": "When the USSD screen appears with the specified amount, approve the payment by entering the PIN"
    }
  ]
  ...
}
```

{% endtab %}
{% endtabs %}


# Card Payment

### Set Payment Method

When the payment transaction is to be completed using card, the **`payment_method`** field should be set to **`CARD`** in the post request collection body. For card payments, since we only support 3D. This means that the customer's card must be enabled for 3D authentication for them to complete their card payments. So in the request body, you should provide a **`redirect_url`** where the customer will be navigated to when they complete or cancel the transaction

{% hint style="danger" %}

#### redirect\_url

It must be secured by **SSL.** ie, it must start with **https\://**
{% endhint %}

{% tabs %}
{% tab title="Sample Request Body" %}

```javascript
{
  ...
  "payment_method": "CARD",
  "redirect_url": "https://your-redirect_url"
  ...
}
```

{% endtab %}
{% endtabs %}

### Redirect customer

We expect your application to redirect the customer to that **`payment_url`** to complete the payment


# Direct card payment

A **direct card payment** is a payment transaction in which your customer has authorized you to take money from their card using their full card details. However, the **`Card`** details are sent as an encrypted string.

Posting a direct card request is the same as posting a card payment however th&#x65;**`encrypted_card`** parameter will have to be specified. By providing this field, kitegateway will know that the transaction is a direct card payment.

## Providing `encrypted_card`&#x20;

### Encryption

#### **1. Create JSON of the Card details**

{% tabs %}
{% tab title="Data" %}

```javascript
{
    "full_name": "Nakimbugwe Racheal",
    "card_number": "012345666777888999",
    "expiry_month": "02",
    "expiry_year": "24",
    "cvv": "111",
    "billing_address": "Some Street",
    "billing_city": "Some City",
    "billing_zip": "88653",
    "billing_state": "JK",
    "billing_country": "UK"
}
```

{% endtab %}

{% tab title="Description" %}

| Parameter        | Type   | Description                                                                                                    | Required |
| ---------------- | ------ | -------------------------------------------------------------------------------------------------------------- | -------- |
| full\_name       | string | The full name of the card holder as registered by the card issuer                                              | YES      |
| card\_number     | string | The card number. Usually the length of 16 to 19                                                                | YES      |
| expiry\_month    | string | Card expiry month. For single digit months, prefix 0 e.g. `06`                                                 | YES      |
| expiry\_year     | string | Card expiry year                                                                                               | YES      |
| cvv              | string | The card CVV, CVC, etc depending on the nature of the card                                                     | YES      |
| billing\_address | string | Billing address as registered by the card issuer.                                                              | YES      |
| billing\_city    | string | Billing city name as registered by the issuer.                                                                 | YES      |
| billing\_zip     | string | The zip/postal code.                                                                                           | YES      |
| billing\_state   | string | State name.                                                                                                    | YES      |
| billing\_country | string | The 2 character ISO country code. The country code list can be obtained using the API description that follows | YES      |
| {% endtab %}     |        |                                                                                                                |          |
| {% endtabs %}    |        |                                                                                                                |          |

#### **2.** Downloading Public Key

```javascript
// Live
GET https://kitegateway.com/v1/public-key
```

```javascript
// Sandbox
GET https://sandbox.kitegateway.com/v1/public-key
```

{% tabs %}
{% tab title="Shell" %}

```
// live
curl -v -X GET 'https://kitegateway.com/v1/public-key -H 'Authorization: JWT ***' --output kitegateway.public.key.pem

```

{% endtab %}
{% endtabs %}

#### 3.Encryption Card

{% tabs %}
{% tab title="NodeJS" %}

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

const card_data = {
        full_name: "Ankunda Ruth",
        card_number: "0002221238737737737",
        expiry_month: "02",
        expiry_year: "24",
        cvv: "111",
        billing_address: "Kensington Street No. 2",
        billing_city: "London",
        billing_zip: "12345",
        billing_state: "London",
        billing_country: "UK",
    };

function encrypt(card_data) {
    // Stringify card data
    const payload = JSON.stringify(card_data);
    console.log(`Payload size: ${Buffer.from(payload).length} bytes`);

    // Load public key
    const publicKeyFile = "path-to-file/kitegateway.public.key.pem";
    const publicKey = fs.readFileSync(publicKeyFile).toString().replace(/\\n/g, '\n');

    // Check payload size (max 214 bytes for 2048-bit key with OAEP padding)
    if (Buffer.from(payload).length > 214) {
        // Generate AES key and IV
        const aesKey = crypto.randomBytes(32); // 256-bit AES key
        const iv = crypto.randomBytes(16); // 128-bit IV

        // Encrypt payload with AES-256-CBC
        const cipher = crypto.createCipheriv('aes-256-cbc', aesKey, iv);
        let encryptedData = cipher.update(payload, 'utf8', 'base64');
        encryptedData += cipher.final('base64');
        console.log(`AES encrypted data size: ${Buffer.from(encryptedData, 'base64').length} bytes`);

        // Encrypt AES key with RSA-OAEP
        const encryptedAesKey = crypto.publicEncrypt(
            {
                key: publicKey,
                padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
            },
            aesKey
        );
        // Combine encrypted data, IV, and encrypted AES key
        const result = `${encryptedData}::${iv.toString('base64')}::${encryptedAesKey.toString('base64')}`;
        const base64Result = Buffer.from(result).toString('base64');

        // Validate base64
        if (!/^[A-Za-z0-9+/=]+$/.test(base64Result)) {
            console.error('Invalid base64 encoding of hybrid ciphertext.');
            return null;
        }
        console.log(`Hybrid encrypted data (base64): ${base64Result}`);
        return base64Result;
    }

    // Standard RSA-OAEP encryption
    const encryptedData = crypto.publicEncrypt(
        {
            key: publicKey,
            padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
        },
        Buffer.from(payload)
    );
    const base64Result = encryptedData.toString('base64');

    // Validate base64
    if (!/^[A-Za-z0-9+/=]+$/.test(base64Result)) {
        console.error('Invalid base64 encoding of ciphertext.');
        return null;
    }

    return base64Result;
}
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

  /**
 * Encrypts card details using hybrid encryption (RSA-OAEP + AES-256-CBC).
 *
 * @param string $public_key_path Path to the RSA public key file (e.g., 'kitegateway.public.key.pem').
 * @param string $full_name Cardholder's full name.
 * @param string $card_number Card number.
 * @param string $expiry_month Expiry month (MM).
 * @param string $expiry_year Expiry year (YY).
 * @param string $cvv CVV code.
 * @param string $billing_address Billing address.
 * @param string $billing_city Billing city.
 * @param string $billing_zip Billing ZIP/postal code.
 * @param string $billing_state Billing state (e.g., 2-letter code).
 * @param string $billing_country Billing country (e.g., 2-letter code).
 * @return string|null Base64-encoded encrypted data or null on failure.
 */
function encrypt_card_details(
    $public_key_path,
    $full_name,
    $card_number,
    $expiry_month,
    $expiry_year,
    $cvv,
    $billing_address,
    $billing_city,
    $billing_zip,
    $billing_state,
    $billing_country
) {
    // Initialize return value
    $ret = null;

    // Check for OpenSSL extension
    if (!extension_loaded('openssl')) {
        return $ret;
    }

    // Load public key
    $key_content = @file_get_contents($public_key_path);
    if ($key_content === false) {
        return $ret;
    }

    $public_key = openssl_get_publickey($key_content);
    if ($public_key === false) {
        return $ret;
    }

    // Verify key details
    $key_details = openssl_pkey_get_details($public_key);
    if ($key_details === false || !isset($key_details['bits']) || $key_details['bits'] !== 2048) {
        openssl_free_key($public_key);
        return $ret;
    }

    // Prepare card data as JSON
    $card_data = json_encode([
        'full_name' => $full_name,
        'card_number' => $card_number,
        'expiry_month' => $expiry_month,
        'expiry_year' => $expiry_year,
        'cvv' => $cvv,
        'billing_address' => $billing_address,
        'billing_city' => $billing_city,
        'billing_zip' => $billing_zip,
        'billing_state' => $billing_state,
        'billing_country' => $billing_country
    ]);

    if ($card_data === false) {
        openssl_free_key($public_key);
        return $ret;
    }

    $data_size = strlen($card_data);

    // Hybrid encryption for data > 214 bytes
    if ($data_size > 214) {
        // Generate AES key and IV
        $aes_key = openssl_random_pseudo_bytes(32);
        $iv = openssl_random_pseudo_bytes(16);

        // Encrypt data with AES-256-CBC
        $encrypted_data = openssl_encrypt($card_data, 'AES-256-CBC', $aes_key, 0, $iv);
        if ($encrypted_data === false) {
            openssl_free_key($public_key);
            return $ret;
        }

        // Encrypt AES key with RSA-OAEP
        if (!openssl_public_encrypt($aes_key, $encrypted_aes_key, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) {
            openssl_free_key($public_key);
            return $ret;
        }

        // Combine components
        $ret = base64_encode($encrypted_data . '::' . base64_encode($iv) . '::' . base64_encode($encrypted_aes_key));
    } else {
        // Standard RSA-OAEP encryption for small data
        if (!openssl_public_encrypt($card_data, $result, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) {
            openssl_free_key($public_key);
            return $ret;
        }

        $ret = base64_encode($result);
    }

    openssl_free_key($public_key);
    return $ret;
}

// Example usage (for testing)
/*
$public_key_path = 'kitegateway.public.key.pem';
$encrypted = encrypt_card_details(
    $public_key_path,
    'Test User',
    '4111111111111111',
    '12',
    '25',
    '123',
    '123 Main St, Apt 4B',
    'Springfield',
    '62701',
    'IL',
    'US'
);
echo $encrypted ? $encrypted : 'Encryption failed';
*/

?>
```

{% endtab %}

{% tab title="Python" %}

```python
import json
import base64
import os
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend

def encrypt_card_details(
    public_key_path,
    full_name,
    card_number,
    expiry_month,
    expiry_year,
    cvv,
    billing_address,
    billing_city,
    billing_zip,
    billing_state,
    billing_country
):
    try:
        # Load public key
        if not os.path.exists(public_key_path):
            return None
        with open(public_key_path, 'rb') as f:
            public_key = serialization.load_pem_public_key(f.read(), backend=default_backend())
        
        # Verify key size
        if not isinstance(public_key, rsa.RSAPublicKey) or public_key.key_size != 2048:
            return None

        # Prepare card data as JSON
        card_data = json.dumps({
            'full_name': full_name,
            'card_number': card_number,
            'expiry_month': expiry_month,
            'expiry_year': expiry_year,
            'cvv': cvv,
            'billing_address': billing_address,
            'billing_city': billing_city,
            'billing_zip': billing_zip,
            'billing_state': billing_state,
            'billing_country': billing_country
        }).encode('utf-8')

        data_size = len(card_data)

        if data_size > 214:
            # Generate AES key and IV
            aes_key = os.urandom(32)
            iv = os.urandom(16)

            # Encrypt data with AES-256-CBC
            cipher = Cipher(algorithms.AES(aes_key), modes.CBC(iv), backend=default_backend())
            encryptor = cipher.encryptor()
            padded_data = card_data + b'\0' * (16 - (data_size % 16))  # PKCS7-like padding
            encrypted_data = encryptor.update(padded_data) + encryptor.finalize()

            # Encrypt AES key with RSA-OAEP
            encrypted_aes_key = public_key.encrypt(
                aes_key,
                padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), label=None)
            )

            # Combine components
            return base64.b64encode(
                encrypted_data + b'::' + base64.b64encode(iv) + b'::' + base64.b64encode(encrypted_aes_key)
            ).decode('utf-8')
        else:
            # Standard RSA-OAEP encryption
            encrypted_data = public_key.encrypt(
                card_data,
                padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), label=None)
            )
            return base64.b64encode(encrypted_data).decode('utf-8')
    
    except Exception:
        return None

# Example usage
"""
if __name__ == '__main__':
    result = encrypt_card_details(
        'kitegateway.public.key.pem',
        'Test User',
        '4111111111111111',
        '12',
        '25',
        '123',
        '123 Main St, Apt 4B',
        'Springfield',
        '62701',
        'IL',
        'US'
    )
    print(result if result else 'Encryption failed')
"""
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require 'json'
require 'base64'
require 'openssl'

def encrypt_card_details(
  public_key_path,
  full_name,
  card_number,
  expiry_month,
  expiry_year,
  cvv,
  billing_address,
  billing_city,
  billing_zip,
  billing_state,
  billing_country
)
  begin
    # Load public key
    return nil unless File.exist?(public_key_path)
    public_key = OpenSSL::PKey::RSA.new(File.read(public_key_path))
    
    # Verify key size
    return nil unless public_key.n.num_bytes * 8 == 2048

    # Prepare card data as JSON
    card_data = JSON.dump({
      full_name: full_name,
      card_number: card_number,
      expiry_month: expiry_month,
      expiry_year: expiry_year,
      cvv: cvv,
      billing_address: billing_address,
      billing_city: billing_city,
      billing_zip: billing_zip,
      billing_state: billing_state,
      billing_country: billing_country
    })
    
    data_size = card_data.bytesize

    if data_size > 214
      # Generate AES key and IV
      aes_key = OpenSSL::Random.random_bytes(32)
      iv = OpenSSL::Random.random_bytes(16)

      # Encrypt data with AES-256-CBC
      cipher = OpenSSL::Cipher.new('AES-256-CBC')
      cipher.encrypt
      cipher.key = aes_key
      cipher.iv = iv
      encrypted_data = cipher.update(card_data) + cipher.final

      # Encrypt AES key with RSA-OAEP (simulated via PKCS1_OAEP padding)
      encrypted_aes_key = public_key.public_encrypt(aes_key, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)

      # Combine components
      Base64.encode64(
        encrypted_data + '::' + Base64.encode64(iv) + '::' + Base64.encode64(encrypted_aes_key)
      ).chomp
    else
      # Standard RSA-OAEP encryption
      encrypted_data = public_key.public_encrypt(card_data, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
      Base64.encode64(encrypted_data).chomp
    end
  rescue
    nil
  end
end

# Example usage
=begin
result = encrypt_card_details(
  'kitegateway.public.key.pem',
  'Test User',
  '4111111111111111',
  '12',
  '25',
  '123',
  '123 Main St, Apt 4B',
  'Springfield',
  '62701',
  'IL',
  'US'
)
puts result || 'Encryption failed'
=end
```

{% endtab %}

{% tab title="C#" %}

```csharp
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;

public class EncryptCardDetails
{
    public static string Encrypt(
        string publicKeyPath,
        string fullName,
        string cardNumber,
        string expiryMonth,
        string expiryYear,
        string cvv,
        string billingAddress,
        string billingCity,
        string billingZip,
        string billingState,
        string billingCountry)
    {
        try
        {
            // Load public key
            if (!File.Exists(publicKeyPath)) return null;
            string keyContent = File.ReadAllText(publicKeyPath);
            using var rsa = RSA.Create();
            rsa.ImportFromPem(keyContent.ToCharArray());

            // Verify key size
            if (rsa.KeySize != 2048) return null;

            // Prepare card data as JSON
            var cardData = JsonSerializer.Serialize(new
            {
                full_name = fullName,
                card_number = cardNumber,
                expiry_month = expiryMonth,
                expiry_year = expiryYear,
                cvv,
                billing_address = billingAddress,
                billing_city = billingCity,
                billing_zip = billingZip,
                billing_state = billingState,
                billing_country = billingCountry
            });
            byte[] cardDataBytes = Encoding.UTF8.GetBytes(cardData);
            int dataSize = cardDataBytes.Length;

            if (dataSize > 214)
            {
                // Generate AES key and IV
                using var aes = Aes.Create();
                aes.KeySize = 256;
                aes.GenerateKey();
                aes.GenerateIV();

                // Encrypt data with AES-256-CBC
                using var ms = new MemoryStream();
                using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cardDataBytes, 0, cardDataBytes.Length);
                    cs.FlushFinalBlock();
                }
                byte[] encryptedData = ms.ToArray();

                // Encrypt AES key with RSA-OAEP
                byte[] encryptedAesKey = rsa.Encrypt(aes.Key, RSAEncryptionPadding.OaepSHA1);

                // Combine components
                string result = Convert.ToBase64String(encryptedData) + "::" +
                               Convert.ToBase64String(aes.IV) + "::" +
                               Convert.ToBase64String(encryptedAesKey);
                return Convert.ToBase64String(Encoding.UTF8.GetBytes(result));
            }
            else
            {
                // Standard RSA-OAEP encryption
                byte[] encryptedData = rsa.Encrypt(cardDataBytes, RSAEncryptionPadding.OaepSHA1);
                return Convert.ToBase64String(encryptedData);
            }
        }
        catch
        {
            return null;
        }
    }
}

// Example usage
/*
class Program
{
    static void Main()
    {
        string result = EncryptCardDetails.Encrypt(
            "kitegateway.public.key.pem",
            "Test User",
            "4111111111111111",
            "12",
            "25",
            "123",
            "123 Main St, Apt 4B",
            "Springfield",
            "62701",
            "IL",
            "US"
        );
        Console.WriteLine(result ?? "Encryption failed");
    }
}
*/
```

{% endtab %}

{% tab title="Java" %}

```java
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import com.google.gson.Gson;

public class EncryptCardDetails {
    public static String encrypt(
            String publicKeyPath,
            String fullName,
            String cardNumber,
            String expiryMonth,
            String expiryYear,
            String cvv,
            String billingAddress,
            String billingCity,
            String billingZip,
            String billingState,
            String billingCountry) {
        try {
            // Load public key
            File keyFile = new File(publicKeyPath);
            if (!keyFile.exists()) return null;
            String keyContent = new String(Files.readAllBytes(keyFile.toPath()))
                    .replace("-----BEGIN PUBLIC KEY-----", "")
                    .replace("-----END PUBLIC KEY-----", "")
                    .replaceAll("\\s", "");
            byte[] keyBytes = Base64.getDecoder().decode(keyContent);
            X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            PublicKey publicKey = kf.generatePublic(spec);

            // Verify key size
            if (publicKey.getAlgorithm().equals("RSA") && ((java.security.interfaces.RSAPublicKey) publicKey).getModulus().bitLength() != 2048) {
                return null;
            }

            // Prepare card data as JSON
            Gson gson = new Gson();
            String cardData = gson.toJson(new CardData(
                    fullName, cardNumber, expiryMonth, expiryYear, cvv,
                    billingAddress, billingCity, billingZip, billingState, billingCountry));
            byte[] cardDataBytes = cardData.getBytes("UTF-8");
            int dataSize = cardDataBytes.length;

            if (dataSize > 214) {
                // Generate AES key and IV
                byte[] aesKey = new byte[32];
                byte[] iv = new byte[16];
                new java.security.SecureRandom().nextBytes(aesKey);
                new java.security.SecureRandom().nextBytes(iv);

                // Encrypt data with AES-256-CBC
                Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                aesCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(aesKey, "AES"), new IvParameterSpec(iv));
                byte[] encryptedData = aesCipher.doFinal(cardDataBytes);

                // Encrypt AES key with RSA-OAEP
                Cipher rsaCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
                rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
                byte[] encryptedAesKey = rsaCipher.doFinal(aesKey);

                // Combine components
                String result = Base64.getEncoder().encodeToString(encryptedData) + "::" +
                               Base64.getEncoder().encodeToString(iv) + "::" +
                               Base64.getEncoder().encodeToString(encryptedAesKey);
                return Base64.getEncoder().encodeToString(result.getBytes("UTF-8"));
            } else {
                // Standard RSA-OAEP encryption
                Cipher rsaCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
                rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
                byte[] encryptedData = rsaCipher.doFinal(cardDataBytes);
                return Base64.getEncoder().encodeToString(encryptedData);
            }
        } catch (Exception e) {
            return null;
        }
    }

    // Helper class for JSON serialization
    private static class CardData {
        String full_name, card_number, expiry_month, expiry_year, cvv;
        String billing_address, billing_city, billing_zip, billing_state, billing_country;

        CardData(String fullName, String cardNumber, String expiryMonth, String expiryYear, String cvv,
                 String billingAddress, String billingCity, String billingZip, String billingState, String billingCountry) {
            this.full_name = fullName;
            this.card_number = cardNumber;
            this.expiry_month = expiryMonth;
            this.expiry_year = expiryYear;
            this.cvv = cvv;
            this.billing_address = billingAddress;
            this.billing_city = billingCity;
            this.billing_zip = billingZip;
            this.billing_state = billingState;
            this.billing_country = billingCountry;
        }
    }

    // Example usage
    /*
    public static void main(String[] args) {
        String result = encrypt(
                "kitegateway.public.key.pem",
                "Test User",
                "4111111111111111",
                "12",
                "25",
                "123",
                "123 Main St, Apt 4B",
                "Springfield",
                "62701",
                "IL",
                "US"
        );
        System.out.println(result != null ? result : "Encryption failed");
    }
    */
}
```

{% endtab %}
{% endtabs %}

#### 4. Set card\_cipher parameter

From the step above, the resultant string after encryption is what we need to set as the **`encrypted_card`** and include it in the [**`Post Collection Request`**](/receiving-money/make-payment) when making a [**`Card Collection Request`**](/receiving-money/card-payments)

{% tabs %}
{% tab title="Sample Request Body" %}

```javascript
{
  ...
  "encrypted_card": "***"
  ...
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
When the **`encrypted_card`** the parameter is specified in the collection request body, Kitegateway will know that you want to make a direct card payment.&#x20;

Since it's 3D processing, the response object will contain the bank authentication URL where you will redirect the customer to complete the payment.
{% endhint %}


# Crypto Payment

### Set Payment Method

When the payment transaction is to be completed using cryptocurrency, The **`payment_method`** field should be set to **`CRYPTO`** in the post request collection body. We expect you to provide a, **`redirect_url`** the customer will be navigated to when they complete or cancel the transaction.

{% tabs %}
{% tab title="Sample Request Body" %}

```javascript
{
  ...
  "method": "CRYPTO",
  "redirect_url": "https://your-redirect_url"
  ...
}
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}

#### redirect\_url

It must be secured by **SSL.** ie, it must start with **https\://**
{% endhint %}

### Payment Link in response

Once the payment has been initiated, the response body will contain the `payment_url` .&#x20;

{% tabs %}
{% tab title="Sample Response Body" %}

```javascript
{
  ...
  "payment_url": "https://kitegateway.com/v1/collections/payment/387282737839923773737",
  ...
}
```

{% endtab %}
{% endtabs %}

### Redirect customer

We expect your application to redirect the customer to that **`payment_url`** to complete the payment


# Merchant Redirect

### The structure

At our end, we append the redirect parameters to the URL that's set in the initial collection request by you. The final redirect URL would look like the following;

```http
https://redirect_url?id=&merchant_reference=&kitegateway_reference=&status=&message=&signature=
```

{% hint style="danger" %}

#### redirect\_url

It must be secured by **SSL.** ie, it must start with **https\://**
{% endhint %}

Description of the query parameters that we append

| Parameter              | Type   | Description                                                                                                                                                                                                                                                                                                                                                                                            |
| ---------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| id                     | string | The transaction ID of the transaction                                                                                                                                                                                                                                                                                                                                                                  |
| merchant\_reference    | string | Your generated merchant transaction id for the transaction                                                                                                                                                                                                                                                                                                                                             |
| kitegateway\_reference | string | The Kitegateway payment reference of the transaction                                                                                                                                                                                                                                                                                                                                                   |
| status                 | string | <p>The <a href="/appendix/transaction-status-codes">transaction status</a>. Values can be one of; </p><p><strong>PENDING -</strong> When a payment is in the queue for processing, <strong>CANCELLED -</strong> If a customer cancels a payment, </p><p><strong>FAILED</strong> - When a payment fails for some reason</p><p><strong>COMPLETED -</strong> When a payment is successfully completed</p> |
| message                | string | Information describing the status of the transaction                                                                                                                                                                                                                                                                                                                                                   |
| signature              | string | The RSA signature generated by **Kitegateway**. This can optionally be verified by the merchant to ensure that the redirect comes from **Kitegateway** before providing service to the customer                                                                                                                                                                                                        |

{% hint style="warning" %}
&#x20;1\. We strongly recommend you check for the availability of these parameters in the    URL and also confirm that the references correspond to the data available in your application.&#x20;

2\. Further we assert that you should verify the signature so that you are sure that the request is coming from our servers. This way the legitimacy of the redirect is affirmed.
{% endhint %}

### How to verify redirect signature (Optional)

This section describes the steps taken to verify the signature using sample query parameters. Assume that the redirect URL is as follows;&#x20;

```http
https://your.redirecturl?id=8828827777762662662662&merchant_reference=merc-19928288-282772&kitegateway_reference=PL4889KJSuSUUSH&status=COMPLETED&message=Transaction%20Completed%20Successfully&signature=c0K46co6bmQkoDW8XjEWQ7nBAteBo5
```

1. Form the string payload to be used in the signature verification. This is obtained by concatenating values of the redirect data in the format; `id:merchant_reference:kitegateway_reference:status:redirect_url` where redirect\_url is the value you specified for the **redirect\_url** parameter when making the initial collection request.
2. The string payload in our example would therefore be the following;

```bash
2888377377379926:MERC-6778J-KL8UN:PL377399-KTHHSH-888766:COMPLETED:https://your-redirecturl
```

3\. Download the public key as described [here](/receiving-money/direct-card-payment#2-downloading-public-key).

4\. Use the public key to verify the signature as described in the sample source code below

{% tabs %}
{% tab title="JavaScript" %}

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

function isSignatureValid() {
    const strPayload = "2888377377379926:MERC-6778J-KL8UN:PL377399-KTHHSH-888766:COMPLETED:https://your-redirecturl";
    const signature = "signature-from-query-params";
    const publicKeyFile = "path-to-file/kitegateway.public.key.pem";
    const publicKey = fs.readFileSync(publicKeyFile).toString().replace(/\\n/g, '\n');

    const verify = crypto.createVerify("SHA512");
    verify.write(strPayload);
    verify.end();

    // true or false
    return verify.verify(publicKey, signature, 'base64');
}
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
public function isSignatureValid() {
    $file = "path-to-file/kitegateway.public.key.pem";
    $keyContent = file_get_contents($file);
    $publicKey = openssl_get_publickey($keyContent);
    $strPayload = "2888377377379926:MERC-6778J-KL8UN:PL377399-KTHHSH-888766:COMPLETED:https://your-redirecturl";
    $signature = base64_decode("signature-from-query-params");

    // true or false
    return openssl_verify($strPayload, $signature, $publicKey, OPENSSL_ALGO_SHA512) == 1;
}

?>
```

{% endtab %}
{% endtabs %}


# Refund post request

Collection refunds might not go as planned as such you can request that the funds be returned to the customer. When the refund request is made, we reimburse the customer the exact or a fraction of the amount that was paid in the original transaction request. Each transaction indicates this via **`support_partial_refund`** which is sent when a payment request is made or via the webhook notification. if a fraction of the amount can be sent **`support_partial_refund`** will be **`true`**\
\
During the refund request processing, the funds are debited from your respective currency merchant account wallet.\
\
A notification about the status of the refund will be set to the set [`webhook URL`](/appendix/webhook) set under your merchant account API tokens.

{% hint style="danger" %}
Based on the provider, partial refunds may not be available in some scenarios
{% endhint %}

**Live**

```javascript
POST https://kitegateway.com/v1/collections/refund
```

**Sandbox**

```
POST  https://sandbox.kitegateway.com/v1/collections/refund
```

{% tabs %}
{% tab title="Headers" %}

#### Request

| Header            | Value                  | Required |
| ----------------- | ---------------------- | -------- |
| **Content-Type**  | **`application/json`** | YES      |
| **Accept**        | **`application/json`** | YES      |
| **Authorization** | **`JWT ***`**          | YES      |
| {% endtab %}      |                        |          |

{% tab title="Request" %}

#### Request

| Parameter Name         | Type    | Description                                                                                                                       | Required |
| ---------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- | -------- |
| kitegateway\_reference | string  | The Kitegateway reference of the transaction to refund. This is usually included in the API request responses or IPN's            | YES      |
| amount                 | integer | (Optional) Specify for a partial refund. The amount should be less or equal to the transaction amount in the previous transaction | NO       |
| {% endtab %}           |         |                                                                                                                                   |          |

{% tab title="Response" %}

<table data-header-hidden><thead><tr><th width="238">Parameter Name</th><th width="151">Type</th><th width="357">Description</th></tr></thead><tbody><tr><td>Parameter Name</td><td>Type</td><td>Description</td></tr><tr><td>id</td><td></td><td></td></tr><tr><td>kitegateway_reference</td><td>string</td><td>The Kitegateway reference of the transaction to refund. This is usually included in the API request responses or IPN's</td></tr><tr><td>transaction_amount</td><td>integer</td><td>The amount of money to refund</td></tr><tr><td>transaction_currency</td><td>string</td><td>The currency being refunded</td></tr><tr><td>transaction_fee</td><td>integer</td><td>Fee charged</td></tr><tr><td>total_debit</td><td>integer</td><td>Amount debited from wallet</td></tr><tr><td>payment_method</td><td>string</td><td>The payment method that was used during collection</td></tr><tr><td>merchant_reference</td><td>string</td><td>The reference provided by the merchant</td></tr><tr><td>collection_reference</td><td>string</td><td>The kitegateway collection reference that was made prior to this refund</td></tr><tr><td>transaction_status</td><td>string</td><td>One of either PENDING, COMPLETED</td></tr><tr><td></td><td></td><td></td></tr></tbody></table>
{% endtab %}
{% endtabs %}


# Generate PRN

The PRN API allows merchants to create unique payment references for customers. Integrate the API to generate secure, traceable PRNs with a simple request, specifying amount and customer details. The API returns a unique reference, enabling efficient transaction tracking. Streamline payment workflows and enhance user experience with reliable PRN generation for seamless merchant operations.

**Live**

```javascript
POST https://kitegateway.com/v1/collections/prn
```

**Sandbox**

```
POST  https://sandbox.kitegateway.com/v1/collections/prn
```

{% tabs %}
{% tab title="Headers" %}

#### Request

| Header            | Value                  | Required |
| ----------------- | ---------------------- | -------- |
| **Content-Type**  | **`application/json`** | YES      |
| **Accept**        | **`application/json`** | YES      |
| **Authorization** | **`JWT ***`**          | YES      |
| {% endtab %}      |                        |          |

{% tab title="Request" %}

#### Request

| Parameter Name      | Type    | Description                                         | Required |
| ------------------- | ------- | --------------------------------------------------- | -------- |
| merchant\_reference | string  | The Merchant reference of the transaction to track. | YES      |
| amount              | integer | The amount of money that should be transacted       | YES      |
| currency            | string  | The currency that should be used to transact        | YES      |
| narration           | string  | Description of what is being paid for               | YES      |
| {% endtab %}        |         |                                                     |          |

{% tab title="Response" %}

<table data-header-hidden><thead><tr><th width="238">Parameter Name</th><th width="151">Type</th><th width="357">Description</th></tr></thead><tbody><tr><td>Parameter Name</td><td>Type</td><td>Description</td></tr><tr><td>id</td><td></td><td></td></tr><tr><td>kitegateway_reference</td><td>string</td><td>The Kitegateway reference of the transaction to refund. This is usually included in the API request responses or IPN's</td></tr><tr><td>transaction_amount</td><td>integer</td><td>The amount of money to refund</td></tr><tr><td>transaction_currency</td><td>string</td><td>The currency being refunded</td></tr><tr><td>merchant_reference</td><td>string</td><td>The reference provided by the merchant</td></tr><tr><td>transaction_status</td><td>string</td><td>One of either PENDING, COMPLETED</td></tr><tr><td>transaction_type</td><td>string</td><td>One of either COLLECTION, DISBURSEMENT</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

You can also generate the PRN by Navigation to business account and clicking Generate PRN

<figure><img src="https://1651461756-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1osqKR2tRm8OtrtXF4OJ%2Fuploads%2Fo2RIin8sLwm0N8l0rWdZ%2FScreenshot%202025-09-23%20at%2015.59.43.png?alt=media&amp;token=368d4406-a2df-4a43-a4a1-f2b0085b100b" alt=""><figcaption></figcaption></figure>


# Pay PRN

Merchants can process payments seamlessly via <https://kitegateway.com/payments.html> using either their unique Merchant ID or a generated [Payment Reference Number (PRN)](/prn/generate-prn). This flexible system streamlines transaction management enhances tracking ensures reliability


# Wallet Balances

### All wallet Balances

Shows the amount of money remaining in the merchant account wallets

**Live**

```javascript
GET https://kitegateway.com/v1/data/wallets/balances
```

**Sandbox**

```
GET https://sandbox.kitegateway.com/v1/data/wallets/balances
```

{% tabs %}
{% tab title="Request Headers" %}

#### Request Headers

| Header        | Value                  | Required |
| ------------- | ---------------------- | -------- |
| Content-Type  | **`application/json`** | YES      |
| Accept        | **`application/json`** | YES      |
| Authorization | **`JWT ***`**          | YES      |
| {% endtab %}  |                        |          |

{% tab title="Response" %}

#### Request Body

| Parameter Name | Type   | Description         |
| -------------- | ------ | ------------------- |
| currency       | string | The wallet currency |
| balance        | double | The wallet balance  |
| {% endtab %}   |        |                     |

{% tab title="Sample Response" %}

```javascript
{
    "code": 200,
    "status": "success",
    "message": "Request completed successfully.",
    "data": [
        {
            "currency": "UGX",
            "balance": 1250000
        },
        {
            "currency": "USD",
            "balance": 7213
        }
    ]
}
```

{% endtab %}
{% endtabs %}

### Single wallet balance

Shows the amount of money remaining in a specific wallet currency

**Live**

```javascript
GET https://kitegateway.com/v1/data/wallets/:currency/balance
```

**Sandbox**

```
GET https://sandbox.kitegateway.com/v1/data/wallets/:currency/balance
```

{% tabs %}
{% tab title="Request Headers" %}

#### Request Headers

| Header        | Value                  | Required |
| ------------- | ---------------------- | -------- |
| Content-Type  | **`application/json`** | YES      |
| Accept        | **`application/json`** | YES      |
| Authorization | **`JWT ***`**          | YES      |
| {% endtab %}  |                        |          |

{% tab title="Response" %}

#### Request Body

| Parameter Name | Type   | Description         |
| -------------- | ------ | ------------------- |
| currency       | string | The wallet currency |
| balance        | double | The wallet balance  |
| {% endtab %}   |        |                     |

{% tab title="Sample Response" %}

```javascript
{
    "code": 200,
    "status": "success",
    "message": "Request completed successfully.",
    "data": {
            "currency": "UGX",
            "balance": 1250000
        }
}
```

{% endtab %}
{% endtabs %}


# Payment Methods

Below are supported payment methods on our platform

#### MOBILE\_MONEY

To collect or disburse funds using mobile money, you need to set the **payment\_method** parameter in the request body as **`MOBILE_MONEY`**&#x20;

{% hint style="info" %}
Mobile money payments require the customer's mobile phone number specified in th&#x65;**`phone_number`**&#x66;ield put in the international format, including its country code e.g **`256777111222`**
{% endhint %}

{% tabs %}
{% tab title="Sample Request Body" %}

```javascript
{
  ...
  "payment_method": "MOBILE_MONEY"
  "phone_number": "256777111222",
  ...
}
```

{% endtab %}
{% endtabs %}

### CARD

Used to collected card payments by specifying th&#x65;**`CARD`** value in the **payment\_method** field&#x20;

{% hint style="danger" %}
The card method supports only collections at the moment
{% endhint %}

{% tabs %}
{% tab title="Sample Request Body" %}

```javascript
{
  ...
  "payment_method": "CARD"
  ...
}
```

{% endtab %}
{% endtabs %}

Refunds are supported for cards. Go [here](/refunds/refund-post-request) to learn about them

In case you do provide the customer's card details to process the card transactions, we will return a **`payment_url`** where the customer will complete their transaction.&#x20;

When the customer is redirected to the **`payment_url`**, they will securely provide their card details and their transaction will be processed. We do not store the customers' card details but the masked version. The masked version is useful during queries.

### CRYPTO

Set the **payment\_method** parameter in the request body as **`CRYPTO`** to collect funds using crypto \
\
Funds collected will be stored in the base currency of the **provider** used to make the payment. e.g setting the **provider=btc\_usd** means we will collect the payment as **BTC** store it as **USD**. Your USD wallet will be credited at the end of the transaction and we will settle you in USD.&#x20;

{% tabs %}
{% tab title="Sample Request Body" %}

```javascript
{
  ...
  "method": "CRYPTO"
  ...
}
```

{% endtab %}
{% endtabs %}

Completing this transaction redirecting the customer to the **`payment_url`** to complete the payment.


# Transaction status codes

| Status    | Reason                                               |
| --------- | ---------------------------------------------------- |
| PENDING   | A payment that is waiting to be processed            |
| FAILED    | A payment that has failed                            |
| COMPLETED | A payment that was processed successfully            |
| CANCELLED | A payment that was canceled by the merchant customer |


# Webhook

1. All `collection` and `disbursement` transactions notification updates will be sent as **`POST`** to the URL set as the `webhook url` under your merchant account API tokens.<br>
2. Only, `https` URLs can be set or notified.<br>
3. You will need to acknowledge receipt of the notification by responding with the HTTP status code **`200`**. Otherwise, we might keep calling your webhook URL at an interval of 10 minutes for 2 days.<br>
4. To ensure that the notification data sent to your `webhook URL` comes from our servers, set a `webhook hash` under the `Api Tokens`.<br>
5. We will include a header called, `webhook-hash` in the request sent to the `webhook URL`. e.g **webhook-hash: WH-\*\*\*"**

{% hint style="info" %}
You should verify the `webhook-hash` we sent matches what was set under your merchant account before giving service to your customer
{% endhint %}

#### **Responding to webhooks**

We will stop sending notification to your webhook URL if it responds with the following “HTTP status codes” below;

| Code  | Description             |
| ----- | ----------------------- |
| `200` | - OK                    |
| `400` | - Bad Request           |
| `401` | - Unauthorised          |
| `403` | - Forbidden             |
| `422` | - Unprocessable entity. |

**Rejecting webhook notification**

In a scenario where the transaction cannot be processed respond with HTTP codes below;

| Code  | Description                                                                                                                                      |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400` | <p>- Bad Request.<br>- e.g when there’s a missing parameter</p>                                                                                  |
| `422` | <p>- Unprocessable entity.<br>- e.g when the request is fine but you cannot complete it because the amount does not match what you expected.</p> |

{% hint style="danger" %}
**KEYNOTE**

Always verify the, **`amount`** to make sure it matches what is meant to be **`paid`** before giving service to the customer.
{% endhint %}

```javascript
{
    "id": "383737927636356536773773",
    "request_amount": 0.4,
    "request_currency": "USD",
    "account_amount": 1462.53,
    "account_currency": "UGX",
    "transaction_fee": 42.23,
    "total_credit": 1420.30,
    "customer_charged": false,
    "provider": "mtn_ug",
    "merchant_reference": "88736jh-kkas87-mmn736-9n873ms-6636h",
    "kitegateway_reference": "PL-KMSSD-30000",
    "transaction_status": "COMPLETED",
    "transaction_type": "collection",
    "message": "Transaction Completed Successfully",
    "account_number": "Optional - 256777111222",
    "account_name": "Optional",
    "institution_name": "Optional - MTN Mobile Money Uganda"
}
```


# Webhook Trigger

For some reason you might end up not receiving notification from us as such you can trigger the webhook to re-send the latest payment update

**Live**

```javascript
GET https://kitegateway.com/v1/transactions/send-callback/{kitegateway_reference}
```

**Sandbox**

```
GET https://sandbox.kitegateway.com/v1/transactions/send-callback/{kitegateway_reference}
```

{% hint style="warning" %}
This is a secure end point that must be called using the auth token
{% endhint %}

| Parameter              | Type   | Description                                                                   | Required |
| ---------------------- | ------ | ----------------------------------------------------------------------------- | -------- |
| kitegateway\_reference | string | Unique transaction reference that was sent when the transaction was initiated | YES      |


# Signature Verification

In addition to the header,`Webhook-Hash,`when we are sending notification back to the `webhook URL` we provide`Kitegateway-Signature`  so that merchants trust that the callbacks originate from the Kitegateway servers.&#x20;

### **Signature verification can be done with the following procedure;**

1. Retrieve the value of the `Kitegateway-Signature` header.<br>
2. Form the string payload to be used in signature verification. This is obtained by concatenating values of the notification data in the format that follows\
   \
   `id:merchant_reference:kitegateway_reference:transaction_status:webhook_url`\
   \
   where **`webhook_url`** is the full URL as added to your merchant account API token settings.

Assume sample notification data below;

```javascript
{
    ...
    "id": "383737927636356536773773",
    "merchant_reference": "88736jh-kkas87-mmn736-9n873ms-6636h",
    "kitegateway_reference": "PL-KMSSD-30000",
    "transaction_status": "COMPLETED",
    ...
}
```

and that the callback URL is\
`https://some-callback-url`\
\
The string payload would therefore be

`383737927636356536773773:88736jh-kkas87-mmn736-9n873ms-6636h:PL-KMSSD-30000:COMPLETED:https://some-callback-url`<br>

1. Obtain the Kitegateway public key as explained [here](/dashboard/api-credentials#aip_key) and store it as a file.<br>
2. Use the Kitegateway public key to verify the signature as described in the example source codes below;

#### Signature Verification Code Example <a href="#signature-verification-code-samples" id="signature-verification-code-samples"></a>

{% tabs %}
{% tab title="NodeJS" %}

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

function isSignatureValid() {
    const strPayload = "383737927636356536773773:88736jh-kkas87-mmn736-9n873ms-6636h:PL-KMSSD-30000:COMPLETED:https://some-callback-url";
    const signature = "value-of-kitegateway-signature";
    const publicKeyFile = "path-to-file/kitegateway.public.key.pem";
    const publicKey = fs.readFileSync(publicKeyFile).toString().replace(/\\n/g, '\n');

    const verify = crypto.createVerify("SHA512");
    verify.write(strPayload);
    verify.end();

    /*true or false*/
    return verify.verify(publicKey, signature, 'base64');
}
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

public function isSignatureValid() {
    $file = "path-to-file/kitegateway.public.key.pem";
    $keyContent = file_get_contents($file);
    $publicKey = openssl_get_publickey($keyContent);
    $strPayload = "383737927636356536773773:88736jh-kkas87-mmn736-9n873ms-6636h:PL-KMSSD-30000:COMPLETED:https://some-callback-url";
    $signature = base64_decode("value-of-kitegateway-signature");

    /*true or false*/
    return openssl_verify($strPayload, $signature, $publicKey, OPENSSL_ALGO_SHA512) == 1;
}

?>
```

{% endtab %}
{% endtabs %}


# Wordpress Woocomerce Plugin

This plugin allows business to be able to collect money through woocommerce

{% hint style="danger" %}
When generating API KEYS to use in this plugin. It is important to set the webook URL to <https://YOUR_DOMAINNAME.COM/?wc-api=kitegateway-webhook> so that when payment status changes at kitegateway servers your application is able to get the updates.
{% endhint %}

#### Download

You can download this plugin from the wordpress store. You can check out the source code here: <https://github.com/kitegateway/woocommerce> you can download the woocommerce version here <https://github.com/kitegateway/woocommerce/archive/refs/tags/v1.0.1.zip> install to your website directly

Once you have installed the plugin you should be able to set it in the woocommerce settings

<figure><img src="https://1651461756-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1osqKR2tRm8OtrtXF4OJ%2Fuploads%2Fv41dFLZgcLHANebzD9oy%2Fscreenshot-1.png?alt=media&amp;token=2d905ca7-089d-40b3-9a68-e52a197bc893" alt=""><figcaption></figcaption></figure>

You should fill in appropriate details but the most important are the api tokens

<figure><img src="https://1651461756-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1osqKR2tRm8OtrtXF4OJ%2Fuploads%2FZOWdfN20oZ88R9XtM07P%2Fscreenshot-2.png?alt=media&amp;token=d896b937-58b1-4ce5-bc0e-a659bf68c6e1" alt=""><figcaption></figcaption></figure>

The following page will appear in the checkout

<figure><img src="https://1651461756-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1osqKR2tRm8OtrtXF4OJ%2Fuploads%2FsstyKMrgsok12nhT25rt%2Fscreenshot-3.png?alt=media&amp;token=feea7e6c-f176-496a-87b7-dcca8b1a2fec" alt=""><figcaption></figcaption></figure>


