name: comercialrs-painel-supabase-sync
description: Sync leads from Painel do Corretor to Supabase via Tampermonkey (bypasses Cloudflare IP block on VPS)
tags:
- supabase
- chatwoot
- painel-do-corretor
- tampermonkey
- cloudflare-bypass
last_updated: 2026-05-18
ComercialRS — Painel do Corretor → Supabase via Tampermonkey
Context
Cloudflare blocks ALL requests from VPS/server IPs to Painel do Corretor API (api.paineldocorretor.net). The n8n workflow approach fails because n8n runs on the VPS. Solution: Tampermonkey userscript running in the user's browser (browser IP passes Cloudflare) writes leads directly to Supabase.
Architecture
`
Painel do Corretor (browser)
↓ Tampermonkey (GM_xmlhttpRequest with JWT)
Supabase REST API
↓ (crm_leads_duplicate table)
Kanban Chatwoot (reads from Supabase)
`
Prerequisites
- - Tampermonkey extension installed in Chrome
- - User logged into Painel do Corretor (
app2.paineldocorretor.com.br) - - Supabase Cloud project (projeto
dauftiqcvgaydddoxqhh) - - Anon key for Supabase
- - Template literals (backtick strings with
${}) - - Arrow functions (
=>) - -
const/let(usevaronly) - - Tenant ID:
a1af7a2f-7ec6-40cd-b257-86c045875979 - - GraphQL endpoint:
https://api.paineldocorretor.net/graphql - - Auth0 endpoint:
https://auth.paineldocorretor.com.br/oauth/token - - Auth0 client_id:
MtCJ0_REDACTED - - Supabase anon key:
eyJ_REDACTED - - Target table:
crm_leads_duplicate - - Painel login:
contato@rochasalesseguros.com.br/221109
Critical Rules
Code style (ES5 only)
Tampermonkey's built-in ESLint parser fails on:
Always use: var, function() {}, string concatenation with +, Object.assign() for style objects.
Script delivery
Discord corrupts template literals when user copies code. Two options:
1. URL install: Host on VPS, serve via nginx. BUT: chatwoot.rochasalesseguros.com.br doesn't exist in Cloudflare DNS — use chat.rochasalesseguros.com.br/crm-sync-v2.user.js instead
2. Manual paste: User creates new Tampermonkey script and pastes. Code must be ES5-compatible.
JWT Token
The Painel stores JWT (RS256) in localStorage/sessionStorage. Key names are unknown (dynamic Auth0). Find by scanning all localStorage for values starting with eyJ and validating as JWT (3 parts separated by ., header has alg field).
Alternatively, obtain via Auth0 API:
`
POST https://auth.paineldocorretor.com.br/oauth/token
{
"grant_type": "http://auth0.com/oauth/grant-type/password-realm",
"realm": "Username-Password-Authentication",
"username": "contato@rochasalesseguros.com.br",
"password": "221109",
"client_id": "REDACTED",
"audience": "https://paineldocorretor.com.br/api/"
}
`
Token expires ~3 days (259200s).
Supabase Upsert
Use POST /rest/v1/{table}?on_conflict=Id with header Prefer: resolution=merge-duplicates.
Headers required: apikey, Authorization: Bearer , Content-Type: application/json.
Known Data
10 Etapa IDs (confirmed from Network tab)
`
60008110-e9b1-4512-b514-ab1539ea1a1e → novos_leads
885d4f95-99e5-42a0-8150-b494c42c0e34 → qualificacao
6699997d-6978-4679-8b4c-eaab9917fefd → remarketing
4646a3e9-b21a-4339-b75b-6997fa3dbb76 → reuniao_agendada
4e61480b-b4dc-4b80-b0c8-dd3ddf8e43b2 → proposta_enviada
29511da1-1e40-4e9c-8b14-a268ccbdc1d0 → analise_seguradora
2584da59-4c1e-4fcb-8cba-8374acd896a7 → aguardando_pagamento
df8db361-5b4c-4e66-baac-afcfd9fbe50a → fechado
70150b84-6864-4cff-aae1-83195a182d8d → declinado
63f4b9df-55d6-4ff0-a42c-af5ff2ff367b → sem_interesse
`
GraphQL Query (single-line, no template literals)
`javascript
var q = 'query FetchLeads($etapaId:String!,$skip:Int!){negociosElastic(request:{busca:null,take:500,skip:$skip,conditions:[{field:"etapaId",operator:"",value:$etapaId}]}){quantidade items{id nome valor fechamento criadoEm contato{id nome avatar}etapa{id nome}produto{nome}etiquetas{nome}}}}';
`
crm_leads_duplicate columns
Id, Nome, Etapa, Valor, Vendedor, Contato.Email, Contato.Nome, Contato.Telefones (JSON array string), Produto.Ramo, Etiquetas, sync_at, sync_source
Nginx config for serving userscript
Add to /etc/nginx/sites-enabled/chatwoot inside the server block:
`nginx
location /crm-sync-v2.user.js {
alias /var/www/chatwoot-kanban/dist/crm-sync-v2.user.js;
add_header Content-Type "application/javascript";
add_header Cache-Control "no-cache";
}
`
Then nginx -t && nginx -s reload.
Verification
After sync, query Supabase:
`bash
curl -s "https://dauftiqcvgaydddoxqhh.supabase.co/rest/v1/crm_leads_duplicate?select=Id,Nome,Etapa&order=Etapa&limit=20" \
-H "apikey:
-H "Authorization: Bearer
`