Couplr has no published app in Zapier, Make or n8n. Each of those tools has generic webhook and HTTP steps, and those are what these recipes use. Field and button names in third-party tools change over time, so the recipes name the kind of step to use and the values to enter.
Placeholders used below:
| Placeholder | Replace with |
|---|---|
YOUR_API_KEY |
A Couplr API key. See Authentication and API keys. |
YOUR_WEBHOOK_TOKEN |
The token at the end of an inbound webhook URL. Copy the whole URL from the Integrations page. |
YOUR_SIGNING_SECRET |
The signing secret shown when a signed webhook or a destination was created. |
YOUR_UNIQUE_KEY |
A string unique to one operation, such as a UUID or the source record's id. |
Send new leads to Couplr from any automation tool#
Works with Zapier, Make, n8n and anything else that can send an HTTP POST. Use this when a lead arrives in another system, for example an ad lead form or a spreadsheet row, and should become a Couplr customer.
- In Couplr, create an inbound webhook and copy its URL. See Set up an endpoint.
- In the automation tool, add its step for sending a webhook or HTTP request after your trigger.
- Configure the step:
| Setting | Value |
|---|---|
| Method | POST |
| URL | https://couplrfsm.com/hooks/YOUR_WEBHOOK_TOKEN |
| Body type | JSON |
| Body | The lead's fields, for example name, email, phone. Any field names work. You map them in Couplr. |
Header X-Event-Id |
The lead's unique id in the source system, if the tool lets you add headers. |
- Run the step once so Couplr receives a sample, then finish the mapping in Couplr and turn the webhook on.
The step-type names to look for: "Webhooks by Zapier" with the POST action in Zapier, the "HTTP" module's request action in Make, and the "HTTP Request" node in n8n.
The equivalent request with curl:
curl -X POST "https://couplrfsm.com/hooks/YOUR_WEBHOOK_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Event-Id: YOUR_UNIQUE_KEY" \
-d '{"name": "Dana Whitfield", "email": "dana@example.com", "phone": "555-201-8890", "message": "No cooling upstairs"}'
Post a website form straight to Couplr#
A form on another website can post to an inbound webhook from the visitor's browser. Two rules apply, because inbound webhook URLs do not send cross-origin (CORS) headers:
- Send the form as a form post, not JSON. A JSON request from a browser on another site is blocked before it is sent.
- The page cannot read Couplr's response. Show your thank-you message once the request has been sent.
<form id="contact">
<input name="name" required>
<input name="email" type="email">
<input name="phone">
<button>Send</button>
</form>
<p id="contact-status" role="status"></p>
<script>
document.getElementById('contact').addEventListener('submit', async (event) => {
event.preventDefault();
const status = document.getElementById('contact-status');
try {
await fetch('https://couplrfsm.com/hooks/YOUR_WEBHOOK_TOKEN', {
method: 'POST',
mode: 'no-cors',
body: new URLSearchParams(new FormData(event.target)),
});
status.textContent = 'Thanks, we will be in touch.';
} catch (error) {
status.textContent = 'Something went wrong. Please call us.';
}
});
</script>
The webhook URL is visible to anyone who views the page, so anyone could post to it. Use a secret-URL webhook for this, expect some spam, and do not turn on the Speed to Lead text option for a public form. To keep the URL private, or to confirm that Couplr accepted the submission, post the form to your own server and forward it from there.
Send a signed request from your own server#
Use a webhook with "Require a signature" turned on. See Sender authentication.
const crypto = require('crypto');
async function sendLead(lead) {
const body = JSON.stringify(lead);
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto
.createHmac('sha256', process.env.COUPLR_SIGNING_SECRET)
.update(`${timestamp}.${body}`)
.digest('hex');
const response = await fetch(process.env.COUPLR_WEBHOOK_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Hvacpro-Timestamp': timestamp,
'X-Hvacpro-Signature': signature,
'X-Event-Id': String(lead.id),
},
body,
});
if (!response.ok) throw new Error(`Couplr answered ${response.status}`);
}
import hashlib, hmac, json, os, time
import requests
def send_lead(lead):
body = json.dumps(lead)
timestamp = str(int(time.time()))
signature = hmac.new(
os.environ["COUPLR_SIGNING_SECRET"].encode(),
f"{timestamp}.{body}".encode(),
hashlib.sha256,
).hexdigest()
response = requests.post(
os.environ["COUPLR_WEBHOOK_URL"],
data=body,
headers={
"Content-Type": "application/json",
"X-Hvacpro-Timestamp": timestamp,
"X-Hvacpro-Signature": signature,
"X-Event-Id": str(lead["id"]),
},
timeout=10,
)
response.raise_for_status()
Both send the same string they signed. Keep the secret and the URL in environment variables, not in source code.
Look up or create a customer from an automation tool#
Use the tool's HTTP request step with an API key when you need an answer back, for example the customer's Couplr id.
Find a customer by email:
| Setting | Value |
|---|---|
| Method | GET |
| URL | https://couplrfsm.com/api/v1/customers?email=dana@example.com |
Header Authorization |
Bearer YOUR_API_KEY |
Create one when none is found:
| Setting | Value |
|---|---|
| Method | POST |
| URL | https://couplrfsm.com/api/v1/customers |
Header Authorization |
Bearer YOUR_API_KEY |
Header Content-Type |
application/json |
Header Idempotency-Key |
YOUR_UNIQUE_KEY |
| Body | {"name": "Dana Whitfield", "email": "dana@example.com", "phone": "555-201-8890"} |
To test a connection, call GET https://couplrfsm.com/api/v1/me. It succeeds with any valid key.
Book a job for a customer#
Needs a key with jobs:write. Use the customer's id from the previous recipe and a job type name from GET /api/v1/job-types.
curl -X POST "https://couplrfsm.com/api/v1/jobs" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: YOUR_UNIQUE_KEY" \
-d '{"customer_id": 1842, "job_type": "Repair", "scheduled_date": "2026-12-02", "scheduled_start_time": "09:00", "notes": "No cooling upstairs. Gate code 4410."}'
Creating a job has the same effects as creating it in the app: it appears on the schedule and may be assigned to a technician automatically.
Copy paid invoices into another system#
- In Couplr, add an outbound webhook destination for the
invoice.paidevent, pointing at a "catch a webhook" trigger URL in your automation tool or at your own server. See Outbound webhooks. - Each delivery's
data.idis the invoice id. Fetch the full invoice with its line items:
curl "https://couplrfsm.com/api/v1/invoices/9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21" \
-H "Authorization: Bearer YOUR_API_KEY"
- Deliveries can repeat. Skip a delivery whose
idyou have already handled.
Export every customer#
Page through the list until the last page:
import os
import requests
def all_customers():
page = 1
while True:
response = requests.get(
"https://couplrfsm.com/api/v1/customers",
params={"page": page, "per_page": 100},
headers={"Authorization": f"Bearer {os.environ['COUPLR_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
body = response.json()
yield from body["data"]
if page >= body["meta"]["last_page"]:
return
page += 1
At 100 records a page and 120 requests a minute, this reads up to 12,000 customers a minute. On 429, wait for the number of seconds in Retry-After.