Skip to content
Dashboard

n8n Integration

Automate content workflows with n8n's HTTP Request node. Exact field-by-field configuration for self-hosted and cloud instances.

Overview

n8n is a self-hosted (and cloud-hosted) workflow automation tool. Use the HTTP Request node to connect to Brainpercent's API. This guide covers every field in n8n's node configuration, credential setup, and workflow patterns.

Prerequisites

  • An n8n instance, self-hosted (npx n8n or Docker) or n8n.cloud
  • A Brainpercent API key (bp_ prefix) with read + write permissions, created at brainpercent.app/chat/developers. Keys cannot be created over the API.
  • A project id. Every generation call needs one. Fetch it with GET https://www.brainpercent.app/api/v1/projects or add that call as the first HTTP Request node. Projects are created in the app, not over the API.
  • n8n version 0.220+ (for latest HTTP Request node features)

Use the www host in every URL. The apex https://brainpercent.app answers with a 307 redirect and the POST body is dropped when it is followed, so the request arrives empty.

Step 1: Create Header Auth Credential

Before configuring the HTTP Request node, create a reusable credential. Go to Settings → Credentials → Add Credential and search for "Header Auth".

Credential FieldValue
Credential TypeHeader Auth
Name (Label)Brainpercent API
Header Auth: NameAuthorization
Header Auth: ValueBearer bp_your_api_key_here

Self-hosted alternative: You can use environment variables instead. Set BRAINPERCENT_API_KEY=bp_your_key in your n8n environment and reference it as {{ $env.BRAINPERCENT_API_KEY }} in the credential value.

Step 2: HTTP Request Node Configuration

Add an HTTP Request node to your workflow. Here is every field in the node settings panel:

n8n FieldValue
MethodPOST
URLhttps://www.brainpercent.app/api/v1/articles/generate
AuthenticationGeneric Credential Type
Generic Auth TypeHeader Auth
Credential for Header AuthSelect your "Brainpercent API" credential
Send HeadersON
Header ParametersAdd one header (see below)
Send BodyON
Body Content TypeJSON
Specify BodyUsing JSON
JSONYour request body (see below)
Options → Response FormatJSON (auto-detected, default)
Options → Always Output DataON (for error handling)
Options → Timeout30000 ms (30 seconds)

Header Parameters

Under "Header Parameters", add one header (the Authorization is handled by the credential):

NameValue
Content-Typeapplication/json

JSON Body

In the "JSON" field, paste your request body. Use n8n expressions with {{ }} to reference data from previous nodes:

{
  "topic": "Your Article Topic",
  "project_id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "keywords": ["keyword1", "keyword2"],
  "tone": "professional",
  "word_count": 1200
}

topic (3 to 500 characters) and project_id are required. Optional: keywords (up to 20), tone (professional, casual, academic, conversational), word_count (300 to 5000, default 800). There is no length and no language field: the language comes from the project. Costs 1.5 credits and returns 202 with a poll_url.

Workflow: Content Automation Pipeline

Cron → Generate Article → Wait → Check Status → IF Ready → Generate Social

Node 1: Schedule Trigger

FieldValue
NodeSchedule Trigger (previously "Cron")
Rule: Trigger IntervalDays
Rule: Hour9
Rule: Minute0

Node 2: HTTP Request (Generate Article)

Configured as shown in the HTTP Request Node Configuration above. POST to /api/v1/articles/generate.

{
  "topic": "Daily SEO insights for {{ $now.format('MMMM D, YYYY') }}",
  "project_id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "keywords": ["SEO", "daily insights"],
  "tone": "professional",
  "word_count": 900
}

Node 3: Wait

FieldValue
NodeWait
ResumeAfter Time Interval
Wait Amount2
Wait UnitMinutes

Article generation takes roughly 10 to 15 minutes, so this Wait is one turn of a loop, not a single sleep. Node 5 sends the workflow back here until the article reports complete. The Wait node pauses the entire workflow execution, and on self-hosted n8n the workflow stays in memory during the wait, so for production use n8n's queue mode (EXECUTIONS_MODE=queue) so waits do not block other workflows.

Node 4: HTTP Request (Check Status)

FieldValue
MethodGET
URLhttps://www.brainpercent.app/api/v1/articles/{{ $json.data.article_id }}/status
AuthenticationSame "Brainpercent API" Header Auth credential
Send BodyOFF (GET request)

Node 5: IF (Check Generation Status)

IF FieldValue
ConditionBoolean
Value 1{{ $json.data.is_complete }}
Operationis true

Test is_complete, not a status string. Article statuses are draft, queued, cms, needs_editing, failed, and archived: a finished article is cms, and neither published nor generating exists, so a comparison against either will loop forever. Add a second IF on {{ $json.data.status }} equals failed so a failed job breaks out of the loop.

