Guías

Colocar automáticamente campos de firma con etiquetas de anclaje: Posicionamiento de campos basado en texto

Gráfico abstracto con fondo oscuro presenta un rectángulo dividido, líneas punteadas etiquetadas como "X=?" y "Y=?", y una flecha apuntando a la derecha, sugiriendo transformación.

Si alguna vez has posicionado campos de firma calculando coordenadas x/y en un PDF, sabes lo tedioso que se vuelve a gran escala. Cambia la disposición del documento, y cada coordenada se rompe. Agrega una segunda página, y estarás recalculando ajustes para la mitad de tus campos.

Las etiquetas de anclaje solucionan esto. Inserta marcadores de texto como {{SIGN_HERE}} o {{DATE}} directamente en tu plantilla PDF, y Firma.dev los detecta automáticamente y coloca los tipos de campo correctos en esos lugares. Los marcadores se eliminan del documento final, por lo que los firmantes nunca los ven. Una llamada a la API, sin cálculos de coordenadas.

Las etiquetas de anclaje se enviaron en v1.11.0 y soportan todos los tipos de campo, reglas de coincidencia flexibles, y hasta 100 etiquetas por solicitud de firma.

Inicio Rápido

La manera más rápida de hacer que funcionen las etiquetas de anclaje: introduce un marcador en tu PDF, luego crea una solicitud de firma con un arreglo anchor_tags.

Paso 1: Añade el texto {{SIGN_HERE}} en algún lugar de tu PDF donde quieras que aparezca el campo de firma. Puedes hacer esto en cualquier herramienta que genera tus documentos, ya sea una plantilla de Word, una biblioteca PDF o un servicio de generación de documentos.

Paso 2: Crea una solicitud de firma basada en documentos con la definición de la etiqueta de anclaje:

const response = await fetch(
  'https://api.firma.dev/functions/v1/signing-request-api/signing-requests',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.FIRMA_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      workspace_id: workspaceId,
      document: documentBase64,
      name: 'NDA - Acme Corp',
      anchor_tags: [
        {
          anchor_string: '{{SIGN_HERE}}',
          type: 'signature',
          recipient_id: 'temp_1',
          required: true
        }
      ],
      recipients: [
        {
          id: 'temp_1',
          first_name: 'Jane',
          last_name: 'Smith',
          email: 'jane@example.com',
          designation: 'Signer',
          order: 1
        }
      ]
    })
  }
);

const signingRequest = await response.json();
const response = await fetch(
  'https://api.firma.dev/functions/v1/signing-request-api/signing-requests',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.FIRMA_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      workspace_id: workspaceId,
      document: documentBase64,
      name: 'NDA - Acme Corp',
      anchor_tags: [
        {
          anchor_string: '{{SIGN_HERE}}',
          type: 'signature',
          recipient_id: 'temp_1',
          required: true
        }
      ],
      recipients: [
        {
          id: 'temp_1',
          first_name: 'Jane',
          last_name: 'Smith',
          email: 'jane@example.com',
          designation: 'Signer',
          order: 1
        }
      ]
    })
  }
);

const signingRequest = await response.json();
const response = await fetch(
  'https://api.firma.dev/functions/v1/signing-request-api/signing-requests',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.FIRMA_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      workspace_id: workspaceId,
      document: documentBase64,
      name: 'NDA - Acme Corp',
      anchor_tags: [
        {
          anchor_string: '{{SIGN_HERE}}',
          type: 'signature',
          recipient_id: 'temp_1',
          required: true
        }
      ],
      recipients: [
        {
          id: 'temp_1',
          first_name: 'Jane',
          last_name: 'Smith',
          email: 'jane@example.com',
          designation: 'Signer',
          order: 1
        }
      ]
    })
  }
);

const signingRequest = await response.json();

Firma.dev escanea el PDF en busca de {{SIGN_HERE}}, coloca un campo de firma en ese lugar, lo asigna al destinatario y elimina el texto del marcador del documento. Eso es todo.

