Saltar al contenido

Ticket de uso único para abrir o WebSocket da plataforma

POST/api/realtime/ticket

Auth
Requiere token
Quién puede:
owner
admin
Clave de API:
No acepta clave de API
X-CommunityId
X-CommunityId Envía el X-CommunityId de la comunidad en la que ocurre la operación.
Las descripciones de los endpoints vienen de la especificación de la API y, por ahora, están en portugués. La interfaz alrededor está traducida.

Qualquer membro da comunidade (todos os papéis), **com o chat ligado ou desligado**. Devolve um ticket de **uso único**, válido por 60 s, preso à pessoa, a esta comunidade e à geração da sessão. Abra `wss://<api>/api/realtime/socket` (`data.path`) passando o ticket como segundo subprotocolo: `new WebSocket(url, ['memberfy-realtime', ticket])` (`data.protocols`); o servidor responde com `memberfy-realtime`. O ticket nunca vai na URL (na query ele é ignorado). Sem ticket válido a conexão é recusada antes de virar WebSocket (401). Trocar de comunidade fecha o socket e pede outro ticket.

**Salas.** Toda conexão já está em `me` (a própria pessoa), `community` e, para a equipe (owner, admin, moderador, financeiro), `staff`. As demais são pedidas com `{ "type": "subscribe", "rooms": [...] }` e `{ "type": "unsubscribe", "rooms": [...] }`: `space:<id>` (quem abre o espaço) e `item:event:<id>` / `item:post:<id>` (quem abre o evento ou o post), com a mesma regra do `GET` correspondente, sempre nesta comunidade. No máximo 20 salas por conexão. Resposta: `subscribed` (`rooms`) e um `subscribe.denied` (`room`) por sala recusada, **sem motivo**. Quando o acesso da pessoa muda (saiu, novo papel, grupo, acesso do espaço), o servidor reavalia as salas e manda `subscribe.denied` das que ela perdeu, e então `access.changed` (`{}`).

**Avisos de mudança** (`invalidate`): `{ "type": "invalidate", "room": "community", "topic": "event.live", "ids": ["<id>"], "at": "<iso>" }`. Só ids e o nome do tópico, nunca título, texto, valor ou nome; refaça o `GET` do que está na tela. Tópicos: `event.live` (evento começou ou terminou) e `events` (criado, editado, removido) em `community`, `space:<id>` e `item:event:<id>`, só para quem vê aquele espaço (evento privado ou em moderação: só a equipe); `analytics.online` em `staff` para owner e admin, quando o "Online agora" muda (no máximo 1 a cada 5 s); `campaigns.stats` em `staff` quando um envio termina; `menu.changed` em `community` quando o menu muda (seção ou espaço criado, editado, movido, reordenado ou removido, acesso ou visibilidade, modo "um ou vários" de um espaço, extensão ligada ou desligada), com `ids: []`, `communityId` e `reason` (`section.created`, `section.updated`, `section.deleted`, `sections.reordered`, `space.created`, `space.updated`, `space.deleted`, `spaces.reordered`, `space.mode`, `entitlements` ou `multiple`), no máximo cerca de 1 por segundo por comunidade: refaça `GET /api/sections`, que já filtra pelo seu acesso.

Salas de item também para `item:course:<id>` e `item:form:<id>` (a equipe e quem gerencia o formulário; um membro quando está publicado e ele abre o espaço) e, só para os papéis das rotas do editor, `item:campaign:<id>`, `item:email:<id>` (biblioteca), `item:workflow:<id>`, `item:survey:<id>` (owner, admin), `item:certificateTemplate:<id>` (quem emite no espaço, pelo `whoCanIssue`) e `item:emailOverride:<emailKey>` (e-mail padrão, owner e admin). Salas de área (telas de seção): `area:home` (todos), `area:members`, `area:campaigns`, `area:emails`, `area:workflows` (equipe), `area:moderation` (owner, admin, moderador), `area:analytics`, `area:dashboard`, `area:settings` (owner, admin) e `area:finance` (owner, admin, financeiro).

**Quem está aqui** (presença de área). O cliente manda `{ "type": "presence.join", "room": "<sala>", "editing": false }` ao abrir a tela (a sala é avaliada como no `subscribe` e assinada se ainda não estava; no máximo 3 lugares por conexão) e `{ "type": "presence.leave", "room": "<sala>" }` ao sair. Respostas: `presence.joined` (`room`, `editing`) seguido de um retrato `presence`, ou `presence.denied` (`room`), sem motivo. Não precisa de heartbeat: o ping do servidor mantém o lugar, que some 45 s depois da última resposta (fechar a conexão tira na hora). **Atividade:** `{ "type": "presence.active" }` quando há interação (tecla, clique, foco), no máximo a cada 10 s; entrar conta como atividade. A cada mudança (no máximo 1 por segundo por sala) a sala recebe, montado para cada conexão: `{ "type": "presence", "room": "area:campaigns", "area": "area:campaigns", "members": [{ "memberId", "name", "avatarUrl", "editing", "state": "active" | "idle", "lastActiveAt" }], "count": 3, "editingCount": 1, "at" }`. Você nunca está na própria lista; `members` traz no máximo 5 pessoas (editando ativas primeiro, depois as ativas, depois as ociosas) e `count` é o total das outras pessoas na sala. `idle` = conectada, sem atividade há 30 s ou mais (continua na lista; a troca de estado é avisada). **Privacidade:** quem está com o status do chat desligado ("Disponível para conversar" desligado) não aparece nem conta para os outros, mas vê quem está; bloqueio no chat esconde as duas pessoas uma da outra.

