Skip to main content
El Chat XDK se encarga de la gestión de claves, cifrado, descifrado y firma para X Chat. No llama a la HTTP API de X—combínalo con el XDK de Python o TypeScript, o con HTTPS y un token de acceso de usuario. Recorrido de la app: Primeros pasos. Bots de ejemplo: chat-xdk/examples.

Instalar

El paquete de PyPI es chatxdk; impórtalo como chat_xdk. Requiere Python 3.10+.

Inicio rápido

Carga claves, establece tu identidad una vez, descifra un backlog, descifra un evento en vivo y cifra un mensaje. Conecta el cuerpo de envío a POST /2/chat/conversations/{id}/messages como se explica en Primeros pasos. Los snippets usan los dos almacenes de sesión opcionales para las formas más cortas de llamada: set_signing_keys mantiene las claves públicas de los demás participantes (obtenidas del endpoint de claves públicas) para que las llamadas de descifrado puedan verificar a los remitentes sin un argumento por llamada, y set_cache_keys(true) deja que el SDK recuerde la clave verificada de cada conversación para que las llamadas de cifrado solo necesiten el id de conversación y el texto. Omite cualquiera de los dos y pasa los mismos valores por llamada—ambos estilos verifican de forma idéntica; consulta Descifrar.

Ciclo de vida y claves

Construye el SDK, guarda las claves privadas (copia de seguridad segura de claves protegida por código de acceso o un blob de claves local), registra las claves públicas con la Chat API y llama a set_identity(user_id, signing_key_version) después de unlock o import—establece el remitente y la versión de clave de firma con la que cada acción firmada predetermina, de modo que los métodos encrypt y prepare funcionan sin argumentos de identidad por llamada. Llama a generate_keypairs una vez por identidad de dispositivo/app; envía el payload de registro al endpoint de claves públicas. Usa setup / unlock (y helpers de código de acceso relacionados) para la copia de seguridad segura de claves en cada binding. export_keys / import_keys (persistencia de blob de claves en bruto para bots y servidores) están disponibles solo en los bindings nativos—Python, Go, .NET, JVM y Rust. El binding JS/WASM no expone exportación o importación de claves en bruto: en un navegador, cualquier script que alcance la instancia podría exfiltrar la identidad, así que JS mantiene las claves dentro de la copia de seguridad segura de claves. Un servidor JS que quiera evitar un round-trip a un realm de respaldo por solicitud debería reutilizar una instancia Chat desbloqueada entre solicitudes, o correr un binding nativo donde los blobs de claves estén soportados. El SDK también necesita la versión que la X API reporta para tu clave pública registrada, de modo que las entradas de cambio de clave dirigidas a otras versiones se omiten. set_identity la registra junto con el id de usuario; import_keys la acepta directamente como argumento opcional (Rust y Go usan import_keys_with_version / ImportKeysWithVersion).
La configuración de copia de seguridad segura de claves acepta tres formas: el objeto juicebox_config de la X API (recomendado—pasado textualmente), un wrapper completo sdk_config, o un token_map desnudo. Opcional: la verificación de firmas está activa por defecto (reject_unverified = true)—llama a set_reject_unverified(false) para desactivarla (no recomendado); update_config si cambia la configuración del realm de respaldo; is_unlocked / has_identity_key para el estado de la UI. Las listas completas de campos viven en los stubs del repositorio chat-xdk.

Claves de conversación

Tres métodos prepare hacen que una sola llamada haga todo lo que un cambio de clave necesita: generar una clave de conversación nueva, cifrarla para cada participante (a partir de las claves públicas que pases) y firmar el cambio. La identidad del remitente y la versión de la clave de firma provienen de la sesión (set_identity); establece sender_id / signing_key_version en los params para sobrescribir. Todos devuelven la misma forma PreparedConversationChange, lista para hacer POST—renombra el campo del SDK encrypted_key a encrypted_conversation_key en conversation_participant_keys, y mapea las firmas de acción al campo del cuerpo requerido action_signatures. Conserva los bytes en bruto de la clave para encrypt_message y multimedia; nunca pases el sobre cifrado de la API a encrypt.
Verifica las claves recuperadas antes de envolverlas. Los métodos prepare cifran la nueva clave de conversación hacia cualesquiera claves públicas que le pases. Antes de pasarlas, llama a verify_key_binding(identity, signing, signature) en cada registro obtenido—sus campos public_key, signing_public_key e identity_public_key_signature de la API de claves públicas—para que una clave de identidad sustituida no pueda recibir la clave de conversación.
Usa extract_conversation_keys en payloads de eventos de cambio de clave para reconstruir { keys, latest_version }. decrypt_conversation_key desenvuelve un único blob ECIES.
Para group create y member adds, pasa los params que cada método necesita (listas de ids de miembros/admin para prepare_group_create; los nuevos más el roster actual para prepare_group_members_change)—consulta Grupos para ejemplos. Ambos devuelven dos firmas de acción; el POST debe incluir ambas.

