---
# === IDENTITY ===
id: business/erp-integration/workday-raas-integration/2026
canonical_question: "What are Workday RaaS capabilities - 30-minute timeout, no pagination, 2GB output limit, workarounds?"
aliases:
  - "Workday Report as a Service API limits and constraints"
  - "How to handle Workday RaaS timeout and large report workarounds"
  - "Workday RaaS vs WQL for large dataset extraction"
  - "Workday custom report web service integration guide"
entity_type: erp_integration
domain: business > erp-integration > Workday RaaS Integration
region: global
jurisdiction: global
temporal_scope: 2025-2026

# === SYSTEM PROFILE ===
systems:
  - name: "Workday HCM / Financials"
    vendor: "Workday"
    version: "API v45.0+"
    edition: "All editions (RaaS included in standard subscription)"
    deployment: cloud
    api_surface: "RaaS (REST + SOAP)"

# === VERIFICATION ===
last_verified: 2026-03-02
confidence: 0.88
version: 1.0
first_published: 2026-03-02

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: evolving
  last_breaking_change: null
  next_review: 2026-08-29
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "30-minute execution timeout: reports exceeding this window are terminated by Workday"
  - "2 GB maximum output size: advanced custom reports enabled as web services cannot exceed 2 GB response payload"
  - "No native pagination: RaaS returns the entire result set in a single response -- no page/offset support"
  - "~10 API requests per second tenant-wide throttle: exceeding this drops requests silently"
  - "REST URL length ~2,083 characters: limits the number of prompt parameter values passable via GET"
  - "Reports must be Advanced type with 'Enable As Web Service' checked -- standard reports are not RaaS-eligible"
  - "Memory constraints: datasets exceeding ~50K rows risk timeout or out-of-memory failures"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs real-time individual record CRUD (create/update/delete)"
    use_instead: "business/erp-integration/workday-soap-api/2026"
  - condition: "User needs paginated large dataset extraction (>50K rows)"
    use_instead: "business/erp-integration/workday-wql-integration/2026"
  - condition: "User needs event-driven notifications from Workday"
    use_instead: "business/erp-integration/workday-business-events/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: integration_pattern
    question: "What integration pattern do you need?"
    type: choice
    options:
      - "batch reporting (scheduled report extraction)"
      - "incremental sync (delta data loads)"
      - "on-demand query (ad-hoc report pulls)"
      - "large dataset extraction (>50K rows)"
  - key: data_volume
    question: "How many rows does the report return?"
    type: choice
    options:
      - "< 10,000 rows"
      - "10,000-50,000 rows"
      - "> 50,000 rows"
      - "> 100,000 rows"
  - key: direction
    question: "What's the data flow direction?"
    type: choice
    options:
      - "outbound (reading from Workday)"
      - "outbound with filtering (parameterized extraction)"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/business/erp-integration/workday-raas-integration/2026"
suggested_citation: "Source: knowledgelib.io -- AI Knowledge Library (verified 2026-03-02)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to: []
  solves: []
  alternative_to: []
  often_confused_with: []

# === SOURCES ===
sources:
  - id: src1
    title: "Workday RaaS Explained: Reporting as a Service - Complete Guide"
    author: GoFig
    url: https://gofig.ai/blog/workday-raas-explained-complete-guide/
    type: technical_blog
    published: 2025-08-15
    reliability: moderate_high
  - id: src2
    title: "Workday RaaS: Reporting as a Service"
    author: Reco.ai
    url: https://www.reco.ai/hub/workday-raas-reporting-as-a-service
    type: technical_blog
    published: 2025-06-20
    reliability: moderate_high
  - id: src3
    title: "Workday Reports as SOAP Services in WD Studio"
    author: M. Richen
    url: http://mrichen.github.io/wdlearn/report_soap/index.html
    type: community_resource
    published: 2024-03-10
    reliability: moderate_high
  - id: src4
    title: "Workday API Integration Guide (In-Depth)"
    author: Knit
    url: https://www.getknit.dev/blog/workday-api-integration-in-depth
    type: technical_blog
    published: 2025-04-12
    reliability: moderate_high
  - id: src5
    title: "WQL vs RaaS vs REST vs SOAP: Choosing the Right Data Access Strategy in Workday"
    author: Megha Srivastava
    url: https://medium.com/@megha13srivastava/wql-vs-raas-vs-rest-vs-soap-choosing-the-right-data-access-strategy-in-workday-8b59ef740210
    type: technical_blog
    published: 2025-07-18
    reliability: moderate
  - id: src6
    title: "Scaling Workday Integrations With MuleSoft: Parallel Pagination"
    author: MuleSoft
    url: https://blogs.mulesoft.com/dev-guides/workday-integrations-and-parallel-pagination/
    type: technical_blog
    published: 2025-01-22
    reliability: high
  - id: src7
    title: "Workday RaaS Connector - Workato Docs"
    author: Workato
    url: https://docs.workato.com/connectors/workday/workday_raas.html
    type: official_docs
    published: 2025-10-01
    reliability: high
