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

# Authentication

> API key authentication, key format, and dual auth endpoints

<blockquote className="agent-llms-directive">
  For the complete documentation index, see <a href="/llms.txt">llms.txt</a>.
</blockquote>

Xquik uses API key authentication for all developer-facing endpoints.

## API Key Format

Keys follow this format:

```text theme={null}
xq_YOUR_KEY_HERE
```

* **Prefix:** `xq_`
* **Body:** 64 hexadecimal characters
* **Storage:** Hashed in database (raw key never stored)

## Using your API key

Pass the key in the `x-api-key` header:

<CodeGroup>
  ```bash cURL theme={null}
  curl https://xquik.com/api/v1/account \
    -H "x-api-key: xq_YOUR_KEY_HERE"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://xquik.com/api/v1/account", {
    headers: { "x-api-key": "xq_YOUR_KEY_HERE" },
  });
  ```

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

  response = requests.get(
      "https://xquik.com/api/v1/account",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
  )
  ```

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

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

  func main() {
  	req, _ := http.NewRequest("GET", "https://xquik.com/api/v1/account", nil)
  	req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")

  	resp, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	defer resp.Body.Close()

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

## Auth methods by endpoint

Most endpoints support **dual authentication**: either an API key or a session cookie from the dashboard.

<CardGroup cols={2}>
  <Card title="API key only" icon="key-round">
    `GET /account` accepts `x-api-key`. Use it to check plan, credit balance, and monitor billing from server-side integrations.
  </Card>

  <Card title="Session cookie only" icon="shield">
    `POST /api-keys`, `GET /api-keys`, and `DELETE /api-keys/{id}` require a dashboard session cookie.
  </Card>

  <Card title="Account and billing" icon="user-cog">
    `PATCH /account`, `PUT /account/x-identity`, and `POST /subscribe` accept either `x-api-key` or a dashboard session cookie.
  </Card>

  <Card title="Events and webhooks" icon="radio">
    `* /monitors/*`, `GET /events/*`, `* /webhooks/*`, and `GET /webhooks/{id}/deliveries` accept either auth method.
  </Card>

  <Card title="Data and X actions" icon="database">
    `* /draws/*`, `* /extractions/*`, `* /x/*`, `POST /x/media/download`, `* /x-accounts/*`, and `* /x-write/*` accept either auth method.
  </Card>

  <Card title="Content tools and support" icon="sparkles">
    `GET /trends`, `GET /radar`, `* /styles/*`, `* /drafts/*`, `POST /compose`, and `* /support/*` accept either auth method.
  </Card>
</CardGroup>

<Info>
  Use a dashboard session cookie to create the first API key. Existing API keys and OAuth bearer tokens can manage keys for the same account.
</Info>

<Info>
  The MCP server also supports OAuth 2.1 with PKCE for browser-based clients (Claude.ai, ChatGPT Developer Mode). See [OAuth 2.1](/oauth/overview) for the complete flow.
</Info>

## Machine Payments Protocol

32 X-API read-only endpoints also accept [MPP](/mpp/overview) payments instead of API key authentication. When you call an eligible endpoint without an API key or session cookie, the server returns a 402 payment challenge.

### Challenge header

```text theme={null}
WWW-Authenticate: Payment id="...", realm="xquik.com", method="tempo", intent="charge", request="..."
```

| Parameter | Description                                                 |
| --------- | ----------------------------------------------------------- |
| `id`      | Unique challenge identifier                                 |
| `realm`   | Protection space (`xquik.com`)                              |
| `method`  | Payment method (`tempo`)                                    |
| `intent`  | Payment intent (`charge` or `session`)                      |
| `request` | Base64url-encoded JSON with amount, currency, and recipient |

### Credential header

After completing the payment, retry the request with a payment credential:

```text theme={null}
Authorization: Payment <base64url-encoded JSON>
```

The credential contains the original challenge parameters and a method-specific payload proving payment.

### Receipt header

Settled responses include a receipt:

```text theme={null}
Payment-Receipt: <base64url-encoded JSON>
```

The receipt confirms the payment was settled and includes a reference ID and timestamp. The header is attached only to successful 2xx responses for both charge and session intents. Error responses use the status code and response body without a receipt header.

### Eligible endpoints

See the [MPP overview](/mpp/overview#eligible-endpoints) for the full list of 31 endpoints, pricing, and intent types.

<Info>
  MPP only applies to eligible X-API read-only endpoints. Media downloads, private reads, write actions, and all other endpoints require an API key or session cookie.
</Info>

## Key management

### Create a Key

Generate keys from the **API Keys** page in your dashboard or via the API (session auth only):

```bash Create API Key theme={null}
curl -X POST https://xquik.com/api/v1/api-keys \
  -H "Cookie: session_token=YOUR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{"name": "Production"}'
```

The full key (`fullKey`) is returned **once** in the creation response. Store it securely.

### Revoke a Key

```bash Revoke API Key theme={null}
curl -X DELETE https://xquik.com/api/v1/api-keys/123 \
  -H "Cookie: session_token=YOUR_SESSION"
```

Revoked keys are deactivated immediately and cannot be reactivated.

## Error response

Invalid or missing API key returns:

```json theme={null}
{
  "error": "unauthenticated"
}
```

**Status:** `401 Unauthorized`

## Security best practices

<AccordionGroup>
  <Accordion title="Store keys in environment variables">
    Never hardcode API keys in your source code. Use environment variables to keep keys separate from your codebase:

    ```bash .env theme={null}
    XQUIK_API_KEY=xq_YOUR_KEY_HERE
    ```

    Access the key in your application:

    <CodeGroup>
      ```javascript Node.js theme={null}
      const apiKey = process.env.XQUIK_API_KEY;
      ```

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

      api_key = os.environ["XQUIK_API_KEY"]
      ```

      ```go Go theme={null}
      apiKey := os.Getenv("XQUIK_API_KEY")
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Never commit keys to version control">
    Add `.env` to your `.gitignore` to prevent accidental commits:

    ```bash .gitignore theme={null}
    # Environment variables
    .env
    .env.local
    .env.production
    ```

    If a key is accidentally committed, revoke it immediately from your dashboard and generate a new one. Consider the exposed key compromised even if you force-push to remove it from history.
  </Accordion>

  <Accordion title="Rotate keys regularly">
    Rotate API keys periodically to limit the impact of a potential leak:

    1. Create a new key from the dashboard
    2. Update the key in all your environments
    3. Verify all services work with the new key
    4. Revoke the old key

    Xquik supports multiple active keys, so you can rotate without downtime.
  </Accordion>

  <Accordion title="Use separate keys for development & production">
    Create distinct API keys for each environment. This limits blast radius if a development key is compromised and makes it easier to track usage per environment:

    ```bash .env.local theme={null}
    # Development
    XQUIK_API_KEY=xq_dev_key_here
    ```

    ```bash .env.production theme={null}
    # Production
    XQUIK_API_KEY=xq_prod_key_here
    ```

    Name your keys descriptively (e.g., "Production - Backend", "Staging", "Local Dev") so you can identify them in the dashboard.
  </Accordion>
</AccordionGroup>

<Note>
  **Next steps:** [Quickstart](/quickstart) for a complete setup walkthrough, or [OAuth Overview](/oauth/overview) for OAuth 2.1 integration.
</Note>
