WaWeb canonical pipeline

Do socket à mensagem

Como o WhatsApp Web abre um canal seguro, entra sem sessão pareada, recebe a oferta neutra de pareamento, solicita PairCode por ação do controlador, autentica a sessão, baixa o estado da conta e troca mensagens.

Como ler este relatório

O fluxo tem três níveis ao mesmo tempo. O WebSocket carrega frames binários; alguns frames viram stanzas, que são as mensagens estruturadas do protocolo; o relatório usa a sequência do pipeline para preservar a ordem exata em que tudo aconteceu.

Pipeline seq

Número do evento na linha do tempo completa. Inclui transporte, frames, Noise e stanzas.

Direções

C → S é cliente para servidor. S → C é servidor para cliente.

Frame

Pacote binário bruto que passa pelo WebSocket. Antes da primeira stanza, ele é usado pelo Noise.

Stanza

Mensagem estruturada do WhatsApp. Tem direção, tag, atributos e filhos.

Controlador

Ação local do capturador, como abrir o cliente e solicitar PairCode depois do initialize.

Sessão já autenticada

No canônico resume, o cliente abre o socket, não chama PairCode e a primeira stanza já é success.

Noise vs. Signal

Noise protege o canal WebSocket. Signal protege o conteúdo das mensagens ponta a ponta.

Observado vs. inferido

Observado vem direto da captura. Inferido é interpretação do papel daquele evento no fluxo.

Cliente WaWebO aparelho Web que queremos reproduzir em C#.
ServidorO WhatsApp, que aceita sockets, autentica e entrega stanzas.
Celular principalA linha que autoriza o pareamento pelo PairCode.
Celular auxiliarO aparelho de teste que dispara a mensagem recebida no fim.
Controlador da capturaAutomação que abre o cliente oficial e solicita PairCode após o initialize.
Ver linha narrativa e exemplo seguro
O navegador abre sockets quase em paralelo e usa os que carregam frames úteis. Noise negocia um canal cifrado antes de qualquer stanza aparecer. O servidor oferece pareamento porque a sessão ainda não está vinculada. O initialize prepara país/refs; depois o controlador solicita PairCode como ação explícita de usuário. A sessão reconecta, recebe success e inicia o bootstrap operacional. O cliente sincroniza estado, envia texto, faz fanout e recebe mensagem externa.
Atalho observado quando a sessão já existe
resume:
seq 8  controller · client_initialize_called · pairing_code_mode=none
seq 22 stanza recv success
ausentes: pair-device, requestPairingCode_called, pair-success
Exemplo seguro de stanza fictícia
tag: message
direção: recv
attrs: [from, id, type]
children: [enc, reporting]
valores reais: ocultos

Mapa visual do fluxo

Socket Noise Controlador PairCode Auth Bootstrap Envio Recebimento
1 · Socket + Noise O navegador abre o canal e cria um túnel seguro com o servidor.
WebSocket criado canal útil · HTTP upgrade · 101

O navegador abre sockets candidatos e segue pelo que carrega os frames úteis.

Ver detalhes desta etapa
Primeiro cumprimento seguro (client_hello) frame sent · 43B

O navegador manda um primeiro cumprimento cifrado com uma chave descartável.

Ver detalhes desta etapa
Resposta segura (server_hello) frame recv · 350B

O servidor devolve sua parte para os dois lados fecharem o canal seguro.

Ver detalhes desta etapa
Canal seguro pronto (client_finish) frame sent · 372B

O navegador conclui a negociação. A partir daqui as stanzas trafegam cifradas.

Ver detalhes desta etapa
Primeiro WAP decodificado recv iq · pair-device

Primeira oferta de pareamento após o canal seguro abrir; ainda não é a solicitação de PairCode.

Ver detalhes desta etapa
2 · PairCode Depois do initialize, o controlador simula o usuário pedindo pareamento por número.
pair-device S → C · refs de pareamento

O servidor oferece refs; em seguida o cliente pede só o país, ainda sem PairCode.

Ver detalhes desta etapa
Solicitar PairCode controller · client.requestPairingCode

Ação explícita após client.initialize(), como abrir a tela “vincular com número”.

Ver detalhes desta etapa
companion reg C → S · companion_hello + chaves

O pedido local vira link_code_companion_reg com estágio companion_hello.

Ver detalhes desta etapa
country + ref S → C · country_code + ref

O servidor informa o país do número e devolve uma nova referência.

Ver detalhes desta etapa
primary hello S → C · notification; depois C → S · ack

O celular principal entra na conversa; o navegador confirma que recebeu.

