# Guide to Workday Financial Management: Ledger Accounts, Journal Entries, and Expenses

## Introduction

Workday Financial Management uses **Accounting Journals** as the primary mechanism for recording all financial transactions. Unlike some accounting systems that have dedicated "Expense" objects, Workday treats expenses as a specialized type of journal entry. Before working with transactions, you need to understand Workday's **Ledger Account** structure with its Account Sets and hierarchies.

Apideck's unified Accounting API abstracts these complexities by offering three interconnected resources:

- **Ledger Accounts**: The chart of accounts organized by Account Sets (Corporate, GAAP, IFRS, etc.)
- **Journal Entries**: Full control over debit/credit transactions for any accounting operation
- **Expenses**: Streamlined interface for recording already-paid purchases

This guide provides comprehensive coverage of all three resources, explaining how to retrieve account structures, create financial transactions, manage approval workflows, and handle Workday's unique features like Account Sets and Worktags.

## Common Background

### Workday's Journal Architecture

In Workday, financial transactions are recorded as **Journal Entries**. Each journal entry contains:

- **Header Information**: Company, currency, accounting date, memo, journal source
- **Journal Entry Lines**: Individual debit and credit lines with ledger accounts
- **Worktags**: Workday's flexible tagging system for tracking categories (cost centers, projects, spend categories, etc.)
- **Status Information**: Tracking workflow state from draft through posting

**Workday processes journal entries individually**. Each entry can be submitted, approved, and posted through its own workflow without affecting other entries.

### Account Sets and Encoded IDs

Workday uses a hierarchical **Account Set** structure for ledger accounts. Each ledger account belongs to an Account Set (like "Corporate", "GAAP", or "Tax"), allowing multiple accounting frameworks in one system.

**Apideck's Account ID Format:**
```javascript
// Workday ledger account ID is base64-encoded JSON
{
  "Account_Id": "6400",
  "Account_Set_Id": "Corporate"
}
// Encoded: "eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
```

This encoding ensures account references work correctly across Workday's multi-dimensional accounting structure.

## Apideck's Unified Model

Apideck provides a simplified interface for working with Workday's complex SOAP-based financial APIs:

- **Journal Entries**: Full control over all debit and credit lines, suitable for any type of accounting transaction
- **Expenses**: Streamlined interface for "already paid" purchases where you specify expense lines and Apideck generates balancing payment line

Both map to Workday's `Submit_Accounting_Journal` SOAP operation but present different developer experiences:

- **Journal Entries** require explicit debit/credit balance
- **Expenses** automatically create offsetting payment line from the `account` field

---

# I. Ledger Accounts

## Problem Overview

Workday's chart of accounts uses a sophisticated **Account Set** architecture that supports multiple accounting frameworks simultaneously (Corporate, GAAP, IFRS, Tax, etc.). This means a single ledger account like "Professional Fees" isn't uniquely identified by just its account number – you must specify both the Account_Id and the Account_Set_Id.

Working directly with Workday's SOAP APIs for ledger accounts presents challenges:

* **Multi-ID System**: Accounts have WIDs, Account_IDs, Account_Set_IDs, and parent references
* **Account Set Hierarchy**: Each account belongs to a specific accounting framework
* **Complex XML Structures**: SOAP responses contain deeply nested XML with multiple reference types
* **Parent-Child Relationships**: Accounts form hierarchies within Account Sets
* **Status and Type Management**: Active/inactive accounts, various account types (asset, liability, expense, etc.)

Apideck's connector solves this by:
- Encoding Account_Id + Account_Set_Id into a single base64-encoded ID
- Flattening hierarchical structures into simple JSON
- Automatically handling Account Set references in transactions

## Retrieving Ledger Accounts

### Get All Ledger Accounts

`GET /accounting/ledger-accounts` retrieves the complete chart of accounts with Account Set information.

**Example Request:**
```bash
GET /accounting/ledger-accounts
x-apideck-app-id: your-app-id
x-apideck-service-id: workday
```

**Example Response:**
```json
{
  "status_code": 200,
  "data": [
    {
      "id": "eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0=",
      "display_id": "6400",
      "classification": "expense",
      "name": "Professional Fees",
      "active": true,
      "status": "active",
      "parent_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjAwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0=",
        "name": "Operating Expenses",
      }
    }
  ],
  "meta": {
    "items_on_page": 1,
    "cursors": {
      "previous": null,
      "current": "page=1",
      "next": "page=2"
    }
  }
}
```

### Key Response Fields

**Identity Fields:**
- **id**: Base64-encoded JSON containing `Account_Id` and `Account_Set_Id`
- **display_id**: Human-readable ledger account account number

**Classification:**
- **classification**: High-level type (`asset`, `liability`, `equity`, `revenue`, `expense`)

