# Signature Authorization and Calculation

## <mark style="color:blue;">API credentials</mark>

Our Deposits APIs uses API Keys in all of the requests to authenticate. Your API Keys can be retrieved from the Tupay Panel by going to Settings -> API Access.

* The API Keys on the STG and PROD environments are different.

There are basically two set of credentials:

* One API Key and one API Signature for POST operations.
* One API Key key for read-only endpoints.

Authentication to the API is performed via [HTTP Basic Auth](http://en.wikipedia.org/wiki/Basic_access_authentication). You must provide your API Key in all the requests as the basic auth username value. You do not need to provide a password.

Your API Key must be sent in all the API calls using the X-Login field on the header of the request.

Your API Keys, along with your IP Addresses are your way to authenticate yourself, therefore, do not share your secret API keys in publicly accessible areas such as GitHub, client-side code and so forth.

## <mark style="color:blue;">Headers</mark>

<table data-header-hidden><thead><tr><th width="155"></th><th width="105"></th><th width="119"></th><th></th></tr></thead><tbody><tr><td>Header</td><td>Format</td><td>Mandatory</td><td>Description</td></tr><tr><td>Authorization</td><td>String</td><td>Yes</td><td><code>"TUPAY"</code> plus a hash HMAC256 to verify request integrity</td></tr><tr><td>X-Login</td><td>String</td><td>Yes</td><td>Merchant <code>API Key</code></td></tr><tr><td>X-Date</td><td>String</td><td>Yes</td><td>ISO8601 Datetime: <code>yyyy-MM-dd'T'HH:mm:ssZ</code>. E.g.: <code>2020-06-21T12:33:20Z</code></td></tr><tr><td>Content-Type</td><td>String</td><td>Yes</td><td><code>application/json</code></td></tr><tr><td>X-Idempotency-Key</td><td>String</td><td>No</td><td>Unique value generated by the client which the server uses to recognize subsequent retries of the same request</td></tr></tbody></table>

## Calculating the Signature

All the calls to our Deposits APIs will contain an `Authorization` field on the header used to ensure request integrity and to authenticate yourself since you will use your own secret key (API Signature) to generate and encrypt a hash.&#x20;

It has to be created using **HMAC-SHA-256 (RFC 2104)** encoding and the payload must include the following details:

> [X-Date](#notes) + [X-Login](#notes) + `JSONPayload`

{% hint style="success" %}
Use your API Signature to generate the Authorization value
{% endhint %}

The `Authorization` field on the header of the requests will contain the string "TUPAY " plus the hash generated, in the following format:

> Authorization: "TUPAY " + HMAC256(X-Date + X-Login + JSONPayload)

Example:

> Authorization: TUPAY 223a9dd4784726f1536c926da7dc69155a57612c5c3c1e1b429c367a5eee67cf

<details>

<summary>Notes</summary>

The <mark style="color:blue;">**`X-Login`**</mark> is your login API Key, it can be retrieved from the Tupay Panel by going to Settings -> API Access -> Deposit credentials -> API Key.

The <mark style="color:blue;">**`X-Date`**</mark> is the date in ISO8601 Datetime with Timezone. Format expected: ISO8601 Datetime with Timezone: `yyyy-MM-dd'T'HH:mm:ssZ`. E.g.: `2020-06-21T12:33:20Z`.&#x20;

The `Authorization` value is case sensitive and must include all the above mentioned values.

The `JSONPayload` is the exact same JSON you sent in the body of the request.

In case the `JSONPayload` value is empty (for example in the status or payment methods endpoints), use an empty string ("") instead.

The `JSONPayload` should be converted to UTF-8 before hashing it to prevent *Invalid Signature* error when sending characters with different encodings.&#x20;

</details>

{% tabs %}
{% tab title="Idempotent Requests" %}
Our API supports [idempotency](https://en.wikipedia.org/wiki/Idempotence) for safely retrying requests without accidentally performing the same operation twice. This is useful when an API call is disrupted in transit and you do not receive a response. For example, if a request to the Deposit Creation Endpoint does not respond due to a network connection error, you can retry the request with the same idempotency key to guarantee that no more than one deposit is created.

In order to perform an idempotent request you need to send the `X-Idempotency-Key: <key>` header with a random and unique string.

Idempotency works by saving the resulting status code and body of the first request made for any given idempotency key, regardless of whether it succeeded or failed. Subsequent requests with the same key return the same result, including `500` errors.

An idempotency key is a unique value generated by the client which the server uses to recognize subsequent retries of the same request. How you create unique keys is up to you, but we suggest using V4 UUIDs, or another random string with enough entropy to avoid collisions.

All `POST` requests accept idempotency keys. Sending idempotency keys in `GET` and `DELETE` requests has no effect and should be avoided as these requests are idempotent by definition.

### Content-Type

All of our Deposits APIs are designed to receive and respond the information in JSON format.

This header won't change across the requests, and shall always be: `application/json`
{% endtab %}

{% tab title="IP Whitelisting" %}
For security purposes, you need to whitelist the IPs from where you will call our API.

In order to whitelist your IPs and make the process as smoother as possible, you should go to **Settings -> API Access** and add the list of IPs you will possibly use under the **Deposit IP Address** section.

<figure><img src="/files/qPdtuCNNGfNN5e9XBaoP" alt="" width="306"><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

<details>

<summary>Best Practices</summary>

We recommend you follow this list of technical and security practices to maximize the security of the information end-to-end.

1. Always make sure to verify the Signatures control string sent in the notifications to validate the veracity.
2. All information we receive is converted to UTF-8. Be sure to convert it to UTF-8 as well to ensure that both parties have the same details.
3. Always validate that a deposit is not released more than once based on the deposit\_id (Notifications can be sent multiple times). Make sure that a deposit is not released more than once based on the deposit\_id, as the notification may be sent more than once.

</details>

## <mark style="color:blue;">Examples</mark>

Check the examples in the different languages on how to properly calculate the Signature.

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

```php
<?php

class Directa24Example {
 
	const TUPAY_AUTHORIZATION_SCHEME = "TUPAY ";
	const HMAC_SHA256 = 'sha256';
		
	public static function build_deposit_key_signature($api_signature, $x_date, $deposits_api_key, $json_payload)
	 {	
		// Concatenate the content of the header X-Date, your deposits API Key (X-Login) and 
		// the whole JSON payload of the body of the request
		$string = $x_date . $deposits_api_key . $json_payload;
	
		// Generate the HASH by using yur own deposits API Signature and 
		// concatenate "D24 " in front of the hash
		return  self::TUPAY_AUTHORIZATION_SCHEME . hash_hmac(self::HMAC_SHA256, $string, $api_signature);	
	}
}

```

{% endtab %}

{% tab title="C#" %}

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

namespace Application 
{

    class Directa24Example 
    {
    
        public readonly static string TUPA_AUTHORIZATION_SCHEME = "TUPAY ";
        
        private readonly static string HMAC_SHA256 = "HmacSHA256";
        
        public static String buildDepositKeySignature(String apiSignature, String xDate, String depositKey, String jsonPayload)
        {
            byte[] hmacSha256 = null;
            var apiSignatureEncod = Encoding.UTF8.GetBytes(apiSignature);
            var hash = new HMACSHA256(apiSignatureEncod);
            hmacSha256 = hash.ComputeHash(buildByteArray(xDate, depositKey, jsonPayload));  
            return TUPAY_AUTHORIZATION_SCHEME + toHexString(hmacSha256).ToLower();
        }
        
        private static byte[] buildByteArray(String xDate, String apiKey, String jsonPayload)
        {
            try
            {
                MemoryStream stream = new MemoryStream();
                var xDateEncod = Encoding.UTF8.GetBytes(xDate);
                var apiKeyEncod = Encoding.UTF8.GetBytes(apiKey);
                stream.Write(xDateEncod, 0, xDateEncod.Length);
                stream.Write(apiKeyEncod, 0, apiKeyEncod.Length);
                if (!string.IsNullOrWhiteSpace(jsonPayload))
                {
                    var jsonPayloadEncod = Encoding.UTF8.GetBytes(jsonPayload);
                    stream.Write(jsonPayloadEncod, 0, jsonPayloadEncod.Length);
                }
                return stream.ToArray();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        
        private static string toHexString(byte[] bytes)
        {
            return BitConverter.ToString(bytes).Replace("-", string.Empty);
        }
    }
}


```

{% endtab %}

{% tab title="Java" %}

```java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public static final String TUPAY_AUTHORIZATION_SCHEME = "TUPAY ";

private static final String HMAC_SHA256 = "HmacSHA256";

public static String buildDepositKeySignature(String apiSignature, String xDate, String depositKey, String JSONPayload)
      throws NoSuchAlgorithmException, InvalidKeyException, IOException {
   byte[] hmacSha256 = null;
   Mac mac = Mac.getInstance(HMAC_SHA256);
   SecretKeySpec secretKeySpec = new SecretKeySpec(apiSignature.getBytes(StandardCharsets.UTF_8), HMAC_SHA256);
   mac.init(secretKeySpec);
   hmacSha256 = mac.doFinal(buildByteArray(xDate, apiKey, JSONPayload));
   return TUPAY_AUTHORIZATION_SCHEME + toHexString(hmacSha256);
}

private static byte[] buildByteArray(String xDate, String apiKey, String JSONPayload) throws IOException {
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   bos.write(xDate.getBytes(StandardCharsets.UTF_8));
   bos.write(apiKey.getBytes(StandardCharsets.UTF_8));
   if (JSONPayload != null) {
      bos.write(payload.getBytes(StandardCharsets.UTF_8));
   }
   return bos.toByteArray();
}

private static String toHexString(byte[] bytes) {
   Formatter formatter = new Formatter();
   for (byte b : bytes) {
      formatter.format("%02x", b);
   }
   return formatter.toString();
}


```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.tupayonline.com/english/api-documentation/deposit/signature-authorization-and-calculation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
