⚔ The Planning Quest REST API Cookbook
Parts I–III Parts IV–V Parts VI–IX Groovy I Groovy II 💻 Lab 👥 Workforce 🌐 REST API CLI Prep
Navigate
🏠 Home 📖 Parts I–III 📖 Parts IV–V 📖 Parts VI–IX 📘 Groovy Deep-Dive I ⚡ Groovy Deep-Dive II 👥 Workforce Planning 💻 Groovy Lab 📝 Quiz 🃏 Flashcards 🔬 Enterprise Labs 🧮 Simulators ⚙ EPM Automate CLI 🌐 REST API Cookbook 🎯 Interview Prep 🆕 What's New 🔍 Search
Jump To
🔐 Authentication ⚙ Job Operations 📊 Data Operations 🗂 Metadata 📋 Planning Units 📝 Forms & Grids 🔗 Data Integration 💡 Production Tips
🌐 REST API Cookbook · EPM 25.06+
Oracle EPM Cloud REST API
Production-ready recipes · 38 endpoints across 7 categories · curl + Python · Vision Corp examples
38
Endpoints
7
Categories
25.06
EPM Aligned
v3
API Version
💡Base URL pattern: https://planning-{identity}.pbcs.{dc}.oraclecloud.com/HyperionPlanning/rest/v3/
Vision Corp: planning-a123456.pbcs.us2.oraclecloud.com — All endpoints below are relative to this base.
🔐Authentication & Connection3 recipes
GET /applications/{application} Essential

Verify connection and retrieve application metadata. Use as a health-check before running any automation pipeline.

curl -X GET \ "https://planning-a123456.pbcs.us2.oraclecloud.com/HyperionPlanning/rest/v3/applications/VisionCorp" \ -H "Authorization: Basic $(echo -n '[email protected]:$EPM_PWD' | base64)" \ -H "Content-Type: application/json" # Response: 200 OK { "name": "VisionCorp", "type": "PLANNING", "databaseType": "BSO", "status": "RUNNING" }
Auth options: Basic Auth (base64 user:pass) for dev/test. OAuth 2.0 Client Credentials (recommended) for production. Never hardcode credentials — use environment variables or Oracle Vault.
POST OAuth 2.0 — Client Credentials Flow Essential

Production-recommended authentication. Tokens expire after 3600s — cache and refresh proactively.

# Step 1: Get access token from IDCS curl -X POST \ "https://idcs-{tenant}.identity.oraclecloud.com/oauth2/v1/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&scope=urn:opc:resource:consumer::all" # Python — token caching pattern import requests, os, time _token_cache = {'token': None, 'expires_at': 0} def get_token(): if time.time() < _token_cache['expires_at'] - 60: return _token_cache['token'] r = requests.post(TOKEN_URL, data={ 'grant_type': 'client_credentials', 'client_id': os.environ['EPM_CLIENT_ID'], 'client_secret': os.environ['EPM_CLIENT_SECRET'], 'scope': 'urn:opc:resource:consumer::all' }) data = r.json() _token_cache['token'] = data['access_token'] _token_cache['expires_at'] = time.time() + data['expires_in'] return _token_cache['token']
GET /applications/{app}/dimensions Essential

List all dimensions. Useful for API-driven metadata validation and automated testing.

GET /applications/VisionCorp/dimensions # Response { "dimensions": [ { "name": "Account", "type": "Account", "generationCount": 5 }, { "name": "Entity", "type": "Entity", "generationCount": 4 }, { "name": "Period", "type": "Period", "generationCount": 3 }, { "name": "Year", "type": "Year", "generationCount": 2 }, { "name": "Scenario", "type": "Scenario", "generationCount": 2 }, { "name": "Version", "type": "Version", "generationCount": 2 } ]}
Job Operations (Async)6 recipes
💡Async pattern: All EPM job endpoints return a jobId immediately (202 Accepted). Poll GET /jobs/{jobId} every 5–10 seconds until status is Completed, Error, or Invalid. Never assume synchronous completion.
POST /applications/{app}/jobs — Run Business Rule Async Essential

Submit a Groovy business rule via REST. The most common EPM automation call.