**Hierarchy:**
- **parent_account**: Parent account details in the hierarchy

**Status:**
- **active**: Whether account is active
- **status**: Account status (active, inactive)

### Get One Ledger Account

`GET /accounting/ledger-accounts/{id}` retrieves a specific account by its encoded ID.

**Example Request:**
```bash
GET /accounting/ledger-accounts/eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0=
x-apideck-service-id: workday
```

**Response:** Single account object with same structure as shown above.

## Understanding the Encoded Account ID

### Decoding the ID Structure

Apideck encodes Workday's two-part account reference into a single ID:

**Encoded Format:**
```
eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0=
```

**Decoded JSON:**
```json
{
  "Account_Id": "6400",
  "Account_Set_Id": "Corporate"
}
```

### Why Encoding is Necessary

Workday's SOAP API requires both pieces of information to uniquely identify an account:

**Workday XML Structure:**
```xml
<wd:Ledger_Account_Reference>
  <wd:ID wd:type="Ledger_Account_ID" 
         wd:parent_type="Account_Set_ID" 
         wd:parent_id="Corporate">6400</wd:ID>
</wd:Ledger_Account_Reference>
```

**Why both are needed:**
- Account "6400" might exist in multiple Account Sets (Corporate, GAAP, IFRS)
- Each Account Set represents a different accounting framework
- The same account number can have different configurations per framework

### Using Encoded IDs in Transactions

When creating journal entries or expenses, use the full encoded ID:

```json
{
  "line_items": [
    {
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      }
    }
  ]
}
```

Apideck automatically:
1. Decodes the base64 ID
2. Extracts Account_Id and Account_Set_Id
3. Constructs proper Workday XML references
4. Validates the account exists and is active

---

# II. Journal Entries

## Problem Overview

Workday's Financial Management uses **Accounting Journals** as the universal mechanism for recording financial transactions. However, working directly with Workday's SOAP APIs presents several challenges:

* **SOAP Complexity**: Workday uses SOAP/XML for financial operations, requiring complex XML request construction
* **Account Set Hierarchy**: Ledger accounts exist within Account Sets, requiring both Account_Id and Account_Set_Id for proper references
* **Multi-ID System**: Every Workday object has multiple IDs (WID, reference IDs, display IDs) requiring careful handling
* **Worktags Complexity**: Flexible tagging system with type-specific IDs and parent relationships
* **Status Workflow**: Six distinct status states with specific transitions between them

Apideck's connector abstracts these complexities by providing a unified **Journal Entry** model that handles SOAP envelope construction, account encoding, worktag mapping, and status translation automatically.

## Initial Setup

Before using journal entry operations, you need to configure your Workday connection in Apideck:

### Workday API Access

Please refer to this guide - https://developers.apideck.com/connectors/workday/docs/consumer+connection

## Adding Journal Entries (Create)

When you **add** a journal entry via Apideck, you are creating an Accounting Journal in Workday via the `Submit_Accounting_Journal` SOAP operation.

### Key Aspects

* **Unified journal entry model**: Apideck provides a simplified JSON model that maps to Workday's complex XML structure
* **Status control at creation**: Set `status: draft` to save without submitting, or `status: posted` to submit and post immediately
* **Automatic balancing validation**: Workday enforces debit/credit balance. Entries will fail submission if debits don't equal credits
* **Worktags support**: Map tracking_categories to Workday's flexible worktag system (cost centers, projects, spend categories)
* **Account encoding**: Apideck handles the base64 encoding of Account_Id + Account_Set_Id structures
* **Immutable after posting**: Once `status: posted`, the entry becomes part of the general ledger and cannot be modified

### Workday-Specific Fields

```json
{
  "number": "JE-2025-001",           // Journal number (reference)
  "status": "draft",                 // draft | pending_approval | approved | posted
  "posted_at": "2025-01-15",         // Accounting date
  "currency": "USD",                 // Currency code
  "company_id": "Global_Modern_Services_Inc_USA",  // Organization_Reference_ID
  "memo": "Q1 Adjusting Entry",      // Journal memo
  "source_type": "Manual_Journal",   // Journal source (Manual_Journal, System, etc.)
  "line_items": [                    // Must balance (total debits = total credits)
    {
      "type": "debit",              // "debit" or "credit"
      "total_amount": 5000.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="  // Base64 encoded
      },
      "tracking_categories": [      // Workday Worktags
        {
          "parent_id": "Spend_Category_ID",
          "id": "Legal_and_Auditing_Fees"
        },
        {
          "parent_id": "Cost_Center_Reference_ID",
          "id": "50000_Office_of_CFO"
        }
      ]
    },
    {
      "type": "credit",
      "total_amount": 5000.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiMjA1MCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      },
      "tracking_categories": [
        {
          "parent_id": "Spend_Category_ID",
          "id": "Legal_and_Auditing_Fees"
        },
        {
          "parent_id": "Cost_Center_Reference_ID",
          "id": "50000_Office_of_CFO"
        }
      ]
    }
  ]
}
```

