Whatsapp Trigger Node produces 429 Response on Publish

Describe the problem/error/question

When I try publish workflows with Whatsapp Trigger Node it fails mutliple times with Error: Workflow could not be published:

(#2200) Callback verification failed with the following errors: curl_errno = 56; curl_error = CONNECT tunnel failed, response 429; HTTP Status Code = 429; HTTP Message = Too Many Requests

Eventually it does succeed. This error also affects my Whatsapp Flows, as data is only exchanged intermittently, because I guess most data is blocked by throttling.

Here is the workflow:

{
“nodes”: [
{
“parameters”: {
“updates”: [
“messages”
],
“options”: {
“messageStatusUpdates”: [
“all”
]
}
},
“type”: “n8n-nodes-base.whatsAppTrigger”,
“typeVersion”: 1,
“position”: [
96,
-592
],
“id”: “9ab9fd24-6c16-4ebf-9a6c-2e73d9a87742”,
“name”: “WhatsApp Trigger”,
“webhookId”: “d68e0638-f8da-4f78-9c3a-8de498f4fe31”,
“credentials”: {
“whatsAppTriggerApi”: {
“id”: “qWVxbPXJkVeC5wGY”,
“name”: “WhatsApp OAuth - Whapp”
}
},
“onError”: “continueRegularOutput”
},
{
“parameters”: {
“httpMethod”: “POST”,
“path”: “donation-flow”,
“responseMode”: “responseNode”,
“options”: {}
},
“type”: “n8n-nodes-base.webhook”,
“typeVersion”: 2.1,
“position”: [
112,
-336
],
“id”: “9bf817cf-2c8d-411b-962c-b554ba94c297”,
“name”: “Webhook”,
“webhookId”: “ec10d621-b166-43a7-9e2e-d95b83ab0871”
},
{
“parameters”: {
“respondWith”: “text”,
“responseBody”: “={{ $json.data }}”,
“options”: {}
},
“type”: “n8n-nodes-base.respondToWebhook”,
“typeVersion”: 1.4,
“position”: [
944,
-336
],
“id”: “3500cf5c-0f91-42f2-b64e-c815b913b681”,
“name”: “Respond to Webhook”
},
{
“parameters”: {
“method”: “POST”,
“url”: “https://aitomate.co.za/aitomate_demos_whatsapp/whatsapp-flow-decrypt.php”,
“sendHeaders”: true,
“headerParameters”: {
“parameters”: [
{
“name”: “Content-Type”,
“value”: “application/json”
}
]
},
“sendBody”: true,
“bodyParameters”: {
“parameters”: [
{
“name”: “encrypted_flow_data”,
“value”: “={{ $json.body.encrypted_flow_data }}”
},
{
“name”: “encrypted_aes_key”,
“value”: “={{ $json.body.encrypted_aes_key }}”
},
{
“name”: “initial_vector”,
“value”: “={{ $json.body.initial_vector }}”
},
{
“name”: “screen_name”,
“value”: “DETAILS”
}
]
},
“options”: {}
},
“type”: “n8n-nodes-base.httpRequest”,
“typeVersion”: 4.3,
“position”: [
304,
-336
],
“id”: “8ef4945f-dd8f-4c5e-8cd2-2b3825d1e441”,
“name”: “HTTP Request9”
},
{
“parameters”: {
“content”: “Decrypt incoming data from Whatsapp Flow”,
“height”: 80,
“width”: 176
},
“type”: “n8n-nodes-base.stickyNote”,
“typeVersion”: 1,
“position”: [
256,
-432
],
“id”: “406db72f-4fe6-40b5-9c1b-58b85fbf6810”,
“name”: “Sticky Note40”
},
{
“parameters”: {
“content”: “Encrypt response to be sent to Whatsapp Flow”,
“height”: 80,
“width”: 176
},
“type”: “n8n-nodes-base.stickyNote”,
“typeVersion”: 1,
“position”: [
720,
-432
],
“id”: “88d21505-ebaf-4b62-8cd3-2eb6936b85f3”,
“name”: “Sticky Note41”
},
{
“parameters”: {
“method”: “POST”,
“url”: “https://aitomate.co.za/aitomate_demos_whatsapp/whatsapp-flow-encrypt.php”,
“sendHeaders”: true,
“headerParameters”: {
“parameters”: [
{
“name”: “Content-Type”,
“value”: “application/json”
}
]
},
“sendBody”: true,
“bodyParameters”: {
“parameters”: [
{
“name”: “encrypted_flow_data”,
“value”: “={{ $(‘Webhook’).item.json.body.encrypted_flow_data }}”
},
{
“name”: “encrypted_aes_key”,
“value”: “={{ $(‘Webhook’).item.json.body.encrypted_aes_key }}”
},
{
“name”: “initial_vector”,
“value”: “={{ $(‘Webhook’).item.json.body.initial_vector }}”
},
{
“name”: “screen_name”,
“value”: “={{ $json.next_screen_name }}”
},
{
“name”: “amount”,
“value”: “={{ $json.decrypted_payload.data.amount }}”
},
{
“name”: “payment_interval”,
“value”: “={{ $json.decrypted_payload.data.payment_interval }}”
},
{
“name”: “payment_method”,
“value”: “={{ $json.decrypted_payload.data.payment_method }}”
}
]
},
“options”: {}
},
“type”: “n8n-nodes-base.httpRequest”,
“typeVersion”: 4.3,
“position”: [
768,
-336
],
“id”: “c8d5df79-8aec-426a-98d4-4ff5002dd8a2”,
“name”: “HTTP Request11”
},
{
“parameters”: {
“jsCode”: “// Get current screen\nconst currentScreen = $json.decrypted_payload?.screen;\n\n// Default value (optional safety)\nlet next_screen_name = null;\n\n// Screen routing logic\nif (currentScreen === ‘DONATION’) {\n next_screen_name = ‘DETAILS’;\n} else if (currentScreen === ‘DETAILS’) {\n next_screen_name = ‘SUMMARY’;\n} else if (currentScreen === ‘SUMMARY’) {\n next_screen_name = ‘COMPLETE’;\n}\n\n// Return updated JSON\nreturn [\n {\n json: {\n …$json,\n next_screen_name\n }\n }\n];\n”
},
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
608,
-336
],
“id”: “a84f0b01-704e-4e0a-8761-faf4e090b941”,
“name”: “Code in JavaScript3”
},
{
“parameters”: {
“conditions”: {
“options”: {
“caseSensitive”: true,
“leftValue”: “”,
“typeValidation”: “strict”,
“version”: 3
},
“conditions”: [
{
“id”: “ce81d51a-f892-46e5-8da7-305c3e0c8b78”,
“leftValue”: “={{ $json.decrypted_payload.action }}”,
“rightValue”: “ping”,
“operator”: {
“type”: “string”,
“operation”: “equals”,
“name”: “filter.operator.equals”
}
}
],
“combinator”: “and”
},
“options”: {}
},
“type”: “n8n-nodes-base.if”,
“typeVersion”: 2.3,
“position”: [
448,
-336
],
“id”: “aa6be20d-199f-4999-8005-a8194f394638”,
“name”: “If31”
},
{
“parameters”: {
“method”: “POST”,
“url”: “https://aitomate.co.za/aitomate_demos_whatsapp/whatsapp-flow-encrypt-health-check.php”,
“sendHeaders”: true,
“headerParameters”: {
“parameters”: [
{
“name”: “Content-Type”,
“value”: “application/json”
}
]
},
“sendBody”: true,
“bodyParameters”: {
“parameters”: [
{
“name”: “decrypted_aes_key”,
“value”: “={{ $json.aes_key_base64 }}”
},
{
“name”: “initial_vector”,
“value”: “={{ $json.initial_vector_base64 }}”
}
]
},
“options”: {}
},
“type”: “n8n-nodes-base.httpRequest”,
“typeVersion”: 4.3,
“position”: [
688,
-560
],
“id”: “aa3a8f3a-bbce-4c66-a4ac-88559c903f84”,
“name”: “HTTP Request34”
},
{
“parameters”: {
“content”: “Used for Running Health Check on End Point”,
“height”: 80
},
“type”: “n8n-nodes-base.stickyNote”,
“typeVersion”: 1,
“position”: [
592,
-640
],
“id”: “31864aef-226b-4e64-adfc-a0510b1432f5”,
“name”: “Sticky Note99”
}
],
“connections”: {
“WhatsApp Trigger”: {
“main”: [

]
},
“Webhook”: {
“main”: [
[
{
“node”: “HTTP Request9”,
“type”: “main”,
“index”: 0
}
]
]
},
“HTTP Request9”: {
“main”: [
[
{
“node”: “If31”,
“type”: “main”,
“index”: 0
}
]
]
},
“HTTP Request11”: {
“main”: [
[
{
“node”: “Respond to Webhook”,
“type”: “main”,
“index”: 0
}
]
]
},
“Code in JavaScript3”: {
“main”: [
[
{
“node”: “HTTP Request11”,
“type”: “main”,
“index”: 0
}
]
]
},
“If31”: {
“main”: [
[
{
“node”: “HTTP Request34”,
“type”: “main”,
“index”: 0
}
],
[
{
“node”: “Code in JavaScript3”,
“type”: “main”,
“index”: 0
}
]
]
},
“HTTP Request34”: {
“main”: [
[
{
“node”: “Respond to Webhook”,
“type”: “main”,
“index”: 0
}
]
]
}
},
“pinData”: {},
“meta”: {
“templateCredsSetupCompleted”: true,
“instanceId”: “245fe68e11b4cc3302473c67f456d11e2883ba1a19da36931944225207f4cf8f”
}
}

