Developers
Estibrain Connect · v1
Let a company connect the CRM or project app they already run to Estibrain. Your app exposes one HTTPS endpoint; Estibrain calls it to pull customers and leads, and to send finished estimates back as a draft for a person in your app to review. Nothing in your app should change without that review. For plain API/webhook access instead, see the API reference.
Every request
POST https://your-app.example.com/estibrain-connect
Content-Type: application/json
Authorization: Bearer <the key your app issued to the company>
X-Estibrain-Protocol: 1
X-Estibrain-Signature: <hex HMAC-SHA256 of the raw body, keyed with that same key>
{ "op": "<operation>", ... }- Authenticate the key and scope everything to the company that key belongs to.
- Verify the signature over the exact raw body; reject mismatches.
- Answer within 20 seconds with JSON. Errors: any 4xx/5xx with
{"error": "…"}; 401/403 means a bad key. - Money is always integer cents. Ids are your ids, as strings.
- The company adds the connection in Estibrain under Settings → Integrations with your endpoint and their key.
ping
→ { "op": "ping" }
← { "ok": true, "name": "Your App" }listCustomers
Customers changed since since (null = all), up to limit per page. Return next_cursor until done. Estibrain matches on your external_id, then email — it fills in blanks and never deletes.
→ { "op": "listCustomers", "since": "2026-10-24T18:00:00Z", "cursor": null, "limit": 200 }
← { "items": [ { "external_id": "c_881", "name": "Dana Price", "company_name": null,
"email": "dana@example.com", "phone": "+18655550142", "address": "100 Main St" } ],
"next_cursor": null }listLeads
Open leads / opportunities. Each points at a customer from listCustomers; they become jobs at stage Lead.
→ { "op": "listLeads", "since": null, "cursor": null, "limit": 200 }
← { "items": [ { "external_id": "l_4410", "customer_external_id": "c_881",
"title": "Composite deck 14x20", "address": "100 Main St", "zip": "37919",
"value_cents": 1850000 } ],
"next_cursor": null }pushEstimate
Sent when a person in Estibrain clicks “Send to <your app>”. File it for review (e.g. a review queue or a draft) — don't apply it automatically. Every line carries where its price came from and how confident Estibrain is; needs-review items should stay visible to the reviewer.
→ { "op": "pushEstimate", "estimate": {
"estibrain_id": "9577ef6f-…", "title": "Composite deck 14x20", "currency": "USD",
"customer": { "external_id": "c_881", "name": "Dana Price", "email": "dana@example.com", "phone": null },
"lead_external_id": "l_4410",
"subtotal_cents": 130859, "markup_pct": 30, "total_cents": 170117,
"lines": [ { "description": "2x10x12 PT joist", "qty": 17, "unit": "EA",
"unit_cost_cents": 3550, "line_total_cents": 60350,
"price_source": "supplier_feed", "confidence": 0.9, "needs_review": false,
"cost_code": "FRAME", "cost_group": "Framing" } ],
"assumptions": ["Joists 12 in OC"], "exclusions": ["Railing"], "needs_review": ["Hangers"],
"url": "https://…/estimates/9577ef6f-…" } }
← { "external_id": "rev_77", "status": "pending_review", "url": "https://your-app…/reviews/rev_77" }price_source is one of user_pricebook, supplier_feed, cci_baseline, community_actual, ai_inferred (AI estimates are always flagged for review).