> ## Documentation Index
> Fetch the complete documentation index at: https://developer.paywint.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Signature Authentication

> How to generate HMAC-SHA256 signatures for secure API access in Paywint.

All requests to Paywint APIs must be authenticated using an HMAC-SHA256 signature. This ensures both the integrity and authenticity of your requests.

You must include:

* `X-Platform-ID` – your API key
* `X-Signature` – generated HMAC-SHA256 signature of the request

***

## Canonical String Format

To generate a valid signature, you need to build a **canonical string** using the following format:

```txt theme={null}
METHOD + PATH + QUERY + BODY_HASH
```

### Definitions

**METHOD**: HTTP method (e.g., GET, POST, PUT)

**PATH**: API path only (e.g., /api/platform/users/create)

**QUERY**: Raw query string (e.g., ?id=123), or empty if none

**BODY\_HASH**: SHA256 hex digest of the raw request body (for POST, PUT, etc.)

### Example Input

```
Method: POST
Path: /api/platform/users/create
Query: ?isExample=true&version=1.0.5
Body:
{
  "name": "John Doe",
  "email": "john@example.com",
  "phone": "9876543210",
  "phone_country_code": "+91"
}
```

## Signature Generation Examples

<CodeGroup>
  ```javascript Node.js theme={null}
  const crypto = require('crypto');

  const method = 'POST';
  const path = '/api/platform/users/create';
  const query = '?isExample=true&version=1.0.5';
  const body = JSON.stringify({
  name: 'John Doe',
  email: 'john@example.com',
  phone: '9876543210',
  phone_country_code: '+91'
  });

  const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
  const canonicalString = `${method}${path}${query}${bodyHash}`;

  const signature = crypto
  .createHmac('sha256', 'your_platform_secret_key')
  .update(canonicalString)
  .digest('hex');

  console.log('X-Signature:', signature);

  ```

  ```python Python theme={null}
  import hashlib
  import hmac

  method = "POST"
  path = "/api/platform/users/create"
  query = "?isExample=true&version=1.0.5"
  body = '{"name": "John Doe", "email": "john@example.com", "phone": "9876543210", "phone_country_code": "+91"}'

  body_hash = hashlib.sha256(body.encode('utf-8')).hexdigest()
  canonical_string = method + path + query + body_hash

  secret_key = b'your_platform_secret_key'
  signature = hmac.new(secret_key, canonical_string.encode('utf-8'), hashlib.sha256).hexdigest()

  print("X-Signature:", signature)

  ```

  ```go Go Lang theme={null}
  package main

  import (
  	"crypto/hmac"
  	"crypto/sha256"
  	"encoding/hex"
  	"fmt"
  )

  func main() {
  	method := "POST"
  	path := "/api/platform/users/create"
  	query := "?isExample=true&version=1.0.5"
  	body := `{"name": "John Doe", "email": "john@example.com", "phone": "9876543210", "phone_country_code": "+91"}`

  	bodyHash := sha256.Sum256([]byte(body))
  	canonical := method + path + query + hex.EncodeToString(bodyHash[:])

  	secret := []byte("your_platform_secret_key")
  	h := hmac.New(sha256.New, secret)
  	h.Write([]byte(canonical))

  	signature := hex.EncodeToString(h.Sum(nil))
  	fmt.Println("X-Signature:", signature)
  }

  ```

  ```php PHP theme={null}
  <?php
  $method = 'POST';
  $path = '/api/platform/users/create';
  $query = '?isExample=true&version=1.0.5';
  $body = json_encode([
      'name' => 'John Doe',
      'email' => 'john@example.com',
      'phone' => '9876543210',
      'phone_country_code' => '+91'
  ]);

  $bodyHash = hash('sha256', $body);
  $canonical = $method . $path . $query . $bodyHash;

  $secretKey = 'your_platform_secret_key';
  $signature = hash_hmac('sha256', $canonical, $secretKey);

  echo "X-Signature: $signature";

  ```

  ```java Java theme={null}
  import javax.crypto.Mac;
  import javax.crypto.spec.SecretKeySpec;
  import java.security.MessageDigest;
  import java.util.Formatter;

  public class SignatureGenerator {
      public static void main(String[] args) throws Exception {
          String method = "POST";
          String path = "/api/platform/users/create";
          String query = "?isExample=true&version=1.0.5";
          String body = "{\"name\": \"John Doe\", \"email\": \"john@example.com\", \"phone\": \"9876543210\", \"phone_country_code\": \"+91\"}";

          MessageDigest md = MessageDigest.getInstance("SHA-256");
          byte[] bodyHashBytes = md.digest(body.getBytes("UTF-8"));
          StringBuilder bodyHash = new StringBuilder();
          for (byte b : bodyHashBytes) {
              bodyHash.append(String.format("%02x", b));
          }

          String canonical = method + path + query + bodyHash.toString();

          String secret = "your_platform_secret_key";
          SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256");
          Mac mac = Mac.getInstance("HmacSHA256");
          mac.init(keySpec);
          byte[] hmacBytes = mac.doFinal(canonical.getBytes("UTF-8"));

          Formatter formatter = new Formatter();
          for (byte b : hmacBytes) {
              formatter.format("%02x", b);
          }

          System.out.println("X-Signature: " + formatter.toString());
          formatter.close();
      }
  }

  ```

  ```ruby Ruby theme={null}
  require 'openssl'
  require 'json'
  require 'digest'

  method = 'POST'
  path = '/api/platform/users/create'
  query = '?isExample=true&version=1.0.5'
  body = {
    name: "John Doe",
    email: "john@example.com",
    phone: "9876543210",
    phone_country_code: "+91"
  }.to_json

  body_hash = Digest::SHA256.hexdigest(body)
  canonical = method + path + query + body_hash

  secret = 'your_platform_secret_key'
  signature = OpenSSL::HMAC.hexdigest("SHA256", secret, canonical)

  puts "X-Signature: #{signature}"


  ```
