Zapier, webhooks and the API
Pro
Send what happens in your agency to Zapier, Make or your own server, add leads from any form, and read or change your data with an API key.
Your agency does not live in one tool. Connect other tools lets Site Haus talk to the rest of your stack: send a message when a lead arrives, a proposal is accepted or a payment lands; add leads from any form; and read or add your data from a script or a Zap.
Open Integrations and choose Zapier, webhooks and API. It has four parts: a lead link, webhooks, API keys and a short Zapier guide.
What people do with it#
- New lead → Slack, Google Sheets or your CRM. Add a webhook for
lead.createdand point it at a Zapier Catch Hook. - Typeform, Tally, Calendly or a website form → a lead in Site Haus. Post to the lead link.
- Proposal accepted → an invoice or a project in another tool. Webhook for
proposal.accepted. - Payment received → a message to your team or your bookkeeping. Webhook for
payment.received. - A task finished in another tool → mark it done here. Use the API from a Zap or a script.
The lead link#
The lead link is an address that adds a lead when something is posted to it. Paste it into any form, booking or chat tool that can send a webhook, or use Webhooks by Zapier → POST. Site Haus understands a name (or first and last name), email, company, website, phone, a message and a budget however the tool spells them, and puts anything else in the lead's notes. The lead appears in Leads as Lead link.
Anyone who has the link can add leads, so only give it to tools you trust. If it leaks, press Make a new link: the old one stops working at once.
Webhooks#
A webhook is a message Site Haus sends to an address you choose when something happens. Press Add a webhook, paste the address (it must start with https://), choose what to send and save. You are shown a signing secret once: copy it. Press Send a test to check the receiver.
What you can subscribe to#
| Event | When |
|---|---|
lead.created | A lead is added: by hand, from a form, from the lead link, by import or through the API |
lead.updated | A lead changes, including moving to another stage (previous_status says where it was) |
form.submitted | Someone sends one of your intake forms, with their answers |
client.created | A client is added |
proposal.sent | A proposal is sent to a client |
proposal.accepted | A client accepts a proposal |
proposal.declined | A client declines a proposal |
proposal.changes_requested | A client asks for changes to a proposal |
payment.received | A proposal payment is paid, by card or crypto |
ticket.created | A client opens a ticket |
ticket.resolved | A ticket is marked resolved or closed |
task.created | A task is made (including one made again by a repeating task) |
task.completed | A task is finished, by your team or by the client |
site.published | A website or app is published |
You can also choose Everything, which includes events we add later. Recent messages shows what was sent.
What a message looks like#
Every message is JSON with the same outline:
{
"id": "evt_5f2c9a1b7d3e4a60",
"type": "lead.created",
"created": 1790000000,
"agency": { "id": "a1b2c3d4e5f6", "name": "Haus & Co" },
"data": {
"object": {
"id": "6d94684ed78a", "name": "Wendy Vee", "company": "Vee Bakery", "email": "[email protected]",
"website": "", "source": "Website form", "status": "New", "amount": 3500,
"notes": "Wants a new site before spring.", "follow_up": "", "created": 1790000000000, "updated": 1790000000000
}
}
}Times in created at the top are seconds; times inside object are milliseconds. The same fields are returned by the API, so an example from one works for the other. Open Add a webhook and press Send a test to see a real message arrive, or ask the API for an example of any event: GET /api/v1/samples/lead.created.
A message also carries these headers:
| Header | What it is |
|---|---|
X-SiteHaus-Event | The event, like lead.created |
X-SiteHaus-Delivery | A unique id for this message. Retries use the same one, so you can ignore a repeat |
X-SiteHaus-Signature | t=<time>,v1=<signature>: proof the message came from Site Haus |
Check the signature#
Anyone could post to your address, so check the signature. It is an HMAC-SHA256 of <t>.<the raw body> using your signing secret, the same way Stripe signs. Reject a message whose time is more than five minutes old.
Node.js
import crypto from 'node:crypto';
function isFromSiteHaus(secret, header, rawBody) {
const m = /t=(\d+),v1=([0-9a-f]+)/.exec(header || ''); if (!m) return false;
if (Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
const want = crypto.createHmac('sha256', secret).update(`${m[1]}.${rawBody}`).digest('hex');
return want.length === m[2].length && crypto.timingSafeEqual(Buffer.from(want), Buffer.from(m[2]));
}Python
import hmac, hashlib, re, time
def is_from_sitehaus(secret, header, raw_body):
m = re.match(r"t=(\d+),v1=([0-9a-f]+)", header or "")
if not m or abs(time.time() - int(m.group(1))) > 300: return False
want = hmac.new(secret.encode(), f"{m.group(1)}.{raw_body}".encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(want, m.group(2))PHP
function isFromSiteHaus($secret, $header, $rawBody) {
if (!preg_match('/t=(\d+),v1=([0-9a-f]+)/', $header ?? '', $m) || abs(time() - (int)$m[1]) > 300) return false;
return hash_equals(hash_hmac('sha256', $m[1] . '.' . $rawBody, $secret), $m[2]);
}Zapier and Make do not check signatures for you. If you use a Catch Hook, the secret address itself is what keeps others out, so do not share it.
When your receiver is down#
Answer with any 2xx status within 10 seconds to say you got it. If you answer something else, or nothing, Site Haus tries again after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours, so a problem of up to about 15 hours is covered. The message is the same each time, with the same delivery id.
- Recent messages lists the last 50 with how each went. Press Send again on any that failed.
- A webhook that fails 15 messages in a row is switched off and you are emailed. Fix the receiver and press Switch on.
- A redirect counts as a failure: give the final address.
- New secret replaces the signing secret. The old one stops working at once.
Limits#
You can add up to 10 webhooks by hand, plus up to 100 that Zapier or another tool makes through the API (each Zap that is turned on makes one). The address must start with https:// and be on the public internet: addresses on a private network or this machine are refused. Messages are at most 64 KB. Nothing secret is ever put in a message: no passwords, tokens or payment details.
API keys#
An API key lets a script or a tool read and add your data. Press Make a key, name it after the tool that will use it, and choose:
- Read and write: look at things, add leads, clients and tasks, change leads and tasks, and set up webhooks.
- Read only: look at things.
The key is shown once. Copy it somewhere safe. You can remove it at any time, and it stops working at once. A key belongs to your agency, so it keeps working if a teammate leaves.
Send the key with every request: Authorization: Bearer <your key>. The API address is shown in Connect other tools, under API keys: it is your Site Haus address followed by /api/v1. It always answers JSON, allows 300 requests a minute per key, and does not let anything be deleted or any email be sent.
| Request | What it does |
|---|---|
GET /me | Checks the key, and says which agency it is for |
GET /leads POST /leads PATCH /leads/:id | List leads (filter with status, since, limit), add one, change one |
GET /clients POST /clients | List clients, add one (their portal password is made in Site Haus, never returned) |
GET /tasks POST /tasks PATCH /tasks/:id | List tasks (filter with status, client), add one, change one |
GET /tickets | List tickets (read only) |
GET /proposals | List proposals (read only) |
GET /webhooks POST /webhooks DELETE /webhooks/:id | List, add and remove webhooks (this is how Zapier's instant triggers work) |
GET /events GET /samples/:event | The events, and an example message for each |
Examples:
# Add a lead
curl https://YOUR-SITE-HAUS/api/v1/leads -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"name":"Wendy Vee","email":"[email protected]","company":"Vee Bakery","amount":3500}'
# Make a task for a client, with a checklist
curl https://YOUR-SITE-HAUS/api/v1/tasks -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"title":"Design the home page","client":"Vee Bakery","due":"2026-12-01","checklist":["Hero","Footer"]}'
# Mark a task done
curl -X PATCH https://YOUR-SITE-HAUS/api/v1/tasks/TASK_ID -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"status":"done"}'An error looks like {"error": "A lead needs a name.", "code": "bad_request"} with a matching status: 401 for a missing or wrong key, 403 for a read-only key, 400 for something wrong in what you sent, 429 for too many requests.
Zapier#
You do not need a special app. Webhooks by Zapier works with everything above.
Start a Zap when something happens in Site Haus
- In Zapier, make a Zap and choose Webhooks by Zapier as the trigger, with the event Catch Hook. Copy the address it gives you.
- In Site Haus, Add a webhook, paste the address, choose the event (for example
proposal.accepted) and save. - Press Send a test in Site Haus, then Test trigger in Zapier. You will see the fields to use in the next steps.
Add a lead or a task from a Zap
- Choose Webhooks by Zapier as an action, with the event POST.
- For a lead, use your lead link as the address, set Payload Type to Json and map the fields (
name,email,company,message…). - For a task or anything else, use
https://<your Site Haus address>/api/v1/tasks, add the headerAuthorizationwithBearer <your key>, and send the JSON from the table above.
Make and n8n work the same way: use a Custom webhook (Make) or Webhook node (n8n) to receive, and an HTTP module or node to send.
Good to know#
- Webhooks and the API are part of the Pro and Power plans. If your plan stops including Agency, they stop until you upgrade.
- Messages are sent in the background, so a slow receiver never slows Site Haus down. They usually arrive within a second or two.
- A message is sent once for each change. Marking a lead as seen, or reading anything, sends nothing.
- Support tickets you send to Site Haus itself are not part of this. Only your own agency's events are sent.