---
title: Authentication
description: >-
  API keys, Clerk JWT, guest access, scopes, and rate limiting for the
  Ivy Biosciences API
tags:
  - auth
  - api-keys
  - jwt
  - guest
---
Authentication is how you prove who you are so the API knows which requests to trust and how to rate-limit them. Start with the public [guest curl path](/docs/api#guest-curl) when you want to try one orchestrated run without an account. Pick an API key for server-side and CLI work, or a Clerk JWT for browser and mobile sessions. Once you've chosen a method, [API Keys](/docs/api/rest-api-keys) covers provisioning credentials and [Rate Limits](/docs/api/rate-limits) covers the ceilings each method carries.

  beginner
  10 min

## Authentication

Every request carries one of three credentials, and the credential decides which account the run is recorded against.

## Authentication Methods

| Method | Use Case | Header |
|--------|----------|--------|
| **API Key** | Server-side, CLI, scripts, CI/CD | `Authorization: Bearer ivy_...` |
| **Clerk JWT** | Browser, mobile (Clerk sessions) | `Authorization: Bearer eyJ...` |
| **Guest orchestrate** | Try-before-signup, demos | No credential; quota is keyed to the caller's IP |

---

## API Key Authentication

API keys use the `ivy_` prefix (not `ivy_sk_`). Three header formats are accepted:

**Bearer (recommended)**

```bash
# Preferred format
curl -H "Authorization: Bearer ivy_your_key_here" \
  https://www.ivybiosciences.com/api/v1/jobs
```

**X-API-Key**

```bash
# Alternative header
curl -H "X-API-Key: ivy_your_key_here" \
  https://www.ivybiosciences.com/api/v1/jobs
```

**ApiKey (legacy)**

```bash
# Legacy format: the compute backend only, never the web app's /api routes
curl -H "Authorization: ApiKey ivy_your_key_here" \
  "$COMPUTE_BACKEND_URL/api/v1/jobs"
```

Only the compute backend accepts this scheme. The web app's `/api` routes don't accept it. Use `Authorization: Bearer ivy_…` or `X-API-Key` there.

> The API key prefix is `ivy_`, not `ivy_sk_`. Some older documentation references may show `ivy_sk_` — this is incorrect.

### Creating API Keys

Only a signed-in Clerk session can create an API key; an API key cannot create another key. Create keys in the web app at [Settings → API keys](https://www.ivybiosciences.com/settings/api-keys), or call the same route with a session token:

```bash
curl -X POST https://www.ivybiosciences.com/api/user/api-keys \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d '{"name": "CI Pipeline", "scopes": ["read", "write"]}'
```

See [API Keys](/docs/api/rest-api-keys) for full management documentation.

---

## Clerk JWT Authentication

For browser and mobile applications using Clerk:

**TypeScript**

```ts
import { useAuth } from "@clerk/nextjs"

const { getToken } = useAuth()

const response = await fetch("/api/v1/jobs", {
  headers: {
    "Authorization": `Bearer ${await getToken({ template: "ivy_api" })}`,
  },
})
```

**Python**

```python
# Obtain JWT from Clerk SDK or session
headers = {"Authorization": f"Bearer {clerk_jwt_token}"}
response = requests.get(f"{BASE_URL}/api/v1/jobs", headers=headers)
```

---

## Guest access

The supported public guest entry point is `POST /api/v1/orchestrate`. It needs no API key or guest header; send a natural-language `prompt` and let the orchestrator choose the allowlisted tools.

**cURL**

```bash
curl -N https://www.ivybiosciences.com/api/v1/orchestrate \
  -H "Content-Type: application/json" \
  -d '{"prompt":"find recent papers on EGFR L858R resistance","stream":true}'
```

**TypeScript**

```ts
const response = await fetch("/api/v1/orchestrate", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    prompt: "find recent papers on EGFR L858R resistance",
    stream: true,
  }),
})
```

### Guest Restrictions

| Restriction | Value |
|-------------|-------|
| Rate limit | 18 orchestrate calls per day per IP |
| Compute budget | $1.00 of compute per IP per UTC day; whichever limit runs out first refuses the call |
| Allowed tools | Guest allowlist; the route may run selected GPU and sandbox tools |
| Data retention | Ephemeral guest session; no durable account history |
| Project context | None |

See the [guest curl quickstart](/docs/api#guest-curl) for the supported public flow.

---

## Scopes

An API key carries up to three capabilities. A new key gets `read` and `write` unless you ask for others.

| Scope | Permissions |
|-------|-------------|
| `read` | Read jobs, projects, results, and usage |
| `write` | Create and update jobs, files, and projects |
| `manage` | Perform destructive or account-level actions |

### Scope Inheritance

Each capability includes the ones below it:

```
manage ⊃ write ⊃ read
```

Keys created before this vocabulary existed keep working: older domain scopes such as `jobs:read` or `tools:all` map onto these three.

### Project Scoping

Jobs and projects can be scoped to an organization:

```bash
curl -X POST https://www.ivybiosciences.com/api/v1/jobs \
  -H "Authorization: Bearer ivy_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "tool_name": "esmfold",
    "tool_input_parameters": {"protein_sequence": "..."},
    "orgId": "org_abc123",
    "projectId": "proj_def456"
  }'
```

An API key can also be restricted to a list of projects when you create it in settings (`allowedProjectIds`). A restricted key reaches only jobs in those projects, on every job route, including status, outputs, downloads, manifests and artifact content. A job with no project, or in any other project, is refused even if your account can open it. The refusal is a 403 or 404 that does not say whether the job exists. A key with no project list reaches every job your account can.

A job's files are stored under the project it ran in. If a job was later moved to another project, a key restricted to the new project can read the job's status but not those files. Use an unrestricted key or a signed-in session for them.

---

## Rate Limits

Limits are set per route and per client, not per authentication method. Signed-in callers (Clerk JWT or API key) get the same per-minute and per-second ceilings; a guest orchestrate call also draws on the daily guest quota in [Guest curl](/docs/api#guest-curl).

A throttled request returns HTTP 429 with a `Retry-After` header. [Rate Limits](/docs/api/rate-limits) lists the ceilings, the response bodies, and how to back off.

---

## Error Format

Most web API routes, including the Harness routes, return this envelope:

```json
{
  "success": false,
  "code": "MACHINE_READABLE_CODE",
  "message": "Human-readable error message"
}
```

Errors forwarded from the compute backend keep its FastAPI shape, `{"detail": "..."}`.

| Status | Meaning |
|--------|---------|
| 401 | Authentication required or token expired |
| 403 | Insufficient permissions (scope too low) |
| 404 | Resource not found |
| 422 | Validation error (bad parameters) |
| 429 | Rate limit exceeded |
| 500 | Server error |
| 503 | Service unavailable (feature disabled) |

## Read next

- [API Keys](/docs/api/rest-api-keys) — create and manage API keys
- [Guest curl](/docs/api#guest-curl) — unauthenticated trial access through the public orchestrator
- [Rate Limits](/docs/api/rate-limits) — detailed rate limit documentation
- [Error Codes](/docs/api/sdk-errors) — complete error reference
