> ## 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.

# Authentication

> Authenticate Just Flow It API requests with a server-side API key sent as a Bearer token.

The Just Flow It API authenticates every request with an **API key** passed as an HTTP Bearer token. Keys are **server-to-server only** — they grant full access to your diagrams and folders and must never be embedded in a browser, mobile app, or any client-side code.

<Warning>
  The API is available on **paid plans only**. Requests made without a valid key, or from a Free-plan account, are rejected. There is no CORS support — calling the API from a browser will fail by design.
</Warning>

## API key format

Every key looks like this:

```
jfi_sk_live_xxxxxxxxxxxxxxxxxxxxxxxx
```

The prefix tells you the environment:

| Prefix         | Environment | Use against          |
| -------------- | ----------- | -------------------- |
| `jfi_sk_live_` | Production  | Your real diagrams   |
| `jfi_sk_test_` | Staging     | Safe, throwaway data |

<Note>
  Only a SHA-256 hash of your key is stored server-side. Just Flow It can never show you the key again after creation — if you lose it, you must revoke it and create a new one.
</Note>

## Sending the key

Pass the key in the `Authorization` header on every request, prefixed with `Bearer`:

<CodeGroup>
  ```bash curl theme={null}
  curl https://justflow.it/api/v1/diagrams \
    -H "Authorization: Bearer jfi_sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
  ```

  ```javascript JavaScript (fetch) theme={null}
  const res = await fetch("https://justflow.it/api/v1/diagrams", {
    headers: {
      Authorization: `Bearer ${process.env.JFI_API_KEY}`,
    },
  });
  const body = await res.json();
  ```

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

  res = requests.get(
      "https://justflow.it/api/v1/diagrams",
      headers={"Authorization": f"Bearer {os.environ['JFI_API_KEY']}"},
  )
  body = res.json()
  ```
</CodeGroup>

## Creating a key

<Steps>
  <Step title="Open the dashboard">
    In the Just Flow It web app, go to **Settings → API keys**.
  </Step>

  <Step title="Create a key">
    Choose which scopes the key should hold, then create it.
  </Step>

  <Step title="Copy it once">
    The full key is shown **in plaintext exactly once**, at creation time. Copy it immediately and store it in a secret manager — you will not be able to see it again.
  </Step>
</Steps>

## Personal vs. organization keys

The kind of key you get — and what it can act on — depends on your plan.

<CardGroup cols={2}>
  <Card title="Pro — personal key" icon="user">
    A **Pro** user gets a **personal key**. It acts on that user's personal diagrams and folders.
  </Card>

  <Card title="Team — organization key" icon="users">
    A member of a **Team** organization gets an **org key**. It acts on that organization's diagrams and folders.
  </Card>
</CardGroup>

<Note>
  Resources carry an `organization_id`: it is `null` for personal resources and set to the org's id for organization resources.
</Note>

## Scopes

A key holds a subset of the following scopes. A request that needs a scope the key does not hold is rejected with `403 insufficient_scope`.

| Scope            | Grants                                          |
| ---------------- | ----------------------------------------------- |
| `diagrams:read`  | List, retrieve, and render diagram images       |
| `diagrams:write` | Create, update, and delete diagrams             |
| `folders:read`   | List and retrieve folders                       |
| `folders:write`  | Create, update, and delete folders              |
| `generate`       | Generate diagrams from natural-language prompts |

## Security best practices

<Tip>
  Treat an API key like a password. Anyone holding it can read and modify all of your (or your org's) diagrams and folders.
</Tip>

* **Server-side only.** Never ship a key to a browser, mobile app, or any client. The API has no CORS support precisely to discourage this.
* **Use environment variables / a secret manager.** Don't hardcode keys in source or commit them to version control.
* **Use test keys in non-production.** Develop and run CI against `jfi_sk_test_` keys so you never touch real data.
* **Scope minimally.** Give a key only the scopes it needs (for example, a reporting job may only need `diagrams:read`).
* **Rotate regularly.** Create a new key, deploy it, then revoke the old one.
* **Revoke immediately on leak.** Revoking a key takes effect at once; subsequent requests return `401 revoked_api_key`.

## Authentication errors

Every error response uses the standard envelope and includes an `X-Request-Id` header. All `401` responses also include a `WWW-Authenticate: Bearer` header.

```json theme={null}
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "The API key provided is invalid."
  },
  "request_id": "req_1a2b3c4d5e6f"
}
```

### 401 — authentication\_error

| Code              | When it happens                                       |
| ----------------- | ----------------------------------------------------- |
| `missing_api_key` | No `Authorization: Bearer` header was sent            |
| `invalid_api_key` | The key is malformed or does not match any stored key |
| `revoked_api_key` | The key was revoked in the dashboard                  |
| `expired_api_key` | The key has expired                                   |

### 403 — permission\_error

| Code                 | When it happens                                                    |
| -------------------- | ------------------------------------------------------------------ |
| `plan_required`      | The account is on the Free plan and cannot use the API             |
| `insufficient_scope` | The key is valid but does not hold the scope the endpoint requires |

<Accordion title="Example: missing scope (403)">
  Calling `POST /v1/diagrams` with a key that holds `diagrams:read` but not `diagrams:write`:

  ```json theme={null}
  {
    "error": {
      "type": "permission_error",
      "code": "insufficient_scope",
      "message": "The API key does not have the required scope 'diagrams:write'."
    },
    "request_id": "req_7g8h9i0j1k2l"
  }
  ```
</Accordion>

<Accordion title="Example: Free plan (403)">
  ```json theme={null}
  {
    "error": {
      "type": "permission_error",
      "code": "plan_required",
      "message": "The API is available on paid plans only."
    },
    "request_id": "req_3m4n5o6p7q8r"
  }
  ```
</Accordion>
