Automating Client Intake in n8n
The best version of a client project is the one where, by the time you sit down to build, the logo, the copy, and the hosting login are already sitting there, typed and validated, waiting for you. n8n-nodes-briefgate is the community node that lets a self-hosted n8n instance make that happen on its own — no one has to remember to email the client, and no one has to remember to go check whether they replied.
This is the how-to companion to BriefGate for n8n, the node's reference page. That page documents every operation, field, and event; this one walks through four complete workflows built on top of them. If a field name or payload isn't explained here, it's there.
Before you start
You need a self-hosted n8n instance — the node isn't yet verified for direct install from n8n Cloud's panel, so today it runs on Docker, npm, or any other of n8n's self-hosted deployment options (see Installing on n8n Cloud for what changes once verification lands).
Install it under Settings → Community Nodes with n8n-nodes-briefgate, or npm install n8n-nodes-briefgate if you manage dependencies yourself. Then create a BriefGate API credential in n8n with an API key from your BriefGate dashboard — use a bg_test_… key while you build (it behaves normally but never emails or texts a real client), and switch to bg_live_… once a workflow is ready to go live.
One detail that trips people up: the BriefGate Trigger node needs a key with the admin scope, because registering a webhook subscribes to events across the whole account — intakes:read/intakes:write cover the BriefGate node's own operations but not that. Give the trigger its own admin-scoped credential, and a narrower key to everything else.
The self-hosted / EU angle. Running n8n yourself already keeps your workflow logic and credentials on infrastructure you control. BriefGate's hosted API pairs with that: per its GDPR documentation, all data is processed exclusively in the EU — hosting in Germany, file storage in Cloudflare R2 under the EU jurisdiction restriction. Worth knowing if residency is part of why you self-host n8n; it isn't the reason to pick BriefGate on its own.
Workflow 1 — A new deal creates the intake automatically
The trigger can be anything that fires when a project starts: a CRM webhook (deal marked won), an n8n Form Trigger, or a plain Webhook node behind whatever system captures new clients today.
| # | Node | Configuration |
|---|---|---|
| 1 | Webhook (or your CRM's trigger, e.g. HubSpot/Pipedrive) | Fires on the event that means "this client is real now" |
| 2 | Edit Fields (Set) | Map the incoming payload to projectName, clientEmail, clientName |
| 3 | BriefGate — Create Intake | See fields below |
On the BriefGate node, set:
- Project Name —
{{$json.projectName}} - Client Email / Client Name — mapped the same way
- Items — the fixed set your team always asks for at kickoff, e.g.
logo(Image, required),hero_copy(Long Text, required),wp_admin(Secret, required) — or switch Specify Items to Using JSON and paste an array - Additional Fields → Chase Schedule —
Default(orGentle/Aggressiveper client type) - Additional Fields → Idempotency Key —
{{$json.dealId}}
The idempotency key matters specifically because this workflow starts from a webhook: CRMs and form providers retry deliveries, and without one a retried webhook creates a second intake for the same client — reusing the same key returns the original intake instead.
Running the node emails the client their portal link immediately and returns the created intake, including its id, which every workflow below needs as intakeId.
Workflow 2 — A completed intake lands in your own storage
Where workflow 1 starts things, this one finishes them: nothing to check by hand, nothing to remember to go collect.
| # | Node | Configuration |
|---|---|---|
| 1 | BriefGate Trigger | Events: Intake Completed |
| 2 | BriefGate — Get Results | Intake ID: {{$json.intake_id}} |
| 3 | HTTP Request | GET each file item's signed url |
| 4 | Write Binary File (or an S3-compatible node) | Write into a project folder on your own storage |
Get Results returns typed values keyed by item: a file/image item comes back as { url, filename, mime, size, checksum_sha256 } with a 24-hour signed URL, and a text item comes back as the plain value. Since you defined the item keys yourself in workflow 1, reference them directly — {{$json.results.logo.url}}, {{$json.results.hero_copy}} — instead of looping over an unknown shape. Feed a file item's signed URL into an HTTP Request node set to return binary data, then write it with Write Binary File, or swap in an S3/MinIO node if that's where client assets live. Text items can go straight into a JSON file written alongside the downloads.
A secret item (an admin login, an API key) needs an API key with the secrets:read (or admin) scope to read, and its value comes back through results exactly once — store it the moment this workflow runs, since every call after that reports secret_unavailable: true instead.
Workflow 3 — A scheduled report of who still owes you something
No webhook is required for this one — it's a standing check rather than a reaction to an event, useful as a Monday-morning digest or a daily nudge to yourself.
| # | Node | Configuration |
|---|---|---|
| 1 | Schedule Trigger | e.g. weekdays at 08:00 |
| 2 | BriefGate — Get Many | Filters → Status: In Progress; Return All: on |
| 3 | Split In Batches (or Loop Over Items) | One iteration per intake |
| 4 | BriefGate — Get Status | Intake ID: {{$json.intake_id}} |
| 5 | Filter | Keep items where progress.outstanding > 0 |
| 6 | Slack / Send Email | Post or email the filtered list |
Get Many with Return All pages through every match instead of stopping at the default limit, so a busy account doesn't silently miss intakes past the first page. Get Status is the lightweight endpoint for this step — it returns item statuses, chase history, and a progress.outstanding count without pulling file content, which is what makes calling it once per intake on a schedule reasonable rather than expensive. Format the filtered results into whatever your team already reads: a Slack message, a digest email, or a row appended to a spreadsheet.
Workflow 4 — An overdue intake gets a deliberate nudge
intake.overdue fires once, the first time a periodic sweep notices an intake passed its due date with a required item still outstanding — independent of the automatic reminder schedule, and meant to tell you, not the client. That makes it a reasonable trigger for a reminder you decide to send, on top of whatever the automatic chase schedule is already doing.
| # | Node | Configuration |
|---|---|---|
| 1 | BriefGate Trigger | Events: Intake Overdue |
| 2 | BriefGate — Send Reminder | Intake ID: {{$json.intake_id}}; Channel: Email (or SMS) |
Send Reminder triggers a chase message outside the automatic schedule. Switching Channel to SMS is worth wiring in for this event specifically — a client who's ignored email reminders for weeks is a reasonable candidate for a different channel; it needs the sms feature and a positive SMS credit balance. Add a second branch posting to Slack so your team knows the intake needed a manual push, not just the client.
intake.stalled pairs with the same pattern: it fires once the reminder allowance is exhausted and the chase engine has cancelled the rest, handing the intake back to you. Add it alongside Intake Overdue in the trigger's Events field to escalate there too.
Reading the event payloads
Every event above carries intake_id, and every one except chase.bounced also carries project_name. None carries the client's own email address — deliberately, since a workflow's execution log has a wider audience than the intake itself. chase.bounced is the one exception, since its whole point is telling you which recipient address failed. For anything else about the client, call Get Status or Get Results rather than expecting the trigger payload to carry it. Full field lists for all six events the trigger supports are in webhooks.md.
Next steps
| Topic | Document |
|---|---|
| Full node and operation reference | n8n.md |
| Webhook event payloads and signature verification | webhooks.md |
| REST API this node wraps | rest-api.md |
| Item types and their constraints | item-types.md |
| How the automatic reminders work | chase.md |