How to Upload a File to a Pega Repository Using an Activity on Embed-Repository-File

Introduction

File storage is a common requirement in enterprise applications. Whether you are archiving generated reports, persisting user-uploaded documents, or integrating with external content management systems. Pega Platform provides a built-in, cloud-compatible mechanism for this through its Repository API, centered on the D_pxNewFile savable data page and the Embed-Repository-File embedded class.

This article walks through a practical, step-by-step implementation of a reusable Activity rule defined on the Embed-Repository-File class, which receives a Base64-encoded file and persists it to any configured Pega repository, whether that is Pega Cloud’s default storage, Amazon S3, Azure Blob Storage, or any other supported provider.

Why an Activity on Embed-Repository-File?

Placing the logic directly on Embed-Repository-File keeps the rule naturally scoped to file operations, makes it reusable across multiple case types, and leverages the class’s built-in properties (pyContents, pyErrorMessage, pyMessage) without requiring additional mappings.


What Is Embed-Repository-File?

Embed-Repository-File is a platform-level embedded class that acts as a metadata and content container for files stored in any Pega-connected repository. It abstracts away the underlying storage provider. Your application code always interacts with the same structure, regardless of whether the backend is S3, Azure Blob, or a local file system.

Key properties relevant to this implementation:

Property Description
pyContents Base64-encoded file content used to populate the file before saving
pyMessage Informational message set on success
pyErrorMessage Error message set when the operation fails or validation fails

For a full list of available OOTB data pages (D_pxNewFile, D_pxGetFile, D_pxListFiles, etc.), refer to the official Using repository APIs in your application documentation (see References).


Activity Overview: SendFileToRepository

The Activity SendFileToRepository, defined on the Embed-Repository-File class, accepts four input parameters and orchestrates the full upload sequence — including input validation, path construction, file population, persistence, and feedback messaging.

Parameters

Parameter Type Description
DestinyDirectory Text Target directory path in the repository (e.g., reports/2026/)
FileName Text Name of the file to be created (e.g., monthly_report.pdf)
FileBase64 Text Base64-encoded content of the file
RepositoryName Text Name of the configured repository (e.g., pegacloudfilestorage)
FullPathDestiny Text (Internal — computed in Step 2) Full file path used in the API call

Flow Summary

The Activity contains 7 steps organized across three logical blocks:

[ Steps 1–5 ] → Main flow (validate → build path → populate → save → success)
[ Step 6 ] → ERROR block (triggered if Save-DataPage fails)
[ Step 7 ] → VALIDATE block (triggered if any input parameter is missing)


Step-by-Step Implementation

Step 1 — Clear Page Messages (Page-Clear-Messages)

The first step resets the step page by clearing any pre-existing messages. This ensures that feedback from any previous execution does not bleed into the current run, an important hygiene step, especially when the Activity is called in a loop or retried.

Method: `Page-Clear-Messages`
Step Page: Default (current `Embed-Repository-File` page)

Step 2 — Validate Inputs and Build Full Path (Property-Set)

This is the most logic-dense step. It has two responsibilities:

2a. Precondition (When Expression — Validation)

Before executing the Property-Set, the Activity evaluates whether any required input parameter is empty. If any of the four parameters (DestinyDirectory, FileName, FileBase64, RepositoryName) is blank, the flow jumps immediately to the VALIDATE block (Step 7), skipping all remaining main-flow steps.

When expression:
Param.DestinyDirectory==""
|| Param.FileName==""
|| Param.FileBase64==""
|| Param.RepositoryName==""
→ Jump To: VALIDATE

2b. Property-Set — Path Construction

If validation passes, the step constructs the full file path by combining DestinyDirectory and FileName. It handles the edge case where the directory string already ends with a / to avoid double-slash paths:

If DestinyDirectory ends with "/" → FullPathDestiny = DestinyDirectory + FileName
Else → FullPathDestiny = DestinyDirectory + "/" + FileName

@if(@endsWith(Param.DestinyDirectory,“/”),Param.DestinyDirectory+Param.FileName,Param.DestinyDirectory+“/”+Param.FileName)

Step 3 — Populate File Content (Property-Set on D_pxNewFile)

This step changes the step page context to D_pxNewFile, loading the data page with the target repository and file path. It then maps the Base64-encoded file content from Param.FileBase64 into the .pyContents property of the data page, effectively staging the file in memory before it is committed.

Method: Property-Set
Step Page: D_pxNewFile[repositoryName: Param.RepositoryName, filePath: Param.FullPathDestiny]
.pyContents = Param.FileBase64