Descifrar

decrypt_events es para historial y backlog: extrae las claves de conversación del stream, devuelve los mensajes descifrados y recopila errores por evento en lugar de fallar todo el lote. decrypt_event es para un solo evento en vivo; lanza/arroja en caso de fallo. Pasa claves de firma para que el SDK pueda verificar a los remitentes. Mapea los campos de clave pública de la API a SigningKeyEntry: public_key_versionpublic_key_version (mismo nombre), signing_public_keypublic_key, public_keyidentity_public_key, más identity_public_key_signature y user_id. Dos almacenes de sesión opcionales te permiten omitir los argumentos de clave por llamada:
  • set_signing_keys(entries) guarda las claves de firma de los participantes; una llamada de descifrado que omita (o pase vacío) el argumento de claves de firma usa el almacén en su lugar. La verificación en sí no cambia—las claves entran al almacén solo mediante esta llamada, nunca desde los eventos que se descifran. Cada llamada reemplaza el conjunto anterior.
  • set_cache_keys(true) habilita la caché de claves de conversación (desactivada por defecto). Mientras está activa, decrypt_events cachea, por conversación, la clave más reciente cuyo cambio de clave llevó una firma válida; decrypt_event recurre a ella cuando se omite su argumento de claves de conversación, y los helpers de cifrado resuelven una clave de conversación omitida a partir de ella. Desactivarla limpia la caché.
Un argumento explícito no vacío siempre gana sobre los almacenes. Los argumentos explícitos por llamada siguen siendo de primera clase—y son la elección correcta para despliegues serverless o multi-instancia, donde una solicitud puede caer en una instancia nueva cuyos almacenes están vacíos. La verificación es obligatoria por defecto: omitir las claves de firma nunca la salta. Sin nada pasado y nada almacenado, los eventos firmados fallan (recolectados en errors para decrypt_events, lanzados para decrypt_event). Para saltar realmente la verificación debes llamar primero a set_reject_unverified(false) (no recomendado en producción).

Cifrar y helpers de envío

encrypt_message(conversation_id, text) construye el texto cifrado firmado para un mensaje de texto; opcionales entities, attachments (mediante media_hash_key), should_notify y ttl_msec. La identidad del remitente se resuelve desde la sesión (set_identity) y la clave de conversación desde la caché de claves opcional (set_cache_keys)—o pasa sender_id / signing_key_version y conversation_key + conversation_key_version de forma explícita. El SDK genera el message_id (un UUID incrustado en el evento firmado) y lo devuelve en el payload—nunca acuñes el tuyo; reutiliza el mismo payload en los reintentos para que un id nunca se acuñe dos veces. Mapea el payload al cuerpo de send-message: message_idmessage_id, encrypted_contentencoded_message_create_event, encoded_event_signatureencoded_message_event_signature. Las respuestas son basadas en eventos. encrypt_reply(conversation_id, text, reply_to_event) toma el evento en bruto en base64 al que se responde. El SDK deriva la vista previa citada (sequence id, remitente, texto, entities, attachments) a partir de él e incrusta el original firmado en el mensaje saliente para que los destinatarios puedan validar la cita. Pasa reply_to_ckces—los eventos de cambio de clave en bruto—cuando el original se cifró bajo una versión de clave más antigua que la respuesta. Cuando el original fue editado, pasa el evento de edición en bruto como reply_to_edit_event: la vista previa cita entonces lo que el mensaje dice ahora (su texto y entities provienen de la edición) y la edición viaja junto al original para que el receptor la verifique. Los campos explícitos reply_to_* permanecen como sobrescrituras para llamadores que ya no tienen el evento en bruto. Las reacciones también son basadas en eventos. encrypt_add_reaction(target_event, emoji) y encrypt_remove_reaction(...) derivan el id de conversación y el sequence id objetivo a partir del evento en bruto al que se reacciona; los mismos params pueden agregar y luego quitar una reacción. Establece conversation_id y target_message_sequence_id de forma explícita solo cuando ya no tengas el evento en bruto. En el lado del receptor, un mensaje descifrado que cita una respuesta lleva reply_preview_validation ("Valid" / "Invalid"; el binding JS usa 'valid' / 'invalid'): el SDK verificó la firma del original incrustado contra tus claves de firma—nunca una clave transportada en el evento—lo descifró y comparó el contenido citado y el autor contra él. Cuando la vista previa incrusta un evento de edición, el SDK verifica la edición de la misma forma (misma conversación, mismo autor que el original) y comprueba el texto citado contra los contenidos editados en lugar del texto previo a la edición. El campo está ausente cuando el mensaje no lleva vista previa o la vista previa no incrusta un original. Trata las vistas previas Invalid como no confiables: el mensaje en sí es auténtico, pero el material citado no lo es—renderiza las citas solo desde el original validado. encrypt / decrypt son para metadatos UTF-8 bajo la clave de conversación (por ejemplo un nombre de grupo cifrado)—no sobres de mensaje. encrypt_stream / decrypt_stream cifran bytes de adjuntos; consulta Multimedia. Las funciones de bajo nivel sign / verify / verify_key_binding admiten flujos avanzados; los cambios de clave de conversación, group creates y member adds los firman los métodos prepare. El id de conversación pasado a encrypt_message / encrypt_reply puede tener cualquier forma que tengas—A:B de eventos, A-B de listados o rutas URL (en cualquier orden), o solo el id de usuario del destinatario—el SDK lo canonicaliza antes de firmar. Los ids de grupo (con prefijo g) pasan sin cambios.

