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

# Authentication

> Exchange your client ID and client secret for an access token.

All Partner API endpoints (other than the authentication endpoint itself) require a short-lived bearer access token. You get one by calling:

```
POST /api/v3/partners/auth
```

## Request

Send your client ID and client secret as HTTP Basic credentials in the `Authorization` header — **not** in the request body.

```
Authorization: Basic base64(client_id:client_secret)
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://be-dev-1.dev.ndovu.co/api/v3/partners/auth \
    -H "Authorization: Basic $(echo -n 'YOUR_CLIENT_ID:YOUR_CLIENT_SECRET' | base64)"
  ```

  ```javascript Node.js theme={null}
  const credentials = Buffer.from(
    `${process.env.NDOVU_CLIENT_ID}:${process.env.NDOVU_CLIENT_SECRET}`
  ).toString("base64");

  const res = await fetch("https://be-dev-1.dev.ndovu.co/api/v3/partners/auth", {
    method: "POST",
    headers: { Authorization: `Basic ${credentials}` },
  });

  const { access_token, expires_in, token_type } = await res.json();
  ```

  ```python Python theme={null}
  import base64
  import requests

  credentials = base64.b64encode(
      f"{CLIENT_ID}:{CLIENT_SECRET}".encode()
  ).decode()

  res = requests.post(
      "https://be-dev-1.dev.ndovu.co/api/v3/partners/auth",
      headers={"Authorization": f"Basic {credentials}"},
  )
  res.raise_for_status()
  token = res.json()["access_token"]
  ```
</CodeGroup>

No request body is required or accepted.

## Response

A successful call returns:

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 3600,
  "token_type": "Bearer"
}
```

| Field          | Type   | Description                                           |
| -------------- | ------ | ----------------------------------------------------- |
| `access_token` | string | JWT to send as a bearer token on subsequent requests. |
| `expires_in`   | number | Lifetime of the token, in seconds.                    |
| `token_type`   | string | Always `Bearer`.                                      |

<Note>
  There is no refresh token. When `access_token` expires, call this endpoint
  again with your client ID and client secret to get a new one.
</Note>

## Using the token

Pass the token as a bearer token on every subsequent request:

```
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

See [Getting Products](/getting-products) for the next step.

## Errors

| Status             | Cause                                                    |
| ------------------ | -------------------------------------------------------- |
| `401 Unauthorized` | Client ID doesn't exist, or client secret doesn't match. |
| `400 Bad Request`  | Missing or malformed `Authorization` header.             |

If you get a `401`, double-check you're sending the **raw** client secret from your onboarding email — not a hashed or re-encoded version of it. If you've lost the original secret, contact [support@ndovu.co](mailto:support@ndovu.co) to have it rotated; we only ever store a one-way hash of it and cannot recover the original value.
