Quotes
Create and manage service quotes for customers
Overview
Quotes allow you to propose work to customers before performing services. They include detailed line items, photos, and can be converted to invoices once accepted. Quotes can be sent via email and tracked through their lifecycle.
List Quotes
Retrieve a paginated list of quotes with filtering.
query InfiniteQuotes($first: Int!, $after: String, $filter: QuoteFilter) {
infiniteQuotes(first: $first, after: $after, filter: $filter) {
edges {
node {
id
number
title
status
total
validUntil
customer {
id
firstName
lastName
}
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
}
}
# Variables
{
"first": 20,
"filter": {
"status": "SENT",
"customerId": "cust_456"
}
}Response:
{
"data": {
"infiniteQuotes": {
"edges": [
{
"node": {
"id": "quote_001",
"number": "QUO-2024-0001",
"title": "Pool Renovation Project",
"status": "SENT",
"total": 5500.00,
"validUntil": "2024-02-15T00:00:00Z",
"customer": {
"id": "cust_456",
"firstName": "John",
"lastName": "Smith"
}
},
"cursor": "eyJpZCI6InF1b3RlXzAwMSJ9"
}
],
"pageInfo": {
"hasNextPage": false,
"endCursor": "eyJpZCI6InF1b3RlXzAwMSJ9"
}
}
}
}Get Single Quote
Retrieve a single quote with all details.
query Quote($selector: QuoteSelector!) {
quote(selector: $selector) {
id
number
title
status
subtotal
tax
total
validUntil
acceptedAt
customer {
id
firstName
lastName
email
}
lineItems {
id
description
quantity
unitPrice
amount
}
notes
terms
photos {
id
url
caption
}
pdfUrl
createdAt
updatedAt
}
}
# Variables
{
"selector": {
"id": "quote_001"
}
}Response:
{
"data": {
"quote": {
"id": "quote_001",
"number": "QUO-2024-0001",
"title": "Pool Renovation Project",
"status": "SENT",
"subtotal": 5000.00,
"tax": 500.00,
"total": 5500.00,
"validUntil": "2024-02-15T00:00:00Z",
"acceptedAt": null,
"customer": {
"id": "cust_456",
"firstName": "John",
"lastName": "Smith",
"email": "john@example.com"
},
"lineItems": [
{
"id": "qli_001",
"description": "Pool resurfacing",
"quantity": 1,
"unitPrice": 3500.00,
"amount": 3500.00
},
{
"id": "qli_002",
"description": "New pool pump installation",
"quantity": 1,
"unitPrice": 1500.00,
"amount": 1500.00
}
],
"notes": "Work to be completed within 2 weeks of acceptance",
"terms": "50% deposit required. Balance due upon completion.",
"photos": [
{
"id": "photo_001",
"url": "https://storage.example.com/quotes/photo_001.jpg",
"caption": "Current pool condition"
}
],
"pdfUrl": "https://storage.example.com/quotes/quote_001.pdf",
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-01-16T09:00:00Z"
}
}
}Create Quote
Create a new quote for a customer.
mutation CreateQuote($input: CreateQuoteInput!) {
createQuote(input: $input) {
id
number
title
status
total
customer {
id
firstName
lastName
}
createdAt
}
}
# Variables
{
"input": {
"customerId": "cust_456",
"title": "Equipment Upgrade",
"validUntil": "2024-03-01T00:00:00Z",
"lineItems": [
{
"description": "Variable speed pump",
"quantity": 1,
"unitPrice": 800.00
},
{
"description": "Installation labor",
"quantity": 4,
"unitPrice": 75.00
}
],
"taxId": "tax_001",
"notes": "Energy-efficient upgrade recommended"
}
}Response:
{
"data": {
"createQuote": {
"id": "quote_002",
"number": "QUO-2024-0002",
"title": "Equipment Upgrade",
"status": "DRAFT",
"total": 1210.00,
"customer": {
"id": "cust_456",
"firstName": "John",
"lastName": "Smith"
},
"createdAt": "2024-01-20T14:00:00Z"
}
}
}Update Quote Status
Update quote status (e.g., mark as accepted).
mutation UpdateQuote($id: ID!, $input: UpdateQuoteInput!) {
updateQuote(id: $id, input: $input) {
id
status
acceptedAt
updatedAt
}
}
# Variables
{
"id": "quote_001",
"input": {
"status": "ACCEPTED"
}
}Response:
{
"data": {
"updateQuote": {
"id": "quote_001",
"status": "ACCEPTED",
"acceptedAt": "2024-01-25T11:00:00Z",
"updatedAt": "2024-01-25T11:00:00Z"
}
}
}REST Endpoints
Upload photos and PDFs, export quotes.
POST
/quotes/:id/photosUpload a photo for a quote
curl -X POST "https://api.poolservicemanager.com/quotes/quote_001/photos" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-F "file=@photo.jpg" \
-F "caption=Current condition"POST
/quotes/:id/pdfUpload a custom PDF for the quote
curl -X POST "https://api.poolservicemanager.com/quotes/quote_001/pdf" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-F "file=@quote.pdf"GET
/quotes/export/csvExport quotes to CSV format
curl -X GET "https://api.poolservicemanager.com/quotes/export/csv?startDate=2024-01-01" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-o quotes.csvField Reference
| Field | Type | Description |
|---|---|---|
id | ID! | Unique identifier |
number | String! | Quote number |
title | String! | Quote title |
customer | Customer! | Customer receiving the quote |
status | QuoteStatus! | Status (DRAFT, SENT, ACCEPTED, DECLINED, EXPIRED) |
subtotal | Float! | Subtotal before tax |
tax | Float! | Tax amount |
total | Float! | Total amount |
validUntil | DateTime(nullable) | Quote expiration date |
acceptedAt | DateTime(nullable) | When quote was accepted |
lineItems | [QuoteLineItem!]! | Quote line items |
notes | String(nullable) | Quote notes |
terms | String(nullable) | Terms and conditions |
photos | [QuotePhoto!]! | Attached photos |
pdfUrl | String(nullable) | Generated PDF URL |
createdAt | DateTime! | Creation timestamp |
updatedAt | DateTime! | Last update timestamp |