### Creating a Draft Journal Entry

**Request to Apideck:**
```bash
POST /accounting/journal-entries
Content-Type: application/json
x-apideck-app-id: your-app-id
x-apideck-service-id: workday

{
  "number": "JE-2025-001",
  "status": "draft",
  "posted_at": "2025-01-15",
  "currency": "USD",
  "company_id": "Global_Modern_Services_Inc_USA",
  "memo": "Q1 Adjusting Entry",
  "source_type": "Manual_Journal",
  "line_items": [
    {
      "type": "debit",
      "total_amount": 5000.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      }
    },
    {
      "type": "credit",
      "total_amount": 5000.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiMjA1MCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      }
    }
  ]
}
```

**What Happens:**
1. Apideck constructs SOAP XML envelope with authentication
2. Sends `Submit_Accounting_Journal` SOAP request to Workday
3. Returns unified response with Workday WID as the `id`

**Response:**
```json
{
  "status_code": 200,
  "status": "OK",
  "service": "workday",
  "resource": "journal-entries",
  "operation": "add",
  "data": {
    "id": "a10dee2ca7258147170cb396fe154022"  // Workday WID
  }
}
```

### Creating and Posting in One Step

To create and immediately post a journal entry, set `status: posted`:

```json
{
  "number": "JE-2025-002",
  "status": "posted",           // ← Will submit AND post
  "posted_at": "2025-01-15",
  "currency": "USD",
  "company_id": "Global_Modern_Services_Inc_USA",
  "memo": "Monthly Depreciation",
  "line_items": [
    {
      "description": "Depreciation Expense",
      "type": "debit",
      "total_amount": 2500.00,
      "ledger_account": { "id": "{encoded-account-id}" },
      "tracking_categories": [
       {
       "id": "",
       "parent_id": ""
       }
      ]
    },
    {
      "description": "Accumulated Depreciation",
      "type": "credit",
      "total_amount": 2500.00,
      "ledger_account": { "id": "{encoded-account-id}" },
      "tracking_categories": [
       {
       "id": "",
       "parent_id": ""
       }
      ]
    }
  ]
}
```

## Updating a Journal Entry

Journal entries can only be updated while in **draft status**. Once submitted for approval or posted, Workday treats them as immutable.

**Update Request:**
```bash
PATCH /accounting/journal-entries/{id}
Content-Type: application/json

{
  "memo": "Updated memo text",
  "line_items": [
    {
      "description": "Updated line description",
      "type": "debit",
      "total_amount": 6000.00,
      "ledger_account": { "id": "{encoded-account-id}" },
      "tracking_categories": [
       {
       "id": "",
       "parent_id": ""
       }
      ]
    },
    {
      "description": "Updated credit line",
      "type": "credit",
      "total_amount": 6000.00,
      "ledger_account": { "id": "{encoded-account-id}" },
      "tracking_categories": [
       {
       "id": "",
       "parent_id": ""
       }
      ]
    }
  ]
}
```

**Important Limitations:**
- ✅ **Can update**: Draft status entries
- ❌ **Cannot update**: Submitted, approved, or posted entries
- ⚠️ **Line replacement**: Update replaces ALL lines, not just modified ones

**Important Notes:**

- **Auto_Complete behavior**: Determined by Workday configuration. Some tenants allow auto-posting for API-created journals, others require manual approval
- **Approval workflows**: Workday may route journals to approvers based on amount thresholds, cost centers, or other business rules
- **No rollback**: Once posted, journal entries are permanent and read-only.
- **Individual Processing**: Workday posts each journal individually – no risk of accidentally posting other unrelated entries

## Retrieving Journal Entries (Get One / Get All)

### Get One Journal Entry

`GET /accounting/journal-entries/{id}` retrieves a single journal entry by its Workday WID.

**Example Request:**
```bash
GET /accounting/journal-entries/a10dee2ca7258147170cb396fe154022
x-apideck-app-id: your-app-id
x-apideck-service-id: workday
```

