> For the complete documentation index, see [llms.txt](https://docs-sdk.crypto-chief.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs-sdk.crypto-chief.com/processing/python/authentication.md).

# Authentication

Every request to the Crypto Processing API is authenticated with two HTTP headers. **The SDK builds and sets them for you** — you only provide your Merchant ID and API key.

```
Merchant:  <your Merchant ID>
Signature: hex(md5(base64(canonicalJSON(body)) + API_KEY))
```

## Credentials

Both values come from your dashboard → **Integration** tab:

* **Merchant ID** — identifies your project.
* **API key** — the **signing secret**. It never leaves your server; the SDK uses it to compute the `Signature` and to verify incoming webhooks.

{% hint style="warning" %}
Treat the API key like a password. Load it from an environment variable and keep it server-side — never commit it or ship it in client apps.
{% endhint %}

## Initialize the client

```python
import os
from cryptochief import CryptoChiefClient

client = CryptoChiefClient(
    merchant_id=os.environ["MERCHANT_ID"],
    api_key=os.environ["API_KEY"],
)
```

The client owns an `httpx.AsyncClient`, so close it when you're done — or use it as an async context manager, which closes it for you:

```python
async with CryptoChiefClient(merchant_id=..., api_key=...) as client:
    ...  # use the client

# or, for a long-lived client created once at startup:
await client.aclose()
```

## Configuration options

```python
client = CryptoChiefClient(
    merchant_id=os.environ["MERCHANT_ID"],
    api_key=os.environ["API_KEY"],
    base_url="https://api-processing.crypto-chief.com",  # default
    timeout=60.0,                                         # per-attempt timeout (seconds)
    retries=3,                                            # retry 5xx + transport errors
    retry_backoff={"base_ms": 200, "max_ms": 5000},      # exponential + jitter
    user_agent="my-service/1.0",
    rsa_private_key=open("rsa_private.pem").read(),       # optional — wallet decryption
    # http_client=my_httpx_client,                       # optional — inject your own httpx.AsyncClient
)
```

To cancel a slow call, wrap it in the standard asyncio timeout — the request and its retries stop with the task:

```python
import asyncio

await asyncio.wait_for(client.payouts.info(uuid), timeout=3)
```

{% hint style="info" %}
**Test mode** is a per-project toggle in the dashboard, not a separate base URL. Point a test-mode project's credentials at the same client.
{% endhint %}

## How signing works

The client canonicalizes the JSON body (recursively sorted keys, HTML-escaped `< > &`), base64-encodes it, appends your API key, and MD5-hashes the result to produce the `Signature`. The same scheme verifies [webhooks](/processing/python/guides/webhooks.md), so one secret secures both directions.
