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

# Authentication

> Bearer API keys, who can create them, and why a request is refused.

Every `/api/v1` request is authenticated with an API key sent as a Bearer token.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://my.flowsign.app/api/v1/workspaces \
    -H "Authorization: Bearer fsk_your_key_here"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://my.flowsign.app/api/v1/workspaces", {
    headers: { Authorization: `Bearer ${process.env.FLOWSIGN_API_KEY}` },
  });

  const { data } = await res.json();
  console.log(data.active, data.workspaces);
  ```

  ```python Python theme={null}
  import os

  import requests

  res = requests.get(
      "https://my.flowsign.app/api/v1/workspaces",
      headers={"Authorization": f"Bearer {os.environ['FLOWSIGN_API_KEY']}"},
      timeout=30,
  )
  res.raise_for_status()

  data = res.json()["data"]
  print(data["active"], data["workspaces"])
  ```

  ```csharp C# theme={null}
  using System.Net.Http.Headers;
  using System.Net.Http.Json;
  using System.Text.Json;

  using var http = new HttpClient { BaseAddress = new Uri("https://my.flowsign.app") };
  http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
      "Bearer",
      Environment.GetEnvironmentVariable("FLOWSIGN_API_KEY"));

  var body = await http.GetFromJsonAsync<JsonElement>("/api/v1/workspaces");
  var data = body.GetProperty("data");

  Console.WriteLine(data.GetProperty("active").GetString());
  ```
</CodeGroup>

Keys start with `fsk_`. FlowSign stores only a hash of the key; the full value is shown once, when the key is created.

## Creating and managing keys

Keys are created in the app at **Settings > API keys** ([my.flowsign.app/settings/api-keys](https://my.flowsign.app/settings/api-keys)).

* **Name** the key after where it will live (for example "Production server").
* **Expiry** is optional. A key with no expiry works until you revoke it; a key with an expiry stops working at the end of that day.
* The key value is displayed once in a reveal dialog and cannot be read again. If you lose it, create a new key.
* **Revoke** a key from the same page. Revocation is immediate and permanent.
* There is no rotate operation. To rotate, create a new key, move your integration to it, then revoke the old one.

The page shows each key's prefix, status (Active, Expired or Revoked), expiry and when it was last used.

<Warning>
  A key carries the full API access of the user who created it. Store it in a secrets manager, never in client-side code or a repository, and revoke it the moment it is no longer needed.
</Warning>

## Who can use the API

* **Permission.** Creating and using keys requires the **API access** permission on the user's profile. The built-in Admin profile has it; Sender and Viewer do not. An administrator can grant it from **Roles & Permissions**.
* **Acting as a user.** A key acts as its creator. Endpoints that change data check that user's permissions, so a key created by someone without the send permission cannot send packages (`403 Missing permission: canSendPackages`).
* **Webhook endpoints** (`/api/v1/webhooks`) additionally require the user to be an organisation admin.
* **Plan.** The public API is included in the Enterprise plan. Webhooks are a separate feature on the same plan. Calls from organisations without the feature return `402`.
* **IP allowlist.** If your organisation has an IP allowlist (**Settings > Security**), API calls from other addresses are refused with `403 IP address not allowed`.

## Workspaces

A key belongs to the organisation and acts in one workspace per request. Send `X-Workspace-Id` to choose the workspace; omit it to act in the default one. See [Workspaces](/api-reference/workspaces).

## Why a request is refused

| Status                            | Cause                                                                                                                                                                                               |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401 Unauthorized`                | No `Authorization` header, a token that does not start with `fsk_`, an unknown key, or a key that is revoked or expired. Also returned when the key's user no longer has the API access permission. |
| `402`                             | The organisation's plan does not include the public API (or webhooks, on webhook routes). The message names the missing feature.                                                                    |
| `403 IP address not allowed`      | The caller's address is outside the organisation's IP allowlist.                                                                                                                                    |
| `403 Missing permission: ...`     | The key's user lacks the permission the endpoint needs.                                                                                                                                             |
| `403 Organisation admin required` | Webhook endpoints are managed by organisation admins only.                                                                                                                                          |

See [Errors](/api-reference/errors) for the response format, validation details and rate limits.
