> ## 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 your API requests using an API key passed in the X-Api-Key header.

## API Key Authentication

Most API requests require authentication via the `X-Api-Key` HTTP header. Keys are scoped to your organisation and grant access to every endpoint your plan permits. The company profile lookup (`GET /api/companies/{id}`) is public so `details_url` links can be resolved without a key.

```bash theme={null}
curl https://connect.jobo.world/api/jobs \
  -H "X-Api-Key: YOUR_API_KEY"
```

<Steps>
  <Step title="Get your API key">
    Sign in to the [Jobo Enterprise Dashboard](https://enterprise.jobo.world) and
    navigate to **Settings → API Keys**. You can create multiple keys — one per
    environment or service — and revoke any key at any time.
  </Step>

  <Step title="Add the header to every request">
    Include `X-Api-Key: YOUR_API_KEY` in every request. The key must be sent as
    an HTTP header — query-parameter authentication is **not** supported.
  </Step>

  <Step title="Use HTTPS only">
    All requests **must** use HTTPS. Plain HTTP requests are rejected with a
    `301` redirect, and the request body is never processed.
  </Step>
</Steps>

***

## Base URL

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

All paths in this documentation are relative to this base URL.

***

## Environments

<Info>
  Jobo Enterprise exposes one production API host. All documented API paths are
  relative to this base URL.
</Info>

| Surface            | URL                          | Purpose                                |
| ------------------ | ---------------------------- | -------------------------------------- |
| **Production API** | `https://connect.jobo.world` | Live job data and customer API traffic |

The public website playground uses short-lived, Turnstile-issued demo tokens
against the same production API host. Those tokens are limited to evaluation
flows and are not a separate CI or application-testing environment.

***

## SDK Authentication

Pass your API key when you instantiate the client — the SDK handles the header for every subsequent call.

<CodeGroup>
  ```python Python theme={null}
  from jobo_enterprise import JoboClient

  client = JoboClient(api_key="YOUR_API_KEY")

  # All subsequent calls are authenticated automatically
  results = client.jobs.search(q="data engineer", page_size=5)
  ```

  ```javascript Node.js theme={null}
  import { JoboClient } from "jobo-enterprise";

  const client = new JoboClient({ apiKey: "YOUR_API_KEY" });

  // All subsequent calls are authenticated automatically
  const results = await client.jobs.search({ q: "data engineer", pageSize: 5 });
  ```

  ```csharp .NET theme={null}
  using Jobo.Enterprise.Client;

  var client = new JoboClient("YOUR_API_KEY");

  // All subsequent calls are authenticated automatically
  var results = await client.Jobs.SearchAsync(new SearchRequest
  {
      Query = "data engineer",
      PageSize = 5
  });
  ```
</CodeGroup>

<Tip>
  Store your API key in an environment variable (e.g. `JOBO_API_KEY`) and read
  it at runtime instead of hard-coding it.
</Tip>

***

## Response Headers

Every successful API response includes headers that help you monitor your usage and stay within limits.

### Credit Headers

Credits are deducted based on the endpoint and plan. Credit headers are present when wallet metering occurs or when a request is rejected for insufficient credits:

| Header               | When        | Description                                                    |
| -------------------- | ----------- | -------------------------------------------------------------- |
| `X-Credits-Deducted` | debit       | Number of credits consumed by this request.                    |
| `X-Credits-Balance`  | debit / 402 | Your wallet balance after the debit or failed precheck.        |
| `X-Credits-Required` | `402` only  | Credits the request would have needed when balance is too low. |

Unmetered responses and metered responses that deduct nothing may omit credit headers.

### Rate-Limit Headers

Rate limits are applied per API key. When you approach or exceed your limit, use these headers to implement backoff:

| Header                  | Type    | Description                                 |
| ----------------------- | ------- | ------------------------------------------- |
| `X-RateLimit-Limit`     | integer | Maximum requests allowed per window         |
| `X-RateLimit-Remaining` | integer | Requests remaining in the current window    |
| `X-RateLimit-Reset`     | integer | Unix epoch timestamp when the window resets |

<Warning>
  When `X-RateLimit-Remaining` reaches **0**, subsequent requests return `429
      Too Many Requests`. Wait until the `X-RateLimit-Reset` timestamp before
  retrying.
</Warning>

***

## Security Best Practices

<Warning>
  Never expose your API key in client-side code, public repositories, or browser
  requests. Always make API calls from your backend server.
</Warning>

* Store API keys in environment variables or a secrets manager (e.g. AWS Secrets Manager, HashiCorp Vault)
* Rotate keys periodically from the dashboard — revoked keys are rejected immediately
* Use separate keys for development, staging, and production
* Monitor usage in the dashboard to detect anomalies and unexpected spikes
* Apply the principle of least privilege — only create keys that your service actually needs

***

## Error Responses

### 401 Unauthorized — Missing or Invalid Key

If your API key is missing, malformed, or revoked, you'll receive:

```json theme={null}
{
  "status": 401,
  "error": "Unauthorized",
  "message": "Missing or invalid API key"
}
```

### 403 Forbidden — Insufficient Permissions

If your key is valid but your plan does not include the requested endpoint:

```json theme={null}
{
  "status": 403,
  "error": "Forbidden",
  "message": "Your plan does not include access to this endpoint"
}
```

### 429 Too Many Requests — Rate Limit Exceeded

If you exceed your per-key rate limit:

```json theme={null}
{
  "status": 429,
  "error": "Too Many Requests",
  "message": "Rate limit exceeded. Retry after 1677721600",
  "retryAfter": 1677721600
}
```

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="I'm getting 401 Unauthorized on every request">
    * Confirm you're sending the key as an **HTTP header** (`X-Api-Key`), not as a query parameter.
    * Check for trailing whitespace or newline characters in the key value.
    * Verify the key has not been revoked in **Settings → API Keys**.
    * Make sure you're calling the production API base URL: `https://connect.jobo.world`.
  </Accordion>

  <Accordion title="My requests work in cURL but fail in my application">
    * Ensure your HTTP client is not stripping custom headers — some frameworks require explicit allow-listing.
    * Double-check that you're using **HTTPS**, not HTTP.
    * If you're behind a corporate proxy, confirm it forwards the `X-Api-Key` header untouched.
  </Accordion>

  <Accordion title="I'm hitting 429 Too Many Requests">
    * Read the `X-RateLimit-Reset` header and wait until that timestamp before retrying.
    * Implement **exponential backoff** with jitter in your retry logic.
    * If you consistently hit limits, consider upgrading your plan or contacting support for a rate-limit increase.
  </Accordion>

  <Accordion title="My credits are depleting faster than expected">
    * Review the `X-Credits-Deducted` header on metered responses to audit usage.
    * Check current rates on [jobo.world/pricing](https://jobo.world/pricing).
    * Monitor your wallet and billing settings in the [dashboard](https://enterprise.jobo.world/credits).
  </Accordion>

  <Accordion title="I need to rotate my API key without downtime">
    1. Create a **new key** in the dashboard.
    2. Deploy the new key to your services.
    3. Once all traffic uses the new key, **revoke** the old one.

    Both keys are valid simultaneously, so there is no gap in access.
  </Accordion>
</AccordionGroup>

***

## Need Help?

<CardGroup cols={2}>
  <Card title="WhatsApp Support" icon="whatsapp" href="https://wa.me/27715111705">
    Chat with our team for fast, real-time assistance.
  </Card>

  <Card title="Email Support" icon="envelope" href="mailto:support@jobo.world">
    Reach us at **[support@jobo.world](mailto:support@jobo.world)** for account or billing queries.
  </Card>
</CardGroup>
