Skip to main content
O Chat XDK cuida da gestão de chaves, criptografia, descriptografia e assinatura para o X Chat. Ele não chama a X HTTP API — combine-o com o XDK Python ou TypeScript, ou com HTTPS e um token de acesso do usuário. Passo a passo do app: Guia de introdução. Bots de exemplo: chat-xdk/examples.

Instalar

O pacote no PyPI é chatxdk; importe-o como chat_xdk. Requer Python 3.10+.

Início rápido

Carregue as chaves, defina sua identidade uma vez, descriptografe um backlog, descriptografe um evento ao vivo, criptografe uma mensagem. Conecte o corpo de envio a POST /2/chat/conversations/{id}/messages como em Guia de introdução. Os snippets usam os dois armazenamentos de sessão opcionais para as formas de chamada mais curtas: set_signing_keys mantém as chaves públicas dos outros participantes (buscadas do endpoint de chaves públicas) para que as chamadas de decrypt possam verificar remetentes sem um argumento por chamada, e set_cache_keys(true) permite que o SDK memorize a chave verificada de cada conversa para que as chamadas de encrypt precisem apenas do ID da conversa e do texto. Pule qualquer um deles e passe os mesmos valores por chamada — os dois estilos verificam de forma idêntica; veja Descriptografar.

Ciclo de vida e chaves

Construa o SDK, armazene as chaves privadas (backup seguro de chaves protegido por código de acesso ou um blob de chave local), registre as chaves públicas com a Chat API e chame set_identity(user_id, signing_key_version) após unlock ou import — isso define o remetente e a versão de chave de assinatura que toda ação assinada usa por padrão, para que os métodos de encrypt e prepare funcionem sem argumentos de identidade por chamada. Chame generate_keypairs uma vez por identidade de dispositivo/app; poste o payload de registro para o endpoint de chaves públicas. Use setup / unlock (e helpers de código de acesso relacionados) para backup seguro de chaves em todos os bindings. export_keys / import_keys (persistência de blob de chave em bruto para bots e servidores) estão disponíveis apenas nos bindings nativos — Python, Go, .NET, JVM e Rust. O binding JS/WASM não expõe exportação ou importação de chaves em bruto: em um navegador, qualquer script que alcance a instância poderia exfiltrar a identidade, então JS mantém as chaves dentro do backup seguro de chaves. Um servidor JS que quer evitar um round-trip ao realm de backup por requisição deve reutilizar uma única instância Chat desbloqueada entre requisições, ou rodar um binding nativo onde blobs de chave são suportados. O SDK também precisa da versão que a X API reporta para sua chave pública registrada, para que entradas de mudança de chave voltadas a outras versões sejam ignoradas. set_identity a registra junto com o ID do usuário; import_keys a aceita diretamente como argumento opcional (Rust e Go usam import_keys_with_version / ImportKeysWithVersion).
A configuração de backup seguro de chaves aceita três formatos: o objeto juicebox_config da X API (recomendado — passado literalmente), um wrapper sdk_config completo, ou um token_map puro. Opcional: a verificação de assinatura está ativa por padrão (reject_unverified = true) — chame set_reject_unverified(false) para desativá-la (não recomendado); update_config se a configuração do realm de backup mudar; is_unlocked / has_identity_key para estado de UI. Listas completas de campos vivem nos stubs do repositório chat-xdk.

Chaves de conversa

Três métodos prepare fazem, cada um, com uma chamada tudo o que uma mudança de chave precisa: gerar uma nova chave de conversa, criptografá-la para cada participante (a partir das chaves públicas que você passa) e assinar a mudança. A identidade do remetente e a versão de chave de assinatura vêm da sessão (set_identity); defina sender_id / signing_key_version nos params para sobrescrever. Todos retornam o mesmo formato PreparedConversationChange, pronto para POST — renomeie o campo do SDK encrypted_key para encrypted_conversation_key em conversation_participant_keys e mapeie as assinaturas de ação para o campo obrigatório action_signatures do corpo. Mantenha os bytes da chave em bruto para encrypt_message e mídia; nunca passe o envelope criptografado da API para encrypt.
Verifique as chaves buscadas antes de envelopar. Os métodos prepare criptografam a nova chave de conversa para quaisquer chaves públicas que você passar. Antes de passá-las, chame verify_key_binding(identity, signing, signature) em cada registro obtido — seus campos public_key, signing_public_key e identity_public_key_signature da API de chaves públicas — para que uma chave de identidade substituída não possa receber a chave de conversa.
Use extract_conversation_keys em payloads de eventos de mudança de chave para reconstruir { keys, latest_version }. decrypt_conversation_key desembrulha um único blob ECIES.
Para criação de grupo e adições de membros, passe os params que cada método precisa (listas de IDs de membros/admins para prepare_group_create; nova mais lista atual para prepare_group_members_change) — veja Grupos para exemplos. Ambos retornam duas assinaturas de ação; o POST precisa incluir ambas.

