Dayalan Punniyamoorthy Blog

Sunday, May 31, 2026

Groovy Rules to Support the Copying of Relational Data, Comments, Attachments, and Supporting Details !

The Oracle Fusion Cloud EPM April 2026 (26.04) release introduces a powerful new Groovy capability that addresses one of the most common automation gaps in EPM Planning and FreeForm applications — the ability to programmatically copy relational and Essbase data, comments, attachments, and supporting details using Groovy business rules.

 

Prior to this enhancement, copying data between scenarios, versions, or periods — especially when it included relational artifacts like cell-level comments, file attachments, and supporting detail — required manual processes or was limited to UI-based copy operations. With this release, Oracle introduces the CopyDataRequest class in the Groovy Rules Java API, giving developers full programmatic control over data copy operations, including all associated relational content.

This is a significant step forward for organizations that rely on automated month-end, quarter-end, or annual planning workflows where preserving the full context of data — not just the numbers — is critical.

 

What Problem Does This Solve?

In typical EPM Planning and FreeForm environments, data exists at multiple layers:

Data Layer

Description

Essbase (Numeric) Data

The core financial or operational data stored in Essbase cubes

Relational Data

Metadata and structural information stored in the relational database

Cell Comments

User-entered notes attached to specific data intersections

Cell Attachments

Files (documents, spreadsheets, images) attached to specific cells

Supporting Details

Line-item breakdowns that roll up into a cell value

Before this enhancement, Groovy rules could manipulate Essbase data programmatically, but copying the full data package — including comments, attachments, and supporting details — required either manual UI operations or complex workarounds. This created challenges in several common scenarios:

  • Seeding budget data from actuals — Comments explaining actual variances were lost during the copy
  • Version management — Copying from a working version to a final version stripped supporting detail
  • Period rollover — Rolling forward a forecast lost the context behind the numbers
  • Scenario planning — Duplicating a base scenario for what-if analysis excluded attachments and notes

 

The New CopyDataRequest Class

The April 2026 release introduces the CopyDataRequest class in the Cloud EPM Groovy Rules Java API. This class provides a fluent, builder-pattern API for defining and executing data copy operations that include all relational artifacts.

Key Methods

Method

Description

setCopySupportingDetail(boolean)

Enables or disables copying of supporting detail line items

setCopyComments(boolean)

Enables or disables copying of cell-level comments

setCopyAttachments(boolean)

Enables or disables copying of cell-level file attachments

addSourceAndTarget(String, String)

Defines a source-to-target member mapping for the copy operation

addFixedMembers(Dimension, String...)

Specifies fixed members or member expressions to constrain the copy scope

copyData()

Executes the copy operation

Important Constraints

  • A single CopyDataRequest object can only be used one time. For multiple copy operations, create a new request object for each iteration.
  • The copy operation respects the existing security model — users must have appropriate access to both source and target intersections.
  • Both Essbase data and relational data are copied in a single, unified operation.

 

Applicable EPM Modules

This enhancement applies to the following Oracle Cloud EPM business processes: [docs.oracle.com]

Module

Supported

Planning

Yes

FreeForm

Yes

 

Code Examples

Example 1: Basic Data Copy with All Relational Artifacts

This example copies data from Current/FY26 to Budget/FY27, including supporting details, comments, and attachments:

Application app = operation.application
Cube cube = app.getCube("Plan2")

CopyDataRequest request = cube.createCopyDataRequest()

    .setCopySupportingDetail(true)
    .setCopyComments(true)
    .setCopyAttachments(true)

request = request

    .addSourceAndTarget("Current", "Budget")
    .addSourceAndTarget("FY26", "FY27")
    .addFixedMembers(app.getDimension("Employee"), "ILvl0Descendants(Employee)")
    .addFixedMembers(app.getDimension("Account"), "Grade", "Salary", "Bonus",
        "Employee Phone", "Employee Email", "Reporting Manager")
    .addFixedMembers(app.getDimension("Currency"), "USD")
    .addFixedMembers(app.getDimension("Version"), "BU Version_1")
    .addFixedMembers(app.getDimension("Entity"), "No Entity")
    .addFixedMembers(app.getDimension("Period"), "BegBalance")

request.copyData()

 

Breaking Down the Code

Step 1 — Get Application and Cube References

Application app = operation.application

Cube cube = app.getCube("Plan2")