OutputConnect To
True (article finished)→ Node 6: Generate Social Content
False (still working)→ Loop back to Node 3: Wait (creates a polling loop)

Node 6: HTTP Request (Generate Social)

FieldValue
MethodPOST
URLhttps://www.brainpercent.app/api/v1/social/generate
{
  "source_url": "https://www.brainpercent.app/articles/{{ $json.data.slug }}",
  "platforms": ["twitter", "linkedin"],
  "project_id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "angle": "Practical takeaways for busy marketers"
}

source_url and platforms (1 to 10) are required. Optional: source_type (website, blog, youtube), angle, title, project_id. There is no tone or language field: use angle to steer it. Valid platforms: instagram, facebook, linkedin, twitter, threads, tiktok, bluesky, pinterest, google_business, telegram. Costs 0.6 credits per platform and returns a single data.content_id.

Node 7: Publish or Schedule

Loop a Wait plus an HTTP Request on https://www.brainpercent.app/api/v1/social/content/{{ $json.data.content_id }} until data.status is ready or completed, then POST to /api/v1/social/publish. Publishing while the content is still generating returns 412, and so does publishing with no connected social accounts.

{
  "content_id": "{{ $json.data.content_id }}"
}

Only content_id is required. Omit platforms to publish every variant. Without scheduled_at you get a 202 and it publishes immediately; with it, a 200 and it is scheduled.

Workflow: Conditional Generation

Check credits before generating to avoid failures and wasted workflow runs.

1

Schedule Trigger or Webhook

2

HTTP Request: GET https://www.brainpercent.app/api/v1/user/credits

3

IF Node: Check credits

IF FieldValue
ConditionNumber
Value 1{{ $json.data.available_credits }}
OperationLarger or Equal
Value 21 (cost of one article)

For a social job the threshold is the number of platforms times 0.6, since that is what one platform costs. 1 credit equals $1.00 of a single balance that covers every content type.

4a

True: HTTP Request → POST /articles/generate

4b

False: Send Notification (Slack/Email node) saying "Low credits!"

Workflow: Webhook Listener

Expose an n8n webhook endpoint that triggers article generation when called externally. This webhook is hosted by your n8n instance and is called by your own systems. Brainpercent does not send webhooks: there is no callback registration and no signed payload, so completion still has to be polled.

Webhook Node Configuration

FieldValue
NodeWebhook
HTTP MethodPOST
Pathgenerate-article
RespondUsing 'Respond to Webhook' Node

The full webhook URL will be: https://your-n8n-instance.com/webhook/generate-article

n8n Expressions Reference

n8n uses JavaScript expressions inside {{ }} to reference data from previous nodes:

Datan8n ExpressionExample
Article ID{{ $json.data.article_id }}f8c9d0e1-2345-...
Article status{{ $json.data.status }}cms
Article finished?{{ $json.data.is_complete }}true
Article slug{{ $json.data.slug }}content-marketing-trends-2026
Credit balance{{ $json.data.available_credits }}42
Social content id (one per job){{ $json.data.content_id }}b1c2d3e4-f5a6-...
LinkedIn caption{{ $json.data.platforms.linkedin }}Caption text...
LinkedIn image (permanent){{ $json.data.image_urls.linkedin }}https://...supabase.co/...
Error code (sits beside data, not inside it){{ $json.error.code }}INSUFFICIENT_CREDITS
Current date{{ $now.format('YYYY-MM-DD') }}2026-02-02
Webhook body field{{ $json.body.topic }}AI Marketing
Env variable{{ $env.BRAINPERCENT_API_KEY }}bp_abc123...

Error Handling & Workflow Settings

Error Trigger Workflow

Create a separate "Error Workflow" in n8n that catches failures from all workflows:

SettingValue
Error Workflow trigger nodeError Trigger
Connected toSlack/Email node for alerts

Then in your main workflow's settings (gear icon), set Error Workflow to point to this error handler.

Retry on Failure

Workflow SettingValue
Retry On FailON
Max Tries3
Wait Between Tries60000 ms (1 minute)

Tips & Best Practices

  • Use Header Auth credentials. Never hardcode API keys in HTTP Request nodes.
  • Enable "Always Output Data" on HTTP Request nodes so subsequent nodes receive data even on error
  • Use the Wait node (not Code node with sleep()) for workflow pauses
  • Set up an Error Trigger workflow to catch failures across all workflows
  • Use "Split In Batches" node when processing large arrays of articles
  • Social generation returns one row for every platform, so there is no items array. Read captions from data.platforms.<platform> and images from data.image_urls.
  • Store the project_id alongside the API key. It is required on every generate call.
  • For self-hosted: use environment variables for secrets, e.g. {{ $env.BRAINPERCENT_API_KEY }}
  • For self-hosted: enable queue mode in production for concurrent workflow execution
  • Enable "Retry On Fail" on HTTP Request nodes with a 60-second interval for rate limit resilience