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

# Nuxt

> Server route in Nuxt 3 to convert documents.

# Nuxt

## Server route

```ts theme={null}
// server/api/convert.post.ts
async function pollJob(jobId: string): Promise<string> {
  const config = useRuntimeConfig();
  while (true) {
    await new Promise((r) => setTimeout(r, 5000));
    const data = await $fetch<{ status: string; body?: string; error?: string }>(
      `${config.flashMdApiUrl}/jobs/${jobId}`,
      { headers: { "x-api-key": config.flashMdApiKey } }
    );
    if (data.status === "completed") return data.body!;
    if (data.status === "failed") throw createError({ statusCode: 502, message: data.error });
  }
}

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig();
  const form = await readMultipartFormData(event);
  const file = form?.find((f) => f.name === "file");

  if (!file) {
    throw createError({ statusCode: 400, message: "Missing file" });
  }

  const res = await fetch(
    `${config.flashMdApiUrl}/convert/raw?filename=${encodeURIComponent(file.filename || "doc")}&mode=fast`,
    {
      method: "POST",
      headers: {
        "x-api-key": config.flashMdApiKey,
        "content-type": file.type || "application/octet-stream",
      },
      body: file.data,
    }
  );

  if (res.status === 200) return res.text();

  if (res.status === 202) {
    const job = await res.json();
    return pollJob(job.job_id);
  }

  throw createError({ statusCode: res.status, message: await res.text() });
});
```

## Config

```ts theme={null}
// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    flashMdApiUrl: "https://api.markpdf.tech",
    flashMdApiKey: "",
  },
});
```

Environment variable: `NUXT_FLASH_MD_API_KEY=tu_key`.
