Quotation API
Quote and work package management endpoints.
Status
These endpoints are planned and not yet implemented.
Endpoints
List Quotes
Returns a paginated list of quotes.
http
GET /api/quotation/quotesQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
pageSize | integer | 10 | Items per page |
customerId | guid | - | Filter by customer |
status | string | - | Filter by status (draft, sent, accepted, rejected) |
Success Response 200 OK
json
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"number": "Q-2026-0001",
"customerId": "660e8400-e29b-41d4-a716-446655440000",
"customerName": "John Doe",
"title": "Bathroom Renovation",
"totalAmount": 125000.00,
"currency": "SEK",
"status": "draft",
"validUntil": "2026-02-12T00:00:00Z",
"createdAt": "2026-01-12T10:00:00Z"
}
],
"meta": {
"total": 1,
"page": 1,
"pageSize": 10
}
}Get Quote
Returns a single quote with all work packages.
http
GET /api/quotation/quotes/{id}Success Response 200 OK
json
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"number": "Q-2026-0001",
"customerId": "660e8400-e29b-41d4-a716-446655440000",
"customerName": "John Doe",
"title": "Bathroom Renovation",
"description": "Complete bathroom renovation including tiles, fixtures, and plumbing",
"workPackages": [
{
"id": "770e8400-e29b-41d4-a716-446655440000",
"name": "Demolition",
"description": "Remove existing fixtures and tiles",
"items": [
{
"id": "880e8400-e29b-41d4-a716-446655440000",
"articleNumber": "LABOR-001",
"description": "Demolition labor",
"quantity": 16,
"unit": "hours",
"unitPrice": 650.00,
"totalPrice": 10400.00
}
],
"subtotal": 10400.00
},
{
"id": "990e8400-e29b-41d4-a716-446655440000",
"name": "Tiling",
"description": "Install new floor and wall tiles",
"items": [
{
"id": "aa0e8400-e29b-41d4-a716-446655440000",
"articleNumber": "TILE-FLOOR-001",
"description": "Floor tiles 30x30",
"quantity": 15,
"unit": "sqm",
"unitPrice": 450.00,
"totalPrice": 6750.00
},
{
"id": "bb0e8400-e29b-41d4-a716-446655440000",
"articleNumber": "LABOR-002",
"description": "Tiling labor",
"quantity": 24,
"unit": "hours",
"unitPrice": 650.00,
"totalPrice": 15600.00
}
],
"subtotal": 22350.00
}
],
"subtotal": 32750.00,
"vatRate": 25,
"vatAmount": 8187.50,
"totalAmount": 40937.50,
"currency": "SEK",
"status": "draft",
"validUntil": "2026-02-12T00:00:00Z",
"createdAt": "2026-01-12T10:00:00Z",
"updatedAt": "2026-01-12T14:30:00Z"
},
"error": null,
"meta": {
"timestamp": "2026-01-12T10:00:00Z",
"requestId": "abc-123"
}
}Create Quote
Creates a new quote.
http
POST /api/quotation/quotesRequest Body
json
{
"customerId": "660e8400-e29b-41d4-a716-446655440000",
"title": "Bathroom Renovation",
"description": "Complete bathroom renovation",
"validUntil": "2026-02-12T00:00:00Z"
}Success Response 201 Created
json
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"number": "Q-2026-0001"
},
"error": null,
"meta": {
"timestamp": "2026-01-12T10:00:00Z",
"requestId": "def-456"
}
}Add Work Package
Adds a work package to a quote.
http
POST /api/quotation/quotes/{quoteId}/work-packagesRequest Body
json
{
"name": "Demolition",
"description": "Remove existing fixtures and tiles"
}Success Response 201 Created
json
{
"data": {
"id": "770e8400-e29b-41d4-a716-446655440000"
},
"error": null,
"meta": {
"timestamp": "2026-01-12T10:00:00Z",
"requestId": "ghi-789"
}
}Add Line Item
Adds a line item to a work package.
http
POST /api/quotation/quotes/{quoteId}/work-packages/{workPackageId}/itemsRequest Body
json
{
"articleNumber": "LABOR-001",
"description": "Demolition labor",
"quantity": 16,
"unit": "hours",
"unitPrice": 650.00
}Success Response 201 Created
json
{
"data": {
"id": "880e8400-e29b-41d4-a716-446655440000",
"totalPrice": 10400.00
},
"error": null,
"meta": {
"timestamp": "2026-01-12T10:00:00Z",
"requestId": "jkl-012"
}
}Send Quote
Sends a quote to the customer.
http
POST /api/quotation/quotes/{id}/sendRequest Body
json
{
"recipientEmail": "customer@example.com",
"message": "Please find attached our quote for your bathroom renovation."
}Success Response 200 OK
json
{
"data": {
"status": "sent",
"sentAt": "2026-01-12T15:00:00Z"
},
"error": null,
"meta": {
"timestamp": "2026-01-12T15:00:00Z",
"requestId": "mno-345"
}
}Quote Status Flow
┌─────────┐ ┌────────┐ ┌──────────┐
│ Draft │ ──► │ Sent │ ──► │ Accepted │ ──► Convert to Contract
└─────────┘ └────────┘ └──────────┘
│
▼
┌──────────┐
│ Rejected │
└──────────┘Frontend Integration
typescript
// features/quotation/hooks/useQuotes.ts
export function useQuotes(params?: QuoteQueryParams) {
return useQuery({
queryKey: ['quotes', params],
queryFn: () => quotationApi.getQuotes(params),
});
}
export function useQuote(id: string) {
return useQuery({
queryKey: ['quotes', id],
queryFn: () => quotationApi.getQuote(id),
});
}
export function useCreateQuote() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateQuoteRequest) => quotationApi.createQuote(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['quotes'] });
},
});
}
export function useSendQuote() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: SendQuoteRequest }) =>
quotationApi.sendQuote(id, data),
onSuccess: (_, { id }) => {
queryClient.invalidateQueries({ queryKey: ['quotes', id] });
},
});
}