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

# Authenticate requests to the SphereScout API

> Learn both authentication methods for the SphereScout API: long-lived API keys for integrations and JWT bearer tokens for user-session-based applications.

Every request to a protected SphereScout endpoint must include an `Authorization` header. The API supports two authentication methods: **API keys** for server-to-server integrations and **JWT bearer tokens** for user-session-based applications. Both use the same header format — only the credential type differs.

## Choose an authentication method

|                | API keys                                      | JWT tokens                               |
| -------------- | --------------------------------------------- | ---------------------------------------- |
| **Best for**   | Server integrations, scripts, automation      | User-facing apps, per-user sessions      |
| **Lifetime**   | No expiry by default (or set a custom expiry) | Short-lived; must be refreshed           |
| **Setup**      | Generate once in the Dashboard                | Login endpoint → access + refresh tokens |
| **Complexity** | Low                                           | Higher (requires token-refresh logic)    |

<Tip>
  For most integrations, API keys are the simpler and more reliable choice. Use JWT tokens only when your application needs to act on behalf of a specific logged-in user.
</Tip>

***

## API key authentication

API keys are long-lived credentials that you generate in the Dashboard or via the API. Include your API key directly as the Bearer token in every request.

```
Authorization: Bearer YOUR_API_KEY
```

<CodeGroup>
  ```bash curl theme={null}
  curl "https://www.spherescout.io/api/user/profile" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

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

  API_KEY = "YOUR_API_KEY"

  response = requests.get(
      "https://www.spherescout.io/api/user/profile",
      headers={"Authorization": f"Bearer {API_KEY}"},
  )
  response.raise_for_status()
  profile = response.json()
  print(profile)
  ```
</CodeGroup>

See [API keys](/api-access/api-keys) for how to create, list, and revoke keys.

***

## JWT token authentication

JWT authentication involves three steps: logging in to obtain tokens, using the access token in requests, and refreshing the access token before it expires.

### Step 1 — Obtain tokens

Send a POST request to `/api/auth/login` with your account credentials. The response contains an access token and a refresh token.

**Request**

<ParamField body="username" type="string" required>
  Your account email address. The field is named `username` in the request body.
</ParamField>

<ParamField body="password" type="string" required>
  Your account password.
</ParamField>

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://www.spherescout.io/api/auth/login" \
    -H "Content-Type: application/json" \
    -d '{
      "username": "you@example.com",
      "password": "your-password"
    }'
  ```

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

  response = requests.post(
      "https://www.spherescout.io/api/auth/login",
      json={
          "username": "you@example.com",
          "password": "your-password",
      },
  )
  response.raise_for_status()
  tokens = response.json()

  access_token = tokens["access"]
  refresh_token = tokens["refresh"]
  print(f"Access token: {access_token[:20]}...")
  ```
</CodeGroup>

**Response fields**

<ResponseField name="access" type="string" required>
  Short-lived JWT access token. Use this as your Bearer token in subsequent requests.
</ResponseField>

<ResponseField name="refresh" type="string" required>
  Long-lived refresh token. Use this to obtain a new access token when the current one expires. Store this token securely — treat it like a password.
</ResponseField>

<ResponseField name="user" type="object">
  Account information returned at login.

  <Expandable title="user properties">
    <ResponseField name="id" type="string">
      Unique account identifier.
    </ResponseField>

    <ResponseField name="email" type="string">
      Account email address.
    </ResponseField>

    <ResponseField name="first_name" type="string">
      First name on the account.
    </ResponseField>

    <ResponseField name="last_name" type="string">
      Last name on the account.
    </ResponseField>

    <ResponseField name="remaining_credits" type="number">
      Credits available for exports this billing period.
    </ResponseField>

    <ResponseField name="subscription_plan" type="string">
      Current subscription plan name.
    </ResponseField>
  </Expandable>
</ResponseField>

### Step 2 — Use the access token

Include the access token as a Bearer token in the `Authorization` header of every request:

```
Authorization: Bearer ACCESS_TOKEN
```

