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

# API Error Codes, Response Formats, and Troubleshooting

> Reference for all Nexenergie API HTTP status codes and JSON error response formats, with causes and recommended fixes for each error type.

When a request fails, the Nexenergie API returns a standard JSON error body alongside an HTTP status code. Reading the `detail` field usually tells you exactly what went wrong — it contains a human-readable description of the specific failure, making it straightforward to distinguish between a bad parameter, a missing forecast, or an authentication problem without referring to this page.

## Error Response Format

All error responses share a consistent JSON envelope, regardless of the status code:

```json theme={null}
{
  "error": "not_found",
  "detail": "Forecast for 2024-11-20 is not yet available",
  "status": 404
}
```

<ResponseField name="error" type="string">
  A short, machine-readable error code in `snake_case` (e.g., `"not_found"`, `"unauthorized"`, `"validation_error"`). Use this field for programmatic error handling and branching logic.
</ResponseField>

<ResponseField name="detail" type="string">
  A human-readable description of the error, specific to the failing request. This field describes what was wrong and often suggests how to fix it. In validation errors (`422`), this may be a structured array of field-level messages.
</ResponseField>

<ResponseField name="status" type="integer">
  The HTTP status code, mirrored in the response body for convenience when your HTTP client abstracts away status codes.
</ResponseField>

## HTTP Status Codes

The Nexenergie API uses standard HTTP status codes. The table below covers every code you may encounter, its meaning in the context of this API, and the recommended action.

