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

# Troubleshoot Your Payzah Integration: Errors and Fixes

> Diagnose the most common Payzah integration problems by symptom, understand what each error code actually means, and apply the fix without contacting support.

Most integration problems fall into a small number of recurring patterns. This page is organised by **symptom** — start with what you are seeing, then follow the fix. For the complete list of codes, see the [Response Codes](/docs/api-reference/response-codes) reference.

<Tip>
  Before troubleshooting anything, confirm you are hitting the environment you think you are. Pointing test credentials at production endpoints — or the reverse — is the single most common cause of unexplained failures.
</Tip>

## Diagnose by Symptom

### Authentication and Setup

| Symptom                                     | Likely cause                                                  | Fix                                                                                                                      |
| ------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Every request returns code `10014`          | Private key is not Base64-encoded, or has trailing whitespace | Encode with `base64_encode($privateKey)`. Trim the key string — a stray newline from a copied `.env` value will break it |
| Requests worked in test, fail in production | Using the test key against production endpoints               | Test and production keys are different. Store both, select by environment                                                |
| Code `10013` on every call                  | Body is being sent as form data, not JSON                     | Set `Content-Type: application/json` and serialise the body with `json_encode` / `JSON.stringify`                        |
| Code `10015` when using `payment_type=2`    | Account not enabled for direct Credit Card                    | Use `payment_type=3` (transit page, includes cards) or contact Payzah support to enable the permission                   |

### Payment Initialization

| Symptom                 | Likely cause                                      | Fix                                                                                                 |
| ----------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Code `10001`            | `trackid` contains special characters             | Use alphanumeric only. Strip hyphens, slashes, and spaces if your order IDs contain them            |
| Code `10002` or `10004` | `trackid` or `amount` missing                     | Check field names are lowercase and exactly as documented. A typo silently becomes a missing field  |
| Code `10003`            | `amount` is malformed                             | Send a plain decimal string, e.g. `"11.250"`. No currency symbols, commas, or spaces                |
| Code `10005` / `10006`  | `success_url` or `error_url` missing              | Both are mandatory on every initialization request, even if they point to the same handler          |
| Codes `10007`–`10011`   | A `udf1`–`udf5` field contains special characters | Sanitise UDF values before sending. These fields are alphanumeric only                              |
| `transit_url` is empty  | You sent `payment_type` `1` or `2`                | Direct integration populates `direct_url` instead. Read the correct field for your `payment_type`   |
| `direct_url` is empty   | You sent `payment_type` `3`                       | Transit integration populates `transit_url`. See the [comparison table](/docs/guides/direct-integration) |

### Status Checks and Refunds

| Symptom                                       | Likely cause                                                    | Fix                                                                                                                               |
| --------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Code `10012` on status check                  | `trackid` and `payment_id` do not match a real transaction      | Both must come from the same transaction. `payment_id` is the `PaymentID` from the initialization response, not your own order ID |
| Code `10012` on refund                        | `trackid` and `refrence_code` do not match a successful payment | Confirm the original transaction is `CAPTURED` first. Refunds against voided or uncaptured payments will not be found             |
| Refund returns `status: false` but HTTP 200   | Treating the HTTP status as the result                          | Always read the `status` field. A `200` with `status: false` means nothing was refunded                                           |
| Refund rejected with a valid reference        | Field name misspelled as `reference_code`                       | The field is `refrence_code` — note the spelling                                                                                  |
| Customer charged but your order never updated | Customer closed the tab before the redirect fired               | Do not rely on the redirect alone. Poll the status endpoint for any order left pending                                            |

## What to Do for Each Payment Status

A redirect to your `success_url` does **not** confirm payment. Always read `paymentStatus` and act accordingly.

| Status           | Fulfil the order? | Action                                                                                |
| ---------------- | ----------------- | ------------------------------------------------------------------------------------- |
| `CAPTURED`       | Yes               | Funds are secured. Fulfil and mark the order paid                                     |
| `NOT CAPTURED`   | No                | Authorised but not captured. Investigate before acting — do not ship                  |
| `VOIDED`         | No                | No funds were taken. Notify the customer and allow a retry                            |
| `CANCELED`       | No                | Customer abandoned checkout. Allow a retry; no action needed                          |
| `DENIED BY RISK` | No                | Blocked by risk controls. Do not retry automatically — direct the customer to support |
| `HOST TIMEOUT`   | No                | Outcome unknown. Hold the order and confirm manually before refunding or fulfilling   |

<Warning>
  `HOST TIMEOUT` is the most dangerous status to mishandle. Never auto-refund and never auto-fulfil on a timeout — confirm the real outcome in your processor portal or with Payzah support first.
</Warning>

## Still Stuck?

When contacting Payzah support, include the following so the issue can be traced without reproducing it:

* The `trackid` and `PaymentID` for the affected transaction
* The full raw response body, including the `code` and `message` fields
* The environment (test or production) and the exact endpoint URL you called
* The approximate timestamp of the request

<Note>
  Never include your private key, card numbers, or customer payment details in a support ticket. Payzah will never ask for your private key.
</Note>