This retrieves the current application context and the specific cube (plan type) where the data resides.

 

Step 2 — Create the CopyDataRequest and Set Options


CopyDataRequest request = cube.createCopyDataRequest()

.setCopySupportingDetail(true)

.setCopyComments(true)

.setCopyAttachments(true)


The fluent builder pattern allows chaining of configuration methods. Setting each flag to true ensures that all relational data types are included in the copy.

 

Step 3 — Define Source-to-Target Mappings


request = request

.addSourceAndTarget("Current", "Budget")

.addSourceAndTarget("FY26", "FY27")


Multiple source-to-target pairs can be chained. In this case, the Scenario dimension maps Current to Budget, and the Year dimension maps FY16 to FY17.

 

Step 4 — Constrain the Scope with Fixed Members

.addFixedMembers(app.getDimension("Employee"), "ILvl0Descendants(Employee)")

.addFixedMembers(app.getDimension("Account"), "Grade", "Salary", "Bonus", ...)


Fixed members define the dimensional scope of the copy. You can use individual member names or Essbase member selection functions like ILvl0Descendants().

 

Step 5 — Execute the Copy


request.copyData()


This triggers the actual data copy operation.

  

Example 2: Iterative Copy to Multiple Versions

This example copies last year's Actual data from the Final version to all level-0 versions in this year's Budget:

Application app = operation.application
Cube cube = app.getCube("Plan2")

List<Member> versions = app.getDimension("Version")

    .getEvaluatedMembers("ILvl0Descendants(Version)", cube)
versions.remove(app.getDimension("Version").getMember("Final"))

versions.each { version ->

    CopyDataRequest request = cube.createCopyDataRequest()
        .setCopySupportingDetail(true)
        .setCopyComments(true)
        .setCopyAttachments(true)

    request = request

        .addSourceAndTarget("Actual", "Budget")
        .addSourceAndTarget("&LastYear", "&ThisYear")
        .addSourceAndTarget("Final", version)

    request.addFixedMembers(app.getDimension("Employee"),

        "ILvl0Descendants(Employee)")
    request.addFixedMembers(app.getDimension("Account"),
        "Grade", "Salary", "Bonus", "Employee Phone",
        "Employee Email", "Reporting Manager")
    request.addFixedMembers(app.getDimension("Currency"), "USD")
    request.addFixedMembers(app.getDimension("Entity"), "No Entity")
    request.addFixedMembers(app.getDimension("Period"), "BegBalance")

    request.copyData()

}


Key Points in This Example

  • Substitution Variables (&LastYear, &ThisYear) can be used in source-to-target mappings, enabling dynamic year-based copy operations
  • A new CopyDataRequest is created inside the loop for each version, since each request object can only be used once
  • Member objects (not just strings) can be passed as target values, as shown with the version variable

 

Example 3: Using Runtime Prompts (RTPs) with Member References

This example demonstrates using Runtime Prompt variables and explicit member references:

/*RTPS: {MyEmployees}*/
Application app = operation.application
Cube cube = app.getCube("Plan2")

Member salaryMember = app.getDimension("Account").getMember("Salary")

CopyDataRequest request = cube.createCopyDataRequest()

    .setCopySupportingDetail(false)
    .setCopyComments(false)
    .setCopyAttachments(false)

// Use RTP variable and member reference for targeted copy

request = request
    .addSourceAndTarget("Actual", "Budget")
    .addFixedMembers(app.getDimension("Employee"), rtps.MyEmployees)
    .addFixedMembers(app.getDimension("Account"), salaryMember)

request.copyData()

Key Points

  • The RTPS comment line (/*RTPS: {MyEmployees}*/) is mandatory when using Runtime Prompt variables — this is one of the most common Groovy validation errors flagged by the Groovy Script Validator
  • Individual relational data types can be selectively excluded by setting flags to false
  • Member objects retrieved via getMember() can be used directly in addFixedMembers()


  Practical Use Cases

1. Automated Budget Seeding

Copy actual data from the completed fiscal year into the new budget cycle, preserving all comments and supporting details that explain the actuals. This eliminates the need for manual re-entry of contextual information during the budget preparation process.

2. Forecast Rolling

Automate monthly forecast rolling by copying the current forecast period forward, including all supporting detail line items and analyst comments. This ensures continuity and auditability across forecast cycles.

