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

# Get Quote PDF

> Download a quote PDF (signed when available, otherwise unsigned)

## Authorization

<ParamField header="Authorization" type="string" required>
  Bearer token for authentication. Format: `Bearer qwoty_your_token`
</ParamField>

## Path Parameters

<ParamField path="id" type="string" required>
  UUID of the project
</ParamField>

## Query Parameters

<ParamField query="force" type="boolean" default="false">
  Force PDF regeneration before download. Use `true` to bypass freshness checks.
</ParamField>

## Behavior

* If the project is `accepted` and a signed PDF exists, the signed file is returned.
* Otherwise, an unsigned PDF is returned (generated on demand if needed).
* The response is a file download with `application/pdf` content type.

**Source:** `src/app/api/projects/[id]/pdf/route.ts` (kept outside `app/api/(bff)/` as a documented, tool-friendly HTTP contract).

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url "https://qwoty.app/api/projects/550e8400-e29b-41d4-a716-446655440000/pdf?force=false" \
    --header "Authorization: Bearer qwoty_your_token" \
    --output quote.pdf
  ```

  ```javascript JavaScript theme={null}
  const projectId = '550e8400-e29b-41d4-a716-446655440000'

  const response = await fetch(
    `https://qwoty.app/api/projects/${projectId}/pdf?force=false`,
    {
      headers: {
        Authorization: 'Bearer qwoty_your_token',
      },
    },
  )

  if (!response.ok) {
    const error = await response.json()
    throw new Error(error.error)
  }

  const blob = await response.blob()
  ```

  ```python Python theme={null}
  import requests

  project_id = '550e8400-e29b-41d4-a716-446655440000'

  response = requests.get(
      f'https://qwoty.app/api/projects/{project_id}/pdf?force=false',
      headers={
          'Authorization': 'Bearer qwoty_your_token'
      }
  )

  if response.status_code != 200:
      raise Exception(response.json().get('error', 'Request failed'))

  with open('quote.pdf', 'wb') as f:
      f.write(response.content)
  ```
</CodeGroup>

## Response

<ResponseField name="Content-Type" type="string">
  Always `application/pdf` on success.
</ResponseField>

<ResponseField name="Content-Disposition" type="string">
  Attachment filename. Example: `quote-Q-2024-001.pdf` or
  `quote-Q-2024-001-signed.pdf`.
</ResponseField>

<ResponseExample>
  ```text 200 application/pdf theme={null}
  (binary PDF file)
  ```

  ```json 404 theme={null}
  {
    "error": "Project not found"
  }
  ```

  ```json 500 theme={null}
  {
    "error": "Failed to prepare PDF"
  }
  ```
</ResponseExample>
