Developers

Estibrain API reference

Pull your estimates, proposals, and invoices into your own tools, and receive real-time webhooks when things happen. The machine-readable spec lives at /api/v1/openapi (OpenAPI 3.1).

Authentication

Create an API key in Settings → API (you'll see it once). Send it as a Bearer token on every request. Keys are scoped to your organization: read, or read + write (needed to send customers and leads in).

curl https://cortex.structureworkstn.com/api/v1/estimates \
  -H "Authorization: Bearer estibrain_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Rate limit: 120 requests / minute per key. Exceeding it returns 429.

Endpoints

POST/api/v1/leads

A lead from your CRM, website or form tool: the customer (matched by external_ref, then email, else created) plus a job at stage Lead on the pipeline. Safe to send twice.

Returns: customer_id, customer_created, job_id, job_created, stage

GET/api/v1/customers

List customers. Filter with ?email=, ?external_ref= (your CRM's id) or ?q= (name/company/email).

Returns: id, name, company_name, email, phone, address, lifecycle, source, external_ids

POST/api/v1/customers

Create a customer, or update the existing match (same external_ref, then same email). Existing details are only filled in, never overwritten.

Returns: the customer + created (true/false)

GET/api/v1/customers/{id}

One customer with their jobs and pipeline stages.

Returns: customer + jobs[] (id, name, status, estimated_value)

PATCH/api/v1/customers/{id}

Change name, company_name, email, phone, address, notes, lifecycle or external_ref. Omitted fields are kept.

Returns: the updated customer

GET/api/v1/pipeline

Every job with its stage (lead, estimating, proposed, won, lost, active, complete), customer and value.

Returns: id, name, stage, customer_id, value, external_ids

GET/api/v1/estimates

List your 100 most recent estimates.

Returns: id, title, status, total, created_at

GET/api/v1/estimates/{id}

One estimate with line items, assumptions, exclusions, and needs-review flags.

Returns: estimate + lines[] (description, qty, unit, unit_cost, price_source, confidence)

GET/api/v1/proposals

List your 100 most recent proposals.

Returns: id, number, title, status, total, signed_at

GET/api/v1/invoices

List your 100 most recent invoices.

Returns: id, number, status, total, amount_paid, balance

All responses are JSON: { "data": … } on success, { "error": "…" } otherwise (401 bad key, 403 scope/plan, 404 not found, 429 rate limit).

Webhooks

Add endpoints in Settings → Webhooks. Estibrain POSTs a JSON body to each active endpoint subscribed to the event:

{
  "event": "invoice.paid",
  "data": { "invoice_id": "…", "number": "INV-1042", "amount": 2500 },
  "ts": 1760000000000
}
EventFires when
estimate.createdAn estimate is saved (by the AI estimator or the API).
proposal.sentA proposal is marked sent and its client link goes live.
proposal.signedA client signs a proposal on the public portal.
invoice.paidA payment lands on an invoice (Stripe checkout completes).
change_order.approvedA change order is approved.
customer.createdA customer is added (in the app, by the API, or from a connected system).
customer.updatedA customer's details change.
lead.createdA new lead (customer + job) arrives through the API or a connected system.
project.status_changedA job moves stage on the pipeline (e.g. proposed → won).

Verifying signatures

Every delivery includes an X-Estibrain-Signature header (also sent as the deprecated X-Cortex-Signature during the rename) — a hex HMAC-SHA256 of the raw request body using your endpoint's signing secret (shown once at creation). Reject anything that doesn't match:

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: string, header: string, secret: string): boolean {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  return (
    header.length === expected.length &&
    timingSafeEqual(Buffer.from(header), Buffer.from(expected))
  );
}

Respond with any 2xx to acknowledge. Failed deliveries are logged and visible in Settings → Webhooks.

Connect the CRM you already use

Estibrain keeps its own customers and pipeline, and stays in step with yours through the API and webhooks — directly, or with Zapier / Make / n8n. Send your CRM's own record id as external_ref and nothing ever duplicates.

New lead in your CRM → a job in Estibrain

curl -X POST https://cortex.structureworkstn.com/api/v1/leads \
  -H "Authorization: Bearer estibrain_live_…" -H "Content-Type: application/json" \
  -d '{
    "customer": { "name": "Dana Price", "email": "dana@example.com",
                  "phone": "(865) 555-0142", "external_ref": "crm-contact-881" },
    "lead":     { "title": "Composite deck 14x20", "address": "100 Main St",
                  "zip": "37919", "estimated_value": 18500, "external_ref": "crm-deal-4410" }
  }'

Estibrain → your CRM

Building your own app? Use Estibrain Connect

If your company runs its own CRM or project app, implement the three-operation Estibrain Connect protocol and add it in Settings → Integrations: Estibrain pulls your customers and leads and sends finished estimates back for a person to review.

API reference · Estibrain