| Code  | Name                  | Meaning                                             | Typical Cause                                                                  | Suggested Fix                                                                      |
| ----- | --------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| `200` | OK                    | Request succeeded                                   | —                                                                              | No action needed                                                                   |
| `400` | Bad Request           | The request was syntactically invalid               | Malformed date string, unknown query parameter, or unsupported session number  | Check request parameters against the endpoint reference                            |
| `401` | Unauthorized          | Authentication credential is missing or invalid     | No `Authorization` header, expired token, or revoked API key                   | Re-authenticate via `POST /auth/token` or verify your API key is active            |
| `403` | Forbidden             | Credential is valid but lacks permission            | Accessing a resource outside your subscription tier or another tenant's data   | Check your plan entitlements or contact Nexenergie support                         |
| `404` | Not Found             | The requested resource does not exist               | Forecast not yet generated for the requested date, or an invalid endpoint path | Verify the date is within the available range; see [Common Errors](#common-errors) |
| `422` | Unprocessable Entity  | Request body or parameters failed schema validation | Missing required field, wrong data type, or value outside the allowed range    | Read the `detail` field for the list of failing fields and constraints             |
| `429` | Too Many Requests     | Rate limit exceeded                                 | More than 60 requests/minute on a single key                                   | Wait until `X-RateLimit-Reset`, then retry; see [Common Errors](#common-errors)    |
| `500` | Internal Server Error | An unexpected error occurred on the server          | Transient infrastructure issue                                                 | Retry with exponential backoff; contact support if the error persists              |

<Info>
  `4xx` errors indicate a problem with the request and will not resolve by retrying without a change. `5xx` errors indicate a server-side problem and are safe to retry.
</Info>

## Common Errors

<AccordionGroup>
  <Accordion title="401: My token keeps expiring">
    Tokens issued by `POST /auth/token` are valid for **86 400 seconds (24 hours)**. After that window, every request returns `401 Unauthorized` until you obtain a fresh token.

    The most robust fix is to build automatic re-authentication into your HTTP client. The snippet below wraps every request and transparently refreshes the token whenever a `401` is received:

    ```python Python theme={null}
    import httpx
    import time

    TOKEN_URL = "https://app.nexenergie.ai/api/v1/auth/token"
    API_BASE  = "https://app.nexenergie.ai/api/v1"

    def fetch_token(username: str, password: str) -> tuple[str, float]:
        resp = httpx.post(
            TOKEN_URL,
            data={"username": username, "password": password},
        )
        resp.raise_for_status()
        data = resp.json()
        expiry = time.time() + data["expires_in"] - 60  # 60-second safety margin
        return data["access_token"], expiry

    class AutoRefreshClient:
        def __init__(self, username: str, password: str):
            self.username = username
            self.password = password
            self.token, self.expiry = fetch_token(username, password)

        def _headers(self) -> dict:
            if time.time() >= self.expiry:
                self.token, self.expiry = fetch_token(self.username, self.password)
            return {"Authorization": f"Bearer {self.token}"}

        def request(self, method: str, path: str, **kwargs) -> httpx.Response:
            resp = httpx.request(method, f"{API_BASE}{path}", headers=self._headers(), **kwargs)
            if resp.status_code == 401:
                # Force a refresh in case the token was revoked server-side
                self.token, self.expiry = fetch_token(self.username, self.password)
                resp = httpx.request(method, f"{API_BASE}{path}", headers=self._headers(), **kwargs)
            resp.raise_for_status()
            return resp
    ```

    If you prefer not to manage token lifecycle, generate a long-lived **API key** from your dashboard — API keys do not expire unless explicitly revoked.
  </Accordion>

  <Accordion title="404: Forecast not available for this date">
    The Nexenergie API returns `404 Not Found` when a forecast has not yet been generated for the requested date. Forecasts follow OMIE publication schedules:

    * **Day-ahead forecasts** are published **D-1** (the day before delivery), typically after the OMIE day-ahead auction closes at 12:00 CET. Requesting a forecast for today or a future date before the model has run will return `404`.
    * **Intraday session forecasts** (sessions 1–3) are published incrementally on the delivery day, according to the OMIE intraday session schedule.

    **Steps to resolve:**

    1. Check that the requested date is in the past or has passed the relevant publication cutoff.
    2. Query the `/forecasts/available-dates` endpoint to retrieve the list of dates for which forecasts are currently accessible:

    ```bash cURL theme={null}
    curl --request GET \
      --url 'https://app.nexenergie.ai/api/v1/forecasts/available-dates' \
      --header 'Authorization: Bearer <token>'
    ```

    3. Ensure your date format matches the expected `YYYY-MM-DD` ISO 8601 format. A malformed date string triggers a `400 Bad Request`, not `404`.

    If you consistently receive `404` for dates that should be available, contact Nexenergie support — it may indicate a model run failure for that date.
  </Accordion>

  <Accordion title="429: Rate limit exceeded">
    The default rate limit is **60 requests per minute** per API key or token. When the limit is exceeded, all subsequent requests in that window return `429 Too Many Requests` until the window resets.

    Use the response headers to determine when you can resume:

    | Header                  | Value                                 |
    | ----------------------- | ------------------------------------- |
    | `X-RateLimit-Limit`     | `60`                                  |
    | `X-RateLimit-Remaining` | `0`                                   |
    | `X-RateLimit-Reset`     | Unix timestamp when the window resets |
    | `Retry-After`           | Seconds to wait before retrying       |

    The safest strategy is **exponential backoff with jitter**, which prevents multiple clients from hammering the API simultaneously after a shared reset:

    ```python Python theme={null}
    import httpx
    import time
    import random

    def get_with_backoff(
        url: str,
        headers: dict,
        max_retries: int = 5,
    ) -> httpx.Response:
        for attempt in range(max_retries):
            response = httpx.get(url, headers=headers)

            if response.status_code == 429:
                # Respect the Retry-After header when present, otherwise use backoff
                retry_after = response.headers.get("Retry-After")
                if retry_after:
                    wait = float(retry_after)
                else:
                    wait = (2 ** attempt) + random.uniform(0, 1)

                print(f"Rate limited. Waiting {wait:.1f}s before retry {attempt + 1}/{max_retries}.")
                time.sleep(wait)
                continue

            response.raise_for_status()
            return response

        raise RuntimeError(f"Request failed after {max_retries} retries due to rate limiting.")
    ```

    If your workload regularly approaches or exceeds the default limit, contact Nexenergie to discuss elevated rate limits for your account.
  </Accordion>
</AccordionGroup>

<Note>
  For persistent `500 Internal Server Error` responses that do not resolve after retrying, please contact Nexenergie support at [support@nexenergie.ai](mailto:support@nexenergie.ai) and include the request URL, timestamp, and the `detail` field from the error response to help us investigate quickly.
</Note>
