---
# === IDENTITY ===
id: business/erp-integration/oracle-erp-cloud-rest-api-capabilities/2026
canonical_question: "What are Oracle ERP Cloud (Fusion) REST API capabilities - 499-record pagination, expand vs fields?"
aliases:
  - "Oracle Fusion Cloud REST API limits and pagination"
  - "Oracle ERP Cloud API capabilities and rate limits"
  - "How to paginate Oracle Fusion REST API beyond 499 records"
  - "Oracle Cloud Applications REST API expand vs fields parameter"
entity_type: erp_integration
domain: business > erp-integration > Oracle ERP Cloud REST API Capabilities
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === SYSTEM PROFILE ===
systems:
  - name: "Oracle ERP Cloud (Fusion)"
    vendor: "Oracle"
    version: "24B"
    edition: "All editions (Enterprise, Standard)"
    deployment: "cloud"
    api_surface: "REST"

# === VERIFICATION ===
last_verified: 2026-03-01
confidence: 0.92
version: 1.0
first_published: 2026-03-01

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: volatile
  last_breaking_change: "REST Framework v3 (2022) — expand returns collection resources with pagination"
  next_review: 2026-08-28
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "Maximum 500 records per REST request (practical limit 499 due to < 500 behavior)"
  - "Default page size is 25 records if limit parameter not specified"
  - "Maximum 1 MB payload size per REST request"
  - "Bulk API limited to 50 operations per batch call"
  - "Rate limits are tiered by identity domain type: Free (150/min), Oracle Apps (1,500/min), Premium (5,000/min)"
  - "REST API not recommended for bulk data operations exceeding 500 records — use FBDI instead"
  - "Server may override client-specified limit parameter to protect application performance"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs bulk data import/export of >500 records at a time"
    use_instead: "Use FBDI (File-Based Data Import) or BI Publisher reports for bulk operations"
  - condition: "User needs SOAP API capabilities for Oracle ERP Cloud"
    use_instead: "Oracle ERP Cloud SOAP API documentation"
  - condition: "User needs Oracle Integration Cloud (OIC) adapter capabilities"
    use_instead: "Oracle Integration Cloud ERP adapter documentation"

# === AGENT HINTS ===
inputs_needed:
  - key: integration_pattern
    question: "What integration pattern do you need?"
    type: choice
    options:
      - "real-time sync (individual records, <1s latency)"
      - "batch/bulk (scheduled, high volume)"
      - "event-driven (webhook, CDC, platform events)"
      - "file-based (CSV/XML import/export)"
  - key: data_volume
    question: "What's your daily data volume?"
    type: choice
    options:
      - "< 1,000 records/day"
      - "1,000-100,000 records/day"
      - "> 100,000 records/day"
  - key: direction
    question: "What's the data flow direction?"
    type: choice
    options:
      - "inbound (writing to this ERP)"
      - "outbound (reading from this ERP)"
      - "bidirectional sync"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/business/erp-integration/oracle-erp-cloud-rest-api-capabilities/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-03-01)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to: []
  solves: []
  alternative_to: []
  often_confused_with: []

# === SOURCES (7 authoritative sources) ===
sources:
  - id: src1
    title: "REST API for Common Features in Oracle Fusion Cloud Applications"
    author: Oracle
    url: https://docs.oracle.com/en/cloud/saas/applications-common/24d/farca/Resource_Methods.html
    type: official_docs
    published: 2026-01-15
    reliability: authoritative
  - id: src2
    title: "Oracle Fusion API Essentials — Rate Limits and Capabilities"
    author: Rollout
    url: https://rollout.com/integration-guides/oracle-fusion/api-essentials
    type: technical_blog
    published: 2025-06-15
    reliability: moderate_high
  - id: src3
    title: "Max Supported Value for Limit Parameter in GET REST API Call"
    author: Oracle Support
    url: https://support.oracle.com/knowledge/Oracle%20Fusion%20Applications/2429019_1.html
    type: official_docs
    published: 2024-03-01
    reliability: authoritative
  - id: src4
    title: "How to Extract Large Data from Oracle Fusion Using REST APIs in OIC"
    author: Soalicious
    url: https://soalicious.blogspot.com/2024/06/oic-how-to-extract-large-data-from.html
    type: technical_blog
    published: 2024-06-15
    reliability: moderate_high
  - id: src5
    title: "Oracle Fusion Cloud ERP Integration Patterns with Oracle PaaS"
    author: Oracle A-Team
    url: https://www.ateam-oracle.com/oracle-fusion-cloud-erp-applications-integrations-guidelines-patternsuse-cases-using-oracle-paas
    type: technical_blog
    published: 2024-09-01
    reliability: high
  - id: src6
    title: "Configure OAuth Using the Fusion Applications Identity Domain"
    author: Oracle
    url: https://docs.oracle.com/en/cloud/saas/applications-common/24c/oaext/configure-oauth.html
    type: official_docs
    published: 2025-01-15
    reliability: authoritative
  - id: src7
    title: "REST API for Oracle Fusion Cloud Financials — All REST Endpoints"
    author: Oracle
    url: https://docs.oracle.com/en/cloud/saas/financials/24c/farfa/rest-endpoints.html
    type: official_docs
    published: 2025-06-01
    reliability: authoritative