Descriptografar

decrypt_events é para histórico e backlog: puxa chaves de conversa do stream, retorna mensagens descriptografadas e coleta erros por evento em vez de falhar o lote inteiro. decrypt_event é para um único evento ao vivo; lança erro em caso de falha. Passe as chaves de assinatura para que o SDK possa verificar os remetentes. Mapeie campos de chave pública da API para SigningKeyEntry: public_key_versionpublic_key_version (mesmo nome), signing_public_keypublic_key, public_keyidentity_public_key, mais identity_public_key_signature e user_id. Dois armazenamentos de sessão opt-in permitem omitir os argumentos de chave por chamada:
  • set_signing_keys(entries) armazena as chaves de assinatura dos participantes; uma chamada de decrypt que omite (ou passa vazio) o argumento de signing-keys usa o armazenamento. A verificação em si não muda — as chaves entram no armazenamento apenas por essa chamada, nunca a partir dos eventos sendo descriptografados. Cada chamada substitui o conjunto anterior.
  • set_cache_keys(true) habilita o cache de chaves de conversa (desligado por padrão). Enquanto habilitado, decrypt_events faz cache, por conversa, da chave mais recente cuja mudança de chave carregou uma assinatura válida; decrypt_event recorre a ela quando seu argumento de chaves de conversa é omitido, e os helpers de encrypt resolvem uma chave de conversa omitida a partir dele. Desabilitar limpa o cache.
Um argumento explícito não vazio sempre vence sobre os armazenamentos. Argumentos explícitos por chamada continuam sendo de primeira classe — e são a escolha certa para deployments serverless ou multi-instância, onde uma requisição pode cair em uma instância nova cujos armazenamentos estão vazios. A verificação é obrigatória por padrão: omitir as chaves de assinatura nunca a pula. Sem nada passado e nada armazenado, eventos assinados falham (coletados em errors para decrypt_events, lançados para decrypt_event). Para efetivamente pular a verificação você precisa primeiro chamar set_reject_unverified(false) (não recomendado em produção).

Helpers de criptografia e envio

encrypt_message(conversation_id, text) constrói o texto cifrado assinado para uma mensagem de texto; opcionais entities, attachments (via media_hash_key), should_notify e ttl_msec. A identidade do remetente é resolvida a partir da sessão (set_identity) e a chave de conversa a partir do cache de chaves opt-in (set_cache_keys) — ou passe sender_id / signing_key_version e conversation_key + conversation_key_version explicitamente. O SDK gera o message_id (um UUID embutido no evento assinado) e o retorna no payload — nunca crie o seu; reutilize o mesmo payload em reenvios para que um ID nunca seja cunhado duas vezes. Mapeie o payload para o corpo de envio: message_idmessage_id, encrypted_contentencoded_message_create_event, encoded_event_signatureencoded_message_event_signature. Respostas são baseadas em eventos. encrypt_reply(conversation_id, text, reply_to_event) recebe o evento em bruto base64 que está sendo respondido. O SDK deriva dela a pré-visualização citada (sequence id, remetente, texto, entidades, anexos) e embute o original assinado na mensagem de saída para que os destinatários possam validar a citação. Passe reply_to_ckces — os eventos brutos de mudança de chave — quando o original tiver sido criptografado sob uma versão de chave mais antiga do que a resposta. Quando o original foi editado, passe o evento bruto de edição como reply_to_edit_event: a pré-visualização então cita o que a mensagem diz agora (seu texto e entidades vêm da edição), e a edição viaja junto com o original para o destinatário conferir. Os campos explícitos reply_to_* continuam disponíveis como sobrescritas para chamadores que já não têm o evento em bruto. Reações também são baseadas em eventos. encrypt_add_reaction(target_event, emoji) e encrypt_remove_reaction(...) derivam o ID da conversa e o sequence id alvo do evento em bruto que está sendo reagido; os mesmos params podem adicionar e depois remover uma reação. Defina conversation_id e target_message_sequence_id explicitamente somente quando você não tiver mais o evento em bruto. Do lado do recebedor, uma mensagem descriptografada que cita uma resposta carrega reply_preview_validation ("Valid" / "Invalid"; o binding JS usa 'valid' / 'invalid'): o SDK verificou a assinatura do original embutido contra suas chaves de assinatura — nunca uma chave carregada no evento — o descriptografou e comparou o conteúdo citado e o autor contra ele. Quando a pré-visualização embute um evento de edição, o SDK verifica a edição da mesma forma (mesma conversa, mesmo autor do original) e confere o texto citado contra o conteúdo editado, e não contra o texto pré-edição. O campo está ausente quando a mensagem não carrega pré-visualização ou a pré-visualização não embute um original. Trate pré-visualizações Invalid como não confiáveis: a mensagem em si é autêntica, mas o material citado não é — renderize citações apenas a partir do original validado. encrypt / decrypt são para metadados UTF-8 sob a chave de conversa (por exemplo, um nome de grupo criptografado) — não envelopes de mensagem. encrypt_stream / decrypt_stream criptografam bytes de anexos; veja Mídia. sign / verify / verify_key_binding de baixo nível suportam fluxos avançados; mudanças de chave de conversa, criações de grupo e adições de membros são assinadas pelos métodos prepare. O ID de conversa passado para encrypt_message / encrypt_reply pode ser qualquer forma que você tenha — A:B de eventos, A-B de listagens ou paths de URL (em qualquer ordem), ou apenas o ID de usuário do destinatário — o SDK o canonicaliza antes de assinar. IDs de grupo (prefixados com g) passam sem alteração.