Ver detalhes desta etapa
pair-success S → C · pair-success; depois C → S · pair-device-sign

O servidor autoriza o novo aparelho; o navegador assina como prova.

Ver detalhes desta etapa
3 · Auth A sessão recém-criada é apresentada e aceita pelo servidor.
Troca de canal stream:error · xmlstreamend

O servidor encerra o canal antigo. A sessão real entra no canal seguinte.

Ver detalhes desta etapa
Novo socket ws-3 · reconexão autenticada

O navegador abre nova conexão com os dados combinados no pareamento.

Ver detalhes desta etapa
Frame autenticado ws-3 · frame sent · 165B

O navegador envia um frame curto no novo canal antes do success.

Ver detalhes desta etapa
Login aceito (success) S → C · lid, props, companion key

O servidor aceita a entrada e devolve identidade e regras de uso.

Ver detalhes desta etapa
4 · Bootstrap A conta baixa configurações, dispositivos e mensagens antigas, como um app abrindo pela primeira vez.
Capacidades e rotas media_conn · props · edge_routing

O navegador pergunta por onde mandar mídia, quais regras valem e onde estão os servidores.

Ver detalhes desta etapa
Registro e chaves registration · identity · skey

O navegador envia chaves descartáveis usadas para cifrar conversas futuras.

Ver detalhes desta etapa
Privacidade privacy · list · respostas

O servidor entrega regras de privacidade e listas que fazem parte do estado da conta.

Ver detalhes desta etapa
Mensagens e dispositivos active · usync · offline · devices

O navegador descobre aparelhos vinculados e baixa mensagens que chegaram antes dele.

Ver detalhes desta etapa
Perfil e chaves picture · business_profile · tokens · key

O navegador puxa foto, perfil, tokens e chaves vigentes antes do envio.

Ver detalhes desta etapa
5 · Envio O cliente manda a mensagem; o attr device_fanout indica a provável cópia para outros aparelhos.
Mensagem principal stanza 140 · sent message · participants + device-identity

O navegador envia a primeira cópia cifrada da mensagem.

Ver detalhes desta etapa
Ack + receipt stanzas 141-148 · phash, recipient, receipt

Servidor e cliente trocam confirmações de processamento e recibos de estado.

Ver detalhes desta etapa
Preparação do fanout usync · key · query · sync

Antes de replicar, o navegador confere chaves e dispositivos atuais.

Ver detalhes desta etapa
Fanout stanza 169 · sent message · device_fanout · inferido

Observamos o attr device_fanout; nesta captura ele aparece depois da mensagem recebida.

Ver detalhes desta etapa
6 · Recebimento Outro celular manda mensagem para esta conta e o navegador recebe.
Auxiliar envia contexto externo · não é stanza

O celular auxiliar dispara a mensagem que aparecerá no WebSocket.

Ver detalhes desta etapa
Mensagem recebida stanza 152 · enc + url_text + url_number + reporting

Chega uma mensagem cifrada; o texto real só existiria depois de decifrar.

Ver detalhes desta etapa
Receipt stanza 153 · C → S

O navegador avisa ao servidor: recebeu.

Ver detalhes desta etapa
Sync pós-recebimento usync · identity · final list

Antes de encerrar a captura, o navegador confere identidades e contatos.

Ver detalhes desta etapa

Relatório analítico por bloco

Esta seção abre cada caixa do mapa. Cada painel separa o que foi observado nos contratos de captura, o que é inferência de leitura e quais campos são apenas nomes estruturais. As ações locais do controlador aparecem como eventos próprios para não confundir oferta do servidor com escolha do usuário. Nenhum payload, telefone, JID, cookie, token, chave, ref ou valor bruto da captura é publicado.

WebSocket criado

observadopipeline seq 10-24

Leitura

O navegador abre dois sockets quase em paralelo. Nesta captura, o ws-2 carrega o pareamento; o ws-1 recebe 101 e fecha sem carregar stanza.

Entrada chromium_started, recorder anexado e handshake HTTP de WebSocket.
Saída ws-2 pronto para receber os frames binários do Noise.
Regra de leituraO número do socket não define papel fixo; o canal útil é o que sobrevive e carrega frames.

Mini pipeline

SeqEventoContrato
10-11createdwebsocket_created para ws-1 e ws-2.
12-13requestHeaders por nome; valores como Cookie/User-Agent ficam fora do relatório.
14, 18responseHTTP 101 aceita o upgrade para WebSocket.
24closews-1 fecha sem stanza associada.

