Integrations
Declario can tell your other tools when something happens to a proposal: with a Slack message, a signed webhook request, or a deal update in HubSpot.
Available integrations
Integrations are set up in Settings → Integrations.
| Integration | Status | Plan | Connection |
|---|---|---|---|
| Slack | Available | From Pro | Slack incoming webhook |
| Webhooks | Available | From Pro | Signed HTTPS requests |
| HubSpot | Available | From Agency | OAuth |
| Available | Every plan | OAuth |
Google is used for signing in only.
Slack
Available from the Pro plan. Declario posts to one Slack channel per workspace through an incoming webhook. It is not a Slack app, and it cannot post to different channels for different events.
- In Slack, create an incoming webhook for the channel you want and copy its URL.
- In Settings → Integrations, under Slack, paste it into Incoming webhook URL. The address must use HTTPS.
- Under Events to post, choose which events post a message, then choose Save Slack settings.
Only admins can change the Slack integration. When a client opens a proposal for the first time, Slack gets a message whenever a webhook URL is saved, whichever events you chose.
Webhooks
Available from the Pro plan. A webhook endpoint receives an HTTPS POST request from Declario for each event you choose.
- In Settings → Integrations, under Webhooks, choose Add endpoint. Enter the Endpoint URL, an optional name and the Events to send, then choose Create endpoint.
- The URL must use HTTPS and point to a public address. Local and private network addresses are refused.
- Copy the Signing secret, which starts with
whsec_. It is shown once and cannot be displayed again. - An endpoint can be switched between Sending and Paused, or deleted. To change the secret, delete the endpoint and create it again.
The request
Each delivery is a POST with a JSON body and these headers:
X-Declario-Signature:t=<unix ms>,v1=<hex hmac>X-Declario-Event: the event name, for exampleproposal.acceptedContent-Type: application/json
{
"event": "proposal.accepted",
"timestamp": "2026-09-18T10:42:07.512Z",
"data": {
"proposalId": "8f14e45f-ceea-467a-9575-6c1a2f8d0b4e",
"proposalTitle": "Website redesign",
"clientName": "Northwind Studio",
"signerName": "Anna Nowak"
}
}timestamp is when the event happened, in ISO 8601. The keys in data depend on the event, as listed below. The body carries no workspace id and no delivery id.
Events
Declario sends these 7 events:
| Event | Sent when | Keys in data |
|---|---|---|
| proposal.sent | The proposal's status changes to Sent: when you send it, when an approver approves it, or when you set it by hand. | proposalId, proposalTitle, clientId |
| proposal.viewed | The client opens a sent proposal for the first time (data has clientName), or someone sets the status to Viewed by hand (data has clientId). | proposalId, proposalTitle, clientName | clientId |
| proposal.accepted | The client signs. | proposalId, proposalTitle, clientName, signerName |
| proposal.rejected | The client declines. reason is empty if none was given. | proposalId, proposalTitle, reason |
| client.created | A client is added, including through onboarding and CSV import. | clientId, clientName, contactName, email |
| approval.requested | A proposal is submitted for approval. | proposalId, proposalTitle |
| approval.approved | An admin or manager approves a proposal. approvedBy is their user id. | proposalId, approvedBy |
The endpoint form may offer other event names; only the events in this table are sent.
Verifying the signature
The signature is HMAC-SHA256 over <t>.<raw request body>, keyed with the endpoint's signing secret and written in lowercase hex. To check a request:
- Read the raw request body, before any JSON parsing.
- Split the signature header on commas and read
t, a Unix time in milliseconds, andv1. - Compute the HMAC of
t, a full stop and the raw body, and compare it withv1in constant time. - Reject requests whose
tis too far from your own clock, to limit replayed requests.
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.DECLARIO_WEBHOOK_SECRET; // whsec_…
const TOLERANCE_MS = 5 * 60 * 1000;
function verify(rawBody, header, secret) {
// Header: "t=<unix ms>,v1=<hex hmac>"
const parts = Object.fromEntries(
header.split(",").map((part) => {
const i = part.indexOf("=");
return [part.slice(0, i).trim(), part.slice(i + 1).trim()];
})
);
const t = Number(parts.t);
if (!Number.isFinite(t) || !/^[0-9a-f]{64}$/.test(parts.v1 ?? "")) return false;
// t is in milliseconds.
if (Math.abs(Date.now() - t) > TOLERANCE_MS) 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"));
}
// Sign-check the raw bytes, before any JSON parsing.
app.post("/declario", express.raw({ type: "application/json" }), (req, res) => {
const rawBody = req.body.toString("utf8");
const header = req.get("X-Declario-Signature") ?? "";
if (!verify(rawBody, header, SECRET)) return res.status(401).end();
const { event, data } = JSON.parse(rawBody);
console.log(req.get("X-Declario-Event"), event, data);
res.status(204).end();
});
app.listen(3000);Delivery
- Declario waits up to 10 seconds for your endpoint to answer. The response is not used.
- There are no retries and no delivery log: a request that fails is not sent again. Keep your endpoint fast and available.
- The order of deliveries is not guaranteed. Use
timestampto put events in order.
HubSpot
Available on the Agency plan. Declario syncs clients to HubSpot contacts and proposals to deals.
- An admin or manager opens Settings → Integrations and chooses Connect HubSpot.
- Sign in to HubSpot and allow access to contacts and deals.
- Back in Declario, a notice says whether the connection worked, and HubSpot shows as Connected with your HubSpot account (portal) ID.
What syncs to HubSpot
- A client is added: a contact is created, or updated if one with the same email exists, with the email, first and last name (split from the contact name) and company.
- A proposal is sent: a deal is created in the default pipeline, named after the proposal, with its total value as the amount, and associated with the client's contact. Each proposal gets one deal.
- The proposal is viewed, accepted or rejected: the deal moves to the matching stage.
- The client declines with a reason: the reason is added to the deal as a note.
| Declario status | HubSpot deal stage (internal name) |
|---|---|
| Sent | presentationscheduled |
| Viewed | decisionmakerboughtin |
| Accepted | closedwon |
| Rejected | closedlost |
Approval events are not sent to HubSpot. Sync errors are not shown in Declario.
Coming soon
These are planned but not available yet:
- Pipedrive
- Google Calendar
- Microsoft Teams
- REST API
There is no public API yet. Webhooks are the way to get proposal events into your own systems today; see API.