openapi: 3.0.3 info: title: Buildxact Public API version: v3 description: >- Buildxact's public REST API for residential construction estimating and job management. The API is fronted by Azure API Management and requires both an Ocp-Apim-Subscription-Key (identifying the partner / customer organization) and an Authorization: Bearer access token (identifying the specific user and tenant). Endpoints follow REST conventions with OData query support: $filter (operators include eq, gt, lt, contains, in), $orderBy with asc/desc, $top, $skip, and $count=true (record total returned in the x-odata-total-count response header). A short-lived access token is obtained via the accounts/auth/login endpoint and may be refreshed via accounts/auth/refresh-token. Rate-limited at 100 requests per 30-second window. A separate UAT/staging environment is available at developer-uat.buildxact.com for integration testing. contact: name: Buildxact API Support url: https://developer.buildxact.com/getting-started termsOfService: https://www.buildxact.com/au/terms-of-use/ license: name: Buildxact API Terms url: https://www.buildxact.com/au/terms-of-use/ servers: - url: https://api.buildxact.com description: Production - url: https://api-v3.buildxact.com description: Production (v3 host used for the accounts/auth endpoints) - url: https://developer-uat.buildxact.com description: UAT / Staging tags: - name: Authentication description: First-party login and bearer token refresh. - name: Estimates description: Construction estimates — the top-level pricing document for a job. - name: Estimate Items description: Line items inside an estimate (materials, labor, assemblies). - name: Tax Context description: Tax rates and inclusivity rules applied to estimate totals. security: - SubscriptionKey: [] BearerAuth: [] paths: /accounts/auth/login: post: tags: - Authentication summary: Login and Obtain Bearer Token description: >- Exchange a Buildxact user email and plaintext API key for a short-lived bearer token plus refresh token. The subscription key header is still required to route the request through API Management. operationId: login security: - SubscriptionKey: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/LoginRequest' responses: '200': description: Authentication succeeded. content: application/json: schema: $ref: '#/components/schemas/TokenResponse' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /accounts/auth/refresh-token: post: tags: - Authentication summary: Refresh Bearer Token description: >- Exchange a refresh token for a new short-lived access token without re-prompting the user for credentials. operationId: refreshToken security: - SubscriptionKey: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RefreshTokenRequest' responses: '200': description: New access token issued. content: application/json: schema: $ref: '#/components/schemas/TokenResponse' '401': $ref: '#/components/responses/Unauthorized' /estimates: get: tags: - Estimates summary: List Estimates description: >- Return a paginated list of estimates for the authenticated tenant. Supports OData $filter, $orderBy, $top, $skip, and $count. operationId: listEstimates parameters: - $ref: '#/components/parameters/ODataFilter' - $ref: '#/components/parameters/ODataOrderBy' - $ref: '#/components/parameters/ODataTop' - $ref: '#/components/parameters/ODataSkip' - $ref: '#/components/parameters/ODataCount' responses: '200': description: Estimate collection. headers: x-odata-total-count: description: Total estimate count when $count=true is supplied. schema: type: integer content: application/json: schema: type: array items: $ref: '#/components/schemas/Estimate' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' post: tags: - Estimates summary: Create Estimate description: Create a new construction estimate for the authenticated tenant. operationId: createEstimate requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Estimate' responses: '201': description: Estimate created. content: application/json: schema: $ref: '#/components/schemas/Estimate' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' /estimates/{estimateId}: parameters: - $ref: '#/components/parameters/EstimateId' get: tags: - Estimates summary: Get Estimate description: Return a single estimate by its identifier, including totals and tax context. operationId: getEstimate responses: '200': description: Estimate found. content: application/json: schema: $ref: '#/components/schemas/Estimate' '404': $ref: '#/components/responses/NotFound' patch: tags: - Estimates summary: Update Estimate description: Partially update fields on an existing estimate. operationId: updateEstimate requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Estimate' responses: '200': description: Estimate updated. content: application/json: schema: $ref: '#/components/schemas/Estimate' '400': $ref: '#/components/responses/BadRequest' '404': $ref: '#/components/responses/NotFound' delete: tags: - Estimates summary: Delete Estimate description: Delete an estimate by identifier. operationId: deleteEstimate responses: '204': description: Estimate deleted. '404': $ref: '#/components/responses/NotFound' /estimates/{estimateId}/items: parameters: - $ref: '#/components/parameters/EstimateId' get: tags: - Estimate Items summary: List Estimate Items description: >- Return the line items belonging to an estimate. Supports OData $filter, $orderBy, $top, $skip, and $count. operationId: listEstimateItems parameters: - $ref: '#/components/parameters/ODataFilter' - $ref: '#/components/parameters/ODataOrderBy' - $ref: '#/components/parameters/ODataTop' - $ref: '#/components/parameters/ODataSkip' - $ref: '#/components/parameters/ODataCount' responses: '200': description: Estimate item collection. headers: x-odata-total-count: description: Total item count when $count=true is supplied. schema: type: integer content: application/json: schema: type: array items: $ref: '#/components/schemas/EstimateItem' post: tags: - Estimate Items summary: Add Estimate Item description: Add a new line item to an estimate. operationId: addEstimateItem requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EstimateItem' responses: '201': description: Estimate item created. content: application/json: schema: $ref: '#/components/schemas/EstimateItem' /estimates/{estimateId}/items/{itemId}: parameters: - $ref: '#/components/parameters/EstimateId' - $ref: '#/components/parameters/ItemId' get: tags: - Estimate Items summary: Get Estimate Item description: Return a single estimate line item. operationId: getEstimateItem responses: '200': description: Estimate item found. content: application/json: schema: $ref: '#/components/schemas/EstimateItem' '404': $ref: '#/components/responses/NotFound' patch: tags: - Estimate Items summary: Update Estimate Item description: Partially update an estimate line item. operationId: updateEstimateItem requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EstimateItem' responses: '200': description: Estimate item updated. content: application/json: schema: $ref: '#/components/schemas/EstimateItem' delete: tags: - Estimate Items summary: Delete Estimate Item description: Remove an estimate line item. operationId: deleteEstimateItem responses: '204': description: Estimate item deleted. /tax-rates: get: tags: - Tax Context summary: List Tax Rates description: >- Return the tax rates available to the authenticated tenant, used to interpret tax-inclusive and tax-exclusive totals on estimates and estimate items. operationId: listTaxRates responses: '200': description: Tax rate collection. content: application/json: schema: type: array items: $ref: '#/components/schemas/TaxRate' components: securitySchemes: SubscriptionKey: type: apiKey in: header name: Ocp-Apim-Subscription-Key description: Azure API Management subscription key issued to a partner organization. BearerAuth: type: http scheme: bearer bearerFormat: JWT description: Short-lived bearer token obtained from /accounts/auth/login. parameters: EstimateId: name: estimateId in: path required: true schema: type: string description: Unique identifier of the estimate. ItemId: name: itemId in: path required: true schema: type: string description: Unique identifier of the estimate line item. ODataFilter: name: $filter in: query description: OData filter expression (operators include eq, gt, lt, contains, in). schema: type: string ODataOrderBy: name: $orderBy in: query description: OData orderBy expression (e.g. fieldName asc, fieldName desc). schema: type: string ODataTop: name: $top in: query description: Page size — maximum records to return. schema: type: integer minimum: 1 ODataSkip: name: $skip in: query description: Number of records to skip for pagination. schema: type: integer minimum: 0 ODataCount: name: $count in: query description: When true, include the total record count in the x-odata-total-count response header. schema: type: boolean responses: BadRequest: description: Malformed request. content: application/json: schema: $ref: '#/components/schemas/Error' Unauthorized: description: Missing or invalid credentials. content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: Resource not found. content: application/json: schema: $ref: '#/components/schemas/Error' TooManyRequests: description: Rate limit exceeded (100 requests per 30-second window). content: application/json: schema: $ref: '#/components/schemas/Error' schemas: LoginRequest: type: object required: - email - apiKey properties: email: type: string format: email description: Buildxact user email address. apiKey: type: string description: Plaintext API key issued to the Buildxact user. RefreshTokenRequest: type: object required: - refreshToken properties: refreshToken: type: string description: Refresh token previously returned by /accounts/auth/login. TokenResponse: type: object properties: accessToken: type: string description: Short-lived bearer token to use in the Authorization header. refreshToken: type: string description: Token used to mint a new access token without re-authenticating. expiresIn: type: integer description: Lifetime of the access token, in seconds. tokenType: type: string example: Bearer Estimate: type: object description: >- A construction estimate — the priced document a builder issues to a client capturing scope, line items, markup, and tax. properties: id: type: string description: Estimate identifier. name: type: string description: Human-readable estimate name. jobId: type: string description: Identifier of the parent job, if any. customerId: type: string description: Identifier of the customer this estimate is for. status: type: string description: Estimate status (e.g. Draft, Sent, Accepted, Declined). currency: type: string description: ISO 4217 currency code applied to monetary fields. total: type: number format: double description: Subtotal of all items before markup and tax. markup: type: number format: double description: Markup amount applied on top of the subtotal. totalIncMarkup: type: number format: double description: Subtotal plus markup, exclusive of tax. taxIncMarkup: type: number format: double description: Tax amount calculated on the markup-inclusive total. totalIncMarkupTax: type: number format: double description: Grand total including markup and tax. taxContext: $ref: '#/components/schemas/TaxContext' createdAt: type: string format: date-time modifiedAt: type: string format: date-time EstimateItem: type: object description: A line item on an estimate — material, labor, subcontractor, or assembly. properties: id: type: string estimateId: type: string description: type: string category: type: string description: Cost category (e.g. Materials, Labor, Subcontractor). unit: type: string description: Unit of measure (e.g. each, hour, m2, lf). quantity: type: number format: double unitCost: type: number format: double total: type: number format: double markup: type: number format: double totalIncMarkup: type: number format: double totalIncTax: type: number format: double taxContext: $ref: '#/components/schemas/TaxContext' TaxRate: type: object properties: id: type: string name: type: string rate: type: number format: double description: Tax rate as a decimal (e.g. 0.10 for 10%). isDefault: type: boolean TaxContext: type: object description: >- Tax inclusivity context — describes whether stored monetary values on an estimate or item already include tax and which tax rate applies. properties: taxRateId: type: string taxRate: type: number format: double pricesIncludeTax: type: boolean Error: type: object properties: code: type: string message: type: string details: type: array items: type: object