POST /applications/VisionCorp/jobs Content-Type: application/json { "jobType": "RULES", "jobName": "OEP_CalculateWFP", "parameters": { "Scenario": "Budget", "Version": "Working", "Entity": "Total_Entity", "Period": "Jan", "Year": "FY2025" } } # Response: 202 Accepted { "jobId": 12847, "status": "Processing" } # Poll until done: GET /applications/VisionCorp/jobs/12847 → { "status": "Completed", "completionTime": "2025-06-01T02:34:18Z" }
jobType values: RULES · IMPORT_DATA · EXPORT_DATA · IMPORT_METADATA · EXPORT_METADATA · CLEAR_DATA · REFRESH_DATABASE
GET /applications/{app}/jobs/{jobId} — Poll Job Status Async

Terminal states: Completed, Error, Invalid. Intermediate: Processing, Queued.

# Python — poll until done with timeout import time, requests def run_and_wait(job_body, headers, base_url, timeout=300): r = requests.post(f"{base_url}/jobs", json=job_body, headers=headers) job_id = r.json()['jobId'] elapsed = 0 while elapsed < timeout: s = requests.get(f"{base_url}/jobs/{job_id}", headers=headers).json() if s['status'] in ('Completed', 'Error', 'Invalid'): return s time.sleep(5); elapsed += 5 raise TimeoutError(f"Job {job_id} timed out after {timeout}s") # Usage result = run_and_wait({"jobType": "RULES", "jobName": "OEP_CalculateWFP"}, HDR, BASE) if result['status'] != 'Completed': raise RuntimeError("Rule failed: " + result.get('jobOutputInfo', ''))
POST /applications/{app}/jobs — Run Data Rule Async

Execute a Data Integration / FDMEE data load rule.

POST /applications/VisionCorp/jobs { "jobType": "IMPORT_DATA", "jobName": "GL_Actuals_Monthly_Load", "parameters": { "startPeriod": "Jan-25", "endPeriod": "Mar-25", "importMode": "REPLACE", "exportMode": "STORE_DATA" } }
importMode values: REPLACE (recommended for actuals) · MERGE · ACCUMULATE · SUBTRACT
POST Nightly Automation Pipeline — Full Chain Advanced

Complete nightly pipeline: Load → Calculate → Sync → Export → Alert on failure.

#!/usr/bin/env python3 # Vision Corp Nightly Budget Pipeline via REST API import requests, time, os, logging BASE = "https://planning-a123456.pbcs.us2.oraclecloud.com/HyperionPlanning/rest/v3/applications/VisionCorp" HDR = {"Authorization": f"Bearer {get_token()}", "Content-Type": "application/json"} PIPELINE = [ {"jobType": "IMPORT_DATA", "jobName": "WF_HCM_Actuals_Load"}, {"jobType": "RULES", "jobName": "OEP_CalculateWFP"}, {"jobType": "RULES", "jobName": "OEP_SyncWFP_To_FS"}, {"jobType": "EXPORT_DATA", "jobName": "WF_CFO_Pack_Export"}, ] for job in PIPELINE: logging.info(f"Starting: {job['jobName']}") result = run_and_wait(job, HDR, BASE) if result['status'] != 'Completed': send_alert(f"EPM Pipeline FAILED at {job['jobName']}") break logging.info(f"✓ {job['jobName']} done in {result.get('elapsed','?')}ms")
Vision Corp Pattern
This pipeline runs nightly at 02:30 UTC via GitHub Actions (cron). Slack alert fires if any job status != Completed. Teams are notified before 07:00 their local time.
📊Data Operations6 recipes
POST /applications/{app}/jobs — Export Data Slice Essential

Export a specific data slice to the server inbox/outbox. Download the file in a second call.

POST /applications/VisionCorp/jobs { "jobType": "EXPORT_DATA", "jobName": "Budget_FY2025_Export", "parameters": { "exportFileName": "Budget_FY2025.txt", "scenario": "Budget", "version": "Working", "year": "FY2025", "period": "BegBalance,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec" } } # After job completes, download the file: GET /applications/VisionCorp/files/budget/Budget_FY2025.txt
POST /applications/{app}/jobs — Clear Data Async

Clear a data slice before a reload. Use sparingly — always clear only the specific intersection you're about to reload.