Streams de multimedia

Cifra los bytes del archivo con la misma clave de conversación usada para el texto, sube mediante las APIs de multimedia del chat y adjunta media_hash_key en encrypt_message. Este no es el modelo de multimedia de Posts (expansions=attachments.media_keys). Flujo completo de subida/descarga: Multimedia.

Streaming incremental para multimedia grande

Para archivos grandes, evita mantener toda la carga útil en memoria: stream_encryptor() / stream_decryptor() devuelven un StreamEncryptor / StreamDecryptor que alimentas por fragmentos (de aproximadamente 1 MB cada uno) con push(chunk), y luego llamas a finish() una vez al final. Al descifrar, finish() detecta un stream truncado (falla si la entrada terminó antes del frame final), así que no trates el texto plano acumulado como completo hasta que finish() tenga éxito.
Solo JS/WASM: finish() consume y libera el objeto WASM subyacente—nunca llames a free() después de finish() (lanza excepción). Llama a free() solo para abandonar un stream antes de finalizarlo (por ejemplo, en una ruta de error).

Utilidades

Los helpers de base64/hex, detección MIME y dimensiones de imágenes están disponibles como funciones a nivel de módulo (Python/JS/Rust/Go) o en ChatXdkUtilities (C#/Java)—útiles al construir metadatos de adjuntos sin traer librerías adicionales.

Tipos importantes

Estos tipos conceptuales aparecen entre lenguajes (los nombres exactos de campos difieren; JS suele usar discriminadores de evento en camelCase como message):
  • SendPayload — valor de retorno de encrypt_message y los demás helpers de cifrado: el message_id generado por el SDK (un UUID incrustado en el evento firmado—envíalo como el message_id del mensaje y consérvalo para deduplicar), encrypted_content, encoded_event_signature, metadatos de firma, conversation_key_version y should_notify. Mapea al cuerpo de send de la Chat API.
  • PublicKeyRegistrationPayload — salida de generate_keypairs / getters de clave pública para la API de add-public-key.
  • SigningKeyEntry — material público del remitente pasado a decrypt para verificación de firmas, o almacenado mediante set_signing_keys.
  • PreparedConversationChange — salida de los tres métodos prepare: el conversation_id derivado o pasado, los bytes en bruto de conversation_key, conversation_key_version, participant_keys (user_id, encrypted_key, public_key_version) y action_signatures (message_id, encoded_message_event_detail, signature, signature_version, public_key_version, signature_payload opcional—omitido en las firmas de cambio de clave porque ese payload incrusta la clave en texto plano).
  • DecryptEventsResult — messages, errors opcional y conversation_keys extraídas. Los mensajes descifrados que citan una respuesta llevan reply_preview_validation (consulta Cifrar y helpers de envío).
Para listas completas de campos, usa los stubs de lenguaje en el repositorio chat-xdk (docs/API.md, *.pyi, index.d.ts).

Errores

Python normalmente lanza ValueError con un mensaje descriptivo (por ejemplo, un código de acceso inválido). TypeScript/JavaScript lanza Error. Go devuelve (value, error). Prefiere decrypt_events para el historial, así un evento defectuoso no aborta el lote; inspecciona la colección de errores para fallos parciales. Algunos errores de verificación son permanentes. Las firmas son inmutables y se verifican reconstruyendo el payload firmado desde el evento en sí, así que un evento antiguo que falla con signature missing or no matching signing key o un desajuste ECDSA fallará en cada carga futura—ninguna reintentación, actualización de claves o llamada a la API puede sanarlo. Trata estos como tombstones, no como errores transitorios. Rotar la clave de conversación inicia un historial limpio y verificable desde ese punto en adelante.

Próximos pasos

Primeros pasos

Conecta el Chat XDK a la Chat API

Multimedia

Cifrado de streams y REST de multimedia

Eventos en tiempo real

Webhooks y entrega de actividad

Solución de problemas

Fallos comunes