Formularios de Comunicación: recibir solicitudes desde tu sitio o tu sistema
Los formularios de Comunicación reciben solicitudes —contacto, cotización, reclamo, ejercicio de derechos sobre datos personales— y cada una entra a la bandeja de tu equipo como un caso con número, plazo y responsable. La persona recibe un acuse por correo con ese número. Esta guía explica las tres formas de hacer llegar esas solicitudes: incrustando el formulario en tu sitio, con tu propio formulario HTML, o desde tu servidor.
Tres formas de que entre una solicitud
Sección titulada «Tres formas de que entre una solicitud»Un mismo formulario recibe solicitudes por tres puertas, y las tres crean el mismo caso: igual tipo, campos, plazo y destino. Sólo cambia la puerta que queda registrada.
| Puerta | Quién envía | Credencial | Cuándo conviene |
|---|---|---|---|
| Alojada | Una persona, en la página del formulario o en el formulario incrustado en tu sitio | Ninguna, con captcha | Quieres el formulario listo, sin programar. Ver Incrustar el formulario |
| Pública | El navegador de la persona, desde tu propio formulario HTML | Ninguna, con captcha | Quieres que el formulario tenga el diseño de tu sitio. Ver Tu propio formulario HTML |
| Servidor | Tu sistema, de servidor a servidor | Una API key de tu empresa | Tu sistema ya tiene los datos. Ver Desde tu servidor |
La puerta alojada y la pública son anónimas: quien llena el formulario no tiene cuenta. Por eso tienen defensas que no se pueden apagar: captcha, campo trampa, tope de envíos por visitante y por IP, y la cuota diaria de tu empresa. La de servidor no las tiene, porque la API key ya identifica a tu empresa.
Antes de empezar
Sección titulada «Antes de empezar»1. El servicio Comunicación habilitado
Sección titulada «1. El servicio Comunicación habilitado»Si tu empresa no tiene el servicio, no puedes crear formularios y la puerta de servidor responde 403
diciéndolo.
2. Un formulario publicado
Sección titulada «2. Un formulario publicado»Los formularios se crean y se publican en el panel, en Comunicación → Tipos de solicitud y
formularios. Sólo se puede enviar a un formulario publicado: uno en borrador o despublicado
responde 409 FORMULARIO_NO_PUBLICADO, y uno archivado responde 404.
De cada formulario necesitas, según la puerta:
- El identificador del formulario (
idPublico): 22 letras y números. Está en la pestaña Publicar, en la sección «Enviar desde tu servidor». Lo usan la puerta pública y la de servidor. - La clave de cada campo: en la pestaña Campos, cada campo muestra su «Identificador
interno» (por ejemplo
correoomensaje). Son las claves decamposy dearchivos, en la puerta pública y en la de servidor.
Qué valor lleva cada tipo de campo
Sección titulada «Qué valor lleva cada tipo de campo»Vale para la puerta pública y la de servidor:
| Tipo de campo (en el panel) | Valor en campos |
|---|---|
| Texto corto | Texto, hasta 200 caracteres |
| Texto largo | Texto, hasta 5.000 caracteres |
| Correo electrónico | Texto con un correo válido, hasta 254 caracteres |
| Teléfono | Texto, hasta 20 caracteres |
| RUT | Texto, con o sin puntos y guion. Se valida el dígito verificador |
| Lista de opciones | El valor de la opción, no su etiqueta. Si admite varias, un arreglo de valores sin repetir |
| Casilla | true o false. Una casilla obligatoria o de declaración tiene que ir en true |
| Archivo | No va en campos: va en archivos, con su archivoId. Ver Adjuntar archivos |
Un campo obligatorio que no mandas, o un valor que no cumple su tipo, responde 422 CAMPO_INVALIDO
con el campo y el motivo. Nunca se rellena un valor faltante ni se crea la solicitud a medias.
Un campo que el formulario no define se rechaza
Sección titulada «Un campo que el formulario no define se rechaza»Si mandas una clave que el formulario no tiene, el envío responde 422 con todas esas claves, y no
se crea nada:
{ "statusCode": 422, "error": "CAMPO_NO_DEFINIDO", "message": "Los campos «empresa_x» no existen en este formulario", "campos": ["empresa_x"]}Es a propósito: un dato que tu integración cree estar enviando y que la plataforma descartara en silencio sería un dato perdido. Si alguien de tu equipo elimina un campo del formulario, te enteras en el primer envío, no semanas después.
En la práctica, esto quiere decir que tu código manda sólo las claves que el formulario define:
si tu formulario HTML tiene inputs propios (un buscador, un campo de tu analítica), no los mandes.
Lo más simple es una lista blanca que traduzca el name de cada input a la clave del campo.
Desde tu sitio
Sección titulada «Desde tu sitio»Incrustar el formulario
Sección titulada «Incrustar el formulario»Es lo más rápido: el formulario lo dibuja la plataforma, con los colores y el logo que configuraste en la pestaña Presentación, y el captcha y la sesión ya vienen resueltos.
En la pestaña Publicar del formulario, la sección «Compartir el formulario» tiene dos cosas:
- El enlace: una página propia del formulario, para compartir por correo, redes o un código QR.
- El código para incrustar: un
<iframe>y un<script>que pegas en tu sitio donde quieras el formulario. El script ajusta el alto del iframe al contenido, para que no aparezcan barras de desplazamiento.
Una solicitud que llega así queda con la puerta alojada.
Tu propio formulario HTML
Sección titulada «Tu propio formulario HTML»Si quieres que el formulario sea parte del diseño de tu sitio, puedes hacer tu propio <form> y
mandarlo desde el navegador a la puerta pública. No necesitas backend: la puerta responde a
cualquier origen (CORS abierto, sin cookies ni cabeceras propias), así que un sitio estático puede
hablarle directo.
El envío tiene tres pasos:
1. GET /public/comunicacion/formularios/{idPublico}2. GET /public/comunicacion/formularios/{idPublico}/desafio3. POST /public/comunicacion/formularios/{idPublico}/envios- Definición: los campos, el texto informativo y la
sesiondel visitante, firmada y válida por 2 horas. - Desafío: un captcha que el navegador resuelve solo, sin que la persona haga nada.
- Envío: responde
201con el número de la solicitud.
Pide la definición al cargar la página o cuando la persona empieza a escribir, no al enviar: así
también puedes mostrar el texto informativo que configuraste. Si el formulario está despublicado,
la definición responde { "estado": "despublicado", "mensaje": "…" } y conviene mostrar ese mensaje
en vez del formulario.
El desafío
Sección titulada «El desafío»El captcha es de ALTCHA: una prueba de trabajo que el navegador calcula, sin
imágenes que resolver. El desafío trae algorithm, challenge, salt, signature y maxnumber;
hay que encontrar el número n tal que el SHA-256 de salt + n sea igual a challenge, y mandar la
solución en base64. Cada solución sirve para un solo envío y vence a los 5 minutos: pide un
desafío nuevo para cada envío.
async function resolverDesafio(base) { const d = await (await fetch(`${base}/desafio`)).json(); for (let n = 0; n <= d.maxnumber; n++) { const bytes = new TextEncoder().encode(d.salt + n); const hash = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes)); const hex = Array.from(hash, (b) => b.toString(16).padStart(2, '0')).join(''); if (hex === d.challenge) { return btoa(JSON.stringify({ algorithm: d.algorithm, challenge: d.challenge, number: n, salt: d.salt, signature: d.signature, })); } } throw new Error('No se pudo resolver el desafío');}crypto.subtle sólo existe en páginas servidas por https (o en localhost).
El envío
Sección titulada «El envío»const base = 'https://api.redcumbre.cl/public/comunicacion/formularios/{idPublico}';
const definicion = await (await fetch(base)).json(); // al cargar la página
async function enviar(campos, trampa) { const res = await fetch(`${base}/envios`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sesion: definicion.sesion, altcha: await resolverDesafio(base), trampa, // el valor del campo trampa: una persona lo deja vacío campos, // { nombre: '…', correo: '…', mensaje: '…' } }), }); return { status: res.status, cuerpo: await res.json() };}La respuesta trae el número y lo que hay que mostrar al terminar, según lo que configuraste en el panel: un texto o una dirección a la que llevar a la persona.
{ "numero": 42, "exito": { "texto": "Recibimos tu solicitud N° 42. Te enviamos un correo con el detalle." } }{ "numero": 42, "exito": { "redireccion": "https://www.tu-empresa.cl/gracias" } }La respuesta no trae nada más: con el identificador del formulario no se puede leer ninguna solicitud.
Dominios autorizados
Sección titulada «Dominios autorizados»En la pestaña Presentación, «Dominios autorizados» limita desde qué sitios se acepta un envío por
la puerta pública: por ejemplo tu-empresa.cl, que cubre también sus subdominios. Si declaras
dominios, un envío desde otro sitio —o sin la cabecera Origin, que el navegador manda sola—
responde 403 ORIGEN_NO_DECLARADO. Sin dominios declarados, se acepta desde cualquiera.
Este filtro reduce el ruido de quien copia tu formulario en otro sitio, pero no es un control de acceso: un programa que no es un navegador puede declarar el origen que quiera. Lo que contiene el abuso son el captcha, los topes y la cuota.
Topes y cuota
Sección titulada «Topes y cuota»| Límite | Valor | Al pasarlo |
|---|---|---|
| Envíos por visitante, por formulario | 5 por hora (el visitante es la sesión) | 429 |
| Envíos por IP | 30 por hora | 429 |
| Desafíos por IP | 60 por minuto | 429 |
| Archivos por sesión | 10 | 429 |
| Cuota diaria de tu empresa | 1.000 envíos al día, salvo que REDCUMBRE haya fijado otra para tu empresa | 429 CUOTA_DIARIA_ALCANZADA |
El 429 de la cuota diaria trae el código en codigo y el texto en mensaje, no en error y
message. Un formulario de ejercicio de derechos no se rechaza por la cuota: la solicitud entra
retenida, y tu equipo decide en la bandeja si es legítima: el ejercicio de un derecho no se
pierde por volumen. La puerta de servidor no cuenta para la cuota.
Archivos desde el navegador
Sección titulada «Archivos desde el navegador»Igual que en la puerta de servidor, primero subes y después envías. La subida
es POST /public/comunicacion/formularios/{idPublico}/archivos en multipart/form-data, con el
archivo en el campo archivo y la sesión en el campo sesion. Devuelve { archivoId }, que va en
archivos del envío. El archivo queda ligado a esa sesión: con otra, el envío responde
422 ARCHIVO_NO_DISPONIBLE. La subida no lleva captcha; el desafío viaja en el envío.
Errores de la puerta pública
Sección titulada «Errores de la puerta pública»| Código | Qué pasó | Qué hacer |
|---|---|---|
401 SESION_FORMULARIO_INVALIDA | La sesión falta, venció (2 horas) o es de otro formulario | Pide la definición otra vez y reintenta, sin borrar lo que escribió la persona |
403 sin código | El captcha falta, es inválido o ya se usó | Pide un desafío nuevo |
403 ORIGEN_NO_DECLARADO | El sitio no está entre los dominios autorizados | Revisa la pestaña Presentación |
404 | El formulario no existe o está archivado. La definición también responde 404 si está en borrador | Revisa el identificador |
409 FORMULARIO_NO_PUBLICADO | El formulario se despublicó | Muestra el mensaje de la definición |
422 CAMPO_INVALIDO | Un valor no cumple: vienen campo y motivo | Muestra el error junto al campo |
422 CAMPO_NO_DEFINIDO | Mandaste una clave que el formulario ya no tiene | Ajusta la lista de campos que mandas |
429 | Un tope o la cuota diaria | Pide a la persona que lo intente más tarde |
Los 422 y el 403 de origen llevan el código en error: decide por el código, no por el texto.
Desde tu servidor
Sección titulada «Desde tu servidor»Una API key con el rol COMUNICACION_SOLICITUDES_CREAR
Sección titulada «Una API key con el rol COMUNICACION_SOLICITUDES_CREAR»La llave la crea un administrador de tu empresa en el panel, en General → API Keys. En el desplegable de rol, el que corresponde es Comunicación — crear solicitudes.
El rol es angosto a propósito: permite crear solicitudes y subir sus archivos, y nada más.
Con esa llave no se leen casos, no se listan formularios y no se configura nada: cualquier otra
operación responde 403. Así, si la llave se filtra desde tu servidor, quien la tenga puede crear
solicitudes pero no puede leer ninguna de las que ya recibiste.
Una llave revocada responde 401 desde la llamada siguiente.
Crear una solicitud
Sección titulada «Crear una solicitud»curl -X POST "https://api.redcumbre.cl/{tenantSlug}/comunicacion/solicitudes" \ -H "Authorization: Bearer {api_key}" \ -H "Content-Type: application/json" \ -d '{ "formulario": "4fT9kQ2mXbR7vLpZ1cN8sW", "claveIdempotencia": "contacto-pedido-4471", "referencia": "pedido-4471", "persona": { "idExterno": "cliente-0932" }, "campos": { "nombre": "María Soto", "correo": "maria.soto@ejemplo.cl", "rut": "12.345.678-5", "motivo": "despacho", "mensaje": "El pedido llegó incompleto.", "acepta_contacto": true } }'Respuesta:
{ "numero": 42, "sandbox": false }numero es el número de la solicitud dentro de tu empresa: el mismo que ve tu equipo en la bandeja.
La respuesta no trae nada más, ni el estado, ni la persona, ni los campos: la puerta de servidor
sólo crea.
| Campo | Qué es |
|---|---|
formulario | El identificador del formulario (22 caracteres) |
claveIdempotencia | Una clave de tu sistema que hace seguro el reintento. Ver Reintentar sin duplicar |
campos | Los valores, por clave de campo |
archivos | El archivoId de cada campo de tipo archivo. Ver Adjuntar archivos |
referencia | Opcional. Un texto de tu sistema que queda con la solicitud y vuelve en cada aviso |
persona.idExterno | Opcional. El identificador de la persona en tu sistema |
Los tipos y los largos exactos están en Swagger.
Reintentar sin duplicar
Sección titulada «Reintentar sin duplicar»claveIdempotencia es obligatoria, de 8 a 100 caracteres. Si repites la llamada con la misma clave,
la respuesta es 200 con el mismo número: no se crea otra solicitud y la persona no recibe
otro acuse. El primer envío responde 201.
| Respuesta | Qué significa |
|---|---|
201 { numero } | Solicitud creada |
200 { numero } | Esa clave ya tenía solicitud: es la misma, no se creó otra |
La clave vale por empresa, y la llave de prueba y la real tienen cada una su espacio: una clave que usaste probando no choca con la misma clave en real.
Esta clave es propia de los formularios y va en el cuerpo, como claveIdempotencia. No es la
idempotencyKey de los documentos tributarios descrita en
Reglas transversales.
Adjuntar archivos
Sección titulada «Adjuntar archivos»Si el formulario tiene campos de tipo archivo, el envío va en dos pasos: primero subes cada archivo y después creas la solicitud con los identificadores que te devolvió la subida.
1. Subir el archivo
Sección titulada «1. Subir el archivo»curl -X POST "https://api.redcumbre.cl/{tenantSlug}/comunicacion/solicitudes/archivos" \ -H "Authorization: Bearer {api_key}" \ -F "archivo=@boleta.pdf"{ "archivoId": "cmb2x7k1p0003qz8f4h2d9n1e", "sandbox": false }2. Crear la solicitud con el archivo
Sección titulada «2. Crear la solicitud con el archivo»{ "formulario": "4fT9kQ2mXbR7vLpZ1cN8sW", "claveIdempotencia": "reclamo-pedido-4471", "campos": { "correo": "maria.soto@ejemplo.cl", "mensaje": "Adjunto la boleta." }, "archivos": { "comprobante": "cmb2x7k1p0003qz8f4h2d9n1e" }}Reglas de los archivos:
- Tipos: PDF, JPEG y PNG, reconocidos por su contenido, no por la extensión ni por el tipo
que declares. Un ejecutable renombrado a
.pdfse rechaza al subirlo. - Tamaño: hasta 10 MB por archivo. Uno más grande se corta en la subida con
413. - Cuántos: hasta 10 subidas por llave cada 24 horas.
- Quién lo usa: el archivo queda ligado a la llave que lo subió. Crear la solicitud con otra
llave responde
422 ARCHIVO_NO_DISPONIBLE. - Cuánto dura: un archivo que no se usa en una solicitud dentro de 24 horas se borra.
| Rechazo | Cuándo |
|---|---|
422 ARCHIVO_TIPO_NO_PERMITIDO | Al subir: el contenido no es PDF, JPEG ni PNG |
413 | Al subir: el archivo pasa de 10 MB |
422 ARCHIVO_NO_DISPONIBLE | Al crear la solicitud: el archivo no existe, venció o lo subió otra llave |
Tu equipo descarga los archivos desde el caso, en el panel. No hay una URL pública del archivo.
Errores de la puerta de servidor
Sección titulada «Errores de la puerta de servidor»| Código | Qué pasó | ¿Reintentar? |
|---|---|---|
401 | Falta la llave, no es válida o fue revocada | No. Revisa el header Authorization |
403 | La llave no tiene el rol COMUNICACION_SOLICITUDES_CREAR, o tu empresa no tiene el servicio Comunicación | No |
404 | El formulario no existe en tu empresa o está archivado | No. Revisa el identificador |
409 FORMULARIO_NO_PUBLICADO | El formulario está en borrador o despublicado | No, hasta que alguien lo publique |
422 CAMPO_NO_DEFINIDO | Mandaste claves que el formulario no tiene: vienen en campos | No. Corrige el cuerpo |
422 CAMPO_INVALIDO | Falta un obligatorio o un valor no cumple su tipo: vienen campo y motivo | No. Corrige el cuerpo |
413 / 422 ARCHIVO_* | Ver Adjuntar archivos | No |
5xx | Error del lado de Redcumbre | Sí, con la misma claveIdempotencia |
Los 422 de los formularios llevan el código en error: decide por ese código, no por el texto de
message. La forma general de los errores está en
Reglas transversales.
Saber qué pasa con la solicitud: los avisos
Sección titulada «Saber qué pasa con la solicitud: los avisos»Ninguna de las tres puertas lee solicitudes. Lo que pasa después con cada una te llega por webhook, con tres eventos del módulo Comunicación:
| Evento | Cuándo |
|---|---|
solicitud.creada | Se creó una solicitud, entrara por la puerta que entrara |
solicitud.resuelta | Tu equipo la cerró. Trae el motivo, por ejemplo respondida o descartada |
solicitud.reabierta | Una solicitud cerrada se volvió a abrir |
Te suscribes a ellos como a cualquier otro evento, en el panel, en General → Webhooks. La firma, los reintentos y la verificación HMAC son los de todos los webhooks: ver Webhooks.
{ "event": "solicitud.resuelta", "data": { "numero": 42, "tipo": "contacto", "estado": "resuelto", "motivo": "respondida", "referencia": "pedido-4471", "puerta": "servidor", "retenidaPorCuota": false, "ocurridoAt": "2026-10-20T14:05:12.000Z" }, "timestamp": "2026-10-20T14:05:13.000Z", "sandbox": false}referenciaes la que mandaste al crear la solicitud. Úsala para amarrar el aviso con el registro de tu sistema. Si no mandaste referencia, el campo no viene.estadoesabiertoensolicitud.creadaysolicitud.reabierta, yresueltoensolicitud.resuelta.puertadice por dónde entró:servidor,publicaoalojada. Una solicitud que tu equipo creó dentro de la bandeja —por ejemplo, convirtiendo una conversación— traeconversion,cambio_tipoorespuesta_tardia.- El aviso no trae datos de la persona: ni nombre, ni correo, ni ningún valor de los campos. Es a propósito: un webhook pasa por más sistemas que la bandeja, y los datos personales se quedan en ella.
Probar en el modo de prueba
Sección titulada «Probar en el modo de prueba»El modo de prueba existe sólo en la puerta de servidor, porque es una propiedad de la credencial. Con una llave de prueba que tenga el mismo rol, la solicitud se crea marcada de prueba:
- Ninguna persona recibe correo: el acuse queda en la bandeja de mensajes simulados, que ves con
redcumbre bandeja. - Los avisos van firmados con el secreto de prueba y llegan a tu URL de prueba, nunca a la real.
- No se cobra.
- La solicitud no aparece en la bandeja del modo real.
Los eventos solicitud.* no se disparan con redcumbre eventos disparar: se provocan creando una
solicitud con la llave de prueba, que es la prueba real del flujo.
Cada solicitud que se crea cuenta como un envío de formulario, por cualquiera de las tres puertas. No cuentan un reintento con la misma clave de idempotencia, un envío rechazado ni una solicitud de prueba. Los precios están en redcumbre.cl/precios.