:warning: Technical note: The step page must be set correctly here. If D_pxNewFile resolves to a null page (common when parameters are missing or misnamed), the Activity will throw an InvalidReferenceException. Always confirm both repositoryName and filePath are non-empty before this step, which is why Step 2’s validation runs first.

Step 4 — Commit the File to the Repository (Save-DataPage)

This is the step that actually persists the file to the repository. It calls Save-DataPage on D_pxNewFile with the same repositoryName and filePath parameters, instructing the platform to write the staged content to the configured storage backend.

Method: Save-DataPage
Data Page: D_pxNewFile
Parameters passed: repositoryName, filePath (from Param.RepositoryName and Param.FullPathDestiny)

If Save-DataPage throws a PRRuntimeException, the exception is caught, the message is added to the step page, and the flow branches to the ERROR block.

A Transition evaluates the StepStatusFail When condition after the method executes. If the step status is failure, it also branches to the ERROR block.

Step 5 — Success Message (Property-Set-Messages)

Reached only when Step 4 completes successfully. Sets a success message on the .pyMessage property of the step page to confirm the file was uploaded. The Activity then exits immediately via an “Always → Skip remaining steps” transition, ensuring Steps 6 and 7 (error paths) are never executed on a successful run.

Method: Property-Set-Messages
Property: .pyMessage
Message: "File sent successfully."

Step 6 — [ERROR Block] Failure Message (Property-Set-Messages)

Reached when Step 4 fails (either via exception or the StepStatusFail transition). Sets an error message on .pyErrorMessage to notify the calling code that the upload did not succeed.

Block: ERROR
Method: Property-Set-Messages
Property: .pyErrorMessage
Message: "Sorry, there was an error sending your file."

Step 7 — [VALIDATE Block] Missing Parameters Message (Property-Set-Messages)

Reached when Step 2’s precondition detects one or more missing input parameters. Sets a validation message on .pyErrorMessage to inform the caller of the issue.

Block: VALIDATE
Method: Property-Set-Messages
Property: .pyErrorMessage
Message: "All parameters are required for this activity."

Technical Considerations

Pega Cloud compatibility: D_pxNewFile and Save-DataPage are the recommended, cloud-compliant replacement for the deprecated Connect-File approach. The default repository name on Pega Cloud is pegacloudfilestorage.

File size limit: By default, D_pxNewFile supports in-memory file content up to 45 MB. For larger files, increase the Dynamic System Setting repository/maxFileSizeInMemory or consider streaming via pyStream instead of pyContents.

Base64 encoding: The caller is responsible for encoding the file content as Base64 before passing it to Param.FileBase64. This is standard when sourcing files from REST payloads or attachment properties.

Repository access roles: Ensure the executing operator has either the PegaRULES:RepositoryAdministrator or PegaRULES:RepositoryUser role assigned. Operations will fail silently or with a permission error otherwise.

Reusability: Because the Activity is defined on Embed-Repository-File (not on a specific application class), it can be called from any class in your application via a Call method, keeping your implementation DRY and consistent.

Conclusion

This Activity provides a clean, reusable, and cloud-safe pattern for programmatically uploading files to any Pega-configured repository. By combining input validation, smart path construction, and structured error routing, all within a single Activity on Embed-Repository-File, you get a robust utility that integrates naturally into any case or data flow.

Whether you are archiving case attachments, persisting generated documents, or bridging with external storage backends, this pattern gives you a solid foundation to build on.

References

Your pega documentation links aren’t opening for me :frowning: Can you update them?

I was looking to see why we weren’t outlining the OOTB repository on the Application Rule? That should be the default way before extending further using approaches like this?

1 Like

@MarcCheong tks for the feedback on the links and the questions.
I just update all links, should work now.

About the OOTB question: That’s a great observation. The OOTB repository configuration on the Application Rule should indeed be your first stop before extending into custom Activity-based approaches like the one described in this article.

The Activity-based approach described in this article becomes relevant when you need:

  • Programmatic control over file construction. Dynamically building file content at runtime using clipboard data.
  • Custom metadata handling, specific encryption, or extended logic during the upload process.
  • Integration with providers not natively supported by the OOTB list (FTP, Google Drive).
  • Dynamic path toggling across environments that the standard repository rule doesn’t support.

The OOTB Application Rule repository configuration is the recommended baseline, it’s declarative, maintainable, and leverages Pega’s standardized APIs. The Activity-based approach in this article is a purposeful extension for scenarios where that baseline doesn’t fully meet the requirements. Think of it as: configure first, extend only when necessary.

1 Like