---

# Workday RaaS (Report as a Service) Integration

## TL;DR

- **Bottom line**: RaaS exposes Workday custom reports as REST/SOAP web services for outbound data extraction. Best for scheduled report pulls under 50K rows; use WQL with native pagination for anything larger.
- **Key limit**: 30-minute execution timeout + 2 GB output cap + zero native pagination. All three constraints interact -- a large report that exceeds any one of these fails completely.
- **Watch out for**: No pagination means Workday attempts to generate the entire result set in memory at once. Reports over ~50K rows routinely timeout or hit the 2 GB wall. You must implement pseudo-pagination using prompt parameter date-range chunking.
- **Best for**: Scheduled batch extraction of HR, payroll, and financial data under 50K rows per report run, with prompt-based filtering.
- **Authentication**: ISU (Integration System User) + WS-Security for SOAP; ISU + Basic Auth or OAuth 2.0 for REST. RaaS is included in all Workday subscriptions -- no additional license required.

## System Profile

Workday RaaS (Reports as a Service) converts Advanced custom reports into web service endpoints accessible via both REST and SOAP protocols. It is included in every Workday subscription at no additional cost. RaaS is outbound-only -- it reads data from Workday but cannot write, update, or delete records. For write operations, use Workday SOAP Web Services or REST API.

This card covers the RaaS surface specifically. Workday offers four data access strategies: SOAP Web Services (full CRUD), REST API (modern JSON-based subset), RaaS (report-driven extraction), and WQL (Workday Query Language with native pagination). RaaS is the most commonly used for integration data extraction because it leverages existing report definitions. [src5]

