# QRIS API Integration

This section is intended for QRIS partner to integrate with Indodana.

## Preparation

To get started, please make sure that you have the `MERCHANT_API_KEY` and `MERCHANT_SECRET_KEY` read&#x79;**.**

You also need to make sure that you have access to our staging & production API URLs. The `staging` API URL is located in <https://stg-k-api.indodanafinance.com>. The `production` API URL is located in <https://api.indodanafinance.co.id>.

{% hint style="info" %}
Here are preparation list you might required during this integration:

* [ ] [Merchant Account](https://dev.indodana.id/indodana-paylater/go-live-preparation/developer-help)
* [ ] [Merchant API Key](https://dev.indodana.id/indodana-paylater/go-live-preparation/developer-help)
* [ ] Indodana Staging URL
* [ ] Indodana Production URL
* [ ] [Whitelist Indodana IP](https://dev.indodana.id/indodana-paylater/go-live-preparation/whitelist-ip)
  {% endhint %}

## Authorizing Your Request

The important thing that you need to know when you want to perform a direct integration is the API authentication. By default, all of Indodana Merchant API endpoints are secured and you will need to authenticate your request. To be able to execute the API successfully, you will need to authorize yourself by presenting a valid `Authorization` header in your HTTP request.&#x20;

To generate the `Authorization` header, please refer to the following snippets of code.

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

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

const apiKey = '<MERCHANT_API_KEY>'
const secret = '<MERCHANT_SECRET_KEY>'
const nonce = Math.floor(Date.now() / 1000);

const hmac = crypto.createHmac('sha256', secret);
  
var generateAuthorizationHeader = function () {
  const content = `${apiKey}:${nonce}`;
  
  var signature = null
  var authorization = ''
  hmac.on('readable', () => {
    const data = hmac.read();
    if (data) {
      signature = data.toString('hex')
      authorization = `Bearer ${apiKey}:${nonce}:${signature}`
    }
  });
  hmac.write(content);
  hmac.end();
  
  console.log('HTTP Authorization Header')
  console.log('Authorization: ' + authorization)
  
  return authorization
}
generateAuthorizationHeader()
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
  $apiKey = '<MERCHANT_API_KEY>';
  $secret = '<MERCHANT_SECRET_KEY>';

  function generateAuthorizationHeader() {
    $nonce = time();

    $string = $apiKey.':'.$nonce;
    $signature = hash_hmac('sha256', $string, $secret);

    echo 'HTTP Authorization Header'.PHP_EOL;
    echo "Authorization: Bearer {$apiKey}:{$nonce}:{$signature}".PHP_EOL;
    
    return "Bearer {$apiKey}:{$nonce}:{$signature}";
  }
?>
```

{% endtab %}
{% endtabs %}

As you can see, the content of `Authorization` header is generated by creating a `sha256` hash of `apiKey:nonce`. The `sha256` hash algorithm should take the `MERCHANT_SECRET_KEY` as the secret key. The example result of the above snippets when you try to ran the code should be as follow

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

```
HTTP Authorization Header
Authorization: Bearer sudahlahbossque:1562328997:091e834ec466df5e31b87077134e9d44ac428f515b78055673a2cfa65dbd5956
```

{% endtab %}
{% endtabs %}

## \[Webview Flow] Purchase Transaction Checkout <a href="#purchase-transaction-checkout" id="purchase-transaction-checkout"></a>

<mark style="color:green;">`POST`</mark> `https://{baseUrl}/v3/checkout_url`

This checkout API v3 enables QuickPay integration. You need to pass valid `x-user-token` on the header so user can enjoy the easy & fast checkout experience.\
\
Don't worry if you don't have the Indodana QuickPay user token for current checkout user in the first place, our checkout page already handle the flow and **you need to store the token every time Indodana sends the token via callback to your system and use this token for subsequent transaction**.

`*` means the parameter is required

#### Headers

| Name                                            | Type   | Description                                                                                                     |
| ----------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------- |
| X-User-Token<mark style="color:red;">\*</mark>  | string | Indodana QuickPay user token. You can pass `null` if user account not connected yet in your platform.           |
| Authorization<mark style="color:red;">\*</mark> | string | <p>The generated authentication signature with format<br><code>Bearer {api\_key}:{nonce}:{signature}</code></p> |

#### Request Body

| Name                                                      | Type   | Description                                                                                                                                                                          |
| --------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| merchantUserKey<mark style="color:red;">\*</mark>         | string | User identifier in merchant's platform. Indodana will send the Indodana QuickPay user token alongside this information so you know the owner of the token.                           |
| transactionDetails<mark style="color:red;">\*</mark>      | object | ***\<Transaction>*** - Detail of the transaction.                                                                                                                                    |
| customerDetails<mark style="color:red;">\*</mark>         | object | ***\<Customer>*****&#x20;-** Detail of the customer.                                                                                                                                 |
| sellers<mark style="color:red;">\*</mark>                 | array  | Array of ***\<Seller>*****&#x20;-** Detail of the sellers involved in the transaction. May contain more than 1 seller.                                                               |
| billingAddress<mark style="color:red;">\*</mark>          | object | ***\<Address>*****&#x20;-** Billing address of the customer for the transaction.                                                                                                     |
| shippingAddress<mark style="color:red;">\*</mark>         | string | (Required only for goods, for service / digital product is not required) <***Address>*****&#x20;-** Shipping address of the customer for the transaction.                            |
| paymentType<mark style="color:red;">\*</mark>             | string | (Required for active Indodana QuickPay user token) Installment options / payment terms chosen by the customer. ***Possible values:*** `30_days`, `3_months`, `6_months`, `12_months` |
| approvedNotificationUrl<mark style="color:red;">\*</mark> | string | The URL that will be called by Indodana when the transaction is approved and successful.                                                                                             |
| cancellationRedirectUrl<mark style="color:red;">\*</mark> | string | The URL for user to be redirected if transaction's cancelled in Indodana's checkout page.                                                                                            |
| backToStoreUrl<mark style="color:red;">\*</mark>          | string | The URL for user to be redirected after completes the checkout process.                                                                                                              |
| expirationAt                                              | string | Timestamp when the transaction expired on merchant's platform.                                                                                                                       |
| metadata                                                  | object | Key value pair contains additional information of transaction                                                                                                                        |

{% tabs %}
{% tab title="API Request w/o Tip" %}

```javascript
{
    "merchantUserKey": "<MERCHANT-USER-KEY>",
    "transactionDetails": {
      "merchantOrderId": "<MERCHANT-ORDER-ID>",
      "amount": 45000,
      "items": [
        {
          "id": "<MERCHANT-ITEM-ID>",
          "name": "QRIS",
          "category": "<ITEM-CATEGORY>",
          "price": 45000,
          "url": "http://merchant.com/qris",
          "imageUrl": "http://merchant.com/qris/cover.jpg",
          "type": "offline-store",
          "quantity": 1,
          "parentType": "SELLER",
          "parentId": "<MERCHANT-SELLER-ID>"
        }
      ]
    },
    "customerDetails": {
      "firstName": "First",
      "lastName": "Last",
      "email": "first.last@gmail.com",
      "phone": "081212345678"
    },
    "sellers": [
      {
        "id": "<MERCHANT-SELLER-ID>",
        "name": "Penjual iPhone",
        "url": "https://merchant.com/shop",
        "sellerIdNumber": "<MERCHANT-SELLER-ID-NUMBER>",
        "email": "seller@merchant.com",
        "officialSeller": false,
        "address": {
          "firstName": "Merchant",
          "lastName": "Seller",
          "address": "Kelapa Gading",
          "city": "Jakarta Utara",
          "postalCode": "11240",
          "phone": "081812345678",
          "countryCode": "IDN"
        }
      }
    ],
    "billingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "shippingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "metadata": {
      "location": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "scanQrisLocation": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "qrisContent": "<QRIS-CONTENT>",
      "transactionPurpose": "CONSUMPTIVE",
      "mpan": "<QRIS-MPAN>"
    },
    "paymentType": "3_months",
    "approvedNotificationUrl": "https://payment-notification.merchant.com/transaction-approval-handler",
    "cancellationRedirectUrl": "http://merchant.com/phone/iphone-6s",
    "backToStoreUrl": "http://merchant.com/phone/iphone-6s",
    "expirationAt": "2019-12-31T18:00:00+07:00"
}
```

{% endtab %}

{% tab title="API Request w/ Tip" %}

```javascript
{
    "merchantUserKey": "<MERCHANT-USER-KEY>",
    "transactionDetails": {
      "merchantOrderId": "<MERCHANT-ORDER-ID>",
      "amount": 50000,
      "items": [
        {
          "id": "<MERCHANT-ITEM-ID>",
          "name": "QRIS",
          "category": "<ITEM-CATEGORY>",
          "price": 45000,
          "url": "http://merchant.com/qris",
          "imageUrl": "http://merchant.com/qris/cover.jpg",
          "type": "offline-store",
          "quantity": 1,
          "parentType": "SELLER",
          "parentId": "<MERCHANT-SELLER-ID>"
        }
      ]
    },
    "customerDetails": {
      "firstName": "First",
      "lastName": "Last",
      "email": "first.last@gmail.com",
      "phone": "081212345678"
    },
    "sellers": [
      {
        "id": "<MERCHANT-SELLER-ID>",
        "name": "Penjual iPhone",
        "url": "https://merchant.com/shop",
        "sellerIdNumber": "<MERCHANT-SELLER-ID-NUMBER>",
        "email": "seller@merchant.com",
        "officialSeller": false,
        "address": {
          "firstName": "Merchant",
          "lastName": "Seller",
          "address": "Kelapa Gading",
          "city": "Jakarta Utara",
          "postalCode": "11240",
          "phone": "081812345678",
          "countryCode": "IDN"
        }
      }
    ],
    "billingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "shippingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "metadata": {
      "location": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "scanQrisLocation": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "qrisContent": "<QRIS-CONTENT>",
      "transactionPurpose": "CONSUMPTIVE",
      "tipAmount": 5000.00,
      "mpan": "<QRIS-MPAN>"
    },
    "paymentType": "3_months",
    "approvedNotificationUrl": "https://payment-notification.merchant.com/transaction-approval-handler",
    "cancellationRedirectUrl": "http://merchant.com/phone/iphone-6s",
    "backToStoreUrl": "http://merchant.com/phone/iphone-6s",
    "expirationAt": "2019-12-31T18:00:00+07:00"
}
```

{% endtab %}

{% tab title="200 Checkout successful with QuickPay" %}

```
{
  "status": "OK",
  "redirectUrl": "https://quickpay.indodanafinance.co.id/product-installment/quickpay?purchaseTransactionId=aa5023a7-8803-11eb-9b88-7947f72d641d&pid=wat-wat&c=checkout&utm_source=wat-wat&utm_campaign=wat-wat&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwdXJjaGFzZVRyYW5zYWN0aW9uSWQiOiJhYTUwMjNhNy04ODAzLTExZWItOWI4OC03OTQ3ZjcyZDY0MWQiLCJ1c2VySWQiOiI1ZjUwMDBkMS1mM2NlLTQ4NDgtYWNiNS0xZmM5YzZkZjU2ZTAiLCJpc3MiOiJJTkRPREFOQSIsInNjb3BlIjoiUVVJQ0tQQVkiLCJpYXQiOjE2MTYwODM0ODgsImV4cCI6MTYxNjA4NTI4OH0.tOEOdk44iMxCO8quk2_mvcc4A38oZL3iE0Kdh_zkCmY",
  "transactionId": "aa5023a7-8803-11eb-9b88-7947f72d641d"
}
```

{% endtab %}

{% tab title="Error Response" %}

```
{
  "status": "ERROR",
  "error": {
    "kind": "GenericValidationError"
    "message": "<Object>"
  }
}
```

{% endtab %}
{% endtabs %}

#### Object Type References

For object specification of **Transaction**, **Customer**, **Seller,** **Address**, and **Metadata** can refer to this [API reference](https://dev.indodana.id/indodana-paylater/api-reference/api-reference#object-type-references).

## \[Jump App Flow] Generate OTT (One Time Token) <a href="#purchase-transaction-checkout" id="purchase-transaction-checkout"></a>

<mark style="color:green;">`POST`</mark> `https://{baseUrl}/v1/generate_ott`

`*` means the parameter is required

#### Headers

| Name                                            | Type   | Description                                                                                                     |
| ----------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------- |
| X-User-Token<mark style="color:red;">\*</mark>  | string | Indodana QuickPay user token                                                                                    |
| Authorization<mark style="color:red;">\*</mark> | string | <p>The generated authentication signature with format<br><code>Bearer {api\_key}:{nonce}:{signature}</code></p> |

#### Request Body

| Name                                              | Type   | Description                                                                                                                                                |
| ------------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| merchantUserKey<mark style="color:red;">\*</mark> | string | User identifier in merchant's platform. Indodana will send the Indodana QuickPay user token alongside this information so you know the owner of the token. |

{% tabs %}
{% tab title="200 Successful" %}

```
{
  "status": "OK",
  "oneTimeToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiQ0xJRU5UX0tFWV8xIiwiZXhwIjoxNzIxOTc0NDg1fQ.HLkOoz61WkHP9SlB5Sy4e8aF19vyYa13Pm_Gn4mwnwA",
  "expiresInMs": "300000"
}
```

{% endtab %}

{% tab title="Non 200 Error" %}

```
{
  "status": "ERROR",
  "error": {
    "kind": "GenericValidationError"
    "message": "<Object>"
  }
}
```

{% endtab %}
{% endtabs %}

## \[Jump App Flow] Purchase Transaction Checkout with OTT <a href="#purchase-transaction-checkout" id="purchase-transaction-checkout"></a>

<mark style="color:green;">`POST`</mark> `https://{baseUrl}/v1/qris/direct_checkout`

`*` means the parameter is required

#### Headers

| Name                                               | Type   | Description                                                                                                     |
| -------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------- |
| X-User-Token<mark style="color:red;">\*</mark>     | string | Indodana QuickPay user token.                                                                                   |
| Authorization<mark style="color:red;">\*</mark>    | string | <p>The generated authentication signature with format<br><code>Bearer {api\_key}:{nonce}:{signature}</code></p> |
| X-One-Time-Token<mark style="color:red;">\*</mark> | string | One time token resulted from Generate OTT API                                                                   |

#### Request Body

| Name                                                      | Type   | Description                                                                                                                                                                          |
| --------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| merchantUserKey<mark style="color:red;">\*</mark>         | string | User identifier in merchant's platform. Indodana will send the Indodana QuickPay user token alongside this information so you know the owner of the token.                           |
| transactionDetails<mark style="color:red;">\*</mark>      | object | ***\<Transaction>*** - Detail of the transaction.                                                                                                                                    |
| customerDetails<mark style="color:red;">\*</mark>         | object | ***\<Customer>*****&#x20;-** Detail of the customer.                                                                                                                                 |
| sellers<mark style="color:red;">\*</mark>                 | array  | Array of ***\<Seller>*****&#x20;-** Detail of the sellers involved in the transaction. May contain more than 1 seller.                                                               |
| billingAddress<mark style="color:red;">\*</mark>          | object | ***\<Address>*****&#x20;-** Billing address of the customer for the transaction.                                                                                                     |
| shippingAddress<mark style="color:red;">\*</mark>         | string | (Required only for goods, for service / digital product is not required) <***Address>*****&#x20;-** Shipping address of the customer for the transaction.                            |
| paymentType<mark style="color:red;">\*</mark>             | string | (Required for active Indodana QuickPay user token) Installment options / payment terms chosen by the customer. ***Possible values:*** `30_days`, `3_months`, `6_months`, `12_months` |
| approvedNotificationUrl<mark style="color:red;">\*</mark> | string | The URL that will be called by Indodana when the transaction is approved and successful.                                                                                             |
| cancellationRedirectUrl<mark style="color:red;">\*</mark> | string | The URL for user to be redirected if transaction's cancelled in Indodana's checkout page.                                                                                            |
| backToStoreUrl<mark style="color:red;">\*</mark>          | string | The URL for user to be redirected after completes the checkout process.                                                                                                              |
| expirationAt                                              | string | Timestamp when the transaction expired on merchant's platform.                                                                                                                       |
| metadata                                                  | object | Key value pair contains additional information of transaction                                                                                                                        |

{% tabs %}
{% tab title="API Request w/o Tip" %}

```javascript
{
    "merchantUserKey": "<MERCHANT-USER-KEY>",
    "transactionDetails": {
      "merchantOrderId": "<MERCHANT-ORDER-ID>",
      "amount": 45000,
      "items": [
        {
          "id": "<MERCHANT-ITEM-ID>",
          "name": "QRIS",
          "category": "<ITEM-CATEGORY>",
          "price": 45000,
          "url": "http://merchant.com/qris",
          "imageUrl": "http://merchant.com/qris/cover.jpg",
          "type": "offline-store",
          "quantity": 1,
          "parentType": "SELLER",
          "parentId": "<MERCHANT-SELLER-ID>"
        }
      ]
    },
    "customerDetails": {
      "firstName": "First",
      "lastName": "Last",
      "email": "first.last@gmail.com",
      "phone": "081212345678"
    },
    "sellers": [
      {
        "id": "<MERCHANT-SELLER-ID>",
        "name": "Penjual iPhone",
        "url": "https://merchant.com/shop",
        "sellerIdNumber": "<MERCHANT-SELLER-ID-NUMBER>",
        "email": "seller@merchant.com",
        "officialSeller": false,
        "address": {
          "firstName": "Merchant",
          "lastName": "Seller",
          "address": "Kelapa Gading",
          "city": "Jakarta Utara",
          "postalCode": "11240",
          "phone": "081812345678",
          "countryCode": "IDN"
        }
      }
    ],
    "billingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "shippingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "metadata": {
      "location": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "scanQrisLocation": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "qrisContent": "<QRIS-CONTENT>",
      "transactionPurpose": "CONSUMPTIVE",
      "mpan": "<QRIS-MPAN>"
    },
    "paymentType": "3_months",
    "approvedNotificationUrl": "https://payment-notification.merchant.com/transaction-approval-handler",
    "cancellationRedirectUrl": "http://merchant.com/phone/iphone-6s",
    "backToStoreUrl": "http://merchant.com/phone/iphone-6s",
    "expirationAt": "2019-12-31T18:00:00+07:00"
}
```

{% endtab %}

{% tab title="API Request w/ Tip" %}

```javascript
{
    "merchantUserKey": "<MERCHANT-USER-KEY>",
    "transactionDetails": {
      "merchantOrderId": "<MERCHANT-ORDER-ID>",
      "amount": 50000,
      "items": [
        {
          "id": "<MERCHANT-ITEM-ID>",
          "name": "QRIS",
          "category": "<ITEM-CATEGORY>",
          "price": 45000,
          "url": "http://merchant.com/qris",
          "imageUrl": "http://merchant.com/qris/cover.jpg",
          "type": "offline-store",
          "quantity": 1,
          "parentType": "SELLER",
          "parentId": "<MERCHANT-SELLER-ID>"
        }
      ]
    },
    "customerDetails": {
      "firstName": "First",
      "lastName": "Last",
      "email": "first.last@gmail.com",
      "phone": "081212345678"
    },
    "sellers": [
      {
        "id": "<MERCHANT-SELLER-ID>",
        "name": "Penjual iPhone",
        "url": "https://merchant.com/shop",
        "sellerIdNumber": "<MERCHANT-SELLER-ID-NUMBER>",
        "email": "seller@merchant.com",
        "officialSeller": false,
        "address": {
          "firstName": "Merchant",
          "lastName": "Seller",
          "address": "Kelapa Gading",
          "city": "Jakarta Utara",
          "postalCode": "11240",
          "phone": "081812345678",
          "countryCode": "IDN"
        }
      }
    ],
    "billingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "shippingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "metadata": {
      "location": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "scanQrisLocation": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "qrisContent": "<QRIS-CONTENT>",
      "transactionPurpose": "CONSUMPTIVE",
      "tipAmount": 5000.00,
      "mpan": "<QRIS-MPAN>"
    },
    "paymentType": "3_months",
    "approvedNotificationUrl": "https://payment-notification.merchant.com/transaction-approval-handler",
    "cancellationRedirectUrl": "http://merchant.com/phone/iphone-6s",
    "backToStoreUrl": "http://merchant.com/phone/iphone-6s",
    "expirationAt": "2019-12-31T18:00:00+07:00"
}
```

{% endtab %}

{% tab title="200 Checkout successful with QuickPay" %}

```
{
  "status": "OK",
  "transactionId": "aa5023a7-8803-11eb-9b88-7947f72d641d"
}
```

{% endtab %}

{% tab title="Error Response" %}

```
{
  "status": "ERROR",
  "error": {
    "kind": "GenericValidationError"
    "message": "<Object>"
  }
}
```

{% endtab %}
{% endtabs %}

#### Object Type References

For object specification of **Transaction**, **Customer**, **Seller,** **Address**, and **Metadata** can refer to this [API reference](https://dev.indodana.id/indodana-paylater/api-reference/api-reference#object-type-references).

## \[Jump App Flow] Get Transaction Agreement HTML <a href="#purchase-transaction-checkout" id="purchase-transaction-checkout"></a>

<mark style="color:green;">`POST`</mark> `https://{baseUrl}/v1/qris/generate_agreement`

`*` means the parameter is required

#### Headers

| Name                                            | Type   | Description                                                                                                     |
| ----------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------- |
| X-User-Token<mark style="color:red;">\*</mark>  | string | Indodana QuickPay user token.                                                                                   |
| Authorization<mark style="color:red;">\*</mark> | string | <p>The generated authentication signature with format<br><code>Bearer {api\_key}:{nonce}:{signature}</code></p> |

#### Request Body

| Name                                                      | Type   | Description                                                                                                                                                                          |
| --------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| merchantUserKey<mark style="color:red;">\*</mark>         | string | User identifier in merchant's platform. Indodana will send the Indodana QuickPay user token alongside this information so you know the owner of the token.                           |
| transactionDetails<mark style="color:red;">\*</mark>      | object | ***\<Transaction>*** - Detail of the transaction.                                                                                                                                    |
| customerDetails<mark style="color:red;">\*</mark>         | object | ***\<Customer>*****&#x20;-** Detail of the customer.                                                                                                                                 |
| sellers<mark style="color:red;">\*</mark>                 | array  | Array of ***\<Seller>*****&#x20;-** Detail of the sellers involved in the transaction. May contain more than 1 seller.                                                               |
| billingAddress<mark style="color:red;">\*</mark>          | object | ***\<Address>*****&#x20;-** Billing address of the customer for the transaction.                                                                                                     |
| shippingAddress<mark style="color:red;">\*</mark>         | string | (Required only for goods, for service / digital product is not required) <***Address>*****&#x20;-** Shipping address of the customer for the transaction.                            |
| paymentType<mark style="color:red;">\*</mark>             | string | (Required for active Indodana QuickPay user token) Installment options / payment terms chosen by the customer. ***Possible values:*** `30_days`, `3_months`, `6_months`, `12_months` |
| approvedNotificationUrl<mark style="color:red;">\*</mark> | string | The URL that will be called by Indodana when the transaction is approved and successful.                                                                                             |
| cancellationRedirectUrl<mark style="color:red;">\*</mark> | string | The URL for user to be redirected if transaction's cancelled in Indodana's checkout page.                                                                                            |
| backToStoreUrl<mark style="color:red;">\*</mark>          | string | The URL for user to be redirected after completes the checkout process.                                                                                                              |
| expirationAt                                              | string | Timestamp when the transaction expired on merchant's platform.                                                                                                                       |
| metadata                                                  | object | Key value pair contains additional information of transaction                                                                                                                        |

{% tabs %}
{% tab title="API Request w/o Tip" %}

```javascript
{
    "merchantUserKey": "<MERCHANT-USER-KEY>",
    "transactionDetails": {
      "merchantOrderId": "<MERCHANT-ORDER-ID>",
      "amount": 45000,
      "items": [
        {
          "id": "<MERCHANT-ITEM-ID>",
          "name": "QRIS",
          "category": "<ITEM-CATEGORY>",
          "price": 45000,
          "url": "http://merchant.com/qris",
          "imageUrl": "http://merchant.com/qris/cover.jpg",
          "type": "offline-store",
          "quantity": 1,
          "parentType": "SELLER",
          "parentId": "<MERCHANT-SELLER-ID>"
        }
      ]
    },
    "customerDetails": {
      "firstName": "First",
      "lastName": "Last",
      "email": "first.last@gmail.com",
      "phone": "081212345678"
    },
    "sellers": [
      {
        "id": "<MERCHANT-SELLER-ID>",
        "name": "Penjual iPhone",
        "url": "https://merchant.com/shop",
        "sellerIdNumber": "<MERCHANT-SELLER-ID-NUMBER>",
        "email": "seller@merchant.com",
        "officialSeller": false,
        "address": {
          "firstName": "Merchant",
          "lastName": "Seller",
          "address": "Kelapa Gading",
          "city": "Jakarta Utara",
          "postalCode": "11240",
          "phone": "081812345678",
          "countryCode": "IDN"
        }
      }
    ],
    "billingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "shippingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "metadata": {
      "location": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "scanQrisLocation": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "qrisContent": "<QRIS-CONTENT>",
      "transactionPurpose": "CONSUMPTIVE",
      "mpan": "<QRIS-MPAN>"
    },
    "paymentType": "3_months",
    "approvedNotificationUrl": "https://payment-notification.merchant.com/transaction-approval-handler",
    "cancellationRedirectUrl": "http://merchant.com/phone/iphone-6s",
    "backToStoreUrl": "http://merchant.com/phone/iphone-6s",
    "expirationAt": "2019-12-31T18:00:00+07:00"
}
```

{% endtab %}

{% tab title="API Request w/ Tip" %}

```javascript
{
    "merchantUserKey": "<MERCHANT-USER-KEY>",
    "transactionDetails": {
      "merchantOrderId": "<MERCHANT-ORDER-ID>",
      "amount": 50000,
      "items": [
        {
          "id": "<MERCHANT-ITEM-ID>",
          "name": "QRIS",
          "category": "<ITEM-CATEGORY>",
          "price": 45000,
          "url": "http://merchant.com/qris",
          "imageUrl": "http://merchant.com/qris/cover.jpg",
          "type": "offline-store",
          "quantity": 1,
          "parentType": "SELLER",
          "parentId": "<MERCHANT-SELLER-ID>"
        }
      ]
    },
    "customerDetails": {
      "firstName": "First",
      "lastName": "Last",
      "email": "first.last@gmail.com",
      "phone": "081212345678"
    },
    "sellers": [
      {
        "id": "<MERCHANT-SELLER-ID>",
        "name": "Penjual iPhone",
        "url": "https://merchant.com/shop",
        "sellerIdNumber": "<MERCHANT-SELLER-ID-NUMBER>",
        "email": "seller@merchant.com",
        "officialSeller": false,
        "address": {
          "firstName": "Merchant",
          "lastName": "Seller",
          "address": "Kelapa Gading",
          "city": "Jakarta Utara",
          "postalCode": "11240",
          "phone": "081812345678",
          "countryCode": "IDN"
        }
      }
    ],
    "billingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "shippingAddress": {
      "firstName": "First",
      "lastName": "Last",
      "address": "Tomang",
      "city": "Jakarta Barat",
      "postalCode": "11430",
      "phone": "081987654321",
      "countryCode": "IDN"
    },
    "metadata": {
      "location": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "scanQrisLocation": {
        "lat": 6.123391,
        "lng": -107.900012
      },
      "qrisContent": "<QRIS-CONTENT>",
      "transactionPurpose": "CONSUMPTIVE",
      "tipAmount": 5000.00,
      "mpan": "<QRIS-MPAN>"
    },
    "paymentType": "3_months",
    "approvedNotificationUrl": "https://payment-notification.merchant.com/transaction-approval-handler",
    "cancellationRedirectUrl": "http://merchant.com/phone/iphone-6s",
    "backToStoreUrl": "http://merchant.com/phone/iphone-6s",
    "expirationAt": "2019-12-31T18:00:00+07:00"
}
```

{% endtab %}

{% tab title="200 Successful" %}

```
{
  "status": "OK",
  "agreementHtml": "<HTML String>"
}
```

{% endtab %}

{% tab title="Non 200 Error" %}

```
{
  "status": "ERROR",
  "error": {
    "kind": "GenericValidationError"
    "message": "<Object>"
  }
}
```

{% endtab %}
{% endtabs %}

#### Object Type References

For object specification of **Transaction**, **Customer**, **Seller,** **Address**, and **Metadata** can refer to this [API reference](https://dev.indodana.id/indodana-paylater/api-reference/api-reference#object-type-references).

## QRIS Transaction Metadata Callback

To be called by Merchant Partner after a successful transaction to update Indodana's transaction metadata.&#x20;

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

```javascript
const Promise = require('bluebird')
const superagent = Promise.promisifyAll(require('superagent'));
const path = require('path')

// Variable authorization should contain value of : 
//    'Bearer <api-key>:<nonce>:<signature>'
var authorization = generateAuthorizationHeader()

var baseUrl = "https://stg-k-api.indodanafinance.com/chermes/merchant"
var endpoint = `${baseUrl}/v1/transactions/qris/metadata`
  
var payload = {
  "merchantOrderId": "<MERCHANT-ORDER-ID>",
  "paidAt": "2024-01-01T13:00:00.000+07:00",
  "acquirer": "Indodana",
  "customerPan": "123456789",
  "referenceNumber": "REF-123456789"
}

superagent
    .post(endpoint)
    .set('Authorization', authorization)
    .send(payload)
    .endAsync()
    .then(response => {
      // Do something with response.body
      console.log(response.body)
    })
    .catch(err => {
      // Handle error
      console.log(err.response.text)
    });

```

{% endtab %}
{% endtabs %}

The sample responses (successful & error responses) that are possibly returned by the API can be found in the section of [API Reference > QRIS Transaction Metadata Callback.](https://dev.indodana.id/indodana-paylater/api-reference/api-reference#qris-transaction-metadata-callback)

## QRIS Check Transaction Status

In times of operating, there are several times that you may need to provide / check the status of the transaction (e.g: at the time of customer inquiry, or when you need to synchronize the state of the transaction). Indodana has provided an API endpoint for the merchants to easily check their transaction status.

There are several transaction statuses that the merchant needs to be aware of:

* ***INITIATED -*** Transaction has been created by Indodana
* ***EXPIRED -*** Customer failed to complete the transaction
* ***PAID -*** Transaction passed the fraud detection and is confirmed to-be-paid by Indodana
* ***REJECTED -*** If the transactions is identified as fraudulent transactions or in blacklisted merchants

![](https://1156563816-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LejA16TJVbqk0LLzQDc%2Fuploads%2FPbsuVB2GqT4yciFGwgig%2Fcheckstatusdiagram.png?alt=media\&token=a0bf1d4f-3a6d-4b9d-8d06-8c7de27243b0)

It's really simple to check your transaction status. This is the code that will be required to perform the transaction status check.

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

```javascript
const Promise = require('bluebird')
const superagent = Promise.promisifyAll(require('superagent'));
const path = require('path')

// Variable authorization should contain value of : 
//    'Bearer <api-key>:<nonce>:<signature>'
var authorization = generateAuthorizationHeader()

var baseUrl = "https://stg-k-api.indodanafinance.com/chermes/merchant"
var endpoint = `${baseUrl}/v1/transactions/qris/check_status`
  
var payload = {
  "merchantOrderId": "<MERCHANT-ORDER-ID>"
}

superagent
    .get(endpoint)
    .set('Authorization', authorization)
    .query(payload)
    .send()
    .endAsync()
    .then(response => {
      // Do something with response.body
      console.log(response.body)
    })
    .catch(err => {
      // Handle error
      console.log(err.response.text)
    });

```

{% endtab %}
{% endtabs %}

The sample responses (successful & error responses) that are possibly returned by the API can be found in the section of [API Reference > Sample API Request & Response > QRIS Check Transaction Status](https://dev.indodana.id/indodana-paylater/api-reference/api-reference#qris-check-transaction-status).

## Purchase Transaction Cancellation / Refund

Merchant is able to void / cancel a completed transaction. Note that, there are two types of cancellation. The first is ***FULL CANCELLATION -*** when the amount that is posted in the Refund / Cancellation request is the same as the transaction amount. The second is ***PARTIAL CANCELLATION -*** when the amount that is posted in the Refund / Cancellation request is different / less than the transaction amount.

{% hint style="warning" %}
It is required for merchant to include the cancellation reason, the preferred cancellation reason that given to Indodana are:

* **Expired** - when the seller does not give a response for the transaction after the predetermined time
* **Out of Stock** - when the seller does not give a response for the transaction after the predetermined time
* **Items Returned** - when the customer has cancelled the transaction because there was an issue with the item
* **Others** - any other reason beside the three above<br>
  {% endhint %}

### Full Cancellation

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

```javascript
const Promise = require('bluebird')
const superagent = Promise.promisifyAll(require('superagent'));
const path = require('path')

// Variable authorization should contain value of : 
//    'Bearer <api-key>:<nonce>:<signature>'
var authorization = generateAuthorizationHeader()

var baseUrl = "https://stg-k-api.indodanafinance.com/chermes/merchant"
var endpoint = `${baseUrl}/v3/order_cancellation`
  
var payload = {
  "refundId":"<MERCHANT-REFUND-ID>",
  "merchantOrderId":"<MERCHANT-ORDER-ID>",
  "cancellationAmount" : 100000,
  "cancellationReason":"Out of stock",
  "cancelledBy":"<SELLER/CUSTOMER>",
  "cancellationDate":"2019-09-12T18:18:18+07:00"
}

superagent
    .post(endpoint)
    .set('Authorization', authorization)
    .send(payload)
    .endAsync()
    .then(response => {
      // Do something with response.body
      console.log(response.body)
    })
    .catch(err => {
      // Handle error
      console.log(err.response.text)
    });
```

{% endtab %}
{% endtabs %}

The sample responses (successful & error responses) that are possibly returned by the API can be found in the section of [API Reference > Sample API Request & Response > Refund / Purchase Transaction Cancellation / Refund](https://dev.indodana.id/indodana-paylater/api-reference/api-reference#purchase-transaction-cancellation-refund).

### Partial Cancellation

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

```javascript
const Promise = require('bluebird')
const superagent = Promise.promisifyAll(require('superagent'));
const path = require('path')

// Variable authorization should contain value of : 
//    'Bearer <api-key>:<nonce>:<signature>'
var authorization = generateAuthorizationHeader()

var baseUrl = "https://stg-k-api.indodanafinance.com/chermes/merchant"
var endpoint = `${baseUrl}/v3/order_cancellation`
  
var payload = {
  "refundId":"<MERCHANT-REFUND-ID>",
  "merchantOrderId":"<MERCHANT-ORDER-ID>",
  "cancellationAmount" : 50000,  
  "cancellationReason":"Out of stock",
  "cancelledBy":"<SELLER/CUSTOMER>",
  "cancellationDate":"2019-09-12T18:18:18+07:00"
}

superagent
    .post(endpoint)
    .set('Authorization', authorization)
    .send(payload)
    .endAsync()
    .then(response => {
      // Do something with response.body
      console.log(response.body)
    })
    .catch(err => {
      // Handle error
      console.log(err.response.text)
    });
```

{% endtab %}
{% endtabs %}

The sample responses (successful & error responses) that are possibly returned by the API can be found in the section of [API Reference > Sample API Request & Response > Refund / Purchase Transaction Cancellation / Refund](https://dev.indodana.id/indodana-paylater/api-reference/api-reference#purchase-transaction-cancellation-refund).
