Bids
Overview
Bids are the top-level entity representing a complete construction estimate. Each bid contains scopes, which in turn contain estimation items across six modules.
Base Operations
List Bids
- Request
- Response
GET /api/bids
Cookie: sAccessToken=...; sRefreshToken=...
[
{
"id": "uuid",
"bidNumber": "BID-2025-001",
"name": "Shopping Center Foundation",
"clientId": "uuid",
"status": "SUBMITTED",
"equipmentBiddingMode": "TRADITIONAL",
"concreteCost": 125000.00,
"laborCost": 85000.00,
"equipmentCost": 22000.00,
"materialCost": 15000.00,
"subcontractorCost": 12000.00,
"miscCost": 5000.00,
"subtotalCost": 264000.00,
"overheadAmount": 26400.00,
"profitAmount": 43560.00,
"totalCost": 333960.00,
"createdBy": "user@example.com",
"createdAt": "2025-01-15T10:00:00.000Z",
"lastUpdated": "2025-01-20T14:30:00.000Z"
},
...
]
Roles: ADMIN, ESTIMATOR, PM
Get Pipeline Bids
- Request
- Response
GET /api/bids/pipeline
Cookie: sAccessToken=...; sRefreshToken=...
{
"draft": [
{
"id": "uuid",
"bidNumber": "BID-2025-001",
"name": "Shopping Center Foundation",
"clientName": "ABC Construction",
"status": "DRAFT",
"totalCost": 333960.00,
"lastUpdated": "2025-01-20T14:30:00.000Z"
}
],
"submitted": [...],
"negotiation": [...],
"awarded": [...],
"lost": [...]
}
Roles: ADMIN, ESTIMATOR, PM
Returns bids grouped by status for pipeline/kanban views. Useful for dashboard displays showing bid progression through lifecycle stages.
Get Bid
- Request
- Response
GET /api/bids/:id
Cookie: sAccessToken=...; sRefreshToken=...
{
"id": "uuid",
"bidNumber": "BID-2025-001",
"name": "Shopping Center Foundation",
"clientId": "uuid",
"location": "Austin, TX",
"status": "SUBMITTED",
"equipmentBiddingMode": "TRADITIONAL",
"overheadPercentage": 10.0,
"profitPercentage": 15.0,
"taxExempt": false,
"perDiemEnabled": true,
"shareCode": null,
"shareCodeAt": null,
"sourceBidId": null,
"sourceUserId": null,
"concreteCost": 125000.00,
"laborCost": 85000.00,
"equipmentCost": 22000.00,
"materialCost": 15000.00,
"subcontractorCost": 12000.00,
"miscCost": 5000.00,
"subtotalCost": 264000.00,
"overheadAmount": 26400.00,
"profitAmount": 43560.00,
"totalCost": 333960.00,
"createdBy": "user@example.com",
"createdAt": "2025-01-15T10:00:00.000Z",
"lastUpdated": "2025-01-20T14:30:00.000Z",
"client": {
"id": "uuid",
"name": "ABC Construction"
},
"scopes": [
{
"id": "uuid",
"name": "Foundation",
"totalCost": 180000.00
},
...
]
}
Roles: ADMIN, ESTIMATOR, PM
Create Bid
- Request
- Response
POST /api/bids
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"bidNumber": "BID-2025-002",
"name": "Office Building Foundation",
"clientId": "uuid",
"location": "Houston, TX",
"overheadPercentage": 12.0,
"profitPercentage": 18.0,
"taxExempt": false,
"perDiemEnabled": true,
"equipmentBiddingMode": "GANTT"
}
{
"id": "uuid",
"bidNumber": "BID-2025-002",
"name": "Office Building Foundation",
"status": "DRAFT",
"message": "Bid created successfully"
}
Roles: ADMIN, ESTIMATOR
Required Fields:
bidNumber(string, unique) - User-defined identifiername(string) - Job/project nameclientId(string, UUID) - Client reference
Optional Fields:
location(string) - Job locationoverheadPercentage(number, default: global variable)profitPercentage(number, default: global variable)taxExempt(boolean, default: false)perDiemEnabled(boolean, default: false)status(enum: DRAFT, SUBMITTED, NEGOTIATION, AWARDED, LOST, COMPLETED)equipmentBiddingMode(string: "TRADITIONAL" or "GANTT", default: "TRADITIONAL")
Update Bid
- Request
- Response
PUT /api/bids/:id
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"name": "Updated Job Name",
"status": "SUBMITTED",
"overheadPercentage": 15.0
}
{
"id": "uuid",
"message": "Bid updated successfully"
}
Roles: ADMIN, ESTIMATOR
Delete Bid
- Request
- Response
DELETE /api/bids/:id
Cookie: sAccessToken=...; sRefreshToken=...
{
"message": "Bid deleted successfully"
}
Roles: ADMIN
Only bids with status DRAFT can be deleted. Delete will cascade to all scopes and items.
Duplicate Bid
- Request
- Response
POST /api/bids/:id/duplicate
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"bidNumber": "BID-2025-003",
"name": "Copy of Shopping Center Foundation"
}
{
"id": "uuid",
"bidNumber": "BID-2025-003",
"message": "Bid duplicated successfully"
}
Roles: ADMIN, ESTIMATOR
Features:
- Deep copy of all scopes and items
- Resets status to DRAFT
- Creates new unique IDs
- Preserves cost structure
- Preserves all concrete item fields including second-mat rebar configuration (BM-86)
- Gantt Mode: Copies equipment and labor distributions with remapped scope IDs (Feb 2026)
- Timeline Costs: Preserves all timeline-based cost allocations for Gantt bidding mode
Bid Sharing
Generate Share Code
- Request
- Response
POST /api/bids/:id/share
Cookie: sAccessToken=...; sRefreshToken=...
{
"shareCode": "BID-X7K9M2P4",
"shareCodeAt": "2025-12-17T10:00:00.000Z"
}
Roles: ADMIN, ESTIMATOR (owner only)
Share codes are 8-character alphanumeric codes that allow other users to import your bid.
Revoke Share Code
- Request
- Response
DELETE /api/bids/:id/share
Cookie: sAccessToken=...; sRefreshToken=...
{
"message": "Share code revoked"
}
Roles: ADMIN, ESTIMATOR (owner only)
Preview Shared Bid
- Request
- Response
GET /api/bids/share/:code
Cookie: sAccessToken=...; sRefreshToken=...
{
"jobName": "Shopping Center Foundation",
"location": "Texas",
"scopeCount": 4,
"createdBy": "user@example.com",
"createdAt": "2025-12-01T10:00:00.000Z",
"equipmentBiddingMode": "TRADITIONAL"
}
Roles: ADMIN, ESTIMATOR, PM
Preview returns non-sensitive metadata only (no pricing, no scope details).
Import Bid
- Request
- Response
POST /api/bids/import/:code
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"clientId": "uuid",
"newName": "My Copy of Shopping Center"
}
{
"id": "uuid",
"message": "Bid imported successfully",
"sourceBidId": "uuid",
"sourceUserId": "uuid"
}
Roles: ADMIN, ESTIMATOR
Features:
- Creates full deep copy
- Tracks source with
sourceBidIdandsourceUserId - Status starts as DRAFT
- New bid requires unique
bidNumber - Gantt Mode: Copies equipment and labor distributions with remapped scope IDs (Feb 2026)
- Timeline Costs: Preserves all timeline-based cost allocations for Gantt bidding mode
Exports
PDF Export
- Request
- Response
GET /api/bids/:id/pdf
Cookie: sAccessToken=...; sRefreshToken=...
Binary PDF file download
Roles: ADMIN, ESTIMATOR, PM
CSV Export
- Request
- Response
GET /api/bids/:id/csv
Cookie: sAccessToken=...; sRefreshToken=...
Binary CSV file download
Roles: ADMIN, ESTIMATOR, PM
Excel Export
- Request
- Response
GET /api/bids/:id/excel
Cookie: sAccessToken=...; sRefreshToken=...
Binary .xlsx file download
Roles: ADMIN, ESTIMATOR, PM
PM Export
- Request
- Response (Google Sheets)
- Response (Excel)
POST /api/bids/:id/export/pm
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: application/json
{
"format": "google_sheets"
}
{
"success": true,
"format": "google_sheets",
"url": "https://docs.google.com/spreadsheets/d/...",
"spreadsheetId": "1abc..."
}
Binary .xlsx file download
Roles: ADMIN, ESTIMATOR, PM
Formats:
google_sheets- Creates Google Sheet with tracking templateexcel- Downloads Excel file
Template Sections:
- GENERAL CONDITIONS → Miscellaneous items
- LABOR → Labor items
- CONCRETE MATERIAL → Material items (concrete)
- PUMPING → Subcontractor items (pumps)
- REINFORCING MATERIALS → Material items (rebar)
- MATERIALS → Other material items
- EQUIPMENT → Equipment items
- FUEL & HAULING → Aggregated fuel/delivery costs
- SUBCONTRACTORS → Non-pump subcontractor items
PDF Preview
- Request
- Response
POST /api/bids/:id/pdf/preview
Cookie: sAccessToken=...; sRefreshToken=...
{
"preview": "data:application/pdf;base64,JVBERi0xLjQK..."
}
Roles: ADMIN, ESTIMATOR, PM
Returns base64-encoded PDF for in-browser preview.
Bid Attachments
List Attachments
- Request
- Response
GET /api/bids/:bidId/attachments
Cookie: sAccessToken=...; sRefreshToken=...
[
{
"id": "uuid",
"bidId": "uuid",
"filename": "uuid-screenshot.png",
"originalName": "screenshot.png",
"mimeType": "image/png",
"size": 245678,
"url": "https://storage.googleapis.com/...",
"uploadedBy": "user-uuid",
"createdAt": "2025-12-11T10:00:00.000Z"
},
...
]
Roles: ADMIN, ESTIMATOR, PM
URLs are signed with 24-hour expiration. They are regenerated on each request.
Upload Attachment
- Request
- Response
POST /api/bids/:bidId/attachments
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: multipart/form-data
{
"file": [binary]
}
{
"id": "uuid",
"filename": "uuid-screenshot.png",
"url": "https://storage.googleapis.com/..."
}
Roles: ADMIN, ESTIMATOR
Requirements:
- Max file size: 10MB
- Allowed types: JPEG, PNG, GIF, WebP, PDF
- Storage: Google Cloud Storage (
gs://forge-475221-attachments)
Upload Multiple Attachments
- Request
- Response (201 - All Success)
- Response (207 - Partial Success)
POST /api/bids/:bidId/attachments/multiple
Cookie: sAccessToken=...; sRefreshToken=...
Content-Type: multipart/form-data
{
"files": [binary, binary, ...]
}
{
"attachments": [
{ "id": "uuid", "filename": "..." },
{ "id": "uuid", "filename": "..." }
]
}
{
"attachments": [{ "id": "uuid", "filename": "file1.pdf" }],
"failed": [{ "filename": "file2.pdf", "error": "File too large" }]
}
Roles: ADMIN, ESTIMATOR
Limits:
- Max 10 files per request
- Max 10MB per file
Delete Attachment
- Request
- Response
DELETE /api/bids/:bidId/attachments/:id
Cookie: sAccessToken=...; sRefreshToken=...
{
"message": "Attachment deleted successfully"
}
Roles: ADMIN, ESTIMATOR
Data Model
interface Bid {
id: string // UUID
bidNumber: string // Unique, user-defined
name: string // Job/project name
clientId: string // Client UUID
location: string | null // Job location
createdBy: string // User email
status: BidStatus // Lifecycle state
// Equipment Mode
equipmentBiddingMode: string // "TRADITIONAL" | "GANTT"
// Cost Totals (read-only, auto-calculated)
concreteCost: number
laborCost: number
equipmentCost: number
materialCost: number
subcontractorCost: number
miscCost: number
subtotalCost: number
overheadAmount: number
profitAmount: number
totalCost: number
// Settings
overheadPercentage: number
profitPercentage: number
taxExempt: boolean
perDiemEnabled: boolean
// Sharing
shareCode: string | null // BID-XXXXXXXX
shareCodeAt: DateTime | null
sourceBidId: string | null // If imported
sourceUserId: string | null // If imported
// Timestamps
createdAt: DateTime
lastUpdated: DateTime
// Relations
client: Client
scopes: Scope[]
attachments: Attachment[]
}
enum BidStatus {
DRAFT
SUBMITTED
NEGOTIATION
AWARDED
COMPLETED
LOST
}
Equipment Bidding Modes
TRADITIONAL Mode
- Equipment items assigned to individual scopes
- Scope-based cost allocation
- Simple rental calculations
GANTT Mode
- Equipment tracked at bid level with timeline
- Timeline-based cost distribution across scopes
- Overlap detection and proportional allocation
- More accurate for multi-scope equipment usage
View Gantt Mode Equipment Endpoints →