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

# Errors

> How the API signals failure, and what to do about it.

The API uses standard HTTP status codes. The response body for an
error is JSON and follows Symfony's [RFC 7807 Problem
Details](https://www.rfc-editor.org/rfc/rfc7807) shape with one or two
extensions for validation failures.

## Status codes

| Code                        | Used when                                                             |
| --------------------------- | --------------------------------------------------------------------- |
| `200 OK`                    | The request succeeded. Most successful writes also return `200`.      |
| `400 Bad Request`           | The body could not be parsed or a non-validation error occurred.      |
| `401 Unauthorized`          | Missing, malformed, or revoked secret key.                            |
| `403 Forbidden`             | The key is valid but the action is not permitted.                     |
| `404 Not Found`             | The resource does not exist on this workspace.                        |
| `409 Conflict`              | The resource already exists or is in a state that blocks this action. |
| `422 Unprocessable Entity`  | One or more fields failed validation.                                 |
| `500 Internal Server Error` | Something broke on our side; safe to retry idempotent requests.       |

## Error body

```json theme={null}
{
  "type": "https://tools.ietf.org/html/rfc2616#section-10",
  "title": "An error occurred",
  "status": 404,
  "detail": "ugwo.error.not_found"
}
```

The `detail` field is a translation key on most errors. The dashboard
maps these to human strings; when integrating server-to-server, treat
the status code as the source of truth and use `detail` for logging.

## Validation errors

When a request fails validation, the response is `422` with a
`violations` array describing each offending field:

```json theme={null}
{
  "title": "Validation Failed",
  "status": 422,
  "detail": "amount: The amount must be an integer.",
  "violations": [
    {
      "propertyPath": "amount",
      "title": "The amount must be an integer.",
      "code": "ba785a8c-82cb-4283-967c-3cf342181b40"
    }
  ]
}
```

`propertyPath` matches the request-body field name.

## Common pitfalls

<AccordionGroup>
  <Accordion title="401 on every request, even with a valid key">
    Make sure the header is `Authorization: Bearer <key>`. A trailing
    newline, a `sk_` prefix missing, or whitespace will all reject.
    Also: did you regenerate the key in the dashboard recently?
  </Accordion>

  <Accordion title="404 when fetching an ugwo you just created">
    Ugwo IDs are scoped to the workspace that owns the key. If you
    created the ugwo with a test key, you cannot fetch it with a live
    key.
  </Accordion>

  <Accordion title="422 with `currency` violation">
    `currency` must be one of the [supported ISO-4217
    codes](/concepts#currencies) (e.g. `NGN`, `GHS`, `KES`). The full
    list lives on the Kwugwo `Currency` enum.
  </Accordion>

  <Accordion title="`medium` validation fails">
    Allowed values are `bank_transfer`, `mobile_money`, and `ussd`.
    The medium must also be enabled for the currency on the
    workspace's PSPs or checkout; a typo here will surface as a
    routing failure on the activity, not on ugwo creation.
  </Accordion>
</AccordionGroup>

## Retries

The API does not yet support idempotency keys, so retry only on
network errors or `5xx` responses, and only for `GET` /
state-checking calls. For `POST` calls that create an ugwo or
activity, treat any ambiguous failure as "needs operator review"
rather than auto-retrying; you may otherwise charge a customer twice.
