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 forwarding form data to another system.
Example: news article on the school website
Suppose the school has created an n8n workflow that publishes a news article on the school’s WordPress website. In AI-School, you then only enter 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:
- Turn the short text into a polished draft using an LLM node and a prompt that fits the school’s tone.
- Create 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 performs 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 of each other.
- If the workflow has no fields, the webhook is called immediately.
- If the workflow does have fields, a form opens first. The user fills in the fields and then starts the workflow with the button.
- The entered 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 continues in n8n. The window does not show a spinner and can be closed immediately.
- If enabled during registration, the workflow can send intermediate steps or the end result back to AI-School.
- If approval is enabled during 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 the Workflow assistants tab.
- In the card at the top, click New workflow and choose n8n workflow.
- Enter the workflow name and the n8n production URL.
- Set Header authentication with a header name and secret header value.
- Under Callbacks from n8n, only check the parts that are actually built into this n8n workflow: progress, approval, and/or workflow completion.
- Optionally add the fields that should be sent in the POST request.
- Save the workflow.
All three callback options are off by default. If you later add callbacks or an approval step in n8n, update the registration in AI-School as well. The dialog then knows whether it only needs to show a start confirmation or should keep waiting 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 dropdown; Multiple choices shows checkboxes. The selected 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.
- Give this node the exact name Start workflow. The examples below use this name.
- Set HTTP Method to POST.
- Under Authentication, choose Header Auth and select a Header Auth credential.
- In that credential, enter the same header name and secret value as in the workflow in AI-School.
- Set Respond or Response Mode to Immediately. The app will then receive an immediate successful start confirmation while n8n continues working.
- Copy the Production URL of the Webhook node to the n8n production URL field in AI-School. Do not use the test URL with
/webhook-test/. - Activate the workflow in n8n.
The data from AI-School is available 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 always read it directly from the Start workflow node.
Example of the JSON body
If you define fields with the names prompt, client_name, audiences, and date, n8n will receive this JSON body, for example. AI-School automatically adds the integration object.
{
"prompt": "Create a short summary of the request.",
"client_name": "Example organization",
"audiences": ["staff", "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-execution"
}
}
The callback token belongs to one execution. Do not store it in logs, fixed configuration, or other systems.
Optional: send progress and completion back
AI-School can only display what n8n reports back. Use these callbacks only if you enabled Report intermediate progress and/or Report the end of the workflow during registration.
Set up the HTTP Request node
-
Add an HTTP Request node and name it, for example, Report progress.
-
Set Method to POST.
-
Click Expression for URL.
-
Paste this exact expression:
{{ $('Start workflow').first().json.body.integration.callbackUrl }} -
Under Authentication, choose None. The temporary token will be added as a header in the next step.
-
Turn on Send Headers and add these two headers:
Name Value AuthorizationBearer {{ $('Start workflow').first().json.body.integration.callbackToken }}Content-Typeapplication/json -
Turn on 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_creation",
"label": "Create document"
},
"message": "The document is being created."
}
- Choose Execute step while testing the workflow through the app. The node should return status 200.
Copy this HTTP Request node for each status update. For each copy, adjust at least eventId, step.id, step.label, and message.
Set up 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" on success, type: "failed" for an error you handle yourself, and type: "rejected" when the user rejects the workflow.
For a successful execution, 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": "completion",
"label": "Workflow completed"
},
"message": "The workflow has been completed.",
"output": {
"result": "Short description or link to the result"
}
}
Within one execution, use a different eventId for every callback. Also always use a clear step.label: this is the text the user sees in the execution window.
Optional: ask for approval in the app
Set up the Wait node
- Add a Wait node at the point where approval is needed.
- Under Resume, choose On Webhook Call.
- Set HTTP Method to POST.
- Under Authentication, choose Header Auth.
- Select the same Header Auth credential as for the Start workflow node.
- Place a copy of the previously configured HTTP Request node before the Wait node and name it Request approval.
- Use the same dynamic URL and headers in this node. Only replace the JSON body with:
{
"tenant": "{{ $('Start workflow').first().json.body.integration.tenant }}",
"runId": "{{ $('Start workflow').first().json.body.integration.runId }}",
"eventId": "document-review",
"type": "approval_required",
"executionId": "{{ $execution.id }}",
"step": {
"id": "document_review",
"label": "Review document"
},
"approval": {
"question": "May the workflow continue?",
"context": "First review the generated document.",
"resumeUrl": "{{ $execution.resumeUrl }}",
"choices": [
{ "value": "approve", "label": "Approve" },
{ "value": "reject", "label": "Reject" }
]
}
}
Connect Request approval to the Wait node. The user will then see the buttons in AI-School. The secret resume URL is not given to the browser; the server securely sends the choice to the Wait node.
Process the choice after the Wait node
-
Add a Switch node after the Wait node.
-
Use this value to check:
{{ $json.body.decision }} -
Create, for example, a route for
approveand a route forreject. -
End each route with an appropriate
completed,rejected, orfailedcallback.
A choice value may only contain letters, numbers, _, and -. The label may contain normal readable text.
Set the production callback URL
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 in every callback node. Choose Expression in the URL field of the HTTP Request node and use:
{{ $('Start workflow').first().json.body.integration.callbackUrl }}
AI-School automatically provides the correct production URL on every start. Use the fixed URL above only to verify during testing that the expression points to AI-School.
The callables triggerCustomN8nWorkflow, triggerN8nWorkflow, and resumeN8nWorkflow are called by the app itself. You do not need to set these URLs in n8n.
Send unexpected errors back
A regular failed callback only works when the workflow reaches the relevant HTTP Request node. For unexpected node errors, also use a central n8n Error Workflow.
Create a central Error Workflow
-
Create a separate workflow in n8n named AI-School - send errors back.
-
Add an Error Trigger node.
-
Then add an HTTP Request node.
-
Set Method to POST.
-
Enter this fixed production URL in URL:
https://europe-west1-ai-school-pro.cloudfunctions.net/n8nWorkflowExecutionFailed -
Choose Authentication: None.
-
Turn on Send Headers and add:
Name Value n8n-handihow-namethe secret default value you receive from the platform administrator Content-Typeapplication/json -
Turn on 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.
- Open the settings of the regular workflow and select this new Error Workflow under Error Workflow.
Always send at least one progress callback immediately after Start workflow with executionId: "{{ $execution.id }}". This way, the app knows 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 only 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: check whether the header name and value are exactly the same in both systems.
- Missing data: check whether the field names in the application match the keys expected by n8n.
- No request in n8n: check whether the workflow starts with a webhook trigger and uses POST.
- The execution window keeps running: if you enabled Report the end of the workflow, check whether n8n sends a final
completed,failed, orrejectedcallback. If you do not expect callbacks, turn off all three options during registration. - No progress visible: check whether Report intermediate progress is enabled during registration, whether the
integrationobject is preserved, and whether each callback has a uniqueeventId. - Approval buttons do not work: check the Wait node,
resumeUrl, header authentication, and the allowed characters inchoices[].value.