Nota que las etiquetas de anclaje solo funcionan con la creación de solicitudes de firma basadas en documentos, no basadas en plantillas. Estás enviando el PDF sin procesar y dejando que el sistema de anclaje maneje la colocación de campos.

Tipos de Campo Soportados

Las etiquetas de anclaje soportan cada tipo de campo disponible en Firma.dev. Establece la propiedad type en cada etiqueta de anclaje a uno de estos valores:

signature para campos de firma, initials para campos de iniciales, text para entrada de texto de una sola línea, textarea para entrada de texto de varias líneas, date para campos de fecha, checkbox para cajas de verificación, radio para grupos de botones de radio, dropdown para selecciones de listas desplegables, url para campos de URL, stamp para campos de sello, y file para campos de carga de archivo.

Cada tipo representa el widget de campo apropiado en la experiencia de firma. Una etiqueta de anclaje date crea un selector de fecha, una dropdown crea un menú de selección, y así sucesivamente.

Opciones de Coincidencia y Posicionamiento

El comportamiento predeterminado de coincidencia funciona para la mayoría de los casos, pero puedes ajustar cómo Firma.dev encuentra y posiciona los campos creados por anclaje.

Sensibilidad a mayúsculas y minúsculas: Establece case_sensitive a true o false (el valor predeterminado es false). Con coincidencia insensible a mayúsculas, {{sign_here}} y {{SIGN_HERE}} coinciden.

Coincidencia de palabra completa: Establece whole_word en true para evitar coincidencias parciales. Si tu cadena de anclaje es SIGN y whole_word es false, también coincidiría con SIGNATURE o COSIGN. Configurarlo en true asegura que solo coincida la palabra exacta.

Objetivo de ocurrencias específicas: Si tu PDF contiene la misma cadena de anclaje varias veces, puedes dirigirte a específicas con occurrence. Establece en 1 para la primera coincidencia, 2 para la segunda, y así sucesivamente. O omítelo o configura match_all en true para colocar campos en cada ocurrencia.

Posicionamiento por desplazamiento: Ajusta finamente donde el campo se coloca en relación al texto de anclaje usando offset_x y offset_y. Puedes especificar desplazamientos en porcentajes (relativos a las dimensiones de la página) o en píxeles. Esto es útil cuando deseas que el campo se posicione ligeramente abajo o a la derecha del marcador, en lugar de directamente encima.

Manejo elegante de anclajes faltantes: Establece ignore_if_not_present a true si la cadena de anclaje podría no existir en cada documento. Sin esto, un anclaje faltante devuelve un error. Con él habilitado, Firma.dev omite silenciosamente esa etiqueta y procesa el resto.

Configuración Avanzada

Aquí hay un ejemplo más completo que combina múltiples etiquetas de anclaje con diferentes tipos de campo, dimensiones personalizadas y desplazamientos de posicionamiento:

