Tutorial de inicio rápido
¿Usas Cursor, Claude u otra herramienta de codificación basada en IA? Conéctala con la documentación de Legalesign para obtener ayuda contextual mientras sigues este tutorial.
En este tutorial completarás las llamadas API clave que la mayoría de los desarrolladores necesitan para una integración de firma electrónica: subir un documento y enviarlo para firma.
La API de Legalesign es escalable, versátil y ha sido probada en producción en los sistemas de nuestros clientes durante muchos años. Puedes usarla para un documento con un solo firmante, o enviar documentos para testigos o aprobaciones, optimizada para lotes, con formularios y más. Puedes integrarla para un propósito único o incrustarla dentro de tu software para tus clientes - ver integraciones.
La API REST realiza la mayoría de las funciones y es la forma más fácil de comenzar. Si necesitas más, revisa la interfaz GraphQL. Legalesign es API primero con GraphQL. Puedes usar cualquiera, según prefieras.
Seguiremos estos pasos:
- Crear una cuenta + clave API (ver Obtén verificación para acceso API).
- Confirmar que las credenciales funcionan y obtener tu ID de equipo.
- Subir un documento vía la app web.
- Enviar ese documento para firmar vía API.
- Descargarlo después de firmado.
- Subir un documento vía API.
La API REST de Legalesign es fácil de usar. La referencia técnica incluye un editor de código. Puedes hacer solicitudes directamente desde la referencia técnica con tu clave API, o simplemente copiar y pegar directamente en tu código.
Figura 1: El editor de código de la API REST.
Bibliotecas cliente
O para la interfaz GraphQL Node.js
Recomendamos que los desarrolladores trabajen directamente con la API en lugar de los SDKs. Para ayudar, hay un generador de código para copiar y pegar en la especificación técnica, y tu IA puede producir ejemplos rápidamente usando la especificación OpenAPI. ¿Por qué? La API fuente tiene más funcionalidad que los SDKs, de todos modos querrás conocer los endpoints que usas, evitarás sobrecarga de abstracción y dependencias, y—basado en nuestra experiencia—lo harás más rápido también.
1. Crear una cuenta
Ve a registro en legalesign y sigue el proceso para crear una cuenta.
Se te pedirá crear un equipo. Los equipos son la base de Legalesign. Todo el procesamiento de documentos ocurre en un equipo. Debes referirte a tu equipo en la mayoría de las llamadas API.
Un 'equipo' o un 'grupo' es lo mismo. En la app web hablamos de 'equipos', pero en el esquema API es un grupo.
Ajustes API
Ve al Panel de API. Genera tus credenciales API en la sección Clave API.
Tómate un momento para revisar el Portal para Desarrolladores.
Entorno de pruebas (Sandbox)
En la sección de Entorno, una alerta muestra si estás en modo sandbox o producción.
El sandbox limita dónde puedes enviar tus documentos. Verás un formulario para añadir hasta 5 correos electrónicos aprobados - añade algunos ahora.
Cuando tu integración esté lista: pasa a modo producción.
Crea un segundo equipo. Usa tu primer equipo para desarrollo y los otros(s) para producción. Informa soporte del nombre de tu equipo de desarrollo para excluirlo de facturación.
Clave API
En la sección Clave API verás los detalles de tus claves. Solo verás la clave cuando crees una.
La sección de Inicio rápido contiene ejemplos para copiar y pegar y probar tu clave.

Webhooks y registros
Agrega webhooks (listeners para eventos de Legalesign) y revisa tus registros.

