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

# Authentication

> Authenticate requests to the Dotlet API with an API key or a bearer token.

The Dotlet API supports two ways to authenticate, depending on where the request comes from.

| Method           | Use when                                                                           | Header                          |
| ---------------- | ---------------------------------------------------------------------------------- | ------------------------------- |
| **API key**      | Calling the API directly from a server, script, or backend integration             | `X-API-Key`                     |
| **Bearer token** | Calling the API on behalf of a signed-in user, such as from a dashboard or session | `Authorization: Bearer <token>` |

Most endpoints accept either method. **DNS record endpoints are the exception**: `create`, `get`, `update`, `delete`, and `sync` on `/api/v1/registrar/dns/{domain_name}/records/*` currently accept an **API key only**. Listing records (`GET /api/v1/registrar/dns/{domain_name}/records`) accepts either method, same as everything else.

## Authenticate with an API key

Generate an API key from your Dotlet dashboard, then pass it on every request in the `X-API-Key` header.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.dotlet.net/api/v1/registrar/availability/example.com \
    -H "X-API-Key: dk_••••••••••••••••"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.dotlet.net/api/v1/registrar/availability/example.com', {
    headers: { 'X-API-Key': 'dk_••••••••••••••••' }
  });
  const data = await response.json();
  console.log(data);
  ```

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

  response = requests.get(
      'https://api.dotlet.net/api/v1/registrar/availability/example.com',
      headers={'X-API-Key': 'dk_••••••••••••••••'}
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	req, _ := http.NewRequest("GET", "https://api.dotlet.net/api/v1/registrar/availability/example.com", nil)
  	req.Header.Set("X-API-Key", "dk_••••••••••••••••")

  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()

  	body, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(body))
  }
  ```
</CodeGroup>

<Warning>
  Treat your API key like a password. Don't commit it to version control or expose it in client-side code. If a key is exposed, revoke it from your dashboard and generate a new one.
</Warning>

## Authenticate with a bearer token

For endpoints that operate on behalf of a signed-in user, obtain a token from the password token endpoint and send it in the `Authorization` header.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.dotlet.net/api/v1/registrar/dns/example.com/records \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.dotlet.net/api/v1/registrar/dns/example.com/records', {
    headers: { 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' }
  });
  const data = await response.json();
  console.log(data);
  ```

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

  response = requests.get(
      'https://api.dotlet.net/api/v1/registrar/dns/example.com/records',
      headers={'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'}
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	req, _ := http.NewRequest("GET", "https://api.dotlet.net/api/v1/registrar/dns/example.com/records", nil)
  	req.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")

  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()

  	body, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(body))
  }
  ```
</CodeGroup>

Tokens expire. If a request fails with a `401`, request a new token rather than retrying with the expired one.

<Note>
  This example works because listing DNS records accepts either an API key or a bearer token. Creating, reading a single record, updating, deleting, or syncing records currently accepts an **API key only**, use `X-API-Key` for those, even in a session-based context.
</Note>

## Handling authentication errors

| Status             | Meaning                                                       | Fix                                                                       |
| ------------------ | ------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `401 Unauthorized` | No credentials were sent, or the token has expired            | Include a valid `X-API-Key` or `Authorization` header                     |
| `403 Forbidden`    | Credentials were valid but don't have access to this resource | Confirm the key belongs to the organization that owns the domain or order |

## Next step

<Card title="Quickstart" icon="rocket" href="/quickstart">
  Use your API key to check domain availability and register your first domain.
</Card>
