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

# Errors

> How the Just Flow It API reports errors: the error envelope, X-Request-Id, and the full error.type to HTTP status mapping.

The Just Flow It API uses conventional HTTP status codes and returns a consistent JSON **error envelope** on every failed request. The same envelope shape is used for all `4xx` and `5xx` responses, so you can write one error handler that works across every endpoint.

## The error envelope

Every error response has the same JSON shape:

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "missing_parameter",
    "message": "Missing required parameter: prompt.",
    "param": "prompt"
  },
  "request_id": "req_8f3c1a9e2b7d4f60"
}
```

<ResponseField name="error" type="object" required>
  The error object describing what went wrong.

  <Expandable title="error">
    <ResponseField name="error.type" type="string" required>
      A high-level category that maps 1:1 to the HTTP status code. Branch on this in your error handler. See the [table below](#error-types).
    </ResponseField>

    <ResponseField name="error.code" type="string" required>
      A specific, stable machine-readable code within the `type` (for example `missing_parameter`). Use this for programmatic branching.
    </ResponseField>

    <ResponseField name="error.message" type="string" required>
      A human-readable explanation. Safe to log; not intended to be parsed.
    </ResponseField>

    <ResponseField name="error.param" type="string">
      Present only when the error is tied to a specific request parameter (for example `prompt` or `folder_id`). Absent otherwise.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="request_id" type="string" required>
  A unique identifier for this request, at the **top level** of the response (a sibling of `error`, not nested inside it). Give this to support when reporting a problem.
</ResponseField>

<Warning>
  `request_id` lives at the top level of the response body. The `type`, `code`, `message`, and `param` fields live **inside** `error`. Do not assume `request_id` is nested under `error`.
</Warning>

## X-Request-Id

Every API response — successful or not — includes an **`X-Request-Id`** response header. Its value is the same identifier returned as `request_id` in the error envelope.

These are two surfaces of the same id:

* **`X-Request-Id` header** — present on **every** response, including `2xx` successes and `204 No Content` responses that have no body.
* **`request_id` body field** — present in **every error** envelope.

<Tip>
  Always read and log the `X-Request-Id` header, even on success. If a response has no body (such as a `204` from `DELETE`) or a malformed body, the header is the only place the id appears.
</Tip>

<Note>
  `401 Unauthorized` responses also include a `WWW-Authenticate: Bearer` header.
</Note>

## Error types

`error.type` maps directly to the HTTP status code. The table lists every type, its status, the codes that can appear under it, and what it means.

| `error.type`            | HTTP status | `error.code` values                                                                             | Meaning                                                                                                                                                          |
| ----------------------- | ----------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invalid_request_error` | `400`       | `invalid_json`, `missing_parameter`, `invalid_parameter`, `payload_too_large`, `invalid_cursor` | The request was malformed: unparseable JSON, a missing or invalid parameter, a body that was too large, or a bad/expired pagination cursor.                      |
| `authentication_error`  | `401`       | `missing_api_key`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`                      | The API key is missing, unrecognized, revoked, or expired. Response includes `WWW-Authenticate: Bearer`.                                                         |
| `permission_error`      | `403`       | `plan_required`, `insufficient_scope`                                                           | The key is valid but not allowed: the plan does not include API access (`plan_required`), or the key lacks the required scope (`insufficient_scope`).            |
| `not_found_error`       | `404`       | `resource_not_found`                                                                            | The requested resource does not exist or is not accessible by this key.                                                                                          |
| `conflict_error`        | `409`       | —                                                                                               | The request conflicts with the current state of the resource.                                                                                                    |
| `validation_error`      | `422`       | `validation_failed`                                                                             | The request was well-formed but semantically invalid — for example, invalid BPMN 2.0.                                                                            |
| `rate_limit_error`      | `429`       | `rate_limit_exceeded`, `quota_exceeded`                                                         | A limit was hit: the per-key request burst limit (`rate_limit_exceeded`) or the monthly AI generation quota (`quota_exceeded`). Response includes `Retry-After`. |
| `api_error`             | `500`       | `internal_error`                                                                                | Something went wrong on our side. Retry later and, if it persists, contact support with the `request_id`.                                                        |

<Note>
  The `Generation` resource has its own job-level `error` object (`{ code, message }`) that describes why an async generation **failed**. That is part of a successful `200`/`202` poll response — it is **not** the error envelope described on this page.
</Note>

## Example error response

A `422` returned when importing invalid BPMN 2.0 to `POST /diagrams/import`. Note `error.param` pinpointing the offending field, and `request_id` at the top level.

```http theme={null}
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
X-Request-Id: req_8f3c1a9e2b7d4f60
```

```json theme={null}
{
  "error": {
    "type": "validation_error",
    "code": "validation_failed",
    "message": "The provided XML is not valid BPMN 2.0.",
    "param": "bpmn_xml"
  },
  "request_id": "req_8f3c1a9e2b7d4f60"
}
```

## Handling errors

<CodeGroup>
  ```bash cURL theme={null}
  # Capture both the body and the X-Request-Id header.
  curl -sS -D - -o body.json \
    -X POST https://justflow.it/api/v1/diagrams/import \
    -H "Authorization: Bearer jfi_sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{ "bpmn_xml": "not-valid-bpmn" }' \
    | grep -i "^x-request-id:"

  cat body.json
  ```

  ```javascript JavaScript (fetch) theme={null}
  const res = await fetch("https://justflow.it/api/v1/diagrams/import", {
    method: "POST",
    headers: {
      Authorization: "Bearer jfi_sk_live_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ bpmn_xml: "not-valid-bpmn" }),
  });

  // X-Request-Id is present on every response, success or failure.
  const requestId = res.headers.get("X-Request-Id");

  if (!res.ok) {
    const { error } = await res.json();
    console.error(
      `[${requestId}] ${res.status} ${error.type}/${error.code}: ${error.message}` +
        (error.param ? ` (param: ${error.param})` : "")
    );

    switch (error.type) {
      case "authentication_error":
        throw new Error("Check your API key.");
      case "permission_error":
        throw new Error("Your plan or key scope does not allow this.");
      case "rate_limit_error":
        // Honor the Retry-After header before retrying.
        break;
      default:
        throw new Error(error.message);
    }
  }
  ```

  ```python Python (requests) theme={null}
  import requests

  res = requests.post(
      "https://justflow.it/api/v1/diagrams/import",
      headers={
          "Authorization": "Bearer jfi_sk_live_...",
          "Content-Type": "application/json",
      },
      json={"bpmn_xml": "not-valid-bpmn"},
  )

  # X-Request-Id is present on every response, success or failure.
  request_id = res.headers.get("X-Request-Id")

  if not res.ok:
      error = res.json()["error"]
      param = f" (param: {error['param']})" if error.get("param") else ""
      print(f"[{request_id}] {res.status_code} {error['type']}/{error['code']}: {error['message']}{param}")

      if error["type"] == "rate_limit_error":
          retry_after = res.headers.get("Retry-After")
          # Wait `retry_after` seconds before retrying.
          ...
  ```
</CodeGroup>

## Using request\_id for support

When something goes wrong and you need help, the `request_id` lets us locate the exact request in our logs.

<Steps>
  <Step title="Capture the id">
    Read `X-Request-Id` from the response header (always present), or `request_id` from the error body. They are the same value.
  </Step>

  <Step title="Log it alongside the error">
    Store the `request_id` with `error.type`, `error.code`, and the HTTP status. Logging it on success too means you can correlate a later report with the originating call.
  </Step>

  <Step title="Include it in your report">
    When contacting support, send the `request_id`, the endpoint and method, the approximate timestamp, and the `error.type` / `error.code` you received.
  </Step>
</Steps>

<Tip>
  Include the `request_id` in every support message. It is the fastest way for us to trace exactly what happened on a specific call.
</Tip>