---

# Oracle ERP Cloud (Fusion) REST API Capabilities

## TL;DR

- **Bottom line**: Oracle Fusion Cloud REST APIs support full CRUD on hundreds of ERP resources with JSON payloads, but are limited to 499 records per request and best suited for real-time, low-volume integrations — use FBDI for bulk operations. [src1]
- **Key limit**: Maximum 500 records per request (practical limit 499), default page size 25, 1 MB payload maximum, rate limits tiered by identity domain (150-5,000 requests/min). [src2, src3]
- **Watch out for**: The `limit` parameter caps at 500 but server can silently override it downward; always check `hasMore` attribute and implement pagination loops. [src3, src4]
- **Best for**: Real-time individual record CRUD operations, small-batch reads (<500 records), and metadata/describe queries on Oracle Fusion Cloud ERP modules. [src5]
- **Authentication**: OAuth 2.0 via OCI IAM (JWT bearer for server-to-server); basic auth supported but not recommended for production. [src6]

## System Profile

Oracle ERP Cloud (Fusion) is Oracle's cloud-native ERP suite covering Financials, Procurement, Project Management, and Supply Chain. The REST API surface uses the Oracle Fusion Applications REST framework, which has evolved through multiple versions (most recently Framework v3, introducing collection-based pagination for expanded child resources). This card covers the REST API specifically — SOAP services, FBDI, BI Publisher, and the Oracle Integration Cloud (OIC) adapter are separate integration surfaces with different capabilities and constraints.

All Oracle Fusion Cloud editions share the same REST API framework. Rate limits depend on the OCI Identity and Access Management (IAM) domain type, not the Fusion Cloud edition.

