Connect Make, Zapier or your own scripts - Conduit Help
HELP
Getting Started

Connect Make, Zapier or your own scripts

Create an API key, call the Conduit API for customers, leads, jobs, bids and invoices, and get webhooks when things happen.

Updated Nov 9, 2026 · 7 min read · For Owner

The API lets other tools work with your Conduit account. An AI receptionist can add a lead the moment a call ends, Make or Zapier can create a customer from a web form, and your own script can pull this week’s jobs or unpaid invoices. You find it under Integrations, on the API & webhooks tab.

Lessons in this guide

Start
  1. 1 Try it yourself

How API keys work

  • A key acts as the person who created it. It can only do what that person can do in Conduit, and only in the company it was created in. If that person leaves the company, the key stops working.
  • A key reaches the endpoints listed below and nothing else. Settings, team, payments and everything not listed answer 403.
  • You see the whole key once. Conduit keeps only a scrambled copy. After you close it, the list shows the first characters (like cfc_live_ab12cd34…) so you can tell keys apart. Lost a key? Revoke it and create a new one.
  • Up to 10 active keys per company. Make one per tool, named after it, so you can revoke one without breaking the others.
  • 300 requests a minute per key. Past that, requests answer 429 until the minute is up.

Creating and revoking keys takes the Configure integrations permission (Admin and Owner by default; see Team and permissions).

Create and revoke a key

Open Integrations, choose the API & webhooks tab, type a name in Key name and choose Create key. Copy the key into Make, Zapier or your script, then choose Done. To turn a key off, choose Revoke next to it and confirm with Revoke key; anything using it stops working straight away.

Endpoints

Every request goes to https://www.conduitforcontractors.com/api/v1 with the header Authorization: Bearer cfc_live_… (your key). Send JSON with Content-Type: application/json.

What Requests
Customers GET /customers, GET /customers/:id, POST /customers, PATCH /customers/:id
Leads GET /crm/leads, GET /crm/leads/:id, POST /crm/leads, PATCH /crm/leads/:id
Jobs GET /jobs, GET /jobs/:id, POST /jobs
Bids GET /bids, GET /bids/:id
Invoices GET /invoices, GET /invoices/:id

Lists take page and per_page (up to 100) and return the records plus a pagination object with page, per_page, total and total_pages. Customers and leads take q to search; jobs and bids take status, customer_id and project_id.

Create a customer. Fields: name (required), email, phone, company_name, customer_type (residential, commercial or property_manager), address, city, state, zip, source, notes.

curl -X POST https://www.conduitforcontractors.com/api/v1/customers \
  -H "Authorization: Bearer cfc_live_…" \
  -H "Content-Type: application/json" \
  -d '{"customer": {"name": "Rosa Diaz", "email": "rosa@example.com", "phone": "5555550142", "address": "12 Elm St", "city": "Denver", "state": "CO", "zip": "80202", "source": "AI receptionist"}}'

Create a lead. Fields: name, email, phone, company_name, address, city, state, zip, source, notes, estimated_value, stage, tags. A new lead starts in the new stage unless you send stage.

curl -X POST https://www.conduitforcontractors.com/api/v1/crm/leads \
  -H "Authorization: Bearer cfc_live_…" \
  -H "Content-Type: application/json" \
  -d '{"lead": {"name": "Rosa Diaz", "phone": "5555550142", "source": "AI receptionist", "notes": "Musty smell in the basement"}}'

Update a customer or a lead. PATCH /customers/:id takes a customer object and PATCH /crm/leads/:id takes a lead object, with the same fields as creating one. Send only the fields you want to change; anything you leave out stays as it is.

curl -X PATCH https://www.conduitforcontractors.com/api/v1/crm/leads/31 \
  -H "Authorization: Bearer cfc_live_…" \
  -H "Content-Type: application/json" \
  -d '{"lead": {"stage": "contacted", "estimated_value": 4500}}'

Text message consent is recorded in Conduit, not through the API: an API key cannot turn a customer’s or lead’s text consent on or off, and an sms_consent field in the request is ignored.

Create a job. Fields: title, customer_id, scheduled_start, scheduled_end (ISO 8601 times), description, job_type, priority, assigned_to_id, project_id, address, city, state, zip. Without a project_id the job stands on its own, like a service call booked in the app.