Streams de mídia

Criptografe bytes de arquivo com a mesma chave de conversa usada para texto, faça upload via APIs de mídia do Chat e anexe media_hash_key em encrypt_message. Este não é o modelo de mídia de Posts (expansions=attachments.media_keys). Fluxo completo de upload/download: Mídia.

Streaming incremental para mídia grande

Para arquivos grandes, evite manter o payload inteiro em memória: stream_encryptor() / stream_decryptor() retornam um StreamEncryptor / StreamDecryptor que você alimenta em chunks (cerca de 1 MB cada) com push(chunk), e depois chama finish() uma vez ao final. Na descriptografia, finish() detecta um stream truncado (falha se a entrada terminou antes do frame final), então não trate texto simples enviado com push como completo até que ele seja bem-sucedido.
Apenas JS/WASM: finish() consome e libera o objeto WASM subjacente — nunca chame free() após finish() (ele lança). Chame free() apenas para abandonar um stream antes de finalizar (por exemplo, em uma rota de erro).

Utilitários

Helpers de base64/hex, detecção de MIME e dimensões de imagem estão disponíveis como funções de nível de módulo (Python/JS/Rust/Go) ou ChatXdkUtilities (C#/Java) — úteis ao construir metadados de anexos sem depender de bibliotecas extras.

Tipos importantes

Estes tipos conceituais aparecem entre linguagens (nomes exatos de campos diferem; JS usa frequentemente discriminadores de evento em camelCase como message):
  • SendPayload — valor de retorno de encrypt_message e dos outros helpers de encrypt: o message_id gerado pelo SDK (um UUID embutido no evento assinado — envie-o como message_id da mensagem e guarde-o para deduplicação), encrypted_content, encoded_event_signature, metadados de assinatura, conversation_key_version e should_notify. Mapeie para o corpo de envio da Chat API.
  • PublicKeyRegistrationPayload — saída de generate_keypairs / getters de chave pública para a API add-public-key.
  • SigningKeyEntry — material público do remetente passado para decrypt para verificação de assinatura, ou armazenado via set_signing_keys.
  • PreparedConversationChange — saída dos três métodos prepare: o conversation_id derivado ou passado, os bytes brutos de conversation_key, conversation_key_version, participant_keys (user_id, encrypted_key, public_key_version) e action_signatures (message_id, encoded_message_event_detail, signature, signature_version, public_key_version, opcional signature_payload — omitido em assinaturas de mudança de chave porque esse payload embute a chave em texto simples).
  • DecryptEventsResult — mensagens, erros opcionais e conversation_keys extraídas. Mensagens descriptografadas que citam uma resposta carregam reply_preview_validation (veja Helpers de criptografia e envio).
Para listas completas de campos, use os stubs de linguagem do repositório chat-xdk (docs/API.md, *.pyi, index.d.ts).

Erros

Python normalmente lança ValueError com uma mensagem descritiva (por exemplo, um código de acesso inválido). TypeScript/JavaScript lança Error. Go retorna (value, error). Prefira decrypt_events para histórico para que um evento ruim não aborte o lote; inspecione a coleção de erros para falhas parciais. Alguns erros de verificação são permanentes. Assinaturas são imutáveis e verificadas reconstruindo o payload assinado a partir do próprio evento, então um evento antigo que falha com signature missing or no matching signing key ou uma incompatibilidade ECDSA falhará em cada carregamento futuro — nenhuma nova tentativa, atualização de chave ou chamada de API pode curá-lo. Trate-os como lápides, não como erros transitórios. Rotacionar a chave de conversa inicia um histórico limpo e verificável a partir daquele ponto.

Próximos passos

Guia de introdução

Conecte o Chat XDK à Chat API

Mídia

Criptografia de streams e REST de mídia

Eventos em tempo real

Webhooks e entrega por atividade

Solução de problemas

Falhas comuns