| Property | Value |
|---|---|
| **Vendor** | Oracle |
| **System** | Oracle ERP Cloud (Fusion) 24B |
| **API Surface** | REST (HTTPS/JSON) |
| **Current Framework Version** | REST Framework v3+ |
| **Editions Covered** | All (Enterprise, Standard) |
| **Deployment** | Cloud |
| **API Docs URL** | [Oracle Fusion Cloud REST API](https://docs.oracle.com/en/cloud/saas/applications-common/24d/farca/Resource_Methods.html) |
| **Status** | GA |

## API Surfaces & Capabilities

Oracle Fusion Cloud offers multiple integration surfaces. The REST API is one of several; choosing the right surface depends on data volume, latency requirements, and integration pattern. [src5]

| API Surface | Protocol | Best For | Max Records/Request | Rate Limit | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| REST API | HTTPS/JSON | Individual record CRUD, queries <500 records | 500 (practical 499) | Tiered: 150-5,000/min | Yes | No |
| SOAP Web Services | HTTPS/XML | Legacy integrations, some metadata ops | Varies by service | Shared with REST | Yes | No |
| FBDI (File-Based Data Import) | CSV via UCM | Bulk data import >500 records, data migration | 100K rows/file (10 MB) | N/A (async) | No | Yes |
| BI Publisher Reports | HTTPS/XML | Bulk data export, scheduled reporting | No hard limit | N/A (async) | No | Yes |
| Business Events | Oracle AQ/JMS | Event-driven integration, CDC | N/A | N/A | Yes | N/A |
| OIC ERP Cloud Adapter | Pre-built connector | Orchestrated multi-step integrations | Depends on pattern | OIC-managed | Both | Both |

## Rate Limits & Quotas

### Per-Request Limits

| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Max records per GET | 500 (practical 499) | REST API collection queries | Default 25 if `limit` not specified; server may override downward [src3] |
| Max request body size | 1 MB | REST API POST/PATCH/PUT | Applies to request payload [src2] |
| Max batch operations | 50 | Bulk API (batch endpoint) | Operations per single batch call [src2] |
| CSV import max rows | 100,000 | FBDI file uploads | Per file, max 10 MB file size [src2] |
| CSV export max rows | 100,000 | BI Publisher/export | Per export operation [src2] |

### Rolling / Daily Limits

Rate limits in Oracle Fusion Cloud are managed at the OCI IAM identity domain level, not at the Fusion application level. The following are per-minute limits by domain tier. [src2]

| Limit Type | Free Tier | Oracle Apps Tier | Premium Tier | Window |
|---|---|---|---|---|
| Authentication requests | 150/min | 1,000/min | 4,500/min | Per minute |
| Token management | 150/min | 1,000/min | 3,400/min | Per minute |
| Other API calls | 150/min | 1,500/min | 5,000/min | Per minute |
| Bulk API operations | 200/min | 200/min | 200/min | Per minute |

When rate limits are exceeded, the API returns HTTP 429 (Too Many Requests) with a `retry-after` response header indicating when the request can be retried. [src2]

## Authentication

Oracle Fusion Cloud REST APIs support multiple authentication methods, with OAuth 2.0 being the recommended approach for production integrations. [src6]

| Flow | Use When | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| OAuth 2.0 JWT Bearer | Server-to-server, unattended integrations | Configurable (default ~1h) | New JWT per request | Recommended for production [src6] |
| OAuth 2.0 3-Legged | User-context operations, interactive apps | Access: ~1h, Refresh: until revoked | Yes | Requires callback URL and user consent [src6] |
| Basic Auth (username/password) | Development, testing, quick prototyping | Session-based | N/A | Not recommended for production — no MFA support [src6] |

### Authentication Gotchas

- OAuth requires configuring a Confidential Application in the OCI IAM domain linked to your Fusion instance — this is separate from creating an integration user in Fusion [src6]
- JWT bearer flow requires a digital certificate (self-signed works for dev; use CA-signed for production). The certificate must be uploaded to the OCI IAM Confidential Application [src6]
- Basic auth credentials are the integration user's Fusion username and password — if the admin changes the user's password or enforces MFA, the integration breaks silently [src6]
- Access tokens are scoped to the integration user's Fusion security roles — the REST API enforces the same row-level security as the Fusion UI [src1]

## Constraints

<!-- Agents: read this section before recommending any integration approach from this unit.
     These are hard constraints that must not be violated. -->

- **499-record ceiling**: REST GET requests return at most 499 records per page (the `limit` parameter accepts up to 500 but the response is capped at <500). You must implement pagination loops using `offset` and `hasMore`. [src3, src4]
- **Server override on limit**: Even if you set `limit=500`, the server may return fewer records to protect application performance. Always check `hasMore` rather than counting returned records. [src3]
- **1 MB payload limit**: POST/PATCH request bodies cannot exceed 1 MB. For larger payloads, split into multiple requests or use FBDI. [src2]
- **No streaming/CDC via REST**: REST API is request-response only. For event-driven patterns, use Business Events or the OIC ERP Cloud Adapter. [src5]
- **FBDI mandatory for bulk**: REST API is explicitly not recommended for data volumes >500 records per operation. Oracle's integration guidelines direct bulk operations to FBDI. [src5]
- **Rate limits are per identity domain, not per user**: All integrations sharing the same OCI IAM domain share the same rate limit pool. Multiple integration apps can exhaust each other's quotas. [src2]
- **No partial-success on batch**: Batch operations via the REST batch endpoint are all-or-nothing — if one operation fails, the entire batch may roll back depending on the resource implementation. [src1]

## Integration Pattern Decision Tree

```
START - User needs to integrate with Oracle ERP Cloud (Fusion) via REST API
|-- What's the integration pattern?
|   |-- Real-time (individual records, <1s)
|   |   |-- Data volume < 500 records/operation?
|   |   |   |-- YES -> REST API: use standard CRUD endpoints
|   |   |   |   |-- Multi-object in single call? -> Use batch endpoint (max 50 ops)
|   |   |   |   +-- Single object -> Standard POST/PATCH/GET/DELETE
|   |   |   +-- NO -> NOT suitable for REST API
|   |   |       +-- Use FBDI for bulk import, BI Publisher for bulk export
|   |   +-- Need response shaping?
|   |       |-- Fewer fields -> Use `fields` parameter (reduces payload)
|   |       |-- Child resources -> Use `expand` parameter (avoids N+1)
|   |       +-- No links needed -> Use `onlyData=true` (smaller payload)
|   |-- Batch/Bulk (scheduled, high volume)
|   |   |-- Data volume < 500 records?
|   |   |   |-- YES -> REST API with pagination loop is acceptable
|   |   |   +-- NO -> FBDI for import, BI Publisher reports for export
|   |   +-- Need full data migration?
|   |       +-- Use FBDI + ESS jobs (not REST API)
|   |-- Event-driven (webhook, CDC)
|   |   +-- REST API does NOT support events
|   |       |-- Use Business Events for ERP-originated events
|   |       +-- Use OIC ERP Cloud Adapter for orchestrated event handling
|   +-- File-based (CSV/XML)
|       +-- Use FBDI (REST API is for record-level, not file-level operations)
|-- Which direction?
|   |-- Inbound (writing to Fusion) -> POST/PATCH; check payload size < 1 MB
|   |-- Outbound (reading from Fusion) -> GET with pagination; use finder for indexed queries
|   +-- Bidirectional -> Design conflict resolution; use LastUpdateDate for optimistic locking
+-- Error tolerance?
    |-- Zero-loss required -> Implement idempotency (check before create), retry with backoff on 429
    +-- Best-effort -> Fire-and-forget with basic 429 retry
```

## Quick Reference

### Key Query Parameters

| Parameter | Purpose | Example | Notes |
|---|---|---|---|
| `limit` | Max records per page | `?limit=499` | Default 25, max 500 (practical 499). Server can override. [src1, src3] |
| `offset` | Pagination start index | `?offset=499` | 0-indexed. offset=0 returns from first item. [src1] |
| `fields` | Select specific fields | `?fields=InvoiceId,InvoiceNumber` | Reduces payload size; comma-separated field names. [src1] |
| `expand` | Include child resources | `?expand=invoiceLines` | Comma-separated child names, or `expand=all`. Framework v3+: returns as paginated collection. [src1] |
| `onlyData` | Omit HATEOAS links | `?onlyData=true` | Default false. Cannot combine with `links` parameter. Significantly reduces response size. [src1] |
| `finder` | Named predefined query | `?finder=PrimaryKey;InvoiceId=12345` | Uses predefined WHERE clause with bind variables. Faster than `q` for indexed lookups. [src1] |
| `q` | Ad-hoc filter/query | `?q=InvoiceNumber='INV-001'` | SCIM-style filter syntax. Supports =, !=, co, sw, gt, lt, ge, le. [src1] |
| `orderBy` | Sort results | `?orderBy=CreationDate:desc` | Ascending default. Use `:asc` or `:desc` suffix. [src1] |
| `totalResults` | Include total count | `?totalResults=true` | Adds `totalResults` field to response. Performance cost — avoid for large collections. [src1] |
| `links` | Control link relations | `?links=self,canonical` | Specify which links to include. Mutually exclusive with `onlyData=true`. [src1] |

### REST API Base URL Structure

```
https://{pod}.fa.{datacenter}.oraclecloud.com/fscmRestApi/resources/{version}/{resource}
```

Example: `https://abcd-test.fa.us2.oraclecloud.com/fscmRestApi/resources/v1/invoices` [src1, src7]

### Common Financial REST Endpoints

| Operation | Method | Endpoint | Payload | Notes |
|---|---|---|---|---|
| List invoices | GET | `/fscmRestApi/resources/v1/invoices` | N/A | Paginated; use `limit` and `offset` [src7] |
| Get invoice by ID | GET | `/fscmRestApi/resources/v1/invoices/{InvoiceId}` | N/A | Returns single resource with child links [src7] |
| Create invoice | POST | `/fscmRestApi/resources/v1/invoices` | JSON | Provide required fields per describe endpoint [src7] |
| Update invoice | PATCH | `/fscmRestApi/resources/v1/invoices/{InvoiceId}` | JSON | Partial update — only include changed fields [src7] |
| Delete invoice | DELETE | `/fscmRestApi/resources/v1/invoices/{InvoiceId}` | N/A | Not supported on all resources [src7] |
| Describe resource | GET | `/fscmRestApi/resources/v1/invoices/describe` | N/A | Returns metadata: fields, types, children, actions [src1] |
| Execute action | POST | `/fscmRestApi/resources/v1/invoices/{id}` | JSON (action payload) | Custom actions defined per resource [src1] |
| Access child | GET | `/fscmRestApi/resources/v1/invoices/{id}/invoiceLines` | N/A | Navigate parent-child relationships [src7] |

## Step-by-Step Integration Guide

### 1. Authenticate with OAuth 2.0 JWT Bearer

Obtain an access token from the OCI IAM domain linked to your Fusion instance. You need: (a) a Confidential Application configured in OCI IAM, (b) a client ID and secret, (c) the Fusion instance scope. [src6]

```bash
# Step 1: Request OAuth token from OCI IAM
curl -X POST "https://idcs-{tenant}.identity.oraclecloud.com/oauth2/v1/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -u "{client_id}:{client_secret}" \
  -d "grant_type=client_credentials&scope=https://{pod}.fa.{dc}.oraclecloud.com:443urn:opc:resource:consumer::all"
```

**Verify**: Response contains `access_token` field with JWT string and `expires_in` value (typically 3600 seconds).

### 2. Query a resource collection with pagination

Fetch all invoices using pagination. The response includes `hasMore` (boolean) and `count` (records in current page). Loop until `hasMore` is false. [src1, src4]

```bash
# First page: 499 records starting from offset 0
curl -X GET "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=499&offset=0&onlyData=true&fields=InvoiceId,InvoiceNumber,InvoiceAmount,InvoiceDate" \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json"
```

**Verify**: Response JSON contains `items` array, `hasMore` boolean, and `count` integer. If `hasMore` is true, increment `offset` by the number of returned records.

### 3. Handle pagination loop for large datasets

When the dataset exceeds 499 records, implement an offset-based loop. [src4]

```python
# Input:  Valid OAuth token, base_url, resource path
# Output: All records across multiple pages

import requests

def fetch_all_records(base_url, resource, token, fields=None):
    """Paginate through Oracle Fusion REST API results."""
    all_items = []
    offset = 0
    limit = 499  # Practical maximum
    has_more = True

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    }

    while has_more:
        params = {
            "limit": limit,
            "offset": offset,
            "onlyData": "true"
        }
        if fields:
            params["fields"] = ",".join(fields)

        resp = requests.get(
            f"{base_url}/fscmRestApi/resources/v1/{resource}",
            headers=headers,
            params=params
        )
        resp.raise_for_status()
        data = resp.json()

        items = data.get("items", [])
        all_items.extend(items)
        has_more = data.get("hasMore", False)
        offset += len(items)

        print(f"Fetched {len(items)} records (total: {len(all_items)}, hasMore: {has_more})")

    return all_items
```

**Verify**: `len(all_items)` matches the expected total count (compare with `totalResults` if enabled).

### 4. Use expand vs fields for response shaping

The `expand` parameter includes child resources inline (avoids N+1 queries). The `fields` parameter limits which fields are returned (reduces payload). Combine both for optimal performance. [src1]

```bash
# Expand invoice lines as child collection, but only fetch specific fields
curl -X GET "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/{InvoiceId}?expand=invoiceLines&fields=InvoiceId,InvoiceNumber,InvoiceAmount;invoiceLines:LineNumber,LineAmount,Description&onlyData=true" \
  -H "Authorization: Bearer {access_token}"
```

**Verify**: Response includes `invoiceLines` as nested collection with only the specified fields. No HATEOAS links present (due to `onlyData=true`).

### 5. Create a record with POST

Create a new resource by POSTing a JSON payload. Use the `describe` endpoint first to discover required fields. [src1, src7]

```bash
# Discover required fields
curl -X GET "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/describe" \
  -H "Authorization: Bearer {access_token}"

# Create a new invoice
curl -X POST "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices" \
  -H "Authorization: Bearer {access_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "InvoiceNumber": "INV-2026-001",
    "InvoiceCurrency": "USD",
    "InvoiceAmount": 1500.00,
    "InvoiceDate": "2026-03-01",
    "BusinessUnit": "US1 Business Unit",
    "Supplier": "Acme Corp"
  }'
```

**Verify**: HTTP 201 response with the created resource, including system-generated `InvoiceId`.

### 6. Implement error handling with exponential backoff

Handle rate limiting (429) and transient failures with exponential backoff. [src2]

```python
# Input:  Request function and parameters
# Output: Successful response or raise after max retries

import time
import requests

def resilient_request(method, url, headers, max_retries=5, **kwargs):
    """Execute REST API request with exponential backoff on 429."""
    for attempt in range(max_retries):
        resp = requests.request(method, url, headers=headers, **kwargs)

        if resp.status_code == 429:
            retry_after = int(resp.headers.get("Retry-After", 2 ** attempt))
            wait = min(retry_after, 60)  # Cap at 60 seconds
            print(f"Rate limited (429). Retrying in {wait}s (attempt {attempt + 1}/{max_retries})")
            time.sleep(wait)
            continue

        if resp.status_code >= 500:
            wait = 2 ** attempt
            print(f"Server error ({resp.status_code}). Retrying in {wait}s")
            time.sleep(wait)
            continue

        resp.raise_for_status()
        return resp

    raise Exception(f"Max retries ({max_retries}) exceeded for {url}")
```

**Verify**: On 429, function waits and retries; on 5xx, uses exponential backoff; on 4xx (other than 429), raises immediately.

## Code Examples

### Python: Fetch All Suppliers with Pagination and Field Selection

```python
# Input:  OAuth token, Fusion base URL
# Output: List of all supplier dicts with selected fields

import requests

BASE_URL = "https://{pod}.fa.{dc}.oraclecloud.com"
TOKEN = "{your_oauth_token}"

headers = {
    "Authorization": f"Bearer {TOKEN}",
    "Content-Type": "application/json"
}

all_suppliers = []
offset = 0
has_more = True

while has_more:
    resp = requests.get(
        f"{BASE_URL}/fscmRestApi/resources/v1/suppliers",
        headers=headers,
        params={
            "limit": 499,
            "offset": offset,
            "onlyData": "true",
            "fields": "SupplierId,Supplier,SupplierNumber,Status"
        }
    )
    resp.raise_for_status()
    data = resp.json()
    items = data.get("items", [])
    all_suppliers.extend(items)
    has_more = data.get("hasMore", False)
    offset += len(items)

print(f"Total suppliers: {len(all_suppliers)}")
```

### JavaScript/Node.js: Query with Finder Parameter

```javascript
// Input:  OAuth token, invoice number to look up
// Output: Invoice object matching the finder query

const fetch = require("node-fetch"); // v3.x

const BASE_URL = "https://{pod}.fa.{dc}.oraclecloud.com";
const TOKEN = "{your_oauth_token}";

async function findInvoiceByNumber(invoiceNumber) {
  const url = new URL(`${BASE_URL}/fscmRestApi/resources/v1/invoices`);
  url.searchParams.set("finder", `PrimaryKey;InvoiceNumber=${invoiceNumber}`);
  url.searchParams.set("onlyData", "true");

  const resp = await fetch(url.toString(), {
    headers: {
      Authorization: `Bearer ${TOKEN}`,
      "Content-Type": "application/json",
    },
  });

  if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${await resp.text()}`);

  const data = await resp.json();
  return data.items?.[0] || null;
}

