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

# Create an API token

> POST /console/token/

Creates a new Management API key. This endpoint lives on the **regular** Scanova API host (`qcg-api.scanova.io`) and is authenticated the same way as any other logged-in dashboard request — an OAuth access token, **not** a Management API key.

<Note>
  This is the one Management API–related call you make from a trusted context using your own login, not from the integration that will use the resulting key. See the [overview](/api-reference/management-api/overview) for the full two-host architecture.
</Note>

## Request

```
POST https://qcg-api.scanova.io/console/token/
Authorization: Bearer <your_oauth_access_token>
Content-Type: application/json
```

### Body parameters

<ParamField body="name" type="string" required>
  A human-readable label for the key, e.g. `"Zapier — production"`. Shown in the dashboard's key list so you can tell keys apart.
</ParamField>

<ParamField body="environment" type="string" default="sandbox">
  One of `sandbox`, `live`, `zapier`, `mcp`. Permanent for the life of the key — determines which plan quota is checked on every data-host request the key makes, and for `zapier`/`mcp` keys, which `User-Agent` header the calling client must send. See [Plan quota](/api-reference/management-api/overview#plan-quota) for the full mapping.
</ParamField>

<ParamField body="expiry" type="integer" default="-1">
  One of `-1` (Never), `30`, `90`, or `365` — days after creation the key stops working. There is no way to extend an existing key's expiry; create a new one instead.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://qcg-api.scanova.io/console/token/" \
    -H "Authorization: Bearer <your_oauth_access_token>" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Zapier — production",
      "environment": "zapier",
      "expiry": 365
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "name": "Zapier — production",
    "key": "401f7ac837da42b97f613d789819ff93537bee6a",
    "environment": "zapier",
    "expiry": 365,
    "created_by": {
      "id": 1042,
      "full_name": "Jordan Lee",
      "email": "jordan@example.com"
    },
    "created": "2026-08-16T09:12:33.512000Z",
    "expiry_date": "2027-08-16T09:12:33.512000Z",
    "expired": false,
    "usage_count": 0
  }
  ```
</ResponseExample>

### Response fields

<ResponseField name="key" type="string">
  The raw Management API key. **This is the only response that ever returns the full key value** — there is no reveal/retrieve-later endpoint, so store it immediately.
</ResponseField>

<ResponseField name="expiry_date" type="string | null">
  The absolute expiry timestamp computed from `created` + `expiry` days, or `null` when `expiry` is `-1` (Never).
</ResponseField>

<ResponseField name="expired" type="boolean">
  Whether the key has already passed its `expiry_date`. Expired keys fail authentication on the data host but aren't automatically deleted — remove them explicitly via [`DELETE /console/token/{key}/`](/api-reference/management-api/tokens/remove) if you want them off the list.
</ResponseField>

<ResponseField name="usage_count" type="integer">
  Lifetime count of requests made with this specific key, across its entire history. This is different from the aggregate, environment-wide figures returned by the [usage endpoints](/api-reference/management-api/tokens/usage-stats) below, which sum across every key sharing that environment.
</ResponseField>

## Listing existing tokens

The same `console/token/` path also accepts `GET` (no body) to list every key on the account, returning the same shape as the create response for each. You can filter by environment: `GET /console/token/?environment=live`.

<Note>
  Both creating and listing tokens re-check plan quota using the request's `environment` — the body field on create, the query parameter on list, defaulting to `sandbox` if omitted. If your plan's sandbox and live quotas differ, pass `?environment=live` explicitly when listing live-environment keys, since the default otherwise checks the sandbox quota.
</Note>

## Related

* [Management API overview](/api-reference/management-api/overview) — the two-host architecture and per-`environment` quota mapping this endpoint's `environment` field feeds into.
* [Remove an API token](/api-reference/management-api/tokens/remove) — revoke a key created here.
* [Usage statistics](/api-reference/management-api/tokens/usage-stats) — aggregate request counts for keys sharing an environment.
* [List / create QR codes](/api-reference/management-api/qr/list) — the first data endpoint most integrations call with a key created here.


## OpenAPI

````yaml api-reference/openapi/management-api.json POST /console/token/
openapi: 3.1.0
info:
  title: Scanova Management API (v2)
  description: >-
    The complete Scanova Management API — every endpoint available at
    management.scanova.io (QR codes, folders, tags, leads, forms, analytics,
    plans, shared users & roles), plus the token-creation and usage-stats
    endpoints used to authenticate against it. Every path and request/response
    shape below was verified live against a real API key and the actual running
    backend (Phase 7, 2026-08-16) — not guessed from reading urls.py alone.
  version: 2.0.0
servers:
  - url: https://management.scanova.io
    description: Management API — QR/folder/tag/lead/form/analytics/plans endpoints
security:
  - apiKeyAuth: []
paths:
  /console/token/:
    post:
      summary: Create an API token
      operationId: createApiToken
      responses:
        '201':
          description: Token created
components:
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        Send your Management API key as the raw value of the Authorization
        header — no "Bearer " or "Token " prefix, and no other characters.
        Example: `Authorization: 401f7ac837da42b97f613d789819ff93537bee6a`. A
        header containing more than one space-separated part is rejected
        outright. Requests also require the request's Host header to be the
        management API host (e.g. management.scanova.io) — the same key sent to
        the regular API host will not authenticate.

````