POST /applications/VisionCorp/jobs { "jobType": "CLEAR_DATA", "jobName": "VisionCorp", "parameters": { "scenario": "Budget", "version": "Working", "years": "FY2025", "periods": "Jan,Feb,Mar", "entities": "NA" } }
Production safety: Always clear only what you're about to reload. Clearing Budget·Working for the full year at 2am, then having the load fail, leaves planners with blank numbers in the morning.
GET /applications/{app}/files/{path} — Download File Essential

Download any file from the EPM server inbox/outbox after an export job completes.

curl -X GET \ "https://planning-a123456.pbcs.us2.oraclecloud.com/HyperionPlanning/rest/v3/applications/VisionCorp/files/budget/Budget_FY2025.txt" \ -H "Authorization: Bearer $TOKEN" \ -o Budget_FY2025.txt # Python download r = requests.get(f"{BASE}/files/budget/Budget_FY2025.txt", headers=HDR, stream=True) with open('Budget_FY2025.txt', 'wb') as f: for chunk in r.iter_content(8192): f.write(chunk)
🗂Metadata Operations5 recipes
GET /applications/{app}/dimensions/{dim}/members/{member} Essential

Get member properties: aliases, UDAs, attributes, parent, children.

GET /applications/{app}/dimensions/{dim}/members/{member}/descendants Essential

Get all descendants of a member. Add ?level=0 to get leaf members only.

POST /applications/{app}/jobs — Import Metadata Async

Load dimension metadata from a flat file (upload file first, then import).

importMode values for metadata: MERGE (safe default — adds/updates, keeps existing) · REPLACE (removes members not in file) · ADD (adds only)
📋Planning Units & Workflow4 recipes
GET /applications/{app}/plantypes/{plantype}/approvalUnits Essential

Retrieve all planning unit approval statuses for workflow monitoring.

Vision Corp Use Case
Nightly script checks all units. If any are NotStarted 3 days before the budget deadline, it automatically sends a Slack reminder via the Slack API.
POST /applications/{app}/plantypes/{plantype}/approvalUnits — Change Status Advanced

Programmatically promote, reject, or sign off planning units via REST.

action values: PROMOTE · REJECT · APPROVE · SIGN_OFF · REOPEN
📝Forms & Grid Data4 recipes
POST /applications/{app}/forms/{form}/data — Read Grid Data Essential

Read data from a specific form at a given POV — same data the planner sees in the browser.

PATCH /applications/{app}/forms/{form}/data — Write Grid Data Advanced

Write data to a form grid via REST — same as a planner saving data in the browser.

Use cases: Automated seed-loading from prior year actuals, ETL pipelines writing directly to planning forms, integration with external approval tools that write approved values back to EPBCS.
🔗Data Integration (DI)4 recipes
GET /dataintegration/rest/v1/jobs — List DI Jobs Essential

Note: Data Integration uses a different base URL: /dataintegration/rest/v1/

POST /dataintegration/rest/v1/jobs — Execute DI Integration Async

Trigger a Data Integration pipeline directly (alternative to the Planning jobs endpoint).

💡Production Tips & Patterns

Rate Limits & Throttling

ConcernLimitBest Practice
Concurrent API requests~10 per serviceSerialize your pipeline — run jobs sequentially
Job poll frequencyNo hard limitPoll every 5–10s, not every 500ms
File upload size~250MBSplit large exports; use compression
Token expiry3600s (OAuth)Cache token, refresh 60s before expiry

Error Handling Matrix

HTTP StatusMeaningAction
202Job accepted (async)Poll /jobs/{id}
400Bad request — invalid paramsLog request body; fix parameters
401Auth failedRefresh token; check credentials
403Insufficient permissionsCheck service account roles in EPBCS
404Resource not foundVerify app name, dim name, job name
429Rate limitedBack off with exponential retry
503Service maintenanceRetry after 30–60s; check Oracle status page
Service account setup: Create a dedicated service account ([email protected]) with only the permissions needed (Power User minimum for job execution). Never use a personal login for automation — password changes will break your pipelines at 2am.
🧙
Oracle · AI Tutor
REST API & Integration Specialist · EPM 25.06+
OAuth 2.0 setup Run rule + poll Jobs vs DI API Export + download Rate limit handling Workforce Planning APIs
← Workforce Planning EPM Automate CLI →
No endpoints match your search.