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

# Quickstart

> Authenticate, render a PDF, poll to completion, and download — in five minutes.

## Prerequisites

* A Craftkit project with a **published template** and its slug.
* A project API key (`ck_live_…`) for the environment you are calling.

<Info>
  Create a key in **Dashboard → your project → API keys**. Copy it immediately — it is shown
  once. Keys are environment-specific; see [Authentication](/guides/authentication).
</Info>

## 1. Verify connectivity

```bash theme={null}
curl https://api.craftkit.dev/health
# → { "status": "ok" }
```

## 2. Read the template manifest

Confirm the template exists and learn exactly which keys it expects.

```bash theme={null}
curl https://api.craftkit.dev/v1/templates/invoice \
  -H "Authorization: Bearer $CRAFTKIT_API_KEY"
```

```json theme={null}
{
  "slug": "invoice",
  "published": true,
  "currentVersionNumber": 3,
  "manifest": {
    "variables": [
      { "key": "customer.name", "dataType": "text", "required": true },
      { "key": "invoice.total", "dataType": "currency", "required": true }
    ],
    "loops": []
  },
  "jsonSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "...": "..." }
}
```

## 3. Enqueue a render

```bash theme={null}
curl -X POST https://api.craftkit.dev/v1/templates/invoice/render \
  -H "Authorization: Bearer $CRAFTKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "customer": { "name": "Ada Lovelace" },
      "invoice": { "total": 4200 }
    }
  }'
```

```json theme={null}
{
  "id": "…",
  "status": "queued",
  "pollUrl": "https://api.craftkit.dev/v1/renders/…",
  "downloadUrl": null,
  "errorMessage": null,
  "createdAt": "2026-06-05T10:00:00.000Z"
}
```

<Note>
  Rendering is **asynchronous**. The response is `202` with `status: "queued"` and
  `downloadUrl: null`. There is no synchronous mode — you poll (or use a webhook). See
  [Render lifecycle](/guides/render-lifecycle).
</Note>

## 4. Poll until complete

```ts theme={null}
async function waitForRender(renderId: string, timeoutMs = 30_000) {
  const deadline = Date.now() + timeoutMs;
  let delay = 250;
  const headers = { Authorization: `Bearer ${process.env.CRAFTKIT_API_KEY}` };
  while (Date.now() < deadline) {
    const r = await fetch(`https://api.craftkit.dev/v1/renders/${renderId}`, { headers });
    const render = await r.json();
    if (render.status === 'succeeded') return render.downloadUrl as string;
    if (render.status === 'failed') throw new Error(render.errorMessage ?? 'render failed');
    await new Promise((res) => setTimeout(res, delay));
    delay = Math.min(delay * 2, 5_000); // 250ms → 500ms → 1s → 2s → cap 5s
  }
  throw new Error('render timed out');
}
```

## 5. Use the PDF

When `status` is `succeeded`, `downloadUrl` points at the rendered PDF. For a durable,
guest-shareable link, mint a [share link](/guides/sharing) instead.

<Card title="Go deeper: server-to-server integration" icon="server" href="/guides/headless-integration">
  Idempotency, manifest binding, pipelines, images, and webhooks for a production backend.
</Card>