**Example Response:**
```json
{
  "status_code": 200,
  "data": {
    "id": "a10dee2ca7258147170cb396fe154022",
    "number": "10783",
    "status": "posted",
    "posted_at": "2021-06-30T00:00:00Z",
    "currency": "USD",
    "company_id": "Global_Modern_Services_Inc_USA",
    "memo": "Q2 Audit Accrual",
    "source_type": "Manual_Journal",
    "line_items": [
      {
        "line_number": 1,
        "description": "Q2 Audit Accrual",
        "type": "debit",
        "total_amount": 60000,
        "ledger_account": {
          "id": "eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
        },
        "tracking_categories": [
          {
            "parent_id": "Spend_Category_ID",
            "id": "Legal_and_Auditing_Fees"
          },
          {
            "parent_id": "Cost_Center_Reference_ID",
            "id": "50000_Office_of_CFO"
          }
        ]
      },
      {
        "line_number": 2,
        "description": "Q2 Audit Accrual",
        "type": "credit",
        "total_amount": 60000,
        "ledger_account": {
          "id": "eyJBY2NvdW50X0lkIjoiMjA1MCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
        },
        "tracking_categories": [
          {
            "parent_id": "Spend_Category_ID",
            "id": "Legal_and_Auditing_Fees"
          },
          {
            "parent_id": "Cost_Center_Reference_ID",
            "id": "50000_Office_of_CFO"
          }
        ]
      }
    ],
    "created_at": "2021-08-08T17:28:20Z",
    "updated_at": "2021-08-08T17:37:04Z"
  }
}
```

### Get All Journal Entries

`GET /accounting/journal-entries` returns a list of journal entries.

**Example:**
```bash
GET /accounting/journal-entries
```

**Response Structure:**
```json
{
  "status_code": 200,
  "data": [
    {
      "id": "...",
      "number": "10783",
      "status": "posted",
      "posted_at": "2025-01-15T00:00:00Z",
      "total_amount": 60000,
      "currency": "USD",
      "company_id": "Global_Modern_Services_Inc_USA",
      "memo": "Q2 Audit Accrual",
      "line_items": [...],
      "created_at": "...",
      "updated_at": "..."
    }
  ],
  "meta": {
    "items_on_page": 1,
    "cursors": {
      "previous": null,
      "current": "page=1",
      "next": null
    }
  }
}
```

---

# III. Expenses

## Problem Overview

Workday doesn't have a dedicated "Expense" API resource. Instead, expenses are recorded as a specific type of **Accounting Journal** where:

- **Debit lines** represent expense accounts (where money was spent)
- **Credit line** represents the payment account (cash, bank, or credit card)
- **Journal Source** is typically set to identify expense-related entries

Apideck abstracts this by providing an **Expenses** resource that:
- Accepts simplified expense line items (just amounts and accounts)
- Automatically generates the offsetting payment/credit line
- Uses Workday's `Submit_Accounting_Journal` under the hood

## Initial Setup

**No additional expense-specific configuration** is required. Apideck's expense operations use the same Workday journal mechanisms as journal entries.

## Adding Expenses (Create)

When you **add** an expense via Apideck, you specify the expense lines and payment source. Apideck automatically:
1. Creates expense lines as journal entry debits
2. Generates balancing credit line from the `account` field
3. Sets appropriate journal source and tracking

### Expense Request Structure

```json
{
  "transaction_date": "2025-01-15",
  "account": {
    "id": "eyJBY2NvdW50X0lkIjoiMTAwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
  },
  "tracking_categories" : [
    {
      "id": "820000_Sale_Department",
      "parent_id": "Cost_Center_Reference_ID"
    }
  ],
  "currency": "USD",
  "company_id": "Global_Modern_Services_Inc_USA",
  "memo": "Travel expenses - Client visit",
  "number": "EXP-2025-001",
  "status": "draft",
  "line_items": [
    {
      "total_amount": 450.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjEwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      },
      "tracking_categories": [
        {
          "parent_id": "Cost_Center_Reference_ID",
          "id": "40000_Sales_Department"
        }
      ]
    },
    {
      "total_amount": 250.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjExMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      },
      "tracking_categories": [
        {
          "parent_id": "Cost_Center_Reference_ID",
          "id": "40000_Sales_Department"
        }
      ]
    }
  ]
}
```

### How Multiple Lines Are Created

**Your expense input:**
- 2 expense line items totaling $700.00 (debits)
- 1 payment account (credit)

**Apideck generates journal entry:**
```
Line 1: Debit  $450.00 - Travel Transportation (6100)
Line 2: Debit  $250.00 - Travel Lodging (6110)
Line 3: Credit $700.00 - Corporate Credit Card (1000)  ← Auto-generated
```

**Result**: Balanced journal entry with 3 lines that represents the complete expense transaction.

### Request to Apideck

```bash
POST /accounting/expenses
Content-Type: application/json
x-apideck-app-id: your-app-id
x-apideck-service-id: workday

{
  "transaction_date": "2025-01-15",
  "account": {
    "id": "eyJBY2NvdW50X0lkIjoiMTAwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
  },
  "currency": "USD",
  "company_id": "Global_Modern_Services_Inc_USA",
  "memo": "Travel expenses",
  "status": "draft",
  "line_items": [
    {
      "total_amount": 450.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjEwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      }
    },
    {
      "total_amount": 250.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjExMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      }
    }
  ]
}
```