// Usage
findInvoiceByNumber("INV-2026-001").then(console.log).catch(console.error);
```

### cURL: Quick API Tests

```bash
# Input:  Valid OAuth token, Fusion instance URL
# Output: API responses for common operations

# Test authentication — list first 5 invoices
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=5&onlyData=true" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# Describe a resource — see all available fields and children
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/describe" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# Filter with q parameter — invoices created after a date
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?q=CreationDate%20gt%20%272026-01-01%27&limit=10&onlyData=true" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# PATCH update — change invoice description
curl -X PATCH "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/{InvoiceId}" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"Description": "Updated via REST API"}'
```

## Data Mapping

### REST API Response Structure

| Response Field | Type | Description | Present When |
|---|---|---|---|
| `items` | Array | Array of resource objects | Collection GET |
| `count` | Integer | Number of records in current page | Collection GET |
| `hasMore` | Boolean | Whether more pages exist | Collection GET |
| `totalResults` | Integer | Total matching records | Only with `totalResults=true` |
| `links` | Array | HATEOAS navigation links | When `onlyData` is false (default) |

### Data Type Gotchas

- Oracle Fusion REST API dates use ISO 8601 format (`YYYY-MM-DD`) but datetime fields include timezone offset — e.g., `2026-03-01T10:30:00+00:00`. Always parse with timezone awareness. [src1]
- Amount/currency fields are returned as numbers, not strings. Multi-currency environments require fetching the currency code from a separate field (e.g., `InvoiceCurrency`) — the amount field alone does not indicate currency. [src7]
- Boolean fields in Oracle Fusion are often stored as `Y`/`N` strings (not true/false JSON booleans). Check the `describe` endpoint to verify the data type. [src1]
- Flexfield values (DFF/EFF) are accessed via child resources (e.g., `/invoices/{id}/invoiceHeaderDFF`), not via direct fields on the parent resource. [src1]
- The `q` filter parameter uses SCIM-style operators (`eq`, `co`, `sw`, `gt`, `lt`, `ge`, `le`), not SQL syntax. String values must be enclosed in single quotes within the query string. [src1]

## Error Handling & Failure Points

### Common Error Codes

| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| 400 | Bad Request | Malformed JSON, invalid field names, wrong data types | Check payload against `describe` endpoint; validate field names and types [src1] |
| 401 | Unauthorized | Expired/invalid token, wrong credentials | Refresh OAuth token; verify integration user status in Fusion [src6] |
| 403 | Forbidden | Insufficient security roles on integration user | Grant required Fusion security roles (e.g., Financials REST role) [src6] |
| 404 | Not Found | Wrong resource path, nonexistent record ID, wrong API version | Verify endpoint URL and resource version; use `describe` to confirm resource exists [src1] |
| 429 | Too Many Requests | Rate limit exceeded for identity domain tier | Exponential backoff starting at 2s, max 60s; check `Retry-After` header [src2] |
| 500 | Internal Server Error | Server-side processing failure, data validation | Retry with backoff; if persistent, check Fusion application logs via EM Console [src1] |
| 503 | Service Unavailable | Maintenance window, pod restart | Check Oracle Cloud Status Dashboard; retry after maintenance window [src2] |

### Failure Points in Production

- **Silent pagination truncation**: The server can return fewer records than the `limit` without explanation. Relying on `count == limit` to detect more pages is unreliable — always use the `hasMore` boolean. Fix: `Check hasMore attribute instead of comparing count to limit`. [src3, src4]
- **OAuth token expiry in long-running jobs**: Pagination loops fetching thousands of records may exceed the token's lifetime (default ~1h). The integration silently starts returning 401s mid-pagination. Fix: `Track token expiry time and refresh proactively before it expires; implement token refresh in the pagination loop`. [src6]
- **Flexfield access requires separate requests**: Descriptive flexfields (DFF) and extensible flexfields (EFF) are not included in the parent resource response by default. Integration developers expect them in the main payload and get empty values. Fix: `Use expand parameter to include DFF/EFF child resources, or make separate GET calls to child resource endpoints`. [src1]
- **Finder parameter bind variable format**: Finders require semicolon-separated bind variables (e.g., `finder=PrimaryKey;Id=123`), but some developers use `&` or `=` delimiters. The API returns 200 with empty results instead of an error. Fix: `Use semicolons between finder name and bind variables; verify with describe endpoint which finders and bind variables are available`. [src1]
- **Batch endpoint rollback behavior**: The REST batch endpoint may roll back all operations if one fails, depending on the resource. This is undocumented per resource. Fix: `Test batch error behavior per resource in non-production; implement single-record fallback for critical operations`. [src1]

## Anti-Patterns

### Wrong: Fetching all records without pagination

```python
# BAD — Assumes single request returns all records
resp = requests.get(f"{base_url}/invoices", headers=headers)
all_invoices = resp.json()["items"]  # Only gets first 25 records (default limit)
```

### Correct: Always implement pagination with hasMore check

```python
# GOOD — Paginates through all records using hasMore
all_invoices = []
offset = 0
has_more = True
while has_more:
    resp = requests.get(
        f"{base_url}/invoices",
        headers=headers,
        params={"limit": 499, "offset": offset, "onlyData": "true"}
    )
    data = resp.json()
    all_invoices.extend(data["items"])
    has_more = data.get("hasMore", False)
    offset += len(data["items"])