const response = await fetch(
  'https://api.firma.dev/functions/v1/signing-request-api/signing-requests',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.FIRMA_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      workspace_id: workspaceId,
      document: documentBase64,
      name: 'Employment Agreement',
      anchor_tags: [
        {
          anchor_string: '{{EMPLOYEE_SIGNATURE}}',
          type: 'signature',
          recipient_id: 'temp_1',
          required: true,
          width: 30,
          height: 8,
          offset_y: 2
        },
        {
          anchor_string: '{{EMPLOYEE_DATE}}',
          type: 'date',
          recipient_id: 'temp_1',
          required: true
        },
        {
          anchor_string: '{{EMPLOYEE_INITIALS}}',
          type: 'initials',
          recipient_id: 'temp_1',
          required: true,
          match_all: true
        },
        {
          anchor_string: '{{MANAGER_SIGNATURE}}',
          type: 'signature',
          recipient_id: 'temp_2',
          required: true
        },
        {
          anchor_string: '{{BENEFITS_OPT_IN}}',
          type: 'checkbox',
          recipient_id: 'temp_1',
          required: false,
          ignore_if_not_present: true
        }
      ],
      recipients: [
        {
          id: 'temp_1',
          first_name: 'Sarah',
          last_name: 'Chen',
          email: 'sarah@example.com',
          designation: 'Signer',
          order: 1
        },
        {
          id: 'temp_2',
          first_name: 'Mike',
          last_name: 'Torres',
          email: 'mike@example.com',
          designation: 'Signer',
          order: 2
        }
      ]
    })
  }
);
const response = await fetch(
  'https://api.firma.dev/functions/v1/signing-request-api/signing-requests',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.FIRMA_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      workspace_id: workspaceId,
      document: documentBase64,
      name: 'Employment Agreement',
      anchor_tags: [
        {
          anchor_string: '{{EMPLOYEE_SIGNATURE}}',
          type: 'signature',
          recipient_id: 'temp_1',
          required: true,
          width: 30,
          height: 8,
          offset_y: 2
        },
        {
          anchor_string: '{{EMPLOYEE_DATE}}',
          type: 'date',
          recipient_id: 'temp_1',
          required: true
        },
        {
          anchor_string: '{{EMPLOYEE_INITIALS}}',
          type: 'initials',
          recipient_id: 'temp_1',
          required: true,
          match_all: true
        },
        {
          anchor_string: '{{MANAGER_SIGNATURE}}',
          type: 'signature',
          recipient_id: 'temp_2',
          required: true
        },
        {
          anchor_string: '{{BENEFITS_OPT_IN}}',
          type: 'checkbox',
          recipient_id: 'temp_1',
          required: false,
          ignore_if_not_present: true
        }
      ],
      recipients: [
        {
          id: 'temp_1',
          first_name: 'Sarah',
          last_name: 'Chen',
          email: 'sarah@example.com',
          designation: 'Signer',
          order: 1
        },
        {
          id: 'temp_2',
          first_name: 'Mike',
          last_name: 'Torres',
          email: 'mike@example.com',
          designation: 'Signer',
          order: 2
        }
      ]
    })
  }
);
const response = await fetch(
  'https://api.firma.dev/functions/v1/signing-request-api/signing-requests',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.FIRMA_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      workspace_id: workspaceId,
      document: documentBase64,
      name: 'Employment Agreement',
      anchor_tags: [
        {
          anchor_string: '{{EMPLOYEE_SIGNATURE}}',
          type: 'signature',
          recipient_id: 'temp_1',
          required: true,
          width: 30,
          height: 8,
          offset_y: 2
        },
        {
          anchor_string: '{{EMPLOYEE_DATE}}',
          type: 'date',
          recipient_id: 'temp_1',
          required: true
        },
        {
          anchor_string: '{{EMPLOYEE_INITIALS}}',
          type: 'initials',
          recipient_id: 'temp_1',
          required: true,
          match_all: true
        },
        {
          anchor_string: '{{MANAGER_SIGNATURE}}',
          type: 'signature',
          recipient_id: 'temp_2',
          required: true
        },
        {
          anchor_string: '{{BENEFITS_OPT_IN}}',
          type: 'checkbox',
          recipient_id: 'temp_1',
          required: false,
          ignore_if_not_present: true
        }
      ],
      recipients: [
        {
          id: 'temp_1',
          first_name: 'Sarah',
          last_name: 'Chen',
          email: 'sarah@example.com',
          designation: 'Signer',
          order: 1
        },
        {
          id: 'temp_2',
          first_name: 'Mike',
          last_name: 'Torres',
          email: 'mike@example.com',
          designation: 'Signer',
          order: 2
        }
      ]
    })
  }
);

Algunas cosas a notar en este ejemplo. La etiqueta {{EMPLOYEE_INITIALS}} usa match_all: true, por lo que si el PDF tiene marcadores de iniciales en las páginas 1, 5 y 12, los tres obtienen campos. La casilla de verificación {{BENEFITS_OPT_IN}} usa ignore_if_not_present: true porque no todas las versiones del acuerdo de empleo incluyen esa sección. Y el offset_y: 2 en el campo de firma lo desplaza ligeramente hacia abajo desde la posición del texto de anclaje.

