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

# Quickstart

> Upload a document, get a structured Markdown filesystem, and give your agent file access in minutes.

Upload a document, wait for structuring, then point your agent at the files.

## Prerequisites

You need a Shelv API key. Pick whichever path suits your workflow:

<Tabs>
  <Tab title="API">
    No browser required — ideal for AI agents and coding agents (Claude Code, Codex, OpenClaw).

    ```bash theme={"theme":{"light":"github-light","dark":"poimandres"}}
    # Register
    curl -X POST https://api.shelv.dev/v1/auth/register \
      -H "Content-Type: application/json" \
      -d '{"name": "Alice", "email": "alice@example.com", "password": "your-secure-password"}'

    # Check your email for the 6-digit code, then verify
    curl -X POST https://api.shelv.dev/v1/auth/verify-email \
      -H "Content-Type: application/json" \
      -d '{"email": "alice@example.com", "code": "123456"}'
    ```

    The verify response contains your API key. Save it:

    ```bash theme={"theme":{"light":"github-light","dark":"poimandres"}}
    export SHELV_API_KEY="sk_live_..."
    ```

    See the full [Authentication guide](/guides/authentication#get-an-api-key) for details.
  </Tab>

  <Tab title="Dashboard">
    1. Sign in at [shelv.dev](https://shelv.dev)
    2. Open **Settings > API Keys**
    3. Create a key and copy it
  </Tab>
</Tabs>

Set environment variables:

<CodeGroup>
  ```bash curl theme={"theme":{"light":"github-light","dark":"poimandres"}}
  export SHELV_API_URL="https://api.shelv.dev"
  export SHELV_API_KEY="sk_your_api_key"
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"poimandres"}}
  const SHELV_API_URL = process.env.SHELV_API_URL ?? "https://api.shelv.dev";
  const SHELV_API_KEY = process.env.SHELV_API_KEY!;
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"poimandres"}}
  import os

  shelv_api_url = os.environ.get("SHELV_API_URL", "https://api.shelv.dev")
  shelv_api_key = os.environ["SHELV_API_KEY"]
  ```
</CodeGroup>

## 1. Upload a document

<CodeGroup>
  ```bash curl theme={"theme":{"light":"github-light","dark":"poimandres"}}
  curl -X POST "$SHELV_API_URL/v1/shelves" \
    -H "Authorization: Bearer $SHELV_API_KEY" \
    -F "file=@contract.pdf" \
    -F "name=My Contract"
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"poimandres"}}
  import { readFile } from "node:fs/promises";

  const form = new FormData();
  form.append("file", new Blob([await readFile("contract.pdf")]), "contract.pdf");
  form.append("name", "My Contract");

  const res = await fetch(`${SHELV_API_URL}/v1/shelves`, {
    method: "POST",
    headers: { Authorization: `Bearer ${SHELV_API_KEY}` },
    body: form,
  });
  const shelf = await res.json();
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"poimandres"}}
  import requests

  with open("contract.pdf", "rb") as f:
      res = requests.post(
          f"{shelv_api_url}/v1/shelves",
          headers={"Authorization": f"Bearer {shelv_api_key}"},
          files={"file": ("contract.pdf", f)},
          data={"name": "My Contract"},
      )
  shelf = res.json()
  ```
</CodeGroup>

Optional fields:

* `template=book|legal-contract|charter-party|academic-paper`
* `review=true` to pause in `review` before finalization

Save the returned shelf public ID:

<CodeGroup>
  ```bash curl theme={"theme":{"light":"github-light","dark":"poimandres"}}
  export SHELF_PUBLIC_ID="shf_0123456789abcdef01234567"
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"poimandres"}}
  const SHELF_PUBLIC_ID = shelf.publicId; // "shf_0123456789abcdef01234567"
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"poimandres"}}
  shelf_public_id = shelf["publicId"]  # "shf_0123456789abcdef01234567"
  ```
</CodeGroup>

## 2. Wait for completion

<Tabs>
  <Tab title="Webhooks (recommended)">
    Register a webhook endpoint **once** — it will receive events for every shelf you submit.

    ```bash theme={"theme":{"light":"github-light","dark":"poimandres"}}
    # One-time setup
    curl -X POST "$SHELV_API_URL/v1/webhooks" \
      -H "Authorization: Bearer $SHELV_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "url": "https://your-app.com/webhooks/shelv",
        "events": ["shelf.ready", "shelf.failed"]
      }'
    ```

    When a shelf reaches `ready` or `failed`, your endpoint receives a signed POST with the `shelfPublicId` in the payload. See the [Webhooks guide](/guides/webhooks) for signature verification and handler details.
  </Tab>

  <Tab title="Polling">
    Poll the shelf status endpoint until it reaches a terminal state.

    <CodeGroup>
      ```bash curl theme={"theme":{"light":"github-light","dark":"poimandres"}}
      curl "$SHELV_API_URL/v1/shelves/$SHELF_PUBLIC_ID" \
        -H "Authorization: Bearer $SHELV_API_KEY"
      ```

      ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"poimandres"}}
      const res = await fetch(`${SHELV_API_URL}/v1/shelves/${SHELF_PUBLIC_ID}`, {
        headers: { Authorization: `Bearer ${SHELV_API_KEY}` },
      });
      const shelf = await res.json();
      ```

      ```python Python theme={"theme":{"light":"github-light","dark":"poimandres"}}
      import requests

      res = requests.get(
          f"{shelv_api_url}/v1/shelves/{shelf_public_id}",
          headers={"Authorization": f"Bearer {shelv_api_key}"},
      )
      shelf = res.json()
      ```
    </CodeGroup>
  </Tab>
</Tabs>

Common flow:

`uploading -> parsing -> structuring -> verifying -> ready`

If `review=true`, status stops at `review` until you call `POST /v1/shelves/{shelfPublicId}/approve`.

## 3. Browse the filesystem

When status is `ready` or `review`:

<CodeGroup>
  ```bash curl theme={"theme":{"light":"github-light","dark":"poimandres"}}
  curl "$SHELV_API_URL/v1/shelves/$SHELF_PUBLIC_ID/tree" \
    -H "Authorization: Bearer $SHELV_API_KEY"
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"poimandres"}}
  const res = await fetch(`${SHELV_API_URL}/v1/shelves/${SHELF_PUBLIC_ID}/tree`, {
    headers: { Authorization: `Bearer ${SHELV_API_KEY}` },
  });
  const tree = await res.json();
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"poimandres"}}
  import requests

  res = requests.get(
      f"{shelv_api_url}/v1/shelves/{shelf_public_id}/tree",
      headers={"Authorization": f"Bearer {shelv_api_key}"},
  )
  tree = res.json()
  ```
</CodeGroup>

## 4. Read a file

<CodeGroup>
  ```bash curl theme={"theme":{"light":"github-light","dark":"poimandres"}}
  curl "$SHELV_API_URL/v1/shelves/$SHELF_PUBLIC_ID/files/clauses/force-majeure.md" \
    -H "Authorization: Bearer $SHELV_API_KEY"
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"poimandres"}}
  const res = await fetch(
    `${SHELV_API_URL}/v1/shelves/${SHELF_PUBLIC_ID}/files/clauses/force-majeure.md`,
    { headers: { Authorization: `Bearer ${SHELV_API_KEY}` } },
  );
  const markdown = await res.text();
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"poimandres"}}
  import requests

  res = requests.get(
      f"{shelv_api_url}/v1/shelves/{shelf_public_id}/files/clauses/force-majeure.md",
      headers={"Authorization": f"Bearer {shelv_api_key}"},
  )
  markdown = res.text
  ```
</CodeGroup>

## 5. Choose how your agent accesses files

* `@shelv/mcp` — [MCP server](/guides/mcp-server) for MCP clients ([source](https://github.com/shelv-dev/shelv-mcp))
* [OpenClaw skill](/guides/openclaw) — upload, poll, and hydrate from OpenClaw
* `GET /v1/shelves/{shelfPublicId}/tree` for full tree access
* `GET /v1/shelves/{shelfPublicId}/files/*` for individual file reads
* `GET /v1/shelves/{shelfPublicId}/archive-url` for snapshots
* `GET /v1/helpers/download.sh` for archive pull
* `@shelv/adapters` for sandbox hydration and snapshots ([source](https://github.com/shelv-dev/shelv-adapters))

<Tip>Already set up a webhook? You can skip polling entirely — see step 2.</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="Shelves" icon="folder" href="/concepts/shelves">
    Understand lifecycle and status-gated endpoints.
  </Card>

  <Card title="Authentication" icon="key" href="/guides/authentication">
    Lock down API key and route auth behavior.
  </Card>

  <Card title="Webhooks" icon="bell" href="/guides/webhooks">
    Receive signed lifecycle events.
  </Card>

  <Card title="Archive Download" icon="file-archive" href="/guides/archive-download">
    Pull portable snapshots for CI and offline jobs.
  </Card>

  <Card title="MCP Server" icon="plug" href="/guides/mcp-server">
    Connect Claude Code, Cursor, or any MCP client.
  </Card>
</CardGroup>
