Documentation

Place an order

POST /api/v1/reports/orders: every field, the scope rule, sandbox behaviour, and the 201 you get back.

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.

POST /api/v1/reports/orders

Places an order and returns 201 with the order in its initial state. Measurements arrive later — wait for the completed webhook rather than polling.

FieldRequiredRules
countryYesUS or CA. Validated first — every other field depends on it
streetYesstring
cityYesstring
stateYes2-letter state or province abbreviation
postalCodeYesUS 12345 or 12345-6789; CA A1A 1A1. Format only — we don't check it agrees with the state
latitudeYesnumber, −90 to 90
longitudeYesnumber, −180 to 180
scopeYesprimary_only, primary_and_garage, or all_structures. Not defaulted
reportTypeNoresidential (default) or commercial
reportNameNoYour own label, printed on the report
claimNoClaim number for the job, up to 64 characters. The annotators put it on the Xactimate .esx, and the file downloads as <claim>.esx — see the ESX endpoint. Set here or not at all
notesNoFree text for the technician
clientInfoNoObject. Only firstName, lastName, email, phone, street, city, state, county are kept — anything else is dropped. 200 chars each
curl -X POST "https://api.roofquery.com/api/v1/reports/orders" \
  -H "Authorization: Bearer rq_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "country": "US",
    "street": "6515 Turnbridge Pl",
    "city": "Prospect",
    "state": "KY",
    "postalCode": "40059",
    "latitude": 38.3526391,
    "longitude": -85.6208045,
    "scope": "primary_and_garage",
    "reportType": "residential",
    "reportName": "Henderson — 6515 Turnbridge",
    "claim": "CLAIM12345",
    "notes": "Detached garage at rear.",
    "clientInfo": {
      "firstName": "Dana",
      "lastName": "Henderson",
      "email": "[email protected]",
      "phone": "502-555-0148"
    }
  }'

201 Created. totals, structures and files are empty until the report is delivered.

{
  "orderId": "rq_ord_8f3a21c9",
  "status": "processing",
  "previousStatus": null,
  "event": null,
  "reason": null,
  "sandbox": false,
  "sandboxScenario": null,
  "createdAt": "2026-08-12T14:03:11.000Z",
  "updatedAt": "2026-08-12T14:03:11.000Z",
  "completedAt": null,
  "property": {
    "address": "6515 Turnbridge Pl, Prospect, KY 40059, USA",
    "latitude": 38.3526391,
    "longitude": -85.6208045
  },
  "report": {
    "type": "residential",
    "name": "Henderson — 6515 Turnbridge",
    "claim": "CLAIM12345",
    "scope": "primary_and_garage",
    "scopeLabel": "Primary structure and detached garage",
    "notes": "Detached garage at rear.",
    "format": "xml"
  },
  "clientInfo": {
    "firstName": "Dana",
    "lastName": "Henderson",
    "email": "[email protected]",
    "phone": "502-555-0148"
  },
  "billing": {
    "amount": 13,
    "currency": "usd",
    "method": "account_balance",
    "holdReference": "rq_ord_8f3a21c9",
    "refunded": false,
    "released": false
  },
  "revisions": [],
  "totals": null,
  "structures": null,
  "files": []
}

Sandbox. A rq_test_sk_* key runs a scheduled timeline against your real webhooks and never contacts the provider. The scenario is chosen by the address you order and nothing else — see sandbox scenarios. There is no header or body field that forces one, so a sandbox order and a live order are the same request; only the key differs.