Ponto de convergência: comparar o papel do canal, não assumir que ws-1 sempre será o principal.

client_hello

inferidopipeline seq 15-17

Leitura

O primeiro frame binário pré-stanza é interpretado pelo recorder como client_hello. Ele abre o handshake Noise e ainda não é uma stanza WAP.

Framews-2, direção sent, opcode binário, 43 bytes.
ConfiançaO evento vem de source=inferred_from_pre_stanza_binary_frame.

Mini pipeline

SeqCamadaContrato
15wirewebsocket_frame sent, payload_kind=binary, payload_size=43.
16noisenoise_handshake_started, inferido pelo primeiro frame pré-stanza.
17noiseclient_hello, wire_frame_index=1.

Não publicar chave efêmera nem bytes do frame. O relatório só precisa da forma e do tamanho.

server_hello

inferidopipeline seq 19-20

Leitura

O servidor responde no mesmo ws-2 com um frame binário maior. A captura o classifica como a segunda etapa do Noise.

Framerecv, opcode binário, 350 bytes.
SaídaCliente tem material para finalizar o handshake.

Mini pipeline

SeqCamadaContrato
19wirewebsocket_frame recv, payload_size=350.
20noiseserver_hello, wire_frame_index=2.

client_finish

inferidopipeline seq 21-23

Leitura

O terceiro frame pré-stanza encerra a negociação Noise. Depois dele, o próximo evento estruturado já é uma stanza decodificada.

Framesent, opcode binário, 372 bytes.
TransiçãoNoise concluído → tráfego WAP decodificável.

Mini pipeline

SeqCamadaContrato
21wirewebsocket_frame sent, payload_size=372.
22noiseclient_finish, wire_frame_index=3.
23noisenoise_handshake_completed.

Primeiro WAP decodificado

observadostanza 1 · seq 25

Leitura

Esse é o primeiro nó WAP legível depois do Noise. Ele prova que o canal cifrado já transporta stanzas estruturadas e que o servidor reconheceu uma sessão sem vínculo.

Stanzarecv iq, attrs [from,id,type,xmlns].
Filhopair-device, contendo refs com conteúdo em bytes.
ImportanteEssa oferta não prova que PairCode foi pedido; a solicitação aparece depois como evento do controlador.

Mini pipeline

StanzaSeqContrato
125recv iq / pair-device.
226sent iq / empty, resposta curta ao servidor.

pair-device

observadostanzas 1-2

Leitura

O servidor entrega referências temporárias porque o cliente ainda não tem sessão. Essa é uma oferta de pareamento neutra: ela aparece antes de o usuário escolher PairCode e é seguida por uma consulta automática de país.

Recebidopair-device com 6 ref.
Respondidosent iq vazio, usado como confirmação técnica.
Quem pediu?Ninguém pediu PairCode ainda. O controlador só solicita a rota por número depois de client.initialize().
PreparaçãoDurante o initialize, o cliente envia link_code_companion_reg stage=get_country_code; isso ainda não gera o código.

Mini pipeline

StanzaSeqContrato
125recv iq, child pair-device, refs em bytes.
226sent iq, sem filhos.
329sent iq / link_code_companion_reg, stage get_country_code.

Solicitar PairCode

observadocamada controller

Leitura

Depois que client.initialize() retorna, o capturador executa a mesma intenção de um usuário no WhatsApp Web: abrir a opção de vincular por número de telefone. No código, isso é a chamada pública client.requestPairingCode(TEST_PHONE).

Antesclient_initialize_returned, sem PairCode automático no initialize.
Açãopaircode_user_action_started e requestPairingCode_called.
PrivacidadeO log registra apenas phone_size, nunca o telefone.

Mini pipeline

CamadaEventoContrato
controllerclient_initialize_returned · seq 31Cliente oficial carregado e pronto para ação local.
controllerpaircode_user_action_started · seq 33Ação open_phone_number_pairing.
controllerrequestPairingCode_called · seq 34API pública do whatsapp-web.js, com telefone redigido por tamanho.

companion reg

observadostanzas 3-4 e 11

Leitura

O mesmo nome de stanza aparece em três momentos. A stanza 3 é preparação automática do initialize; a stanza 4 é a resposta direta à ação requestPairingCode; a stanza 11 finaliza a troca de chaves depois que o celular principal entra na conversa.

Campos voláteisjid, nonce, refs, chaves públicas e bundles.
Contrato fixoTag link_code_companion_reg, attrs por nome e ordem relativa dos estágios.

Mini pipeline

