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

# Authentication

> API keys and bearer tokens for the Engini DeveloperAPI.

The DeveloperAPI accepts two credentials. **Either one alone is sufficient** - do not send both on the same request (a Bearer token always wins if you do).

| Method                    | Header                        | When to use                                                                                                  |
| ------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------ |
| **API key** (recommended) | `x-api-key: eng_...`          | Servers, scripts, CI, and AI agents. The key is bound to your account server-side - no other headers needed. |
| Bearer token              | `Authorization: Bearer <jwt>` | The JWT issued by Engini sign-in; used by first-party apps and short-lived sessions.                         |

## Where the credentials come from

* **API key** - created in your Engini account settings at [app.engini.io](https://app.engini.io). Sign in to the app however you like - email/password or **OAuth (Google, Microsoft, GitHub)** - then create a key. The CLI's `engini login` opens this page for you on a TTY.
* **Bearer JWT** - the session token Engini issues when you sign in (including via the OAuth providers above). It's what the web app itself uses; you can pass it to the SDK (`token=`) or API for short-lived, user-scoped calls.
* **OAuth apps** - third-party applications (and MCP clients) can obtain Engini Bearer tokens programmatically through the standard OAuth 2.1 authorization-code flow: see [OAuth apps](/concepts/oauth-apps).

<Note>
  OAuth sign-in to Engini happens in the browser/web app - there is no OAuth device flow inside the CLI or SDK. For anything long-lived or headless, use an API key. (OAuth to *third-party applications* - Salesforce, Outlook, Gmail... - is a different flow and is fully supported programmatically: see [Connections & OAuth](/sdk/connections).)
</Note>

## Base URL

```
https://api.engini.io/v1
```

## Verify a credential

```bash theme={null}
curl https://api.engini.io/v1/auth/whoami -H "x-api-key: $ENGINI_API_KEY"
```

Returns the user, company, role, and caller type behind the credential. The SDKs expose this as `client.auth.whoami()`, the CLI as `engini whoami`.

## In the SDKs

<CodeGroup>
  ```python Python theme={null}
  from engini import Engini

  client = Engini()                      # ENGINI_API_KEY (preferred) or ENGINI_API_TOKEN
  client = Engini(api_key="eng_...")     # explicit API key  -> x-api-key header
  client = Engini(token="...")           # explicit PAT      -> Authorization: Bearer
  ```

  ```typescript TypeScript theme={null}
  import { Engini } from "@engini/sdk";

  const client = new Engini();                    // ENGINI_API_KEY (preferred) or ENGINI_API_TOKEN
  const client2 = new Engini({ apiKey: "eng_..." });
  const client3 = new Engini({ token: "..." });
  ```
</CodeGroup>

`api_key`/`token`/`auth` are mutually exclusive. With no explicit credential, the SDKs read `ENGINI_API_KEY` first, then `ENGINI_API_TOKEN`.

## Failures

Missing or invalid credentials return `401`; a valid credential without access to the resource returns `403`. Both carry the standard [error envelope](/concepts/pagination-and-errors).