3. Version Snapshotting

Create point-in-time snapshots of planning data by copying from a working version to an archive version, including all attachments and supporting documentation. This is critical for regulatory compliance and audit readiness.

4. Scenario Duplication

Duplicate a base planning scenario into multiple what-if scenarios, preserving the full context of the original plan including all relational artifacts. This enables faster scenario analysis without losing the analytical context behind the numbers.

5. Month-End / Period-End Automation

Integrate this capability into existing month-end automation scripts to create a fully automated data management pipeline that handles not just numeric data but the complete data package.

 

 

Integration with the Groovy Engine Update

It is important to note that this feature arrives alongside the announcement of a mandatory Groovy engine update planned for May 2026 (26.05). The new Groovy engine introduces stricter validation rules, which means existing Groovy business rules may need to be updated.

Recommended Actions

  1. Run the Groovy Script Validator in your test environment immediately
  2. Review the validation report and fix any flagged scripts
  3. When writing new CopyDataRequest scripts, ensure compliance with the new validation rules:
    • Use explicit data types instead of def
    • Always include the RTPS comment line
    • Add the "d" suffix to floating-point numbers
    • Remove empty generic type declarations
  4. Test thoroughly before the 26.05 update is applied

 

Technical Considerations

Performance

  • Large-scale copy operations that include supporting details and attachments will take longer than data-only copies
  • Consider breaking large copy operations into smaller batches using fixed member constraints
  • Monitor job execution times and adjust scope as needed

Security

  • The copy operation respects the application's security model
  • Users executing the Groovy rule must have read access to source intersections and write access to target intersections
  • Service Administrator or Power User roles are typically required

Error Handling

  • Wrap copy operations in try-catch blocks for robust error handling
  • Log the source and target mappings before execution for troubleshooting
  • Validate member existence before creating the request to avoid runtime errors

 

Conclusion

The Groovy Rules to Support the Copying of Relational Data, Comments, Attachments, and Supporting Details in Oracle EPM Cloud April 2026 (26.04) fills a critical gap in EPM automation. By providing a clean, programmatic API for copying the complete data package — not just numeric values — Oracle is enabling organizations to build truly end-to-end automated workflows for budgeting, forecasting, and financial close processes.

For EPM developers and administrators, the new CopyDataRequest class offers a powerful, flexible, and well-designed API that integrates seamlessly into existing Groovy business rules. Combined with Runtime Prompts, substitution variables, and member selection functions, it provides the tools needed to automate even the most complex data management scenarios while preserving the full context and auditability of financial data.

This is a feature that planning teams have been waiting for — and it delivers exactly what is needed to take EPM automation to the next level.

Happy Days on the cloud! 


Updates to the GET Job Status REST API!

The Oracle Fusion Cloud EPM April 2026 (26.04) release delivers a significant enhancement to one of the most frequently used REST APIs in the EPM automation ecosystem — the GET Job Status REST API. This API, which serves as the backbone for monitoring Data Integration job execution, has been enhanced to return more granular job status details, providing administrators and developers with deeper visibility into job processing states.

This enhancement directly addresses a long-standing need in enterprise EPM environments where understanding why a job failed — not just that it failed — is critical for maintaining efficient financial close processes, automated data pipelines, and integration workflows.

 

What is the GET Job Status REST API?

The Retrieve Job Status REST API is a core Data Integration API that allows you to poll the EPM Cloud environment to get the processing state for a job with a specified ID. It is essential for any automation workflow that needs to monitor whether a triggered integration, data load, or export has completed successfully.

REST Endpoint

GET /aif/rest/{api_version}/jobs/{jobIdentifier}

  • API Version: The current REST API version for Data Integration must be V1
  • Required Roles: Service Administrator, Power User
  • Media Type: application/json

 

What Changed in April 2026 (26.04)?

Prior to this update, the GET Job Status API returned basic status information — a numeric code and a high-level descriptor. While functional, this limited the ability of automated workflows to diagnose failures programmatically or make intelligent retry decisions.

With the April 2026 enhancement, the API now returns more granular job status details, enabling:

 

Richer error diagnostics — More detailed information about why a job failed

  • Improved troubleshooting — Administrators can pinpoint issues without navigating the UI
  • Smarter automation — Scripts and pipelines can make better decisions based on detailed status responses
  • Enhanced audit trails — More comprehensive logging for compliance and governance

 