StanzaSeqContrato
329stage=get_country_code, preparação automática ainda no initialize.
435stage=companion_hello, com JID, notificação, plataforma, chaves e nonce.
1151stage=companion_finish, com bundle, identidade pública e ref.

country + ref

observadostanzas 5-6

Leitura

São duas respostas distintas: uma informa o país do número e a outra devolve uma nova referência de pareamento. O mapa junta as duas por leitura visual, mas o contrato separa.

Stanza 5country_code com attr iso.
Stanza 6link_code_companion_reg com link_code_pairing_ref.

Mini pipeline

StanzaSeqContrato
537recv iq / country_code.
639recv iq / link_code_companion_reg, child link_code_pairing_ref.

primary hello

observadostanzas 9-10

Leitura

O servidor entrega a notificação vinda do aparelho principal. Ela carrega chave efêmera, identidade primária e ref. O cliente responde com ack.

Recebidonotification / link_code_companion_reg com attrs [from,id,t,type].
Respondidosent ack com attrs [class,id,to,type].

Mini pipeline

StanzaSeqContrato
947link_code_pairing_wrapped_primary_ephemeral_pub, primary_identity_pub, link_code_pairing_ref.
1048sent ack da notificação.

pair-success

observadostanzas 12-14

Leitura

O servidor aceita o pareamento e entrega metadados de jurisdição, criptografia, plataforma, identidade do dispositivo e dados de negócio. O cliente fecha com pair-device-sign.

pair-successjurisdiction, encryption-metadata, client-props, platform, device-identity, biz, device.
Assinaturapair-device-sign / device-identity com key-index.

Mini pipeline

StanzaSeqContrato
1253recv iq vazio.
1355recv iq / pair-success.
1457sent iq / pair-device-sign.

Troca de canal

observadocausa inferidastanzas 15-16

Leitura

O fato observado é o fechamento do stream antigo com stream:error e xmlstreamend. A interpretação de que isso prepara a reconexão autenticada vem da vizinhança do fluxo.

Fatorecv stream:error com attr code; recv xmlstreamend sem attrs.
Depoisws-3/ws-4 surgem nas seq 62-63; ws-2 fecha na seq 66.

Mini pipeline

Stanza/SeqEventoContrato
15 / 59stanzarecv stream:error, sem publicar o valor do código.
16 / 60stanzarecv xmlstreamend.
62-63transportwebsocket_created ws-3/ws-4, antes do fechamento do ws-2.
66transportwebsocket_closed ws-2.

Novo socket

observadopipeline seq 62-72

Leitura

A reconexão também abre dois sockets quase em paralelo. Nesta captura, o ws-3 carrega o caminho útil e o ws-4 fecha antes do success.

Socket útilws-3, handshake 101, frames binários e stanzas seguintes.
Socket auxiliarws-4, handshake 101, fechado na seq 71.

Mini pipeline

SeqEventoContrato
62-63createdws-3 e ws-4.
64-65,67,69handshakeRequests e responses 101.
68,70,72wireFrames 43B, 350B e 165B no ws-3.
71closews-4 fechado.

Nesta reconexão, a captura mostra três frames pré-success no ws-3; não há evento client_finish separado como no primeiro socket.

Frame autenticado

observadopipeline seq 72

Leitura

Antes do success, o novo socket útil envia um frame binário curto. A captura não publica esse payload como stanza; ele fica registrado como evidência de transporte imediatamente antes da autenticação aceita.

Framewebsocket_frame sent no ws-3, payload 165B.
DepoisO servidor responde com success na stanza 17.

Mini pipeline

SeqEventoContrato
72wirewebsocket_frame sent no ws-3, payload 165B.
73stanzarecv success.

success

observadostanza 17 · seq 73

Leitura

O servidor aceita a sessão. A partir daqui a captura entra no bootstrap operacional: mídia, props, privacidade, sync, identidade e mensagens pendentes.

Attrsabprops, companion_enc_static, creation, lid, location, props, t.
PublicaçãoSomente nomes dos atributos; valores são material sensível.

Mini pipeline

StanzaSeqContrato
1773recv success, conteúdo vazio, attrs de identidade e propriedades.
18-2075-77Primeiras consultas de bootstrap: media_conn, props, iq vazio.

Sessão já autenticada

baseline resumestanza 1 · seq 22

Leitura

Quando a sessão já está persistida, o canônico logado não passa por PairCode. O controlador chama client.initialize() com pairing_code_mode=none, o WebSocket abre o canal seguro, e a primeira stanza decodificada já é success.

