Clutched API
A JSON REST API for connecting Clutched to your CRM and other tools: read clients, proposals, contracts and invoices, create clients and draft proposals, and receive signed webhooks when deals move. Money is always in minor units (cents) with a currency code; dates are ISO 8601.
Base URL: https://clutched.io/api/v1
Authentication
Create a key in Settings → API and integrations. Send it as a bearer token on every request. Keys are shown once and stored hashed; revoke a key there at any time.
curl https://clutched.io/api/v1/me \ -H "Authorization: Bearer cl_live_…"
Endpoints
| GET | /me Check your key and see which workspace it belongs to. |
| GET | /clients List clients, newest first. Query: limit (max 100), offset, email |
| POST | /clients Create a client. Fires client.created. |
| GET | /clients/{id} Get one client. |
| PATCH | /clients/{id} Update any client fields. |
| GET | /packages List your packages (what you sell) with prices. |
| GET | /proposals List proposals with totals, line items and the client link. Query: limit, offset, status, client_id, updated_since (ISO date) |
| POST | /proposals Create a draft proposal from packages, for an existing or new client. Review and send it in the app. |
| GET | /proposals/{id} Get one proposal. |
| GET | /contracts List contracts and their signers, from proposals or standalone. Query: limit, offset, status |
| GET | /contracts/{id} Get one contract. |
| GET | /invoices List invoices with line items, tax and payment status. Query: limit, offset, status, client_id |
| GET | /invoices/{id} Get one invoice. |
Lists return { object: "list", data: [...], limit, offset }. Page with offset until fewer than limit come back.
Create a proposal
Creates a draft from your packages. Pass an existing client_id or a new client. Open it in the app to review and send.
curl -X POST https://clutched.io/api/v1/proposals \
-H "Authorization: Bearer cl_live_…" \
-H "Content-Type: application/json" \
-d '{
"title": "Website rebuild",
"client": { "company": "Acme Ltd", "contact_name": "Sam Lee", "email": "sam@acme.com" },
"package_ids": ["<package id>", "<package id>"],
"intro": "Thanks for the call today…"
}'Webhooks
Add an https endpoint in Settings → API and integrations and choose events. We POST JSON like this, with the same object shape the API returns:
{
"id": "evt_…",
"type": "proposal.signed",
"created_at": "2026-10-17T12:00:00.000Z",
"data": { "object": "proposal", "id": "…", "status": "signed", "totals": { … }, … }
}Events:
- proposal.sent
- proposal.viewed
- proposal.accepted
- proposal.declined
- proposal.signed
- contract.sent
- contract.signed
- invoice.created
- invoice.paid
- client.created
Respond with any 2xx within 5 seconds. Failed deliveries are logged in Settings, where you can retry them or send a test event.
Verifying signatures
Each request carries X-Clutched-Signature: t=<unix time>,v1=<hex>, where v1 is the HMAC-SHA256 of `${t}.${rawBody}` keyed with the endpoint’s secret. Reject requests older than five minutes.
import crypto from "node:crypto";
function verify(secret, header, rawBody) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(parts.v1, "hex"));
}CRM recipes
No code: in Zapier, use “Webhooks by Zapier → Catch Hook” as the trigger, paste its URL as a Clutched webhook endpoint, then add “HubSpot → Update Deal” (match by the client’s email or a deal property) to move the deal stage on proposal.accepted, proposal.signed and invoice.paid. With code: HubSpot workflows can call our API to create a draft proposal when a deal reaches a stage.
Same pattern with Zapier or Make: catch our webhook, find the person by email, update the deal (won on proposal.signed, add a note with the proposal link on proposal.sent).
Point a webhook at a Salesforce Flow (via an Apex REST endpoint or a middleware such as Zapier/Make) to update the Opportunity, and use GET /proposals?updated_since= for scheduled syncs.
The in-app assistant can walk you through any of these: open it and say which CRM you use.
Errors
Errors return a non-2xx status and { error: { code, message } }.
- 401 unauthorized: missing, invalid or revoked key
- 402 plan_required: the workspace’s plan doesn’t include API access
- 404 not_found: no such record in your workspace
- 422 invalid_request: the body didn’t validate; the message says which field
- 500 server_error: try again