2. Una solicitud GET exitosa
La url raíz siempre es: https://eu-api.legalesign.com/
Comienza con una solicitud GET para confirmar que tus credenciales funcionan. Reemplaza los valores de usuario y secreto en el código siguiente.
En los ejemplos se usa curl, y puedes cambiar entre cURL, Node.js, Python, C#, y Go usando las pestañas siguientes.
- cURL
- Node.js
- Python
- C#
- Go
curl -H "Authorization: ApiKey username:secret" -H "Content-Type: application/json" -X GET https://eu-api.legalesign.com/api/v1/group/
import fetch from 'node-fetch';
async function getGroups() {
const response = await fetch('https://eu-api.legalesign.com/api/v1/group/', {
method: 'GET',
headers: {
'Authorization': 'ApiKey username:secret',
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
const data = await response.json();
console.log(data);
}
getGroups().catch((error) => {
console.error(error);
process.exit(1);
});
import requests
headers = {
"Authorization": "ApiKey username:secret",
"Content-Type": "application/json",
}
response = requests.get(
"https://eu-api.legalesign.com/api/v1/group/",
headers=headers,
timeout=30,
)
response.raise_for_status()
print(response.json())
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
using var client = new HttpClient();
using var request = new HttpRequestMessage(
HttpMethod.Get,
"https://eu-api.legalesign.com/api/v1/group/"
);
request.Headers.TryAddWithoutValidation("Authorization", "ApiKey username:secret");
request.Headers.TryAddWithoutValidation("Content-Type", "application/json");
using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}
}
package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://eu-api.legalesign.com/api/v1/group/", nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "ApiKey username:secret")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
log.Fatalf("request failed: %s", resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
Documentación API: Referencia API GET grupo.
Al ejecutar la consulta anterior, verás tus grupos devueltos en JSON. Éxito. 👏
Los datos de la respuesta contienen el 'resource uri' para tu grupo y se ve así /api/v1/group/:groupId/. Toma nota de esto, lo necesitarás para la mayoría de llamadas API.
Un resource uri siempre tendrá el mismo formato. Para un PDF sería '/api/v1/templatepdf/:pdfId/', para un documento enviado será '/api/v1/document/:documentId/'. Observa que todos los URIs terminan con una barra. Lo mismo se aplica a las URLs para tus llamadas API, siempre terminan con barra.
Si la solicitud GET falla revisa que:
- tu ApiKey esté correctamente formateada (comience con 'ApiKey'),
- tengas un header Content-Type como application/json, y
- tu url termine con una barra.
/rest-api/how-to/troubleshooting).
3. Subir un documento vía la app web
Para empezar, subiremos un documento a través de la app web y lo enviaremos vía API. Cubriremos cómo subir un documento vía API más adelante.
Ve a la app web y sube tu documento. Añade un rol para un solo firmante y arrastra un campo de firma. La página del editor indicará si el documento es 'válido' (un ejemplo de 'inválido' sería si añades un rol de firmante sin un campo de firma relacionado).
En el editor del formulario, copia la larga ID alfanumérica de la URL, decodifícala en base64 y descarta las primeras 3 letras (que deberían ser 'tpl'). Lo que resta es un UUID que es tu ID.
En lenguaje REST API el resource uri para este documento es /api/v1/templatepdf/UUID/.
Aprende más sobre IDs de web y API.
Nuestra nomenclatura es que un documento subido es una 'plantilla' y cuando envías una creas un 'documento'.
Si quieres archivar una plantilla cuando el documento es enviado, configura 'archive_upon_send' como atributo en la solicitud de subida. Si quieres que la plantilla nunca aparezca y se elimine después de enviar, pon el título '[deleted]' - nuestros sistemas de limpieza lo detectarán y eliminarán después de uno o dos días. También puedes establecer tiempos de retención cortos a nivel de grupo - aprende más.
4. Enviar un documento para firma
Ahora enviamos esto vía API. Recuerda usar un correo aprobado en tu sandbox. Usa las pestañas para obtener la solicitud en tu lenguaje preferido.
- cURL
- Node.js
- Python
- C#
- Go
curl -H "Authorization: ApiKey [username]:[secret]" -H "Content-Type: application/json" -X POST --data '{ "group": "/api/v1/group/[:groupId]/", "name": "Name of doc", "templatepdf": "/api/v1/templatepdf/UUID/", "signers": [{"firstname": "Joe", "lastname": "Bloggs", "email": "[your@email.com]", "order": 0 }], "do_email": true }' https://eu-api.legalesign.com/api/v1/document/
import fetch from 'node-fetch';
const payload = {
group: '/api/v1/group/[:groupId]/',
name: 'Name of doc',
templatepdf: '/api/v1/templatepdf/UUID/',
signers: [
{
firstname: 'Joe',
lastname: 'Bloggs',
email: '[your@email.com]',
order: 0,
},
],
do_email: true,
};
async function sendDocument() {
const response = await fetch('https://eu-api.legalesign.com/api/v1/document/', {
method: 'POST',
headers: {
'Authorization': 'ApiKey [username]:[secret]',
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (response.status !== 201) {
const errorBody = await response.text();
throw new Error(`Request failed with status ${response.status}: ${errorBody}`);
}
console.log('Document sent successfully');
const location = response.headers.get('location');
if (location) {
console.log(`Location: ${location}`);
}
}
sendDocument().catch((error) => {
console.error(error);
process.exit(1);
});
import requests
payload = {
"group": "/api/v1/group/[:groupId]/",
"name": "Name of doc",
"templatepdf": "/api/v1/templatepdf/UUID/",
"signers": [
{
"firstname": "Joe",
"lastname": "Bloggs",
"email": "[your@email.com]",
"order": 0,
}
],
"do_email": true,
}
headers = {
"Authorization": "ApiKey [username]:[secret]",
"Content-Type": "application/json",
}
response = requests.post(
"https://eu-api.legalesign.com/api/v1/document/",
json=payload,
headers=headers,
timeout=30,
)
response.raise_for_status()
print("Document sent successfully")
print("Location:", response.headers.get("Location"))
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
var payload = new
{
group = "/api/v1/group/[:groupId]/",
name = "Name of doc",
templatepdf = "/api/v1/templatepdf/UUID/",
signers = new[]
{
new
{
firstname = "Joe",
lastname = "Bloggs",
email = "[your@email.com]",
order = 0,
},
},
do_email = true,
};
using var client = new HttpClient();
using var request = new HttpRequestMessage(
HttpMethod.Post,
"https://eu-api.legalesign.com/api/v1/document/"
);
request.Headers.TryAddWithoutValidation("Authorization", "ApiKey [username]:[secret]");
var json = JsonSerializer.Serialize(payload);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine("Document sent successfully");
if (response.Headers.Location is not null)
{
Console.WriteLine($"Location: {response.Headers.Location}");
}
}
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
)
func main() {
payload := map[string]any{
"group": "/api/v1/group/[:groupId]/",
"name": "Name of doc",
"templatepdf": "/api/v1/templatepdf/UUID/",
"signers": []map[string]any{
{
"firstname": "Joe",
"lastname": "Bloggs",
"email": "[your@email.com]",
"order": 0,
},
},
"do_email": true,
}
body, err := json.Marshal(payload)
if err != nil {
log.Fatal(err)
}
req, err := http.NewRequest(
http.MethodPost,
"https://eu-api.legalesign.com/api/v1/document/",
bytes.NewReader(body),
)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "ApiKey [username]:[secret]")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusCreated {
log.Fatalf("unexpected status: %s", resp.Status)
}
fmt.Println("Document sent successfully")
fmt.Println("Location:", resp.Header.Get("Location"))
}
Actualiza todos los corchetes. Referencia API para enviar un documento.
Cuando visites la documentación referencia para enviar un documento revisa bien todos los posibles atributos. Verás muchos que ayudarán con las cuestiones prácticas de una integración: etiquetas para tus propias referencias e IDs (que volverán a ti en webhooks), un redireccionamiento para los firmantes, texto personalizado en el pdf, y más.
Una llamada exitosa devuelve código de estado 201. ✨
Obtener el nuevo id del documento enviado
La parte importante de la respuesta es el header location. Este contiene el id nuevo del documento.
Usa atributos 'tag' del documento y añade tus propias referencias para facilitar la vinculación con tu base de datos.
El header location tendrá este aspecto: /api/v1/status/:documentId/.
El URI 'status' devuelve un conjunto breve (y rápido de consultar) de atributos del documento.
Para solicitar todo de un documento usa /api/v1/document/:documentId/.
Si una solicitud falla, el CUERPO de la respuesta normalmente contiene información de error. Si no obtienes un estado exitoso, revisa el CUERPO por texto explicativo. También consulta solución de problemas.
Aprende más sobre la llamada API Enviar Documento.
5. Descargar el documento firmado
Con el ID del documento enviado que recibiste, haz una solicitud de descarga de PDF en el lenguaje que prefieras:
- cURL
- Node.js
- Python
- C#
- Go
curl -H "Authorization: ApiKey [username]:[secret]" -o download.pdf -X GET https://eu-api.legalesign.com/api/v1/pdf/:documentId/
import { writeFile } from 'node:fs/promises';
import fetch from 'node-fetch';
async function downloadPdf() {
const response = await fetch('https://eu-api.legalesign.com/api/v1/pdf/:documentId/', {
method: 'GET',
headers: {
'Authorization': 'ApiKey [username]:[secret]',
},
});
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
const buffer = await response.arrayBuffer();
await writeFile('download.pdf', Buffer.from(buffer));
console.log('Saved download.pdf');
}
downloadPdf().catch((error) => {
console.error(error);
process.exit(1);
});
import requests
headers = {"Authorization": "ApiKey [username]:[secret]"}
response = requests.get(
"https://eu-api.legalesign.com/api/v1/pdf/:documentId/",
headers=headers,
stream=True,
timeout=30,
)
response.raise_for_status()
with open("download.pdf", "wb") as file:
for chunk in response.iter_content(chunk_size=8192):
file.write(chunk)
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
using var client = new HttpClient();
using var request = new HttpRequestMessage(
HttpMethod.Get,
"https://eu-api.legalesign.com/api/v1/pdf/:documentId/"
);
request.Headers.TryAddWithoutValidation("Authorization", "ApiKey [username]:[secret]");
using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var bytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("download.pdf", bytes);
Console.WriteLine("Saved download.pdf");
}
}
package main
import (
"io"
"log"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest(
http.MethodGet,
"https://eu-api.legalesign.com/api/v1/pdf/:documentId/",
nil,
)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "ApiKey [username]:[secret]")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
log.Fatalf("request failed: %s", resp.Status)
}
file, err := os.Create("download.pdf")
if err != nil {
log.Fatal(err)
}
defer file.Close()
if _, err := io.Copy(file, resp.Body); err != nil {
log.Fatal(err)
}
log.Println("Saved download.pdf")
}
El binario PDF va en el cuerpo de la respuesta. El comando curl '-o' coloca el CUERPO de la respuesta directamente en un archivo.
Muchas bibliotecas REST o HTTP tratan los objetos respuesta HTTP como si fueran archivos; en ese caso simplemente guarda tu objeto respuesta como un archivo normal.
Usa webhooks para ser notificado de un evento de firma y luego descarga el documento. Ver webhooks.
6. Subir un PDF
Haz clic aquí para descargar un PDF de ejemplo con etiquetas de texto, más sobre campos de formulario PDF a continuación.
Para esta llamada, convierte tu PDF en una cadena codificada en base64. Esto no se hace correctamente en el generador de código de la documentación. En su lugar, copia este pseudocódigo y tu IA amigable lo convertirá a tu lenguaje preferido:
$data = (
'group': '/api/v1/group/:groupId/',
'title': 'title of pdf',
'pdf_file': base64encode(open('/path/to/file','rb')),
'process_tags': true
)
$headers = (
'Authorization': 'ApiKey username:secret',
'Content-Type': 'application/json'
)
response = httplibrary.post('https://eu-api.legalesign.com/api/v1/templatepdf/', jsonEncode($data), $headers)
assert response.status == 201
pdfId = response.headers['location']
Referencia API para subir PDF.
Como de costumbre, una respuesta exitosa POST devolverá estado '201' y el nuevo ID estará en el header 'location' de la respuesta.
assert response.status == 201
pdfId = response.headers['location']
Tu resource URI para pdf será /api/v1/templatepdf/:pdfId/.
Enviar el nuevo PDF
Vuelve al código que usaste para enviar tu primer documento y reemplaza el valor templatepdf.
Haz la solicitud de nuevo y eso es todo, enviaste tu PDF para firmar.
Antes de comenzar a programar, sin embargo, sigue leyendo para aprender más sobre campos PDF.
¿Qué pasa con los campos PDF?
¿Cómo sabe Legalesign dónde debe firmar la persona en el PDF, o qué secciones cambiar al enviarlo? La respuesta es que nuestro PDF fue preparado previamente con etiquetas: colocamos una etiqueta de texto Legalesign dentro del PDF y configuramos 'process_tags' en true en la solicitud de subida del PDF.
Descarga un PDF de ejemplo con etiquetas de texto.
Las etiquetas de texto son texto especialmente formateado para poner en un PDF. Legalesign parseará el texto en tu archivo, reemplazando las etiquetas con campos de firma y formulario. Para un firmante solo necesitas agregar: <<t=signature>>. Legalesign lo identificará y ubicará ahí la firma. Aprende sobre etiquetas de texto.
Las etiquetas de texto tienen curva de aprendizaje y requieren prueba y error. Otros métodos se detallan a continuación, pero con ellas obtienes toda la capacidad del sistema de formularios Legalesign. Usa la app web para probar etiquetas. Contacta a soporte para ayuda y ejemplos.
Aquí hay 4 formas adicionales de configurar campos:
1. La versión más fácil/rápida. Configura tu PDF usando la app web de Legalesign.
Después de subir un PDF irás a la interfaz de editor donde puedes arrastrar y soltar campos de formulario.
Arrastra y suelta una firma, luego anota la ID codificada en la dirección web. Será algo como 'dHBsMTRlZTQ0ZWUtZGE0Ni0xMWVmLTllZmUtMDI5ZGQ0ODkzZGRk'.
Decodifica esta ID de base64 y verás que es un UUID precedido por 'tpl'. La parte UUID (quita 'tpl') es tu pdfID. Aprende más sobre IDs Legalesign.
Tu resource URI API PDF será - /api/v1/templatepdf/:pdfId/.
Pon eso en el atributo 'templatepdf' de la llamada de envío de documento.
Si piensas enviar este PDF más de una vez, asegúrate de que 'Auto archive' esté desactivado. Ver cómo
2. Usa coordenadas x/y para campos.
La forma más simple de comenzar con coordenadas x/y es configurar un PDF en la app web y luego consultar vía API esos campos (GET Campos PDF - /api/v1/templatepdf/:pdfId/fields/).
El objeto JSON que recibes es el mismo esquema JSON que necesitas para crear campos.
Úsalo como plantilla. Modifica los valores y haz POST al mismo endpoint (ajustando el ID de PDF según corresponda). Endpoint para crear campo PDF.
3. Incrusta nuestra página de edición PDF. NUEVO!
Usa nuestro componente editor para incrustar nuestro editor PDF directamente en tu propia app. Aprende más sobre el componente editor de documentos.
4. Campos de formulario PDF NUEVO!
Si tu PDF contiene campos normales de formulario PDF, Legalesign puede importarlos automágicamente.
¡Feliz codificación!
En este tutorial adquiriste credenciales API, consultaste exitosamente tus grupos, enviaste un documento para firmar usando HTML y PDF, y descargaste un documento firmado.
¡Feliz codificación! Estamos aquí para ayudar, contacta soporte para cualquier asistencia.
Genial, llegaste al final—gracias por leer esto. Nuestra última solicitud y consejo, basado en años de experiencia de desarrolladores integrando esta API, es que te tomes un momento para leer todos los atributos en el endpoint de creación de documento (y hagas clic para ver qué contienen 'signers', 'pdftext' y 'signertext*) - es la llamada más importante en tu integración. Crear un documento para firmar.