Presenteclient_initialize_called, client_initialize_returned e recv success.
Ausentepair-device, paircode_user_action_started, requestPairingCode_called, link_code_companion_reg e pair-success.
DepoisO fluxo entra direto no bootstrap: media_conn, acks, props, privacy, active e demais consultas de estado.

Mini pipeline resume

SeqCamadaContrato
8controllerclient_initialize_called, pairing_code_mode=none.
21controllerclient_initialize_returned, ainda sem ação de PairCode.
22stanzarecv success, primeira stanza do fluxo logado.
24+stanzaBootstrap operacional começa com media_conn e confirmações.

Fonte: captures/baseline-resume/20260516T185317.341Z, com 126 eventos de pipeline e 50 stanzas.

Capacidades, mídia e rotas

observadostanzas 18-28

Leitura

O cliente busca conectividade de mídia, propriedades de protocolo, rotas e estado sujo. O estado offline aparece depois, já no bloco de mensagens e dispositivos.

Obrigatórios observadosmedia_conn, props, edge_routing, dirty.
ComplementaresConsultas de foto, privacidade e respostas vazias.

Mini pipeline

StanzaSeqContrato
18-2075-77sent iq: media_conn, props, vazio.
21-2281-83recv ib: edge_routing, dirty.
23-2884-95picture/privacy, resposta vazia e resposta media_conn.

Registro Signal e chaves

observadostanzas 29-33

Leitura

É um dos maiores pontos estruturais do bootstrap. O cliente envia registro, identidade, uma lista grande de prekeys e skey. A captura também recebe erros nessa vizinhança.

Stanza 29registration, type, identity, list com 812 key, skey.
Risco de diffNão comparar bytes de chaves; comparar presença, contagem e formato.

Mini pipeline

StanzaSeqContrato
2997sent iq / registration+type+identity+list+skey.
3099recv iq / props+erid, com 1356 prop.
31,33101,105recv iq / error; observado, não tratado como falha automática.
32102sent iq / clean.

Privacidade e listas

observadostanzas 25, 34-45

Leitura

Essa parte sincroniza regras de privacidade e listas de visibilidade. Termos e avisos aparecem no baseline resume, mas não neste trecho do fresh.

Enviossent iq / privacy aparece 5 vezes: stanzas 25 e 35-38.
Respostasrecv iq / privacy aparece nas stanzas 34 e 41-44; list aparece na stanza 39.

Mini pipeline

StanzaSeqContrato
2586sent iq / privacy, consulta inicial.
34107recv iq / privacy, resposta com categorias.
35-38108-111Novas consultas privacy com lista/addressing mode.
39-45117-129recv iq / list, respostas vazias e respostas privacy.

Mensagens pendentes, dispositivos e sync

observadostanzas 46-95, 96-123

Leitura

Esta parte mistura ações do cliente com eventos de fundo que chegaram enquanto a sessão carregava: presença ativa, consultas usync, mensagens cifradas pendentes, receipts, devices e snapshots de app-state.

Mensagens de fundorecv message / meta+verified_name+enc: stanzas 58-63 neste bloco; uma mensagem tardia do mesmo formato aparece na stanza 126.
Multi-devicedevices, add, identity e usync.
Eventos raroswa_ad_account_nonce, collection e devices aparecem aqui e ajudam o diff.

Mini pipeline

StanzaSeqContrato
46-57130-153active, usync, offline, acks e devices.
58-80154-192Mensagens recebidas de fundo, receipts e acks.
81-95194-221usync, identity, list, collections e respectivo ack.
96-123224-278Snapshots, presença, unified session, perfil, tokens, key e patches.

Essas mensagens não são a mensagem auxiliar final. São eventos recebidos durante o bootstrap e precisam ser tolerados no diff.

Perfil, presença e chaves finais do bootstrap

observadostanzas 124-139

Leitura

O fim do bootstrap resolve erros, listas, perfil de negócio, grupos, fotos, sync e lista final. Ele termina imediatamente antes do primeiro envio de mensagem.

Eventos únicosrecv iq / groups, mensagens de fundo tardias e lista final.
Perfilbusiness_profile, fotos, sync, list e ack final antes do envio.

Mini pipeline

StanzaSeqContrato
124-127280-286Erros/lista, mensagem de fundo tardia e receipt.
128-134288-300business_profile, grupos, fotos e lista.
135-139302-310Resultado, ack, sync e lista final pré-envio.

Mensagem principal

observadorótulo inferidostanza 140 · seq 312

Leitura

Esse é o primeiro sent message do cliente no baseline. Chamamos de mensagem principal porque é o envio direto antes das confirmações; o fanout aparece mais tarde, depois de eventos intercalados.

