# Signature

KwikPaisa APIs use HMAC SHA256 based request signing to authenticate and validate every API request securely.

Each request must include a generated signature in the X-SIGNATURE header. The signature helps verify:

* Request authenticity
* Payload integrity
* Timestamp validity
* Merchant authorization

This security mechanism protects APIs against unauthorized access, payload tampering, and replay attacks.

***

## Signature Formula

```http
HMAC_SHA256(payload + timestamp, secret_key)
```

## How Signature Generation Works

To generate a valid signature:

1. Prepare the request payload
2. Recursively sort all payload keys
3. Convert the payload into JSON format
4. Generate current UNIX timestamp in seconds
5. Concatenate:

```http
payload + timestamp
```

6. Generate HMAC SHA256 hash using your `secret_key`

## Example Payload

```json
{ 
 "order_id": "123456",
 "amount": "100"
}
```

## Important Payload Rules

Before generating the signature:

* Payload keys must be sorted recursively
* JSON payload must remain unchanged
* Use unescaped slashes in JSON encoding
* Do not modify payload after signature generation
* Generate a fresh timestamp for every request

Any mismatch between:

* Request payload
* Timestamp
* Secret key

will result in authentication failure.

{% tabs %}
{% tab title="Node.js" %}

```http
const crypto = require('crypto');
const data = {
  order_id: '123456',
  amount: '100'
};
const sortedData = Object.keys(data)
  .sort()
  .reduce((obj, key) => {
    obj[key] = data[key];
    return obj;
  }, {});
const payload = JSON.stringify(sortedData);
const timestamp = Math.floor(Date.now() / 1000);
const secretKey = 'YOUR_SECRET_KEY';
const signature = crypto
  .createHmac('sha256', secretKey)
  .update(payload + timestamp)
  .digest('hex');
console.log(signature);
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
$data = [
    'order_id' => '123456',
    'amount' => '100'
];
function sortPayload($data)
{
    if (!is_array($data)) {
        return $data;
    }
    ksort($data);
    foreach ($data as $key => $value) {
        $data[$key] = sortPayload($value);
    }
    return $data;
}
$payload = json_encode(
    sortPayload($data),
    JSON_UNESCAPED_SLASHES
);
$timestamp = time();
$secretKey = 'YOUR_SECRET_KEY';
$signature = hash_hmac(
    'sha256',
    $payload . $timestamp,
    $secretKey
);
echo $signature;
```

{% endtab %}

{% tab title="Python" %}

```python
import json
import hmac
import hashlib
import time
data = {
    "order_id": "123456",
    "amount": "100"
}
sorted_data = dict(sorted(data.items()))
payload = json.dumps(
    sorted_data,
    separators=(',', ':')
)
timestamp = str(int(time.time()))
secret_key = "YOUR_SECRET_KEY"
signature = hmac.new(
    secret_key.encode(),
    (payload + timestamp).encode(),
    hashlib.sha256
).hexdigest()
print(signature)
```

{% endtab %}

{% tab title="Java" %}

```java
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
public class SignatureGenerator {
    public static String generateSignature(
        Map<String, Object> data,
        String secretKey,
        long timestamp
    ) throws Exception {
        TreeMap<String, Object> sortedData = new TreeMap<>(data);
        ObjectMapper mapper = new ObjectMapper();
        String payload = mapper.writeValueAsString(sortedData);
        String signString = payload + timestamp;
        Mac sha256Hmac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(
            secretKey.getBytes(),
            "HmacSHA256"
        );
        sha256Hmac.init(secretKeySpec);
        byte[] hash = sha256Hmac.doFinal(
            signString.getBytes()
        );
        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            hexString.append(String.format("%02x", b));
        }
        return hexString.toString();
    }
}
```

{% endtab %}

{% tab title=".NET (C#)" %}

```c
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
class Program
{
    static void Main()
    {
        var data = new SortedDictionary<string, object>
        {
            { "order_id", "123456" },
            { "amount", "100" }
        };
        string payload = JsonConvert.SerializeObject(data);
        long timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        string signString = payload + timestamp;
        string secretKey = "YOUR_SECRET_KEY";
        using(var hmac = new HMACSHA256(
            Encoding.UTF8.GetBytes(secretKey)))
        {
            byte[] hash = hmac.ComputeHash(
                Encoding.UTF8.GetBytes(signString)
            );
            string signature = BitConverter
                .ToString(hash)
                .Replace("-", "")
                .ToLower();
            Console.WriteLine(signature);
        }
    }
}
```

{% endtab %}

{% tab title="Flutter / Dart" %}

```dart
import 'dart:convert';
import 'package:crypto/crypto.dart';
void main() {
  Map<String, dynamic> data = {
    "order_id": "123456",
    "amount": "100"
  };
  final sortedKeys = data.keys.toList()..sort();
  final sortedData = {
    for (var key in sortedKeys) key: data[key]
  };
  String payload = jsonEncode(sortedData);
  int timestamp = DateTime.now()
      .millisecondsSinceEpoch ~/ 1000;
  String secretKey = "YOUR_SECRET_KEY";
  String signString = payload + timestamp.toString();
  var hmacSha256 = Hmac(
    sha256,
    utf8.encode(secretKey)
  );
  var digest = hmacSha256.convert(
    utf8.encode(signString)
  );
  String signature = digest.toString();
  print(signature);
}
```

{% endtab %}

{% tab title="Go" %}

```go
package main
import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"time"
)
func main() {
	payload := map[string]string{
		"order_id": "123456",
		"amount":   "100",
	}
	payloadJSON, _ := json.Marshal(payload)
	timestamp := fmt.Sprintf("%d", time.Now().Unix())
	message := string(payloadJSON) + timestamp
	secretKey := "YOUR_SECRET_KEY"
	h := hmac.New(sha256.New, []byte(secretKey))
	h.Write([]byte(message))
	signature := hex.EncodeToString(h.Sum(nil))
	fmt.Println(signature)
}
```

{% endtab %}
{% endtabs %}

## Common Authentication Errors

### 401 Unauthorized

Possible reasons:

* Invalid signature
* Wrong secret key
* Expired timestamp
* Incorrect payload format
* Missing headers

### Invalid Signature

This usually happens when:

* Payload is modified after signing
* Keys are not sorted correctly
* JSON formatting differs
* Timestamp mismatch occurs

## Security Best Practices

* Never expose your `secret_key` publicly
* Always generate signatures on the server side
* Use HTTPS for all API requests
* Generate unique timestamps for every request
* Rotate credentials periodically
* Validate webhook signatures before processing callbacks

## Recommended Workflow

1. Generate timestamp
2. Prepare payload
3. Generate signature
4. Attach required headers
5. Send API request
6. Validate API response


---

# 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://developers.kwikpaisa.com/v3-guide/authentication/signature.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.