API Response Parameters

The following table details the response parameters returned by the GET Job Status API: 

Parameter

Description

Example

status

Numeric status code of the job

0

details

Details about the job status

"SUCCESS"

jobId

The unique ID of the job

1881

jobName

The name of the job

BESSAPP

jobStatus

The descriptive status of the job

SUCCESS

descriptiveStatus

Human-readable status

Completed or Error

logFileName

Path to the job log file

outbox/logs/BESSAPP-DB_1881.log

outputFileName

Path to the output file

outbox/BESSAPPJan-06.csv

processType

Type of process executed

EXPORT_MAPPING

executedBy

User who executed the job

admin

 

Job Status Codes

The API uses the following numeric status codes to indicate the state of a job:

 

Status Code

Description

-1

In Progress

0

Success

1

Error

2

Cancel Pending

3

Cancelled

4

Invalid Parameter

Integer.MAX_VALUE

Unknown

 

Example: API Response

The following is an example of the JSON response body when member mappings are exported successfully:

JSON

{
  "links": [0],
  "status": "0",
  "details": "null",
  "jobId": "1881",
  "jobStatus": "SUCCESS",
  "logFileName": "outbox/logs/BESSAPP-DB_1881.log",
  "outputFileName": "outbox/BESSAPPJan-06.csv",
  "processType": "EXPORT_MAPPING",
  "executedBy": "admin"

How It Fits into Automation Workflows

The Submit → Poll → Collect pattern is the foundation of most EPM automation workflows. Here's how the enhanced GET Job Status API fits into this pattern:

Step 1: Submit the Job (POST)

Trigger a Data Integration job using the POST method:

POST /aif/rest/V1/jobs

Content-Type: application/json

 

{

  "jobType": "INTEGRATION",

  "jobName": "GL_DATA_LOAD",

  "importMode": "Replace",

  "exportMode": "Merge",

  "fileName": "inbox/gl_data.csv"

}

The response returns a jobId and a link/href for status tracking.

 

Step 2: Poll for Status (GET) — Enhanced in 26.04

Use the enhanced GET Job Status API to monitor execution:

GET /aif/rest/V1/jobs/{jobId}

Poll at regular intervals until the status moves from -1 (In Progress) to a terminal state (0 = Success, 1 = Error, 3 = Cancelled).

With the 26.04 enhancement, the response now provides more granular details about the processing state, enabling your automation scripts to:

  • Log detailed error information for failed jobs
  • Trigger conditional retry logic based on specific failure reasons
  • Send targeted notifications with actionable error details
  • Generate comprehensive audit reports with job execution context

Step 3: Collect Results

On success, retrieve output files or logs from the paths returned in the response (logFileName, outputFileName).

 

Practical Use Cases

1. PowerShell / EPM Automate Automation Scripts

If you are running automation scripts (like the FCCS automation scripts many organizations maintain), the enhanced status details allow your scripts to:

  • Differentiate between a mapping error vs. a connectivity error
  • Include specific failure reasons in email notifications
  • Make intelligent decisions about whether to retry or escalate

 

2. Groovy Rules with REST API Calls

Groovy business rules that trigger integrations via REST can now leverage the enhanced status details for more robust error handling:

// Poll with enhanced status details
while (status == IN_PROGRESS && retries < maxRetries) {
    status = getJobStatus(connectionName, jobId)
    // Now includes granular details for better error handling
    sleep(delay)


3. DevOps and CI/CD Pipelines

For organizations integrating EPM into DevOps pipelines, the enhanced API enables:

  • More precise pipeline stage gates based on detailed job outcomes
  • Better error categorization for automated incident creation
  • Richer telemetry for monitoring dashboards

 

Authentication Requirements

The GET Job Status API supports the following authentication methods:

 

Method

Description

Basic Authentication

Base64-encoded identitydomain.username:password

OAuth 2.0 (Recommended)

Token-based authentication with access token and refresh token

 

For environments with MFA enabled, OAuth 2.0 is required.

 

Conclusion

The Updates to the GET Job Status REST API in Oracle EPM Cloud April 2026 (26.04) may seem like a subtle enhancement, but its impact on enterprise automation is significant. By returning more granular job status details, Oracle is enabling organizations to build smarter, more resilient, and more observable automation pipelines.

For EPM administrators and developers who rely on REST APIs for data integration workflows — whether through PowerShell scripts, Groovy rules, or DevOps pipelines — this enhancement means better error diagnostics, faster troubleshooting, and more intelligent automation logic.

Combined with other April 2026 enhancements like Customization of Data Integration Roles and the new Agentic AI REST APIs, this update reinforces Oracle's commitment to making EPM Cloud a truly API-first, automation-ready platform.

Happy Days on the Cloud!!! 


New REST APIs to Support Agentic AI Interaction – Oracle EPM Cloud April 2026!

Introduction

The Oracle Fusion Cloud EPM April 2026 (26.04) release introduces a groundbreaking set of new REST APIs specifically designed to enable Agentic AI interaction with EPM Cloud applications. These APIs represent a strategic shift in how organizations can interact with their EPM environments — moving from traditional UI-driven processes to intelligent, programmatic, and AI-powered workflows.

This is not a future roadmap item — it is live in 26.04, and it signals Oracle's clear commitment to making EPM Cloud a platform that supports modern AI-driven enterprise architectures. 



Oracle EPM April 2026 (26.04) Update – AI, Automation, and Platform Enhancements!

The Oracle Fusion Cloud Enterprise Performance Management (EPM) April 2026 release marks a significant step forward in the evolution of modern EPM platforms. After a period of platform consolidation and updates, this release introduces a broad set of enhancements spanning Artificial Intelligence (AI), automation, security, and enterprise integration.

This update is not just incremental—it represents a strategic shift toward intelligent, API-driven, and highly automated EPM ecosystems, enabling organizations to move beyond traditional finance processes into more predictive, data-driven decision-making environments.


Key Themes

Several strategic themes define this release:

  • AI-driven decision support enabling predictive insights and intelligent automation
  • Expanded REST API capabilities supporting automation and DevOps-driven deployments
  • Stronger integration frameworks for seamless data exchange across enterprise systems
  • Enhanced governance and security controls for improved compliance and access management

Collectively, these enhancements align Oracle EPM with modern enterprise architecture standards, where automation, intelligence, and scalability are key priorities.

 

Wednesday, May 27, 2026

Oracle EPM Authentication Deep Dive: Basic Auth vs OAuth 2.0!

Oracle EPM (Enterprise Performance Management Cloud) supports two primary authentication models for automation and integrations:

  • Basic Authentication (Username + Password)
  • OAuth 2.0 (Token-based authentication)

Both are supported for:

  •  EPM Automate
  •  REST APIs
  •  Integration Agent

However, Oracle clearly recommends OAuth 2.0 as the modern and secure approach, primarily because it eliminates the need to expose passwords in scripts and integrations.

Friday, May 15, 2026

Oracle EPM Automate copyToSftp — Eliminate the Middleman: Direct Cloud-to-SFTP File Transfers!

If you've been running Oracle EPM Cloud automations for any length of time, chances are your file transfer workflow looks something like this: run a data export in EPM Cloud, download the file to an intermediary server using downloadFile, then use a third-party SFTP client (like WinSCP) to upload it to the destination SFTP server. It works — but it's clunky, introduces unnecessary dependencies, and creates security exposure by landing sensitive financial data on a local disk.

What if I told you there's a single command that sends files directly from EPM Cloud to any SFTP server — no local download, no third-party tools, no files touching intermediate servers?

Meet copyToSftp.

In this post, I'll walk through what copyToSftp does, the authentication methods it supports (including the newly introduced SSH key-based auth), the prerequisites, and — most importantly — the real-world lessons I learned while implementing it for a production FCCS-to-Adaptive integration at a client site.

 

The Problem: The Traditional 5-Step Relay

Before copyToSftp, a typical EPM-to-SFTP automation looked like this:

EPM Cloud ──downloadFile── Local Server ──WinSCP── SFTP Server

The full workflow:

  1. epmautomate runDataRule — Generate the extract in EPM Cloud
  2. epmautomate downloadFile — Download to local server inbox
  3. Rename-Item — Rename with timestamp for versioning
  4. WinSCP PutFiles() — Upload to destination SFTP
  5. Move-Item — Archive locally

Dependencies required:

  • WinSCP .NET assembly (WinSCPnet.dll)
  • Stored SFTP credentials (sftp_credential.xml via DPAPI)
  • Local inbox and Archive directories
  • Network connectivity from local server to SFTP

 


 

The Solution: copyToSftp — One Command, Zero Intermediaries

The copyToSftp command copies a file directly from an EPM Cloud environment to an SFTP server. No downloading. No local staging. No third-party libraries.

 

EPM Cloud ──copyToSftp── SFTP Server

 

The new workflow:

  1. epmautomate runDataRule — Generate the extract in EPM Cloud
  2. epmautomate copyToSftp — Send directly to SFTP

That's it. Two steps.

 


 

 

 

Authentication Methods

As of the April 2026 update, copyToSftp supports three authentication methods:

 

Method 1: Username + Password

The simplest approach — provide SFTP credentials directly.

 

epmautomate copyToSftp sftp://myserver/dir/file.csv myFile.csv username=jDoe password=myPassword

  

Pros

Cons

Simple setup

Password in plain text on command line

No key management

EPM warns about clear-text passwords

Works with most SFTP servers

Less secure for automation





Method 2: Username + Private Key (Unprotected)

SSH key-based authentication without a passphrase — ideal for automated scripts.


epmautomate copyToSftp sftp://myserver/dir/file.csv myFile.csv username=jDoe privateKey=C:\keys\my_key.pem


Pros

Cons

No password transmitted

Key file must be secured on disk

Industry best practice

Unprotected key = risk if server compromised

Automation-friendly

Requires .pem format

No clear-text warning

Method 3: Username + Private Key + Passphrase

The most secure option — the private key itself is encrypted with a passphrase.


epmautomate copyToSftp sftp://myserver/dir/file.csv myFile.csv username=jDoe privateKey=C:\keys\my_key.pem passphrase=myPassPhrase


Pros

Cons

Highest security

Passphrase on command line (use -p param file)

Key + passphrase = two-factor

Slightly more complex setup

Meets compliance requirements



Command Syntax

epmautomate copyToSftp SFTP_SERVER_URL EPM_FILE_NAME

    username=USERNAME

    [password=PASSWORD]

    [privateKey=KEY_FILE]

    [passphrase=PASSPHRASE]

 

Parameter

Description

Required?

SFTP_SERVER_URL

Full SFTP URL including directory and target filename

Yes

EPM_FILE_NAME

Name of the file in EPM Cloud (outbox)

Yes

username

SFTP user account

Yes

password

SFTP password (if not using key auth)

Conditional

privateKey

Full local path to .pem private key file

Conditional

passphrase

Passphrase for encrypted private keys

Optional

 

Supported Cryptographic Algorithms

The SFTP server must support at least one algorithm from each category:

Category

Supported Algorithms

Ciphers

chacha20-poly1305@openssh.com, aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, aes256-gcm@openssh.com, aes128-cbc, aes192-cbc, aes256-cbc

MACs

hmac-sha2-256-etm@openssh.com, hmac-sha2-512-etm@openssh.com, hmac-sha1-etm@openssh.com, hmac-sha2-256, hmac-sha2-512, hmac-sha1

Key Exchange

curve25519-sha256, ecdh-sha2-nistp256/384/521, diffie-hellman-group14-sha256, diffie-hellman-group16-sha512, and others

Host Key

ecdsa-sha2-nistp256/384/521, ssh-ed25519, rsa-sha2-256/512, ssh-rsa, and certificate variants


 

Prerequisites

Before using copyToSftp, ensure the following are in place:

 

1. EPM Automate Installed and Updated

  • Latest version of EPM Automate CLI installed on your automation server
  • Java Runtime Environment (JRE) configured

 

2. EPM Cloud Login

  • Valid Service Administrator credentials
  • Encrypted password file (pass.epw) recommended:

epmautomate encrypt YourPassword pass.epw AnyRandomKey

 

3. SFTP Server on Port 22

  • copyToSftp supports port 22 only — non-standard ports are not supported

 

4. Private Key in .pem Format (for key-based auth)

  • The key must be in PEM format (e.g., -----BEGIN EC PRIVATE KEY-----)
  • Supported key types: RSA, ECDSA (nistp256/384/521), Ed25519
  • The file must be stored locally on the machine running EPM Automate (not uploaded to EPM Cloud)

 

5. IP Allowlisting (if applicable)

  • If the SFTP server has IP allowlisting enabled, add Oracle's outbound IP address for the OCI region hosting your EPM environment

 

6. Public Key on SFTP Server

  • The corresponding public key must be added to the authorized_keys file on the SFTP server under the appropriate user account

 

Real-World Implementation: FCCS → Adaptive via SFTP

Here's where theory meets reality. I implemented copyToSftp for a production FCCS-to-Adaptive integration, replacing a WinSCP-based pipeline that had been running for months. Below are the actual findings, errors encountered, and solutions discovered.

 

The Setup

Component

Detail

Source

Oracle FCCS (Test Instance)

Destination

awssftp1.brooksautomation.com

Auth

ECDSA private key (-----BEGIN EC PRIVATE KEY-----)

Username

fccs

Files

DLR_Data_Extract_JE.csv, DLR_Data_Extract_AllEntities.csv


The private key file must reside on the local machine running EPM Automate. The command reads it locally and uses it for the SSH handshake.

 

 

  • File Extension Must Be .pem

 

  • Do NOT Include password= with Key Auth

When using key-based auth, the password= parameter must be omitted entirely. Including it — even with a dummy value — causes a parsing failure.

 

  • PowerShell Mangles key=value Arguments in Scripts

 

Even after placing the .pem file in the correct directory, EPM Automate reported "File does not exist."

 

The Java process running EPM Automate operates under a different security context. The file existed but wasn't readable.

 

The Final Working Command

After all the troubleshooting, here's the exact command that works:

 

epmautomate copyToSftp sftp://awssftp.server.com/DLR_Data_Extract_JE.csv DLR_Data_Extract_JE.csv username=fccs privateKey=C:\Scripts\secure\privatekey-sftp.pem

 

 

Before vs. After Comparison

Metric

Before (downloadFile + WinSCP)

After (copyToSftp)

Steps per file

5

2

Dependencies

WinSCP DLL, credential XML, inbox/archive folders

None — EPM Automate only

Data on local disk

Yes

Never

Auth method

Password (DPAPI encrypted)

SSH key (.pem)

Security exposure

Password + files on intermediary server

Key-only, zero local data

Lines of PowerShell

~80 (SFTP section)

~10

Failure points

Download, rename, connect, upload, archive

Single copyToSftp call


 

Pipeline Alternative: No Script Needed

As of the September 2025 update, Oracle also introduced Copy to SFTP and Copy from SFTP as native Pipeline job types in EPM Cloud. This means you can configure the entire extract-and-push flow within the EPM Cloud UI — no PowerShell script required.



This is worth exploring if you want to move the orchestration entirely into EPM Cloud and eliminate the local server dependency altogether.

 

Quick Reference: Troubleshooting Checklist

Error

Cause

Fix

EPMAT-7: File does not exist

Wrong path, wrong extension, or permissions

Use full path, .pem extension, grant read access

EPMAT-7: Invalid or missing parameter: privateKey

Empty privateKey= value or space after =

No space: privateKey=C:\path\key.pem

EPMAT-7: Invalid or missing parameter: password

password= included with key auth

Remove password= entirely

Usage text dumps before error

PowerShell mangling key=value args

Use cmd /c or --% in scripts

EPMAT-7: Session is not authenticated

Not logged in before copyToSftp

Run epmautomate login first

EPMAT-1: File already exists

File from previous upload still in EPM

Run epmautomate deleteFile first

Connection timeout

IP not allowlisted on SFTP server

Add Oracle OCI outbound IP to SFTP allowlist


 

Conclusion

copyToSftp is one of those features that fundamentally simplifies your EPM automation architecture. It eliminates intermediary servers, third-party dependencies, and local data exposure — replacing a fragile 5-step relay with a single, secure, auditable command.

Combined with the April 2026 enhancement for SSH key-based authentication, it now meets enterprise compliance requirements for secure file transfers without compromising on automation capability.

 

Whether you're pushing FCCS extracts to Adaptive, sending reconciliation data to FloQast, or transferring reports to any SFTP endpoint — copyToSftp should be your default approach.

 

Key takeaways:

  •  Use .pem format for private keys
  •  Omit password= when using key auth
  •  Use cmd /c in PowerShell scripts to avoid argument parsing issues
  •  Grant file read permissions for the Java process
  •  Allowlist Oracle's OCI outbound IP on your SFTP server
  •  Consider Pipeline job types for fully cloud-native orchestration

Happy days on the Cloud!!!