curl -X POST https://www.conduitforcontractors.com/api/v1/jobs \
  -H "Authorization: Bearer cfc_live_…" \
  -H "Content-Type: application/json" \
  -d '{"job": {"title": "Mold inspection", "customer_id": 14, "scheduled_start": "2026-11-10T09:00:00-07:00", "scheduled_end": "2026-11-10T11:00:00-07:00"}}'

List jobs, invoices and bids.

curl "https://www.conduitforcontractors.com/api/v1/jobs?status=scheduled&per_page=25" -H "Authorization: Bearer cfc_live_…"
curl "https://www.conduitforcontractors.com/api/v1/invoices?page=1" -H "Authorization: Bearer cfc_live_…"
curl "https://www.conduitforcontractors.com/api/v1/bids?status=sent" -H "Authorization: Bearer cfc_live_…"

Each job has id, job_number, title, status, customer_id, customer_name, scheduled_start, scheduled_end and full_address. Each invoice has id, invoice_number, status, customer_name, total, amount_paid, amount_due, issue_date and due_date. Each bid has id, bid_number, title, status, customer_name, total and valid_until.

A request that fails answers with an error sentence: 401 for a missing, wrong or revoked key, 403 for an endpoint a key cannot reach or a permission its creator does not have, 404 for a record that is not in your company, 422 for a field that is missing or wrong (with the field named), and 429 when the key is over its limit.

Webhooks

A webhook is the other direction: Conduit sends a POST to your URL when something happens, so Make or Zapier can react without checking every few minutes. Add an endpoint in the Webhooks section of the same tab and choose its events:

Event Sent when
lead.created A lead is added
customer.created A customer is added
bid.accepted A bid is accepted
job.created A job is created
invoice.paid An invoice is paid in full

Each POST is JSON with id, event, created_at, company_id and data, the record as the API returns it. Answer with any 2xx status within 15 seconds. Anything else is tried again: five attempts in all, the retries 1 minute, 5 minutes, 30 minutes and 2 hours after the one before, so about 2 hours 36 minutes from first try to last. Recent deliveries on the endpoint shows each attempt. After 20 failed attempts in a row the endpoint is paused until you resume it.

The same event can arrive more than once (a retry after a slow answer, say). Every attempt carries the same id, so keep the ids you have handled and ignore one you have seen before.

Verify the signature

Every POST is signed with the endpoint’s secret (whsec_…, shown once when you add the endpoint). The X-Conduit-Signature header is sha256= followed by the HMAC-SHA256 of the X-Conduit-Timestamp header, a period and the raw body. Before trusting a delivery:

  1. Compute the signature over the raw body exactly as it arrived, before parsing the JSON.
  2. Compare it with the header using a constant-time comparison.
  3. Refuse a timestamp more than five minutes old, so a captured request cannot be replayed later.

Node (Express, with express.raw({ type: "application/json" })):

const crypto = require("crypto")
const ts = req.get("X-Conduit-Timestamp"), sig = req.get("X-Conduit-Signature") || ""
const expected = "sha256=" + crypto.createHmac("sha256", process.env.CONDUIT_WEBHOOK_SECRET).update(`${ts}.${req.body}`).digest("hex")
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300
const valid = fresh && sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
if (!valid) return res.status(401).end()

Ruby (Rails):

body = request.raw_post
ts = request.headers["X-Conduit-Timestamp"]
expected = "sha256=#{OpenSSL::HMAC.hexdigest("SHA256", ENV.fetch("CONDUIT_WEBHOOK_SECRET"), "#{ts}.#{body}")}"
fresh = (Time.now.to_i - ts.to_i).abs < 300
valid = fresh && Rack::Utils.secure_compare(expected, request.headers["X-Conduit-Signature"].to_s)
head :unauthorized unless valid

Make and Zapier

Make: add the HTTP module and choose Make a request. Set the URL to an endpoint above and the method to GET or POST. Add a header named Authorization with the value Bearer followed by a space and your key. For a POST, set the body type to Raw, the content type to JSON (application/json) and paste the JSON from the example, mapping your fields into it. To react to Conduit events, start the scenario with Webhooks > Custom webhook, copy the address Make gives you and add it as a webhook endpoint in Conduit.

Zapier: use Webhooks by Zapier. Custom Request calls the API with the same URL, header and JSON; Catch Hook gives you an address to add as a webhook endpoint in Conduit.

Still need a hand?

Tell us what you were trying to do so we can help and improve this guide.

Contact support