Las dimensiones (width y height) siguen el mismo sistema de coordenadas basado en porcentajes utilizado por campos posicionados manualmente. Las etiquetas de anclaje y los campos manuales funcionan juntos, por lo que puedes usar anclajes para la mayoría de tus campos y aún así añadir campos manuales basados en coordenadas en la misma solicitud para casos especiales.

Migración desde Otras Plataformas

Si estás migrando desde otro proveedor de firmas electrónicas que utiliza la colocación de campos basada en texto, los conceptos se mapean directamente. La sintaxis de la cadena de anclaje y los nombres de las propiedades difieren, pero el mecanismo subyacente es el mismo: inserta un marcador, define el tipo de campo, permite que la API maneje la colocación.

Desde DocuSign Auto-Place: DocuSign utiliza anchorString, anchorXOffset, anchorYOffset, y tipos de pestañas específicos como signHereTabs. En Firma.dev, esto se convierte en anchor_string, offset_x, offset_y, y el campo universal type. anchorIgnoreIfNotPresent de DocuSign se mapea a ignore_if_not_present. anchorCaseSensitive de DocuSign se mapea a case_sensitive. La principal diferencia estructural es que Firma.dev usa un solo arreglo anchor_tags con una propiedad type, en lugar de arreglos separados para cada tipo de pestaña.

Desde Yousign Smart Anchors: El concepto de "anclajes inteligentes" de Yousign con detección de tipo de campo se traduce directamente. Las opciones de coincidencia y posicionamiento son comparables, aunque los nombres de las propiedades usan la convención snake_case de Firma.dev.

El límite es de 100 etiquetas de anclaje por solicitud de firma, lo que cubre la mayoría de los flujos de trabajo de documentos cómodamente. Si estás procesando documentos que realmente necesitan más de 100 campos, considera dividir en múltiples solicitudes de firma o usar una combinación de etiquetas de anclaje y definiciones de campo basadas en plantillas.

Referencia de API

El arreglo anchor_tags está disponible en el punto de creación de solicitudes de firma basadas en documentos (POST /signing-requests). Cada elemento en el arreglo es un objeto AnchorTag con aproximadamente 25 propiedades configurables.

Las propiedades clave:

anchor_string (obligatorio) es el marcador de texto que se busca en el PDF. type (obligatorio) es el tipo de campo a crear. recipient_id asigna el campo a un destinatario específico usando su ID o ID temporal. required marca el campo como obligatorio u opcional. offset_x y offset_y ajustan la posición del campo en relación al lugar del anclaje. width y height establecen dimensiones personalizadas para el campo. case_sensitive controla si la coincidencia es sensible a mayúsculas. whole_word previene coincidencias de cadenas parciales. occurrence apunta a una instancia específica cuando el anclaje aparece múltiples veces. match_all coloca campos en cada ocurrencia. ignore_if_not_present omite la etiqueta sin error si el texto de anclaje no se encuentra en el documento.

Para el esquema completo con todas las propiedades y sus tipos, consulta el registro de cambios de la API para v1.11.0.

Siguientes Pasos

Las etiquetas de anclaje van bien con la generación programática de documentos. Si tu aplicación genera contratos, NDA o documentos de incorporación a partir de plantillas, puedes insertar cadenas de anclaje durante la generación y dejar que Firma.dev maneje la colocación de campos automáticamente en cada solicitud.

Comienza con Firma.dev gratis, sin necesidad de tarjeta de crédito.

  1. Encabezado

Background Image

¿Listo para añadir firmas electrónicas a tu aplicación?

Comienza gratis. No se requiere tarjeta de crédito. Paga solo 0,029 € por sobre cuando estés listo para ponerlo en marcha.

Background Image

¿Listo para añadir firmas electrónicas a tu aplicación?

Comienza gratis. No se requiere tarjeta de crédito. Paga solo 0,029 € por sobre cuando estés listo para ponerlo en marcha.

Background Image

¿Listo para añadir firmas electrónicas a tu aplicación?

Comienza gratis. No se requiere tarjeta de crédito. Paga solo 0,029 € por sobre cuando estés listo para ponerlo en marcha.