> ## 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.

# Merchant Authentication

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

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

## Overview

All V2 Merchant API endpoints require a JWT token passed via the `x-access-token` header. You obtain the token by exchanging your merchant API key at `POST /authenticate`.

Merchant API keys start with `mk_live_` (or `mk_test_` for test mode) and are created in the PuppetVendors admin under **Settings → API Access**. The full key is revealed once at creation.

## Authenticating

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

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

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

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

```json 200 theme={null}
{
  "success": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expiresIn": 1209600,
    "scope": "merchant",
    "shopDomain": "my-store.myshopify.com"
  }
}
```

* `scope` is `"merchant"` for merchant tokens — vendor keys (`vk_`) authenticate at the same endpoint but return `"vendor"` scope
* The key's prefix determines the token scope: `mk_` keys mint merchant-scoped tokens with the `admin:users`, `admin:vendors`, and `admin:payouts` permissions

## Using the Token

Include the token in all subsequent requests via the `x-access-token` header. Send the token value directly, with no `Bearer` prefix:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://production-api.puppetvendors.com/vendors?page=1&limit=20" \
    -H "x-access-token: YOUR_JWT_TOKEN"
  ```

  ```python Python theme={null}
  resp = requests.get(
      "https://production-api.puppetvendors.com/vendors",
      params={"page": 1, "limit": 20},
      headers={"x-access-token": token}
  )
  ```

  ```javascript JavaScript theme={null}
  const resp = await fetch("https://production-api.puppetvendors.com/vendors?page=1&limit=20", {
    headers: { "x-access-token": token }
  });
  ```
</CodeGroup>

## Token Expiry & Refresh

Merchant tokens expire after **14 days** (1209600 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://production-api.puppetvendors.com/refresh-token \
  -H "x-access-token: YOUR_CURRENT_TOKEN"
```

Revoking the key refuses the next request made with any token minted from it.

## Verifying a Key

`POST /verify` is a side-effect-free probe: it confirms the key is valid and reachable and returns the scope, mode, and identity it carries, but does **not** issue a JWT or count as a use (`lastUsedAt` is unchanged). Any key that passes `/verify` will also pass `/authenticate`.

```bash theme={null}
curl -X POST https://production-api.puppetvendors.com/verify \
  -H "Content-Type: application/json" \
  -d '{ "apiKey": "mk_live_YOUR_MERCHANT_API_KEY" }'
```

## Key Rotation & Revocation

* **Rotate** a key in **Settings → API Access** — the previous key keeps working for a **24-hour grace window**, so a rotation is an overlap rather than a cutover
* **Revoke** a key to immediately refuse any token minted from it

## Scope Behaviour

Merchant tokens administer the whole shop: vendor management, user management, and payout adjustments across all vendors. Endpoints outside the merchant surface (orders, products, payouts, fulfillments, documents) return HTTP 403 — those stay on the V1 API token.