### What Happens Behind the Scenes

 **Workday Processing**:
   - Validates the journal entry structure
   - Checks business rules and permissions
   - Assigns WID and journal number
   - Sets initial status based on submission flag

**Response Structure:**
```json
{
  "status_code": 200,
  "data": {
    "id": "a10dee2ca7258147170cb396fe154022",
    "transaction_date": "2025-01-15T00:00:00Z",
    "total_amount": 700.00,
    "type": "expense",
    "status": "draft",
    "currency": "USD",
    "company_id": "Global_Modern_Services_Inc_USA",
    "memo": "Travel expenses",
    "account": {
      "id": "eyJBY2NvdW50X0lkIjoiMTAwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
    },
    "tracking_categories" : [
      {
        "parent_id": "Cost_Center_Reference_ID",
        "id": "40000_Sales_Department"
      }
    ],
    "line_items": [
      {
        "total_amount": 450.00,
        "ledger_account": {
          "id": "eyJBY2NvdW50X0lkIjoiNjEwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
        },
        "tracking_categories" : [
          {
            "parent_id": "Cost_Center_Reference_ID",
            "id": "40000_Sales_Department"
          }
        ],
      },
      {
        "total_amount": 250.00,
        "ledger_account": {
          "id": "eyJBY2NvdW50X0lkIjoiNjExMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
        },
        "tracking_categories" : [
          {
            "parent_id": "Cost_Center_Reference_ID",
            "id": "40000_Sales_Department"
          }
        ]
      }
    ],
    "created_at": "2025-01-15T14:23:10Z",
    "updated_at": "2025-01-15T14:23:10Z"
  }
}
```

## Key Aspects of Expense Creation

### Automatic Balancing

**You provide:**
```json
{
  "account": { "id": "credit-card-account" },  // Payment source
  "line_items": [
    { "total_amount": 450.00, "ledger_account": {...} },  // Expense 1
    { "total_amount": 250.00, "ledger_account": {...} }   // Expense 2
  ]
}
```

**Apideck generates:**
```
Debit:  $450.00 - Travel Transportation (Expense line 1)
Debit:  $250.00 - Travel Lodging       (Expense line 2)
Credit: $700.00 - Corporate Credit Card (Auto-generated from account)
-----------------------------------------------------
Total:  $700.00 = $700.00 ✓ Balanced
```

### Worktags (Tracking Categories)

Workday's **Worktags** are flexible dimensions for tracking expenses by cost center, project, region, etc.

**Tracking Categories Structure:**
```json
{
  "tracking_categories": [
    {
      "id": "40000_Sales_Department",        
      "parent_id": "Cost_Center_Reference_ID"          
    },
    {
      "id": "Travel_Entertainment",
      "parent_id": "Spend_Category_ID"
    },
    {
      "id": "PRJ-2025-Q1-Expansion",
      "parent_id": "Project_ID"
    }
  ]
}
```

**Common Worktag Types:**
- `Cost_Center_Reference_ID`: Cost center allocation (required when creating a journal-entry)
- `Spend_Category_ID`: Expense category classification
- `Project_ID`: Project tracking
- `Region_ID`: Geographic tracking

**Applied to Line Items:**
Each expense line can have its own set of worktags, allowing detailed expense allocation:

```json
{
  "line_items": [
    {
      "description": "Airfare - East Coast",
      "total_amount": 450.00,
      "ledger_account": {...},
      "tracking_categories": [
        { "parent_id": "Cost_Center_Reference_ID", "id": "40000_Sales" },
        { "parent_id": "Region_ID", "id": "US_East" }
      ]
    },
    {
      "description": "Hotel - West Coast",
      "total_amount": 250.00,
      "ledger_account": {...},
      "tracking_categories": [
        { "parent_id": "Cost_Center_Reference_ID", "id": "40000_Sales" },
        { "parent_id": "Region_ID", "id": "US_West" }
      ]
    }
  ]
}
```

### Status Control

Expenses support the same status workflow as journal entries:

- **`draft`**: Save expense without submitting for approval
- **`posted`**: Submit and attempt to post to ledger

## Updating an Expense

Like journal entries, expenses can only be updated while in **draft status**.

**Update Request:**
```bash
PATCH /accounting/expenses/{id}
Content-Type: application/json

{
  "memo": "Updated travel expenses",
  "line_items": [
    {
      "total_amount": 475.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjEwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      },
      "tracking_categories": [
        { "parent_id": "Cost_Center_Reference_ID", "id": "40000_Sales" },
        { "parent_id": "Region_ID", "id": "US_East" }
      ]
    },
    {
      "total_amount": 275.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjExMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      },
      "tracking_categories": [
        { "parent_id": "Cost_Center_Reference_ID", "id": "40000_Sales" },
        { "parent_id": "Region_ID", "id": "US_East" }
      ]
    }
  ]
}
```