```

### Wrong: Using REST API for bulk data import

```python
# BAD — Creating 10,000 invoices one by one via REST API
for invoice in ten_thousand_invoices:
    requests.post(f"{base_url}/invoices", json=invoice, headers=headers)
    # This will: (a) take hours, (b) risk rate limiting, (c) have no batch rollback
```

### Correct: Use FBDI for bulk operations

```python
# GOOD — For >500 records, use File-Based Data Import
# 1. Generate CSV in FBDI template format
# 2. Upload CSV to UCM via REST
# 3. Invoke ESS import job via REST
# 4. Poll ESS job status until complete

# REST API is only for: reading the FBDI job status
resp = requests.get(
    f"{base_url}/erpintegrations/v1/ess-job-status/{job_id}",
    headers=headers
)
```

### Wrong: Fetching full payloads when only a few fields are needed

```bash
# BAD — Returns all fields including HATEOAS links for every record
curl "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=499"
```

### Correct: Use fields + onlyData to minimize payload

```bash
# GOOD — Only returns needed fields, no links (much smaller response)
curl "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=499&onlyData=true&fields=InvoiceId,InvoiceNumber,InvoiceAmount,InvoiceDate"
```

## Common Pitfalls

- **Default limit is 25, not 500**: If you forget the `limit` parameter, you only get 25 records per page. Many developers assume the API returns all records or the maximum by default. Fix: `Always explicitly set limit=499 in production code`. [src1, src3]
- **expand behavior changed in Framework v3**: Prior to Framework v3, `expand` returned child items as a flat array. In v3+, it returns them as a collection resource with their own pagination. Code written for pre-v3 may break. Fix: `Handle expanded child resources as collections with their own hasMore/count/offset`. [src1]
- **q parameter syntax vs SQL**: The `q` filter uses SCIM operators (e.g., `q=Amount gt 1000`), not SQL WHERE clauses. Using SQL syntax silently returns zero results. Fix: `Use SCIM filter operators: eq, ne, co, sw, gt, lt, ge, le. Enclose string values in single quotes`. [src1]
- **totalResults has performance cost**: Adding `totalResults=true` forces the server to count all matching records before returning the page. On large collections, this can increase response time by 10x. Fix: `Only use totalResults on the first request if you need a progress indicator; omit it for subsequent pages`. [src1]
- **Describe endpoint is not versioned the same way**: The `describe` endpoint metadata may differ between resource versions (e.g., `11.13.18.05` vs `v1`). Always use the same version prefix for describe and data operations. Fix: `Pin your integration to a specific resource version and use that version consistently across describe, GET, POST, and PATCH`. [src1]
- **Concurrent requests share rate limit pool**: If multiple integration apps use the same OCI IAM domain, they compete for the same rate limit quota. One runaway integration can block all others. Fix: `Monitor API usage across all apps; consider separate IAM domains for independent integrations if on Premium tier`. [src2]

## Diagnostic Commands

```bash
# Test authentication — simple GET to verify token validity
curl -s -o /dev/null -w "%{http_code}" \
  "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?limit=1" \
  -H "Authorization: Bearer {token}"