<CodeGroup>
  ```bash curl theme={null}
  curl "https://www.spherescout.io/api/companies?countries=DE&email=true" \
    -H "Authorization: Bearer ACCESS_TOKEN"
  ```

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

  headers = {"Authorization": f"Bearer {access_token}"}

  response = requests.get(
      "https://www.spherescout.io/api/companies",
      headers=headers,
      params={"countries": "DE", "email": "true"},
  )
  response.raise_for_status()
  data = response.json()
  print(f"Total contacts: {data['totalCount']}")
  ```
</CodeGroup>

### Step 3 — Refresh the access token

Access tokens expire after a short period. When a request returns `401 Unauthorized`, exchange your refresh token for a new access token by calling `POST /api/token/refresh`.

**Request**

<ParamField body="refresh" type="string" required>
  The refresh token you received when you logged in.
</ParamField>

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://www.spherescout.io/api/token/refresh" \
    -H "Content-Type: application/json" \
    -d '{"refresh": "YOUR_REFRESH_TOKEN"}'
  ```

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

  def refresh_access_token(refresh_token: str) -> str:
      response = requests.post(
          "https://www.spherescout.io/api/token/refresh",
          json={"refresh": refresh_token},
      )
      response.raise_for_status()
      data = response.json()
      return data["access"]

  # Call when you receive a 401
  new_access_token = refresh_access_token(refresh_token)
  ```
</CodeGroup>

**Response fields**

<ResponseField name="access" type="string" required>
  A new short-lived access token. Replace the expired token in your application with this value.
</ResponseField>

<ResponseField name="refresh" type="string">
  A new refresh token, if token rotation is enabled. Update your stored refresh token if this field is present in the response.
</ResponseField>

***

## Error responses

### 401 Unauthorized

A `401` response means your credential is missing, invalid, or expired.

```json theme={null}
{
  "detail": "Authentication credentials were not provided."
}
```

```json theme={null}
{
  "detail": "Given token not valid for any token type",
  "code": "token_not_valid"
}
```

**What to do:**

* **API key:** Verify the key is correctly copied and has not been revoked in the Dashboard.
* **JWT access token:** The token has expired. Call `POST /api/token/refresh` with your refresh token to get a new access token.
* **JWT refresh token:** If the refresh call also returns `401`, the refresh token has expired or been invalidated. Re-authenticate by calling `POST /api/auth/login` again.

### Full JWT refresh pattern

The following Python example shows a complete pattern for handling token expiry automatically:

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

BASE_URL = "https://www.spherescout.io"

class SphereScoutClient:
    def __init__(self, email: str, password: str):
        self.email = email
        self.password = password
        self.access_token: str | None = None
        self.refresh_token: str | None = None

    def login(self) -> None:
        response = requests.post(
            f"{BASE_URL}/api/auth/login",
            json={"username": self.email, "password": self.password},
        )
        response.raise_for_status()
        data = response.json()
        self.access_token = data["access"]
        self.refresh_token = data["refresh"]

    def _refresh(self) -> None:
        if not self.refresh_token:
            raise RuntimeError("No refresh token — call login() first")
        response = requests.post(
            f"{BASE_URL}/api/token/refresh",
            json={"refresh": self.refresh_token},
        )
        response.raise_for_status()
        data = response.json()
        self.access_token = data["access"]
        if "refresh" in data:
            self.refresh_token = data["refresh"]

    def get(self, path: str, **kwargs) -> dict:
        headers = {"Authorization": f"Bearer {self.access_token}"}
        response = requests.get(f"{BASE_URL}{path}", headers=headers, **kwargs)
        if response.status_code == 401:
            self._refresh()
            headers["Authorization"] = f"Bearer {self.access_token}"
            response = requests.get(f"{BASE_URL}{path}", headers=headers, **kwargs)
        response.raise_for_status()
        return response.json()


# Usage
client = SphereScoutClient("you@example.com", "your-password")
client.login()
data = client.get("/api/companies", params={"countries": "US", "email": "true"})
print(f"Found {data['totalCount']} contacts")
```

***

## Summary

<Note>
  For server-to-server integrations, use an API key — it requires no token management and works with a single header on every request. Reserve JWT tokens for applications where individual users log in with their own SphereScout credentials.
</Note>
