---
title: "List quotes"
method: GET
path: "/quotes"
tags: ["Quotes"]
---

# List quotes

`GET /quotes`

## Request

- Base URL: `https://joinways.app/api/v1`
- URL: `https://joinways.app/api/v1/quotes`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://joinways.app/oauth/authorize`, token URL `https://joinways.app/api/oauth/token`, scopes: `mcp.read`)

Quotes of the workspace, newest first. Only live quotes by default: a version replaced by a later platform version or by an amendment is left out unless `include_superseded` is true. The sample quotes created at onboarding are never listed. **Role permission:** `reports.view` or `quotes.manage` (quotes carry revenue).

## Query parameters

- `page` integer
- `per_page` integer
- `event_id` string, uuid
- `status` QuoteStatus[]
- `include_superseded` boolean

## Response `200`

Page of quotes (summary fields).

- object: Envelope wrapping a page of results.
  - `data` QuoteSummary[], required: The page of results (item type depends on the endpoint).
    - `id` string, uuid
    - `event_id` string, uuid
    - `quote_number` string, nullable
    - `title` string
    - `status` 'draft' | 'pending' | 'accepted' | 'signed' | 'rejected' | 'invoiced' | 'paid' | 'cancelled': `draft` = not sent yet; `pending` = sent, awaiting the client; `accepted` / `signed` = client agreement (signed = signature recorded); `rejected` = refused; `invoiced` = at least one invoice issued (a deposit included); `paid` = fully settled; `cancelled` = withdrawn. accepted, signed, invoiced and paid are live contracts counted in the event's confirmed amount (unless replaced, see `superseded_by_quote_id`).
    - `currency` string
    - `total_excl_tax` number
    - `total_tax` number
    - `total_incl_tax` number
    - `is_signed` boolean, nullable
    - `signed_at` string, date-time, nullable
    - `signature_mode` 'manual' | 'public' | 'null', nullable
    - `signer_name` string, nullable
    - `signer_email` string, nullable
    - `is_invoiced` boolean, nullable
    - `invoice_number` string, nullable
    - `invoice_date` string, date-time, nullable
    - `due_date` string, date-time, nullable
    - `payment_date` string, date-time, nullable
    - `is_reverse_charge` boolean, nullable
    - `sent_at` string, date-time, nullable: When the quote was sent (for a platform quote, when the platform transmitted it).
    - `viewed_at` string, date-time, nullable
    - `last_viewed_at` string, date-time, nullable
    - `view_count` integer
    - `expires_at` string, date-time, nullable: Validity end of the offer.
    - `created_at` string, date-time
    - `author_id` string, uuid
    - `billing_profile_id` string, uuid, nullable
    - `source` 'joinways' | 'platform': `joinways` = written in Joinways. `platform` = a booking platform's own document recorded in Joinways, mostly read from the platform's emails (quote transmitted, with its PDF), or imported once signed. A platform quote is read-only: its amounts, discounts, currency and lines are never edited, it is never deleted nor duplicated, and its status only takes `accepted` or `rejected` through the API; its PDF is the platform's.
    - `source_platform` string, nullable: Booking platform the document comes from (platform quote), or the one a Joinways quote was deposited to (e.g. Kactus).
    - `external_reference` string, nullable: The platform's own quote number (a platform that renumbers each revision gives each version its own). Unique per event.
    - `platform_pushed_at` string, date-time, nullable: When a Joinways quote was deposited on the platform (first deposit only).
    - `superseded_by_quote_id` string, uuid, nullable: Set when this quote was replaced: by a later version the booking platform sent, or by a signed amendment. A replaced quote keeps its status but never counts in the event's confirmed amount; only quotes where this is null are live. Set by Joinways only.
    - `superseded_at` string, date-time, nullable: When the quote was replaced (null while it is live).
  - `pagination` object, required
    - `page` integer, required: Current 1-based page.
    - `per_page` integer, required: Items per page.
    - `total` integer, nullable, required: Total matching items across all pages (`null` only on a page past the last one, when unknown).
    - `total_pages` integer, nullable, required

## Other responses

- `400`: Validation failed (`invalid_request`). For a body that fails the schema, `details` holds `formErrors` and `fieldErrors`.
- `401`: Missing, invalid, expired or revoked bearer token (`unauthorized`).
- `403`: `forbidden`: the token lacks the scope, its owner's role lacks the permission named by the operation, or the workspace has neither the Pro plan nor a trial (`details.reason` `plan_not_eligible`).
- `429`: Too many requests (`rate_limited`). `details.reason`: `per-ip`, `per-account-minute`, `per-account-day`, or `email_rate_limited` (email budget). Always carries `Retry-After`: wait that many seconds.

---

[API](https://skmtc.dev/joinways/apis/joinways-public-api.md) · [All operations](https://skmtc.dev/joinways/apis/joinways-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/joinways/apis/joinways-public-api/revisions/39e84309953e?raw)