# Expected: 200 (success) or 401 (token issue)

# Discover available resources — list resource catalog
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# Describe resource schema — fields, children, and available actions
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/describe" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# Check available finders for a resource
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/describe" \
  -H "Authorization: Bearer {token}" | python -c "
import json, sys
data = json.load(sys.stdin)
for f in data.get('Resources', {}).get('finders', []):
    print(f'Finder: {f[\"name\"]} - Variables: {[v[\"name\"] for v in f.get(\"variables\", [])]}')"

# Test q filter syntax — find specific record
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices?q=InvoiceNumber%20eq%20%27INV-001%27&onlyData=true&limit=1" \
  -H "Authorization: Bearer {token}" | python -m json.tool

# Check child resources for a parent record
curl -s "https://{pod}.fa.{dc}.oraclecloud.com/fscmRestApi/resources/v1/invoices/{InvoiceId}?expand=all&onlyData=true" \
  -H "Authorization: Bearer {token}" | python -c "
import json, sys
data = json.load(sys.stdin)
for key in data:
    if isinstance(data[key], (dict, list)):
        print(f'Child resource: {key}')"
```

## Version History & Compatibility

| Framework Version | Approximate Release | Status | Breaking Changes | Migration Notes |
|---|---|---|---|---|
| REST Framework v3+ | 2022 | Current | `expand` returns collection resources (paginated) instead of flat arrays | Update expand parsing to handle collection structure with hasMore/count |
| REST Framework v2 | 2019 | Legacy | N/A | Flat expand responses; no child pagination |
| REST Framework v1 | 2016 | Deprecated | N/A | Limited query parameters; basic CRUD only |

Resource versions (e.g., `11.13.18.05` vs `v1`) are independent of framework versions. Always use `v1` (latest) unless you need backward compatibility with a specific older version. [src1]

### Deprecation Policy

Oracle Fusion Cloud REST API resource versions follow the quarterly release cadence (e.g., 24A, 24B, 24C, 24D). Older resource versions remain accessible but may not receive new features. Oracle does not publish a fixed deprecation timeline for REST resource versions — monitor the Release Readiness documents for each quarterly update. [src1]

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Real-time individual record CRUD (<500 records) | Bulk data import/export (>500 records) | FBDI for import, BI Publisher for export [src5] |
| Querying with complex filters (q parameter) | Full data migration or initial load | FBDI + ESS scheduled processes [src5] |
| Metadata discovery (describe endpoint) | Event-driven / CDC integration | Business Events + OIC Adapter [src5] |
| Small-batch reads with field selection | Streaming or real-time notifications | Business Events subscriptions [src5] |
| Interactive UI integrations needing <1s response | High-concurrency parallel processing | FBDI + multiple parallel jobs [src5] |
| Prototyping and testing with cURL/Postman | Scheduled nightly data sync of entire tables | BI Publisher reports + OIC [src5] |

## Important Caveats

- Rate limits are subject to change with each Oracle Cloud release and may vary by region and pod. Always verify current limits against your specific identity domain's tier and Oracle documentation. [src2]
- The 499-record practical limit is a widely observed behavior across Oracle Fusion Cloud instances, but Oracle's official documentation states 500 as the maximum. Test with your specific instance to confirm behavior. [src3]
- REST API endpoint availability varies by Oracle Fusion Cloud module. Not all ERP objects have REST endpoints — check the module-specific REST API documentation (e.g., Financials, Procurement, Project Management). [src7]
- Oracle frequently adds new REST resources in quarterly updates. The resource catalog (`/fscmRestApi/resources/`) on your instance is the authoritative source for what's available. [src1]
- Performance characteristics (response time, throughput) depend heavily on your Oracle pod, the complexity of security rules, and concurrent usage by other tenants on the same infrastructure.

## Related Units

- No related ERP integration units currently published. As more Oracle ERP Cloud cards are created, cross-references will be added.
