Preskočiť na obsah

REST hooks for Make, Zapier and n8n

A REST hook is a webhook that an application creates and removes itself through the API, so nobody has to paste URLs into the Dakoty app. Make, Zapier and n8n use this pattern: when you switch a scenario on they subscribe, and when you switch it off they unsubscribe. You can use the same endpoints from your own integration. Deliveries, signatures and retries work exactly as in Webhooks.

The key needs the scope webhooks:manage and, in addition, the read scope of every event it subscribes to, for example leads:read for lead.created. The event catalog with scopes is on the Webhooks page. A key that lacks one of the event scopes gets 403 FORBIDDEN and no hook is created.

Send the HTTPS target_url (up to 2048 characters, a public host) and the events either as an events array or, in the shape Zapier uses, as a single event string. name is optional; without it Dakoty names the hook after the key and the first event. The reply is 201 with the hook and its signing secret.

Terminal window
curl -sS -X POST https://api.dakoty.com/api/v1/public/webhooks \
-H "Authorization: Bearer $DAKOTY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target_url":"https://example.com/dakoty/webhook","events":["lead.created","lead.won"],"name":"CRM sync"}'

The secret (starting with whsec_) is returned only in this response and is never shown again, so save it next to the hook id. The response is sent with Cache-Control: no-store. Use the secret to verify deliveries as described in Verifying signatures.

{
"data": {
"id": "2c7f0f4e-8d1a-4b53-9d1e-5a6b7c8d9e0f",
"target_url": "https://example.com/dakoty/webhook",
"events": ["lead.created", "lead.won"],
"name": "CRM sync",
"created_at": "2026-10-11T08:30:12Z",
"secret": "whsec_..."
}
}

An unknown event returns 422 UNKNOWN_EVENT. An address that is not https://, points to a private or internal host, or does not resolve returns 422 WEBHOOK_URL_INVALID or WEBHOOK_URL_BLOCKED. When the organization has reached its maximum number of webhooks you get 409 LIMIT_EXCEEDED. Send an Idempotency-Key so a retried subscribe request does not register the hook twice; see Idempotency.

GET /webhooks lists the REST hooks of the calling key and GET /webhooks/{id} returns one; neither ever returns the secret. DELETE /webhooks/{id} unsubscribes and answers 204. A key sees only the hooks it created, so a hook of another key, a hand-made webhook from the app and an unknown id all answer 404. GET /webhooks/events lists the available event types and GET /webhooks/events/{type}/sample returns a sample envelope.

A small helper pair for an app that follows a user’s scenario on and off. It needs Node.js 18 or newer.

const BASE = "https://api.dakoty.com/api/v1/public";
const headers = {
Authorization: `Bearer ${process.env.DAKOTY_API_KEY}`,
"Content-Type": "application/json",
};
export async function subscribe(targetUrl, events) {
const res = await fetch(`${BASE}/webhooks`, {
method: "POST",
headers,
body: JSON.stringify({ target_url: targetUrl, events }),
});
const body = await res.json();
if (res.status !== 201) throw new Error(`${res.status} ${body.error.code}`);
return body.data; // keep data.id and data.secret
}
export async function unsubscribe(id) {
const res = await fetch(`${BASE}/webhooks/${id}`, { method: "DELETE", headers });
if (res.status !== 204 && res.status !== 404) throw new Error(`unsubscribe failed: ${res.status}`);
}

The same pair with requests. Treat 404 on delete as success, because the hook may already be gone.

import os
import requests
BASE = "https://api.dakoty.com/api/v1/public"
HEADERS = {"Authorization": f"Bearer {os.environ['DAKOTY_API_KEY']}"}
def subscribe(target_url, events):
r = requests.post(f"{BASE}/webhooks", headers=HEADERS, timeout=30,
json={"target_url": target_url, "events": events})
if r.status_code != 201:
raise RuntimeError(f"{r.status_code} {r.json()['error']['code']}")
return r.json()["data"] # keep data["id"] and data["secret"]
def unsubscribe(hook_id):
r = requests.delete(f"{BASE}/webhooks/{hook_id}", headers=HEADERS, timeout=30)
if r.status_code not in (204, 404):
raise RuntimeError(f"unsubscribe failed: {r.status_code}")

REST hooks are owned by the application, so Dakoty does not switch them off like hand-made webhooks. A REST hook is deleted when your endpoint answers 410 Gone, when it has had no successful delivery for 72 hours, and when the API key that created it is revoked. Your application should treat a missing hook as normal: when a scenario is switched on, call GET /webhooks/{id} for the stored id and subscribe again if it answers 404. Hand-made webhooks stay in the app and are described in the Slovak help article Webhooks.