Information on my n8n setup

  • n8n version: 2.6.4
  • Database (default: SQLite): SQLite
  • n8n EXECUTIONS_PROCESS setting (default: own, main): main
  • Running n8n via (Docker, npm, n8n cloud, desktop app): docker
  • Operating system: Alpine Linux v3.22

When calling Whatsapp you must have provided a callback URL.
This error seems to be the requested callback url (from Whatsapp to the url) got rejected due to throttling.

The only way is to raise the rate limit from whatsapp services on requested callback URL server

Thanks for this but it is unfortunately not Whatsapp throttling. As I have copied the workflow to n8n cloud and the problem goes away. It is some type of bug on n8n self hosted. Would appreciate any further assistance:

  • n8n version: 2.6.4
  • Database (default: SQLite): SQLite
  • n8n EXECUTIONS_PROCESS setting (default: own, main): main
  • Running n8n via (Docker, npm, n8n cloud, desktop app): docker
  • Operating system: Alpine Linux v3.22

Hello @Gunter_Berger ,

The error CONNECT tunnel failed confirms your instance is still trying to use the n8n development tunnel, which has strict rate limits and blocks production traffic.

Try this:
• Open your Docker Compose configuration or .env file.
• Remove the N8N_TUNNEL_SUBDOMAIN variable (and the --tunnel flag if present in the command).
• Set WEBHOOK_URL to your actual public domain (e.g., https://n8n.your-domain.com/).
• Restart your container with docker-compose up -d.
• Update your WhatsApp App settings in the Meta Developer Console to point to this new webhook URL.

Let me know if that gets it working.

Thank you for your kind efforts and creating some hope in me, but it unfortunately hasnt helped. It would be a miracle if you can help me get it working.

Here is my entire docker-config.yml file:

version: “3.7”

services:
traefik:
image: “traefik”
restart: always
command:
- “–api=true”
- “–api.insecure=true”
- “–providers.docker=true”
- “–providers.docker.exposedbydefault=false”
- “–entrypoints.web.address=:80”
- “–entrypoints.web.http.redirections.entrypoint.to=websecure”
- “–entrypoints.web.http.redirections.entrypoint.scheme=https”
- “–entrypoints.websecure.address=:443”
- “–certificatesresolvers.mytlschallenge.acme.tlschallenge=true”
- “–certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}”
- “–certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json”
- “–serversTransport.forwardingTimeouts.dialTimeout=60s”
- “–serversTransport.forwardingTimeouts.responseHeaderTimeout=60s”
- “–serversTransport.forwardingTimeouts.idleConnTimeout=120s”
ports:
- “80:80”
- “443:443”
volumes:
- traefik_data:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- n8n-network

