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

# Authentication

> All Payaza API requests are authenticated using your API key. Learn how to retrieve, encode, and use your key correctly.

## How authentication works

Every Payaza API request requires an `Authorization` header. The format is:

```
Authorization: Payaza <base64-encoded-api-key>
```

Two things are different from most APIs:

1. The prefix is **`Payaza`** — not `Bearer`
2. Your API key must be **Base64-encoded** before use

***

## Step 1 — Retrieve your API key

<Steps>
  <Step title="Log in to the Payaza dashboard">
    Go to [business.payaza.africa](https://business.payaza.africa) and log in to your account.
  </Step>

  <Step title="Open Settings → Developers">
    Click **Settings** in the left sidebar, then select **Developers** from the dropdown.
  </Step>

  <Step title="Generate your keys">
    Click the **Generate Keys** button to create your API keys. Toggle between **Test Mode** and **Live Mode** to retrieve the key for each environment.
  </Step>
</Steps>

<img src="https://res.cloudinary.com/dlxl6fi3r/image/upload/v1770819737/authenticationpic_upbfjr.png" />

<Warning>
  Never expose your API key in client-side code, browser JavaScript, or a public repository. If a key is ever compromised, regenerate it immediately from the dashboard.
</Warning>

***

## Step 2 — Encode your key in Base64

Your API key must be Base64-encoded before placing it in the `Authorization` header.

<CodeGroup>
  ```bash Terminal theme={null}
  echo -n "your-api-key-here" | base64
  ```

  ```javascript Node.js theme={null}
  const apiKey = "your-api-key-here";
  const encodedKey = Buffer.from(apiKey).toString("base64");
  // Use encodedKey in your Authorization header
  ```

  ```python Python theme={null}
  import base64

  api_key = "your-api-key-here"
  encoded_key = base64.b64encode(api_key.encode()).decode()
  # Use encoded_key in your Authorization header
  ```

  ```php PHP theme={null}
  $api_key = "your-api-key-here";
  $encoded_key = base64_encode($api_key);
  // Use $encoded_key in your Authorization header
  ```
</CodeGroup>

***

## Step 3 — Make an authenticated request

These are the possible headers that can be added to a Payaza API request:

| Header          | Required       | Value                         |
| --------------- | -------------- | ----------------------------- |
| `Authorization` | Yes            | `Payaza <base64-encoded-key>` |
| `X-TenantID`    | Depends on API | `test` or `live`              |
| `Content-Type`  | Yes (POST/PUT) | `application/json`            |

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url https://api.payaza.africa/live/payaza-account/api/v1/mainaccounts \
    --header 'Authorization: Payaza UFo4748S0xJVkUtSJDS5RThDQzEtQjAzMS00RUNBLTgwOTctRUVCMjA5NzJENTY0' \
    --header 'X-TenantID: test'
  ```

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

  const apiKey = "your-api-key-here";
  const encodedKey = Buffer.from(apiKey).toString("base64");

  const { data } = await axios.get(
    "https://api.payaza.africa/live/payaza-account/api/v1/mainaccounts",
    {
      headers: {
        Authorization: `Payaza ${encodedKey}`,
        "X-TenantID": "test",
      },
    }
  );
  ```

  ```python Python theme={null}
  import base64
  import requests

  api_key = "your-api-key-here"
  encoded_key = base64.b64encode(api_key.encode()).decode()

  response = requests.get(
      "https://api.payaza.africa/live/payaza-account/api/v1/mainaccounts",
      headers={
          "Authorization": f"Payaza {encoded_key}",
          "X-TenantID": "test",
      },
  )
  data = response.json()
  ```

  ```php PHP theme={null}
  $api_key = "your-api-key-here";
  $encoded_key = base64_encode($api_key);

  $curl = curl_init();
  curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.payaza.africa/live/payaza-account/api/v1/mainaccounts",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
      "Authorization: Payaza " . $encoded_key,
      "X-TenantID: test",
    ],
  ]);

  $response = json_decode(curl_exec($curl), true);
  curl_close($curl);
  ```
</CodeGroup>

<Note>
  `X-TenantID` is required for some APIs but not all. For APIs that require it, use `test` during development and `live` in production. See the [Required headers by API](#required-headers-by-api) table below for a full breakdown.
</Note>

***

## Required headers by API

Different Payaza APIs require different combinations of headers. Use this table as a quick reference before making requests.

| API                                | `Authorization`       | `X-TenantID`     | `X-ProductID` | `Content-Type`     |
| ---------------------------------- | --------------------- | ---------------- | ------------- | ------------------ |
| Card Collections                   | `Payaza <base64-key>` | Not required     | Not required  | `application/json` |
| Momo / XOF / ZAR / SLE Collections | `Payaza <base64-key>` | `test` or `live` | `app`         | `application/json` |
| Apple Pay / Google Pay             | `Payaza <base64-key>` | Not required     | Not required  | `application/json` |
| Transfers (Payouts)                | `Payaza <base64-key>` | `test` or `live` | Not required  | `application/json` |
| Virtual Accounts                   | `Payaza <base64-key>` | Not required     | Not required  | `application/json` |
| Sub-accounts                       | `Payaza <base64-key>` | `test` or `live` | Not required  | `application/json` |
| Refunds & Chargebacks              | `Payaza <base64-key>` | Not required     | Not required  | `application/json` |
| Account Enquiry                    | `Payaza <base64-key>` | `test` or `live` | Not required  | `application/json` |

<Note>
  `X-ProductID: app` is only required for the Momo, XOF, ZAR, and SLE collections API (`/subsidiary/collections/v1/...`). All other APIs do not require it.
</Note>

<Note>
  `X-TenantID` is **not required** for Apple Pay, Google Pay, Virtual Accounts, Refunds, and Chargebacks. All other listed APIs require `X-TenantID` set to `test` (development) or `live` (production).
</Note>

***

## Test vs Live environments

Payaza uses a single API base URL (`https://api.payaza.africa/live/`) for both environments. The `/live/` segment in the URL is a fixed path prefix — it does **not** change between environments. Only the `X-TenantID` header and the API key distinguish test from live.

|              | Test                                    | Live                                     |
| ------------ | --------------------------------------- | ---------------------------------------- |
| `X-TenantID` | `test`                                  | `live`                                   |
| API key      | Generated in **Test Mode** on dashboard | Generated in **Live Mode** on dashboard  |
| Transactions | Not processed or settled                | Real transactions processed and settled  |
| KYB required | No                                      | Yes — must be approved before going live |

<Note>
  You can begin testing immediately after creating your Payaza account. KYB (Know Your Business) verification is only required to access the live environment.
</Note>

***

## Authentication errors

A failed authentication returns this response:

```json theme={null}
{
  "message": "Authentication failed",
  "status": false,
  "retry_count": 0
}
```

| Cause                                            | Fix                                                      |
| ------------------------------------------------ | -------------------------------------------------------- |
| Missing `Authorization` header                   | Add the header to your request                           |
| Raw (non-encoded) API key used                   | Base64-encode your key before use                        |
| Wrong prefix — e.g. `Bearer` instead of `Payaza` | Change the prefix to `Payaza`                            |
| Test key used with `X-TenantID: live`            | Match the key to the correct environment                 |
| Key was regenerated on the dashboard             | Copy the new key, encode it, and update your integration |

***

## What's next

<CardGroup cols={2}>
  <Card title="Getting Started" icon="rocket" href="/guides/getting-started">
    Walk through account setup and make your first API call end-to-end.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/guides/webhooks">
    Receive real-time payment notifications when events happen on your account.
  </Card>

  <Card title="Transfers" icon="money-bill-transfer" href="/guides/transfers">
    Start sending payouts to bank accounts and mobile wallets.
  </Card>

  <Card title="Errors" icon="triangle-exclamation" href="/guides/errors">
    A reference for all API error responses and how to resolve them.
  </Card>
</CardGroup>
