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 colocado campos de firma calculando coordenadas x/y en un PDF, sabes lo tedioso que se vuelve a gran escala. Cambia el diseño del documento y cada coordenada se rompe. Añade una segunda página y tendrás que recalcular los desplazamientos de la mitad de tus campos.

Las etiquetas ancla 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 esas ubicaciones. Los marcadores se eliminan del documento final, así que los firmantes nunca los ven. Una sola llamada a la API, sin cálculos de coordenadas.

Las etiquetas ancla se lanzaron en la v1.11.0 y admiten todos los tipos de campo, reglas de coincidencia flexibles y hasta 100 etiquetas por solicitud de firma.

Inicio rápido

La forma más rápida de hacer que las etiquetas ancla funcionen: inserta un marcador en tu PDF y luego crea una solicitud de firma con un array 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 hacerlo con la herramienta que genere 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 documento con la definición de la etiqueta ancla:

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 analiza el PDF en busca de {{SIGN_HERE}}, coloca un campo de firma en esa ubicación, lo asigna al destinatario y elimina el texto marcador del documento. Eso es todo.

Ten en cuenta que las etiquetas ancla solo funcionan con la creación de solicitudes de firma basadas en documento, no con las basadas en plantillas. Estás enviando el PDF en bruto y dejando que el sistema de anclaje gestione la colocación de los campos.

Tipos de campo admitidos

Las etiquetas ancla admiten todos los tipos de campo disponibles en Firma.dev. Establece la propiedad type en cada etiqueta ancla en 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 casillas de verificación, radio para grupos de botones de opción, dropdown para listas desplegables, url para campos URL, stamp para campos de sello y file para campos de carga de archivos.

Cada tipo muestra el widget de campo adecuado en la experiencia de firma. Una etiqueta ancla date crea un selector de fecha, una dropdown crea un menú desplegable, y así sucesivamente.

Opciones de coincidencia y posicionamiento

El comportamiento de coincidencia predeterminado funciona en la mayoría de los casos, pero puedes ajustar con más precisión cómo Firma.dev encuentra y posiciona los campos creados por anclaje.

Sensibilidad a mayúsculas y minúsculas: Establece case_sensitive en true o false (el valor predeterminado es false). Con coincidencia sin distinción de mayúsculas y minúsculas, {{sign_here}} y {{SIGN_HERE}} coinciden ambas.

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

Orientación de ocurrencias específicas: Si tu PDF contiene la misma cadena ancla varias veces, puedes dirigirte a ocurrencias concretas con occurrence. Establécelo en 1 para la primera coincidencia, 2 para la segunda y así sucesivamente. Omítelo o establece match_all en true para colocar campos en cada ocurrencia.

Posicionamiento mediante desplazamiento: Ajusta con precisión dónde se sitúa el campo con respecto al texto ancla 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 quieres que el campo quede ligeramente debajo o a la derecha del marcador, en lugar de directamente encima.

Gestión elegante de anclajes ausentes: Establece ignore_if_not_present en true si la cadena ancla puede no existir en todos los documentos. Sin esto, un anclaje ausente devuelve un error. Con ello activado, Firma.dev omite silenciosamente esa etiqueta y procesa el resto.

Configuración avanzada

Aquí tienes un ejemplo más completo que combina varias etiquetas ancla 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
        }
      ]
    })
  }
);

Cosas a tener en cuenta en este ejemplo. La etiqueta {{EMPLOYEE_INITIALS}} usa match_all: true, así que si el PDF tiene marcadores de iniciales en las páginas 1, 5 y 12, los tres reciben campos. La casilla {{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 del campo de firma lo desplaza ligeramente hacia abajo desde la posición del texto ancla.

Las dimensiones (width y height) siguen el mismo sistema de coordenadas basado en porcentajes que usan los campos posicionados manualmente. Las etiquetas ancla y los campos manuales funcionan conjuntamente, así que puedes usar anclas para la mayor parte de tus campos y seguir añadiendo campos manuales basados en coordenadas en la misma solicitud para casos límite.

Migración desde otras plataformas

Si estás migrando desde otro proveedor de firma electrónica que usa colocación de campos basada en texto, los conceptos se corresponden directamente. La sintaxis de la cadena ancla y los nombres de las propiedades difieren, pero el mecanismo subyacente es el mismo: incrusta un marcador, define el tipo de campo y deja que la API gestione la colocación.

Desde la colocación automática de DocuSign: DocuSign usa anchorString, anchorXOffset, anchorYOffset y tipos específicos de pestaña como signHereTabs. En Firma.dev, esto se convierte en anchor_string, offset_x, offset_y y el campo universal type. anchorIgnoreIfNotPresent de DocuSign se corresponde con ignore_if_not_present. anchorCaseSensitive de DocuSign se corresponde con case_sensitive. La principal diferencia estructural es que Firma.dev usa un único anchor_tags array con una propiedad type, en lugar de arrays separados para cada tipo de pestaña.

Desde Smart Anchors de Yousign: El concepto de «smart anchors» de Yousign con detección del 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 ancla por solicitud de firma, lo que cubre cómodamente la mayoría de los flujos de trabajo de documentos. Si procesas documentos que realmente necesitan más de 100 campos, considera dividirlos en varias solicitudes de firma o usar una combinación de etiquetas ancla y definiciones de campos basadas en plantillas.

Referencia de la API

El array anchor_tags está disponible en el endpoint de creación de solicitudes de firma basado en documento (POST /signing-requests). Cada elemento del array es un objeto AnchorTag con unas 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 que se va 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 con respecto a la ubicación del ancla. width y height establecen dimensiones personalizadas del campo. case_sensitive controla si la coincidencia distingue entre mayúsculas y minúsculas. whole_word evita coincidencias parciales de cadenas. occurrence apunta a una instancia específica cuando el ancla aparece varias veces. match_all coloca campos en cada ocurrencia. ignore_if_not_present omite la etiqueta sin error si el texto ancla no se encuentra en el documento.

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

Siguientes pasos

Las etiquetas ancla combinan bien con la generación programática de documentos. Si tu app genera contratos, NDAs o documentos de incorporación a partir de plantillas, puedes incrustar cadenas ancla durante la generación y dejar que Firma.dev gestione la colocación de los campos automáticamente en cada solicitud.

Empieza gratis con Firma.dev, sin tarjeta de crédito requerida.

  1. Encabezado

Imagen de fondo

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

Comienza gratis. No se requiere tarjeta de crédito. Paga solo 0,049 € por sobre cuando estés listo para empezar.

Imagen de fondo

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

Comienza gratis. No se requiere tarjeta de crédito. Paga solo 0,049 € por sobre cuando estés listo para empezar.

Imagen de fondo

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

Comienza gratis. No se requiere tarjeta de crédito. Paga solo 0,049 € por sobre cuando estés listo para empezar.