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

# Authentication

> Obtain and use OAuth2 Bearer tokens for the Fundflow API and Finance API.

Both APIs use **OAuth2 client credentials flow**. Every request requires a short-lived Bearer token in the `Authorization` header.

***

## Get an Access Token

Exchange your Client ID and Secret at the token endpoint for your environment:

| Environment | URL                                                                                     |
| ----------- | --------------------------------------------------------------------------------------- |
| Staging     | `https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token` |
| Production  | `https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token`         |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=client_credentials" \
    -d "client_id=YOUR_CLIENT_ID" \
    -d "client_secret=YOUR_CLIENT_SECRET"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    'https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token',
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'client_credentials',
        client_id: process.env.CLIENT_ID,
        client_secret: process.env.CLIENT_SECRET,
      }),
    }
  );
  const { access_token, expires_in } = await response.json();
  ```

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

  response = requests.post(
      'https://login-staging.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token',
      data={
          'grant_type': 'client_credentials',
          'client_id': os.environ['CLIENT_ID'],
          'client_secret': os.environ['CLIENT_SECRET'],
      }
  )
  access_token = response.json()['access_token']
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 300,
  "token_type": "Bearer"
}
```

<Tip>
  Tokens expire after **5 minutes** (300 seconds). Build token refresh into your client — see [Token Refresh](#token-refresh) below.
</Tip>

***

## Use the Token

Pass the `access_token` as a Bearer token on every request:

**Fundflow API:**

```bash theme={null}
curl -X GET https://api-fundflow-staging.venly.io/v1/company \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

**Finance API:**

```bash theme={null}
curl -X GET https://api-staging.venlyfinance.com/v1/parties \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

***

## Token Refresh

Request a new token before the current one expires. A 30-second buffer is sufficient:

```javascript theme={null}
let accessToken = null;
let tokenExpiresAt = 0;

async function getToken() {
  if (Date.now() < tokenExpiresAt - 30_000) return accessToken;

  const res = await fetch(TOKEN_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.CLIENT_ID,
      client_secret: process.env.CLIENT_SECRET,
    }),
  });

  const data = await res.json();
  accessToken = data.access_token;
  tokenExpiresAt = Date.now() + data.expires_in * 1000;
  return accessToken;
}
```

A `401 Unauthorized` response means the token has expired — re-authenticate and retry the request once.

***

## Environments

|                    | Staging                            | Production                 |
| ------------------ | ---------------------------------- | -------------------------- |
| **Token endpoint** | `login-staging.venly.io`           | `login.venly.io`           |
| **Fundflow API**   | `api-fundflow-staging.venly.io/v1` | `api-fundflow.venly.io/v1` |
| **Finance API**    | `api-staging.venlyfinance.com/v1`  | `api.venlyfinance.com/v1`  |

<Info>
  Staging credentials and production credentials are separate. Staging calls do not move real funds.
</Info>

See [Endpoints & URLs](/getting-started/endpoints) for the complete base URL reference.

***

## Security

* Store `CLIENT_ID` and `CLIENT_SECRET` in environment variables or a secrets manager — never in source code or version control.
* Never log or expose tokens in client-side code.
* Treat a leaked secret as compromised immediately — rotate it via your Venly account and invalidate any outstanding tokens.