**Behind the Scenes:**
1. Apideck fetches existing expense journal from Workday
2. Validates expense is in draft status
3. Merges updates with existing data
4. Recalculates payment line credit amount ($750.00 total)
5. Submits updated journal to Workday with new line structure

**Important:**
- Update replaces ALL expense lines
- Payment account credit line is automatically recalculated

## Posting (Approving) an Expense

Posting an expense follows the same workflow as journal entries. Update the status to trigger submission:

### Option 1: Create Posted Expense
```json
POST /accounting/expenses
{
  "status": "posted",  // Submit immediately
  "transaction_date": "2025-01-15",
  "account": { "id": "..." },
  "line_items": [...]
}
```

### Option 2: Post Draft Expense
```json
PATCH /accounting/expenses/{id}
{
  "status": "posted"  // Submit existing draft
}
```

**Checking Status:**
```bash
GET /accounting/expenses/{id}

{
  "id": "a10dee2ca7258147170cb396fe154022",
  "status": "posted",  // Successfully posted
  "posted_at": "2025-01-15T00:00:00Z",
  "total_amount": 700.00,
  ...
}
```

## Retrieving Expenses (Get One / Get All)

### Get One Expense

`GET /accounting/expenses/{id}` retrieves a specific expense by its WID.

**Example Response:**
```json
{
  "status_code": 200,
  "data": {
    "id": "a10dee2ca7258147170cb396fe154022",
    "number": "10783",
    "transaction_date": "2025-01-15T00:00:00Z",
    "total_amount": 700.00,
    "type": "expense",
    "status": "posted",
    "currency": "USD",
    "company_id": "Global_Modern_Services_Inc_USA",
    "memo": "Travel expenses",
    "account": {
      "id": "eyJBY2NvdW50X0lkIjoiMTAwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
    },
    "tracking_categories": [
      {
        "parent_id": "Cost_Center_Reference_ID",
        "id": "40000_Sales_Department"
      }
    ],
    "line_items": [
      {
        "total_amount": 450.00,
        "unit_price": 450.00,
        "ledger_account": {
          "id": "eyJBY2NvdW50X0lkIjoiNjEwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
        },
        "tracking_categories": [...]
      },
      {
        "total_amount": 250.00,
        "unit_price": 250.00,
        "ledger_account": {
          "id": "eyJBY2NvdW50X0lkIjoiNjExMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
        },
        "tracking_categories": [...]
      }
    ],
    "created_at": "2025-01-15T14:23:10Z",
    "updated_at": "2025-01-15T14:23:10Z"
  }
}
```

### Get All Expenses

`GET /accounting/expenses` returns expenses.

**Example Request:**
```bash
GET /accounting/expenses
```

**Response:**
```json
{
  "status_code": 200,
  "data": [
    {
      "id": "a10dee2ca7258147170cb396fe154022",
      "number": "10783",
      "transaction_date": "2025-01-15T00:00:00Z",
      "total_amount": 700.00,
      "type": "expense",
      "status": "posted",
      "currency": "USD",
      "account": {
        "id": "...",
      },
      "line_items": [...],
      "created_at": "2025-01-15T14:23:10Z",
      "updated_at": "2025-01-15T14:23:10Z"
    }
  ],
  "meta": {
    "items_on_page": 1,
    "cursors": {
      "previous": null,
      "current": "page=1",
      "next": null
    }
  }
}
```

---

# IV. Workday-Specific Considerations

## Account Sets and Multi-Dimensional Accounting

### Understanding Account Sets

**Account Reference Structure:**
```xml
<wd:Ledger_Account_Reference>
  <wd:ID wd:type="Ledger_Account_ID" 
         wd:parent_type="Account_Set_ID" 
         wd:parent_id="Corporate">6400</wd:ID>
</wd:Ledger_Account_Reference>
```

### How Apideck Handles Account Sets

**Encoding:**
When you use Apideck's Ledger Accounts API, you receive encoded account IDs:
```bash
GET /accounting/ledger-accounts/eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0=

# Decoded structure:
{
  "Account_Id": "6400",
  "Account_Set_Id": "Corporate"
}
```

**In Expense/Journal Requests:**
```json
{
  "line_items": [
    {
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="
      }
    }
  ]
}
```

**Apideck's Transformation:**
1. Decodes base64 ID
2. Extracts Account_Id and Account_Set_Id
3. Constructs proper Workday XML structure
4. Sends to Workday with correct parent references

### Working with Different Account Sets

If you need to record transactions in multiple accounting frameworks:

