Sample written n8n review · internal demonstration

Validated webhook to a fictional contacts API

A focused review of a five-node training workflow. The happy path and input rejection are clear, but the workflow should not be exposed publicly until request authentication, duplicate protection, and transport-error handling are defined.

Demonstration only. This is not client work, a testimonial, or evidence of a client outcome. It reviews Argos-owned synthetic files and a local fictional API. No production system, account, credential, or personal data was accessed.
Review date21 Sep 2026
Export reviewed5 nodes
Evidence reviewed5 HTTP runs
Review decisionRevise before public use

Scope and intended behaviour

The workflow accepts a JSON contact, allows a non-empty name up to 100 raw characters and a status of new or active, then forwards the normalized object to a local fictional API. Invalid input returns HTTP 400 without calling that API.

Receive webhook
ID: receive · POST
Validate name and status
ID: validate · IF
POST local fictional API
ID: post · HTTP Request
Return API result
ID: response · Respond

False branch: Validate name and status → Reject invalid input (ID: invalid, HTTP 400).

Evidence checked

Workflow JSON · Recorded HTTP results · Original demonstration

The export, test harness, recorded HTTP results, execution summary, and pre-activation result were read together. The recorded run used Node 24.21.0 and n8n 2.38.7 on 11 Sep 2026.

Assertions passed5 / 5
API calls observed2
Objects stored1
n8n status5 “success”
Recorded caseHTTP / callsWhat it establishes
Spaced valid name201 / 1The outbound body contains the trimmed name and accepted status.
Blank name400 / 0The false branch blocks a whitespace-only name.
Unknown status400 / 0The allow-list rejects paid.
Missing name400 / 0A missing name does not reach the API.
API returns 503503 / 1neverError: true allows the response node to relay the upstream 503.

Interpretation guardrail: all five n8n executions are marked success because each workflow path completed. That execution status does not mean five successful contact creations.

Prioritized findings

P0 · before exposure

The webhook has no request authentication

receive → validate
Evidence

Receive webhook defines POST, path, and response mode only; its options object is empty. No preceding node validates a signature, token, timestamp, or caller identity.

Suggested correction

Require a secret header or, preferably, verify an HMAC over the raw request body plus a timestamp. Reject missing, invalid, or stale signatures before the HTTP Request node. Keep the secret in n8n credentials or environment-backed configuration.

P0 · data integrity

Repeated deliveries can create duplicate contacts

receive → post
Evidence

The outbound body contains only name and status. The export has no event ID lookup, idempotency key, durable deduplication step, or upsert operation. The test sends each valid payload once, so duplicates are untested.

Suggested correction

Require an immutable event ID. Create a durable processing record atomically, perform the side effect, then mark it succeeded. Do not mark the event permanently processed before the side effect succeeds. If the outcome is uncertain, keep a recoverable state and reconcile it before retrying. Alternatively, pass the event ID to an API that guarantees idempotent creation. Define retention and responses for in-progress, succeeded, and retryable events.

P1 · reliability

Transport failures have no explicit response path

post → response
Evidence

POST local fictional API uses a 5-second timeout and neverError: true, but has only its normal output connected. The evidence covers an HTTP 503 response from a reachable server. It does not cover connection refusal, DNS failure, TLS failure, invalid JSON, or timeout.

Suggested correction

Route the HTTP Request node's error output inside the same execution to a Respond to Webhook node that returns a stable 502 or 504 response. Use a separate error workflow only for logging or alerting; it is not a guaranteed response path for the original webhook request. Decide retry policy only after idempotency exists, because a timed-out write may have committed upstream.

P1 · interface

The upstream response is exposed without a boundary

response
Evidence

Return API result returns $json.body and $json.statusCode directly. Any future upstream error detail or schema change therefore becomes part of the public webhook response.

Suggested correction

Map known upstream outcomes to a small documented response schema, for example {ok, contactId} on success and a stable public error code on failure. Log internal details separately and redact credentials, headers, and payload fields.

P2 · maintainability

Validation and normalization disagree at the length boundary

validate ↔ post
Evidence

The IF node checks $json.body.name.length <= 100, while the HTTP node sends $json.body.name.trim(). A valid normalized name can be rejected solely because surrounding spaces make the raw value exceed 100 characters.

Suggested correction

Normalize once in a Set/Edit Fields or Code node, then validate and send that same normalized field. Split invalid-name and invalid-status outcomes if callers need actionable feedback.

Working as designed

The invalid-input branch prevents the side effect

validate → invalid

Three recorded invalid cases each returned HTTP 400 and made zero API calls. The explicit allow-list for status is easier to audit than a permissive string check. Preserve this fail-before-write ordering when authentication and normalization are added.

Recommended change order

  1. Define the public contract: authentication method, stable response schema, event ID, and accepted normalized fields.
  2. Protect the side effect: authenticate first; implement atomic processing/succeeded states and reconciliation of uncertain failures before adding retries.
  3. Make failures deterministic: separate received HTTP errors from transport failures; map both to controlled webhook responses.
  4. Expand the tests: duplicate event, invalid signature, stale timestamp, connection refusal, timeout after a possible write, non-JSON upstream response, and the 100-character normalized boundary.
  5. Add operations: use a separate error workflow for redacted logging or alerts, define retention, and add a deployment check that confirms the intended workflow is active.
Release recommendation: suitable as a local learning demonstration. For an internet-facing or production workflow, resolve both P0 findings and test the transport-error path before activation.

Limits of this review

Request a written review

Before sharing: check your export locally →

One redacted workflow of up to 25 nodes, its expected result and an input/output example. USD 35, within two business days after scope and start date agreement; one clarification round. Review only: no production access, credentials, video call or repair.

Request this review format → · Return to the portfolio