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

# API Authentication

> Authenticate API requests using tokens for programmatic access to Zygo

Zygo supports two authentication methods: browser sessions for the web UI and API tokens for programmatic access. This guide covers API token authentication.

## How It Works

**1. Generate a Token**

Obtain a signed JWT token from the Zygo API while logged in via the browser or using an existing valid token.

**2. Pass the Token**

Include the token in the `token` HTTP header on every API request.

**3. Specify the Tenant**

The tenant is determined by the `{tenant_id}` in each endpoint's URL path. No session or tenant switching is needed.

## Generating a Token

> [!NOTE]
>
> You must be logged in via the browser to generate your first token. After that, you can use the token itself to generate new tokens.

```bash theme={null}
curl -X GET "https://your-zygo-instance.com/api/token?expiration=3600" \
  -H "Cookie: session=YOUR_SESSION_COOKIE"
```

**Response:**

```json theme={null}
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "expires_in": 3600
}
```

### Parameters

| Parameter | Type | Default | Description |
| - | - | - | - |
| `expiration` | integer (query) | 600 | Token lifetime in seconds |

## Using the Token

Pass the token in the `token` header on every request. No session cookie is needed.

> [tab] curl
>
> ```bash theme={null}
> curl -X GET "https://your-zygo-instance.com/api/tenants/{tenant_id}/flows" \
>   -H "token: eyJhbGciOiJIUzI1NiIs..."
> ```

> [tab] Python
>
> ```python theme={null}
> import requests
>
> TOKEN = "eyJhbGciOiJIUzI1NiIs..."
> BASE = "https://your-zygo-instance.com/api"
>
> response = requests.get(
>     f"{BASE}/tenants/{tenant_id}/flows",
>     headers={"token": TOKEN}
> )
> print(response.json())
> ```

> [tab] JavaScript
>
> ```javascript theme={null}
> const TOKEN = "eyJhbGciOiJIUzI1NiIs...";
> const BASE = "https://your-zygo-instance.com/api";
>
> const response = await fetch(
>   `${BASE}/tenants/${tenantId}/flows`,
>   { headers: { token: TOKEN } }
> );
> const data = await response.json();
> ```

## Token vs. Session

Understanding the difference between the two authentication methods:

| | Browser Session | API Token |
| - | - | - |
| **How it works** | Cookie-based, managed by Flask-Login | Stateless JWT in `token` header |
| **Tenant context** | Set once via the UI or `/session/{tenant_id}` | Determined per-request from the URL |
| **State** | Stateful — server stores session data | Stateless — no server-side state |
| **Best for** | Web UI interactions | Scripts, integrations, CI/CD |
| **Login count** | Incremented on login | Not incremented |
| **Multi-tenant** | Switch tenants with `/session/{tenant_id}` | Access any tenant per-request via URL |

## Multi-Tenant Access

Unlike browser sessions where you switch tenants, API tokens let you access any tenant you're a member of by changing the `tenant_id` in the URL:

```bash theme={null}
# Access Tenant A
curl -H "token: $TOKEN" /api/tenants/tenant-a-id/flows

# Access Tenant B (same token, different URL)
curl -H "token: $TOKEN" /api/tenants/tenant-b-id/flows
```

The token identifies **you**. The URL identifies **what you're accessing**. Your roles are resolved per-tenant — you might be an Admin in Tenant A and a Viewer in Tenant B.

> [!WARNING]
>
> Each individual API request is scoped to a single tenant. You cannot access resources from multiple tenants within a single request.

## Error Responses

| Status | Meaning |
| - | - |
| `401` | Token is missing, invalid, or expired |
| `403` | Token is valid but you lack permission (wrong role or not a tenant member) |
| `404` | Resource not found (or belongs to a tenant you don't have access to) |

> [!NOTE]
>
> For security, Zygo returns `404` rather than `403` when you try to access a specific resource in a tenant you're not a member of. This prevents leaking information about whether a resource exists.

## Security Best Practices

> [accordion] Use short expiration times
>
> Set token expiration to the minimum duration you need. For scripts that run once, 600 seconds (10 minutes) is reasonable. For long-running integrations, consider refreshing the token periodically rather than using a very long expiration.

> [accordion] Never commit tokens to source control
>
> Store tokens in environment variables or a secrets manager. Treat them like passwords.

> [accordion] Use one token per integration
>
> If you have multiple scripts or services calling the API, generate a separate token for each. This makes it easier to revoke access if one is compromised.

> [accordion] Rotate tokens regularly
>
> Tokens are short-lived by design. Build your integrations to handle token refresh gracefully.


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