Attrsid, peer_recipient_pn, to, type.
Filhosparticipants com múltiplos to; device-identity em bytes redigidos.

Mini pipeline

StanzaSeqContrato
140312sent message / participants+device-identity.
141-148314-328Ack com phash, receipts e confirmações do envio.

peer_recipient_pn é nome estrutural; o telefone real não deve aparecer no HTML público.

Ack + receipt do envio

observadostanzas 141-148

Leitura

Confirmações não são uma coisa só. ack confirma processamento de stanza; receipt comunica estado de mensagem; e o cliente responde cada recibo com a forma de ack correspondente.

AckStanza 141 tem phash; stanzas 143, 145 e 147 são acks enviados pelo cliente.
ReceiptStanzas 142, 144, 146 e 148 comunicam estado/recibo.

Mini pipeline

StanzaSeqContrato
141314recv ack, attrs incluem phash.
142316recv receipt, attrs incluem recipient.
143318sent ack com attrs [class,id,to,type].
144-148320-328Receipts, acks e sent receipt sem expor valores.

Preparação do fanout

observadostanzas 155-168

Leitura

Entre o envio primário e o device_fanout, entram a mensagem recebida do auxiliar e uma sequência de consultas de estado, chaves, query, sync e addons. Essa etapa evita tratar o fanout como uma repetição imediata.

Consultasusync, key, query, sync, my_addons.
Respostasusync, result, sync, list, my_addons.

Mini pipeline

StanzaSeqContrato
155-158341-348parameters e duas consultas usync.
159-164350-359query, sync, tokens de acesso, result e my_addons.
165-168362-368sync, my_addons, key e list antes do fanout.

Fanout

observadosemântica inferidastanzas 169-180

Leitura

O fato observado é um segundo sent message com attr device_fanout. A leitura de que ele replica a mensagem para dispositivos vem do nome do atributo e do contrato multi-device; nesta captura ele fica depois da mensagem recebida do auxiliar.

Stanza 169sent message, attrs incluem device_fanout, filhos participants e device-identity.
Depoisack, receipt, usync, identity e lista final.

Mini pipeline

StanzaSeqContrato
169370sent message / device_fanout.
170-174372-380ack, receipt e acks enviados.
175-180382-392usync, identity e list finais.

Dispositivo auxiliar envia

evento externoantes da stanza 152

Leitura

Este bloco é contexto do cenário de teste, não um evento do contrato de pipeline. A primeira evidência observada no protocolo é a mensagem recebida na stanza 152.

Não vem do JSONLAção do Android auxiliar.
Primeiro efeitorecv message / enc+url_text+url_number+reporting.

Mini pipeline

MarcoOrigemContrato
externocenárioDispositivo auxiliar de teste envia a mensagem.
152 / 336pipelinePrimeiro efeito observável no WebSocket.

Mensagem recebida

observadostanza 152 · seq 336

Leitura

A conta em teste recebe uma stanza message cifrada. Ela traz o envelope enc e filhos estruturais como url_text, url_number e reporting. O conteúdo real não é publicado.

Attrsfrom, id, notify, sender_pn, sts, t, type.
Filhosenc, url_text, url_number, reporting.

Mini pipeline

StanzaSeqContrato
152336recv message, conteúdo em filhos, enc em bytes.
153338sent receipt confirma recebimento.

A presença de url_text e url_number é estruturalmente relevante; valores ficam redigidos.

sender_pn é apenas o nome do atributo observado; o número real não é publicado.

Receipt de recebimento

observadostanza 153 · seq 338

Leitura

O cliente confirma para o servidor que recebeu a mensagem. Esse recibo é curto e não carrega o conteúdo da mensagem.

Stanzasent receipt, attrs [id,to].
DepoisO cliente continua com consultas de sincronização e identidade.

Mini pipeline

StanzaSeqContrato
153338sent receipt, sem filhos.
154340sent ack da mensagem recebida.

Sync pós-recebimento

observadorótulo inferidostanzas 155-180

Leitura

O protocolo não emite um “fim” explícito aqui. Chamamos de sync pós-recebimento a sequência de iq, usync, identity, receipts e lista final que cerca o fanout e encerra a captura.

Pré-fanoutStanzas 155-168: parâmetros, usync, query, sync, tokens, addons, key e list.
FanoutStanza 169 envia a cópia com device_fanout.
FinalStanzas 170-180 fecham ack/receipt, usync, identity e lista final.

Mini pipeline

