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

# Vendor Authentication

> Authenticate with the PuppetVendors V2 API using a vendor API key

<Note>
  **V2 Preview** — This authentication flow is part of the V2 API preview. Breaking changes may occur.
</Note>

## Overview

All V2 Vendor API endpoints require a JWT token passed via the `x-access-token` header. There are two ways to get a token:

| Method           | Best For                           | Endpoint                  |
| ---------------- | ---------------------------------- | ------------------------- |
| **API Key**      | Integrations, scripts, AI agents   | `POST /authenticate`      |
| **Portal Login** | Custom vendor portals, mobile apps | `POST /portal/auth/login` |

## Method 1: API Key Authentication (Recommended)

Use this for programmatic access. Your vendor API key starts with `vk_`.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://staging-api.puppetvendors.com/authenticate \
    -H "Content-Type: application/json" \
    -d '{
      "apiKey": "vk_live_YOUR_VENDOR_API_KEY"
    }'
  ```

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

  resp = requests.post(
      "https://staging-api.puppetvendors.com/authenticate",
      json={"apiKey": "vk_live_YOUR_VENDOR_API_KEY"}
  )
  token = resp.json()["data"]["token"]
  ```

  ```javascript JavaScript theme={null}
  const resp = await fetch("https://staging-api.puppetvendors.com/authenticate", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ apiKey: "vk_live_YOUR_VENDOR_API_KEY" })
  });
  const { data } = await resp.json();
  const token = data.token;
  ```
</CodeGroup>

```json 200 theme={null}
{
  "success": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expiresIn": 86400,
    "scope": "vendor",
    "permissions": ["orders:read", "products:read", "products:write"],
    "shopDomain": "my-store.myshopify.com",
    "mode": "live",
    "vendorId": "507f1f77bcf86cd799439012"
  }
}
```

* `scope` is always `"vendor"` for vendor tokens — it's the token type
* `permissions` lists the specific scopes granted to your API key (e.g., `orders:read`, `products:write`)

### Getting a Vendor API Key

You can create API keys in the vendor portal under **Settings > API Keys**, or your merchant can provide one. See [API Keys & Scopes](/api-reference/v2/vendor/api-keys-scopes) for details on key permissions.

## Method 2: Portal Login

Use this if you're building a custom login experience for vendors.

```bash theme={null}
curl -X POST https://staging-api.puppetvendors.com/portal/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "vendor@example.com",
    "password": "your-password",
    "shopDomain": "my-store.myshopify.com"
  }'
```

<Info>
  Portal login is rate limited to **5 attempts per 15 minutes** per IP address.
</Info>

## Using the Token

Include the token in all subsequent requests via the `x-access-token` header:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://staging-api.puppetvendors.com/orders?first=10" \
    -H "x-access-token: YOUR_JWT_TOKEN"
  ```

  ```python Python theme={null}
  resp = requests.get(
      "https://staging-api.puppetvendors.com/orders",
      params={"first": 10},
      headers={"x-access-token": token}
  )
  orders = resp.json()["data"]["items"]
  ```

  ```javascript JavaScript theme={null}
  const resp = await fetch("https://staging-api.puppetvendors.com/orders?first=10", {
    headers: { "x-access-token": token }
  });
  const { data } = await resp.json();
  ```
</CodeGroup>

## Token Expiry & Refresh

Tokens expire after **24 hours** (86400 seconds). Use `POST /refresh-token` with a valid (non-expired) token to get a new one without re-authenticating:

```bash theme={null}
curl -X POST https://staging-api.puppetvendors.com/refresh-token \
  -H "x-access-token: YOUR_CURRENT_TOKEN"
```

## Scope Behaviour

Vendor-scoped tokens automatically filter all data to your vendor account. For example, calling `GET /orders` will only return orders containing your line items. Attempting to access another vendor's data returns HTTP 403.

## API Key Scopes

API keys can be restricted to specific permissions. See the full [API Keys & Scopes reference](/api-reference/v2/vendor/api-keys-scopes) for a complete list of available scopes and what each one grants access to.
