π PDF Attachment - Complete Usage Guide
Purpose: How to generate and attach PDFs to communications
Available Templates: Invoice, Payment, Order, General
Use Cases: Email invoices, payment receipts, order confirmations, custom documents
π― THREE WAYS TO USE PDF ATTACHMENTSβ
- Via REST API (from frontend or external apps)
- Via Backend Service (from other backend services)
- Auto-Attach When Sending (integrated into send flow)
π‘ METHOD 1: REST API (Recommended for Frontend)β
Endpoint:β
POST /communications/:id/attach-pdf
Request Body:β
{
templateType: "invoice" | "payment" | "order" | "general",
templateData: { ... }, // Template-specific data
autoAttach?: boolean // If true, includes in next send
}
Example 1: Attach Invoice PDFβ
curl -X POST http://localhost:3000/communications/comm-123/attach-pdf \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"templateType": "invoice",
"templateData": {
"invoiceNumber": "INV-001",
"invoiceDate": "2025-11-01",
"dueDate": "2025-11-15",
"companyName": "FlowPOS",
"companyAddress": "123 Main St, City, State 12345",
"companyPhone": "+1234567890",
"companyEmail": "info@flowpos.com",
"customerName": "John Doe",
"customerEmail": "john@example.com",
"items": [
{
"name": "Product A",
"quantity": 2,
"unitPrice": "$100.00",
"amount": "$200.00"
},
{
"name": "Product B",
"quantity": 3,
"unitPrice": "$100.00",
"amount": "$300.00"
}
],
"subtotal": "$500.00",
"tax": "$50.00",
"totalAmount": "$550.00",
"paymentTerms": "Net 30",
"notes": "Thank you for your business!",
"paymentInstructions": "Please pay via bank transfer or credit card"
},
"autoAttach": true
}'
Response:
{
"success": true,
"pdfFilename": "invoice-2025-11-01-comm-123.pdf",
"pdfSize": 45678,
"communication": { ... }
}
Example 2: Attach Payment PDFβ
curl -X POST http://localhost:3000/communications/comm-456/attach-pdf \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"templateType": "payment",
"templateData": {
"paymentId": "PAY-001",
"paymentDate": "2025-11-01",
"customerName": "Jane Smith",
"paymentMethod": "Credit Card",
"amount": "$550.00",
"companyName": "FlowPOS",
"transactionId": "TXN-ABC123",
"invoiceNumber": "INV-001",
"notes": "Payment received successfully",
"description": "Thank you for your prompt payment!"
}
}'
Example 3: Attach Order PDFβ
curl -X POST http://localhost:3000/communications/comm-789/attach-pdf \
-H "Content-Type: application/json" \
-d '{
"templateType": "order",
"templateData": {
"orderNumber": "ORD-001",
"orderDate": "2025-11-01",
"customerName": "Bob Johnson",
"customerEmail": "bob@example.com",
"customerPhone": "+1234567890",
"companyName": "FlowPOS",
"items": [
{
"name": "Widget A",
"description": "High-quality widget",
"quantity": 5,
"price": "$20.00",
"total": "$100.00"
}
],
"subtotal": "$100.00",
"shippingCost": "$10.00",
"tax": "$11.00",
"totalAmount": "$121.00",
"shippingAddress": "456 Oak Ave, City, State 67890",
"estimatedDelivery": "November 5, 2025",
"trackingNumber": "TRACK123456",
"trackingUrl": "https://tracking.example.com/TRACK123456"
}
}'
Example 4: Attach General PDFβ
curl -X POST http://localhost:3000/communications/comm-999/attach-pdf \
-H "Content-Type: application/json" \
-d '{
"templateType": "general",
"templateData": {
"companyName": "FlowPOS",
"title": "Important Announcement",
"subtitle": "Q4 2025 Update",
"recipientName": "Valued Customer",
"greeting": "Dear Valued Customer,",
"message": "<p>We are excited to announce new features coming in Q4 2025!</p><p>These include improved reporting, mobile app, and more.</p>",
"highlightText": "Early access available for premium customers",
"actionUrl": "https://flowpos.com/early-access",
"actionText": "Sign Up for Early Access",
"details": [
{ "label": "Release Date", "value": "December 1, 2025" },
{ "label": "Pricing", "value": "No additional cost" },
{ "label": "Support", "value": "24/7 available" }
],
"notes": "Contact us if you have any questions",
"companyEmail": "support@flowpos.com"
}
}'
π» METHOD 2: BACKEND SERVICE (From Your Code)β
In Your NestJS Service:β
import { CommunicationPdfService } from '@/communications/application/services/communication-pdf.service';
import { AttachPdfToCommunicationUseCase } from '@/communications/application/use-cases/attach-pdf-to-communication.use-case';
@Injectable()
export class YourService {
constructor(
private readonly pdfService: CommunicationPdfService,
private readonly attachPdfUseCase: AttachPdfToCommunicationUseCase,
) {}
async sendInvoiceWithPdf(invoice: Invoice, customerId: string) {
// 1. Create communication
const communication = await this.communicationsService.send({
businessId: invoice.businessId,
recipientType: 'customer',
recipientId: customerId,
recipientContact: invoice.customerEmail,
channel: 'email',
type: 'invoice',
subject: `Invoice ${invoice.number}`,
content: `Your invoice ${invoice.number} is attached.`,
});
// 2. Generate and attach PDF
const pdfResult = await this.attachPdfUseCase.execute({
communicationId: communication.id,
templateType: 'invoice',
templateData: {
invoiceNumber: invoice.number,
invoiceDate: invoice.date,
dueDate: invoice.dueDate,
companyName: invoice.business.name,
companyAddress: invoice.business.address,
customerName: invoice.customer.name,
customerEmail: invoice.customer.email,
items: invoice.items.map(item => ({
name: item.product.name,
quantity: item.quantity,
unitPrice: `$${item.unitPrice.toFixed(2)}`,
amount: `$${item.total.toFixed(2)}`
})),
subtotal: `$${invoice.subtotal.toFixed(2)}`,
tax: `$${invoice.tax.toFixed(2)}`,
totalAmount: `$${invoice.total.toFixed(2)}`,
paymentTerms: 'Net 30',
},
autoAttach: true,
});
console.log(`PDF attached: ${pdfResult.pdfFilename}`);
return pdfResult;
}
}
Direct PDF Generation (Without Communication):β
@Injectable()
export class InvoiceService {
constructor(private readonly pdfService: CommunicationPdfService) {}
async generateInvoicePdfOnly(invoice: Invoice) {
// Create a mock communication object (just for PDF generation)
const mockCommunication = {
id: 'temp-' + Date.now(),
channel: 'email',
type: 'invoice',
// ... other required fields
};
// Generate PDF
const pdf = await this.pdfService.generateInvoicePdf(
mockCommunication as any,
{
invoiceNumber: invoice.number,
customerName: invoice.customer.name,
totalAmount: `$${invoice.total.toFixed(2)}`,
// ... all other data
}
);
// pdf = { filename, content (base64), mimeType }
// You can now:
// - Save to file system
// - Return to frontend for download
// - Email directly
// - Store in database
return pdf;
}
}
π METHOD 3: AUTO-ATTACH DURING SEND (Integrated)β
Future Enhancement:β
You can modify the CommunicationsService.send() method to automatically generate and attach PDFs based on communication type:
// In communications.service.ts
async send(data: SendCommunicationDto): Promise<SelectableCommunication> {
// ... existing send logic ...
// Auto-generate PDF for invoice emails
if (data.type === 'invoice' && data.channel === 'email' && data.invoiceData) {
const pdf = await this.pdfService.generateInvoicePdf(
communication,
data.invoiceData
);
// Add to attachments
if (!data.attachments) {
data.attachments = [];
}
data.attachments.push({
filename: pdf.filename,
content: pdf.content,
mimeType: pdf.mimeType,
});
}
// Continue with send...
}
π TEMPLATE DATA REFERENCEβ
Invoice Template Data:β
interface InvoiceTemplateData {
// Required
invoiceNumber: string;
invoiceDate: string;
companyName: string;
customerName: string;
totalAmount: string;
// Optional
dueDate?: string;
companyAddress?: string;
companyPhone?: string;
companyEmail?: string;
customerAddress?: string;
customerEmail?: string;
customerPhone?: string;
items?: Array<{
name: string;
quantity: number;
unitPrice: string;
amount: string;
}>;
subtotal?: string;
tax?: string;
discount?: string;
paymentTerms?: string;
referenceNumber?: string;
notes?: string;
paymentInstructions?: string;
footerText?: string;
}
Usage:
await attachPdfUseCase.execute({
communicationId: 'comm-123',
templateType: 'invoice',
templateData: {
invoiceNumber: 'INV-001',
invoiceDate: '2025-11-01',
companyName: 'FlowPOS',
customerName: 'John Doe',
totalAmount: '$550.00',
// ... other optional fields
}
});
Payment Template Data:β
interface PaymentTemplateData {
// Required
paymentId: string;
paymentDate: string;
customerName: string;
paymentMethod: string;
amount: string;
companyName: string;
// Optional
transactionId?: string;
invoiceNumber?: string;
notes?: string;
description?: string;
footerText?: string;
}
Usage:
await attachPdfUseCase.execute({
communicationId: 'comm-456',
templateType: 'payment',
templateData: {
paymentId: 'PAY-001',
paymentDate: '2025-11-01',
customerName: 'Jane Smith',
paymentMethod: 'Credit Card',
amount: '$550.00',
companyName: 'FlowPOS',
transactionId: 'TXN-ABC123',
}
});
Order Template Data:β
interface OrderTemplateData {
// Required
orderNumber: string;
orderDate: string;
customerName: string;
customerEmail: string;
companyName: string;
totalAmount: string;
// Optional
customerPhone?: string;
items?: Array<{
name: string;
description?: string;
quantity: number;
price: string;
total: string;
}>;
subtotal?: string;
shippingCost?: string;
tax?: string;
shippingAddress?: string;
estimatedDelivery?: string;
trackingNumber?: string;
trackingUrl?: string;
notes?: string;
supportEmail?: string;
footerText?: string;
}
Usage:
await attachPdfUseCase.execute({
communicationId: 'comm-789',
templateType: 'order',
templateData: {
orderNumber: 'ORD-001',
orderDate: '2025-11-01',
customerName: 'Bob Johnson',
customerEmail: 'bob@example.com',
companyName: 'FlowPOS',
totalAmount: '$121.00',
items: [
{ name: 'Widget', quantity: 5, price: '$20', total: '$100' }
],
trackingNumber: 'TRACK123456',
}
});
General Template Data:β
interface GeneralTemplateData {
// Required
companyName: string;
message: string; // Can include HTML
// Optional
title?: string;
subtitle?: string;
recipientName?: string;
greeting?: string;
highlightText?: string;
additionalInfo?: string;
actionUrl?: string;
actionText?: string;
details?: Array<{ label: string; value: string }>;
notes?: string;
closing?: string;
senderName?: string;
contactInfo?: string;
logoUrl?: string;
companyAddress?: string;
companyPhone?: string;
companyEmail?: string;
companyWebsite?: string;
footerText?: string;
}
Usage:
await attachPdfUseCase.execute({
communicationId: 'comm-999',
templateType: 'general',
templateData: {
companyName: 'FlowPOS',
title: 'Important Announcement',
message: '<p>We have exciting news to share!</p>',
actionUrl: 'https://flowpos.com/news',
actionText: 'Read More',
}
});
π¨ FROM FRONTEND (TypeScript/React)β
Using the API Service:β
// In your communicationsService.ts (frontend)
export const attachPdfToCommunication = async (
communicationId: string,
templateType: 'invoice' | 'payment' | 'order' | 'general',
templateData: Record<string, unknown>,
autoAttach = true
) => {
const response = await api.post(
`/communications/${communicationId}/attach-pdf`,
{
templateType,
templateData,
autoAttach,
}
);
return response.data;
};
// Usage in your component
const handleAttachInvoice = async (communicationId: string, invoice: Invoice) => {
try {
const result = await attachPdfToCommunication(
communicationId,
'invoice',
{
invoiceNumber: invoice.number,
customerName: invoice.customerName,
totalAmount: `$${invoice.total.toFixed(2)}`,
items: invoice.items.map(item => ({
name: item.name,
quantity: item.quantity,
unitPrice: `$${item.price.toFixed(2)}`,
amount: `$${item.total.toFixed(2)}`,
})),
// ... more fields
}
);
toast.success(`PDF attached: ${result.pdfFilename}`);
} catch (error) {
toast.error('Failed to attach PDF');
}
};
π§ COMPLETE WORKFLOW EXAMPLESβ
Workflow 1: Send Invoice Email with PDFβ
// Step 1: Create and send communication
const communication = await communicationsService.send({
businessId: 'business-123',
recipientType: 'customer',
recipientId: 'customer-456',
recipientContact: 'customer@example.com',
channel: 'email',
type: 'invoice',
subject: `Invoice ${invoice.number} from FlowPOS`,
content: `
<p>Dear ${invoice.customerName},</p>
<p>Your invoice is attached to this email.</p>
<p>Total amount: ${invoice.total}</p>
<p>Due date: ${invoice.dueDate}</p>
`,
});
// Step 2: Generate and attach PDF
const pdfResult = await attachPdfUseCase.execute({
communicationId: communication.id,
templateType: 'invoice',
templateData: {
invoiceNumber: invoice.number,
invoiceDate: formatDate(invoice.date),
dueDate: formatDate(invoice.dueDate),
companyName: business.name,
companyAddress: business.address,
customerName: invoice.customer.name,
customerEmail: invoice.customer.email,
items: invoice.items.map(item => ({
name: item.product.name,
quantity: item.quantity,
unitPrice: formatCurrency(item.unitPrice),
amount: formatCurrency(item.total),
})),
subtotal: formatCurrency(invoice.subtotal),
tax: formatCurrency(invoice.tax),
totalAmount: formatCurrency(invoice.total),
paymentTerms: 'Net 30',
notes: 'Thank you for your business!',
},
autoAttach: true,
});
// Step 3: Communication is now sent with PDF attached!
console.log(`Invoice sent with PDF: ${pdfResult.pdfFilename}`);
Workflow 2: Send Payment Confirmation with Receiptβ
async function sendPaymentConfirmation(payment: Payment) {
// 1. Create communication
const communication = await communicationsService.send({
businessId: payment.businessId,
recipientType: 'customer',
recipientId: payment.customerId,
recipientContact: payment.customerEmail,
channel: 'email',
type: 'payment_confirmation',
subject: `Payment Confirmation - ${payment.id}`,
content: `
<p>Dear ${payment.customerName},</p>
<p>We have received your payment of ${formatCurrency(payment.amount)}.</p>
<p>Transaction ID: ${payment.transactionId}</p>
<p>Your receipt is attached.</p>
`,
});
// 2. Attach PDF receipt
await attachPdfUseCase.execute({
communicationId: communication.id,
templateType: 'payment',
templateData: {
paymentId: payment.id,
paymentDate: formatDate(payment.date),
customerName: payment.customerName,
paymentMethod: payment.method,
amount: formatCurrency(payment.amount),
companyName: payment.business.name,
transactionId: payment.transactionId,
invoiceNumber: payment.invoiceNumber,
description: 'Thank you for your payment!',
},
autoAttach: true,
});
return communication;
}
Workflow 3: Bulk Attach PDFsβ
async function bulkAttachInvoices(communications: SelectableCommunication[], invoices: Invoice[]) {
const requests = communications.map((comm, index) => ({
communicationId: comm.id,
templateType: 'invoice' as const,
templateData: {
invoiceNumber: invoices[index].number,
customerName: invoices[index].customerName,
totalAmount: formatCurrency(invoices[index].total),
// ... more data
},
autoAttach: true,
}));
// Attach all PDFs in bulk
const results = await attachPdfUseCase.executeBulk(requests);
console.log(`Attached ${results.length} PDFs successfully`);
return results;
}
π― PRACTICAL USE CASESβ
Use Case 1: Invoice Emailsβ
When: Customer makes a purchase
Action: Send email with invoice PDF attached
// In your sales service
async onSaleCompleted(sale: Sale) {
// Send invoice email
const comm = await communicationsService.send({
recipientContact: sale.customer.email,
channel: 'email',
type: 'invoice',
subject: `Invoice ${sale.invoiceNumber}`,
content: 'Your invoice is attached',
});
// Attach PDF
await attachPdfUseCase.execute({
communicationId: comm.id,
templateType: 'invoice',
templateData: { /* invoice data */ },
autoAttach: true,
});
}
Use Case 2: Payment Receiptsβ
When: Payment is received
Action: Send confirmation email with receipt PDF
// In your payment service
async onPaymentReceived(payment: Payment) {
const comm = await communicationsService.send({
recipientContact: payment.customer.email,
channel: 'email',
type: 'payment_confirmation',
subject: 'Payment Received',
content: 'Thank you! Receipt attached.',
});
await attachPdfUseCase.execute({
communicationId: comm.id,
templateType: 'payment',
templateData: {
paymentId: payment.id,
amount: formatCurrency(payment.amount),
// ...
},
});
}
Use Case 3: Order Confirmationsβ
When: Order is placed
Action: Send confirmation email with order details PDF
async onOrderPlaced(order: Order) {
const comm = await communicationsService.send({
recipientContact: order.customer.email,
channel: 'email',
type: 'order_confirmation',
subject: `Order Confirmation #${order.number}`,
content: 'Your order details are attached',
});
await attachPdfUseCase.execute({
communicationId: comm.id,
templateType: 'order',
templateData: {
orderNumber: order.number,
customerName: order.customer.name,
// ...
},
});
}
Use Case 4: Custom Documentsβ
When: Send any custom document
Action: Use general template for flexibility
async sendCustomDocument(data: {
recipient: string;
title: string;
message: string;
details?: Array<{label: string, value: string}>;
}) {
const comm = await communicationsService.send({
recipientContact: data.recipient,
channel: 'email',
type: 'general_notification',
subject: data.title,
content: data.message,
});
await attachPdfUseCase.execute({
communicationId: comm.id,
templateType: 'general',
templateData: {
companyName: 'FlowPOS',
title: data.title,
message: data.message,
details: data.details,
},
});
}
π GET ATTACHMENTSβ
Get All Attachments for a Communication:β
# Via API
curl http://localhost:3000/communications/comm-123/attachments
Response:
{
"communicationId": "comm-123",
"attachments": [
{
"id": "att-1",
"filename": "invoice-2025-11-01-comm-123.pdf",
"mimeType": "application/pdf",
"sizeBytes": 45678,
"fileUrl": null,
"createdAt": "2025-11-01T10:00:00Z"
}
]
}
From Backend:β
// Get attachments
const attachments = await attachmentHandler.getAttachments('comm-123');
console.log(attachments);
// [
// {
// id: 'att-1',
// filename: 'invoice.pdf',
// mimeType: 'application/pdf',
// sizeBytes: 45678,
// ...
// }
// ]
π LIST AVAILABLE TEMPLATESβ
Get Available PDF Templates:β
# Via API
curl http://localhost:3000/communications/pdf-templates/available
Response:
[
{
"type": "invoice",
"name": "Invoice",
"description": "Professional invoice with itemized list"
},
{
"type": "payment",
"name": "Payment Confirmation",
"description": "Payment receipt and confirmation"
},
{
"type": "order",
"name": "Order Confirmation",
"description": "Order details with shipping information"
},
{
"type": "general",
"name": "General Communication",
"description": "Flexible template for any communication"
}
]
β‘ QUICK EXAMPLESβ
Minimal Invoice:β
await attachPdfUseCase.execute({
communicationId: 'comm-123',
templateType: 'invoice',
templateData: {
invoiceNumber: 'INV-001',
invoiceDate: '2025-11-01',
companyName: 'FlowPOS',
customerName: 'John Doe',
totalAmount: '$100.00',
},
});
Minimal Payment:β
await attachPdfUseCase.execute({
communicationId: 'comm-456',
templateType: 'payment',
templateData: {
paymentId: 'PAY-001',
paymentDate: '2025-11-01',
customerName: 'Jane Smith',
paymentMethod: 'Card',
amount: '$100.00',
companyName: 'FlowPOS',
},
});
Minimal General:β
await attachPdfUseCase.execute({
communicationId: 'comm-999',
templateType: 'general',
templateData: {
companyName: 'FlowPOS',
message: '<p>Important message here</p>',
},
});
π§ͺ TESTING THE FEATUREβ
Test with curl:β
# 1. Start backend
cd apps/backend
pnpm start:dev
# 2. First, create a communication
curl -X POST http://localhost:3000/communications/send \
-H "Content-Type: application/json" \
-d '{
"businessId": "business-123",
"recipientType": "customer",
"recipientContact": "test@example.com",
"channel": "email",
"type": "invoice",
"subject": "Test Invoice",
"content": "Testing PDF attachment"
}'
# Note the communication ID from response (e.g., "comm-abc123")
# 3. Attach PDF to that communication
curl -X POST http://localhost:3000/communications/comm-abc123/attach-pdf \
-H "Content-Type: application/json" \
-d '{
"templateType": "invoice",
"templateData": {
"invoiceNumber": "INV-TEST-001",
"invoiceDate": "2025-11-01",
"companyName": "FlowPOS Test",
"customerName": "Test Customer",
"totalAmount": "$99.99"
}
}'
# 4. Check attachments
curl http://localhost:3000/communications/comm-abc123/attachments
π‘ BEST PRACTICESβ
1. Always Provide Required Fieldsβ
Each template has required fields. Make sure to include them:
- Invoice: invoiceNumber, companyName, customerName, totalAmount
- Payment: paymentId, customerName, amount, companyName
- Order: orderNumber, customerName, companyName, totalAmount
- General: companyName, message
2. Format Currency Consistentlyβ
// Good
totalAmount: '$550.00'
unitPrice: '$100.00'
// Also good (with locale)
totalAmount: formatCurrency(550.00) // Returns '$550.00'
3. Format Dates Consistentlyβ
// Good
invoiceDate: '2025-11-01'
invoiceDate: 'November 1, 2025'
// Use helper function
invoiceDate: formatDate(new Date(), 'YYYY-MM-DD')
4. Include Items for Better PDFsβ
// Minimal (works)
totalAmount: '$550.00'
// Better (more professional)
items: [
{ name: 'Product A', quantity: 2, unitPrice: '$100', amount: '$200' },
{ name: 'Product B', quantity: 3, unitPrice: '$100', amount: '$300' }
],
subtotal: '$500.00',
tax: '$50.00',
totalAmount: '$550.00'
5. Use autoAttach for Emailβ
// For emails, use autoAttach: true
await attachPdfUseCase.execute({
communicationId: comm.id,
templateType: 'invoice',
templateData: { ... },
autoAttach: true, // β
Automatically includes in email
});
// For non-email channels, autoAttach doesn't apply
// (SMS/WhatsApp can't have PDF attachments)
π TROUBLESHOOTINGβ
Error: "Communication not found"β
Cause: Invalid communication ID
Fix: Verify the communication exists
// Check if communication exists
const comm = await communicationsService.findById('comm-123');
if (!comm) {
throw new Error('Communication not found');
}
Error: "Template not found"β
Cause: Template file missing or wrong path
Fix: Check templates exist in:
apps/backend/src/communications/templates/
βββ communication-invoice.html
βββ communication-payment.html
βββ communication-order.html
βββ communication-general.html
Missing Data in PDFβ
Cause: Template variables not provided
Fix: Provide all required fields
// Check what variables your template needs
// Look at the HTML template file and find {{variables}}
// Invoice requires:
templateData: {
invoiceNumber: '...', // Required
companyName: '...', // Required
customerName: '...', // Required
totalAmount: '...', // Required
// Optional fields can be omitted
}
π MONITORING & DEBUGGINGβ
Check Logs:β
When you attach a PDF, you'll see logs like:
[CommunicationPdfService] Generating invoice PDF for communication comm-123
[CommunicationPdfService] PDF generated successfully: invoice-2025-11-01-comm-123.pdf (45678 bytes)
[AttachPdfToCommunicationUseCase] Auto-attaching PDF to email communication comm-123
[AttachmentHandlerService] Saved 1 attachment(s) for communication comm-123
Check Database:β
-- See all attachments for a communication
SELECT * FROM communication_attachment
WHERE communication_id = 'comm-123';
-- Results:
-- id | communication_id | filename | mime_type | size_bytes | file_url
π― SUMMARYβ
Three Ways to Use:β
- REST API - From frontend or external apps
- Backend Service - From other NestJS services
- Integrated - Auto-attach during send
Four Template Types:β
- Invoice - Professional invoices with items
- Payment - Payment confirmations and receipts
- Order - Order confirmations with shipping
- General - Flexible for any communication
Key Endpoints:β
POST /communications/:id/attach-pdf - Attach PDF
GET /communications/:id/attachments - Get attachments
GET /communications/pdf-templates - List templates
β NEXT STEPSβ
- Try it! Use one of the curl examples above
- Integrate Add to your frontend/backend workflows
- Customize Modify templates for your branding
- Extend Add more template types as needed
Need help with a specific use case? Let me know! π
Document Version: 1.0
Last Updated: November 1, 2025
Status: β
Ready to use!