Salesforce Documents

Attach Generated PDFs Back to Salesforce: Naming, Versioning, and Files API

RMMS.Cloud Team · Product Team
·9 min read
  • Salesforce Files
  • ContentVersion
  • document automation
  • Salesforce admin
  • DocForge

The mess that arrives in six months

Without naming and versioning discipline, the Files tab on every Opportunity becomes a graveyard: Proposal.pdf, Proposal (1).pdf, Proposal-final.pdf, Proposal-FINAL-v2.pdf. Nobody can tell which was sent or signed. Audit takes hours, not minutes.

The fix is two decisions made on day one: a deterministic naming convention and explicit use of the Salesforce Files versioning model.

A naming convention that scales

  • Pattern: {record_type}-{record_number}-{template_code}-v{version}.pdf.
  • Example: OPP-00042-PROPOSAL-v3.pdf.
  • Why: sortable, searchable, immediately understandable, never collides.
  • Avoid: spaces, customer names in file names, "FINAL" labels, manual suffixes.

Files API model: ContentVersion vs Attachment

Salesforce has two attachment models:

  • Attachments (legacy): simple but no versioning; avoid for new automation.
  • ContentVersion + ContentDocument: versioning built in; preferred for any modern document automation.

Always write to ContentVersion. Same file name with a new version creates a new ContentVersion linked to the same ContentDocument—exactly what you want for "v2 of the proposal."

The minimum metadata to set per upload

  1. Title: the file name following the convention.
  2. VersionData: the PDF bytes.
  3. PathOnClient: the file name with extension.
  4. ContentDocumentId: link to the existing ContentDocument for versioning.
  5. FirstPublishLocationId: on first version, the Opportunity ID for sharing.
  6. Custom fields: template version, generator run ID, signer status.

Linking and sharing

Use ContentDocumentLink to attach to multiple records (Opportunity, Account, custom Document object). Set the right ShareType (V for viewer, C for collaborator, I for inferred) and Visibility (AllUsers, InternalUsers, SharedUsers) per use case.

Governor limits to design around

  • ContentVersion inserts count against DML rows—batch large jobs.
  • VersionData size limit per file (Salesforce-defined); compress before upload when possible.
  • Heap size for large PDFs—stream rather than load fully into memory.
  • Asynchronous patterns (Queueable, Batch Apex) for bulk operations.

What to log per generation

  • Run ID, template version, mapping version.
  • Source record IDs (Opportunity, Account, related objects).
  • Output ContentDocument ID and version number.
  • Timestamp and user.
  • Status: success, partial, failure with reason.

Cleanup is part of the design

  1. Mark abandoned versions (draft never sent) for purge after N days.
  2. Never delete versions tied to signed documents—legal hold.
  3. Provide a search by template + status to find specific versions fast.
  4. Export and archive after closed-won/lost based on retention policy.

Automated attach is more than ContentDocumentLink

Uploading a PDF to Files is the easy part. Durable automation also sets filename convention, writes version metadata to custom fields, prevents duplicate attachments on Flow retry, and notifies downstream systems that the document exists.

Use idempotent keys: {OpportunityId}_{templateVersion}_{generationTimestamp} so a retried Flow does not create five identical PDFs named proposal.pdf.

Attachment automation layers

LayerImplementationFailure if skipped
GenerateInvocable action / APIEmpty attach
Name + pathFormula on Opportunity fieldsUnsearchable Files clutter
Link recordContentDocumentLinkOrphan file in library
Metadata stampCustom fields on OpportunityNo audit trail
Downstream notifyPlatform event / webhookERP never sees doc

Flow design patterns that survive retries

  1. Check custom field Last_Proposal_Hash__c before generate—skip if input unchanged.
  2. Store generation job ID; treat duplicate job ID as no-op.
  3. On failure, write error code to Opportunity—not silent rollback.
  4. Grant Files access via standard sharing, not "Modify All Data" service user.
  5. Archive superseded PDFs to subfolder instead of delete for legal retention.

Example: Stage 3 proposal on Opportunity update

Flow triggers when Stage moves to Proposal. Action generates PDF, names it OPP-2026-0142_Proposal_v3.pdf, links to Opportunity, sets Proposal_Generated_At__c, fires platform event ProposalReady. CPQ integration listens and unlocks send-for-signature button. Retry after transient timeout sees same job ID and exits without duplicate attach—Files tab stays clean.

Sharing rules and customer community visibility

Auto-attached PDFs inherit parent Opportunity sharing—verify partner community users cannot see draft proposals meant for direct customers only. Use separate subfolders or content document link visibility flags when Experience Cloud is in play.

Log which automation user owns the attach; audits ask who had access at generation time, not just who clicked send later.

Include file size in generation log—oversized proposals over 25 MB fail silently on some mobile email clients when reps forward Files links to customers.

Write integration tests that simulate Flow fault and retry paths—duplicate ContentDocumentLink records are the most common silent clutter on high-volume Opportunity records.

Alert when attach latency exceeds 60 seconds so admins catch governor-limit pressure before reps flood support.

Review high-volume Opportunities weekly so duplicate proposal attachments never clutter the Files tab unnoticed.

Document automation earns trust when ops owns the pipeline: weekly batch reviews, mapping change control, and a single owner who can explain every failed row to finance without opening three tools. Treat the generator like payroll—silent success, loud failures, zero mystery duplicates in numbering or filenames.

Where DocForge for Salesforce fits

DocForge for Salesforce writes generated PDFs to ContentVersion with deterministic naming, version control, generator metadata, and proper sharing—your Opportunity Files tab stays clean six months in. Sign in and inspect the file structure on a test record.