Estimates

Run material matching against a partner-supplied item list

Runs catalog matching only — no file extraction, no estimate generation. Use this when you already have line items (id + product name + optional group/unit) and just want our supplier-catalog matches.

Processing is asynchronous; results are delivered via webhook to callbackUrl in the same format as POST /v1/estimate. The response webhook will carry type: "MATCHING" and each matched row's attributes.partnerItemId echoes the input id so you can correlate.

Workflow:

  1. POST your items to this endpoint
  2. Receive an immediate response with estimateJobId
  3. Receive a webhook at callbackUrl when matching completes
  4. Alternatively, poll GET /v1/estimate/{estimateJobId}
post/v1/estimate/match

Request

  • Base URL: https://api.handoff.ai
  • URL: https://api.handoff.ai/v1/estimate/match
  • Auth: HTTP bearer

Request body

addressstring

Address or ZIP code for regional availability and pricing

callbackUrlstring uri

Webhook URL for job completion notification

externalIdstring

Partner's internal id for this matching request

storeReferencestring

Store, location, or region identifier for applying store-level AI presets

customerReferencestring

Partner's internal reference for tracking specific customers and applying customer-level AI presets

metadataobject

Custom key-value pairs for tracking context. Keys must be alphanumeric with underscores, max 64 chars. Values can be strings (max 256 chars), numbers, or arrays. Maximum 20 pairs.

Example request

{
  "items": [
    {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "productName": "2x6 PT Bottom Plates",
      "group": "Framing",
      "unit": "LF",
      "quantity": 22
    }
  ],
  "address": "Austin, TX 78701",
  "callbackUrl": "https://partners.example.com/webhooks/estimate",
  "externalId": "MATCH-12345",
  "storeReference": "STORE-NYC-001",
  "customerReference": "CUST-ORD-789",
  "metadata": {
    "includeMEP": true,
    "source": "takeoff-api",
    "projectId": "proj-123"
  }
}

Response

Matching job created successfully

estimateJobIdstring uuid required

Unique identifier for the matching job (same identifier space as /v1/estimate)

status'PENDING' | 'EXTRACTING' | 'LABELING' | 'AGENTIC_TAKEOFF' | 'INGESTING' | 'PROCESSING' | 'HUMAN_REVIEW' | 'COMPLETED' | 'FAILED' | 'CANCELED' required

Current job status. Possible values: PENDING, EXTRACTING, LABELING, AGENTIC_TAKEOFF, INGESTING, PROCESSING, HUMAN_REVIEW, COMPLETED, FAILED, CANCELED

createdAtstring date-time required

ISO 8601 timestamp of job creation

estimatedCompletionTimestring date-time required

ISO 8601 timestamp of expected completion

metadataobject

Custom metadata provided during job creation

Example response

{
  "estimateJobId": "e1a2b3c4-d5e6-4f7a-8b9c-0d1e2f3a4b5c",
  "status": "PENDING",
  "createdAt": "2025-12-05T14:30:00Z",
  "estimatedCompletionTime": "2025-12-05T14:35:00Z",
  "metadata": {
    "includeMEP": true,
    "source": "takeoff-api",
    "projectId": "proj-123"
  }
}

Changes

No recorded changes to this operation across all 1 revision of this API.