{"openapi":"3.1.0","info":{"title":"Estibrain API","version":"1.0.0","description":"Your Estibrain estimates, proposals and invoices, the CRM (customers, leads, pipeline) so another CRM can stay in step, plus outbound webhooks for real-time events. Manage API keys at /settings/api and webhook endpoints at /settings/webhooks."},"servers":[{"url":"/api/v1"}],"security":[{"bearerAuth":[]}],"paths":{"/leads":{"post":{"summary":"Send in a lead","description":"Customer (matched by external_ref, then email, else created) plus a job at stage 'lead'. Idempotent with external_ref. Needs a write-scope key.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["customer"],"properties":{"customer":{"$ref":"#/components/schemas/CustomerInput"},"lead":{"type":"object","properties":{"title":{"type":"string"},"address":{"type":"string"},"zip":{"type":"string"},"estimated_value":{"type":"number","description":"dollars"},"external_ref":{"type":"string","description":"your CRM's id for the deal"}}}}}}}},"responses":{"200":{"description":"Already had this lead (matched by external_ref)"},"201":{"description":"Lead created"},"400":{"description":"Invalid customer or lead","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing write scope or plan does not include API write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers":{"get":{"summary":"List customers","parameters":[{"name":"email","in":"query","schema":{"type":"string"}},{"name":"external_ref","in":"query","schema":{"type":"string"}},{"name":"q","in":"query","schema":{"type":"string"},"description":"name, company or email contains"}],"responses":{"200":{"description":"Customers","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create or update a customer","description":"Updates the match (same external_ref, then same email); only blank fields are filled.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerInput"}}}},"responses":{"200":{"description":"Matched an existing customer"},"201":{"description":"Created"},"400":{"description":"Invalid customer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/customers/{id}":{"get":{"summary":"Get a customer with their jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Customer"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update a customer","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerInput"}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/pipeline":{"get":{"summary":"Jobs by stage","description":"Every job with stage, customer and value (latest proposal, else estimate, else the lead's estimate).","responses":{"200":{"description":"Jobs"}}}},"/estimates":{"get":{"summary":"List estimates","description":"Up to 100 most recent estimates in your organization.","responses":{"200":{"description":"Estimate list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EstimateSummary"}}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing read scope or plan does not include API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (120 requests / minute per key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/estimates/{id}":{"get":{"summary":"Get one estimate","description":"One estimate with its line items, assumptions, and exclusions.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Estimate detail","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/EstimateDetail"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing read scope or plan does not include API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found (or not in your organization)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/proposals":{"get":{"summary":"List proposals","description":"Up to 100 most recent proposals in your organization.","responses":{"200":{"description":"Proposal list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProposalSummary"}}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing read scope or plan does not include API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/invoices":{"get":{"summary":"List invoices","description":"Up to 100 most recent invoices in your organization.","responses":{"200":{"description":"Invoice list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceSummary"}}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing read scope or plan does not include API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key from /settings/api, sent as `Authorization: Bearer estibrain_live_…`. Keys are org-scoped; read scope only. Rate limit: 120 requests/minute per key."}},"schemas":{"CustomerInput":{"type":"object","properties":{"name":{"type":"string"},"company_name":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"address":{"type":"string"},"notes":{"type":"string"},"lifecycle":{"type":"string","enum":["lead","customer","past"]},"external_ref":{"type":"string","description":"your CRM's id for this person/company"}}},"Customer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"company_name":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"address":{"type":["string","null"]},"lifecycle":{"type":"string","enum":["lead","customer","past"]},"source":{"type":"string","enum":["manual","api","connect","portal"]},"external_ids":{"type":"object","additionalProperties":{"type":"string"}}}},"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"EstimateSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"status":{"type":"string","enum":["draft","verified","approved"]},"total":{"type":"number"},"created_at":{"type":"string","format":"date-time"}}},"EstimateLine":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"description":{"type":"string"},"qty":{"type":"number"},"unit":{"type":"string"},"unit_cost":{"type":"number"},"line_total":{"type":"number"},"price_source":{"type":"string","enum":["user_pricebook","supplier_feed","cci_baseline","community_actual","ai_inferred"]},"confidence":{"type":"number","minimum":0,"maximum":1},"source_ref":{"type":["string","null"]},"needs_review":{"type":"boolean"}}},"EstimateDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"status":{"type":"string"},"subtotal":{"type":"number"},"markup_pct":{"type":"number"},"total":{"type":"number"},"assumptions":{"type":"array","items":{}},"exclusions":{"type":"array","items":{}},"needs_review":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/EstimateLine"}}}},"ProposalSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"number":{"type":["string","null"]},"title":{"type":"string"},"status":{"type":"string","enum":["draft","sent","viewed","approved","rejected","expired"]},"total":{"type":"number"},"signed_at":{"type":["string","null"],"format":"date-time"}}},"InvoiceSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"number":{"type":["string","null"]},"status":{"type":"string","enum":["draft","sent","viewed","partial","paid","overdue","void"]},"total":{"type":"number"},"amount_paid":{"type":"number"},"balance":{"type":"number"}}},"WebhookDelivery":{"type":"object","description":"Body Estibrain POSTs to your webhook endpoints. Verify the X-Estibrain-Signature header: hex HMAC-SHA256 of the raw request body using your endpoint's secret.","properties":{"event":{"type":"string","enum":["estimate.created","proposal.sent","proposal.signed","invoice.paid","change_order.approved"]},"data":{"type":"object","description":"Event-specific payload."},"ts":{"type":"integer","description":"Unix epoch milliseconds when the event fired."}},"required":["event","data","ts"]}}},"webhooks":{"cortex-event":{"post":{"summary":"Outbound event delivery","description":"Estibrain POSTs this to every active webhook endpoint subscribed to the event. Configure endpoints at /settings/webhooks.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}}},"responses":{"200":{"description":"Acknowledge with any 2xx status."}}}}}}