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

# Authentication

> Authenticate to the Platform API using client credentials to manage products programmatically.

The Platform API uses OAuth 2.0 client credentials for authentication. This guide walks you through obtaining and using access tokens.

## Prerequisites

<Check>
  You must have access to Product Portal in the [Fiskil Console](https://console.fiskil.com/) to generate API keys.
</Check>

## Generate API credentials

<Steps>
  <Step title="Navigate to API Keys">
    In the Fiskil Console, navigate to **API Keys** in the sidebar.
  </Step>

  <Step title="Select permissions">
    Generate credentials with the appropriate product management scopes:

    | Scope                         | Description                                           |
    | ----------------------------- | ----------------------------------------------------- |
    | `api:provider.products.read`  | List and view products through internal API endpoints |
    | `api:provider.products.write` | Create, update, and delete products                   |

    <Note>
      Public API endpoints are visible globally and do not require read permissions.
    </Note>
  </Step>

  <Step title="Store credentials securely">
    After generating, the Console displays a **Client ID** and **Client Secret** pair. Store these securely - you'll need them to obtain access tokens.

    <Warning>
      The client secret is only shown once. Store it in a secure location such as secrets manager.
    </Warning>
  </Step>
</Steps>

## Obtain an access token

Exchange your client credentials for a short-lived access token:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.fiskil.com/v1/token \
    -H "Content-Type: application/json" \
    -d '{
      "client_id": "your_client_id",
      "client_secret": "your_client_secret"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.fiskil.com/v1/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: process.env.FISKIL_CLIENT_ID,
      client_secret: process.env.FISKIL_CLIENT_SECRET
    })
  });

  const { token, expires_in } = await response.json();
  ```

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

  response = requests.post(
      'https://api.fiskil.com/v1/token',
      json={
          'client_id': 'your_client_id',
          'client_secret': 'your_client_secret'
      }
  )

  data = response.json()
  token = data['token']
  expires_in = data['expires_in']
  ```
</CodeGroup>

<ResponseExample>
  ```json Success theme={null}
  {
    "token": "eyJhbGc....",
    "expires_in": 900
  }
  ```
</ResponseExample>

### Response fields

<ResponseField name="token" type="string" required>
  The access token to use in the `Authorization` header for subsequent API requests.
</ResponseField>

<ResponseField name="expires_in" type="integer" required>
  Token validity period in seconds. Default is 900 seconds (15 minutes).
</ResponseField>

## Make authenticated requests

Include the access token in the `Authorization` header using the Bearer scheme:

```bash theme={null}
curl -X GET https://api.fiskil.com/v1/data-provider/cdr/products \
  -H "Authorization: Bearer eyJhbGc...."
```

<Tip>
  Tokens expire after 15 minutes. Implement token refresh logic in your application to obtain new tokens before expiry.
</Tip>

## Error responses

| Status Code             | Description                                      |
| ----------------------- | ------------------------------------------------ |
| `401 Unauthorized`      | Invalid or expired credentials                   |
| `403 Forbidden`         | Insufficient permissions for the requested scope |
| `429 Too Many Requests` | Rate limit exceeded                              |

<AccordionGroup>
  <Accordion title="Invalid credentials">
    ```json theme={null}
    {
      "error": "invalid_client",
      "error_description": "The client credentials are invalid"
    }
    ```

    **Solution:** Verify your client ID and secret are correct and haven't been revoked.
  </Accordion>

  <Accordion title="Insufficient permissions">
    ```json theme={null}
    {
      "error": "insufficient_scope",
      "error_description": "The access token does not have the required scope"
    }
    ```

    **Solution:** Generate new API credentials with the required scopes.
  </Accordion>
</AccordionGroup>

## Security best practices

* **Never expose credentials** in client-side code or version control
* **Rotate secrets regularly** and revoke unused credentials
* **Use environment variables** or a secrets manager for credential storage
* **Implement token caching** to reduce authentication requests
* **Monitor API usage** through the Console for unusual activity
