ClutchedAPI reference · v1

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

HubSpot

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.

Pipedrive

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).

Salesforce

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