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

# Error Handling

> Check ApiResponse envelopes, read Core error bodies, and handle validation and transport failures with the Python SDK.

export const CtaCallout = props => {
  const {title, buttonLabel, href, trackingEvent, buttonTarget, rel = "noopener noreferrer", children} = props;
  const handleCtaClick = () => {
    if (typeof window === "undefined" || !trackingEvent) {
      return;
    }
    try {
      window.dispatchEvent(new CustomEvent("blnk:docs-cta", {
        detail: {
          name: trackingEvent,
          href
        }
      }));
    } catch {}
    try {
      window.posthog?.capture?.(trackingEvent, {
        href
      });
    } catch {}
    const gaPayload = {
      cta_href: href
    };
    try {
      window.gtag?.("event", trackingEvent, gaPayload);
    } catch {}
    try {
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({
        event: trackingEvent,
        ...gaPayload
      });
    } catch {}
  };
  const isExternal = typeof href === "string" && (/^https?:\/\//i).test(href);
  const target = buttonTarget ?? (isExternal ? "_blank" : undefined);
  const linkRel = isExternal ? rel : undefined;
  return <section className="cta-callout not-prose relative my-8 w-full min-w-0 overflow-hidden rounded-xl border border-zinc-200 p-5 dark:border-white/10">
      <div className="cta-callout-noise" aria-hidden="true" />
      <div className="cta-callout-layout">
        {title ? <div className="cta-callout-title-row">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" width="14" height="14" className="cta-callout-icon shrink-0 text-zinc-800 dark:text-zinc-200" aria-hidden="true">
              <g fill="none" fillRule="nonzero">
                <path d="M28 0v28H0V0h28ZM14.691833333333335 27.134333333333334l-0.012833333333333334 0.0023333333333333335 -0.08283333333333333 0.04083333333333334 -0.023333333333333334 0.004666666666666667 -0.016333333333333335 -0.004666666666666667 -0.08283333333333333 -0.04083333333333334c-0.011666666666666667 -0.004666666666666667 -0.022166666666666668 -0.0011666666666666668 -0.028000000000000004 0.005833333333333334l-0.004666666666666667 0.011666666666666667 -0.019833333333333335 0.49933333333333335 0.005833333333333334 0.023333333333333334 0.011666666666666667 0.015166666666666667 0.12133333333333333 0.08633333333333333 0.0175 0.004666666666666667 0.014000000000000002 -0.004666666666666667 0.12133333333333333 -0.08633333333333333 0.014000000000000002 -0.018666666666666668 0.004666666666666667 -0.019833333333333335 -0.019833333333333335 -0.4981666666666667c-0.0023333333333333335 -0.011666666666666667 -0.0105 -0.019833333333333335 -0.019833333333333335 -0.021Zm0.3091666666666667 -0.13183333333333336 -0.015166666666666667 0.0023333333333333335 -0.21583333333333335 0.1085 -0.011666666666666667 0.011666666666666667 -0.0035000000000000005 0.012833333333333334 0.021 0.5016666666666667 0.005833333333333334 0.014000000000000002 0.009333333333333334 0.008166666666666668 0.23450000000000004 0.1085c0.014000000000000002 0.004666666666666667 0.026833333333333334 0 0.03383333333333334 -0.009333333333333334l0.004666666666666667 -0.016333333333333335 -0.03966666666666667 -0.7163333333333334c-0.0035000000000000005 -0.014000000000000002 -0.011666666666666667 -0.023333333333333334 -0.023333333333333334 -0.025666666666666667Zm-0.8341666666666667 0.0023333333333333335a0.026833333333333334 0.026833333333334334 0 0 0 -0.0315 0.007000000000000001l-0.007000000000000001 0.016333333333333335 -0.03966666666666667 0.7163333333333334c0 0.014000000000000002 0.008166666666666668 0.023333333333333334 0.019833333333333335 0.028000000000000004l0.0175 -0.0023333333333333335 0.23450000000000004 -0.1085 0.011666666666666667 -0.009333333333333334 0.004666666666666667 -0.012833333333333334 0.019833333333333335 -0.5016666666666667 -0.0035000000000000005 -0.014000000000000002 -0.011666666666666667 -0.011666666666666667 -0.21466666666666667 -0.10733333333333334Z" strokeWidth="1.1667" />
                <path fill="currentColor" d="M14 2.916666666666667A1.75 1.75 0 0 1 15.750000000000002 4.666666666666667v6.302333333333334L21.207666666666668 7.816666666666667a1.75 1.75 0 0 1 1.75 3.031L17.5 14l5.457666666666667 3.151166666666667a1.75 1.75 0 0 1 -1.75 3.031l-5.457666666666667 -3.1500000000000004V23.333333333333336a1.75 1.75 0 0 1 -3.5 0v-6.302333333333334L6.792333333333334 20.183333333333337a1.75 1.75 0 1 1 -1.75 -3.031L10.5 14 5.042333333333334 10.848833333333333a1.75 1.75 0 0 1 1.75 -3.031l5.457666666666667 3.1500000000000004V4.666666666666667A1.75 1.75 0 0 1 14 2.916666666666667Z" strokeWidth="1.1667" />
              </g>
            </svg>
            <p className="cta-callout-title min-w-0 font-semibold text-zinc-800 dark:text-zinc-200">
              {title}
            </p>
          </div> : null}
        <div className={`cta-callout-body text-sm leading-normal text-zinc-800 dark:text-zinc-200${title ? " cta-callout-body--indented" : ""}`}>
          {children}
        </div>
        <a href={href} target={target} rel={linkRel} onClick={handleCtaClick} data-docs-cta={trackingEvent || undefined} className="cta-callout-button inline-flex items-center justify-center gap-1 rounded-full bg-white px-3 py-1.5 text-sm font-semibold transition hover:bg-zinc-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/50 dark:bg-white dark:hover:bg-zinc-200">
          {buttonLabel}
          <span className="cta-callout-button-arrow" aria-hidden="true">
            →
          </span>
        </a>
      </div>
    </section>;
};

Every SDK method returns an `ApiResponse`. The SDK does not raise on API failures. Check `status` before you use `data`.

On success, `data` holds the resource. On failure, `status` and `message` describe what went wrong. `error` holds structured Core error details when available. `data` may hold Core's raw error JSON or be `None`.

<Tip>
  Do not wrap SDK calls in `try/except` for API failures. `blnk_init` raises `ValueError` only when `base_url` is missing.
</Tip>

***

## Parse the response

Read the envelope first. Use `status` to classify the failure, then read the field that carries detail for that type.

```python wrap theme={"system"}
from dataclasses import dataclass
from typing import Any, Optional

@dataclass
class BlnkApiErrorDetail:
    code: str
    message: str
    details: Optional[Any] = None

@dataclass
class ApiResponse:
    status: int
    message: str
    data: Any
    error: Optional[BlnkApiErrorDetail] = None
```

| Property  | Contains                                                                        |
| :-------- | :------------------------------------------------------------------------------ |
| `status`  | HTTP-style codes: 2xx success, 4xx client error, etc.                           |
| `data`    | Success body, or Core error JSON on rejection. May be `None`.                   |
| `error`   | Structured error parsed from Core's `error_detail`. Use `error.code` for logic. |
| `message` | Human-readable description. For logs and UI only. Do not use for logic.         |

***

## How to handle errors

<Steps>
  <Step title="Check status">
    Confirm success before you use `data`. On every call, check that `status` is in the 2xx range for the method you called.

    ```python Error handling wrap theme={"system"}
    response = blnk.transactions.get("txn_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94")

    if response.status < 200 or response.status >= 300:
        error_code = response.error.code if response.error else None

        if response.status == 404:
            # Resource not found: check error_code (e.g. TXN_NOT_FOUND)
            pass
        elif response.status in (401, 403):
            # Auth or scope failure: check the API key
            pass
        else:
            # Log status, error_code, and response.message
            pass
    else:
        # Use response.data
        pass
    ```
  </Step>

  <Step title="Read the error detail">
    Use the field that matches the failure type:

    * **Core rejection** (`status` is a Core HTTP error and `data` is set): read `response.error.code` for the code Core returned.
    * **SDK validation** (`status == 400` and `data` is `None`): read `response.message` and fix the payload before retrying.

    Route on `response.status` when you do not need code-level logic (401, 404, 409, 5xx).
  </Step>

  <Step title="Configure transport handling">
    When the SDK cannot reach Core or the request times out, you get `status: 500` and `data: None`.

    Configure timeout and logging in [your SDK client](/sdks/python/start/using-the-sdk#timeouts-and-retries) to investigate these failures.
  </Step>
</Steps>

***

## Core errors

When Core rejects a request, the SDK wraps the failure in an `ApiResponse`. It sets `status` to Core's HTTP status, `message` to the error message, `data` to Core's JSON error body, and `error` to structured details parsed from `error_detail`.

On Core 0.15.0 and later, a rejected request looks like this:

```python 404 Not Found wrap theme={"system"}
response = blnk.transactions.get("txn_missing")

# response:
# ApiResponse(
#   status=404,
#   message="transaction not found",
#   data={
#     "error": "transaction not found",
#     "error_detail": {
#       "code": "TXN_NOT_FOUND",
#       "message": "transaction not found",
#       "details": {},
#     },
#   },
#   error=BlnkApiErrorDetail(
#     code="TXN_NOT_FOUND",
#     message="transaction not found",
#     details={},
#   ),
# )
```

Read the failure from `response.error.code`. Use `response.status` to choose a broad response. Treat `response.error.message` as display text; Core may change wording between releases. On older Core versions, `response.error.code` may be `UNKNOWN`.

| Status         | When it happens                                          | What to do                                                            |
| :------------- | :------------------------------------------------------- | :-------------------------------------------------------------------- |
| `404`          | Resource ID or path does not exist                       | Check `response.error.code` (e.g. `TXN_NOT_FOUND`, `IDT_NOT_FOUND`)   |
| `401` or `403` | API key, scope, or permission failure                    | Check the key, scopes, and whether the method requires the master key |
| `409`          | Conflict (duplicate reference, lock, or in-progress job) | Retry only if the operation is safe to repeat                         |
| `400`          | Core rejected the payload                                | Fix the request body before retrying                                  |
| `5xx`          | Core or upstream failure                                 | Retry later and check Core logs                                       |

<Warning>
  Do not match exact `error` strings in application logic. Message text can change. Prefer `response.error.code` for routing and `response.error.message` for user-facing messages only. See the [0.15.0 migration guide](/changelog/v15-migration) and [API error codes](/advanced/error-codes).
</Warning>

***

## Client-side validation

Some methods validate input before sending a request. When validation fails, Core never receives the call.

| Field     | Value                                                                  |
| :-------- | :--------------------------------------------------------------------- |
| `status`  | `400`                                                                  |
| `message` | Validation error string, e.g. `reference field must be a valid string` |
| `data`    | `None`                                                                 |
| `error`   | `None`                                                                 |

<Tip>
  Each [SDK method page](/sdks/python/ledgers/create-ledger) lists required fields for that call.
</Tip>

***

## Transport failures

When the SDK cannot reach Core or the request times out, you get `status: 500`, `data: None`, and a `message` describing the failure. Configure timeout and logging in [Using the SDK](/sdks/python/start/using-the-sdk#timeouts-and-retries).

When debugging transport failures, log `status`, `message`, and the endpoint you called.

***

## Related docs

<CardGroup cols={2}>
  <Card title="Using the SDK" icon="code" href="/sdks/python/start/using-the-sdk">
    Timeouts, retries, and logging.
  </Card>

  <Card title="0.15.0 migration" icon="arrow-right" href="/changelog/v15-migration">
    Error codes, inflight queuing, and reconciliation changes.
  </Card>

  <Card title="Quick start" icon="rocket" href="/sdks/python/start/quick-start">
    Install the SDK and create your first transaction.
  </Card>

  <Card title="Changelog" icon="scroll-text" href="/changelog/blnk-py">
    Python SDK releases and version history.
  </Card>
</CardGroup>

***

## Need help?

We are very happy to help you make the most of Blnk, regardless of whether it is your first time or you are switching from another tool.

To ask questions or discuss issues, please [contact us](mailto:support@blnkfinance.com) or [join our Discord community](https://discord.gg/7WNv94zPpx).

<CtaCallout title="Connect your ledger to Blnk Cloud" href="https://cloud.blnkfinance.com/auth/sign-up?utm_source=blnk_docs&utm_medium=documentation&utm_campaign=need-help" buttonLabel="Open Blnk Cloud" trackingEvent="clicked_cloud_signup">
  Sign up and manage your ledger with our back-office dashboard. You can invite teammates to collaborate and manage your ledger operations directly from the dashboard.
</CtaCallout>
