Skip to content
Blog

n8n Trigger Nodes: Webhook vs Polling for Your API

If your API can send the events customers need to a workflow URL, start with a webhook trigger. If it cannot, polling may work, but only if the API lets you find every relevant change without repeatedly scanning an unbounded collection. If neither condition holds, ship useful actions first and describe the event gap honestly.

In n8n, a trigger starts the workflow and supplies its first data. An action runs after the workflow starts. The n8n node-type documentation distinguishes webhook triggers, which receive events, from polling triggers, which check for changes periodically. That is a design choice about the SaaS API as much as it is a choice about node code.

Start with the event your customer needs

“Booking created” sounds like one event. A customer may also need “booking rescheduled” and “booking cancelled.” Write down the exact events before choosing a transport. Then check whether your API exposes each event, the fields needed downstream, and a stable identifier for deduplication.

Question Webhook trigger Polling trigger
What must the service expose? Event delivery to a callback URL, either through self-service registration or a configured destination A list or change endpoint that reveals new and updated records reliably
When can the workflow start? After the service delivers the event After the next successful poll finds the change
What consumes API requests while nothing changes? Usually no repeated list request; registration or follow-up fetches may still use the API A request on each interval, multiplied by pages and connected accounts
What must you recover from? Failed delivery, duplicate delivery, disabled subscriptions, and missed events Failed polls, pagination changes, overlapping runs, and missed or duplicate records
What must the user configure? A reachable callback and any service-side subscription or secret API access, a polling interval, and sometimes a scope or lookback window

Neither column guarantees reliability. A fast webhook that drops failed deliveries can be worse than a well-designed poller. A poller that only reads page one can quietly miss records.

When a webhook trigger fits

Use a webhook when the provider can send the exact event, with enough information to identify it, to an n8n endpoint. Check how a customer registers the destination, which events they can select, how the service signs requests, what response it expects, whether it retries, and how long it retains failed deliveries. Those answers determine whether you can build a dependable trigger.

A dedicated node can handle subscription setup and cleanup if the API supports that lifecycle. If the customer can paste in a callback URL but the service has no subscription API, n8n's built-in Webhook node may already cover the workflow. It exposes separate test and production URLs. Document which URL the customer must register for the published workflow; a working test URL is not proof that production delivery is configured.

Treat repeated deliveries as normal input. Store or compare an event ID when the provider supplies one, and make downstream actions safe to repeat where possible. If the payload only contains a record ID, fetch the record before assuming it contains every field the workflow needs.

When polling fits

Polling is viable when a list or change endpoint provides a dependable way to find what changed since the previous successful run. A cursor, change token, or updated-since filter is especially useful. A response timestamp alone is not equivalent to a server-side filter: you still need a way to fetch all candidate records.

Before offering a “new item” trigger, answer these questions with a real account and test data:

  1. Can the endpoint return all relevant records, including the ones on later pages?
  2. Can you filter or sort by creation or update time, rather than by an unrelated business date?
  3. What stable ID lets you suppress records already emitted?
  4. What happens if a poll fails or the workflow is inactive for a day?
  5. How many requests will the chosen interval use across every connected account?

Save the checkpoint only after a successful scan. Use a lookback window where records can arrive late or pagination shifts, and deduplicate across that overlap. For updates, compare a stable record ID plus a documented version or update timestamp. Check how deletions and cancellations appear; a disappeared row is not automatically a documented cancellation event.

TidyCal shows why the filter matters

TidyCal's automation help says customers cannot configure webhooks. It points them to Zapier for booking events or to its API to fetch bookings. The same help page states a limit of 60 API requests per minute per account.

Its bookings API reference documents a list endpoint with pagination and filters for booking start date, end date, and cancellation status. The example response includes booking IDs and creation and update timestamps. The documented list parameters do not show a created-since or updated-since filter. That is a documentation observation, not a claim that an undocumented filter cannot exist.

Suppose someone books an appointment three months away today. A poll that asks only for appointments starting this week will miss the new booking, even though the booking was created today. Widening the appointment-date window increases the number of pages to inspect. Before promising a TidyCal “booking created” polling trigger, test the full retrieval window, page ordering, duplicates, cancellations, and recovery after downtime with actual account data. A rate limit alone does not tell you whether that scan is practical.

If your product needs booking events immediately, TidyCal's documented Zapier route may be the available option. If the customer only needs to fetch or create a booking during an existing workflow, an action can solve that task without pretending to detect events.

How each trigger type looks in node code

Both trigger types are programmatic nodes, and n8n's verification rules require triggers to be built that way. The difference is which method n8n calls.

A webhook trigger declares a webhook and the lifecycle methods n8n uses to register it with the service when the workflow is activated and remove it when the workflow is deactivated:

