✅ Simplified PDF API - Final Design
Based on user feedback: Removed confusing /attach-pdf endpoint
New design: Simple, logical, works correctly
Workflow: Generate PDF first, then send with attachment
🎯 CLEAN API DESIGN
Only 3 PDF Endpoints (Simple!):
POST /communications/generate-pdf → Generate PDF, get base64
POST /communications/send → Send with attachments
GET /communications/:id/attachments → View what was sent
GET /communications/pdf-templates → List available templates
That's it! Simple and clear! ✅
📡 THE CORRECT WORKFLOW
Two Steps:
Step 1: Generate PDF
↓
POST /communications/generate-pdf
↓
Returns: { filename, content (base64), mimeType }
↓
Step 2: Send with PDF
↓
POST /communications/send
{
attachments: [
{ filename, content, mimeType } ← From step 1
]
}
↓
Email sent WITH PDF! ✅
🚀 EXAMPLE USAGE
Complete Example:
# Step 1: Generate PDF
curl -X POST 'http://localhost:4000/communications/generate-pdf' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"templateType": "invoice",
"templateData": {
"invoiceNumber": "INV-12350",
"invoiceDate": "2025-11-01",
"companyName": "RPA Solution",
"customerName": "John Doe",
"totalAmount": "$550.00",
"items": [
{
"name": "Product A",
"quantity": 2,
"unitPrice": "$100.00",
"amount": "$200.00"
}
]
}
}' | jq '.'
# Response:
# {
# "filename": "invoice-2025-11-01-temp123.pdf",
# "content": "JVBERi0xLjQK...", ← COPY THIS!
# "mimeType": "application/pdf",
# "sizeBytes": 12345
# }
# Step 2: Send with PDF (paste the content from step 1)
curl -X POST 'http://localhost:4000/communications/send' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"businessId": "33b6db4b-51c5-45ee-8d04-c01c2d157f66",
"createdBy": "6c0c4f32-d74a-4a84-892f-3bead447d765",
"channel": "email",
"type": "invoice",
"recipientType": "customer",
"recipientContact": "luisrangelc@gmail.com",
"subject": "Invoice #12350 - With PDF!",
"content": "<p>Your invoice is attached.</p>",
"attachments": [
{
"filename": "invoice-12350.pdf",
"content": "PASTE_BASE64_FROM_STEP_1_HERE",
"mimeType": "application/pdf"
}
]
}'
Check Gmail → Email with PDF attachment! 📧📎
💻 BACKEND CODE (TypeScript)
Simple Service Method:
@Injectable()
export class InvoiceService {
constructor(
private readonly generatePdfUseCase: GenerateCommunicationPdfUseCase,
private readonly communicationsService: CommunicationsService,
) {}
async sendInvoiceWithPdf(invoice: Invoice) {
// 1. Generate PDF
const pdf = await this.generatePdfUseCase.execute({
templateType: 'invoice',
templateData: {
invoiceNumber: invoice.number,
companyName: invoice.business.name,
customerName: invoice.customer.name,
totalAmount: `$${invoice.total.toFixed(2)}`,
// ... more fields
}
});
// 2. Send email with PDF
return await this.communicationsService.send({
businessId: invoice.businessId,
recipientContact: invoice.customerEmail,
channel: 'email',
type: 'invoice',
subject: `Invoice ${invoice.number}`,
content: '<p>Invoice attached as PDF</p>',
attachments: [
{
filename: pdf.filename,
content: pdf.content,
mimeType: pdf.mimeType
}
]
});
}
}
Usage:
await invoiceService.sendInvoiceWithPdf(invoice);
// ✅ Generates PDF and sends email in one call!
🎨 FRONTEND CODE (React/TypeScript)
// Frontend service
export const generatePdf = async (templateType, templateData) => {
const response = await api.post('/communications/generate-pdf', {
templateType,
templateData
});
return response.data;
};
export const sendCommunication = async (data) => {
const response = await api.post('/communications/send', data);
return response.data;
};
// Component
const handleSendInvoice = async (invoice: Invoice) => {
try {
setLoading(true);
// 1. Generate PDF
const pdf = await generatePdf('invoice', {
invoiceNumber: invoice.number,
customerName: invoice.customerName,
companyName: 'RPA Solution',
totalAmount: formatCurrency(invoice.total)
});
// 2. Send with PDF
await sendCommunication({
recipientContact: invoice.customerEmail,
channel: 'email',
type: 'invoice',
subject: `Invoice ${invoice.number}`,
content: '<p>Invoice attached</p>',
attachments: [
{
filename: pdf.filename,
content: pdf.content,
mimeType: pdf.mimeType
}
]
});
toast.success('Invoice sent with PDF!');
} catch (error) {
toast.error('Failed to send invoice');
} finally {
setLoading(false);
}
};
📊 CLEAN API SUMMARY
All Communication Endpoints:
GET /communications List communications
GET /communications/:id Get by ID
POST /communications Create (draft)
POST /communications/send Send communication
PATCH /communications/:id Update
DELETE /communications/:id Delete
POST /communications/:id/resend Resend failed
GET /communications/stats Statistics
PDF Endpoints:
POST /communications/generate-pdf ✨ Generate PDF
GET /communications/:id/attachments View attachments
GET /communications/pdf-templates List templates
Clean, simple, logical! ✅
🏆 WHAT WE CLEANED UP
Removed (Confusing):
- ❌
POST /communications/:id/attach-pdf- Implied you could attach after sending - ❌
AttachPdfToCommunicationUseCase- Not needed
Kept (Makes Sense):
- ✅
POST /communications/generate-pdf- Generate PDF before sending - ✅
GenerateCommunicationPdfUseCase- Clean use case - ✅
POST /communications/send- Send with attachments - ✅
GET /communications/:id/attachments- View what was sent
🎯 FILES UPDATED
✅ communications.controller.ts (cleaned up)
- Removed: attach-pdf endpoint
- Kept: generate-pdf endpoint
✅ communications.module.ts (cleaned up)
- Removed: AttachPdfToCommunicationUseCase
- Kept: GenerateCommunicationPdfUseCase
✅ attach-pdf-to-communication.use-case.ts (deleted)
- Not needed anymore
✅ generate-communication-pdf.use-case.ts (kept)
- This is what we need!
🎊 FINAL API DESIGN
PDF Workflow (Simple!):
1. Generate PDF
POST /communications/generate-pdf
Body: { templateType, templateData }
Returns: { filename, content (base64), mimeType }
2. Send Email
POST /communications/send
Body: {
...,
attachments: [
{ filename, content, mimeType } ← From step 1
]
}
✅ Email sent with PDF attachment!
No confusion, no extra steps, just works! 🚀
🎉 TRY IT NOW!
After restarting backend:
# Generate PDF
curl -X POST 'http://localhost:4000/communications/generate-pdf' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"templateType": "invoice",
"templateData": {
"invoiceNumber": "TEST-001",
"companyName": "RPA Solution",
"customerName": "Your Name",
"totalAmount": "$99.99"
}
}'
# Copy the "content" value from response
# Then send email with that PDF
✅ SUMMARY
You were right! The /attach-pdf endpoint was confusing and didn't make sense.
New clean design:
- ✅ Simple workflow (generate → send)
- ✅ Clear purpose for each endpoint
- ✅ No confusion about when to use what
- ✅ Works the way users expect
API is now clean and logical! 🎊
Document Version: 1.0
Last Updated: November 1, 2025, 12:15 PM
Status: ✅ Simplified and improved!