Desarrolladores · API · Webhooks

Un POST. Enviado a firmar.

Una API REST para enviar PDF a firmar y seguir a cada firmante, webhooks firmados para cada paso, claves de idempotencia y códigos de error estables. Las claves API y los webhooks están incluidos en el plan Enterprise.

Lo que puedes construir: firmas desde tu propio software
curl https://api.wesign.now/v1/signing-requests \
  -H "Authorization: Bearer $WSK_KEY" \
  -H "Idempotency-Key: order-123/sign" \
  -F "file=@contract.pdf" \
  -F 'signers=[{"email":"jane@acme.com","role":"client"}]' \
  -F "placement=auto_append"

# → 201 Created
# {
#   "documentId": "8a1e4f9a-…",
#   "status": "pending",
#   "signers": [{
#     "role": "client",
#     "signingUrl": "https://acme.wesign.now/en/sign/…",
#     "emailed": true, …
#   }], …
# }
Qué obtienes

Una API, webhooks y una documentación que también leen tus herramientas.

API REST

Envía un PDF, sigue a cada firmante, envía un recordatorio o retira la solicitud, y descarga el PDF sellado y su registro de auditoría. Claves Bearer, respuestas JSON y una especificación OpenAPI 3.1 con un id para cada operación.

Resumen de la API

Webhooks firmados

signing_request.sent, .viewed, .signed, document.completed y más, cada uno firmado con HMAC-SHA256. Una entrega fallida se reintenta durante unas 45 horas; desde el registro de entregas puedes volver a enviarla.

Eventos de webhook

Documentación para asistentes de IA

llms.txt enumera cada página de la documentación, llms-full.txt las contiene todas en texto plano, y openapi.json la forma exacta de solicitudes y respuestas. Dáselos a tu asistente de programación.

Para asistentes de IA

Ejemplos concretos.

Cuatro llamadas que necesitan la mayoría de las integraciones. Nombres de campo como en la especificación OpenAPI.

1. Envío con colocación por ancla

Pon en tu PDF un marcador como [[ls:signature:buyer]]. Colocamos ahí el campo de firma del comprador y ocultamos el marcador. ¿Sin marcador en el PDF? Añadimos una página de firma.

POST /v1/signing-requests
Content-Type: multipart/form-data

file=@offer.pdf        # the PDF contains [[ls:signature:buyer]]
signers=[{"email":"buyer@acme.com","role":"buyer","name":"Ann Buyer"}]
placement=anchors

2. Varios firmantes, en orden

Tres firmantes, uno tras otro. El firmante 2 recibe la invitación solo cuando el firmante 1 ha firmado.

POST /v1/signing-requests
Content-Type: multipart/form-data

file=@contract.pdf
signing_mode=sequential
placement=auto_append
signers=[
  {"email":"founder@acme.com","role":"founder"},
  {"email":"investor@vc.example","role":"investor"},
  {"email":"witness@law.example","role":"witness"}
]

3. Receptor de webhook

Comprueba la marca de tiempo y el HMAC sobre el cuerpo sin procesar y luego actúa según el evento.

// Node + Express. The full verifier (Node and PHP) is in the docs.
app.post('/wesign/callback', express.raw({ type: 'application/json' }), (req, res) => {
  // X-WeSign-Signature: t=<unix seconds>,v1=<hex>  (two v1 for 24 h after a rotation)
  const parts = (req.get('x-wesign-signature') ?? '').split(',')
  const t = parts[0]?.startsWith('t=') ? parts[0].slice(2) : ''
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.status(401).end()
  const expected = crypto.createHmac('sha256', SECRET)
    .update(`${t}.${req.body}`).digest()
  const valid = parts.filter((p) => p.startsWith('v1=')).some((p) => {
    const got = Buffer.from(p.slice(3), 'hex')
    return got.length === expected.length && crypto.timingSafeEqual(got, expected)
  })
  if (!valid) return res.status(401).end()

  const evt = JSON.parse(req.body.toString('utf8'))
  if (evt.event === 'document.completed') {
    // fetch evt.signed_pdf_url with your API key, compare evt.sha256, keep a copy
  }
  res.sendStatus(200)
})

4. Reintento idempotente

La misma clave con el mismo cuerpo en 24 horas repite la primera respuesta, así que un reintento tras un error de red nunca envía dos veces.

POST /v1/signing-requests
Idempotency-Key: order-123/sign

# First call:                      201 Created
# Same key + same body (24 h):     201, the same body, Idempotent-Replayed: true
# Same key while the first runs:   409 idempotency_in_progress + Retry-After
# Same key + a different body:     422 idempotency_key_reuse

Hecho para producción.

Claves Bearer, dos alcances

Cada clave pertenece a un solo workspace. Una clave full llama a toda la API; una clave embedded solo gestiona sesiones de firma integrada. Limita una clave a tus direcciones IP; una revocación surte efecto al momento.

60 solicitudes por minuto y clave

Una ventana fija por clave en todos los endpoints /v1. Las respuestas correctas llevan las cabeceras RateLimit-*; un 429 lleva Retry-After.

Códigos de error estables

Cada error es un JSON con un mensaje legible (error), un code estable y, donde ayuda, meta. Compara el code; el mensaje puede cambiar.

PDF sellados y verificables

El PDF firmado lleva un sello PAdES que cualquier lector compatible puede verificar. El registro de auditoría lista cada evento con su hora, el correo y la dirección IP enmascarada del firmante, y cada verificación por código SMS.

El acceso a la API viene con Enterprise.

Las claves API y los webhooks forman parte del plan Enterprise. Cuéntanos qué quieres conectar. La documentación es pública, así que puedes leerla antes.