Dashboard
Real-time overview
Activity
Recent Requests
| Time | Type | Method | Path | Status | Duration |
|---|---|---|---|---|---|
| Waiting for requests... | |||||
Request Log
Full request/response history with payload details.
| Time | Type | Method | Path | Status | Duration | Size | |
|---|---|---|---|---|---|---|---|
| Loading... | |||||||
TCP / UDP Proxies
Stream-level proxies (TCP, UDP, TLS). Used for SIP/VoIP and other non-HTTP protocols. Each profile can listen on multiple transports and forward to a single upstream.
| Name | Status | Listeners | Upstream | Transport | |
|---|---|---|---|---|---|
| Loading... | |||||
Webhooks
Fan-out incoming payloads to multiple destination URLs.
| Name | Status | Port | Targets | Auth | In-Flight | |
|---|---|---|---|---|---|---|
| Loading... | ||||||
Destinations
Fan-out destinations configured for this webhook.
| URL | Type | Filter | Retry | |
|---|---|---|---|---|
| No destinations. | ||||
Chat Connectors
Bridge digital channels (WhatsApp, generic JSON) into contact center sessions and fan agent replies back out.
| Name | Status | Channel | Port | Replies To | Activity | |
|---|---|---|---|---|---|---|
| Loading... | ||||||
Guia de integração — GoContact
Um conector liga um canal digital (WhatsApp Meta, Smooch/Sunshine, ou JSON genérico) a uma sessão de webchat GoContact, e devolve as respostas do agente. Modo GoContact: poll (API tradicional do plugin + polling) ou webchat-api (Webchat API oficial; respostas empurradas para um callback). O canal (Meta/Smooch/generic) é independente do modo. A porta de cada conector está na tabela acima — substitui <host>:<porta> pela porta real (exposta via o teu proxy).
Canal generic — entrada (n8n / o teu sistema → Midleman)
POST para a porta do conector em qualquer path. Auth: se definiste um Verify Token, envia-o em ?token= ou no header X-Forward-Token.
POST http://<host>:<porta>/?token=SEGREDO
Content-Type: application/json
# texto simples:
{ "chatId": "244939609354", "name": "João", "text": "Olá" }
# com ficheiro (o Midleman descarrega e injeta no contact center):
{ "chatId": "244939609354", "name": "João",
"file": { "url": "https://.../foto.jpg", "filename": "foto.jpg", "mimetype": "image/jpeg" } }
# várias mensagens de uma vez:
{ "messages": [ { "chatId": "c1", "text": "oi" }, { "chatId": "c2", "text": "olá" } ] }
# resposta:
{ "status": "accepted", "messages": 1, "requestId": "..." }
Aliases aceites: chatId=idChat/from · name=displayName · text=message/mensagem. Cada mensagem precisa de text ou file. No n8n usa o nó HTTP Request com método POST e body JSON para este endpoint.
Respostas do agente (Midleman → o teu sistema / cliente)
Para receberes as respostas do agente, ativa Direct reply (Meta/Smooch — entrega direta ao cliente) e/ou configura Webhook Targets (o Midleman faz POST do evento). No canal generic só há webhooks (sem direct reply).
POST <o-teu-webhook>
X-Connector: nome-do-conector
{
"connector": "nome-do-conector",
"channel": "generic",
"event": "agent_message", // ou "agent_joined" | "chat_closed"
"chatId": "cliente-244939609354",
"displayName": "João",
"message": {
"uuid": "id-unico", "text": "Em que posso ajudar?",
"timestamp": 1781700000000, "agentName": "Maria",
"userType": "AGENT",
"file": null // ou { url, filename, mimetype, size }
}
}
# chat_closed → message:null + "reason": "agent"|"admin"|"expired"
Responde 2xx para confirmar. agent_message é at-least-once (repete em falha) → deduplica por message.uuid. chat_closed: 3 tentativas, depois DLQ.
Meta WhatsApp / Smooch
Aponta o webhook do provedor para a porta do conector. Meta: usa o Verify Token no handshake (hub.challenge) e aceita o envelope completo, o value "nu", ou um array deles. Smooch: valida por X-Smooch-Signature (webhook secret). Vários conectores podem partilhar o mesmo feed Meta — cada um filtra pelo seu Phone Number Filter (phone_number_id).
# Callback URL a registar na Meta/Smooch: https://<host>:<porta>/?token=VERIFY_TOKEN
Modo webchat-api (push) — callback & URLs
A GoContact empurra as respostas do agente para o Midleman. Regista este URL no painel da GoContact (o Callback token protege o endpoint):
# Callback (agente → Midleman): https://<host>:<porta>/gocontact/callback?token=CALLBACK_TOKEN
API Base URL (eu.ds.gocontact.com) faz toda a API (auth, conversas, mensagens). Base URL (a instância, ex. gotaag.ucall.co.ao) serve só os anexos em webchat-api — opcional, só preciso se houver ficheiros. Os loginFields (nome/telefone do cliente) são detetados automaticamente; podes forçar o mapeamento em Login field mapping.
Handover bot → humano (transferir com histórico)
Quando o teu chatbot quer passar o cliente a um agente humano, cria a conversa na GoContact já com o histórico. Só em modo webchat-api. Auth = igual ao inbound (verify token).
POST http://<host>:<porta>/handover?token=SEGREDO
Content-Type: application/json
{
"chatId": "cliente-244939609354",
"name": "João",
"phoneNumberId": "879847985208219", // routing das respostas na Meta
"history": [
{ "from": "client", "text": "Quero falar com um humano", "timestamp": 1781700000000 },
{ "from": "bot", "text": "Claro, vou transferir-te.", "timestamp": 1781700001000 }
]
}
# resposta:
{ "status": "ok", "conversationUuid": "…", "contactId": "…", "historyCount": 2 }
from: "bot" → marcado como BOT; o resto → CLIENT (o agente vê os dois lados). Máx 100 mensagens (fica com as mais recentes), só texto. Depois disto, as mensagens do cliente reutilizam a sessão e as respostas saem pelo provedor configurado.
Anexos (por modo)
poll: qualquer tipo de ficheiro é enviado para o storage da instância GoContact. webchat-api: a API só aceita jpg/png/pdf no upload do cliente — outros tipos (áudio/vídeo) não são suportados pela API. Os anexos do agente (nos dois modos) são servidos pela instância: <Base URL>/storage/webchat-attachments/….
HTTP Proxies
Reverse proxies with auth injection — expose any HTTP upstream on a dedicated port with credentials hidden from clients.
| Name | Status | Port | Target URL | Auth Header | Access | Blocked Ext. | |
|---|---|---|---|---|---|---|---|
| Loading... | |||||||
Users
Every account: dashboard admins, proxy users, and LDAP-backed identities. Promote a user to admin via Edit.
| Name | Email / Username | Role | 2FA | Created | |
|---|---|---|---|---|---|
| Loading... | |||||
OAuth Clients
External applications (Supabase, etc.) that authenticate users via Midleman as the OAuth2/OIDC provider.
| Name | Client ID | Redirect URIs | Created | Access | |
|---|---|---|---|---|---|
| Loading... | |||||
OIDC Endpoints
Configure in Supabase as a Custom OAuth provider using these URLs (replace with your public domain — JWKS_PORT behind Nginx):
Response payloads
{
"access_token": "<JWT>",
"id_token": "<JWT>",
"token_type": "Bearer",
"expires_in": 86400,
"scope": "openid profile email",
"refresh_token": "<opaque>"
}
access_token and id_token carry the same RS256 JWT — verify via the JWKS endpoint above.
{
"iss": "<JWT_ISSUER>",
"sub": "<uuid-v5 derived from midleman_uid>",
"aud": "<oauth_client_id>",
"iat": 1730000000,
"exp": 1730086400,
"midleman_uid": 42,
"preferred_username": "jdoe",
// included when "email" scope is granted
"email": "jdoe@example.com",
"email_verified": true,
// included when "profile" scope is granted
"name": "John Doe",
// included when the authorize request had a nonce
"nonce": "<client-supplied>"
}
Authorization: Bearer <access_token>{
"sub": "<uuid>",
"preferred_username": "jdoe",
"email": "jdoe@example.com",
"email_verified": true,
"name": "John Doe",
"midleman_uid": 42
}
grant_type=refresh_token{
"access_token": "<new JWT>",
"id_token": "<new JWT>",
"token_type": "Bearer",
"expires_in": 86400,
"scope": "openid profile email",
"refresh_token": "<rotated opaque>"
}
Refresh tokens are single-use and rotate on every call. The previous token is invalidated.
{
"error": "invalid_grant",
"error_description": "Authorization code expired or already used"
}
Consent Pages
Library of reusable pages. OAuth clients and proxy profiles reference them by name instead of duplicating the text.
| Name | Title | Updated | |
|---|---|---|---|
| Loading... | |||
LDAP / Active Directory
External directories used to authenticate admins and/or profile users. Multiple servers can run in parallel.
| Name | URL | Base DN | Scope | 2FA | Status | |
|---|---|---|---|---|---|---|
| Loading... | ||||||
Notes
- Scope: admin → dashboard login only; proxy → profile users only; both → both.
- 2FA: required enforces TOTP on first login; optional allows skipping; disabled ignores it. LDAP admins always require TOTP.
- The bind admin password is encrypted with AES-256-GCM using a key derived from the JWT RSA key.
- The filter must contain
{login}. Default coversuid,mailandsAMAccountName.
Notifications
Define recipient groups and the rules that decide which events reach them. Events are matched by category and severity; channels default to email for info/warning and email + SMS for critical, with optional per-rule overrides.
Nginx Proxy Manager
Manage proxy hosts, certificates and HTTPS termination from inside Midleman. Optional addon — Midleman keeps working without it.
Report Feeds
Fetch GoContact reports and expose them as a JSON API with configurable field mapping and API key auth.
| Name | Template | Owner Type | Date Range | Cache | Last Fetch | |
|---|---|---|---|---|---|---|
| Loading... | ||||||
Activity Log
Consumer API
Authenticate with an API Key via header X-API-Key, Authorization: Bearer <key> or query param ?apiKey=<key>.
# Flat route (feed sem grupo) GET /reports/:name X-API-Key: <your-api-key> # Grouped route (feed com group + slug) GET /reports/:group/:slug X-API-Key: <your-api-key> # Detail (requer detail.idField configurado) GET /reports/:group/:slug/:id GET /reports/:name/:id # Streaming áudio GET /reports/:group/:slug/:id/audio # Filtros — exact-match GET /reports/:group/:slug?agentName=João # Filtros — operadores tipados (?campo__op=valor) GET /reports/:group/:slug?startDate__gte=2026-01-01&startDate__lte=2026-01-31 GET /reports/:group/:slug?talkTime__gte=60&direction__contains=inbound # Swagger/OpenAPI GET /reports/docs?apiKey=<key> ← global GET /reports/:group/docs?apiKey=<key> ← específico do grupo
Audit Log
History of administrative actions — who did what, when, and from where.
| When | Actor | Action | Target | IP | |
|---|---|---|---|---|---|
| Loading... | |||||