Authentication
All API requests require an X-API-Key header. Requests without a valid key receive a 401 response.
X-API-Key: rk_live_your_key_here
Key security
- Keys are SHA-256 hashed at rest — the raw key is shown once at creation and cannot be recovered.
- Generate and manage keys at roofrecon.app/developer.
- Never commit keys to source control.
Keys are generated in the developer portal and shown once at creation time. Keep them in your own secret manager.
Reports
Submits an address to the RoofRecon proprietary measurement engine. The request is synchronous — the response is returned once analysis is complete (typically 10–30 seconds).
Request body
{
"address": "123 Main St, City, ST 12345"
}Response
{
"data": {
"reportId": 12345,
"status": "completed",
"address": "123 Main St, City, ST 12345",
"totalRoofAreaSqFt": 2418,
"primaryPitch": "6/12",
"pdfUrl": "https://www.roofrecon.app/api/v1/reports/12345/pdf"
}
}Returns a paginated list of reports for your account.
Query parameters
| Param | Default | Description |
|---|---|---|
| page | 1 | Page number |
| limit | 20 | Results per page (max 100) |
| status | — | Filter: completed | failed | pending |
Response
{
"data": [ { "reportId": 12345, "address": "...", "status": "completed" } ],
"meta": { "page": 1, "limit": 20, "total": 47 }
}Returns the complete structured report including facets, vertices, linear measurements, material estimates, and siding scope specs when the report is linked to a SidingRecon job.
Response (abridged)
{
"data": {
"reportId": 12345,
"address": "123 Main St, City, ST 12345",
"status": "completed",
"totalRoofAreaSqFt": 2418,
"roofingSquares": 24.2,
"buildingFootprintSqFt": 1840,
"primaryPitch": "6/12",
"sidingScope": {
"source": "vision",
"estimatedAreaLowSqFt": 1840,
"estimatedAreaHighSqFt": 2260,
"recommendedWasteFactor": 15,
"primaryMaterial": "Vinyl lap siding",
"stories": 2,
"confidence": "high"
},
"facets": [
{
"id": 1,
"area": 612,
"pitch": "6/12",
"vertices": [[0,0],[20,0],[20,30],[0,30]],
"edgeTypes": ["ridge","eave","rake","rake"]
}
],
"linearMeasurements": {
"ridgeFt": 42,
"hipFt": 0,
"valleyFt": 18,
"rakeFt": 96,
"eaveFt": 88
},
"pdfUrl": "https://www.roofrecon.app/api/v1/reports/12345/pdf"
}
}Returns a 302 redirect to a time-limited signed URL for the RoofRecon Measurement Report PDF.
Estimates
Generates a material and labor estimate from an existing completed report. Returns a shareable signature URL. When a SidingRecon project is attached to the report, the response also includes siding scope specs.
Request body
{
"reportId": 12345,
"materialTier": "standard", // "economy" | "standard" | "premium"
"brandPreference": "GAF", // optional: "GAF" | "OC" | "CertainTeed"
"contractorName": "John Smith", // optional
"contractorCompany": "Smith Roofing LLC", // optional
"contractorPhone": "216-555-0100" // optional
}Response
{
"data": {
"estimateId": "est_xyz789",
"tier": "standard",
"totalEstimate": 14850.00,
"signatureUrl": "https://roofrecon.app/sign/est_xyz789?token=...",
"pdfUrl": "https://www.roofrecon.app/api/v1/estimates/est_xyz789/pdf",
"sidingScope": {
"estimatedAreaLowSqFt": 1840,
"estimatedAreaHighSqFt": 2260,
"recommendedWasteFactor": 15,
"primaryMaterial": "Vinyl lap siding",
"stories": 2,
"confidence": "high"
}
}
}Returns the full estimate including line items, material quantities, siding scope specs, and current signature status.
Returns a 302 redirect to the signed estimate PDF. Includes contractor branding if configured.
SidingRecon
SidingRecon endpoints let you create siding analyses from property photos and retrieve elevation-level measurements, material type detection, and condition notes.
Submits property photos for siding analysis. Returns area range estimates and material notes once processing is complete.
Request body
{
"jobId": 456,
"photos": [
"https://storage.example.com/front.jpg",
"https://storage.example.com/left.jpg",
"https://storage.example.com/right.jpg"
]
}Response
{
"data": {
"sidingProjectId": 789,
"status": "completed",
"areaRange": "1800–2200 sqft",
"materialNotes": "Vinyl lap siding, 4-inch exposure, fair condition"
}
}Returns the full siding analysis including per-elevation breakdowns, detected material type, and condition notes.
Response
{
"data": {
"id": 789,
"jobId": 456,
"status": "completed",
"areaRange": "1800–2200 sqft",
"elevations": [
{ "name": "Front", "areaSqFt": 620 },
{ "name": "Left", "areaSqFt": 480 },
{ "name": "Right", "areaSqFt": 510 },
{ "name": "Rear", "areaSqFt": 390 }
],
"materialType": "Vinyl lap siding",
"conditionNotes": "Minor fading on south-facing elevation. No visible damage."
}
}Returns the photos uploaded for a siding analysis project, including elevation labels and captions.
Response
{
"data": {
"photos": [
{ "id": 1, "url": "https://...", "elevation": "Front", "caption": "Front elevation" },
{ "id": 2, "url": "https://...", "elevation": "Left", "caption": "Left side" },
{ "id": 3, "url": "https://...", "elevation": "Right", "caption": "Right side" }
]
}
}Webhooks
Webhooks push event notifications to your endpoint instead of requiring you to poll. Register an HTTPS URL and select the events you care about.
Request body
{
"url": "https://yourapp.com/hooks/roofrecon",
"events": ["report.completed", "estimate.signed"]
}Response
{
"data": {
"id": 42,
"url": "https://yourapp.com/hooks/roofrecon",
"events": ["report.completed", "estimate.signed"],
"secret": "8f1e7a4c..." // shown once — save it immediately
},
"meta": {
"message": "Save the secret — it is used to verify webhook signatures and will not be shown again."
}
}Event Types
| Event | Trigger | Payload fields |
|---|---|---|
| report.completed | Report generation finished | reportId, address, status, pdfUrl |
| report.failed | Report generation failed | address, error |
| estimate.created | New estimate generated | estimateId, reportId, totalEstimate, sidingScope |
| estimate.signed | Estimate e-signed by homeowner | estimateId, reportId, signerName |
Signature Verification
Every webhook request includes a X-RoofRecon-Signature header. Verify it using your webhook secret to confirm the request came from RoofRecon.
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const [tPart, vPart] = signature.split(',');
const timestamp = tPart.replace('t=', '');
const expectedSig = vPart.replace('v1=', '');
const computed = crypto
.createHmac('sha256', secret)
.update(timestamp + '.' + payload)
.digest('hex');
return computed === expectedSig;
}Zapier / Make
RoofRecon exposes Zapier and Make-compatible REST Hook endpoints. These are not separate native marketplace apps yet — they use standard subscribe, sample, and action endpoints so you can wire automations without custom backend glue.
Used by Zapier or Make to register a callback URL for events like report.completed and estimate.signed.
Returns sample report data so no-code automation builders can map fields during trigger setup.
Lets Zapier or Make order a report, consume one credit, and return the completed measurement payload in an automation-friendly format.
E-Signatures
The e-signature flow is token-based — no login is required for the homeowner.
- 1
Create an estimate
Call
POST /api/v1/estimates. The response includes asignatureUrl. - 2
Send the link to the homeowner
Email or text the signatureUrl. No account creation required.
- 3
Homeowner reviews and approves
The homeowner visits the URL, reviews the estimate, and clicks Approve. The token in the URL acts as authentication.
- 4
Webhook fired
An
estimate.signedwebhook event is sent to your registered endpoint with the signer's name and timestamp.
signatureUrl token expires after 30 days. Generate a new estimate to issue a fresh link.Errors
All errors follow the same shape: { error: { code, message } }. Match on error.code in your error handling logic.
| Code | HTTP | Description |
|---|---|---|
| MISSING_API_KEY | 401 | X-API-Key header not provided |
| INVALID_API_KEY | 401 | Key is invalid or revoked |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests — check Retry-After header |
| INSUFFICIENT_CREDITS | 402 | Account has no remaining credits — purchase at /billing |
| VALIDATION_ERROR | 400 | Invalid or missing request body fields |
| NOT_FOUND | 404 | Resource not found or not owned by this API key |
| REPORT_GENERATION_FAILED | 500 | Proprietary measurement engine returned an error |
Rate Limits
Rate limits are applied per API key. Each response includes the following headers:
X-RateLimit-Remaining-MinuteRequests remaining in the current 60-second windowX-RateLimit-Remaining-DayRequests remaining for the current calendar day (UTC)Retry-AfterSeconds until the rate limit resets (present on 429 responses only)| Tier | Per minute | Per day | Notes |
|---|---|---|---|
| self_service | 60 | 1,000 | Default for new keys |
| growth | 120 | 5,000 | Contact sales to upgrade |
| scale | 300 | 20,000 | Contact sales to upgrade |
| enterprise | 600 | 100,000 | Custom SLA available |
Code Examples
Complete example: create a report and print the roof area.
curl -X POST https://www.roofrecon.app/api/v1/reports \
-H "X-API-Key: rk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{"address": "477 W Glendale St, Bedford, OH 44146"}'Ready to integrate?
Generate your API key in the developer portal and start creating reports in minutes.
Open Developer Portal