webhooks: [
	{ name: 'default', httpMethod: 'POST', responseMode: 'onReceived', path: 'webhook' },
],

webhookMethods = {
	default: {
		async checkExists(this: IHookFunctions): Promise<boolean> {
			const data = this.getWorkflowStaticData('node');
			return data.webhookId !== undefined;
		},
		async create(this: IHookFunctions): Promise<boolean> {
			const url = this.getNodeWebhookUrl('default');
			const response = await this.helpers.httpRequestWithAuthentication.call(this, 'serviceApi', {
				method: 'POST',
				url: 'https://api.example.com/webhooks',
				body: { url, events: ['booking.created'] },
			});
			this.getWorkflowStaticData('node').webhookId = response.id;
			return true;
		},
		async delete(this: IHookFunctions): Promise<boolean> {
			const data = this.getWorkflowStaticData('node');
			await this.helpers.httpRequestWithAuthentication.call(this, 'serviceApi', {
				method: 'DELETE',
				url: `https://api.example.com/webhooks/${data.webhookId}`,
			});
			delete data.webhookId;
			return true;
		},
	},
};

async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
	const body = this.getBodyData();
	// Verify the provider's signature header here before trusting the body.
	return { workflowData: [this.helpers.returnJsonArray(body)] };
}

If the service has no subscription API, skip webhookMethods and tell users to paste the URL into the service's settings, or point them to n8n's built-in Webhook node.

A polling trigger sets polling: true in its description, and n8n adds the poll interval setting for the user. n8n calls poll() on that schedule. Return null when nothing changed, and keep the checkpoint in node static data so it survives between runs:

async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
	const state = this.getWorkflowStaticData('node');
	const since = (state.lastUpdatedAt as string) ?? new Date(Date.now() - 60_000).toISOString();

	const records = await fetchAllPagesUpdatedSince(this, since); // follow every page

	if (this.getMode() === 'manual') {
		return records.length ? [this.helpers.returnJsonArray(records.slice(0, 1))] : null;
	}

	if (!records.length) return null;
	state.lastUpdatedAt = records[records.length - 1].updated_at;
	return [this.helpers.returnJsonArray(records)];
}

The checkpoint is written only after the fetch succeeds, which matches the "save after a successful scan" rule above. The pagination guide shows how to write the page loop that fetchAllPagesUpdatedSince stands for. Store webhook signing secrets in the node's credential rather than a parameter; the credentials guide covers that.

Quick decision table

Your API offers Build
Webhook subscription API with event types and signatures Webhook trigger with webhookMethods
Webhooks configured by hand in the service's settings Webhook trigger without lifecycle methods, or document the built-in Webhook node
A cursor, change feed, or updated_since filter Polling trigger
Only date filters unrelated to creation time Actions first; poll only after testing the full scan
No events and no reliable change filter Action node only

When an action node is enough

An action node answers requests from a workflow that already has a trigger: “create a booking after a form submission” or “look up a customer when a ticket opens.” It does not need to monitor the SaaS for changes. Start with the jobs customers actually ask for, then add an event trigger once the service can support its delivery contract.

For the broader node-building process, see the custom node creation guide. n8n's building-style guidance says custom trigger nodes require programmatic code; a package can still contain a declarative action node alongside a programmatic trigger. The declarative node guide covers the action side. OpenAPI operations can describe requests and responses, but they do not by themselves prove that an API can push events or support complete incremental polling.

If you are deciding whether to maintain an integration at all, use the SaaS n8n integration decision guide to weigh customer demand and ongoing ownership. For a trigger decision, take one event your customers need and test its delivery or retrieval path end to end before naming it in the node UI.

Frequently asked questions

Yes. n8n allows a declarative action node and a programmatic trigger node in one package. Each still needs its own behavior and tests.

The service must be able to reach the callback URL that n8n uses for the workflow. Check the service's network and security requirements before registering it.

No. Request volume depends on the number of connected accounts, pages per scan, other API calls, and the provider's limit. Choose an interval only after estimating and testing that load.

Usually not for a “booking created” event. Someone can create a booking today for an appointment months away. A creation or update cursor is a better fit when the API supports one.

The workflow may run twice unless the integration deduplicates the delivery or downstream steps are safe to repeat. Use a stable event or record identifier when the provider supplies one.

An action node runs within a workflow that has already started. Use a trigger or another workflow entry point to detect the change.

Only partly. OpenAPI 3.1 can describe webhooks, and list endpoints show whether a cursor or updated-since filter exists. Neither proves delivery, retries or complete incremental results, so test one real event end to end before naming a trigger in the node.

Ready to launch your n8n, Make, Zapier or Activepieces integration?

Give your customers another way to use your product.

Get started