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

# Error Codes — Judit API

> Consolidated list of HTTP codes, application_error, internal exceptions and troubleshooting for the Judit API. Authentication, validation, secrecy, court failures, rate limit and how to resolve each.

> 🤖 This is the single error reference for the Judit API: HTTP 2xx/4xx/5xx codes, internal exceptions (`name`), `application_error` returned in payload (even when HTTP is 200), and practical troubleshooting.

## Anatomy of an error

The Judit API distinguishes two error types:

<CardGroup cols={2}>
  <Card title="Transport errors (HTTP 4xx/5xx)" icon="plug-circle-xmark">
    The request failed on basic validation, authentication, authorization or server side. The payload follows `{ error: { name, message, data } }`.
  </Card>

  <Card title="Application errors (response_type: application_error)" icon="circle-exclamation">
    HTTP is `200`, but the query did not return the expected object. It can be "lawsuit not found", "homonym", secrecy, etc. Comes inside `responses[].response_type = application_error`.
  </Card>
</CardGroup>

## HTTP Status Codes

The API uses standard HTTP conventions.

### Success (2xx)

| HTTP | Meaning | When it happens |
| :- | :- | :- |
| `200` | **OK** | Request processed and data returned successfully. |
| `201` | **Created** | Resource (e.g. new tracker, new request) created successfully. |
| `202` | **Accepted** | Request accepted and queued for asynchronous processing. |

### Client Errors (4xx)

