Los clientes ven un estado honesto de pendiente o reconexión y los mensajes aceptados no se duplican ni se descartan en silencio.
Usa idempotency keys estables
Genera una idempotency key por cada intención del usuario y consérvala hasta que el SDK informe de un resultado aceptado. El motor nativo guarda el body exacto, la marca de tiempo y la clave en la outbox duradera de la cuenta antes de resolver la escritura. No generes otra clave solo porque el ACK se retrase.
El widget web controla su UI de reconexión y pendiente. Los clientes móviles headless exponen resumeSession, refresh y flushOutbox para que el host pueda ofrecer un reintento explícito cuando la misma cuenta reciba un token nuevo. El código siguiente usa la forma del wrapper de TypeScript (startSession(message, options) y sendMessage(text, idempotencyKey)). Dart usa las mismas operaciones con sendMessage(text, idempotencyKey: key). Los clientes Swift y Kotlin directos usan sus DTO de plataforma con la misma regla de clave estable, como muestran sus referencias de plataforma.
const sessionKey = `order-${orderId}-session-${attemptId}`;
const messageKey = `order-${orderId}-question-${attemptId}`;
// Persist each key with its own user intent until the SDK acknowledges it.
await client.startSession("I need help with my order", {
idempotencyKey: sessionKey,
});
await client.sendMessage("The order number is ORD-42", messageKey);
// Call this only from an explicit "Retry the same message" control after
// connectivity and a fresh token for the same account are available.
async function retryPendingMessage() {
await client.resumeSession();
await client.flushOutbox();
}Distingue resultados pendientes, rechazados y duplicados
Un error de red o de limitación puede dejar incierta la admisión. Conserva la mutación original para un reintento explícito con la misma clave. Los errores field-invalid, payload-too-large, message-rejected o idempotency-conflict requieren corregir o investigar el host y no deben repetirse automáticamente con otra clave.
Un resultado session-expired requiere un token firmado nuevo para la misma cuenta antes del reintento. No llames a resetSession por una interrupción temporal porque reset borra intencionadamente la sesión duradera y las mutaciones pendientes.
Haz visible el estado sin conexión
- Muestra una etiqueta de pendiente o reconexión vinculada al estado de carga del SDK y mantén disponible el composer solo cuando el host pueda aceptar otra intención con seguridad.
- Ofrece Retry the same message cuando se recuperen la conectividad y la autenticación. Conserva la idempotency key original detrás del control y desactiva el envío duplicado mientras esté en curso.
- Si el usuario descarta la conversación de forma intencionada, llama a resetSession y muestra el resultado del descarte. Nunca borres el estado duradero solo porque la app pasó a segundo plano.