Skip to main content
After the user signs, your backend creates the final PDF using the SuperDoc API.

Flow

Frontend sends → Backend processes → PDF created
    ↓                   ↓                 ↓
Signing data    1. Annotate fields    Stored
                2. Apply signature

Complete example

app.post('/api/sign', async (req, res) => {
  try {
    const { eventId, document, auditTrail, documentFields, signerFields, signer } = req.body;

    if (!document?.url) {
      return res.status(400).json({ error: 'document.url is required' });
    }
    
    // 1. Fill document fields
    const annotated = await fetch('https://api.superdoc.dev/v1/annotate?to=pdf', {
      method: 'POST',
      headers: { 
        'Authorization': `Bearer ${process.env.SUPERDOC_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        document: { url: document.url },
        fields: [...documentFields, ...signerFields]
      })
    });
    
    if (!annotated.ok) throw new Error('Annotation failed');
    
    // 2. Apply digital signature
    const annotatedData = await annotated.json();
    const signed = await fetch('https://api.superdoc.dev/v1/sign', {
      method: 'POST', 
      headers: { 
        'Authorization': `Bearer ${process.env.SUPERDOC_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        eventId,
        document: { base64: annotatedData?.document?.base64 },
        auditTrail,
        signer
      })
    });
    
    if (!signed.ok) throw new Error('Signing failed');
    
    // 3. Save signed PDF
    const signedData = await signed.json();
    const signedPdfBase64 = signedData?.document?.base64;
    await saveToS3(Buffer.from(signedPdfBase64, 'base64'), `signed/${eventId}.pdf`);

    // 4. Log for compliance
    await db.signatures.create({
      eventId,
      signerName: signerFields.find(f => f.id === '1')?.value,
      signedAt: new Date(),
      auditTrail: JSON.stringify(auditTrail)
    });
    
    res.json({ success: true, documentId: eventId });
    
  } catch (error) {
    console.error('Signing failed:', error);
    res.status(500).json({ error: 'Failed to sign document' });
  }
});

Download/PDF generation

Handle download requests to generate PDFs on-demand:
app.post('/api/generate-pdf', async (req, res) => {
  const { documentSource, fields } = req.body;

  if (!documentSource || typeof documentSource !== 'string') {
    return res.status(400).json({ error: 'documentSource URL is required' });
  }

  const result = await fetch('https://api.superdoc.dev/v1/annotate?to=pdf', {
    method: 'POST',
    headers: { 
      'Authorization': `Bearer ${process.env.SUPERDOC_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      document: { url: documentSource },
      fields: [...(fields?.document || []), ...(fields?.signer || [])]
    })
  });
  
  if (!result.ok) throw new Error('PDF generation failed');
  
  // Send PDF back to frontend
  const data = await result.json();
  const pdfBase64 = data?.document?.base64;
  res.type('application/pdf');
  res.send(Buffer.from(pdfBase64, 'base64'));
});

Data structure

The frontend sends the onSubmit payload plus a document reference and signer details your backend can access:
{
  "eventId": "session-123",
  "document": { "url": "https://example.com/agreement.docx" },
  "signer": {
    "name": "Jane Smith",
    "email": "jane@example.com"
  },
  "documentFields": [
    { "id": "1", "value": "Jane Smith" }
  ],
  "signerFields": [
    { "id": "1", "value": "Jane Smith" },
    { "id": "2", "value": true }
  ],
  "auditTrail": [
    { "type": "ready", "timestamp": "2024-01-15T10:30:00Z" },
    { "type": "scroll", "timestamp": "2024-01-15T10:30:15Z", 
      "data": { "percent": 100 } },
    { "type": "field_change", "timestamp": "2024-01-15T10:30:30Z",
      "data": { "fieldId": "1", "value": "Jane Smith" } },
    { "type": "submit", "timestamp": "2024-01-15T10:30:45Z" }
  ],
  "timestamp": "2024-01-15T10:30:45Z",
  "duration": 45,
  "isFullyCompleted": true
}

API reference