Con la API de propform puedes gestionar tus formularios, envíos, estadísticas, plantillas PDF, papeles de carta, empleados y la configuración de tu cuenta desde aplicaciones externas, por ejemplo, desde tus propias herramientas, scripts o plataformas de automatización como Zapier, Make o n8n.
> URL base: https://propform.io/api/v1
>
> Todas las solicitudes y respuestas están en formato JSON (Content-Type: application/json). Las marcas de tiempo están en formato ISO-8601 (p. ej., 2026-07-07T08:30:00+00:00).
Crear una clave API: Ve a Configuración → Claves API, haz clic en Crear clave API y copia la clave que se muestra (formato pf_live_…). Por motivos de seguridad, solo se te mostrará esta única vez.
Probar la conexión: Sustituye pf_live_DEIN_KEY y accede a:
curl https://propform.io/api/v1/me \
-H "Authorization: Bearer pf_live_DEIN_KEY"
Respuesta:
{ "data": { "id": 42, "name": "Max Makler", "email": "max@makler.de" } }
Primera consulta real: listar tus formularios:
curl https://propform.io/api/v1/forms \
-H "Authorization: Bearer pf_live_DEIN_KEY"
La API utiliza claves API como tokens de portador. Cada solicitud debe incluir la clave en el encabezado Authorization (Authorization: Bearer pf_live_…). Si no se incluye la clave o esta no es válida, la API responde con 401.
Si se supera este límite, la API responde con 429 Too Many Requests y un encabezado Retry-After (segundos hasta el siguiente intento permitido). Incorpora una breve espera en las automatizaciones cuando veas este estado.
Las respuestas correctas proporcionan los datos en el campo data.
Las listas están paginadas. Contrólalas mediante per_page (por defecto 25, máx. 100) y page. La respuesta incluye además links y meta:
{
"data": [ { "id": 14, "internal_title": "Kontaktformular", "active": true } ],
"links": { "first": "...", "last": "...", "prev": null, "next": "...?page=2" },
"meta": { "current_page": 1, "per_page": 25, "total": 63, "last_page": 3 }
}
Los errores siempre tienen un campo message; en el caso de los errores de validación (422), los detalles de cada campo se encuentran en errors:
{
"message": "The url field is required.",
"errors": { "url": ["The url field is required."] }
}
| Estado | Significado |
|---|---|
200 / 201 |
Éxito (201 = recién creado) |
204 |
Éxito, sin datos de respuesta (p. ej., eliminación) |
401 |
Clave API inexistente o no válida |
403 |
El registro no pertenece a tu cuenta (o la función no está incluida en el plan) |
404 |
El registro no existe |
409 |
Acción no disponible actualmente (p. ej., onOffice no está conectado) |
422 |
Error de validación: detalles en el campo errors |
429 |
Límite de rate alcanzado: ten en cuenta Retry-After |
| Método | Punto final | Descripción |
|---|---|---|
GET |
/forms |
Mostrar una lista de formularios propios. Filtro: active (0/1), template (0/1), updated_since (fecha), folder (ID de carpeta o none), per_page, page |
POST |
/forms |
Crear un nuevo formulario: solo se necesita internal_title; se inicia inactivo |
GET |
/forms/{id} |
Leer el formulario completo (incluidos los campos, la configuración del correo electrónico y de ChatGPT) |
PATCH |
/forms/{id} |
Configurar formulario: solo se modifican los campos enviados |
POST |
/forms/{id}/copy |
Copiar el formulario (incluidos los campos, las reglas y la configuración del correo electrónico); la copia se inicia inactiva |
El formulario es un recurso en la API: también puedes leer y escribir los ajustes de envío de correo electrónico y de la integración con ChatGPT directamente en el formulario. Los nombres de los campos coinciden exactamente con los ajustes del editor de formularios.
curl -X PATCH https://propform.io/api/v1/forms/123 \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"title": "Neuer Titel", "active": true}'
Características importantes:
"active": true) solo funciona mientras no se haya alcanzado el límite de formularios activos de tu plan (en caso contrario, 422). Desactivar siempre es posible.slug, los contadores y los indicadores de plantilla. Las contraseñas (por ejemplo, la contraseña del formulario) son modificables, pero nunca aparecen en las respuestas.form_template indica esa liberación; con el filtro template=0/1 puedes filtrar por ello.url público del formulario.Un formulario tiene más de 100 configuraciones (todas las que ofrece también el editor). Las más importantes:
| Campo | Significado |
|---|---|
internal_title |
Nombre interno (visible solo en el panel de control) |
title |
Título público del formulario |
custom_slug |
Parte descriptiva de la URL (debe ser única en tu cuenta) |
active |
Formulario en línea (true) o fuera de línea (false) |
description |
Texto introductorio encima del formulario |
submit_button_label |
Texto del botón de envío |
thankyou_headline / thankyou_text |
Título y texto de la página de agradecimiento |
redirect |
URL de redireccionamiento tras el envío (en lugar de la página de agradecimiento) |
background_color / accent_color |
Colores de diseño (hexadecimal, p. ej., #0d6efd) |
subject / body / receiver |
Asunto, texto y destinatario del correo electrónico de confirmación |
send_email_via_onoffice |
Enviar el correo electrónico de confirmación a través de onOffice |
Puedes ver el objeto completo en cualquier momento a través de GET /forms/{id}.
👉 Encontrarás la lista completa de todos los campos y formatos en la referencia de campos de la API.
| Método | Punto final | Descripción |
|---|---|---|
GET |
/forms/{id}/fields |
Campos de un formulario (ordenados por posición) |
POST |
/forms/{id}/fields |
Crear campo – onoffice_module es obligatorio; la posición se coloca automáticamente al final |
GET |
/fields/{id} |
Leer un campo concreto |
PATCH |
/fields/{id} |
Modificar campo (solo propiedades enviadas) |
DELETE |
/fields/{id} |
Eliminar campo |
PATCH |
/forms/{id}/fields/reorder |
Reordenar campos: field_ids debe contener todos los ID de campo del formulario en el orden deseado |
curl -X POST https://propform.io/api/v1/forms/123/fields \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"onoffice_module": "address", "onoffice_field_name": "Vorname", "label": "Vorname", "required": true}'
| Campo | Significado |
|---|---|
onoffice_module |
Módulo de destino: address, estate, task, calendar, agentsLog – o relationlist para el Campo de vínculo (obligatorio al crear el campo) |
onoffice_field_name |
Nombre del campo de destino en onOffice (véase Configuración de campos de onOffice) |
label |
Etiqueta del campo en el formulario |
hint / placeholder |
Texto de ayuda o marcador de posición en el campo de entrada |
required |
Campo obligatorio (true/false) |
hidden / disabled / read_only |
Oculto / desactivado / solo de lectura |
default_value |
Valor predefinido |
half_size |
Mostrar el campo a medio ancho en pantallas grandes |
datalist |
Valores de selección como lista separada por punto y coma (Rot;Grün;Blau) |
display_variant |
Variante de presentación del campo (véase más abajo) |
select_option_meta |
Datos adicionales por clave de selección para las presentaciones de tarjetas/iconos/imágenes (cadena JSON, véase más abajo) |
Con display_variant controlas cómo se presenta un campo en el formulario — el valor guardado y la conexión con onOffice permanecen idénticos. null o vacío = presentación estándar. Valores válidos según el tipo de campo:
| Tipo de campo onOffice | Valores |
|---|---|
singleselect / user |
radio, buttons, cards, icons, images, likert |
multiselect |
checkboxes, chips, icons, images |
boolean |
checkbox, yesno |
integer |
slider, stars, nps |
float |
slider, stars, nps |
date |
calendar |
Criterio de búsqueda de/a (integer/float en el módulo searchcriteria) |
rangeslider |
Los valores desconocidos o que no corresponden al tipo de campo se ignoran al renderizar (presentación estándar). Para cards, icons e images, select_option_meta aporta los datos adicionales por valor clave de onOffice — una cadena JSON con la forma:
{"haus": {"icon": "home", "description": "Independiente o adosada"}, "wohnung": {"image": "https://…/wohnung.jpg"}}
icon es el nombre de un icono del set integrado Tabler Icons (solo minúsculas/dígitos/guiones, p. ej. home, building-estate, currency-euro), image una URL de imagen http(s) (idealmente de la biblioteca de medios), description un texto debajo del título de la opción (tarjetas, mosaicos de iconos e imágenes). Los iconos aparecen en los mosaicos de iconos, delante de la etiqueta de la opción en el grupo de botones y sobre los botones de la escala Likert. Las entradas vacías o desconocidas se ignoran. En el control deslizante, el valor mínimo/máximo y el intervalo provienen de min_value/max_value/step (también en el rangeslider de/a); en la valoración, max_value determina el número de niveles (2–10, por defecto 5).
Opciones de configuración según la presentación (todas opcionales; los valores no adecuados se ignoran al renderizar):
| Propiedad | Se aplica a | Significado |
|---|---|---|
variant_axis_labels |
slider |
Etiquetas propias debajo del deslizador, separadas por punto y coma (p. ej. económico;medio;caro); tiene prioridad sobre datalist |
slider_allow_input |
slider, rangeslider |
true = el valor también se puede escribir en un campo numérico |
range_default_von / range_default_bis |
rangeslider + de/a estándar |
Preasigna «de» y «a» por separado (tiene prioridad sobre default_value, que rellena ambos lados por igual); en el deslizador, los valores preestablecidos — a diferencia de los controles sin tocar — sí se envían |
scale_label_left / scale_label_right |
stars, nps, likert |
Etiquetas de los extremos de la escala |
rating_symbol |
stars |
stars (estándar), hearts, smileys (escala de estado de ánimo, 2–5 niveles; por encima se vuelve a las estrellas) o custom (icono propio mediante rating_custom_icon) |
rating_custom_icon |
stars |
Nombre de icono Tabler para rating_symbol: "custom" (no válido/vacío ⇒ estrellas) |
variant_tile_size |
cards, icons, images |
compact o large (vacío = normal) |
variant_image_ratio |
images |
square o 16x9 (vacío = 4:3) |
variant_image_fit |
images |
contain = ajustar la imagen completa (vacío = rellenar/recortar) |
multiselect_min_selected / multiselect_max_selected |
presentaciones de selección múltiple | Número mínimo/máximo de opciones seleccionables (se impone en el navegador) |
calendar_date_mode |
calendar |
future (solo desde hoy) o past (solo hasta hoy) |
calendar_min_date / calendar_max_date |
calendar |
Fecha mínima/máxima fija (YYYY-MM-DD); tiene prioridad sobre calendar_date_mode |
calendar_disable_weekends |
calendar |
true = bloquear fines de semana |
yesno_yes_label / yesno_no_label |
yesno |
Etiquetas propias de los botones (vacío = «Sí»/«No» en el idioma de la cuenta) |
yesno_icons |
yesno |
true = iconos en los botones (estándar: marca de verificación/cruz) |
yesno_yes_icon / yesno_no_icon |
yesno |
Iconos Tabler propios en lugar de marca de verificación/cruz (solo surten efecto con yesno_icons: true) |
variant_columns |
radio, checkboxes |
Columnas de la lista: 1–3 (en móvil siempre una columna) |
variant_centered |
botones/mosaicos/chips/yesno/stars/nps/calendar/deslizadores |
true = centrado en lugar de alineado a la izquierda (en los deslizadores, el campo de entrada) |
variant_icon_color |
icons, yesno, buttons, likert |
Color de icono propio en hexadecimal (#RRGGBB); vacío = hereda el color del texto |
Nota sobre selección múltiple: Las presentaciones de mosaicos/listas muestran las opciones de forma plana; allí no existe la automática padre-hijo. El
multiselect_modeguardado no se modifica al establecer una variante de presentación y vuelve a aplicarse en cuanto regresas a la presentación estándar.
Nota sobre el deslizador: El deslizador simple — igual que el deslizador de/a — solo envía un valor tras una interacción; un deslizador sin tocar se comporta como un campo vacío.
Nota: El range-slider antiguo mediante
special_field: "range"sigue funcionando sin cambios (legacy). Para nuevos deslizadores recomendamosdisplay_variant: "slider"— si un campo tiene ambos configurados, ganadisplay_variant.
El Campo de vínculo (mostrar, vincular, crear, editar y desvincular registros de onOffice conectados) se crea con onoffice_module: "relationlist". El tipo de relación se compone de relation_type (p. ej. estate:address:owner) más relation_anchor_module (estate o address – qué lado es el registro cargado en el formulario); a esto se añaden los interruptores relation_show_existing, relation_allow_search, relation_allow_create, relation_allow_edit, relation_allow_remove, la comprobación de duplicados (relation_duplicate_check + relation_duplicate_check_fields) y la lista de elementos del miniformulario relation_subform_elements (matriz de {type: "field", name, required, half} o elementos de diseño {type: "headline"|"description"|"dividingline"|"collapsible", text}). Para la creación existen además relation_advisor_mode (anchor = adoptar el responsable del registro cargado, fixed = usuario fijo de relation_advisor_user_id) y relation_auto_open_create (abrir automáticamente el miniformulario cuando no se muestran conexiones). Todos los valores y límites figuran en la referencia de campos.
curl -X POST https://propform.io/api/v1/forms/123/fields \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"onoffice_module": "relationlist",
"relation_type": "estate:address:owner",
"relation_anchor_module": "estate",
"label": "Propietario",
"relation_show_existing": true,
"relation_allow_create": true,
"relation_subform_elements": [
{"type": "field", "name": "Vorname", "half": true},
{"type": "field", "name": "Name", "required": true, "half": true},
{"type": "field", "name": "Email", "required": true}
]
}'
Ordenación: En el caso de reorder, el orden en la matriz field_ids determina la nueva posición. La matriz debe contener exactamente todos los ID de campo del formulario (si falta alguno o hay alguno que no pertenezca al formulario → 422):
curl -X PATCH https://propform.io/api/v1/forms/123/fields/reorder \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"field_ids": [4712, 4711, 4713]}'
GET /onoffice/fields proporciona la configuración de campos de tu cuenta de onOffice, por módulo (address, estate, task, calendar, agentsLog, file, project) todos los campos con su etiqueta, tipo, longitud y valores permitidos. Así encontrarás los valores válidos para onoffice_field_name. Con ?module=address puedes filtrar por un módulo.
{
"data": {
"address": {
"Vorname": { "label": "Vorname", "type": "varchar", "length": 50, "default": null, "permittedvalues": null },
"Anrede": { "label": "Anrede", "type": "singleselect", "length": null, "default": null,
"permittedvalues": { "HERR": "Herr", "FRAU": "Frau" } }
}
}
}
> Es necesario disponer de una conexión a la API de onOffice que funcione correctamente; de lo contrario, el punto final responderá con 409.
POST /onoffice/fields/refresh vuelve a cargar la configuración de campos desde onOffice, por ejemplo después de haber creado un campo o modificado los valores permitidos en onOffice. La actualización se ejecuta en segundo plano: la respuesta es 202 con data.status = pending; unos segundos después, GET /onoffice/fields devuelve el nuevo estado. Ambos puntos finales devuelven un objeto meta con la fecha de la última generación (updated_at), el idioma de las etiquetas de campo (locale) y refresh_pending (true mientras siga en curso una actualización iniciada a través de la API). Sin esta llamada, propform actualiza la configuración una vez al día y cada vez que se abre la vista general de formularios. Límite: 120 llamadas por hora.
{
"message": "…",
"data": { "status": "pending", "already_pending": false },
"meta": { "updated_at": "2026-09-08T06:12:41+02:00", "locale": "de", "refresh_pending": true, "last_refresh_failed": false }
}
| Método | Punto final | Descripción |
|---|---|---|
GET |
/forms/{id}/rules |
Reglas de un formulario (ordenadas por prioridad) |
PUT |
/forms/{id}/rules |
Reemplazar todas las reglas del formulario (matriz vacía = borrar todas) |
El punto final de escritura funciona igual que el editor de condiciones del panel de control: Siempre se guardan todas las reglas de una sola vez (no se añaden de forma individual). Por lo tanto, primero lee con GET, modifica la lista y devuélvela completa mediante PUT. Una regla se compone de clauses (condiciones «Si», vinculadas a mode = all/any) y actions (acciones «entonces»):
curl -X PUT https://propform.io/api/v1/forms/123/rules \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"rules": [{
"title": "Zusatzfeld einblenden",
"mode": "all", "priority": 10, "is_enabled": 1, "run_on_init": 1,
"clauses": [{"when_field_id": "4711", "operator": "equals", "value": "Ja"}],
"actions": [{"order": 10, "action": "show", "target_field_id": "4712"}]
}]}'
equals, not_equals, empty, not_empty, starts_with, not_starts_with, contains, not_containsshow, hide, enable, disable, require, optional, hide_option, unhide_option, set_value, set_label, make_readonly, unmake_readonly, enable_rules_by_tag, disable_rules_by_tag__form_title, __form_description, __submit, __submit_spinner, __multistep_back, __multistep_next (en este caso, solo set_label, show, hide; en el spinner, solo set_label).403).Encontrarás más detalles sobre el funcionamiento de las reglas en Condiciones, reglas y cálculos.
| Método | Punto final | Descripción |
|---|---|---|
GET |
/forms/{id}/submissions |
Envíos de un formulario. Filtros: created_after, created_before, sort (asc/desc), per_page |
GET |
/submissions/{id} |
Envío individual |
GET |
/forms/{id}/stats |
Visitas, envíos y tasa de conversión; opcionalmente from/to (fecha) |
El contenido de un envío (content) se agrupa por módulos de onOffice:
{
"data": {
"id": 456, "form_id": 123, "index": 42,
"content": { "address": { "Vorname": "Max", "Name": "Mustermann" }, "estate": { "Id": "131" } },
"ip_address": "203.0.113.7",
"created_at": "2026-07-07T08:30:00+00:00"
}
}
Si has desactivado el almacenamiento de datos de envío en la configuración de privacidad, content siempre será null, pero el envío seguirá contando para las estadísticas. La respuesta stats contiene views, submissions y conversion_rate.
En lugar de consultar las respuestas periódicamente, puedes recibir notificaciones mediante webhooks: propform envía inmediatamente un POST a tu URL cada vez que se recibe una nueva respuesta.
💡 También puedes gestionar los webhooks en el frontend sin clave API: en la configuración, en «Webhooks» (para todos los formularios) o directamente en el editor de formularios, en «Webhooks (Zapier, n8n, Make …)».
| Método | Punto final | Descripción |
|---|---|---|
GET |
/webhooks |
Mostrar tus suscripciones a webhooks |
POST |
/webhooks |
Crear suscripción: url (obligatorio), form_id (opcional; si no se especifica, la suscripción se aplica a todos tus formularios), payload_template (opcional; véase más abajo), message_key (opcional; nombre del campo del mensaje resuelto, por defecto text) |
DELETE |
/webhooks/{id} |
Eliminar suscripción |
Requisitos de la URL: debe ser de acceso público y utilizar http:// o https://. Las direcciones internas o locales (p. ej., localhost, 127.0.0.1, direcciones IP de redes privadas) se rechazan por motivos de seguridad (422). Dado que se transmiten los datos de envío, utiliza, en la medida de lo posible, https://.
La respuesta al crear el evento contiene el secret, con el que se firma cada entrega (puedes recuperarlo más tarde en cualquier momento mediante GET /webhooks):
{
"data": {
"id": 7, "event": "submission.created",
"url": "https://example.com/hook", "form_id": 123,
"secret": "a1b2c3…", "payload_template": null, "message_key": "text", "is_active": true,
"failure_count": 0, "last_success_at": null, "last_failure_at": null,
"created_at": "2026-07-07T08:30:00+00:00"
}
}
Cada entrega contiene dos encabezados:
X-Propform-Event: el tipo de evento (actualmente siempre es submission.created)X-Propform-Signature – sha256=<HMAC-SHA256 des Request-Bodys mit deinem secret>Ejemplo de carga útil:
{
"event": "submission.created",
"created_at": "2026-07-07T08:30:00+00:00",
"form": { "id": 123, "slug": "aB3x…", "custom_slug": "kontakt", "title": "…", "internal_title": "…" },
"submission": { "id": 456, "index": 42, "content": { "address": { "Vorname": "Max" } } },
"onoffice_ids": { "address": { "ID": "789" } }
}
payload_template)Opcionalmente, puedes guardar una plantilla de texto libre para cada suscripción. Tras cada envío del formulario, propform resuelve en ella las macros de onOffice (con los registros que el envío ha creado o editado) e incluye el resultado como un campo de mensaje propio en la carga útil: ideal como mensaje listo para Slack y similares, sin tener que montar nada en el flujo de trabajo receptor. El nombre del campo es text por defecto (véase más abajo).
Ejemplo de plantilla:
Nueva solicitud de _Vorname _Name sobre _objekttitel → _getEstateLink
se convierte en la carga útil en:
"text": "Nueva solicitud de Max Mustermann sobre Traumwohnung am Stadtpark → https://smart.onoffice.de/…"
Nombre del campo del mensaje (message_key): Por defecto el campo se llama text, así Slack, Microsoft Teams y Google Chat interpretan la carga útil directamente como mensaje. Discord espera content. Para Zapier/n8n/Make el nombre es libre. Puedes cambiarlo por webhook mediante el parámetro message_key (en el frontend, en «Nombre del campo del mensaje»).
Ten en cuenta:
_getAddressLink, _getEstateLink, …)._objekttitel necesita un inmueble vinculado). Sin contexto, la macro permanece sin resolver en el texto.Comprueba la firma para asegurarte de que la solicitud procede realmente de propform. Calcula el HMAC a partir del cuerpo de la solicitud en bruto (no a partir del JSON analizado) y compáralo en tiempo real.
PHP:
$secret = 'DEIN_WEBHOOK_SECRET';
$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PROPFORM_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
if (!hash_equals($expected, $signature)) {
http_response_code(403);
exit('Ungültige Signatur');
}
// ab hier: $body ist echt – json_decode($body, true) verarbeiten
Node.js (Express):
const crypto = require('crypto');
// WICHTIG: express.raw() nutzen, damit der Body unverändert bleibt
app.post('/hook', express.raw({ type: 'application/json' }), (req, res) => {
const secret = process.env.PROPFORM_WEBHOOK_SECRET;
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(req.body).digest('hex');
const got = req.header('X-Propform-Signature') || '';
if (expected.length !== got.length ||
!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got))) {
return res.status(403).send('Ungültige Signatur');
}
const payload = JSON.parse(req.body.toString());
res.sendStatus(200);
});
2xx. En caso de error, propform intentará la entrega hasta 3 veces (con un tiempo de espera).is_active: false, visible a través de GET /webhooks). A continuación, solo tienes que volver a crearla.Las carpetas estructuran la vista general de formularios en el panel. Cada formulario está en una carpeta como máximo (form_folder_id, null = «Sin carpeta»). Las carpetas pueden tener un subnivel (parent_id, dos niveles como máximo). No confundir con los grupos de formularios, que controlan la autorización de copia.
| Método | Endpoint | Descripción |
|---|---|---|
GET |
/form-folders |
Tus carpetas con sus ID y el número de formularios |
POST |
/form-folders |
Crear una carpeta: se necesita name (máx. 100 caracteres), opcionalmente parent_id (ID de una carpeta principal → crea una subcarpeta) |
PATCH |
/form-folders/{id} |
Renombrar una carpeta (name) y/o moverla (parent_id: ID de una carpeta principal o null = carpeta principal) |
DELETE |
/form-folders/{id} |
Eliminar una carpeta: los formularios se conservan y vuelven a aparecer en «Sin carpeta»; las subcarpetas pasan a ser carpetas principales |
La asignación se establece en el PATCH del formulario mediante form_folder_id (ID de una carpeta propia o null). En la lista de formularios puedes filtrar con ?folder=<id> o ?folder=none.
| Método | Punto final | Descripción |
|---|---|---|
GET |
/form-groups |
Tus grupos con sus ID, el indicador copy y el número de formularios |
POST |
/form-groups |
Crear un grupo: solo se necesita name |
PATCH |
/form-groups/{id} |
Modificar name y/o copy (posibilidad de copiar los formularios de este grupo) |
DELETE |
/form-groups/{id} |
Eliminar el grupo: los formularios se conservan y solo pierden la asignación al grupo |
Puedes asignar los ID de grupo en el PATCH del formulario como form_groups (matriz).
propform puede generar un PDF propio a partir de cada envío (véase Generador de PDF). La plantilla de un formulario —lista de bloques, diseño y ajustes— se puede leer y escribir por completo a través de la API:
| Método | Punto final | Descripción |
|---|---|---|
GET |
/forms/{id}/pdf-template |
Leer la plantilla (enabled, name, blocks, design, settings); si todavía no existe, se propone automáticamente a partir de los campos del formulario |
PATCH |
/forms/{id}/pdf-template |
Actualización parcial: solo se modifican las partes enviadas |
POST |
/forms/{id}/pdf-template/regenerate |
Volver a generar la lista de bloques a partir del conjunto de campos actual (el diseño, los ajustes y el estado activo se conservan) |
GET |
/forms/{id}/pdf-template/preview |
Vista previa real en PDF con datos de ejemplo (application/pdf; máx. 10 solicitudes/minuto) |
GET |
/account/pdf-design |
Leer el preajuste de diseño de la cuenta (design + settings) |
PATCH |
/account/pdf-design |
Modificar el preajuste de diseño: las nuevas plantillas de formulario lo heredan como punto de partida |
curl -X PATCH https://propform.io/api/v1/forms/123/pdf-template \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled": true, "design": {"accent_color": "#0d6efd"}}'
Características importantes:
regenerate (¡sustituye tus propios ajustes de bloques!) o añade los bloques de forma selectiva mediante PATCH.settings.document_signing.enabled, propform se encarga automáticamente de que haya un bloque de firma del documento en la plantilla (si no existe ninguno).blocks es una matriz de bloques. Cada bloque tiene type, un id asignado automáticamente y propiedades que dependen del tipo (máx. 300 bloques por plantilla):
| Tipo | Propiedades |
|---|---|
heading |
text (máx. 500 caracteres), level (1, 2 o 3) |
paragraph |
text (máx. 5.000 caracteres) |
field |
Campo individual con valor: field_id (campo de este formulario) o onoffice (referencia, véase más abajo), label opcional |
fieldlist |
Lista de etiqueta-valor: field_ids = matriz de ID de campo y/o referencias de onOffice |
columns |
Dos columnas: left y right son sendas matrices de bloques (un nivel de profundidad) |
image |
url (http/https), width_percent (10–100), align (left/center/right), caption |
divider |
style: line (línea) o space (espacio) |
pagebreak |
Salto de página, sin propiedades |
signature |
field_id = campo de firma del formulario o null = firma del documento tras el envío; label; required (solo en la firma del documento) |
Referencias de onOffice: en field/fieldlist, en lugar de un ID de campo, también puedes mostrar un campo del registro de onOffice vinculado: {"module": "address", "name": "Telefon1", "label": "Teléfono"} (módulos address y estate; el campo debe existir en tu configuración de campos de onOffice).
Ejemplo:
{
"blocks": [
{"type": "heading", "text": "Autoevaluación del inquilino", "level": 1},
{"type": "paragraph", "text": "Datos del interesado:"},
{"type": "fieldlist", "field_ids": [4711, 4712, {"module": "estate", "name": "objekttitel", "label": "Inmueble"}]},
{"type": "pagebreak"},
{"type": "signature", "field_id": null, "label": "Lugar, fecha y firma", "required": true}
]
}
Claves de diseño (design): font, heading_font, font_size (7–14), text_color/heading_color/accent_color (hexadecimal), logo_url, logo_position (left/center/right), logo_width_mm (10–90), label_column_width (20–60), header_text, footer_text, show_page_numbers, letterhead_id (véase Papeles de carta), así como letterhead_margin_top/right/bottom/left (0–100 mm, null = márgenes del papel de carta).
Claves de ajustes (settings): empty_fields (hide/dash/blank), embed_uploaded_images, attach_uploaded_pdfs, embed_existing_files, embedded_image_size (small/column/full), document_signing.enabled.
El papel de carta propio (PDF o imagen) se coloca como fondo debajo de cada página del PDF generado, opcionalmente con una hoja de continuación propia a partir de la página 2:
| Método | Punto final | Descripción |
|---|---|---|
GET |
/letterheads |
Tus papeles de carta; con ?form_id= exactamente los seleccionables en ese formulario |
POST |
/letterheads |
Subir (multipart/form-data, véase más abajo) |
PATCH |
/letterheads/{id} |
Modificar letterhead_name y los márgenes |
DELETE |
/letterheads/{id} |
Eliminar: las plantillas que lo utilizan vuelven a renderizarse después con el diseño estándar |
Parámetros de subida (POST, multipart): letterhead_name (obligatorio), letterhead_first (obligatorio, PDF/PNG/JPG de hasta 10 MB: la primera hoja), letterhead_continuation (opcional: la hoja de continuación, mismo tipo de archivo), letterhead_margin_top/right/bottom/left (opcional, mm), form_id (opcional: con él, el papel de carta pasa a ser privado del formulario; sin él, se guarda en la biblioteca de la cuenta).
curl -X POST https://propform.io/api/v1/letterheads \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-F "letterhead_name=Papel corporativo" \
-F "letterhead_first=@briefbogen.pdf" \
-F "letterhead_continuation=@folgebogen.pdf"
422. Las imágenes de baja resolución se aceptan, pero la respuesta incluye entonces un aviso en el campo warning.design.letterhead_id en el PATCH de plantillas PDF (los papeles de carta de la cuenta en cualquier formulario, los privados solo en su propio formulario).| Método | Punto final | Descripción |
|---|---|---|
GET |
/account |
Leer la configuración de la cuenta agrupada |
PATCH |
/account |
Actualización parcial: solo se modifican los grupos/campos enviados |
La respuesta está agrupada según las secciones de configuración del panel de control:
| Grupo | Contenido | Modificable |
|---|---|---|
profile |
name (nombre del perfil o de la empresa) |
✅ |
styling |
Todos los valores de diseño predeterminados default_* para nuevos formularios (colores, fuentes, logotipo, aspecto de tarjetas…) |
✅ |
imprint |
Aviso legal estándar: default_privacypolicy_url, default_imprint_url, default_homepage_url, default_imprint_line_1 a _5 |
✅ |
notifications |
Hasta 3 destinatarios de notificaciones técnicas (notification_email_1–3) + notification_self |
✅ |
statistics |
save_submission_data, save_ips (privacidad) |
✅ |
domain |
username (subdominio), externaldomain, externaldomain_active |
❌ solo lectura |
staff_area |
enabled, session_days (1–90), seat_limit + active_members (solo lectura) |
parcialmente |
curl -X PATCH https://propform.io/api/v1/account \
-H "Authorization: Bearer pf_live_DEIN_KEY" \
-H "Content-Type: application/json" \
-d '{"styling": {"default_accent_color": "#0d6efd"}, "statistics": {"save_ips": false}}'
domain es deliberadamente de solo lectura: un cambio del subdominio o del dominio rompería todos los enlaces de formulario ya incrustados; esto solo es posible en el panel de control.staff_area.enabled solo se puede activar si tu plan incluye plazas de empleados (seat_limit > 0; en caso contrario, 422). El propio seat_limit viene determinado por el plan y no es modificable.notifications se guardan como lista compacta: tras guardar, los huecos vacíos se compactan hacia delante.| Método | Punto final | Descripción |
|---|---|---|
GET |
/account/onoffice |
Estado de conexión y ajustes de la conexión con onOffice |
PATCH |
/account/onoffice |
Modificar ajustes (máx. 5 solicitudes/minuto) |
La respuesta contiene, entre otros, api_type (normal/marketplace_api), connection_ok, credentials_set, email_onoffice_api_user (+ _is_functional), field_config_locale y reason_cancellation. Por motivos de seguridad, el token y el secret de la API no aparecen en ninguna respuesta.
Modificable mediante PATCH:
| Campo | Significado |
|---|---|
api_type |
normal (credenciales propias de la API de onOffice) o marketplace_api (conexión Marketplace; requiere un usuario de Marketplace conectado) |
email_onoffice_api_user |
Identidades de correo electrónico del usuario de la API como matriz (máx. 10); cada dirección se comprueba mediante un envío de prueba |
email_onoffice_marketplace_api_user |
Ídem para la conexión Marketplace |
field_config_locale |
Idioma de las etiquetas de campo de onOffice (de, en, …); la caché de configuración de campos se reconstruye después en segundo plano |
reason_cancellation |
Motivos de rechazo propios como matriz (máx. 50 entradas, 40 caracteres cada una; vacío = lista estándar) |
Los formularios con la protección de acceso para empleados activada solo son accesibles tras iniciar sesión mediante un enlace mágico. Los empleados y grupos correspondientes se gestionan a través de la API:
| Método | Punto final | Descripción |
|---|---|---|
GET |
/staff-members |
Empleados, incluida la asignación a grupos, source (onoffice/manual) e is_active |
POST |
/staff-members |
Crear un empleado externo: name, email, opcionalmente groups (matriz de ID de grupo) |
PATCH |
/staff-members/{id} |
Actualización parcial: name, email (solo manuales), groups, is_active |
DELETE |
/staff-members/{id} |
Eliminar empleado (también finaliza las sesiones en curso) |
POST |
/staff-members/import-onoffice |
Importar usuarios de onOffice: onoffice_user_ids (matriz, opcional; si no se indica, todos los importables). Respuesta: created, updated |
GET |
/staff-groups |
Grupos, incluido el número de miembros (onoffice_group_id establecido = reflejado desde onOffice) |
POST |
/staff-groups |
Crear un grupo local (name) |
DELETE |
/staff-groups/{id} |
Eliminar grupo |
staff_area.seat_limit en /account) se aplica de forma estricta al crear, activar e importar (422). Solo los empleados activos ocupan una plaza.is_active: false) finaliza de inmediato todas las sesiones en curso del empleado.staff_only_enabled, staff_allowed_member_ids y staff_allowed_group_ids en el PATCH del formulario; los interruptores de la cuenta (staff_area.enabled, session_days) se encuentran en /account.GET /forms/{id}/submissions?sort=desc y del id más alto ya procesado.GET /me.GET /forms?updated_since=….429, incorporar una breve espera y respetar el encabezado Retry-After.La versión actual es v1 y está fijada en la ruta (/api/v1). Añadimos nuevos campos y puntos finales de forma compatible con versiones anteriores sin cambiar la versión; por lo tanto, tu cliente debería simplemente ignorar los campos desconocidos en las respuestas. Los cambios fundamentales que no sean compatibles con versiones anteriores aparecerían bajo una nueva versión (/api/v2).