> For the complete documentation index, see [llms.txt](https://docs.esimpay.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.esimpay.net/eng/authentication-and-security.md).

# Authentication & Security

### ESIMPAY uses cryptographic authentication based on HMAC-SHA256.

#### Overview

Every request requires two headers:

| Header           | Purpose                           | Example          |
| ---------------- | --------------------------------- | ---------------- |
| `CF-MERCHANT-ID` | Your merchant identifier          | `merchant_12345` |
| `CF-ACCESS-SIGN` | HMAC-SHA256 signature (POST only) | `dGVzdA==`       |

#### Obtaining credentials

1. Sign in to your ESIMPAY account dashboard
2. Go to the "API Keys" section
3. Create a new key
4. Copy:
   * `Merchant ID`
   * `API Secret`

{% hint style="warning" %}
**Important**: never share your `API Secret`! Store it in environment variables.
{% endhint %}

#### Generating a signature

#### Algorithm

1. **Serialization**
   * JSON with sorted keys
   * No whitespace (compact format)
   * UTF-8 encoding
2. **Compute HMAC-SHA256**
   * Use the API Secret as the key
   * Use the JSON as the message
3. **Base64 encoding**
   * Put the result into the `CF-ACCESS-SIGN` header

#### Python example

```python
import json
import hmac
import hashlib
import base64

MERCHANT_ID = 'your_merchant_id'
API_SECRET = 'your_api_secret'

def sign_request(payload):
    """Generates a signature for the request."""
    
    # Step 1: JSON with sorted keys, no spaces.
    json_body = json.dumps(
        payload,
        separators=(',', ':'),      # {"a":1} не {"a": 1}
        ensure_ascii=False,         # UTF-8 как есть
        sort_keys=True,             # ОБЯЗАТЕЛЬНО!
    )
    
    # Step 2: HMAC-SHA256
    digest = hmac.new(
        API_SECRET.encode('utf-8'),
        json_body.encode('utf-8'),
        hashlib.sha256,
    ).digest()
    
    # Step 3: Base64
    signature = base64.b64encode(digest).decode('utf-8')
    
    return json_body, signature

# Using
payload = {
    'orderId': 'order_abc123',
    'productId': 'b27bfd74-c46d-479c-b628-ec7ca69a146f',
    'activationMode': 'NOW',
}

json_body, signature = sign_request(payload)
print(f"JSON: {json_body}")
print(f"Signature: {signature}")
```

#### Node.js example

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

const MERCHANT_ID = 'your_merchant_id';
const API_SECRET = 'your_api_secret';

function signRequest(payload) {
    // Sorting JSON
    const jsonBody = JSON.stringify(payload, Object.keys(payload).sort());
    
    // HMAC-SHA256
    const signature = crypto
        .createHmac('sha256', API_SECRET)
        .update(jsonBody, 'utf-8')
        .digest('base64');
    
    return { jsonBody, signature };
}

// Using
const payload = {
    orderId: 'order_abc123',
    productId: 'b27bfd74-c46d-479c-b628-ec7ca69a146f',
    activationMode: 'NOW'
};

const { jsonBody, signature } = signRequest(payload);
console.log('JSON:', jsonBody);
console.log('Signature:', signature);
```

#### PHP example

```php
<?php

function signRequest($payload) {
    $apiSecret = 'your_api_secret';
    
    // We sort and encode in JSON.
    ksort($payload);
    $jsonBody = json_encode($payload, JSON_UNESCAPED_UNICODE);
    
    // HMAC-SHA256
    $signature = base64_encode(
        hash_hmac('sha256', $jsonBody, $apiSecret, true)
    );
    
    return [$jsonBody, $signature];
}

// Using
$payload = [
    'orderId' => 'order_abc123',
    'productId' => 'b27bfd74-c46d-479c-b628-ec7ca69a146f',
    'activationMode' => 'NOW'
];

[$jsonBody, $signature] = signRequest($payload);
echo "JSON: $jsonBody\n";
echo "Signature: $signature\n";
```

#### &#x20;Complete example with a query.

#### Python + requests

```python
import json
import hmac
import hashlib
import base64
import requests

MERCHANT_ID = 'your_merchant_id'
API_SECRET = 'your_api_secret'
BASE_URL = 'https://api.esimpay.net/api/v1'

def create_order(order_id, product_id):
    payload = {
        'orderId': order_id,
        'productId': product_id,
        'activationMode': 'NOW',
    }
    
    # We are generating a signature.
    json_body = json.dumps(
        payload,
        separators=(',', ':'),
        ensure_ascii=False,
        sort_keys=True,
    )
    
    signature = base64.b64encode(
        hmac.new(
            API_SECRET.encode('utf-8'),
            json_body.encode('utf-8'),
            hashlib.sha256,
        ).digest()
    ).decode('utf-8')
    
    # We are sending a request.
    response = requests.post(
        f'{BASE_URL}/orders/submit',
        data=json_body,
        headers={
            'Content-Type': 'application/json',
            'CF-MERCHANT-ID': MERCHANT_ID,
            'CF-ACCESS-SIGN': signature,
        },
    )
    
    return response.json()

# Using
result = create_order('order_123', 'b27bfd74-c46d-479c-b628-ec7ca69a146f')
print(json.dumps(result, indent=2))
```

### Security best practices

#### 1. Protecting credentials

```python
import os
from dotenv import load_dotenv

load_dotenv()

MERCHANT_ID = os.getenv('ESIMPAY_MERCHANT_ID')
API_SECRET = os.getenv('ESIMPAY_API_SECRET')

if not MERCHANT_ID or not API_SECRET:
    raise ValueError("Missing ESIMPAY credentials")
```

#### 2. Never commit secrets

```bash
# .gitignore
.env
.env.local
secrets.txt
```

#### 3. Use HTTPS

All requests must go over HTTPS (not HTTP).

#### 4. **Rotate your keys**

Update your API keys regularly (at least once a year).

#### Common mistakes

#### ❌ Wrong

```python
# Spaces in JSON
json_body = json.dumps(payload)  # {"key": "value"}

# We don’t sort the keys.
json_body = json.dumps(payload, sort_keys=False)

# We use ASCII encoding.
json_body = json.dumps(payload, ensure_ascii=True)
```

#### ✅ Correct

```python
# Compact JSON without spaces, sorted keys, UTF-8
json_body = json.dumps(
    payload,
    separators=(',', ':'),
    sort_keys=True,
    ensure_ascii=False,
)
```

#### Debugging signatures

```python
# Debug script
import json
import hmac
import hashlib
import base64

payload = {'orderId': 'test', 'productId': 'prod_id'}
api_secret = 'your_secret'

print("1. Original payload:")
print(json.dumps(payload, indent=2))

json_body = json.dumps(payload, separators=(',', ':'), sort_keys=True)
print(f"\n2. JSON body: {json_body}")

hmac_digest = hmac.new(
    api_secret.encode('utf-8'),
    json_body.encode('utf-8'),
    hashlib.sha256,
).digest()
print(f"\n3. HMAC hex: {hmac_digest.hex()}")

signature = base64.b64encode(hmac_digest).decode('utf-8')
print(f"\n4. Signature: {signature}")
```

***

**Ready to integrate? Check out the code examples!**
