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

# Authentication

> Learn how to authenticate with the CUDO Compute API using API keys, manage key rotation, and avoid common errors.

<Note>
  All requests to the CUDO Compute API must be authenticated with an API key in the `Authorization` header unless explicitly documented otherwise.
</Note>

## Overview

The CUDO Compute API uses a simple API key based bearer scheme:

Header format:

```http theme={null}
Authorization: Bearer <api_key>
```

Your API key uniquely identifies you and inherits the permissions of your user or project context. Keep keys secret and never embed them in client-side code or public repositories.

## Create an API key

You can create API keys in two ways:

1. Via the [CUDO Compute console](https://compute.cudo.org/profile/api-keys?create=api-key) (recommended for most users)
2. Programmatically with the `POST /v1/api-keys` endpoint

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.cudocompute.com/v1/api-keys \
    	-H "Authorization: Bearer <existing_api_key>" \
    	-H "Content-Type: application/json" \
    	-d '{ }'
    ```

    Successful response (200):

    ```json theme={null}
    {
    	"id": "ak_12345",
    	"key": "ck_live_XXXXXXXXXXXXXXXX",
    	"createTime": "2025-10-14T12:34:56Z"
    }
    ```

    <Warning>
      The `key` field is only returned once at creation time. Store it securely now; you cannot retrieve it later.
    </Warning>
  </Tab>

  <Tab title="Python (requests)">
    ```python theme={null}
    import os, requests

    BASE_URL = "https://api.cudocompute.com"
    API_KEY = os.getenv("CUDO_API_KEY")  # existing key with permission to create more keys

    resp = requests.post(
    		f"{BASE_URL}/v1/api-keys",
    		headers={
    				"Authorization": f"Bearer {API_KEY}",
    				"Content-Type": "application/json",
    		},
    		json={},
    		timeout=30,
    )
    resp.raise_for_status()
    data = resp.json()
    print("New key id:", data.get("id"))
    print("Store this secret now:", data.get("key"))
    ```
  </Tab>

  <Tab title="JavaScript (fetch)">
    ```js theme={null}
    const BASE_URL = 'https://api.cudocompute.com';
    const API_KEY = process.env.CUDO_API_KEY; // existing key

    async function createApiKey() {
    	const res = await fetch(`${BASE_URL}/v1/api-keys`, {
    		method: 'POST',
    		headers: {
    			'Authorization': `Bearer ${API_KEY}`,
    			'Content-Type': 'application/json'
    		},
    		body: JSON.stringify({})
    	});
    	if (!res.ok) {
    		console.error('Failed', res.status, await res.text());
    		return;
    	}
    	const json = await res.json();
    	console.log('New key id:', json.id);
    	console.log('Key value (save now):', json.key);
    }

    createApiKey();
    ```
  </Tab>
</Tabs>

## Using your API key

Include the header on every request:

```bash theme={null}
curl https://api.cudocompute.com/v1/billing-accounts \
	-H "Authorization: Bearer $CUDO_API_KEY"
```

Python example:

```python theme={null}
import os, requests
API_KEY = os.getenv("CUDO_API_KEY")
resp = requests.get(
		"https://api.cudocompute.com/v1/billing-accounts",
		headers={"Authorization": f"Bearer {API_KEY}"},
		timeout=30,
)
print(resp.status_code, resp.json())
```

## Error handling

Common authentication-related HTTP status codes:

| Code | Meaning           | Typical Cause                                       |
| ---- | ----------------- | --------------------------------------------------- |
| 400  | Bad Request       | Malformed header or body                            |
| 401  | Unauthorized      | Missing / invalid / revoked API key                 |
| 403  | Forbidden         | Authenticated but lacks permission for the resource |
| 429  | Too Many Requests | Rate limit exceeded (apply retry with backoff)      |

<Note>
  Our errors follow the [Google AIP 193](https://google.aip.dev/193) specification. Please see the error codes and formats in the <Link href="/docs/api/errors">Errors</Link> section of the documentation.
</Note>

## Best practices

<Checklist>
  <CheckItem>Never commit keys to version control. Add them to your `.env` and `.gitignore`.</CheckItem>
  <CheckItem>Rotate keys regularly (e.g., every 90 days) and immediately on suspicion of compromise.</CheckItem>
  <CheckItem>Use least privilege: create separate keys per environment or automation scope.</CheckItem>
  <CheckItem>Monitor usage patterns and revoke unused keys.</CheckItem>
</Checklist>

### Rotation workflow example

1. Create a new key.
2. Deploy the new key (update environment variables / secret stores).
3. Verify all services function with the new key.
4. Revoke the old key.

This minimizes downtime and risk.

## Environment variables

Store your key locally in a shell profile or an `.env` file:

```bash theme={null}
export CUDO_API_KEY="ck_live_XXXXXXXXXXXXXXXX"
```

Then reference it in tooling and scripts instead of hardcoding.

## Rate limiting & retries

If you receive HTTP 429, implement exponential backoff (e.g., wait 1s, 2s, 4s, 8s...) and respect any `Retry-After` header (if present). Do not continuously retry invalid keys-fix the credential instead.

## Troubleshooting

| Symptom               | Possible Cause           | Fix                                             |
| --------------------- | ------------------------ | ----------------------------------------------- |
| 401 Unauthorized      | Missing header           | Add `Authorization: Bearer ...`                 |
| 401 Unauthorized      | Typo in key / whitespace | Copy key again; trim spaces/newlines            |
| 401 Unauthorized      | Revoked key              | Generate a new key                              |
| 403 Forbidden         | Insufficient permissions | Use a key with required access or adjust roles  |
| 429 Too Many Requests | Bursty traffic           | Add client-side throttling & retry with backoff |

<Note>
  Currently the API uses a single global bearer scheme named `bearerAuth` with header `Authorization`. There is no separate refresh or OAuth flow.
</Note>

## Next steps

You're authenticated-explore the <Link href="/docs/api">API reference</Link> or jump into building clusters, machines, and more.