```json
{
  "line_items": [
    {
      "description": "Legal Fees",
      "total_amount": 5000.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiQ29ycG9yYXRlIn0="  // Corporate framework
      }
    },
    {
      "description": "Legal Fees",
      "total_amount": 5000.00,
      "ledger_account": {
        "id": "eyJBY2NvdW50X0lkIjoiNjQwMCIsIkFjY291bnRfU2V0X0lkIjoiR0FBUCJ9"  // GAAP framework
      }
    }
  ]
}
```

## Worktags: Workday's Flexible Tracking

### What Are Worktags?

Worktags are Workday's answer to traditional accounting dimensions/segments. Instead of fixed dimensions, Workday allows flexible tagging with type-specific tags:

**Standard Worktag Types:**
- **Cost Centers**: Organizational units (departments, divisions)
- **Spend Categories**: Expense classification (travel, supplies, professional fees)
- **Projects**: Project/grant tracking
- **Regions**: Geographic allocation

### Worktag Structure in Apideck

**Request Format (tracking_categories):**
```json
{
  "tracking_categories": [
    {
      "parent_id": "Cost_Center_Reference_ID",        
      "id": "50000_Office_of_CFO"            
    },
    {
      "parent_id": "Spend_Category_ID",
      "id": "Legal_and_Auditing_Fees"
    },
    {
      "parent_id": "Project_ID",
      "id": "PRJ-2025-Digital-Transformation"
    }
  ]
}
```

**Workday XML Structure:**
```xml
<wd:Worktags_Reference>
  <wd:ID wd:type="Cost_Center_Reference_ID">50000_Office_of_CFO</wd:ID>
</wd:Worktags_Reference>
<wd:Worktags_Reference>
  <wd:ID wd:type="Spend_Category_ID">Legal_and_Auditing_Fees</wd:ID>
</wd:Worktags_Reference>
```

### Worktag Best Practices

**1. Validate Worktag Compatibility:**
- Not all worktag combinations are valid in Workday
- Some worktags are required based on ledger account configuration
- Workday validates worktags at submission time

**2. Use Reference IDs:**
Worktag type IDs commonly end in `_Reference_ID` or `_ID`:
- `Cost_Center_Reference_ID`
- `Spend_Category_ID`
- `Project_ID`
- `Region_Reference_ID`

## SOAP/XML Abstraction

### Apideck Handles SOAP Complexity

Working directly with Workday SOAP APIs requires:
- XML envelope construction
- WSSE security headers
- Namespace management
- Complex nested structures

**Direct SOAP Request (340+ lines):**
```xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:wd="urn:com.workday/bsvc">
  <soapenv:Header>
    <wsse:Security>
      <wsse:UsernameToken>
        <wsse:Username>integrationuser@tenant</wsse:Username>
        <wsse:Password>password</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <wd:Submit_Accounting_Journal_Request wd:Add_Only="true">
      <wd:Business_Process_Parameters>
        <wd:Auto_Complete>true</wd:Auto_Complete>
      </wd:Business_Process_Parameters>
      <wd:Accounting_Journal_Data>
        <wd:Company_Reference>
          <wd:ID wd:type="Organization_Reference_ID">Global_Modern_Services_Inc_USA</wd:ID>
        </wd:Company_Reference>
        <wd:Currency_Reference>
          <wd:ID wd:type="Currency_ID">USD</wd:ID>
        </wd:Currency_Reference>
        <wd:Accounting_Date>2025-01-15</wd:Accounting_Date>
        <wd:Journal_Entry_Line_Replacement_Data>
          <!-- Complex line structure for each debit/credit -->
        </wd:Journal_Entry_Line_Replacement_Data>
      </wd:Accounting_Journal_Data>
    </wd:Submit_Accounting_Journal_Request>
  </soapenv:Body>
</soapenv:Envelope>
```

**Apideck Request (Simple JSON):**
```json
POST /accounting/expenses
{
  "transaction_date": "2025-01-15",
  "account": { "id": "..." },
  "currency": "USD",
  "company_id": "Global_Modern_Services_Inc_USA",
  "line_items": [
    { "description": "Airfare", "total_amount": 450.00, "ledger_account": {...} },
    { "description": "Hotel", "total_amount": 250.00, "ledger_account": {...} }
  ]
}
```

Apideck handles:
- ✅ SOAP envelope construction
- ✅ WSSE authentication
- ✅ XML namespace management
- ✅ Account Set encoding/decoding
- ✅ Worktag structure conversion
- ✅ Line item XML formatting
- ✅ Status code translation
- ✅ Error handling and rollback
---

# V. Comparison: Expenses vs Journal Entries in Workday

## When to Use Each Resource