n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: always
labels:
- traefik.enable=true
- traefik.http.routers.n8n.rule=Host(n8n.aitomate.co.za)
- traefik.http.routers.n8n.tls=true
- traefik.http.routers.n8n.entrypoints=websecure
- traefik.http.routers.n8n.tls.certresolver=mytlschallenge
- traefik.http.services.n8n.loadbalancer.server.port=5678
environment:
- N8N_HOST=n8n.aitomate.co.za
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://n8n.aitomate.co.za
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- N8N_RATE_LIMIT_ENABLED=true
- N8N_RATE_LIMIT_MAX_REQUESTS=100
- N8N_RATE_LIMIT_WINDOW_MS=60000
- N8N_TRUSTED_PROXIES=0.0.0.0/0
- N8N_EXPRESS_TRUST_PROXY=true
volumes:
- n8n_data:/home/node/.n8n
- /local-files:/files
networks:
- n8n-network

appsmith:
image: appsmith/appsmith-ce:v1.93
container_name: appsmith
restart: unless-stopped
environment:
- APPSMITH_MAIL_ENABLED=false
- APPSMITH_DISABLE_TELEMETRY=true
volumes:
- ./stacks:/appsmith-stacks
networks:
- n8n-network
labels:
- traefik.enable=true
- traefik.http.routers.appsmith.rule=Host(dashboard.aitomate.co.za)
- traefik.http.routers.appsmith.entrypoints=websecure
- traefik.http.routers.appsmith.tls=true
- traefik.http.routers.appsmith.tls.certresolver=mytlschallenge
- traefik.http.services.appsmith.loadbalancer.server.port=80