| HTTP | Typical `error.message` | When it happens | How to resolve |
| :- | :- | :- | :- |
| `400` | `BAD_REQUEST` | Malformed payload, missing required fields, invalid enum. | Check `error.data` — lists failed validations. See [Lawsuit Schema](/en/schemas/lawsuit-object). |
| `401` | `UNAUTHORIZED` | `api-key` missing or invalid. | Check the `api-key` header (no space, no `Bearer`). See [Authentication](/en/introduction/authentication). |
| `403` | `FORBIDDEN` | `api-key` is valid but lacks permission (e.g. unbought feature, secrecy without credential). | Verify the feature is enabled in your plan and that there's a court credential in the [Vault](/en/essentials/cofre-de-credenciais). |
| `404` | `NOT_FOUND` | Resource doesn't exist — invalid `request_id`/`tracking_id`, CNJ not in datalake. | Confirm the ID. For new CNJs, fire a previous async query via [`POST /requests`](/en/requests/requests). |
| `422` | `UNPROCESSABLE_ENTITY` | Valid structure but semantically invalid (e.g. `search_type` incompatible with `response_type`). | See the table at [Search Types](/en/requests/requests#supported-search-types). |
| `429` | `TOO_MANY_REQUESTS` | Plan rate limit exceeded. | Implement exponential backoff. Check `X-RateLimit-*` headers in response. |

### Server Errors (5xx)

| HTTP | Typical `error.message` | When it happens | How to resolve |
| :- | :- | :- | :- |
| `500` | `INTERNAL_SERVER_ERROR` | Unexpected Judit-side failure. | Retry with backoff. If it persists, open a ticket at `atendimento@judit.io` referencing the `request_id`. |
| `502` / `504` | `BAD_GATEWAY` / `GATEWAY_TIMEOUT` | Originating court down or timeout. Common in synchronous queries. | Retry — if it persists, async flow via [`POST /requests`](/en/requests/requests) is more resilient. |
| `503` | `SERVICE_UNAVAILABLE` | Maintenance. | Wait a few minutes. Watch status.judit.io (if enabled). |

## HTTP error payload structure

Regardless of status (400 or 500), the response body always follows this contract:

```json theme={null}
{
    "error": {
        "name": "HttpBadRequestError",
        "message": "BAD_REQUEST",
        "data": [
            {
                "field": "search.search_key",
                "rule": "required",
                "message": "search_key is required"
            }
        ]
    }
}
```

| Field | Description |
| :- | :- |
| `error.name` | Exception code (e.g. `HttpBadRequestError`, `HttpNotFoundError`, `HttpUnauthorizedError`, `USER_NOT_FOUND`). Use in your `switch`/`case` for automation. |
| `error.message` | Friendly category (`BAD_REQUEST`, `UNAUTHORIZED`, etc.). |
| `error.data` | Details — array of validations or string with specific message. Useful for displaying form validations to the end user. |

## Internal codes (`error.name`)

Use these values for programmatic automation:

### Authentication and permissions

| Code (`name`) | HTTP | Common cause |
| :- | :- | :- |
| `USER_NOT_FOUND` | 401 | API key not sent or revoked. |
| `INSUFFICIENT_PERMISSIONS` | 403 | Attempt to use a module blocked in your plan. |
| `HttpUnauthorizedError` | 401 | Generic — invalid key. |

### Validation and processing

| Code (`name`) | HTTP | Common cause |
| :- | :- | :- |
| `HttpBadRequestError` | 400 | Malformed JSON or missing fields. |
| `RESOURCE_NOT_FOUND` | 404 | CNJ not yet captured. |
| `REQUEST_NOT_FOUND` | 404 | Queried `request_id` does not exist. |
| `PROCESSING_ERROR` | 422 | Bot failed to read court data. |

## Application errors (`application_error`)

When you receive `response_type: application_error` instead of the expected payload, the query was successfully processed, but the result is a logical exception.

| `response_data.code` | Meaning | When it happens | How to resolve |
| :- | :- | :- | :- |
| `LAWSUIT_NOT_FOUND` | Lawsuit not found. | Non-existent CNJ or inaccessible. | Verify the number and tribunal. May be under secrecy — add `customer_key` (Vault). |
| `ENTITY_NOT_FOUND` | Person/company not found. | CPF/CNPJ doesn't appear in datalake or court. | Try `on_demand: true` to force court fetch. |
| `WARRANT_NOT_FOUND` | Warrant not found in BNMP. | No warrants for the given document. | Try `name` or `rji` search if applicable. |
| `EXECUTION_NOT_FOUND` | Penal execution not found. | No records for the document. | Check the originating court (Penal Execution Justice). |
| `INVALID_CREDENTIAL` | Vault credential invalid or expired. | Court login/token expired. | Update the credential at [Vault](/en/essentials/cofre-de-credenciais). |
| `CRAWLER_ERROR` | Court collection failed. | Court down, captcha failure, layout change. | Retry. If it persists, automatic fallback flow kicks in. |
| `RATE_LIMIT_TRIBUNAL` | Tribunal-imposed limit. | Court blocked further collection. | Judit retries automatically next cycle. Use a higher `cache_ttl_in_days`. |
| `SECRECY_RESTRICTED` | Secret lawsuit without associated credential. | `secrecy_level > 0` and `api-key` has no court credential. | Register a credential at [Vault](/en/essentials/cofre-de-credenciais) and reference via `customer_key`. |
| `HOMONYM_AMBIGUOUS` | Name search returned homonyms. | Common name without extra criteria. | Refine via CPF/CNPJ or apply filters (`tribunals`, `state`). |

### application\_error example

```json theme={null}
{
    "request_id": "87d9f7bf-0071-41ee-a721-e6e1b4082bc9",
    "responses": [
        {
            "response_id": "b6c1a4f0-1234-5678-9abc-def012345678",
            "response_type": "application_error",
            "response_data": {
                "code": "LAWSUIT_NOT_FOUND",
                "message": "Lawsuit 0000000-00.0000.0.00.0000 not found in datalake or court."
            }
        }
    ]
}
```

## Centralized handler (ready-to-use code)

Create a single interceptor to log and handle Judit API errors.

<CodeGroup>
  ```python Python theme={null}
  import requests, os

  def handle_judit_error(response: requests.Response) -> None:
      """Decode and handle Judit API errors."""
      if response.status_code < 400:
          return
      try:
          payload = response.json()
          error_block = payload.get('error', {})
          error_name = error_block.get('name', 'UNKNOWN_ERROR')
          error_details = error_block.get('data', [])
          print(f"❌ HTTP {response.status_code}: {error_name}")
          if error_details:
              print("Details:")
              for detail in error_details:
                  print(f"  - {detail}")
          if error_name == 'USER_NOT_FOUND':
              raise PermissionError("Invalid API key. Check JUDIT_API_KEY.")
          if response.status_code == 429:
              print("⚠️ Rate limit exceeded. Trigger backoff.")
      except ValueError:
          print(f"Critical error {response.status_code}: response is not valid JSON.")
          print(response.text)
  ```

  ```javascript Node.js theme={null}
  async function handleJuditError(response) {
    if (response.ok) return;
    try {
      const payload = await response.json();
      const errorBlock = payload.error || {};
      const errorName = errorBlock.name || 'UNKNOWN_ERROR';
      const errorDetails = errorBlock.data || [];
      console.error(`❌ HTTP ${response.status}: ${errorName}`);
      if (errorDetails.length > 0) {
        console.error("Details:");
        errorDetails.forEach(detail => console.error(`  - ${JSON.stringify(detail)}`));
      }
      if (errorName === 'USER_NOT_FOUND') {
        throw new Error("Invalid API key. Check JUDIT_API_KEY.");
      }
      if (response.status === 429) {
        console.warn("⚠️ Rate limit exceeded. Trigger backoff.");
      }
    } catch (e) {
      if (e.name !== 'SyntaxError') throw e;
      console.error(`Critical error ${response.status}: response is not valid JSON.`);
    }
  }
  ```
</CodeGroup>

## Handling patterns

<AccordionGroup>
  <Accordion title="Exponential backoff on 429 and 5xx">
    Implement retry with jitter:

    ```python theme={null}
    import time, random
    for attempt in range(5):
        resp = requests.post(url, headers=h, json=body)
        if resp.status_code < 500 and resp.status_code != 429:
            break
        sleep = (2 ** attempt) + random.random()
        time.sleep(sleep)
    ```

    The `Retry-After` header (when present) must be respected.
  </Accordion>

  <Accordion title="Idempotency via `callback_id`">
    Webhooks redeliver on failure. Always check `callback_id` before processing — store it in a table (id, received\_at). If already present, ignore.
  </Accordion>

  <Accordion title="`application_error` vs HTTP 4xx distinction">
    Treat `application_error` as a **valid query result** (the integration is fine), while HTTP 4xx indicates that **the call** is wrong. Log them separately in monitoring.
  </Accordion>

  <Accordion title="Secrecy (`secrecy_level`)">
    When the lawsuit is secret and the `api-key` has no registered credential for the court, Judit returns `application_error: SECRECY_RESTRICTED`. To access, register the lawyer's credential at [Vault](/en/essentials/cofre-de-credenciais) and reference it via `customer_key` in the query.
  </Accordion>

  <Accordion title="Quotas and limits">
    On 429, read `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` to adjust dispatching. For mass flows, adopt a sliding window.
  </Accordion>
</AccordionGroup>

## Quick troubleshooting table

| Symptom | Most likely hypothesis | Next step |
| :- | :- | :- |
| HTTP 401 always | Missing `api-key` header / wrong value / space/line break. | `echo $JUDIT_API_KEY \| wc -c` — check the size. |
| HTTP 403 on a specific route | Feature not enabled in your plan. | Talk to Judit at `atendimento@judit.io`. |
| `LAWSUIT_NOT_FOUND` for an existing CNJ | CNJ is under secrecy. | See [Credentials Vault](/en/essentials/cofre-de-credenciais). |
| Webhook doesn't arrive | URL not public/HTTPS, or returning ≠ 2xx. | See [Webhook](/en/webhook/callbacks#endpoint-requirements). |
| 2 webhooks with same `request_id` | Expected behavior — first comes from cache (`cached_response: true`), second from court. | See [cached\_response](/en/webhook/callbacks#two-responses). |
| Tracking with no new events | `recurrence` too high or `notification_filters.step_terms` too restrictive. | Lower recurrence; relax filters. |
| Empty `name` response | Homonym or accented name. | Search by CPF/CNPJ; remove accents for testing. |

## Next steps

* 👉 **[Rate Limits](/en/essentialConcepts/rate-limits)** — Retry with Exponential Backoff function to handle `429`.
* 👉 **[Authentication](/en/introduction/authentication)** — how to send credentials correctly to avoid `401`.
* 👉 **[Webhook & Callbacks](/en/webhook/callbacks)** — redelivery behavior and idempotency.
* 👉 **[Glossary](/en/resource/glossary)** — technical terms referenced here.
* 👉 **[FAQ](/en/resource/faq)** — frequently asked questions.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.