| Property | Value |
|---|---|
| **Vendor** | Workday |
| **System** | Workday HCM / Financials (all modules) |
| **API Surface** | RaaS (Report as a Service) -- REST + SOAP |
| **Current API Version** | v45.0+ (version specified per report endpoint) |
| **Editions Covered** | All editions -- RaaS included in standard subscription |
| **Deployment** | Cloud (SaaS only) |
| **API Docs URL** | [Workday Community - Web Services](https://community.workday.com/) (requires login) |
| **Status** | GA (Generally Available) |

## API Surfaces & Capabilities

| API Surface | Protocol | Best For | Max Output | Pagination | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| RaaS REST | HTTPS/JSON,CSV,XML | Scheduled report extraction <50K rows | 2 GB | No | No | Yes (batch) |
| RaaS SOAP | HTTPS/XML | Multi-instance reports, large parameter sets | 2 GB | No | No | Yes (batch) |
| WQL | HTTPS/JSON | Large dataset queries with pagination | Paginated | Yes (limit/offset) | Yes | Yes |
| SOAP Web Services | HTTPS/XML (WSDL) | Full CRUD operations, complex transactions | Per-operation | Yes | Yes | No |
| REST API | HTTPS/JSON | Modern lightweight CRUD, OAuth-native apps | Per-operation | Yes | Yes | No |

RaaS REST and RaaS SOAP share the same underlying report engine and constraints. The key difference: SOAP allows request parameters in the message body (no URL length limits), while REST passes parameters as URL query strings (capped at ~2,083 characters). [src3]

## Rate Limits & Quotas

### Per-Request Limits

| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Max output size | 2 GB | All RaaS endpoints | Report terminated if output exceeds this |
| Execution timeout | 30 minutes | All RaaS endpoints | Long-running reports killed after 30 min |
| REST URL length | ~2,083 characters | RaaS REST only | Limits number of prompt parameter values via GET |
| SOAP body size | No documented hard limit | RaaS SOAP only | Practical limit is memory/timeout |
| Row threshold for reliability | ~50,000 rows | All RaaS endpoints | Reports above this frequently timeout |

[src1, src2]

### Rolling / Daily Limits

| Limit Type | Value | Window | Notes |
|---|---|---|---|
| API request rate | ~10 requests/second | Per tenant, rolling | Excess requests dropped silently -- no 429 returned |
| Concurrent report executions | Not officially documented | Per tenant | Heavy concurrent RaaS loads degrade tenant performance |
| No daily API call cap | N/A | N/A | Workday does not publish a daily call limit for RaaS |

[src4, src6]

### Workday-Specific Constraints

| Limit Type | Value | Notes |
|---|---|---|
| Report type restriction | Advanced custom reports only | Standard and matrix reports cannot be web-service-enabled |
| Web service enablement | Must be explicitly enabled per report | Check "Enable As Web Service" in report definition |
| XML alias requirement | Required for all report fields | Defines JSON/XML keys in output; missing aliases cause empty fields |
| Prompt parameter filtering | URL query string (REST) or SOAP body | Prompts are the only mechanism for runtime data filtering |

[src1, src7]

## Authentication

| Flow | Use When | Credential Type | Refresh? | Notes |
|---|---|---|---|---|
| ISU + Basic Auth (REST) | Simple REST integrations | Username@tenant + password | N/A | Username format: `ISU_username@tenant_name` |
| ISU + WS-Security (SOAP) | SOAP-based integrations, Studio | UsernameToken in SOAP header | N/A | WS-Security OASIS standard; password in plaintext within SSL tunnel |
| OAuth 2.0 (REST) | Modern SaaS integrations | Client ID + Client Secret + tokens | Yes (refresh token) | Requires API client registration in Workday |

[src2, src4]

### Authentication Gotchas

- ISU username must include the tenant name in the format `username@tenant_id` -- omitting the tenant suffix causes "Customer ID not specified" errors. [src1]
- The ISU must be added to an Integration System Security Group (ISSG) with explicit domain permissions for every data source the report accesses. Missing a single domain causes "Access Denied" with no indication of which domain is missing. [src2]
- OAuth refresh tokens in Workday are non-expiring by default, but an admin can revoke them. Build token refresh logic regardless -- do not assume perpetual validity. [src4]
- Sandbox and production use different ISU credentials and different tenant endpoints. Hardcoding either will break promotion between environments. [src4]

## Constraints
<!-- Agents: read this section before recommending any integration approach from this unit.
     These are hard constraints that must not be violated. -->

- **30-minute timeout**: Workday terminates any RaaS report execution that exceeds 30 minutes. There is no way to extend this. The only workaround is to reduce the data volume per request through prompt-based filtering. [src1]
- **2 GB output cap**: The maximum response payload for any RaaS endpoint is 2 GB. Reports approaching this limit often timeout before reaching it due to memory pressure. [src2, src7]
- **No native pagination**: RaaS generates the entire result set in a single response. There is no page, offset, limit, or cursor parameter. For large datasets, you must implement pseudo-pagination using prompt parameters (date ranges, org filters) to chunk requests. [src1, src5]
- **~10 req/s tenant-wide throttle**: Workday drops requests exceeding approximately 10 per second across the entire tenant (not per integration). No HTTP 429 is returned -- requests are silently dropped. Build queuing and retry from day one. [src6]
- **REST URL length limit**: GET requests via REST are constrained to ~2,083 characters, limiting the number of prompt values you can pass. For large parameter sets, use SOAP instead. [src3]
- **Report must be Advanced type**: Only Advanced custom reports with "Enable As Web Service" checked are eligible for RaaS. Standard reports, matrix reports, and composite reports are not supported. [src1]
- **Memory pressure on tenant**: Large RaaS reports consume tenant memory. Running multiple large reports concurrently degrades performance for all users on the tenant. [src2]

## Integration Pattern Decision Tree

```
START -- User needs to extract data from Workday via reports
|-- How many rows does the report return?
|   |-- < 10,000 rows
|   |   |-- Simple filters? --> RaaS REST with JSON format
|   |   |-- Many filter values (>50)? --> RaaS SOAP (no URL length limit)
|   |   +-- Need incremental loads? --> RaaS REST + Effective_Date prompt
|   |-- 10,000-50,000 rows
|   |   |-- Can filter by date range? --> RaaS REST with date-range pseudo-pagination
|   |   |-- Need full snapshot? --> RaaS SOAP (single call, monitor for timeout)
|   |   +-- Approaching timeout? --> Split into org-based chunks via prompt parameters
|   |-- > 50,000 rows
|   |   |-- WQL available? --> Use WQL with native limit/offset pagination
|   |   |-- Must use reports? --> Mandatory pseudo-pagination (date + org chunking)
|   |   +-- > 200,000 rows? --> WQL pagination + parallel processing
|   +-- > 1,000,000 rows
|       +-- RaaS is NOT viable --> Use WQL with parallel paginated extraction
|-- What output format?
|   |-- JSON --> ?format=json (recommended for most integrations)
|   |-- CSV  --> ?format=csv  (best for data lake/warehouse loads)
|   |-- XML  --> ?format=simplexml (Workday XML) or default (full XML)
|   +-- RSS/GData --> Rarely used; available for specialized feeds
|-- SOAP vs REST?
|   |-- Few prompt values + JSON needed --> REST
|   |-- Many prompt values (>50 IDs) --> SOAP (parameters in body, no URL limit)
|   +-- Need multi-instance in single call --> SOAP (dramatically faster)
+-- Error tolerance?
    |-- Zero-loss required --> Implement retry with exponential backoff + dead letter queue
    +-- Best-effort --> Retry 3x with 30s delays, log failures
```

## Quick Reference

| Operation | Method | Endpoint Pattern | Format | Notes |
|---|---|---|---|---|
| Fetch report (REST/JSON) | GET | `/ccx/service/customreport2/{tenant}/{owner}/{Report_Name}?format=json` | JSON | Most common pattern |
| Fetch report (REST/CSV) | GET | `/ccx/service/customreport2/{tenant}/{owner}/{Report_Name}?format=csv` | CSV | Best for bulk loads |
| Fetch report (REST/XML) | GET | `/ccx/service/customreport2/{tenant}/{owner}/{Report_Name}` | XML | Default if no format specified |
| Fetch with prompts | GET | `.../{Report_Name}?format=json&{Prompt_Name}={value}` | JSON | Prompts filter at runtime |
| Fetch with WID filter | GET | `.../{Report_Name}?format=json&{Field}!WID={workday_id}` | JSON | Filter by Workday ID reference |
| Fetch via SOAP | POST | `/ccx/service/customreport2/{tenant}/{owner}/{Report_Name}` | XML | Parameters in SOAP body |
| WQL query (alternative) | POST | `/api/wql/v1/{tenant}/data?query={WQL}` | JSON | Native pagination via limit/offset |

[src1, src3, src7]

## Step-by-Step Integration Guide

### 1. Create and enable the custom report

Build an Advanced custom report in Workday with the required data sources, columns, and filters. Set XML aliases for every field (these become JSON keys). Enable "Web Service" in the report's Advanced tab. [src1]

**Verify**: Navigate to the report > Related Actions > Web Service > View URLs. You should see REST and SOAP endpoint URLs listed.

### 2. Configure ISU and security permissions

Create an Integration System User (ISU) and an Integration System Security Group (ISSG). Add the ISU to the ISSG. Grant the ISSG domain permissions (GET access) for every data source used by the report. Share the report with the ISSG. [src2]

**Verify**: Log in as the ISU and run the report in the Workday UI. If you see data, the ISU has correct permissions.

### 3. Authenticate and fetch via REST

Construct the RaaS REST URL and call it with Basic Auth. [src1, src7]

```bash
# Input:  ISU credentials, tenant name, report owner, report name
# Output: JSON report data

curl -u "ISU_User@tenant_name:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant_name/report_owner/Report_Name?format=json"
```

**Verify**: HTTP 200 with JSON body containing `Report_Entry` array. HTTP 401 = bad credentials. HTTP 403 = missing domain permissions.

### 4. Add prompt parameters for filtering

Pass prompt values as URL query parameters to filter the report at runtime. [src7]

```bash
# Input:  Report with Effective_Date and Worker_Type prompts configured
# Output: Filtered JSON report data

curl -u "ISU_User@tenant_name:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant_name/report_owner/Report_Name?format=json&Effective_Date=2026-01-01-08:00&Worker_Type!WID=d588c41a446c11de98360015c5e6daf6"
```

**Verify**: Response contains only records matching the filter criteria. Row count should be lower than unfiltered.

### 5. Implement pseudo-pagination for large datasets

Since RaaS lacks native pagination, chunk requests using date-range prompts. [src1, src5]

```python
# Input:  Date range, chunk size in days
# Output: All report data fetched in manageable chunks

import requests
from datetime import datetime, timedelta

BASE_URL = "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant/owner/Report"
AUTH = ("ISU_User@tenant", "password")

def fetch_raas_chunked(start_date, end_date, chunk_days=7):
    """Pseudo-pagination: fetch report in date-range chunks."""
    all_rows = []
    current = start_date
    while current < end_date:
        chunk_end = min(current + timedelta(days=chunk_days), end_date)
        params = {
            "format": "json",
            "Start_Date": current.strftime("%Y-%m-%d-08:00"),
            "End_Date": chunk_end.strftime("%Y-%m-%d-08:00"),
        }
        resp = requests.get(BASE_URL, auth=AUTH, params=params, timeout=1800)
        resp.raise_for_status()
        data = resp.json()
        rows = data.get("Report_Entry", [])
        all_rows.extend(rows)
        print(f"Fetched {len(rows)} rows for {current.date()} to {chunk_end.date()}")
        current = chunk_end
    return all_rows

# Usage
rows = fetch_raas_chunked(datetime(2026, 1, 1), datetime(2026, 3, 1), chunk_days=7)
print(f"Total rows fetched: {len(rows)}")
```

**Verify**: Total row count matches expected count from the full report run in the Workday UI.

### 6. Implement retry logic with throttle handling

Workday silently drops requests exceeding ~10/second. Build in delays and retries. [src6]

```python
# Input:  RaaS URL and auth credentials
# Output: Report data with automatic retry on failure

import time
import requests
from requests.exceptions import RequestException

def fetch_with_retry(url, auth, params, max_retries=5, base_delay=30):
    """Fetch RaaS report with exponential backoff retry."""
    for attempt in range(max_retries):
        try:
            resp = requests.get(url, auth=auth, params=params, timeout=1800)
            if resp.status_code == 200:
                return resp.json()
            elif resp.status_code in (500, 502, 503):
                delay = base_delay * (2 ** attempt)
                print(f"Server error {resp.status_code}, retry in {delay}s...")
                time.sleep(delay)
            else:
                resp.raise_for_status()
        except RequestException as e:
            delay = base_delay * (2 ** attempt)
            print(f"Request failed: {e}, retry in {delay}s...")
            time.sleep(delay)
    raise Exception(f"Failed after {max_retries} retries")
```

**Verify**: Function returns JSON data. Check logs for retry attempts.

## Code Examples

### Python: Fetch RaaS report with Basic Auth

```python
# Input:  ISU credentials, tenant, report details
# Output: Parsed JSON report data as list of dicts

import requests  # requests==2.31.0

WORKDAY_HOST = "https://wd2-impl-services1.workday.com"
TENANT = "your_tenant"
REPORT_OWNER = "ISU_Report_Owner"
REPORT_NAME = "Active_Workers_Report"
ISU_USER = f"ISU_User@{TENANT}"
ISU_PASS = "your_password"

url = f"{WORKDAY_HOST}/ccx/service/customreport2/{TENANT}/{REPORT_OWNER}/{REPORT_NAME}"
params = {"format": "json"}

response = requests.get(url, auth=(ISU_USER, ISU_PASS), params=params, timeout=1800)
response.raise_for_status()

data = response.json()
rows = data.get("Report_Entry", [])
print(f"Fetched {len(rows)} records")
```

### JavaScript/Node.js: Fetch RaaS report with Basic Auth

```javascript
// Input:  ISU credentials, tenant, report details
// Output: Parsed JSON report data

const axios = require("axios"); // axios@1.7.0

const WORKDAY_HOST = "https://wd2-impl-services1.workday.com";
const TENANT = "your_tenant";
const REPORT_OWNER = "ISU_Report_Owner";
const REPORT_NAME = "Active_Workers_Report";
const ISU_USER = `ISU_User@${TENANT}`;
const ISU_PASS = "your_password";

async function fetchRaaSReport(promptParams = {}) {
  const url = `${WORKDAY_HOST}/ccx/service/customreport2/${TENANT}/${REPORT_OWNER}/${REPORT_NAME}`;
  const params = { format: "json", ...promptParams };

  const response = await axios.get(url, {
    auth: { username: ISU_USER, password: ISU_PASS },
    params,
    timeout: 1800000, // 30 min to match Workday timeout
  });

  const rows = response.data.Report_Entry || [];
  console.log(`Fetched ${rows.length} records`);
  return rows;
}

// Usage with prompt parameters
fetchRaaSReport({ Effective_Date: "2026-01-01-08:00" });
```

### cURL: Quick RaaS test

```bash
# Input:  ISU credentials, tenant endpoint
# Output: JSON report data

# Fetch report as JSON
curl -u "ISU_User@tenant_name:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant_name/owner/Report_Name?format=json" \
  -o report_output.json

# Fetch report as CSV
curl -u "ISU_User@tenant_name:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant_name/owner/Report_Name?format=csv" \
  -o report_output.csv

# Fetch with prompt filter
curl -u "ISU_User@tenant_name:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant_name/owner/Report_Name?format=json&Hire_Date_From=2026-01-01-08:00&Hire_Date_To=2026-03-01-08:00"
```

## Data Mapping

### Field Mapping Reference

| RaaS Output Field | External System Target | Type | Transform | Gotcha |
|---|---|---|---|---|
| `Worker` (WID) | External employee ID | String (32 char) | Direct or lookup | WIDs are Workday-internal; use Employee_ID for external mapping |
| `Hire_Date` | Hire date | DateTime | Parse ISO 8601 with timezone offset | Format includes timezone: `2026-01-15-08:00` (not standard ISO) |
| `Worker_Type` (WID) | Employment type | Reference | Map WID to enum | Different tenants may have different WIDs for same type |
| `Annual_Rate` | Salary | Decimal | Convert currency if multi-currency tenant | Amount is in worker's local currency; no currency code in default output |
| `Supervisory_Organization` | Department/Org | Reference | Resolve WID to name via separate report | Nested reference -- requires joining to org hierarchy |
| `Email_Address` | Contact email | String | Filter by usage type (Work vs Personal) | Report may return multiple emails; filter by `Usage_Type` |

### Data Type Gotchas

- Workday dates include a timezone offset suffix (e.g., `2026-01-15-08:00`) that is not standard ISO 8601. Most JSON parsers will not handle this automatically -- strip or convert the offset before parsing. [src1]
- WID (Workday ID) references are opaque 32-character hex strings. They are stable within a tenant but not portable across tenants. Always map to business keys (Employee_ID, Cost_Center_Code) for external systems. [src2]
- Boolean fields in RaaS JSON output are returned as string `"1"` or `"0"`, not native JSON `true`/`false`. Validate your deserialization handles this. [src1]
- Multi-valued fields (e.g., multiple email addresses for one worker) are returned as nested arrays. A report with 10,000 workers each having 3 emails produces 30,000 email sub-records within 10,000 Report_Entry objects. [src7]
- Currency amounts do not include currency code by default. For multi-currency tenants, you must add the currency field to the report explicitly, or amounts become ambiguous. [src2]

## Error Handling & Failure Points

### Common Error Codes

| Code / Error | Meaning | Cause | Resolution |
|---|---|---|---|
| HTTP 401 Unauthorized | Authentication failure | Wrong ISU credentials or missing `@tenant` suffix | Verify username format: `ISU_User@tenant_name` |
| HTTP 403 Forbidden | Access denied | ISU lacks domain permissions for report data sources | Add ISSG to all required domain security policies |
| HTTP 404 Not Found | Report endpoint not found | Report not web-service-enabled or wrong URL path | Verify "Enable As Web Service" is checked; confirm URL from report's Web Service menu |
| HTTP 500 Internal Server Error | Server-side failure | Report timed out, memory exceeded, or malformed prompt value | Reduce data volume via filters; check prompt value format |
| SOAP Fault: `validationError` | Invalid SOAP request | Malformed XML, missing required elements | Validate SOAP envelope structure against WSDL |
| SOAP Fault: `Customer id was not specified` | Missing tenant in credentials | Username missing `@tenant_name` suffix | Format username as `ISU_User@tenant_name` |
| Empty `Report_Entry` array | No data returned | Prompts filtering out all records, or ISU cannot see data | Test in Workday UI as ISU; verify prompt values match data |
| Connection timeout (no response) | Report exceeds 30-minute limit | Dataset too large for single RaaS call | Implement pseudo-pagination with smaller date-range chunks |

[src1, src3]

### Failure Points in Production

- **Silent request drops at rate limit**: Workday drops requests exceeding ~10/second with no HTTP error response. The integration sees a connection timeout or empty response, making it indistinguishable from a network error. Fix: `Implement a request queue with max 8 req/s throughput and exponential backoff retry on any timeout`. [src6]
- **30-minute timeout on growing datasets**: A report that completes in 25 minutes today will timeout in 6 months as data grows. Fix: `Implement date-range pseudo-pagination from day one, even for small datasets. Set chunk size to keep each request under 15 minutes for safety margin`. [src1]
- **Missing XML aliases cause silent data loss**: If a report field lacks an XML alias, it appears in Workday UI results but is silently omitted from the RaaS JSON/XML output. Fix: `Audit every report field for XML alias assignment before going live`. [src7]
- **ISU password expiration breaks unattended integrations**: Workday can enforce password rotation policies on ISU accounts. If the password expires, all RaaS calls return 401. Fix: `Set ISU accounts to non-expiring passwords, or implement automated credential rotation with alerting`. [src4]
- **Tenant-specific WID values break multi-tenant deployments**: WID references for the same business object (e.g., Worker_Type = "Regular") differ between sandbox and production tenants. Fix: `Map by business key (name or code), not by WID. Or maintain a WID mapping table per environment`. [src2]
- **Multi-currency amounts without currency codes**: Reports returning monetary amounts without explicit currency fields lead to silent data corruption when loaded into external systems assuming a single currency. Fix: `Always include the currency reference field alongside any amount field in the report definition`. [src2]

## Anti-Patterns

### Wrong: Fetching entire dataset without filters

```python
# BAD -- fetches all workers in one call; will timeout for orgs with >50K workers
response = requests.get(
    f"{BASE_URL}?format=json",
    auth=AUTH,
    timeout=1800
)
all_workers = response.json()["Report_Entry"]
```

### Correct: Pseudo-paginate with date-range chunking

```python
# GOOD -- fetches in weekly chunks; each chunk stays well under timeout
from datetime import datetime, timedelta

all_workers = []
current = datetime(2026, 1, 1)
end = datetime(2026, 3, 1)
while current < end:
    chunk_end = min(current + timedelta(days=7), end)
    params = {
        "format": "json",
        "Hire_Date_From": current.strftime("%Y-%m-%d-08:00"),
        "Hire_Date_To": chunk_end.strftime("%Y-%m-%d-08:00"),
    }
    resp = requests.get(BASE_URL, auth=AUTH, params=params, timeout=1800)
    all_workers.extend(resp.json().get("Report_Entry", []))
    current = chunk_end
```

### Wrong: Looping REST calls for each worker

```python
# BAD -- one REST call per worker burns through rate limit in seconds
for worker_id in worker_ids:  # 5,000 IDs
    resp = requests.get(f"{BASE_URL}?format=json&Worker!WID={worker_id}", auth=AUTH)
    results.append(resp.json())
# At ~10 req/s limit, this takes 8+ minutes and may get silently throttled
```

### Correct: Single SOAP call with all worker IDs in body

```python
# GOOD -- one SOAP call passes all IDs in the request body (no URL length limit)
# Run time drops from hours to minutes [src3]
import requests

soap_body = f"""<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken>
        <wsse:Username>ISU_User@tenant</wsse:Username>
        <wsse:Password>password</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <bsvc:Execute_Report xmlns:bsvc="urn:com.workday.report/Report_Name">
      {''.join(f'<bsvc:Worker>{wid}</bsvc:Worker>' for wid in worker_ids)}
    </bsvc:Execute_Report>
  </soapenv:Body>
</soapenv:Envelope>"""

resp = requests.post(SOAP_URL, data=soap_body, headers={"Content-Type": "text/xml"})
```

### Wrong: No rate limiting or retry logic

```python
# BAD -- blasts requests with no throttling; Workday drops silently
for chunk in date_chunks:
    resp = requests.get(f"{BASE_URL}?format=json&Date={chunk}", auth=AUTH)
    results.append(resp.json())
```

### Correct: Rate-limited requests with retry

```python
# GOOD -- respects ~10 req/s limit with built-in retry
import time

for i, chunk in enumerate(date_chunks):
    if i > 0 and i % 8 == 0:
        time.sleep(1.5)  # Stay well under 10 req/s
    resp = fetch_with_retry(BASE_URL, AUTH, {"format": "json", "Date": chunk})
    results.append(resp)
```

## Common Pitfalls

- **Assuming RaaS supports pagination**: The most expensive mistake. Teams build integrations assuming they can paginate, then discover in production that a single call must return all data. Fix: `Design for pseudo-pagination from the start using prompt parameters (date ranges, org units) to chunk data`. [src1, src5]
- **Ignoring the 30-minute timeout during development**: Reports run fast in sandbox (small data) but timeout in production (full data). Fix: `Test with production-volume data in a full sandbox. Set chunk sizes to target <15 minutes per call for growth margin`. [src1]
- **Hardcoding WIDs across environments**: Sandbox and production tenants have different WIDs for the same objects. Fix: `Map by business key (Employee_ID, Cost_Center_Code), never by WID`. [src2]
- **Not setting XML aliases on report fields**: Fields without XML aliases are silently dropped from RaaS output. The report looks correct in the Workday UI but returns incomplete data via API. Fix: `Set XML aliases for every field in the report definition. Use consistent naming conventions`. [src7]
- **Using REST when SOAP would be dramatically faster**: One client reduced run time from 1+ hour to 7 minutes by switching from looped REST calls to a single multi-instance SOAP call. Fix: `If you need to pass >50 parameter values, always use SOAP`. [src3]
- **Running concurrent large reports**: Multiple large RaaS reports running simultaneously compete for tenant memory and CPU, causing cascading timeouts. Fix: `Serialize large report executions. Use a job queue that runs one large report at a time`. [src6]
- **Omitting currency codes in multi-currency tenants**: Monetary fields return raw numbers without currency indicators. Fix: `Always add the currency reference field alongside any amount field in the report`. [src2]

## Diagnostic Commands

```bash
# Test RaaS authentication (expect 200 with data, 401 = bad creds, 403 = no access)
curl -s -o /dev/null -w "%{http_code}" \
  -u "ISU_User@tenant:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant/owner/Report?format=json"

# Fetch report and check row count
curl -s -u "ISU_User@tenant:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant/owner/Report?format=json" \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Rows: {len(d.get(\"Report_Entry\",[]))}')"

# Test with specific prompt parameters
curl -s -u "ISU_User@tenant:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant/owner/Report?format=json&Effective_Date=2026-01-01-08:00" \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('Report_Entry',[])[0], indent=2))"

# Measure report execution time (watch for >15 min = at risk of timeout)
time curl -s -u "ISU_User@tenant:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant/owner/Report?format=json" \
  -o /dev/null

# Verify output size (watch for approaching 2GB)
curl -s -u "ISU_User@tenant:password" \
  "https://wd2-impl-services1.workday.com/ccx/service/customreport2/tenant/owner/Report?format=csv" \
  -o report.csv && ls -lh report.csv
```

## Version History & Compatibility

| API Version | Release Date | Status | Breaking Changes | Migration Notes |
|---|---|---|---|---|
| v45.0 | 2025-09 | Current | None | Latest recommended version |
| v43.0 | 2025-03 | Supported | Minor schema changes | Still fully functional for RaaS |
| v40.0 | 2024-03 | Supported | None for RaaS | WQL introduced as alternative |
| v38.0 | 2023-09 | Supported | None for RaaS | Minimum version for OAuth 2.0 |
| v35.0 | 2022-09 | End of Life | N/A | Upgrade to v38.0+ |

[src4]

### Deprecation Policy

Workday follows a release-based versioning model (two major releases per year). API versions are supported for approximately 3 years. RaaS endpoint URLs include the API version implicitly through the tenant configuration. Workday does not force-migrate RaaS endpoints, but underlying report behavior may change with platform updates. Always test after each Workday release update. [src4]

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Scheduled batch extraction of report data (<50K rows per run) | Dataset exceeds 50K rows and cannot be chunked by prompts | WQL with native limit/offset pagination |
| Leveraging existing Workday custom reports | Need to create/update/delete records in Workday | Workday SOAP Web Services or REST API |
| Simple outbound data feeds (HR, payroll, finance) | Need real-time event-driven notifications | Workday Business Process Events |
| Integration with ETL tools that have RaaS connectors (Workato, Fivetran, SnapLogic) | Need complex joins or aggregations at query time | WQL (supports SQL-like queries) |
| Prompt-based filtered extractions with runtime parameters | Need full-text search across Workday data | Workday Search API |
| Quick ad-hoc data pulls during development/testing | Production workload exceeding 10 req/s sustained | Batch via WQL with parallel workers |

## Important Caveats

- RaaS limits (timeout, output size, rate) are tenant-wide and not configurable by customers. Workday does not offer enterprise tier overrides for these limits.
- The ~10 req/s rate limit is tenant-wide, not per-integration. If multiple integrations share a tenant, they share this budget. Coordinate with other integration teams.
- Sandbox environments may have different data volumes than production, causing reports that work in sandbox to timeout in production. Always test with production-equivalent data volumes.
- Workday releases twice per year (March and September). Each release may change report behavior, field availability, or security model. Regression test all RaaS integrations after each release.
- RaaS is read-only. It cannot write data back to Workday. Any integration requiring bidirectional sync needs RaaS + SOAP Web Services (or REST API) in combination.
- The 2 GB output limit and 30-minute timeout interact: a report generating 1.8 GB of output may timeout at 28 minutes, long before hitting the 2 GB cap. Memory pressure is the practical bottleneck, not the stated limits.

## Related Units
<!-- Generated from related_kos frontmatter -->

- No directly related units published yet. Check back for Workday SOAP API, WQL, and Business Events cards.
