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

# Quickstart

> Integrate in minutes — two files, a few lines each. Get a minimal SyncSnap flow running with Next.js and the React SDK.

## Prerequisites

* Node.js 18+
* A SyncSnap project and API key from the [dashboard](https://syncsnap.xyz/dashboard) (or your backend that creates jobs and returns download URLs)
* Next.js app using the App Router

## Step 1: Install packages

```bash theme={null}
npm install @syncsnap/react syncsnap
```

Peer dependencies for the React components (Tailwind and React):

```bash theme={null}
npm install react tailwindcss
```

## Step 2: Environment variable

Your server needs the SyncSnap API key. In `.env.local`:

```bash theme={null}
SYNCSNAP_TOKEN=your_api_key_here
```

Never expose this key to the browser; only the server SDK should use it.

## Step 3: API route

Create the SyncSnap API route so the frontend can create jobs and wait for completion (and optionally get download URLs). Create this file:

**`app/api/syncsnap/[...syncsnap]/route.ts`**

```ts theme={null}
import { SyncsnapServer } from "syncsnap";
import { createRouteHandler } from "syncsnap/next";

const client = new SyncsnapServer();

export const { GET, POST } = createRouteHandler({
	client,
	onCompleted: async (job, presigned) => {
		// Optional: run when job completes. Return value is sent to the client as onCompleted(job, result).
		return presigned
			? { downloadUrl: presigned.url, fileName: presigned.fileName }
			: undefined;
	},
});
```

This single catch-all route handles:

* `POST /api/syncsnap/job` — create job
* `GET /api/syncsnap/job/:id` — get job
* `GET /api/syncsnap/job/:id/wait` — server waits until job completes, then returns `{ job, result? }` (result is from your `onCompleted` callback or the presigned URL)
* `GET /api/syncsnap/job/:id/download` — get presigned download URL

## Step 4: Add the upload button

In any client component:

```tsx theme={null}
"use client";

import { SyncsnapUploadButton } from "@syncsnap/react";

export default function Page() {
	return (
		<SyncsnapUploadButton
			buttonText="Scan to upload"
			onCompleted={(job, result) => {
				// result is whatever your server onCompleted returned (e.g. { downloadUrl, fileName })
				if (
					result &&
					typeof result === "object" &&
					"downloadUrl" in result
				)
					console.log(
						"Download URL:",
						(result as { downloadUrl: string }).downloadUrl,
					);
			}}
		/>
	);
}
```

## Step 5: Styles (Tailwind)

The button and dialog use Tailwind and the SDK theme. In your main CSS (e.g. `app/globals.css`):

```css theme={null}
@import "tailwindcss";
@import "@syncsnap/react/theme";
```

If you use Tailwind v3 or a different setup, see [Styling](/guides/styling).

## Step 6: Run and test

1. Start the dev server: `npm run dev`
2. Open the page and click **Scan to upload**.
3. A dialog opens with a QR code. Scan it with your phone and upload a file.
4. When the job completes, `onCompleted` runs and you can use the presigned download URL.

## Optional: QR code base URL

If the default upload host is wrong (e.g. local or staging), set where the QR code should point:

```tsx theme={null}
<SyncsnapUploadButton
	buttonText="Scan to upload"
	qrBaseUrl="https://upload.staging.syncsnap.xyz"
/>
```

Next: [Next.js App Router](/getting-started/nextjs-app-router) for a fuller walkthrough, or [React SDK](/react/syncsnap-upload-button) and [Server SDK](/server/syncsnap-server) for all options.