StanzaSeqContrato
155-168341-368parameters, usync, query, sync, tokens, addons, key e list.
169370sent message / device_fanout.
170-180372-392ack, receipt, usync, identity e recv iq / list.
-395chromium_closed encerra a captura.

Erros observados que apareceram no caminho

observadopainel transversal

Leitura

A captura tem erros estruturais esperados ou tolerados. Eles não devem sumir do relatório, porque são pontos importantes para diff entre o cliente oficial e o cliente C#.

Streamstream:error seguido de xmlstreamend na troca de canal.
IQQuatro recv iq com child error durante bootstrap.

Mini pipeline

StanzaSeqContrato
1559recv stream:error, valor do code não publicado.
31101recv iq com child error; attrs do child [code,text].
33105recv iq com child error; attrs do child [code,text].
123-124278,280recv iq com child error; attrs do child [code,text].

Na validação de convergência, a presença e a posição desses erros importam mais do que os valores.

Depois de tudo isso, o que sabemos?

A ordem está cobertaO relatório preserva a linha do tempo desde o primeiro socket até o fechamento da captura.
O vazio foi preenchidoO espaço entre abrir o WebSocket e receber pair-device agora mostra o handshake Noise e a primeira stanza.
A ação local ficou explícitaO pedido de PairCode aparece depois do initialize, na camada controller.
Logado pula PairCodeNo baseline resume, não há pair-device, requestPairingCode_called nem pair-success; a primeira stanza é success.
O bootstrap é heterogêneoEle não é uma etapa única: mistura privacidade, chaves, dispositivos, mensagens de fundo e perfil.
O cliente C# tem critérioO que precisa convergir é estrutura: ordem, tags, attrs, filhos e contagens. Valores brutos continuam privados.

Glossário dos termos do mapa

Tradução curta dos nomes mais técnicos que aparecem no fluxo. Os termos ficam no idioma do protocolo para facilitar o diff com os logs, mas a explicação mostra o papel de cada um.