</CodeGroup>

## Complete API Call Examples

Once the signature is generated, use it in the X-Signature header as shown below:

<CodeGroup>
  ```curl Curl theme={null}
  curl -X POST "https://<environment>/api/platform/users/create?isExample=true&version=1.0.5" \
    -H "Content-Type: application/json" \
    -H "X-Platform-ID: YOUR_API_KEY" \
    -H "X-Signature: GENERATED_SIGNATURE" \
    -d '{
      "name": "John Doe",
      "email": "john@example.com",
      "phone": "9876543210",
      "phone_country_code": "+91"
    }'
  ```

  ```javascript Node.js theme={null}
  const axios = require('axios');
  const crypto = require('crypto');

  const apiKey = 'YOUR_API_KEY';
  const secretKey = 'your_platform_secret_key';
  const apiPath = '/api/platform/users/create';
  const query = '?isExample=true&version=1.0.5';
  const url = 'https://<environment>' + apiPath;

  const body = {
    name: 'John Doe',
    email: 'john@example.com',
    phone: '9876543210',
    phone_country_code: '+91'
  };

  const method = 'POST';
  const bodyHash = crypto.createHash('sha256').update(JSON.stringify(body)).digest('hex');
  const canonical = method + apiPath + query + bodyHash;

  const signature = crypto
    .createHmac('sha256', secretKey)
    .update(canonical)
    .digest('hex');

  axios.post(url, body, {
    headers: {
      'Content-Type': 'application/json',
      'X-Platform-ID': apiKey,
      'X-Signature': signature
    }
  })
  .then(res => console.log(res.data))
  .catch(err => console.error(err.response?.data || err.message));

  ```

  ```python Python theme={null}
  import hashlib
  import hmac
  import requests
  import json

  api_key = 'YOUR_API_KEY'
  secret_key = b'your_platform_secret_key'
  api_path = '/api/platform/users/create'
  query = '?isExample=true&version=1.0.5'
  url = 'https://<environment>' + api_path

  body = {
      "name": "John Doe",
      "email": "john@example.com",
      "phone": "9876543210",
      "phone_country_code": "+91"
  }
  body_str = json.dumps(body)
  body_hash = hashlib.sha256(body_str.encode()).hexdigest()
  canonical = 'POST' + api_path + query + body_hash

  signature = hmac.new(secret_key, canonical.encode(), hashlib.sha256).hexdigest()

  headers = {
      'Content-Type': 'application/json',
      'X-Platform-ID': api_key,
      'X-Signature': signature
  }

  response = requests.post(url, data=body_str, headers=headers)
  print(response.status_code, response.text)

  ```

  ```go Go Lang theme={null}
  package main

  import (
  	"bytes"
  	"crypto/hmac"
  	"crypto/sha256"
  	"encoding/hex"
  	"fmt"
  	"io/ioutil"
  	"net/http"
  )

  func main() {
  	apiKey := "YOUR_API_KEY"
  	secretKey := "your_platform_secret_key"
  	apiPath := "/api/platform/users/create"
  	query := "?isExample=true&version=1.0.5"
  	url := "https://<environment>" + apiPath

  	body := `{"name":"John Doe","email":"john@example.com","phone":"9876543210","phone_country_code":"+91"}`
  	bodyHash := sha256.Sum256([]byte(body))
  	canonical := "POST" + apiPath + query + hex.EncodeToString(bodyHash[:])

  	h := hmac.New(sha256.New, []byte(secretKey))
  	h.Write([]byte(canonical))
  	signature := hex.EncodeToString(h.Sum(nil))

  	req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(body)))
  	if err != nil {
  		panic(err)
  	}
  	req.Header.Set("Content-Type", "application/json")
  	req.Header.Set("X-Platform-ID", apiKey)
  	req.Header.Set("X-Signature", signature)

  	client := &http.Client{}
  	resp, err := client.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	defer resp.Body.Close()

  	respBody, _ := ioutil.ReadAll(resp.Body)
  	fmt.Println("Status:", resp.Status)
  	fmt.Println("Response:", string(respBody))
  }

  ```

  ```php PHP theme={null}
  <?php
  $apiKey = 'YOUR_API_KEY';
  $secretKey = 'your_platform_secret_key';
  $apiPath = '/api/platform/users/create';
  $query = '?isExample=true&version=1.0.5';
  $url = 'https://<environment>' . $apiPath;

  $body = json_encode([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'phone' => '9876543210',
    'phone_country_code' => '+91'
  ]);

  $bodyHash = hash('sha256', $body);
  $canonical = 'POST' . $apiPath . $query . $bodyHash;
  $signature = hash_hmac('sha256', $canonical, $secretKey);

  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'X-Platform-ID: ' . $apiKey,
    'X-Signature: ' . $signature
  ]);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $response = curl_exec($ch);
  if ($response === false) {
    echo 'Curl error: ' . curl_error($ch);
  } else {
    echo 'Response: ' . $response;
  }
  curl_close($ch);

  ```

  ```java Java theme={null}
  import java.io.*;
  import java.net.*;
  import javax.crypto.Mac;
  import javax.crypto.spec.SecretKeySpec;
  import java.security.MessageDigest;

  public class PaywintAPI {
      public static void main(String[] args) throws Exception {
          String apiKey = "YOUR_API_KEY";
          String secretKey = "your_platform_secret_key";
          String apiPath = "/api/platform/users/create";
          String query = "?isExample=true&version=1.0.5";
          String url = "https://<environment>" + apiPath;

          String body = "{\"name\": \"John Doe\", \"email\": \"john@example.com\", \"phone\": \"9876543210\", \"phone_country_code\": \"+91\"}";

          MessageDigest md = MessageDigest.getInstance("SHA-256");
          byte[] hash = md.digest(body.getBytes("UTF-8"));
          StringBuilder bodyHash = new StringBuilder();
          for (byte b : hash) bodyHash.append(String.format("%02x", b));
          String canonical = "POST" + apiPath + query + bodyHash.toString();

          Mac mac = Mac.getInstance("HmacSHA256");
          mac.init(new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA256"));
          byte[] hmac = mac.doFinal(canonical.getBytes("UTF-8"));
          StringBuilder signature = new StringBuilder();
          for (byte b : hmac) signature.append(String.format("%02x", b));

          HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
          conn.setRequestMethod("POST");
          conn.setDoOutput(true);
          conn.setRequestProperty("Content-Type", "application/json");
          conn.setRequestProperty("X-Platform-ID", apiKey);
          conn.setRequestProperty("X-Signature", signature.toString());

          try (OutputStream os = conn.getOutputStream()) {
              os.write(body.getBytes("UTF-8"));
          }

          BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
          String line;
          while ((line = br.readLine()) != null) System.out.println(line);
      }
  }

  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'
  require 'json'
  require 'openssl'
  require 'digest'

  api_key = 'YOUR_API_KEY'
  secret_key = 'your_platform_secret_key'
  api_path = '/api/platform/users/create'
  query = '?isExample=true&version=1.0.5'
  url = URI("https://<environment>#{api_path}")

  body = {
    name: 'John Doe',
    email: 'john@example.com',
    phone: '9876543210',
    phone_country_code: '+91'
  }.to_json

  body_hash = Digest::SHA256.hexdigest(body)
  canonical = "POST" + api_path + query + body_hash

  signature = OpenSSL::HMAC.hexdigest('sha256', secret_key, canonical)

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true

  request = Net::HTTP::Post.new(url)
  request['Content-Type'] = 'application/json'
  request['X-Platform-ID'] = api_key
  request['X-Signature'] = signature
  request.body = body

  response = http.request(request)
  puts "Status: #{response.code}"
  puts "Response: #{response.body}"

  ```
</CodeGroup>

<Note>
  Alternatively, you can use the static signature in the [sandbox environment](/environments#sandbox): `8b3cb99a4b8e24fc7e01d0db635e2e47b80818144fe51400c6c6ae3ecbc84f47`
</Note>

## Best Practices

* Keep your **API Key** and **Secret Key** secure — never expose them on the client side
* Always use HTTPS to protect the signature and payload
* Regenerate the signature for every request; it's not reusable

***

Need help? Reach out to [support@paywint.com](mailto:support@paywint.com)