tiktoken:
build:
context: ./tiktoken-server
dockerfile: Dockerfile
restart: always
networks:
- n8n-network

volumes:
traefik_data:
external: true
n8n_data:
external: true

networks:
n8n-network:
driver: bridge

Hi @Gunter_Berger ,

Your docker-config.yml is actually perfect—the issue is that Docker is “lazy” and is still running the old version of the container that had the tunnel enabled.

Try this:

• Run this specific command to force a rebuild:

docker-compose up -d --force-recreate

• Immediately check the logs:

docker logs -f n8n (use your actual container name if different)

Bad Sign: If you see Tunnel URL: https://..., it’s still stuck on the old config.

Good Sign: You should see Editor is now accessible via: https://n8n.aitomate.co.za.

Guide: https://docs.n8n.io/hosting/troubleshooting/

Let me know if that finally kills the tunnel.

Best regards,

Thank you, I did get this: Editor is now accessible via: https://n8n.aitomate.co.za . But the problem still persists :sob:

I did get a lot of errors when i executed that force-recrate command:

root@srv818074:~# docker-compose up -d --force-recreate
Recreating root-traefik-1 …
Recreating root-tiktoken-1 …
Recreating appsmith …
Recreating root-n8n-1 …

ERROR: for root-n8n-1 ‘ContainerConfig’

ERROR: for root-traefik-1 ‘ContainerConfig’

ERROR: for appsmith ‘ContainerConfig’

ERROR: for root-tiktoken-1 ‘ContainerConfig’

ERROR: for n8n ‘ContainerConfig’

ERROR: for traefik ‘ContainerConfig’

ERROR: for appsmith ‘ContainerConfig’