WebSocket
Canal que fica aberto entre cliente e servidor, permitindo troca de dados nos dois sentidos sem abrir uma conexão nova a cada mensagem.
HTTP 101
Resposta do servidor que aceita trocar o HTTP comum por WebSocket. É o sim oficial para abrir o canal persistente.
frame
Pacote bruto que viaja pelo WebSocket. Antes de virar uma stanza legível, tudo aparece como frames binários.
Noise
Protocolo que cria o canal seguro. Depois do handshake Noise, o tráfego passa cifrado entre cliente e servidor.
client_hello
Primeira mensagem do handshake Noise. O cliente envia uma chave temporária para começar a negociação segura.
server_hello
Resposta do servidor no handshake Noise. Ela devolve dados temporários para o cliente continuar a negociação.
client_finish
Mensagem final do handshake Noise. O cliente fecha a negociação e deixa o canal pronto para tráfego cifrado.
stanza
Mensagem estruturada do protocolo, parecida com uma árvore: tem tag, atributos, conteúdo e filhos.
WAP
Formato binário usado pelo WhatsApp para transformar stanzas em bytes compactos antes de enviar pelo socket.
iq
Tipo de stanza usado para pedidos que esperam resposta, como consultar dados, configurar estado ou registrar algo.
PairCode
Código curto digitado no celular para autorizar o novo aparelho sem usar QR code. No canônico, ele é solicitado por ação do controlador depois de client.initialize().
pair-device
Oferta inicial do servidor para uma sessão ainda não pareada. Ele carrega refs, mas não significa que a rota PairCode já foi escolhida.
controlador
Parte do capturador que simula ações do usuário e da automação local, como iniciar o cliente oficial e solicitar PairCode.
companion
Nome do protocolo para o aparelho secundário, ou seja, o cliente que será vinculado ao celular principal.
ref
Identificador temporário do pareamento. Ele amarra a tentativa do companion com o celular principal.
primary hello
Mensagem do celular principal para o companion durante o pareamento. Ela confirma o pedido e envia chaves.
ack
Confirmação curta de recebimento. Diz que uma stanza chegou, sem carregar uma resposta de negócio.
pair-success
Stanza que marca o pareamento como concluído. Depois dela, o companion já pode operar como autorizado.
stream:error
Erro de stream usado aqui como fechamento controlado. O servidor encerra o canal antigo para forçar reconexão.
success
Confirmação de login depois da reconexão. A partir dela, a sessão foi aceita e pode sincronizar dados.
lid
Identificador interno da conta no modelo multi-device. Em muitos pontos ele substitui o telefone.
props
Conjunto de configurações e flags que o servidor entrega para ajustar o comportamento da sessão.
edge_routing
Informação de rota que ajuda o cliente a escolher por onde trafegar com os servidores do WhatsApp.
dirty
Sinal de que algum conjunto de dados precisa ser limpo, confirmado ou sincronizado de novo.
Signal
Protocolo de criptografia ponta a ponta. Ele protege o conteúdo para que só remetente e destino leiam.
skey
Bloco de chave assinada usado no material de criptografia do dispositivo. O relatório mostra só a presença, nunca o valor.
usync
Consulta de sincronização de usuários. Serve para descobrir dispositivos, identidades, status e chaves.
offline
Lote de mensagens e eventos que chegaram enquanto o cliente estava fora e precisam ser entregues ao reconectar.
unified_session
Marcador de sessão enviado durante o bootstrap para alinhar estado entre a sessão Web e o servidor.
device-identity
Bloco assinado que prova quais dispositivos pertencem a uma conta e ajuda a validar o envio cifrado.
receipt
Recibo de estado da mensagem. Pode indicar entrega, recebimento, leitura ou outro avanço do fluxo.
fanout
Envio da mesma mensagem para vários dispositivos do destinatário, cada um com seu envelope cifrado.
phash
Hash estrutural que aparece em confirmação de envio. Ajuda a correlacionar o ack sem expor o conteúdo da mensagem.
my_addons
Consulta de recursos adicionais da conta. No fluxo, aparece como checagem auxiliar antes de concluir o fanout.
enc
Filho da stanza que carrega o conteúdo cifrado pelo Signal. O texto real só aparece depois de decifrar.
pipeline
Linha do tempo completa da captura. Inclui eventos de transporte, frames, handshake, stanzas e fechamento.
seq
Número sequencial de um evento no pipeline. Ele permite dizer exatamente o que veio antes e depois.
sent
Direção cliente para servidor. No mapa aparece como C → S.
recv
Direção servidor para cliente. No mapa aparece como S → C.
attrs
Atributos de uma stanza, como nomes de campos. O relatório publica nomes, não valores sensíveis.
children
Filhos de uma stanza. Eles formam a árvore interna, por exemplo message contendo enc.
payload
Conteúdo carregado por um frame ou stanza. Pode ser bytes cifrados, árvore WAP ou dados redigidos.
opcode
Tipo técnico do frame WebSocket. Aqui o importante é saber quando ele carrega bytes binários.
redigido
Valor ocultado de propósito. A estrutura fica visível, mas telefone, token, chave, JID e payload bruto ficam fora.
captura canônica
Execução do WhatsApp Web oficial observada em detalhe. Ela vira a referência para comparar o cliente C#.
baseline
Registro de referência usado no diff. Se o C# divergir dele, a diferença aponta onde investigar.
fresh
Execução começando sem sessão salva. Por isso inclui pareamento novo, autenticação e primeiro bootstrap.
contrato
Forma esperada do evento: ordem, tag, attrs, filhos, direção e contagens. Valores variáveis não entram no contrato.
JSONL
Arquivo de dados com um JSON por linha. Foi usado como insumo local, mas não é publicado neste HTML.
cliente oficial
O WhatsApp Web real rodando no navegador. Ele é a fonte de verdade do projeto.
cliente C#
A implementação WaWeb que deve reproduzir a mesma estrutura do fluxo observado no cliente oficial.
celular principal
Aparelho dono da conta WhatsApp Business. Ele autoriza o PairCode e mantém a identidade principal.
celular auxiliar
Aparelho usado no teste para enviar a mensagem que aparece como recebida no fim da captura.

Marcos exatos da captura

Faixa Marco Contrato observado
Pipeline 9-23 Handshake Noise antes da primeira stanza client_hello → server_hello → client_finish
Stanza 1 Primeira oferta de pareamento recv iq / pair-device, ainda sem escolha da rota PairCode
Controller Usuário/controlador solicita PairCode paircode_user_action_started → requestPairingCode_called
Stanza 13 Pareamento aceito recv iq / pair-success
Stanza 17 Sessão autenticada recv success / lid + props + companion_enc_static
Resume seq 8-22 Sessão já logada pula pareamento pairing_code_mode=none → recv success, sem pair-device e sem PairCode
Stanza 140 Primeiro envio de texto sent message / participants + device-identity
Stanza 169 Mensagem com device_fanout observado sent message / device_fanout + device-identity
Stanza 152 Mensagem recebida do auxiliar recv message / enc + url_text + url_number + reporting