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

# Quickstart

> Get your first product verification working in about five minutes using a test chip — no hardware required.

This guide walks you through the full verification flow end-to-end: create a collection, add a unit, attach a test chip, simulate a tap, and verify it. Every step uses `curl`.

<Note>
  Every `/v1/*` request includes your API key in the `Authorization` header —
  `Authorization: Bearer end_sk_test_...`. Keep it server-side only, and never
  expose it in browser code. See [Authentication](/authentication) for the full
  details on credential types and session tokens.
</Note>

<Steps>
  <Step title="Create a collection">
    A collection groups related units under one product line. Create one first — units belong to a collection, and the collection must be active before units can be issued.

    ```bash theme={null}
    curl -X POST https://api2.endstate.io/v1/collections \
      -H "Authorization: Bearer end_sk_test_..." \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Summer Tee 2026"
      }'
    ```

    ```json theme={null}
    {
      "id": "8e1a7f50-90ab-4cde-b012-3456789abcde",
      "name": "Summer Tee 2026",
      "external_id": null,
      "redirect_url": null,
      "contract": {
        "status": "deploying",
        "address": "0x1111111111111111111111111111111111111111",
        "chain_id": 84532
      }
    }
    ```

    <Note>
      Single-resource responses return their fields at the top level; list responses
      wrap their array under a plural key. See [Response
      shape](/conventions/responses).
    </Note>

    <Note>
      The collection is created on your organization's **default network**,
      configured by Endstate at onboarding — no network field needed. You can read
      it (and the networks enabled for your organization) from `GET /v1/settings`,
      and pass `chain_id` explicitly only to override it.
    </Note>

    The collection returns immediately with `contract.status: "deploying"` — provisioning is asynchronous. Poll `GET /v1/collections/{collection_id}` until `contract.status` is `"active"` before proceeding.

    ```bash theme={null}
    curl https://api2.endstate.io/v1/collections/8e1a7f50-90ab-4cde-b012-3456789abcde \
      -H "Authorization: Bearer end_sk_test_..."
    ```

    ```json theme={null}
    {
      "id": "8e1a7f50-90ab-4cde-b012-3456789abcde",
      "name": "Summer Tee 2026",
      "external_id": null,
      "redirect_url": null,
      "contract": {
        "status": "active",
        "address": "0x1111111111111111111111111111111111111111",
        "chain_id": 84532
      }
    }
    ```

    When `contract.status` is `"active"`, the collection is ready. Poll on a short interval (one to two seconds) and give up after a reasonable timeout.
  </Step>

  <Step title="Create a unit">
    A unit is the unique digital record for a single physical item. Create one inside your collection.

    ```bash theme={null}
    curl -X POST https://api2.endstate.io/v1/units \
      -H "Authorization: Bearer end_sk_test_..." \
      -H "Content-Type: application/json" \
      -d '{
        "collection_id": "8e1a7f50-90ab-4cde-b012-3456789abcde"
      }'
    ```

    ```json theme={null}
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "external_id": null,
      "name": null,
      "attributes": null,
      "redirect_url": null,
      "created_at": "2026-06-15T10:01:00.000Z",
      "collection": {
        "id": "8e1a7f50-90ab-4cde-b012-3456789abcde",
        "name": "Summer Tee 2026",
        "external_id": null,
        "contract": {
          "address": "0x1111111111111111111111111111111111111111",
          "chain_id": 84532,
          "status": "active"
        },
        "token": {
          "status": "pending",
          "serial": null
        }
      },
      "chips": []
    }
    ```

    The unit starts with `collection.token.status: "pending"`. It moves to `"active"` (and receives a `collection.token.serial`) after a chip is paired in the next step.
  </Step>

  <Step title="Create a test chip">
    A test chip lets you simulate taps without physical hardware. Pass `is_test: true` and the unit you created.

    ```bash theme={null}
    curl -X POST https://api2.endstate.io/v1/chips \
      -H "Authorization: Bearer end_sk_test_..." \
      -H "Content-Type: application/json" \
      -d '{
        "unit_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "is_test": true
      }'
    ```

    ```json theme={null}
    {
      "chip_id": "ABCDEF0123",
      "is_test": true,
      "scan_count": 0,
      "created_at": "2026-06-15T10:02:00.000Z",
      "unit": {
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "external_id": null,
        "name": null,
        "attributes": null,
        "redirect_url": null,
        "created_at": "2026-06-15T10:01:00.000Z",
        "collection": {
          "id": "8e1a7f50-90ab-4cde-b012-3456789abcde",
          "name": "Summer Tee 2026",
          "external_id": null,
          "contract": {
            "address": "0x1111111111111111111111111111111111111111",
            "chain_id": 84532,
            "status": "active"
          },
          "token": {
            "status": "pending",
            "serial": null
          }
        }
      }
    }
    ```

    Note the `chip_id` — you use it in the next two steps. Pairing a chip also triggers issuance: the unit's `token.status` transitions from `"pending"` to `"active"` and `token.serial` is assigned.
  </Step>

  <Step title="Simulate a tap">
    Real chips produce a one-time `e` value when tapped. For test chips, the `/tap` endpoint generates one for you.

    ```bash theme={null}
    curl -X POST https://api2.endstate.io/v1/chips/ABCDEF0123/tap \
      -H "Authorization: Bearer end_sk_test_..."
    ```

    ```json theme={null}
    {
      "chip_id": "ABCDEF0123",
      "e": "C78566198547116F3A715DC1C62AF96F",
      "count": 1
    }
    ```

    Each call to `/tap` produces a fresh, single-use `e` value. Use it immediately in the next step — it cannot be reused.
  </Step>

  <Step title="Verify the tap">
    Submit the `e` value to verify the chip. This is the core API call: it validates authenticity, records the scan, and returns a session token.

    ```bash theme={null}
    curl -X POST https://api2.endstate.io/v1/chips/ABCDEF0123 \
      -H "Authorization: Bearer end_sk_test_..." \
      -H "Content-Type: application/json" \
      -d '{
        "e": "C78566198547116F3A715DC1C62AF96F"
      }'
    ```

    ```json theme={null}
    {
      "id": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
      "session_token": {
        "token": "end_sess_AbCd1234EfGh5678IjKl9012MnOp",
        "expires_at": "2026-06-15T10:12:00.000Z",
        "scope": {
          "chip_id": "ABCDEF0123",
          "unit_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
          "organization_id": "c0ffee00-1234-5678-90ab-cdef01234567"
        }
      },
      "chip": {
        "chip_id": "ABCDEF0123",
        "scan_count": 1
      },
      "unit": {
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "external_id": null,
        "name": null,
        "attributes": null,
        "collection": {
          "id": "8e1a7f50-90ab-4cde-b012-3456789abcde",
          "name": "Summer Tee 2026",
          "external_id": null,
          "contract": {
            "address": "0x1111111111111111111111111111111111111111",
            "chain_id": 84532,
            "status": "active"
          },
          "token": {
            "status": "active",
            "serial": 1
          }
        }
      },
      "redirect_url": null,
      "dry_run": false
    }
    ```

    Two fields to note:

    * **`session_token`** — an object containing a short-lived `token` value (`end_sess_...`) that proves this chip was just tapped. Valid for 600 seconds by default. Pass the `token` string to a client to authorize unit-scoped actions without exposing your API key.
    * **`unit`** — the digital record for the verified item, including its issuance status and serial number.

    If verification fails (e.g., the `e` value was already used), the API returns a structured error. Branch on `error.code` — see [Errors](/conventions/errors).
  </Step>

  <Step title="Introspect the session token (optional)">
    Your client can confirm the session token's scope without holding an API key. Send the `token` string from the `session_token` object as the bearer credential.

    ```bash theme={null}
    curl https://api2.endstate.io/v1/session-tokens/current \
      -H "Authorization: Bearer end_sess_AbCd1234EfGh5678IjKl9012MnOp"
    ```

    ```json theme={null}
    {
      "chip_id": "ABCDEF0123",
      "unit_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "organization_id": "c0ffee00-1234-5678-90ab-cdef01234567",
      "expires_at": "2026-06-15T10:12:00.000Z"
    }
    ```

    This endpoint accepts only `end_sess_*` tokens — not API keys. Use it from browser or mobile clients to confirm a verified session without exposing server credentials.
  </Step>
</Steps>

## Next steps

<CardGroup cols={2}>
  <Card title="Core concepts" icon="layers" href="/concepts/overview">
    Understand collections, units, chips, and how they fit together.
  </Card>

  <Card title="Verify a unit" icon="scan-line" href="/guides/verify-a-unit">
    The full production verification guide, including real chip handling.
  </Card>

  <Card title="Claim a unit" icon="arrow-right-left" href="/guides/claim-a-unit">
    Use the session token you just received to transfer the unit to a recipient.
  </Card>

  <Card title="Authentication" icon="key" href="/authentication">
    API keys, session tokens, and security best practices.
  </Card>
</CardGroup>
