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

# Authentication

> Authenticate with an API key in the X-Api-Key header. Covers key format, limits, rotation, and the one endpoint that needs no key.

Every request except one carries your key in the `X-Api-Key` header.

```bash theme={null}
curl "https://connect.jobo.world/api/jobs?q=engineer&page_size=5" \
  -H "X-Api-Key: $JOBO_API_KEY"
```

```python theme={null}
from jobo_enterprise import JoboClient

with JoboClient(api_key="YOUR_API_KEY") as client:
    results = client.search.search(q="engineer", page_size=5)
```

<Steps>
  <Step title="Create a key">
    Sign in to the [dashboard](https://enterprise.jobo.world) and go to **Settings → API Keys**. The full key is shown **once, at creation** — store it immediately.
  </Step>

  <Step title="Send it as a header on every request">
    Query-parameter authentication is **not** supported, and there is no `Authorization: Bearer` form.
  </Step>

  <Step title="Use HTTPS">
    Plain HTTP is answered with a `301` redirect and never reaches the API. Most HTTP clients silently downgrade a redirected `POST` to `GET` and drop the body, so always call `https://` directly.
  </Step>
</Steps>

***

## Base URL

```
https://connect.jobo.world
```

Every path in these docs is relative to it. `jobs-api.jobo.world` resolves to the same service and appears in some older client configuration, but `connect.jobo.world` is canonical — prefer it in new integrations.

There is a **single production host**. There is no separate sandbox or staging environment, and no test-mode key: every issued key is a live key. For developing without spending, see [free endpoints](/docs/concepts#developing-without-spending).

***

## Key format and scope

Keys look like this:

```
jbe_live_XXXXXXXXXXXXXXXXXXXXX_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

The `jbe_live_` prefix is recognised by secret scanners such as GitHub's, so a leaked key gets flagged.

A key is scoped to **your account**. There is no organisation or team concept, and — importantly — **keys have no scopes or per-endpoint permissions**. Any key can call any endpoint your plan allows; what varies is your [rate-limit group](/docs/rate-limits) and [wallet balance](/docs/billing). Creating a key "for search only" is not possible.

<Note>
  You can hold at most **5 active keys** at a time. Creating a sixth returns `409 Conflict` — revoke or let one expire first.
</Note>

***

## The one endpoint that needs no key

`GET /api/companies/{id}` is **anonymous**. It takes no key, costs nothing, is not rate limited, and is CDN-cached. This exists so the `details_url` on any job resolves from a browser or a public page without exposing a credential.

```bash theme={null}
curl "https://connect.jobo.world/api/companies/{company_id}"
```

Everything else — including `GET /api/companies/{id}/jobs` — requires a key.

***

## Rotating a key

<Steps>
  <Step title="Create the replacement">
    Multiple keys are valid simultaneously, so there is no gap in access.
  </Step>

  <Step title="Deploy it">
    Roll the new key out to every service.
  </Step>

  <Step title="Revoke the old one">
    Once no traffic uses it.
  </Step>
</Steps>

<Warning>
  If you are already at the **5-key limit**, you cannot create the replacement first — you must revoke something before creating, which does break the overlap. Keep a spare slot free if you rotate on a schedule.
</Warning>

Revocation takes effect within roughly **30 seconds**, not instantly: successful authentications are briefly cached. Treat a revoked key as live for that window, and if a key is genuinely compromised, revoke it *and* contact [support@jobo.world](mailto:support@jobo.world).

***

## Storing keys safely

<Warning>
  Never put a key in client-side code, a public repository, or a browser request. All calls should originate from your backend.
</Warning>

* Read keys from environment variables or a secrets manager, never from source.
* Use a separate key per environment and per service, so you can revoke narrowly. Remember the limit of 5.
* Watch usage in the dashboard for unexpected spikes.

```bash theme={null}
export JOBO_API_KEY="your_api_key_here"     # macOS / Linux
```

***

## When authentication fails

A missing or unusable key returns `401` with `WWW-Authenticate: ApiKey realm="api.jobo.world"`:

```json theme={null}
{ "error": "Missing X-Api-Key header" }
```

```json theme={null}
{ "error": "Invalid or expired API key" }
```

Note that a valid key with an insufficient plan or an empty wallet returns **`402`**, not `403`. See [Errors](/docs/errors) for every envelope, and [Response headers](/docs/response-headers) for what accompanies a successful response.

<AccordionGroup>
  <Accordion title="401 on every request">
    * Confirm the key is an **HTTP header** named `X-Api-Key`, not a query parameter.
    * Check for a trailing newline or space in the value — a common result of reading the key from a file.
    * Verify the key is still active under **Settings → API Keys**.
    * Confirm you are calling `https://connect.jobo.world`, not the dashboard host.
  </Accordion>

  <Accordion title="Works in curl, fails in my application">
    * Some HTTP clients and proxies strip unknown custom headers — check that `X-Api-Key` survives to the wire.
    * Confirm HTTPS, not HTTP; a redirect will drop your request body.
    * If you recently rotated, make sure the deployed key is the new one.
  </Accordion>

  <Accordion title="I got a 409 creating a key">
    You already have 5 active keys. Revoke one, or wait for one to expire, then retry.
  </Accordion>

  <Accordion title="My key stopped working right after I revoked a different one">
    Revoking is per-key and does not affect other keys. Confirm which key your service is actually loading — most reports of this turn out to be a stale environment variable or a cached deployment config.
  </Accordion>
</AccordionGroup>
