β 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!