ERROR: for tiktoken ‘ContainerConfig’
Traceback (most recent call last):
File “/usr/bin/docker-compose”, line 33, in
sys.exit(load_entry_point(‘docker-compose==1.29.2’, ‘console_scripts’, ‘docker-compose’)())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/cli/main.py”, line 81, in main
command_func()
File “/usr/lib/python3/dist-packages/compose/cli/main.py”, line 203, in perform_command
handler(command, command_options)
File “/usr/lib/python3/dist-packages/compose/metrics/decorator.py”, line 18, in wrapper
result = fn(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/cli/main.py”, line 1186, in up
to_attach = up(False)
^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/cli/main.py”, line 1166, in up
return self.project.up(
^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/project.py”, line 697, in up
results, errors = parallel.parallel_execute(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/parallel.py”, line 108, in parallel_execute
raise error_to_reraise
File “/usr/lib/python3/dist-packages/compose/parallel.py”, line 206, in producer
result = func(obj)
^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/project.py”, line 679, in do
return service.execute_convergence_plan(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/service.py”, line 579, in execute_convergence_plan
return self._execute_convergence_recreate(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/service.py”, line 499, in _execute_convergence_recreate
containers, errors = parallel_execute(
^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/parallel.py”, line 108, in parallel_execute
raise error_to_reraise
File “/usr/lib/python3/dist-packages/compose/parallel.py”, line 206, in producer
result = func(obj)
^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/service.py”, line 494, in recreate
return self.recreate_container(
^^^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/service.py”, line 612, in recreate_container
new_container = self.create_container(
^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/service.py”, line 330, in create_container
container_options = self._get_container_create_options(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/service.py”, line 921, in _get_container_create_options
container_options, override_options = self._build_container_volume_options(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/service.py”, line 960, in _build_container_volume_options
binds, affinity = merge_volume_bindings(
^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/service.py”, line 1548, in merge_volume_bindings
old_volumes, old_mounts = get_container_data_volumes(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “/usr/lib/python3/dist-packages/compose/service.py”, line 1579, in get_container_data_volumes
container.image_config[‘ContainerConfig’].get(‘Volumes’) or {}
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
KeyError: ‘ContainerConfig’

it looks like you’ve run into a compatibility bug between the newer Docker engine and your older docker-compose version 1.29.2. This specific KeyError: ‘ContainerConfig’ happens because the old tool can’t read the configuration format of newer Docker images.

Try this:
• Run docker-compose down to stop the current containers safely.
• Use the modern Docker command docker compose up -d (without the hyphen) to restart everything.
• Run docker compose logs -f n8n to confirm the tunnel is actually gone and it shows your custom domain.
• Check the WhatsApp trigger again now that the underlying Docker environment is properly refreshed.
• Verify if you have an alias or old binary by running docker-compose --version and docker compose version to compare.

try this and Let me know if it works for you.

Below my different versions. Whatsapp Trigger still not working properly :frowning:

root@srv818074:~# docker-compose --version
docker-compose version 1.29.2, build unknown
root@srv818074:~# docker compose version
Docker Compose version v2.35.1

that version difference is the problem.

Run docker compose down using the new version to completely stop the environment.
Run docker compose up -d --force-recreate to build fresh containers
Check the logs immediately with docker compose logs -f n8n.

I did it and here are the logs:

root@srv818074:~# docker compose logs -f n8n
WARN[0000] /root/docker-compose.yml: the attribute version is obsolete, it will be ignored, please remove it to avoid potential confusion
n8n-1 | Initializing n8n process
n8n-1 | n8n ready on ::, port 5678
n8n-1 | n8n Task Broker ready on 127.0.0.1, port 5679
n8n-1 | Failed to start Python task runner in internal mode. because Python 3 is missing from this system. Launching a Python runner in internal mode is intended only for debugging and is not recommended for production. Users are encouraged to deploy in external mode. See: Task runners | n8n Docs
n8n-1 | Deprecation warning: The storage directory “/home/node/.n8n/binaryData” will be renamed to “/home/node/.n8n/storage” in n8n v3. To migrate now, set N8N_MIGRATE_FS_STORAGE_PATH=true. If you have a volume mounted at the old path, update your mount configuration after migration.
n8n-1 | [license SDK] Skipping renewal on init: license cert is not initialized
n8n-1 | Registered runner “JS Task Runner” (mWGjIor-54qH_M_6DXS-J)
n8n-1 | Version: 2.7.4
n8n-1 | Start Active Workflows:
n8n-1 | Activated workflow “Voice Agent - Ultravox AItomate” (ID: 9ovzN3zMUF3OVzWk)
n8n-1 | Activated workflow “Web Chatbot - AItomate.co.za” (ID: b2OJpHTJbkeIr6D1)
n8n-1 | Activated workflow “Web Chatbot - DNAhealth.co.za” (ID: UbTVRz7bx3Hcohwz)
n8n-1 | Activated workflow “Web Chatbot - Joluka.co.za” (ID: ISxajmKfWNjN1jZF)
n8n-1 | Activated workflow “Airtable - Deduct Credit” (ID: rYsN7vcfjkWfNhQq)
n8n-1 | Activated workflow “Airtable - Recharge Monthly Balance” (ID: 3qq7SNcq5rYo2ZIE)
n8n-1 | Activated workflow “Web Chatbot - Enexi.co.za” (ID: AaPPeRx3VRd1lnoN)
n8n-1 | Activated workflow “Airtable - Hot 1027 - Check User Exists” (ID: XEcuOXVL9gswZwLN)
n8n-1 | Activated workflow “Web Chatbot - Shadecloth.co.za” (ID: 94LDblfRw1UiYPxO)
n8n-1 | Activated workflow “Web Chatbot - Shadenetting.co.za” (ID: qwQdQka8RfCnKyZJ)
n8n-1 | Activated workflow “Log User Input” (ID: REV1FhgSQzjPFVSv)
n8n-1 | Activated workflow “Log AI Agent Output” (ID: IJJz4jk4kYmbupca)
n8n-1 | Activated workflow “Log Whatsapp Push” (ID: ZMwKH4bnsFI0WVoW)
n8n-1 | Activated workflow “Tool Output Tokens - Calculate and Update Last Record” (ID: CdGzDq5SokKkvYDn)
n8n-1 | Activated workflow “Log User Input - No Tokenizer” (ID: ChVcuwELw9tVI8dT)
n8n-1 | Activated workflow “Log AI Agent Output - No Tokenizer” (ID: sl9WZCWyEKmommAQ)
n8n-1 | Activated workflow “MYSQL - Hot 102.7 OpenAI Logs” (ID: X76GO8E644YD4CGQ)
n8n-1 | Activated workflow “Joluka Jackpot - Image to Text Extractor” (ID: QhzdCrHVHqhVX6J6)
n8n-1 | Activated workflow “Log Whatsapp Push - Hot 102.7 - Final Live” (ID: TEBtfx3Qr9ZukOwr)
n8n-1 | Activated workflow “MYSQL - Hot 102.7 OpenAI Logs - Tony API Integration” (ID: hdNb8akllNjzXTNg)
n8n-1 | Activated workflow “Retell AI check_availability” (ID: 1jbeNtCdQwmnU9ei)
n8n-1 | Activated workflow “Retell AI book_appointment” (ID: R9G7cbZmT24KwW8q)
n8n-1 | Activated workflow “DSCJ” (ID: TnubMi1iAxwpGuKy)
n8n-1 |
n8n-1 | Editor is now accessible via:
n8n-1 | https://n8n.aitomate.co.za

problem persists - :sob:

So, the good news is the logs show n8n is finally starting up correctly on your custom domain, and the tunnel is officially gone. Since you’re still seeing that 429 error, it’s probably because Meta’s servers have “cached” the old tunnel URL and are still trying to send data there.

Most likely Your WhatsApp App configuration in the Meta Developer Console is still pointing to the old tunnel address or needs a fresh handshake to recognize your new domain.

Try this:
• Log in to the Meta Developer Portal and open your WhatsApp App settings.
• Go to the Configuration tab under WhatsApp.
• Click Edit on the Webhook section.
• Re-enter your production URL: https://n8n.aitomate.co.za/webhook/d68e0638-f8da-4f78-9c3a-8de498f4fe31.
• Re-verify the token to force Meta to update its routing.
• Check the Executions tab in n8n for any new incoming requests, as they won’t show up in the editor.

Let me know if the verification goes through.

Thank you, however after doing all of that, problem still persists :frowning:

we will fix this

Try this:
• Run docker compose exec n8n curl -v https://n8n.aitomate.co.za/webhook/d68e0638-f8da-4f78-9c3a-8de498f4fe31
• Check your n8n logs again and look for any lines mentioning “Rate limit reached”
• Open your Meta Developer Console and check the Webhook “Response Code” history
• Verify if the 429 error is still exactly the same or if the “HTTP Message” has changed
• Check your Executions tab to see if any requests are hitting n8n but being rejected

Quick questions:
• Can you share the output of that curl command to see how the server responds internally?
• In your Meta dashboard, does the Webhook URL match your WEBHOOK_URL exactly?

Let me know if you can grab that curl output.

Here is the ouput of the curl command on a new webhook, because I thought that might help but it hasnt:

root@srv818074:~# curl -v https://n8n.aitomate.co.za/webhook/a475360b-c6f8-4643-a53b-1fa6c40d91b5/webhook

  • Host n8n.aitomate.co.za:443 was resolved.
  • IPv6: (none)
  • IPv4: 168.231.84.43
  • Trying 168.231.84.43:443…
  • Connected to n8n.aitomate.co.za (168.231.84.43) port 443
  • ALPN: curl offers h2,http/1.1
  • TLSv1.3 (OUT), TLS handshake, Client hello (1):
  • CAfile: /etc/ssl/certs/ca-certificates.crt
  • CApath: /etc/ssl/certs
  • TLSv1.3 (IN), TLS handshake, Server hello (2):
  • TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
  • TLSv1.3 (IN), TLS handshake, Certificate (11):
  • TLSv1.3 (IN), TLS handshake, CERT verify (15):
  • TLSv1.3 (IN), TLS handshake, Finished (20):
  • TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
  • TLSv1.3 (OUT), TLS handshake, Finished (20):
  • SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519 / RSASSA-PSS
  • ALPN: server accepted h2
  • Server certificate:
  • subject: CN=n8n.aitomate.co.za
  • start date: Jan 16 08:38:54 2026 GMT
  • expire date: Apr 16 08:38:53 2026 GMT
  • subjectAltName: host “n8n.aitomate.co.za” matched cert’s “n8n.aitomate.co.za”
  • issuer: C=US; O=Let’s Encrypt; CN=R13
  • SSL certificate verify ok.
  • Certificate level 0: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
  • Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
  • Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
  • TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
  • using HTTP/2
  • [HTTP/2] [1] OPENED stream for https://n8n.aitomate.co.za/webhook/a475360b-c6f8-4643-a53b-1fa6c40d91b5/webhook
  • [HTTP/2] [1] [:method: GET]
  • [HTTP/2] [1] [:scheme: https]
  • [HTTP/2] [1] [:authority: n8n.aitomate.co.za]
  • [HTTP/2] [1] [:path: /webhook/a475360b-c6f8-4643-a53b-1fa6c40d91b5/webhook]
  • [HTTP/2] [1] [user-agent: curl/8.5.0]
  • [HTTP/2] [1] [accept: /]

GET /webhook/a475360b-c6f8-4643-a53b-1fa6c40d91b5/webhook HTTP/2
Host: n8n.aitomate.co.za
User-Agent: curl/8.5.0
Accept: /

< HTTP/2 200
< content-type: application/json; charset=utf-8
< date: Sat, 14 Feb 2026 08:15:05 GMT
< etag: W/“23-NtpDzMsUcnBm9d5fplxPmZoZiD4”
< vary: Accept-Encoding
< content-length: 35
<

  • Connection #0 to host n8n.aitomate.co.za left intact
    {“message”:“Webhook call received”}

And this is then the log:

root@srv818074:~# docker compose logs -f n8n
n8n-1 | Initializing n8n process
n8n-1 | n8n ready on ::, port 5678
n8n-1 | n8n Task Broker ready on 127.0.0.1, port 5679
n8n-1 | Failed to start Python task runner in internal mode. because Python 3 is missing from this system. Launching a Python runner in internal mode is intended only for debugging and is not recommended for production. Users are encouraged to deploy in external mode. See: Task runners | n8n Docs
n8n-1 | Deprecation warning: The storage directory “/home/node/.n8n/binaryData” will be renamed to “/home/node/.n8n/storage” in n8n v3. To migrate now, set N8N_MIGRATE_FS_STORAGE_PATH=true. If you have a volume mounted at the old path, update your mount configuration after migration.
n8n-1 | [license SDK] Skipping renewal on init: license cert is not initialized
n8n-1 | Registered runner “JS Task Runner” (bURlzi0giLKuqkbbwTLLO)
n8n-1 | Version: 2.7.4
n8n-1 | Start Active Workflows:
n8n-1 | Activated workflow “Voice Agent - Ultravox AItomate” (ID: 9ovzN3zMUF3OVzWk)
n8n-1 | Activated workflow “Web Chatbot - AItomate.co.za” (ID: b2OJpHTJbkeIr6D1)
n8n-1 | Activated workflow “Web Chatbot - DNAhealth.co.za” (ID: UbTVRz7bx3Hcohwz)
n8n-1 | Activated workflow “Web Chatbot - Joluka.co.za” (ID: ISxajmKfWNjN1jZF)
n8n-1 | Activated workflow “Airtable - Deduct Credit” (ID: rYsN7vcfjkWfNhQq)
n8n-1 | Activated workflow “Airtable - Recharge Monthly Balance” (ID: 3qq7SNcq5rYo2ZIE)
n8n-1 | Activated workflow “Web Chatbot - Enexi.co.za” (ID: AaPPeRx3VRd1lnoN)
n8n-1 | Activated workflow “Airtable - Hot 1027 - Check User Exists” (ID: XEcuOXVL9gswZwLN)
n8n-1 | Activated workflow “Web Chatbot - Shadecloth.co.za” (ID: 94LDblfRw1UiYPxO)
n8n-1 | Activated workflow “Web Chatbot - Shadenetting.co.za” (ID: qwQdQka8RfCnKyZJ)
n8n-1 | Activated workflow “Log User Input” (ID: REV1FhgSQzjPFVSv)
n8n-1 | Activated workflow “Log AI Agent Output” (ID: IJJz4jk4kYmbupca)
n8n-1 | Activated workflow “Log Whatsapp Push” (ID: ZMwKH4bnsFI0WVoW)
n8n-1 | Activated workflow “Tool Output Tokens - Calculate and Update Last Record” (ID: CdGzDq5SokKkvYDn)
n8n-1 | Activated workflow “Log User Input - No Tokenizer” (ID: ChVcuwELw9tVI8dT)
n8n-1 | Activated workflow “Log AI Agent Output - No Tokenizer” (ID: sl9WZCWyEKmommAQ)
n8n-1 | Activated workflow “MYSQL - Hot 102.7 OpenAI Logs” (ID: X76GO8E644YD4CGQ)
n8n-1 | Activated workflow “Joluka Jackpot - Image to Text Extractor” (ID: QhzdCrHVHqhVX6J6)
n8n-1 | Activated workflow “Log Whatsapp Push - Hot 102.7 - Final Live” (ID: TEBtfx3Qr9ZukOwr)
n8n-1 | Activated workflow “MYSQL - Hot 102.7 OpenAI Logs - Tony API Integration” (ID: hdNb8akllNjzXTNg)
n8n-1 | Activated workflow “Retell AI check_availability” (ID: 1jbeNtCdQwmnU9ei)
n8n-1 | Activated workflow “Retell AI book_appointment” (ID: R9G7cbZmT24KwW8q)
n8n-1 | Activated workflow “DSCJ” (ID: TnubMi1iAxwpGuKy)
n8n-1 |
n8n-1 | Editor is now accessible via:
n8n-1 | https://n8n.aitomate.co.za
n8n-1 | (node:7) [DEP0060] DeprecationWarning: The util._extend API is deprecated. Please use Object.assign() instead.
n8n-1 | (Use node --trace-deprecation ... to show where the warning was created)

The curl output proves your server is healthy, reachable, and correctly serving the 200 OK response.

However, the persistence of the CONNECT tunnel failed error . Since your server logs don’t show these failed requests, this error is coming from Meta. It means Meta is still trying to send verification requests to the old n8n Tunnel URL (which is dead), instead of your new domain.

So When you activate the workflow, n8n tries to register the webhook with Meta. Either n8n is still sending the old tunnel URL due to deep caching, or Meta’s dashboard hasn’t accepted the switch yet.

Try this again:
• Go to the Meta Developer Portal > WhatsApp > Configuration.
Manually paste your new production URL into the “Callback URL” field: https://n8n.aitomate.co.za/webhook/d68e0638-f8da-4f78-9c3a-8de498f4fe31
• Click Verify and Save. (This forces Meta to hit your actual server, which we know works via curl).
• Once verified there, go back to n8n and activate the workflow. n8n should detect the valid webhook and skip the failed registration step.

Question: Does the Meta dashboard let you save the new URL, or does it give an error there too?

It will only allow me to verify and save if the Callback URL and the Verify Token are changed and remember with n8n Whatsappp Webhook node, the subscription happens automaticaly and the verify_token is never exposed.