Outbound webhooks
Send real-time event notifications to any external URL.
Note
Outbound webhooks are available on the Pro plan only.
Overview
Outbound webhooks let Cliento notify any external URL when a key event occurs in your account — an invoice is paid, a milestone is validated, or a quote is accepted. This makes it easy to plug Cliento into Zapier, Make, or your own backend without polling.
Supported events
| Event | Trigger |
|---|---|
invoice.paid | An invoice is marked as paid (Stripe, PayPal, or manual) |
milestone.validated | A client validates a milestone from the portal |
quote.accepted | A client accepts a quote from the portal |
project.status_changed | A project status changes |
Setting up a webhook
- Go to Profile → Outbound webhooks.
- Click Add.
- Enter the destination URL (must be
https://). - Select one or more events to subscribe to.
- Click Create webhook.
Warning
Copy your signing secret immediately after creation — it is shown only once and cannot be recovered. If you lose it, delete the webhook and create a new one.
Payload format
Every request is an HTTP POST with a JSON body:
{
"event": "invoice.paid",
"createdAt": "2026-06-12T10:00:00.000Z",
"data": {
"invoiceId": "clx...",
"invoiceNumber": "INV-0042",
"clientId": "clx...",
"paidVia": "stripe",
"paidAt": "2026-06-12T10:00:00.000Z"
}
}
The data object varies by event type but always includes the relevant entity IDs.
Verifying the signature
Every request includes an X-Cliento-Signature header:
X-Cliento-Signature: sha256=<hex-digest>
The digest is an HMAC-SHA256 of the raw request body signed with your webhook secret. Always verify it before processing:
import { createHmac } from "node:crypto";
function verifySignature(secret: string, rawBody: string, header: string): boolean {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
return expected === header;
}
import hmac, hashlib
def verify(secret: str, raw_body: bytes, header: str) -> bool:
digest = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(digest, header)
Tip
Always use a constant-time comparison (like hmac.compare_digest) to prevent timing attacks.
Retries
If your endpoint returns a non-2xx status or times out (10 s), Cliento retries the delivery automatically:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 15 minutes |
After 4 total attempts without success, the delivery is marked as failed and no further retries are made.
Tip
Make your endpoint idempotent — use the combination of event + data.invoiceId (or the relevant ID) as a deduplication key in case the same event is delivered more than once.
Managing webhooks
From Profile → Outbound webhooks you can:
- Toggle a webhook on/off without deleting it.
- Delete a webhook to permanently stop deliveries to that URL.
Up to 10 webhooks are allowed per account.
Zapier / Make integration
Point the webhook URL at a Zapier Catch Hook or a Make Custom webhook trigger. Use the event field as a filter to branch on different event types in your automation.
Compatible services
Outbound webhooks work with any service that accepts HTTP POST requests. Here are common integrations:
Notification & messaging
- Slack — via Slack Incoming Webhooks or a Zapier/Make step. Post to a channel on every payment or milestone.
- Discord — same pattern via Discord Incoming Webhooks. Useful if your team lives in Discord.
- Telegram — trigger a bot message via the Telegram Bot API.
Automation platforms
- Zapier — use a "Catch Hook" trigger, then connect to 6 000+ apps (Gmail, Notion, Airtable, HubSpot…).
- Make (ex-Integromat) — "Custom webhook" trigger, more flexible for multi-step data transformation.
- n8n — self-hosted alternative, "Webhook" node as trigger.
CRM & sales
- HubSpot — move a deal to "Won" when a quote is accepted, or log a payment activity.
- Pipedrive — update a deal stage or create an activity via the Pipedrive API.
- Notion — add a row to a database (via Zapier/Make or the Notion API directly).
Accounting & finance
- Google Sheets — append a row on each
invoice.paidevent for a lightweight payment ledger. - Airtable — same idea, with richer views and automations on top.
- Pennylane / Qonto — via a custom backend that calls their API after receiving the event.
Custom backends
- Any Express / FastAPI / Laravel endpoint. Verify the
X-Cliento-Signatureheader and process the event however you need. - Supabase Edge Functions or Vercel Functions — serverless handlers that react to events without maintaining a server.
Tip
Zapier and Make are the fastest way to get started — no code required. For more control over data transformation or if you need to fan out to multiple services at once, a lightweight serverless function is worth the extra step.