Documentation

Get an order

GET /api/v1/reports/orders/:id and /status: the order, its measurements, file links and a resolved status block.

API reference

Base URL: https://api.roofquery.com. Authenticate with Authorization: Bearer <your key> — except the four file routes, which take no key.

Copies this whole page as Markdown, so you can paste it into an assistant and have it write the integration. Nothing secret goes on the clipboard — your keys aren't included.

GET /api/v1/reports/orders/:id

The whole order. Identical in shape to the webhook body and to /status, so one handler covers all three — that's the point of the shared payload builder. Once the report is delivered, totals, structures[] and files[] fill in. Field-by-field detail is under Report data.

There is deliberately no paginated list endpoint. State is driven by webhooks, and a list endpoint just invites the polling the webhook stream already replaces.

curl -H "Authorization: Bearer rq_live_sk_..." \
  "https://api.roofquery.com/api/v1/reports/orders/rq_ord_8f3a21c9"

Delivered order, trimmed — structures[].faces[] continues for every facet:

{
  "orderId": "rq_ord_8f3a21c9",
  "status": "completed",
  "sandbox": false,
  "createdAt": "2026-08-12T14:03:11.000Z",
  "completedAt": "2026-08-12T16:01:44.000Z",
  "property": {
    "address": "6515 Turnbridge Pl, Prospect, KY 40059, USA",
    "latitude": 38.3526391,
    "longitude": -85.6208045
  },
  "report": {
    "type": "residential",
    "scope": "primary_and_garage",
    "scopeLabel": "Primary structure and detached garage",
    "format": "xml"
  },
  "billing": {
    "amount": 13, "currency": "usd", "method": "account_balance",
    "holdReference": "rq_ord_8f3a21c9", "refunded": false, "released": false
  },
  "revisions": [],
  "totals": {
    "structureCount": 1,
    "totalAreaSqFt": 5597.29,
    "totalSquares": 55.97,
    "totalEdgeLengthFt": 1234.58,
    "facetCount": 33,
    "predominantPitch": "12/12",
    "edgeTotals": {
      "EAVE":      { "lengthFt": 276.31, "count": 27 },
      "RAKE":      { "lengthFt": 169.20, "count": 13 },
      "RIDGE":     { "lengthFt": 114.58, "count": 12 },
      "HIP":       { "lengthFt": 304.25, "count": 20 },
      "VALLEY":    { "lengthFt": 237.30, "count": 17 },
      "STEP_FLASHING": { "lengthFt": 72.81, "count":  9 },
      "WALL_FLASHING": { "lengthFt": 55.45, "count": 14 },
      "BEND":      { "lengthFt":   4.68, "count":  1 },
      "OTHER":     { "lengthFt":   0.00, "count":  0 }
    },
    "hipsAndRidgesLengthFt": 418.83,
    "pitchAreas": { "12/12": 5204.08, "5/12": 257.97, "11/12": 66.42, "10/12": 48.56, "3/12": 20.26 },
    "complexity": "complex",
    "estimatedAtticSqFt": 4023.89,
    "diagrams": {
      "outline": "https://api.roofquery.com/api/v1/reports/orders/rq_ord_8f3a21c9/diagrams/all/outline",
      "area":    "https://api.roofquery.com/api/v1/reports/orders/rq_ord_8f3a21c9/diagrams/all/area",
      "pitch":   "https://api.roofquery.com/api/v1/reports/orders/rq_ord_8f3a21c9/diagrams/all/pitch",
      "lengths": "https://api.roofquery.com/api/v1/reports/orders/rq_ord_8f3a21c9/diagrams/all/lengths"
    }
  },
  "structures": [
    {
      "index": 1,
      "facetCount": 33,
      "totalAreaSqFt": 5597.29,
      "totalSquares": 55.97,
      "predominantPitch": "12/12",
      "edgeTotals": { "...": "same eight categories, for this building" },
      "hipsAndRidgesLengthFt": 418.83,
      "complexity": "complex",
      "estimatedAtticSqFt": 4023.89,
      "diagrams": { "...": "same four types, addressed to structure 1" },
      "faces": [
        {
          "id": "F1",
          "areaSqFt": 338.51,
          "pitch": "12/12",
          "edges": [
            { "type": "RAKE",   "lengthFt": 23.49 },
            { "type": "EAVE",   "lengthFt":  6.11 },
            { "type": "VALLEY", "lengthFt": 28.76 },
            { "type": "RIDGE",  "lengthFt": 22.72 }
          ]
        }
      ]
    }
  ],
  "files": [
    { "name": "report.pdf", "url": "https://api.roofquery.com/api/v1/reports/orders/rq_ord_8f3a21c9/pdf" },
    { "name": "report.xml", "url": "https://api.roofquery.com/api/v1/reports/orders/rq_ord_8f3a21c9/xml" },
    { "name": "report.esx", "url": "https://api.roofquery.com/api/v1/reports/orders/rq_ord_8f3a21c9/esx" }
  ]
}

An unknown order id and an order belonging to someone else both return 404 not_found, never 403 — otherwise the API could be used to probe which order ids exist.

GET /api/v1/reports/orders/:id/status

Everything GET /orders/:id returns, plus a statusDetail block that answers the two questions you'd otherwise write a switch statement for: is anything further expected, and can I download yet.

curl -H "Authorization: Bearer rq_live_sk_..." \
  "https://api.roofquery.com/api/v1/reports/orders/rq_ord_8f3a21c9/status"
{
  "orderId": "rq_ord_8f3a21c9",
  "status": "in-progress",
  "statusDetail": {
    "code": "in-progress",
    "label": "In progress",
    "description": "A technician is measuring the property.",
    "terminal": false,
    "filesReady": false,
    "known": true,
    "changedAt": "2026-08-12T14:22:07.000Z",
    "estimatedDeliveryHours": 2,
    "estimatedReadyAt": "2026-08-12T16:03:11.000Z",
    "openRevisionId": null
  },
  "totals": null,
  "files": []
}
FieldWhat it is
terminalNothing further is expected on this order
filesReadyThe PDF, XML and ESX can all be fetched right now. Also requires files[] to be non-empty, so it can't disagree with the payload
knownfalse if we add a status your code hasn't seen. Branch on this rather than on an exhaustive switch
changedAtWhen the order last moved
estimatedReadyAtOrder time plus the product's typical turnaround. null once files are ready
openRevisionIdThe revision currently open, or null

status stays the same plain string it is in the webhook payload, so a handler written against webhooks works here unchanged. Turnaround — around 2 hours residential, 8 commercial — is an estimate, not a commitment.