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

# Authentication

> Set up your API key and authenticate every request to the PalPluss API.

# Authentication

Every request must be authenticated. This takes seconds to set up.

Two separate authentication layers exist:

| Layer             | Who                | How                                                                      |
| ----------------- | ------------------ | ------------------------------------------------------------------------ |
| **Console**       | You (the merchant) | Email + password at [console.palpluss.com](https://console.palpluss.com) |
| **Developer API** | Your application   | HTTP Basic Auth with an API key                                          |

Your application never uses your console password. It uses an **API key** you generate inside the console.

***

## Step 1 — Create your account

Register at [console.palpluss.com](https://console.palpluss.com). After email verification and KYC approval your account is active.

<Note>
  KYC is required before initiating live STK Push or B2C transactions. You can generate API keys and test immediately after registration.
</Note>

***

## Step 2 — Generate an API key

1. Log in to [console.palpluss.com](https://console.palpluss.com)
2. Go to **Settings → API Keys**
3. Click **Create API Key**, name it, and select the required scopes
4. Copy the key — it is shown **only once**

```
pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

<Warning>
  Store your API key in environment variables or a secrets manager — never in source code or version control. Revoke and reissue immediately if compromised.
</Warning>

***

## Step 3 — Authenticate requests

Set your API key as the Basic Auth username. Leave the password empty.

<Tip>
  **Trying endpoints from these docs?** The API playground shows two fields:
  paste your API key into the **username** field and leave the **password**
  field empty — it is ignored by PalPluss. That's it, you can copy-paste and
  send requests directly.
</Tip>

```
Authorization: Basic <base64(YOUR_API_KEY:)>
```

Note the trailing colon — it encodes an empty password. Most HTTP clients handle this automatically.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.palpluss.com/v1/wallets/service/balance \
    -u "pk_live_xxxxxxxxxxxxxxxxxxxx:"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.palpluss.com/v1/wallets/service/balance", {
    headers: {
      Authorization: "Basic " + Buffer.from("pk_live_xxxxxxxxxxxxxxxxxxxx:").toString("base64"),
    },
  });
  const data = await response.json();
  ```

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

  response = requests.get(
      "https://api.palpluss.com/v1/wallets/service/balance",
      auth=("pk_live_xxxxxxxxxxxxxxxxxxxx", ""),
  )
  data = response.json()
  ```

  ```php PHP theme={null}
  $apiKey = "pk_live_xxxxxxxxxxxxxxxxxxxx";
  $ch = curl_init("https://api.palpluss.com/v1/wallets/service/balance");
  curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  curl_setopt($ch, CURLOPT_USERPWD, "$apiKey:");
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $response = json_decode(curl_exec($ch), true);
  ```

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

  import (
    "encoding/base64"
    "fmt"
    "net/http"
  )

  func main() {
    apiKey := "pk_live_xxxxxxxxxxxxxxxxxxxx"
    token := base64.StdEncoding.EncodeToString([]byte(apiKey + ":"))

    req, _ := http.NewRequest("GET", "https://api.palpluss.com/v1/wallets/service/balance", nil)
    req.Header.Set("Authorization", "Basic "+token)

    client := &http.Client{}
    resp, _ := client.Do(req)
    fmt.Println(resp.Status)
  }
  ```
</CodeGroup>

***

## How it works

```
Your server                  PalPluss API
─────────                    ────────────
  Request + Authorization header
────────────────────────────────────►
                                         Decode base64
                                         Lookup API key
                                         Verify account active
                                         Check key scopes
  200 OK / 401 Unauthorized
◄────────────────────────────────────
```

1. Send `Authorization: Basic <base64(key:)>` on every request
2. PalPluss decodes the header and looks up the key
3. Valid key + active account → request proceeds
4. Invalid, revoked, or suspended → `401`

***

## API key scopes

| Scope               | What it allows                              |
| ------------------- | ------------------------------------------- |
| `payments:write`    | Initiate STK Push payments                  |
| `b2c:write`         | Send B2C payouts                            |
| `transactions:read` | List and retrieve transactions              |
| `wallets:read`      | Read wallet balances                        |
| `wallets:write`     | Top up service wallet                       |
| `channels:write`    | Create, update, and delete payment channels |

Use the **minimum scopes** your integration needs.

***

## Authentication errors

| HTTP  | Code                 | Reason                                                         |
| ----- | -------------------- | -------------------------------------------------------------- |
| `401` | `INVALID_API_KEY`    | Key not found, revoked, or `Authorization` header is malformed |
| `401` | `TENANT_INACTIVE`    | Account linked to this key is suspended                        |
| `403` | `INSUFFICIENT_SCOPE` | Key lacks the scope required for this endpoint                 |

```json theme={null}
{
  "success": false,
  "error": {
    "message": "Invalid or revoked API key.",
    "code": "INVALID_API_KEY",
    "details": {}
  },
  "requestId": "c1b2a3d4-e5f6-7890-abcd-ef1234567890"
}
```

***

## Rate limiting

**60 requests per minute per API key.** Every response includes:

| Header                  | Description                                       |
| ----------------------- | ------------------------------------------------- |
| `x-ratelimit-limit`     | Maximum requests per minute (always `60`)         |
| `x-ratelimit-remaining` | Requests remaining in the current window          |
| `x-ratelimit-reset`     | Unix timestamp when the window resets             |
| `Retry-After`           | Seconds to wait — present only on `429` responses |

***

## Key rotation

* **Create first, then revoke** — update your application before revoking the old key. Revoking first causes downtime.
* **One key per environment** — separate keys for development, staging, and production.
* **One key per service** — revoke one without affecting others.
* **Rotate regularly** — every 90 days at minimum; immediately if a key is exposed.
* **Audit periodically** — revoke keys that are no longer in use.
