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

# Authentication

> Obtain an access token for the Kravata Stack API and set up production access with mTLS and an IP allowlist.

Kravata assigns API credentials (`apiKey` and `secretKey`) to accepted customers after the onboarding and compliance review. You exchange them for a temporary access token and send that token in every request.

| Environment | Base URL | Requirements |
| - | - | - |
| Test | `https://test-api-kore.kravata.co` | API credentials. |
| Production | `https://partners-api.kravata.co` | API credentials, **mTLS client certificate** and **IP allowlist**. |

## Get an access token

Call [Client Login](/stack/api-reference/authentication/client-login) with your credentials.

<CodeGroup>
  ```bash Test theme={null}
  curl -X POST https://test-api-kore.kravata.co/api/v1/client/token \
    -H "Content-Type: application/json" \
    -d '{
      "apiKey": "YOUR_API_KEY",
      "secretKey": "YOUR_SECRET_KEY"
    }'
  ```

  ```bash Production theme={null}
  curl -X POST https://partners-api.kravata.co/api/v1/client/token \
    --cert client.crt --key client.key \
    -H "Content-Type: application/json" \
    -d '{
      "apiKey": "YOUR_API_KEY",
      "secretKey": "YOUR_SECRET_KEY"
    }'
  ```
</CodeGroup>

The response contains the token (`accessToken`) and its validity in seconds (`expiresIn`). Store the token and reuse it until it expires instead of requesting a new one for every call.

## Authenticate your requests

Send the token in the `Authorization` header of every other request:

```bash theme={null}
curl https://partners-api.kravata.co/api/v1/admin/users \
  --cert client.crt --key client.key \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

When the token expires the API responds with `401`. Request a new one with the same endpoint.

## Production access: mTLS and IP allowlist

For security, the production domain `partners-api.kravata.co` only accepts connections that present the client certificate issued by Kravata for your company, coming from IP addresses you have registered.

<Steps>
  <Step title="Request your mTLS certificate">
    Ask your Kravata point of contact for your **client certificate** (`client.crt`) and **private key** (`client.key`). Store the private key securely: anyone with it and your API credentials can connect as your company.
  </Step>

  <Step title="Present the certificate in every request">
    Configure your HTTP client to send the certificate and key on every production request, including the token request. Connections without a valid certificate are closed during the TLS handshake, before reaching the API.
  </Step>

  <Step title="Register your IP allowlist">
    Call [Update IP Allowlist](/stack/api-reference/authentication/update-ip-allowlist) with the IP ranges of your servers, in CIDR notation. Once a list is registered, requests from any other IP are rejected.
  </Step>
</Steps>

```bash theme={null}
curl -X PUT https://partners-api.kravata.co/api/v1/client/security/ips \
  --cert client.crt --key client.key \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{"allowedIpRanges": ["203.0.113.10/32", "198.51.100.0/24"]}'
```

<Warning>
  The list you send **replaces** the current one. Always include the IP you are calling from: if it is not in the new list, your next requests are rejected, including calls to update the list. Sending an empty list (`[]`) blocks all IPs. If you lock yourself out, contact Kravata to restore access.
</Warning>

### Using the certificate in your HTTP client

<CodeGroup>
  ```python Python (requests) theme={null}
  import requests

  response = requests.post(
      "https://partners-api.kravata.co/api/v1/client/token",
      json={"apiKey": "YOUR_API_KEY", "secretKey": "YOUR_SECRET_KEY"},
      cert=("client.crt", "client.key"),
  )
  ```

  ```javascript Node.js (undici) theme={null}
  import fs from "node:fs";
  import { Agent, fetch } from "undici";

  const dispatcher = new Agent({
    connect: {
      cert: fs.readFileSync("client.crt"),
      key: fs.readFileSync("client.key"),
    },
  });

  const response = await fetch("https://partners-api.kravata.co/api/v1/client/token", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ apiKey: "YOUR_API_KEY", secretKey: "YOUR_SECRET_KEY" }),
    dispatcher,
  });
  ```
</CodeGroup>

In Postman, add the certificate in **Settings → Certificates → Add certificate** for host `partners-api.kravata.co`.

<Note>
  The interactive playground in this documentation cannot present a client certificate, so use it against the test environment. For production, use your own backend, curl or Postman with the certificate configured.
</Note>

<Warning>
  Call the API only from your backend. Your `apiKey`, `secretKey`, certificate private key and access tokens must never reach a browser or a mobile app.
</Warning>