**Edição.** Num editor (campanha, e-mail da biblioteca, automação, evento, curso, formulário, pesquisa, modelo de certificado, configurações em `area:settings`), entre com `"editing": true` (só vale para a equipe e, no formulário, para quem o gerencia). Quem está editando aparece com `editing: true` para os **outros editores** da sala mesmo com o status do chat desligado ("X também está editando"); quem só lê a página não fica sabendo. `editingCount` conta só quem edita **ativo** (um editor ocioso continua listado com `editing`). Em sala de item ou de espaço, quem não está editando ali recebe só `memberId`, `name`, `avatarUrl` e `state` (sem `editing`, `lastActiveAt` nem `editingCount`). Repetir `presence.join` com o mesmo `editing` só devolve `presence.joined`, sem novo retrato. **Chat da comunidade desligado:** a presença não mostra ninguém. Salas de área e quem só lê uma sala de item ou de espaço recebem `presence` com `members: []` e `count: 0` (para todos, equipe incluída). Só quem está editando continua vendo os **outros editores** do mesmo item (`members`, `count` e `editingCount` só com eles), e o `item.saved` e a checagem de versão (409) seguem iguais. Ligar ou desligar o chat (`chat.settings`) manda um retrato novo de cada sala da conexão na hora. A cada gravação desses itens a sala recebe, para a equipe e para quem está editando: `{ "type": "item.saved", "topic": "item.saved", "room": "item:campaign:<id>", "itemType": "campaign", "itemId": "<id>", "by": { "memberId", "name" }, "updatedAt": "<nova versão>", "at" }` ("Fulano salvou alterações — recarregar"; compare `updatedAt` com a versão que você tem para ignorar a sua própria). `itemType`: `event`, `campaign`, `email`, `workflow`, `course` (inclusive módulos e aulas), `form`, `survey`, `certificateTemplate`, `emailOverride` (`itemId` = o `emailKey`) e, na sala `area:settings` (owner e admin, `itemId` = a comunidade), `settings` (a linha da comunidade: perfil, marca, imagens, diretório, remetentes das automações, domínio), `chatSettings`, `notificationSettings`, `messagingSettings` (SMS e WhatsApp), `creditSettings`, `businessInformation` e `payoutSettings`. As gravações aceitam a versão lida (`updatedAt` no corpo, ou `settingsUpdatedAt` na linha da comunidade, ou o cabeçalho `If-Unmodified-Since`) e respondem **409** com a versão atual em `data` quando outra gravação veio antes; cada resposta de sucesso traz a nova versão.

**Outros eventos** (JSON `{ type, data }`): `ready` (`profileId`, `communityId`, `chatAvailable`, `chatEnabled`, `rooms`, `maxRooms`, `pingIntervalMs`), `notification.new` / `notification.read` / `notification.removed` (o sino, em toda comunidade), `ai.dropDescription.ready`, `chat.settings`, `session.revoked` e `pong`. Os eventos do chat (`message.*`, `typing`, `read`, `conversation.*`, `presence.delta`, `me.updated`, `connection.*`, descritos em `POST /api/chat/ticket`) só chegam com o chat **ligado**: com `chatEnabled: false` no `ready` (ou depois de `chat.settings` com `enabled: false`) o socket continua de pé e só os eventos de chat param. **Do cliente:** `subscribe`, `unsubscribe`, `presence.join`, `presence.leave`, `presence.active`, `presence.idle` (`{ "idle": true|false }`, Ausente automático do chat: ver `POST /api/chat/ticket`), `typing` (só com o chat ligado) e `ping`; quadros de até 4 KB, sem binário, no máximo 5 por segundo.

**Códigos de fechamento:** 4004 sessão encerrada (não reconecte com a mesma sessão), 4009 substituído (mais de 10 conexões da pessoa no servidor; a mais antiga fecha), 4029 servidor cheio (conecte de novo mais tarde e use as rotas enquanto isso), 1008 excesso de quadros, 1001 servidor reiniciando. O servidor manda `ping` a cada 25 s; reconecte com espera aleatória e backoff, pedindo ticket novo. Sem Redis: 503, e o app segue buscando pelas rotas.

Headers

NombreTipoDescripción
X-CommunityIdopcionalstring (uuid)ID da comunidade em que a operação acontece. Obrigatório na maioria dos endpoints com escopo de comunidade.

Cuerpo de la solicitud application/json

La especificación no declara los campos de este cuerpo (una subida multipart, por ejemplo). Consulta la guía del tema.

Respuestas

CódigoDescripción
201Ticket emitido.
401Token ausente, inválido ou expirado; token de outra comunidade (o `X-CommunityId` ou o `communityId` do corpo não é o do token); token antigo ou de uma sessão encerrada (troca de senha, convite aceito). Nesses casos a mensagem pede para entrar de novo (`auth.signInAgain`).
403Autenticado, mas sem permissão para esta operação.
500Erro interno do servidor.
503Tempo real fora do ar (sem Redis); use as rotas.

Ejemplo con curl

curl -X POST "https://api.memberfy.net/api/realtime/ticket" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-CommunityId: $COMMUNITY_ID" \
  -H "Content-Type: application/json" \
  -d '{}'