Copiar página

Receta

Pon la firma dentro de tu app

Objetivo: Tu usuario firma sin salir de tu página, en una sesión de firma que solo se abre desde tu dominio.

Para: frontend · nivel intermedio · 15 min · Necesitas: API key de sandbox (solo en tu backend) · Tu dominio, aquí https://app.ejemplo.com · El SDK @allsign/embedded en tu frontend

Grabado en el entorno interno de AllSign con una key de sandbox · backend 24c0469 · · test docs-checks-v3/tests/recetas/firma-embebida-en-tu-app.receta.spec.ts

Los ejemplos usan $ALLSIGN_API_KEY. Defínela una vez con tu key de sandbox: export ALLSIGN_API_KEY="allsign_test_sk_…" (en PowerShell: $env:ALLSIGN_API_KEY="allsign_test_sk_…").

1 Crea el documento con su firmante y su caja de firma

POST /documents ver en la referencia

Qué haces

Todo lo que lleva tu API key pasa en tu backend: crear, enviar y abrir la sesión. El navegador nunca ve la key.

Qué mirar

  • id = "doc_e6d57f83692e4ff5ad07f57f6bd6a117"
  • status = "draft"

2 Envíalo sin mandar invitaciones

POST /documents/{document_id}/send ver en la referencia

Qué haces

recipients vacío pasa el documento a awaiting_signatures sin mandarle correo a nadie: la firma va a pasar dentro de tu página. Si lo envías sin recipients, AllSign invita por correo a cada firmante.

Qué mirar

  • status = "awaiting_signatures"

En producción

Con una key live este envío consume créditos aunque no invite a nadie; en sandbox no se cobra nada.

3 Confirma que nadie recibió invitación

GET /documents/{document_id}/signers ver en la referencia

Qué haces

pending: el firmante está en espera y no se le mandó nada. Con un envío normal aquí verías sent.

Qué mirar

  • data.0.status = "pending"

4 Abre una sesión de firma para ese firmante

POST /signing-sessions ver en la referencia

Qué haces

allowedOrigins dice qué páginas pueden mostrar la firma. A tu frontend solo le pasas el clientSecret: dura 15 minutos y sirve para una sola sesión, así que pídelo cuando tu usuario vaya a firmar.

Qué mirar

  • id = "ses_b702eecc5b8d4dd0a6b58d5a5f2c8f5a"
  • clientSecret = "<client-secret>"
  • expiresAt = "2026-07-11T18:15:01.869000Z"

5 AllSign hace el equivalente por ti: revisa la política de orígenes

GET /signing-sessions/{session_id}/policy sin API key ver en la referencia

Qué haces

Tu código no llama esta operación. Cuando el SDK abre la firma, AllSign consulta el equivalente desde su servidor y lo convierte en el encabezado Content-Security-Policy: frame-ancestors del iframe, que es lo que hace cumplir el navegador: tu página puede enmarcar la firma y cualquier otra no. Se muestra para que entiendas esa política y para depurar; localhost aparece para que pruebes en tu máquina.

Qué mirar

  • allowedOrigins = ["https://app.ejemplo.com"]
  • frameAncestors = "https://app.ejemplo.com http://localhost:*"

En producción

Si la llamas desde el navegador de tu página, falla en el preflight de CORS con un 400: la API v3 solo acepta peticiones de navegador desde orígenes de AllSign.

6 AllSign hace el equivalente por ti: inicia la sesión

POST /signing-sessions/{session_id}/init sin API key ver en la referencia

Qué haces

Tampoco la llama tu código. Cuando ejecutas AllSign.init({ clientSecret }), el iframe de AllSign inicia la sesión con una operación equivalente que revisa lo mismo que ves aquí: que el clientSecret sea válido y que la página que abre la firma (parentOrigin) esté en tus allowedOrigins. Se muestra para que entiendas qué se revisa y para depurar; en tu frontend basta con AllSign.init({ clientSecret }) y luego session.modal(), session.inline('#contenedor') o session.slider().

Qué mirar

  • signatureId = "sgr_fdcf573b43b24b2484b1a795ffff848f"
  • signer = {"email":"ana@ejemplo.com","name":"ana@ejemplo.com"}
  • document = {"id":"doc_e6d57f83692e4ff5ad07f57f6bd6a117","title":"Contrato de servicios — Ana Torres"}

En producción

Igual en producción. Llamarla desde el navegador de tu página falla en el preflight de CORS con un 400: de iniciar la sesión se encarga el SDK.

Errores comunes de esta receta

Errores reales que el test de esta receta provocó a propósito en sandbox, sobre sus mismos pasos. Cada uno enlaza a su explicación en Errores.

RESOURCE_NOT_FOUND · 404 · en el paso 4 (Abre una sesión de firma para ese firmante)

Abre una sesión para alguien que no firma el documento. Qué significa y qué hacer

Respuesta · 404 · RESOURCE_NOT_FOUND
{
  "type": "https://allsign.io/developers/docs/errors#RESOURCE_NOT_FOUND",
  "title": "Not Found",
  "status": 404,
  "detail": "No participant with email nadie@ejemplo.com on document c2af0193-88b8-4767-be86-e9bc40106542",
  "instance": "/v3/signing-sessions",
  "code": "RESOURCE_NOT_FOUND",
  "requestId": "req_243a82a23c1a45aba4757d8ed3758d31"
}

Grabado en el entorno interno de AllSign con una key de sandbox · backend 24c0469 · · test docs-checks-v3/tests/recetas/firma-embebida-en-tu-app.receta.spec.ts

PERMISSION_DENIED · 403 · en el paso 6 (AllSign hace el equivalente por ti: inicia la sesión)

Abre la firma en una página que no está en allowedOrigins. Qué significa y qué hacer

Así responde la API cuando la página que abre la firma no está en allowedOrigins; en tu página lo vas a ver de otra forma. Lo normal es que el navegador ni cargue el iframe y la consola muestre un error de Content-Security-Policy frame-ancestors. Si llega a cargar, la llamada con la que el iframe inicia la sesión responde 403 con el código ORIGIN_NOT_ALLOWED. En los dos casos, agrega ese origen exacto (esquema, dominio y puerto) a allowedOrigins al abrir la sesión.

Respuesta · 403 · PERMISSION_DENIED
{
  "type": "https://allsign.io/developers/docs/errors#PERMISSION_DENIED",
  "title": "Permission denied",
  "status": 403,
  "detail": "The origin 'https://otro.ejemplo.com' is not authorized to embed this session.",
  "instance": "/v3/signing-sessions/ses_ee38d79b09ad45b9ad094034c1910ecc/init",
  "code": "PERMISSION_DENIED",
  "requestId": "req_beaface9931b45e4a4eb9e51c8b13f9c"
}

Grabado en el entorno interno de AllSign con una key de sandbox · backend 24c0469 · · test docs-checks-v3/tests/recetas/firma-embebida-en-tu-app.receta.spec.ts

Siguiente