n8n workflows
AI-School can start n8n workflows via a production webhook. This is useful when you want to start an automated process outside AI-School, for example creating a task, updating a CRM record, starting a reporting flow, or pushing form data to another system.
Example: news article on the school website
Suppose the school has an n8n workflow that publishes a news article on the school's WordPress website. In AI-School you only fill in a short piece of text, for example a few sentences about a project week, sports day, or open day. With that text you start the workflow in n8n.
The n8n workflow can then, for example:
- Create a clean draft from the short text with an LLM node and a prompt that fits the school's tone.
- Generate a suitable illustration with a second LLM node, for example in the school's colors and in a recognizable illustrative style.
- Prepare or publish the text and image as a blog post on the WordPress website.
This is how AI-School and n8n work together: in AI-School the user selects the workflow and enters the required information. n8n then executes the automated steps and ensures the news article ends up neatly on the website.
What does this integration do?
You start an n8n workflow from the workflow overview. Only the production webhook, POST and Header Auth are required. Fields and callbacks from n8n are optional and can be configured independently.
- If the workflow has no fields, the webhook is triggered immediately.
- If the workflow has fields, a form opens first. The user fills in the fields and then starts the workflow with the button.
- The filled values are sent as JSON in a POST request to the n8n webhook.
- Without callbacks AI-School only confirms that the workflow has started and is proceeding in n8n. The window does not show a spinner and can be closed immediately.
- If enabled at registration, the workflow can send intermediate steps or end back to AI-School.
- If approval is enabled at registration, the user can make a choice directly in AI-School. n8n then continues from the waiting step.
Create an n8n workflow in AI-School
An administrator registers the workflow as follows:
- Go to Assistants.
- Open Workflows.
- Choose New n8n workflow.
- Enter the workflow name and the n8n production URL.
- Configure Header authentication with a header name and a secret header value.
- Under Callbacks from n8n, check only the items that were actually built into this n8n workflow: progress, approval and/or the end of the workflow.
- Optionally add the fields that need to be sent in the POST request.
- Save the workflow.
All three callback options are disabled by default. If you later add callbacks or an approval step in n8n, update the registration in AI-School as well. The dialog will then know whether to show only a start confirmation or wait for further signals.
Fields
- Fields are optional.
- Each field has one field name and a type.
- Supported field types are short text, long text, number, yes/no, date, single choice, and multiple choices.
- For Single choice and Multiple choices add the available options. Single choice is shown as a compact select; Multiple choices shows checkboxes. The chosen value or values are sent in the JSON body.
- Required fields must be filled in before the workflow can be started.
- The field name becomes the key in the JSON body sent to n8n.
Create a compatible workflow in n8n
- Create a new workflow in n8n.
- Add a Webhook node as the first node.
- Name this node exactly Start workflow. The examples below use this name.
- Set HTTP Method to POST.
- In Authentication choose Header Auth and select a Header Auth credential.
- In that credential, enter the same header name and secret value as in the AI-School workflow.
- Set Respond or Response Mode to Immediately. The app will receive a successful start confirmation immediately, while n8n continues to work.
- Copy the Production URL of the Webhook node to the field n8n production URL in AI-School. Do not use the test URL with
/webhook-test/. - Activate the workflow in n8n.
The data from AI-School is in n8n under body. The integration data is therefore under body.integration. Do not remove this data in an Edit Fields-, Set-, or Code-node. The examples below read it directly from the node Start workflow.
Example of the JSON body
If you define fields with the names prompt, customerName, targetGroups, and date, n8n would receive this JSON body, for example. AI-School automatically adds the integration object.
{
"prompt": "Create a short summary of the request.",
"customerName": "SampleOrganization",
"targetGroups": ["employees", "parents"],
"date": "2026-09-22",
"integration": {
"runId": "chat-document-id",
"tenant": "default",
"callbackUrl": "https://europe-west1-ai-school-pro.cloudfunctions.net/n8nWorkflowCallback",
"callbackToken": "temporary-token-for-this-run"
}
}
The callback token is tied to a single run. Do not store it in logs, fixed configuration, or other systems.
Optional: sending progress and completion back
AI-School can only display what n8n callbacks. Use these callbacks only if you enabled in registration the options for intermediate progress reports and/or the end of the workflow.
Configure HTTP Request node
-
Add an HTTP Request node and name it, for example, Report progress.
-
Set Method to POST.
-
Click URL and choose Expression.
-
Paste exactly this expression:
{{ $('Start workflow').first().json.body.integration.callbackUrl }} -
Choose Authentication as None. The temporary token is added as a header in the next step.
-
Enable Send Headers and add these two headers:
Name Value AuthorizationBearer {{ $('Start workflow').first().json.body.integration.callbackToken }}Content-Typeapplication/json -
Enable Send Body.
-
Choose Body Content Type: JSON and Specify Body: Using JSON.
-
Paste the JSON below into the JSON field:
{
"tenant": "{{ $('Start workflow').first().json.body.integration.tenant }}",
"runId": "{{ $('Start workflow').first().json.body.integration.runId }}",
"eventId": "document-creation-started",
"type": "progress",
"executionId": "{{ $execution.id }}",
"step": {
"id": "document_maken",
"label": "Document creation"
},
"message": "The document is being created."
}
- Set Execute step while testing the workflow in the app. The node should return status 200.
Copy this HTTP Request node for each status update. For each copy, modify at least eventId, step.id, step.label, and message.
Set the final callback
If Report the end of the workflow is enabled, a final callback must be present at the end of every possible route. Use type: "completed" for success, type: "failed" for a handled error, and type: "rejected" when the user rejects the workflow.
For a successful run, the body can look like this:
{
"tenant": "{{ $('Start workflow').first().json.body.integration.tenant }}",
"runId": "{{ $('Start workflow').first().json.body.integration.runId }}",
"eventId": "workflow-completed",
"type": "completed",
"executionId": "{{ $execution.id }}",
"step": {
"id": "wrapup",
"label": "Workflow completed"
},
"message": "The workflow is completed.",
"output": {
"result": "Short description or link to the result"
}
}
Use a different eventId for each callback within a run. Also always provide a clear step.label visible to the user in the execution window.
Optional: request approval in the app
Wait node setup
- Add a Wait node where approval is required.
- Choose Resume as On Webhook Call.
- Set HTTP Method to POST.
- Choose Authentication as Header Auth.
- Select the same Header Auth credential as the Start workflow node.
- Before the Wait node, add a copy of the previously configured HTTP Request node and name it Ask for approval.
- Use the same dynamic URL and headers. Replace only the JSON body with:
{
"tenant": "{{ $('Start workflow').first().json.body.integration.tenant }}",
"runId": "{{ $('Start workflow').first().json.body.integration.runId }}",
"eventId": "document-check",
"type": "approval_required",
"executionId": "{{ $execution.id }}",
"step": {
"id": "document_check",
"label": "Check document"
},
"approval": {
"question": "May the workflow continue?",
"context": "First verify the generated document.",
"resumeUrl": "{{ $execution.resumeUrl }}",
"choices": [
{ "value": "approve", "label": "Approve" },
{ "value": "reject", "label": "Reject" }
]
}
}
Connect Ask for approval to the Wait node. The user will then see the buttons in AI-School. The secret resume URL is not exposed to the browser; the server sends the choice securely to the Wait node.
Process the choice after the Wait node
-
After the Wait node, add a Switch node.
-
Use the value to check:
{{ $json.body.decision }} -
Create routes for
approveandreject, for example. -
End each route with a corresponding
completed,rejected, orfailedcallback.
A choice value may contain only letters, digits, _, and -. The label may contain regular readable text.
Production callback-url configuration
The production callback URL for AI-School is:
https://europe-west1-ai-school-pro.cloudfunctions.net/n8nWorkflowCallback
Do not paste this URL as fixed text into every callback node. In the URL field of the HTTP Request node, select Expression and use:
{{ $('Start workflow').first().json.body.integration.callbackUrl }}
AI-School thus automatically provides the correct production URL for every start. The fixed URL above is only for testing to verify that the expression points to AI-School.
The callable endpoints triggerCustomN8nWorkflow, triggerN8nWorkflow, and resumeN8nWorkflow are invoked by the app itself. You do not need to configure these URLs in n8n.
Unexpected errors back
A regular failed callback only works when the workflow reaches the corresponding HTTP Request node. For unexpected node errors, use a central n8n Error Workflow.
Create a Central Error Workflow
-
In n8n create a separate workflow named AI-School - send errors back.
-
Add an Error Trigger node.
-
Add an HTTP Request node.
-
Set Method to POST.
-
In URL enter this production URL fixed:
https://europe-west1-ai-school-pro.cloudfunctions.net/n8nWorkflowExecutionFailed -
Choose Authentication: None.
-
Enable Send Headers and add:
Name Value n8n-handihow-namethe secret default value you receive from the platform administrator Content-Typeapplication/json -
Enable Send Body, choose JSON and paste this body:
{
"executionId": "{{ $json.execution.id }}",
"workflowId": "{{ $json.workflow.id }}",
"workflowName": "{{ $json.workflow.name }}",
"lastNode": "{{ $json.execution.lastNodeExecuted }}",
"message": "{{ $json.execution.error.message }}"
}
- Activate the Error Workflow.
- In the settings of the normal workflow, select this new Error Workflow under Error Workflow.
Immediately after Start workflow, always send at least one progress callback with executionId: "{{ $execution.id }}". This lets the app know which execution an unexpected n8n error belongs to.
Important limitations
- Only webhook triggers are supported.
- Only production webhook URLs are supported.
- Test webhook URLs with
/webhook-test/are rejected. - Only POST is supported.
- Only generic header authentication is supported.
- The header value is treated as secret in the application.
- Callback tokens and resume-URLs are processed server-side and are not directly available to users.
- The tenant is determined server-side from the logged-in user, not from a value sent by the browser.
Troubleshooting
- 404 or webhook not registered: activate the workflow in n8n and use the production URL.
- Authentication error: ensure header name and value are exactly the same in both systems.
- Missing data: check that field names in the application match the keys expected by n8n.
- No request in n8n: verify that the workflow starts with a webhook trigger and uses POST.
- Execution window keeps looping: if you enabled Report end of the workflow, check whether n8n sends a final
completed,failed, orrejectedcallback. If you do not expect callbacks, disable all three options at registration. - No progress visible: verify that Report intermediate progress is enabled at registration, or that the
integrationobject remains, and that each callback has a uniqueeventId. - Approval buttons do not work: check the Wait node,
resumeUrl, header authentication, and allowed characters inchoices[].value.