### Use Expenses When:
- ✅ Recording "already paid" purchases
- ✅ Simple expense transactions (purchase + payment)
- ✅ Want automatic payment line generation
- ✅ Line items are all expenses with one payment source
- ✅ Prefer simplified API with less accounting detail

### Use Journal Entries When:
- ✅ Need explicit control over all debits and credits
- ✅ Recording accounting adjustments or accruals
- ✅ Complex multi-line transactions
- ✅ Need full flexibility in line structure

## Implementation Differences

### Expenses Implementation
```javascript
// Apideck receives:
{
  "account": { "id": "credit-card" },
  "line_items": [
    { "total_amount": 450, ledger_account: {...} },
    { "total_amount": 250, ledger_account: {...} }
  ]
}

// Hook generates journal structure:
{
  "Journal_Entry_Line_Replacement_Data": [
    { "Debit_Amount": "450", "Ledger_Account_Reference": {...} },
    { "Debit_Amount": "250", "Ledger_Account_Reference": {...} },
    { "Credit_Amount": "700", "Ledger_Account_Reference": {credit-card} } 
  ]
}
```

### Journal Entries Implementation
```javascript
// Apideck receives:
{
  "line_items": [
    { "type": "debit", "total_amount": 5000, "ledger_account": {...} },
    { "type": "credit", "total_amount": 5000, "ledger_account": {...} }
  ]
}

// Mapping directly converts:
{
  "Journal_Entry_Line_Replacement_Data": [
    { "Debit_Amount": "5000", "Ledger_Account_Reference": {...} },
    { "Credit_Amount": "5000", "Ledger_Account_Reference": {...} }
  ]
}
```

---

# Conclusion

Using Apideck's unified API for Workday Financial Management dramatically simplifies working with resources that Workday implements through complex SOAP operations. This guide covered three interconnected resources that form the foundation of financial data management:

## Three Core Resources

**1. Ledger Accounts:**
- Multi-dimensional chart of accounts organized by Account Sets (Corporate, GAAP, IFRS, Tax)
- Base64-encoded IDs that combine Account_Id + Account_Set_Id
- Hierarchical account structures with parent-child relationships
- REST endpoints for retrieval

**2. Journal Entries:**
- Full control over debit/credit transactions for any accounting operation
- Support for draft, and posted workflows
- Manual balancing requirement with explicit line types
- Suitable for adjustments, accruals, reclassifications, and complex transactions

**3. Expenses:**
- Streamlined interface for recording already-paid purchases
- Automatic payment line generation from the `account` field
- Same approval workflow as journal entries
- Optimized for simple purchase transactions

## What Apideck Handles Automatically

All three resources benefit from Apideck's abstraction layer:

* **SOAP/XML Complexity**: No need to construct XML envelopes or manage namespaces
* **Account Set Encoding**: Transparent encoding/decoding of multi-part account references
* **Worktag Transformation**: Simple JSON tracking_categories → complex Workday Worktag XML
* **Error Handling**: Consistent error responses with actionable validation messages
* **Atomic Operations**: Transaction safety with proper rollback on failures

## Workday's Unique Features

**Account Sets:**
- Support multiple accounting frameworks simultaneously
- Same account number can exist in Corporate, GAAP, IFRS, and Tax Account Sets
- Each framework maintains independent balances and configurations

**Worktags:**
- Flexible tagging system beyond traditional dimensions
- Support for cost centers, projects, regions, spend categories, and custom tags
- Applied at line-item and header level for detailed tracking

**Immutability:**
- Posted entries become part of permanent ledger
- No risk of accidental modification after posting

## Integration Benefits

By leveraging Apideck's Workday connector, developers can:

1. **Work with familiar REST JSON APIs** instead of learning SOAP/XML
2. **Use encoded account IDs** without understanding Workday's multi-ID system
3. **Apply worktags** using simple key-value pairs
4. **Create transactions** with automatic SOAP envelope construction
5. **Track status** through unified workflow states
6. **Handle errors** with consistent validation messages

This allows you to focus on your application logic while ensuring accurate, compliant financial data in Workday's sophisticated financial management system. Whether you're building expense reporting, financial consolidation, or accounting automation, Apideck provides the abstraction layer that makes Workday integration straightforward and maintainable.

---

## Related Resources

**Apideck Documentation:**
- [Apideck Workday Connector Overview](https://www.apideck.com/connectors/workday)
- [Apideck Accounting API - Ledger Accounts](https://developers.apideck.com/apis/accounting/reference#tag/Ledger-Accounts)
- [Apideck Accounting API - Journal Entries](https://developers.apideck.com/apis/accounting/reference#tag/Journal-Entries)
- [Apideck Accounting API - Expenses](https://developers.apideck.com/apis/accounting/reference#tag/Expenses)
- [Apideck - Expense and Bills](https://developers.apideck.com/guides/expenses-bills)
