Copiar página

Receta

Varios firmantes, uno después de otro

Objetivo: Un contrato que firma primero la vendedora y después el comprador, con el comprador sin poder firmar antes de su turno.

Para: integrador · nivel intermedio · 15 min · Necesitas: API key de sandbox · contrato.pdf · Un endpoint HTTPS para webhooks

Grabado en el entorno interno de AllSign con una key de sandbox · backend 24c0469 · · test docs-checks-v3/tests/recetas/varios-firmantes-en-orden.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 Registra tu endpoint de webhooks

POST /webhooks ver en la referencia

Qué haces

Con dos firmantes, cada firma te llega como signer.signed y el cierre como document.completed.

Qué mirar

  • id = "whe_f3ae04f2292e4bb78fc753c4229ba55e"
  • secret = "whsec_…"

2 Crea el documento con el orden de firma

POST /documents ver en la referencia

Qué haces

signingOrder: sequential exige routingOrder en cada firmante: la etapa 1 firma primero y la 2 no recibe nada hasta que la 1 termina. Firmantes con el mismo número firman a la vez. Cualquier correo de @sandbox.allsign.io que no sea signer-success@ ni signer-declined@ se queda pendiente y no recibe correo; aquí usamos dos.

Qué mirar en sandbox

  • id = "doc_c0d4a131b744480689aa24b2f39215cf"
  • signingOrder = "sequential"
  • signerCount = 2

3 Envíalo a firma

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

Qué haces

Solo la etapa activa recibe su invitación: por ahora, la vendedora.

Qué mirar

  • status = "awaiting_signatures"
  • currentStage = 1

En producción

Con una key live el envío consume créditos de tu saldo; en sandbox no se cobra nada.

4 Revisa a quién le toca

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

Qué haces

El comprador está en waiting_turn: existe, pero todavía no tiene liga ni puede firmar.

Qué mirar

  • data.0.status = "waiting_turn"
  • data.0.routingOrder = 2
  • data.1.status = "sent"
  • data.1.routingOrder = 1

5 Intenta firmar por el comprador antes de su turno

POST /sandbox/signers/{signer_id}/sign ver en la referencia

Qué haces

Mientras su etapa no abre, nadie firma por el comprador: el orden lo hace cumplir la API, no tu interfaz.

6 Firma por la vendedora (solo en sandbox)

POST /sandbox/signers/{signer_id}/sign ver en la referencia

Qué haces

Al terminar la etapa 1, AllSign abre la 2 e invita al comprador.

Qué mirar

  • status = "signed"
  • signedAt = "2026-07-11T18:00:05.610000Z"

En producción

Aquí firma la vendedora desde su correo o WhatsApp. Esta operación solo funciona en sandbox.

7 Recuérdale al comprador que ya le toca

POST /documents/{document_id}/signers/{signer_id}/remind ver en la referencia

Qué haces

La etapa 2 se abrió en la misma llamada en que firmó la vendedora. Si el comprador tarda, recuérdale: le reenvía su invitación. En sandbox ningún mensaje sale a @sandbox.allsign.io: delivered viene en false y nextAllowedAt es el mismo instante.

Qué mirar

  • delivered = false
  • nextAllowedAt = "2026-07-11T18:00:06.241000Z"

En producción

Le llega de nuevo el correo o el WhatsApp y delivered viene en true. El siguiente recordatorio a esa persona espera 4 horas: antes de nextAllowedAt la API responde 429.

8 Firma por el comprador (solo en sandbox)

POST /sandbox/signers/{signer_id}/sign ver en la referencia

Qué haces

Era la última firma: el documento se cierra y su evidencia se genera.

Qué mirar

  • status = "signed"

En producción

Aquí firma el comprador desde su invitación.

9 Espera el webhook document.completed

POST tu endpoint · evento document.completed

Qué haces

Llega cuando firmó la última etapa y la evidencia ya está lista.

AllSign le hace POST a la URL que registraste, con el evento document.completed. Responde 2xx rápido y, antes de confiar en el cuerpo, verifica la firma: webhook-signature es un HMAC-SHA256 de webhook-id.webhook-timestamp.cuerpo con el secreto del webhook (Webhooks).

Esta entrega llegó de verdad al receptor del test y su firma se verificó con el secreto del webhook.

Qué mirar

  • data.status = "completed"

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.

VALIDATION_ERROR · 422 · en el paso 2 (Crea el documento con el orden de firma)

Pide sequential y olvida el routingOrder de un firmante. Qué significa y qué hacer

Respuesta · 422 · VALIDATION_ERROR
{
  "type": "https://allsign.io/developers/docs/errors#VALIDATION_ERROR",
  "title": "Validation failed",
  "status": 422,
  "detail": "One or more fields are invalid.",
  "instance": "/v3/documents",
  "code": "VALIDATION_ERROR",
  "requestId": "req_6a8f96e3b2cc40ffa35ad785489ef781",
  "errors": [
    {
      "code": "INVALID_VALUE",
      "detail": "signingOrder='sequential' requires 'routingOrder' on every signer; missing at signers[1]."
    }
  ]
}

Grabado en el entorno interno de AllSign con una key de sandbox · backend 24c0469 · · test docs-checks-v3/tests/recetas/varios-firmantes-en-orden.receta.spec.ts

NOT_YOUR_TURN · 409 · en el paso 7 (Recuérdale al comprador que ya le toca)

Recuérdale al comprador antes de su turno. Qué significa y qué hacer

Respuesta · 409 · NOT_YOUR_TURN
{
  "type": "https://allsign.io/developers/docs/errors#NOT_YOUR_TURN",
  "title": "Conflict",
  "status": 409,
  "detail": "Signer belongs to stage 2 and stage 1 has not finished — nothing to remind yet.",
  "instance": "/v3/documents/doc_0b2b0e22e2f74967b71978464dc385c7/signers/sgr_9986142474b44b3782418f09da8b366f/remind",
  "code": "NOT_YOUR_TURN",
  "requestId": "req_f75b6541f8f540aaa398ccc8c4e240f8",
  "reason": "not_your_turn"
}

Grabado en el entorno interno de AllSign con una key de sandbox · backend 24c0469 · · test docs-checks-v3/tests/recetas/varios-firmantes-en-orden.receta.spec.ts

Siguiente