> ## 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.

# Errors

> Error codes returned by the PalPluss API and how to respond to each one.

# Errors

Every error is predictable. Match on `code` — not `message` — to drive your error handling logic.

```json theme={null}
{
  "success": false,
  "error": {
    "message": "Insufficient service wallet balance to cover the transaction fee.",
    "code": "INSUFFICIENT_SERVICE_BALANCE",
    "details": {}
  },
  "requestId": "c1b2a3d4-e5f6-7890-abcd-ef1234567890"
}
```

Log the `requestId` from every error. It is required when contacting support.

***

## HTTP status codes

| Status | Meaning                                       |
| ------ | --------------------------------------------- |
| `200`  | Success                                       |
| `204`  | Success (no body)                             |
| `400`  | Validation error — fix the request            |
| `401`  | Authentication failed                         |
| `402`  | Insufficient balance                          |
| `403`  | Permission denied                             |
| `404`  | Resource not found                            |
| `409`  | Conflict — resource state prevents the action |
| `422`  | Unprocessable entity                          |
| `429`  | Rate limit or abuse protection triggered      |
| `500`  | Internal server error — contact support       |

***

## Error codes

### Authentication

| Code              | HTTP | What it means                               | What to do                                                                    |
| ----------------- | ---- | ------------------------------------------- | ----------------------------------------------------------------------------- |
| `INVALID_API_KEY` | 401  | Key not found, revoked, or header malformed | Verify the key and `Authorization` header format. Do not retry automatically. |
| `TENANT_INACTIVE` | 401  | Account is suspended                        | Contact support to resolve the account status.                                |

### Rate limiting

| Code                  | HTTP | What it means                                        | What to do                                        |
| --------------------- | ---- | ---------------------------------------------------- | ------------------------------------------------- |
| `RATE_LIMIT_EXCEEDED` | 429  | 60 requests/minute exceeded                          | Wait for `Retry-After` seconds, then retry.       |
| `STK_TEMP_BANNED`     | 429  | STK Push temporarily disabled due to suspected abuse | Wait `details.retryAfterSeconds` before retrying. |

`STK_TEMP_BANNED` includes:

```json theme={null}
{
  "retryAfterSeconds": 3600,
  "bannedUntil": "2026-03-01T12:00:00.000Z",
  "scope": "apiKey"
}
```

### Payments

| Code                           | HTTP | What it means                                         | What to do                                                                               |
| ------------------------------ | ---- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `INSUFFICIENT_SERVICE_BALANCE` | 402  | Service wallet too low to cover the fee               | Top up the service wallet, then retry.                                                   |
| `INVALID_PHONE`                | 400  | Phone number format is invalid                        | Send a valid Kenyan number: `07XXXXXXXX`, `01XXXXXXXX`, or `254XXXXXXXXX`.               |
| `CREDENTIAL_NOT_FOUND`         | 404  | Specified `credentialId` does not exist               | Verify the credential ID in the console.                                                 |
| `CREDENTIAL_INACTIVE`          | 409  | Specified credential is disabled                      | Re-enable the credential in the console.                                                 |
| `CHANNEL_NOT_FOUND`            | 400  | Specified `channelId` does not exist for your account | Verify the channel ID in the console, or omit it to use your default channel.            |
| `NO_PAYMENT_CHANNELS`          | 400  | Account has no payment channels configured            | Create at least one payment channel in the console before initiating payments.           |
| `NO_DEFAULT_CHANNEL`           | 400  | Channels exist but none is marked as default          | Set a channel as default in the console, or pass an explicit `channelId` in the request. |

### B2C payouts

| Code                   | HTTP | What it means              | What to do                                      |
| ---------------------- | ---- | -------------------------- | ----------------------------------------------- |
| `ACCOUNT_INACTIVE`     | 403  | Account is not active      | Contact support.                                |
| `KYC_NOT_VERIFIED`     | 403  | KYC approval required      | Submit KYC from the console and await approval. |
| `INSUFFICIENT_FUNDS`   | 409  | B2C wallet balance too low | Top up the B2C wallet, then retry.              |
| `WALLET_INACTIVE`      | 409  | B2C wallet is not active   | Contact support to activate the wallet.         |
| `UNSUPPORTED_CURRENCY` | 400  | Only `KES` is supported    | Send `"currency": "KES"`.                       |

### Transactions

| Code                    | HTTP | What it means                                | What to do                                                       |
| ----------------------- | ---- | -------------------------------------------- | ---------------------------------------------------------------- |
| `TRANSACTION_NOT_FOUND` | 404  | No transaction with that ID for your account | Verify the ID. Check that the key has `transactions:read` scope. |

### Channels

| Code             | HTTP | What it means                                       | What to do                                           |
| ---------------- | ---- | --------------------------------------------------- | ---------------------------------------------------- |
| `CHANNEL_IN_USE` | 409  | Channel has linked transactions — cannot be deleted | Wait for active transactions to settle, then delete. |

***

## Retry guidance

| Status          | Retry? | Notes                               |
| --------------- | ------ | ----------------------------------- |
| `400`           | No     | Fix the request first               |
| `401`           | No     | Fix credentials first               |
| `402`           | No     | Top up wallet first                 |
| `403`           | No     | Resolve account or KYC issue first  |
| `404`           | No     | Resource does not exist             |
| `409`           | No     | Resolve conflict state first        |
| `429`           | Yes    | Wait for `Retry-After` seconds      |
| `500`           | Yes    | Exponential backoff: 1s, 2s, 4s, 8s |
| Network timeout | Yes    | Exponential backoff                 |
