Flow
Copy
Ask AI
Frontend sends → Backend processes → PDF created
↓ ↓ ↓
Signing data 1. Annotate fields Stored
2. Apply signature
Complete example
Copy
Ask AI
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:Copy
Ask AI
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 theonSubmit payload plus a document reference and signer details your backend can access:
Copy
Ask AI
{
"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
- Authentication - Get your API key
- Annotate endpoint - Fill fields
- Sign endpoint - Apply signature

