---
# === IDENTITY ===
id: business/erp-integration/time-expense-integration/2026
canonical_question: "How do you integrate Concur/Expensify/Navan with ERP for GL coding and approval workflows?"
aliases:
  - "How to connect T&E expense system to ERP for journal posting?"
  - "SAP Concur Financial Integration API for expense report GL coding"
  - "Corporate card reconciliation with ERP clearing accounts"
  - "Expense approval workflow integration with NetSuite/SAP/Oracle"
entity_type: erp_integration
domain: business > erp-integration > time-expense-integration
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === SYSTEM PROFILE ===
systems:
  - name: "SAP Concur"
    vendor: "SAP"
    version: "Expense API v4, Financial Integration API v4"
    edition: "Standard, Professional, Premium"
    deployment: cloud
    api_surface: "REST"
  - name: "Expensify"
    vendor: "Expensify"
    version: "Integration Server API v1"
    edition: "Collect, Control"
    deployment: cloud
    api_surface: "REST"
  - name: "Navan (formerly TripActions)"
    vendor: "Navan"
    version: "Expense API v1, SFTP export"
    edition: "Essentials, Premium, Enterprise"
    deployment: cloud
    api_surface: "REST, SFTP"
  - name: "Brex"
    vendor: "Brex"
    version: "Accounting API v1"
    edition: "Essentials, Premium, Enterprise"
    deployment: cloud
    api_surface: "REST"
  - name: "Ramp"
    vendor: "Ramp"
    version: "Developer API v1"
    edition: "Plus, Enterprise"
    deployment: cloud
    api_surface: "REST"
  - name: "ERP Target"
    vendor: "Various (SAP, Oracle, NetSuite, Microsoft)"
    version: "Multiple"
    edition: "Enterprise"
    deployment: "cloud, on-premise, hybrid"
    api_surface: "REST, OData, SOAP, File Import"

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

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: volatile
  last_breaking_change: "Concur User v1 Form Fields sunset June 2026; Brex acquired by Capital One Jan 2026"
  next_review: 2026-08-30
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "SAP Concur Financial Integration API returns approved documents only -- cannot pull draft or submitted reports"
  - "Expensify API requires partnerUserID/partnerUserSecret pair -- no OAuth flow, credentials per integration"
  - "Navan direct ERP integrations limited to NetSuite, Sage Intacct, QuickBooks Online -- other ERPs require SFTP or API"
  - "Brex Accounting API requires two-way sync -- unidirectional export not supported for real-time mode"
  - "Ramp accounting sync supports NetSuite, Sage Intacct, Oracle Fusion, QuickBooks, Xero -- SAP S/4HANA requires custom build"
  - "Corporate card feeds arrive 24-48h after transaction -- never treat card data as real-time"
  - "Multi-currency expense reports require exchange rate source agreement between T&E system and ERP before go-live"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs AP invoice automation, not employee expense reports"
    use_instead: "business/erp-integration/ap-automation-integration/2026"
  - condition: "User needs payroll integration for reimbursement via paycheck"
    use_instead: "business/erp-integration/payroll-erp-integration/2026"
  - condition: "User needs only corporate card program setup without ERP integration"
    use_instead: "finance/saas-benchmarks/corporate-card-programs/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: te_platform
    question: "Which T&E platform are you using?"
    type: choice
    options:
      - "SAP Concur"
      - "Expensify"
      - "Navan (TripActions)"
      - "Brex"
      - "Ramp"
      - "Other / evaluating"
  - key: erp_target
    question: "Which ERP or accounting system is the target?"
    type: choice
    options:
      - "SAP S/4HANA or ECC"
      - "Oracle ERP Cloud or NetSuite"
      - "Microsoft Dynamics 365 or Business Central"
      - "Sage Intacct"
      - "QuickBooks"
      - "Other"
  - key: integration_scope
    question: "What's the integration scope?"
    type: choice
    options:
      - "Expense report GL coding and journal posting only"
      - "Corporate card feed reconciliation"
      - "Full T&E lifecycle (booking + expense + reimbursement)"
      - "Travel booking + per diem automation"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/business/erp-integration/time-expense-integration/2026"
suggested_citation: "Source: knowledgelib.io -- AI Knowledge Library (verified 2026-03-03)"

# === RELATED UNITS ===
related_kos:
  depends_on:
    - id: "business/erp-integration/ap-automation-integration/2026"
      label: "AP Automation Integration (invoice side of T&E)"
  related_to:
    - id: "business/erp-integration/payroll-erp-integration/2026"
      label: "Payroll Integration (reimbursement via paycheck)"
    - id: "business/erp-integration/netsuite-rest-api/2026"
      label: "NetSuite REST API (common ERP target)"
  solves:
    - id: "business/erp-integration/expense-report-gl-coding/2026"
      label: "Expense Report GL Coding Patterns"
  alternative_to:
    - id: "business/erp-integration/manual-expense-reconciliation/2026"
      label: "Manual Expense Reconciliation (legacy approach)"
  often_confused_with:
    - id: "business/erp-integration/ap-automation-integration/2026"
      label: "AP Automation -- handles vendor invoices, not employee expenses"

# === SOURCES ===
sources:
  - id: src1
    title: "SAP Concur Financial Integration API v4 Documentation"
    author: SAP
    url: https://developer.concur.com/api-reference/financial-integration/v4.financial-integration.html
    type: official_docs
    published: 2025-03-06
    reliability: authoritative
  - id: src2
    title: "SAP Concur Financial Documents Schema v4"
    author: SAP
    url: https://github.com/SAP-docs/preview.developer.concur.com/blob/main/src/api-reference/financial-integration/v4.financial-documents-schema.markdown
    type: official_docs
    published: 2025-01-15
    reliability: authoritative
  - id: src3
    title: "Expensify API Reference -- Integration Server"
    author: Expensify
    url: https://integrations.expensify.com/
    type: official_docs
    published: 2025-06-01
    reliability: authoritative
  - id: src4
    title: "Ramp Developer API -- Accounting Documentation"
    author: Ramp
    url: https://docs.ramp.com/developer-api/v1/accounting
    type: official_docs
    published: 2025-12-01
    reliability: authoritative
  - id: src5
    title: "Brex AI-Native Accounting Automation for ERPs"
    author: Brex
    url: https://www.prnewswire.com/news-releases/brex-brings-ai-native-accounting-automation-to-erps-302665854.html
    type: vendor_release_notes
    published: 2026-01-15
    reliability: high
  - id: src6
    title: "How Expense Data Flows Between ERP, Cards, and Expense Platforms"
    author: SutiSoft
    url: https://www.sutisoft.com/blog/expense-data-flows-between-erp-cards-expense-platforms/
    type: technical_blog
    published: 2025-08-01
    reliability: moderate_high
  - id: src7
    title: "T&E Expense Report Management: Best Practices and Tips"
    author: Oracle NetSuite
    url: https://www.netsuite.com/portal/resource/articles/financial-management/t-e-report-managements.shtml
    type: technical_blog
    published: 2025-05-01
    reliability: high
  - id: src8
    title: "Navan ERP Integrations for Enterprise Expense Management"
    author: Navan
    url: https://navan.com/integrations
    type: official_docs
    published: 2025-11-01
    reliability: high
---

# T&E System-to-ERP Integration Playbook: Concur, Expensify, Navan, Brex & Ramp

## TL;DR

- **Bottom line**: T&E-to-ERP integration follows a universal pattern -- receipt capture to expense report to approval to GL coding to journal posting to reimbursement -- but each platform (Concur, Expensify, Navan, Brex, Ramp) has different API surfaces, export formats, and pre-built ERP connectors that determine your integration complexity.
- **Key limit**: Corporate card feeds arrive 24-48h after transaction; never treat card data as real-time for GL posting. SAP Concur Financial Integration API only returns fully-approved documents.
- **Watch out for**: Exchange rate timing mismatch -- if the T&E system captures the rate at transaction time but the ERP uses the rate at posting time, you get unexplained variances that compound across hundreds of reports.
- **Best for**: Organizations with >50 employees submitting expenses, corporate card programs, or multi-entity structures where manual GL coding and reconciliation consume >20 hours/month.
- **Authentication**: SAP Concur uses OAuth 2.0 (JWT bearer for server-to-server); Expensify uses static API credentials (partnerUserID/partnerUserSecret); Brex/Ramp use OAuth 2.0; Navan uses API key + SFTP for file-based exports.

## System Profile

This playbook covers the end-to-end integration of five major T&E platforms (SAP Concur, Expensify, Navan, Brex, and Ramp) with enterprise ERP systems. It focuses on the data flow from expense creation through GL journal posting and reimbursement. Each T&E platform takes a different approach: Concur provides a dedicated Financial Integration API for ERP posting; Expensify exports via its Integration Server as journal entries, vendor bills, or credit card charges; Navan offers direct connectors for select ERPs plus SFTP; Brex provides a two-way Accounting API; and Ramp offers real-time sync with AI-driven auto-coding.

This card does NOT cover: AP invoice processing (vendor invoices, PO matching), procurement-to-pay workflows, or payroll integration for reimbursement via paycheck. For those, see the related units.

| System | Role | API Surface | Direction |
|---|---|---|---|
| SAP Concur | T&E platform -- expense reports, travel booking, receipt capture | Financial Integration API v4 (REST) | Outbound to ERP |
| Expensify | T&E platform -- expense reports, corporate card, receipt scanning | Integration Server API (REST) | Outbound to ERP |
| Navan | T&E + travel platform -- expense, travel booking, corporate card | Expense API v1, SFTP | Outbound to ERP |
| Brex | Corporate card + expense -- card transactions, receipt matching | Accounting API v1 (REST) | Bidirectional with ERP |
| Ramp | Corporate card + expense -- card transactions, AP automation | Developer API v1 (REST) | Bidirectional with ERP |
| ERP (Target) | Financial system of record -- GL, AP, AR | Varies (REST, OData, SOAP, File Import) | Inbound from T&E |
| iPaaS (Optional) | Integration orchestrator -- Workato, Boomi, MuleSoft, Celigo | Varies | Orchestrator |

## API Surfaces & Capabilities

| T&E Platform | Export Method | Format | Real-time? | Pre-built ERP Connectors | Custom API Available? |
|---|---|---|---|---|---|
| SAP Concur | Financial Integration API v4 | JSON (financial documents) | Near-real-time (poll) | SAP S/4HANA, Oracle, NetSuite, Dynamics 365, Sage Intacct | Yes -- REST API |
| SAP Concur | Standard Accounting Extract (SAE) | Flat file (pipe-delimited) | Batch (scheduled) | Any ERP with file import | N/A -- file-based |
| Expensify | Integration Server API | JSON (reports, transactions) | On-demand (API call) | NetSuite, QBO, Xero, Sage Intacct, Oracle | Yes -- REST API |
| Navan | Direct Integration | JSON | Near-real-time | NetSuite, Sage Intacct, QBO | Limited -- SFTP + API |
| Navan | SFTP Export | CSV/JSON | Batch (scheduled) | Any ERP with file import | N/A -- file-based |
| Brex | Accounting API v1 | JSON | Real-time (two-way sync) | NetSuite, QBO, Xero, Sage Intacct | Yes -- REST API |
| Ramp | Developer API v1 | JSON | Real-time (sync) | NetSuite, Oracle Fusion, Sage Intacct, QBO, Xero | Yes -- REST API |

[src1, src3, src4, src5, src8]

## Rate Limits & Quotas

### Per-Request Limits

| T&E Platform | Limit Type | Value | Notes |
|---|---|---|---|
| SAP Concur | Max financial documents per fetch | 100 per page | Paginate with `nextPage` link |
| SAP Concur | Expense Report API v4 query | 100 reports per page | Use `start` parameter for pagination |
| Expensify | Max report export batch | 1 concurrent request per credential pair | Queue exports sequentially |
| Brex | Max transactions per page | 1,000 | Cursor-based pagination |
| Ramp | Max records per page | 100 | Cursor-based pagination |
| Ramp | Accounting sync batch | 500 GL codes per sync | Split larger code sets |

[src1, src3, src4]

### Rolling / Daily Limits

| T&E Platform | Limit Type | Value | Window | Notes |
|---|---|---|---|---|
| SAP Concur | API calls (OAuth app) | 24,000 requests/hr for Financial Integration | Rolling hourly | Shared across all API surfaces |
| Expensify | API requests | No published hard limit | N/A | Subject to fair-use throttling |
| Brex | API calls | Rate-limited per endpoint | Per minute | 429 response with retry-after header |
| Ramp | API calls | Rate-limited per endpoint | Per minute | 429 response with retry-after header |
| Navan | SFTP export frequency | Configurable (min 1hr) | Scheduled | Direct API rate limits not publicly documented |

[src1, src4, src5]

## Authentication

| T&E Platform | Auth Method | Mechanism | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|---|
| SAP Concur | OAuth 2.0 | JWT bearer (company-level) or Authorization Code (user-level) | Access: 1h, Refresh: 6 months | Yes | Company JWT for Financial Integration API; User OAuth for Expense API |
| Expensify | Static credentials | partnerUserID + partnerUserSecret | Unlimited (until revoked) | No | Generated in Expensify admin; one pair per integration |
| Navan | API Key | Bearer token in header | Long-lived (until rotated) | No | Issued by Navan support for enterprise customers |
| Brex | OAuth 2.0 | Authorization Code flow | Access: 1h | Yes | Scopes: accounting.read, accounting.write, transactions.read |
| Ramp | OAuth 2.0 | Authorization Code flow | Access: 1h | Yes | Scopes: accounting:read, accounting:write, transactions:card:read |

[src1, src3, src4, src5]

### Authentication Gotchas

- SAP Concur company-level JWT requires a one-time admin grant in the Concur admin UI -- cannot be created programmatically. The refresh token expires after 6 months of non-use, silently breaking integrations that run infrequently. [src1]
- Expensify's partnerUserID is tied to a specific Expensify account admin. If that admin leaves the company, the integration breaks. Document the credential owner in your runbook. [src3]
- Brex's OAuth scopes changed significantly with the Accounting API launch. Legacy API keys from pre-2025 integrations do NOT work with the new Accounting API endpoints. [src5]

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

- SAP Concur Financial Integration API only returns documents in `approved` status. You cannot pull pending, submitted, or recalled reports. If you need pre-approval visibility, use the Reports API v4 separately.
- Expensify Integration Server processes one export request at a time per credential pair. Concurrent calls will queue, not parallelize. Design for sequential batch processing.
- Navan direct ERP integrations only support NetSuite, Sage Intacct, and QuickBooks Online as of March 2026. SAP, Oracle, and Dynamics 365 require custom SFTP or API integration via iPaaS.
- Brex Accounting API mandates bidirectional sync for real-time mode. You must push GL account/dimension mappings FROM the ERP TO Brex before transactions flow back. One-way export requires batch CSV mode instead.
- Corporate card transaction data typically arrives 24-48 hours after the transaction posts with the card network. Do not design GL posting workflows that assume same-day card data availability.
- Multi-currency expense reports create exchange rate timing risk. The T&E system captures the rate at transaction time; the ERP may use the rate at posting time. Decide which rate governs BEFORE go-live and configure both systems to match.
- Tax reclaim rules (especially VAT in EU/UK) require the T&E system to capture itemized receipt data and tax codes. Not all T&E platforms support per-line-item tax coding for all jurisdictions.

## Integration Pattern Decision Tree

```
START -- Integrate T&E platform with ERP
|
+-- Which T&E platform?
|   +-- SAP Concur
|   |   +-- SAP S/4HANA or ECC as ERP?
|   |   |   +-- YES --> Use Concur-SAP standard connector (pre-built, certified)
|   |   |   +-- NO --> Use Financial Integration API v4 (poll for approved docs, POST confirmation)
|   |   +-- Need pre-approval data?
|   |       +-- YES --> Reports API v4 (separate from Financial Integration)
|   |       +-- NO --> Financial Integration API v4 only
|   |
|   +-- Expensify
|   |   +-- NetSuite, QBO, Xero, or Sage Intacct?
|   |   |   +-- YES --> Use Expensify native integration (configure in Policy > Connections)
|   |   |   +-- NO --> Use Integration Server API (export as journal entries or vendor bills)
|   |   +-- Export format?
|   |       +-- Journal entries --> GL debit/credit pairs
|   |       +-- Vendor bills --> AP subledger (employee as vendor)
|   |       +-- Credit card charges --> Corporate card clearing account
|   |
|   +-- Navan
|   |   +-- NetSuite, Sage Intacct, or QBO?
|   |   |   +-- YES --> Use Navan direct integration
|   |   |   +-- NO --> SFTP export + custom file import to ERP
|   |   +-- Need travel booking data alongside expenses?
|   |       +-- YES --> Navan uniquely combines booking + expense in one export
|   |       +-- NO --> Expense-only export via SFTP or API
|   |
|   +-- Brex
|   |   +-- Need real-time sync?
|   |   |   +-- YES --> Accounting API (bidirectional, push GL codes to Brex first)
|   |   |   +-- NO --> CSV batch export
|   |   +-- Using Brex AI auto-coding?
|   |       +-- YES --> Let Brex code, then sync coded transactions to ERP
|   |       +-- NO --> Push GL codes from ERP to Brex, then sync back
|   |
|   +-- Ramp
|       +-- Oracle Fusion, NetSuite, Sage Intacct, or QBO?
|       |   +-- YES --> Use Ramp native accounting sync (real-time)
|       |   +-- NO --> Developer API v1 + custom mapping
|       +-- Using Ramp Accounting Agent (AI)?
|           +-- YES --> Agent auto-codes and posts low-risk transactions
|           +-- NO --> Manual review queue before ERP sync
|
+-- Corporate card reconciliation needed?
|   +-- YES --> See "Corporate Card Reconciliation" section below
|   +-- NO --> Expense report journal posting only
|
+-- Multi-entity / intercompany?
    +-- YES --> Configure entity mapping in T&E platform; route journals per entity
    +-- NO --> Single-entity standard flow
```

## Quick Reference

### End-to-End Integration Flow

| Step | Source System | Action | Target System | Data Objects | Failure Handling |
|---|---|---|---|---|---|
| 1 | Employee (mobile/web) | Capture receipt, create expense line | T&E Platform | Expense entry, receipt image, merchant data | Auto-retry OCR; manual entry fallback |
| 2 | T&E Platform | Apply policy rules, auto-code GL account | T&E Platform | Expense type -> GL account mapping, cost center | Flag out-of-policy items for manager review |
| 3 | T&E Platform | Route for approval (manager, finance) | T&E Platform | Approval workflow, delegation rules | Escalation after SLA breach (configurable) |
| 4 | T&E Platform | Mark report as approved, lock for export | T&E Platform | Approved expense report | Reopen if rejected at any approval level |
| 5 | T&E Platform (API) | Export approved report as financial document | iPaaS / Custom | Journal lines: debit expense, credit payable | Retry 3x with exponential backoff, then DLQ |
| 6 | iPaaS / Custom | Transform T&E data to ERP journal format | ERP | Journal entry (debit expense accounts, credit AP/clearing) | Validate GL codes before posting; reject unknown codes |
| 7 | ERP | Post journal entry, create payable | ERP | GL journal, AP voucher | Duplicate check on external reference ID |
| 8 | ERP | Process reimbursement (AP payment run or payroll) | Bank / Payroll | Payment instruction, ACH/wire | Reconcile payment against posted journal |
| 9 | iPaaS / Custom | Post confirmation back to T&E platform | T&E Platform | Posting status, ERP document ID | Update T&E status to "posted" or "failed" |
| 10 | Card Network | Feed corporate card transactions | T&E Platform | Card transaction (merchant, amount, date, MCC) | Match to expense entries; flag orphaned transactions |

[src1, src2, src6, src7]

## Step-by-Step Integration Guide

### 1. Configure GL Account Mapping in the T&E Platform

Before building any API integration, map your ERP chart of accounts into the T&E platform. Every T&E system maintains its own expense type list that must map 1:1 to GL natural accounts. [src6, src7]

| T&E Expense Type | GL Natural Account | GL Account Name | Cost Center Source |
|---|---|---|---|
| Airfare | 6200-100 | Travel - Air | Employee's department |
| Hotel/Lodging | 6200-200 | Travel - Lodging | Employee's department |
| Meals - Client | 6300-100 | Entertainment - Client | Project code |
| Meals - Employee | 6200-300 | Travel - Meals | Employee's department |
| Ground Transport | 6200-400 | Travel - Ground | Employee's department |
| Mileage | 6200-500 | Travel - Mileage | Employee's department |
| Office Supplies | 6500-100 | Office Supplies | Employee's department |
| Software/SaaS | 6600-100 | Software Subscriptions | IT cost center |
| Conference/Training | 6400-100 | Professional Development | Employee's department |

**Verify**: Export a test expense report and confirm every line maps to a valid GL code in your ERP. Zero unmapped lines = ready for production.

### 2. Set Up Authentication for Your T&E Platform API

**SAP Concur (OAuth 2.0 JWT Bearer)**: [src1]

```bash
# Step 1: Exchange company request token for refresh token (one-time admin action)
curl -X POST "https://us2.api.concursolutions.com/oauth2/v0/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=password&username=COMPANY_UUID&credtype=authtoken&password=COMPANY_REQUEST_TOKEN"

# Step 2: Use refresh token to get access token (automated, per-session)
curl -X POST "https://us2.api.concursolutions.com/oauth2/v0/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=refresh_token&refresh_token=YOUR_REFRESH_TOKEN"
```

**Verify**: Response includes `access_token` and `token_type: "Bearer"`. Token expires in 3600 seconds.

**Expensify (Static Credentials)**: [src3]

```bash
# Expensify uses form-encoded POST with static credentials
curl -X POST "https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations" \
  -d 'requestJobDescription={"type":"get","credentials":{"partnerUserID":"YOUR_ID","partnerUserSecret":"YOUR_SECRET"},"inputSettings":{"type":"combinedReportData","filters":{"status":"APPROVED"}}}'
```

**Verify**: Response returns JSON with approved reports list. Non-empty array = credentials work.

### 3. Poll for Approved Expense Reports (SAP Concur Example)

The Financial Integration API v4 returns approved documents ready for ERP posting. Poll this endpoint on a schedule (every 15-60 minutes). [src1, src2]

```bash
# Fetch approved financial documents (expense reports ready for posting)
curl -X GET "https://us2.api.concursolutions.com/financialintegration/fi/v4/companies/transactiontypes/expense/transactions?limit=100" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
```

Response includes journal line items with:
- `accountCode` -- GL natural account from expense type mapping
- `orgUnit1` through `orgUnit6` -- cost center, department, project dimensions
- `journalAmount` -- amount in posting currency
- `journalPayee` -- employee (for reimbursable) or card program (for corporate card)
- `taxAmount` and `taxCode` -- for VAT/GST reclaim

**Verify**: Each document has `systemId` for idempotent posting. Store this to prevent duplicate journals.

### 4. Transform T&E Data to ERP Journal Entry Format

Map the T&E financial document to your ERP's journal entry schema. The core pattern is always the same. [src2, src6]

```python
# Input:  Concur financial document JSON (approved expense report)
# Output: ERP journal entry with debit/credit lines

def transform_expense_to_journal(concur_doc):
    """Transform Concur financial document to ERP journal entry."""
    journal = {
        "reference": concur_doc["systemId"],  # Idempotency key
        "posting_date": concur_doc["approvalDate"],
        "description": f"Expense Report: {concur_doc['reportName']}",
        "lines": []
    }

    for entry in concur_doc["reportEntries"]:
        for allocation in entry.get("allocations", [entry]):
            # DEBIT: Expense account
            journal["lines"].append({
                "account": allocation["accountCode"],
                "debit": allocation["journalAmount"],
                "credit": 0,
                "cost_center": allocation.get("orgUnit1", ""),
                "project": allocation.get("orgUnit2", ""),
                "description": entry["expenseTypeName"],
                "tax_code": allocation.get("taxCode", ""),
            })

    # CREDIT: AP payable (reimbursable) or clearing account (corporate card)
    total = sum(line["debit"] for line in journal["lines"])
    if concur_doc["paymentType"] == "COMPANY_PAID":
        credit_account = "2100-200"  # Corporate card clearing account
    else:
        credit_account = "2100-100"  # Employee AP / reimbursement payable

    journal["lines"].append({
        "account": credit_account,
        "debit": 0,
        "credit": total,
        "cost_center": "",
        "description": f"Payable: {concur_doc['employeeName']}",
    })

    return journal
```

**Verify**: Sum of debits == sum of credits for every journal entry. Any imbalance = transformation bug.

### 5. Post Journal Entry to ERP

Post the transformed journal to your ERP. Use the T&E system's document ID as the external reference for idempotent duplicate prevention. [src7]

```python
# Input:  Transformed journal entry dict
# Output: ERP posting confirmation (document number)

import requests

def post_journal_to_netsuite(journal, netsuite_config):
    """Post journal entry to NetSuite via SuiteTalk REST API."""
    headers = {
        "Authorization": f"Bearer {netsuite_config['token']}",
        "Content-Type": "application/json",
        "Prefer": "respond-async"  # For large batches
    }

    ns_journal = {
        "tranDate": journal["posting_date"],
        "memo": journal["description"],
        "externalId": journal["reference"],  # Idempotency: Concur systemId
        "line": {
            "items": [
                {
                    "account": {"id": resolve_ns_account(line["account"])},
                    "debit": line["debit"] if line["debit"] > 0 else None,
                    "credit": line["credit"] if line["credit"] > 0 else None,
                    "department": {"id": resolve_ns_dept(line["cost_center"])},
                    "memo": line["description"],
                }
                for line in journal["lines"]
            ]
        }
    }

    resp = requests.post(
        f"{netsuite_config['base_url']}/record/v1/journalEntry",
        headers=headers,
        json=ns_journal,
        timeout=30
    )

    if resp.status_code == 204:
        return {"status": "posted", "ns_id": resp.headers.get("Location")}
    elif resp.status_code == 409:
        return {"status": "duplicate", "message": "Already posted (externalId match)"}
    else:
        raise Exception(f"ERP posting failed: {resp.status_code} {resp.text}")
```

**Verify**: ERP returns 204 (created) or 409 (duplicate). Any other status = investigate before retrying.

### 6. Send Posting Confirmation Back to T&E Platform

After successful ERP posting, confirm back to the T&E platform so the document is locked and marked as posted. [src1]

```bash
# SAP Concur: Acknowledge financial document as posted
curl -X POST "https://us2.api.concursolutions.com/financialintegration/fi/v4/companies/transactiontypes/expense/transactions/postingconfirmations" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "systemId": "CONCUR_SYSTEM_ID",
    "postingDocs": [{
      "docId": "DOCUMENT_ID",
      "postingStatus": "SUCCESS",
      "systemMessages": "Posted to ERP as Journal #JE-2026-00042"
    }]
  }'
```

**Verify**: Concur marks the document status as `POSTED`. It will no longer appear in future Financial Integration API polls.

### 7. Configure Corporate Card Feed and Reconciliation

Corporate card reconciliation uses a clearing account pattern. The card network feeds transactions to the T&E platform, and the journal pattern differs from out-of-pocket expenses. [src6]

```
Card Transaction Flow:
1. Employee swipes corporate card --> Card network records transaction
2. Card network feeds transaction to T&E platform (24-48h delay)
3. T&E platform matches transaction to expense entry (auto-match or manual)
4. Manager approves expense report containing card transactions
5. Export to ERP:
   - DEBIT: Expense account (per GL mapping)       $500.00
   - CREDIT: Corporate card clearing account        $500.00
6. Monthly card statement settles:
   - DEBIT: Corporate card clearing account         $12,450.00
   - CREDIT: Bank/cash account                      $12,450.00
7. Reconcile: Clearing account balance should be $0 after settlement
```

**Verify**: At month-end, the corporate card clearing account balance should equal the sum of approved-but-not-yet-settled card transactions. Any other balance = reconciliation issue.

## Code Examples

### Python: Expensify Report Export and GL Transform

```python
# Input:  Expensify API credentials, date range
# Output: List of journal entries ready for ERP posting

import requests

def export_expensify_reports(partner_id, partner_secret, start_date, end_date):
    """Export approved Expensify reports as journal-ready data."""
    payload = {
        "type": "get",
        "credentials": {
            "partnerUserID": partner_id,
            "partnerUserSecret": partner_secret
        },
        "inputSettings": {
            "type": "combinedReportData",
            "filters": {
                "status": "APPROVED",
                "startDate": start_date,  # YYYY-MM-DD
                "endDate": end_date
            }
        }
    }

    resp = requests.post(
        "https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations",
        data={"requestJobDescription": json.dumps(payload)},
        timeout=60
    )

    reports = resp.json()
    journals = []

    for report in reports:
        journal_lines = []
        for expense in report["expenses"]:
            journal_lines.append({
                "account": expense["category"],  # Maps to GL account
                "debit": float(expense["amount"]) / 100,  # Expensify uses cents
                "cost_center": expense.get("tag", ""),
                "description": expense["merchant"],
            })

        total = sum(l["debit"] for l in journal_lines)
        # Credit line depends on payment type
        if report.get("hasCompanyCard"):
            credit_account = "2100-200"  # Card clearing
        else:
            credit_account = "2100-100"  # Employee reimbursement payable

        journal_lines.append({
            "account": credit_account,
            "credit": total,
            "description": f"Payable: {report['submitterEmail']}",
        })

        journals.append({
            "reference": report["reportID"],
            "lines": journal_lines
        })

    return journals
```

[src3]

### JavaScript/Node.js: Ramp Transaction Sync

```javascript
// Input:  Ramp OAuth token, last sync timestamp
// Output: New card transactions with GL coding for ERP posting

const axios = require('axios'); // ^1.7.0

async function syncRampTransactions(accessToken, lastSyncTime) {
  const transactions = [];
  let cursor = null;

  do {
    const params = new URLSearchParams({
      from_date: lastSyncTime,
      page_size: '100',
    });
    if (cursor) params.set('start', cursor);

    const resp = await axios.get(
      `https://demo-api.ramp.com/developer/v1/transactions?${params}`,
      {
        headers: { Authorization: `Bearer ${accessToken}` },
        timeout: 30000,
      }
    );

    for (const txn of resp.data.data) {
      if (txn.accounting_field_selections?.length > 0) {
        transactions.push({
          reference: txn.id,
          date: txn.user_transaction_time,
          merchant: txn.merchant_name,
          amount: txn.amount,  // In cents
          currency: txn.currency_code,
          gl_account: txn.accounting_field_selections.find(
            f => f.type === 'GL_ACCOUNT'
          )?.external_id,
          cost_center: txn.accounting_field_selections.find(
            f => f.type === 'COST_CENTER'
          )?.external_id,
          cardholder: txn.card_holder?.full_name,
          receipt_urls: txn.receipts?.map(r => r.receipt_url) || [],
        });
      }
    }

    cursor = resp.data.page?.next;
  } while (cursor);

  return transactions;
}
```

[src4]

### cURL: Brex Accounting API -- Push GL Codes and Fetch Coded Transactions

```bash
# Step 1: Push GL account list from ERP to Brex (required before sync)
curl -X POST "https://platform.brexapis.com/v2/accounting/accounts" \
  -H "Authorization: Bearer YOUR_BREX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "accounts": [
      {"id": "6200-100", "name": "Travel - Air", "type": "EXPENSE"},
      {"id": "6200-200", "name": "Travel - Lodging", "type": "EXPENSE"},
      {"id": "6300-100", "name": "Entertainment - Client", "type": "EXPENSE"},
      {"id": "2100-200", "name": "Corp Card Clearing", "type": "LIABILITY"}
    ]
  }'

# Step 2: Fetch coded transactions ready for ERP posting
curl -X GET "https://platform.brexapis.com/v2/transactions/card?posted_at_start=2026-03-01T00:00:00Z&expand[]=accounting" \
  -H "Authorization: Bearer YOUR_BREX_TOKEN"
```

[src5]

## Data Mapping

### Field Mapping Reference

| T&E Field (Generic) | SAP Concur Field | Expensify Field | Ramp/Brex Field | ERP Target (GL Journal) | Gotcha |
|---|---|---|---|---|---|
| Expense amount | `journalAmount` | `amount` (cents) | `amount` (cents) | Debit amount | Expensify/Ramp/Brex use cents; divide by 100 |
| GL account | `accountCode` | `category` | `gl_account` (external_id) | Natural account code | Must match ERP chart of accounts exactly |
| Cost center | `orgUnit1` | `tag` | `cost_center` (external_id) | Cost center dimension | Tag mapping varies by Expensify policy |
| Project code | `orgUnit2` | `tag` (if multi-tag) | Custom field | Project dimension | Multi-tag support varies by T&E platform |
| Employee name | `employeeName` | `submitterEmail` | `card_holder.full_name` | Vendor/payee name | Some ERPs require employee as vendor record |
| Transaction date | `transactionDate` | `created` | `user_transaction_time` | Journal date | T&E captures swipe date; ERP may want posting date |
| Currency code | `transactionCurrencyCode` | `currency` | `currency_code` | Transaction currency | Multi-currency requires rate agreement |
| Payment type | `paymentType` | `reimbursable` flag | Card-only (always company-paid) | Credit account selection | Determines clearing account vs AP payable |
| Receipt image URL | `receiptImageUrl` | `receipt.url` | `receipts[].receipt_url` | Attachment | Not all ERPs support attachment via API |
| Report ID | `systemId` | `reportID` | `id` | External reference | Critical for idempotent duplicate prevention |

### Data Type Gotchas

- SAP Concur `journalAmount` is in the posting currency with the sign indicating debit (+) or credit (-). Expensify and Ramp always report positive amounts -- you determine debit/credit from context. [src1, src3]
- Expensify amounts are in cents (integer). A $42.50 expense is `amount: 4250`. Concur uses decimal with currency precision. Brex and Ramp also use cents. Always check the API docs for the amount format. [src3, src4]
- Date formats differ: Concur uses ISO 8601 with timezone (`2026-03-03T14:30:00Z`); Expensify uses `YYYY-MM-DD`; Ramp uses ISO 8601. Normalize to your ERP's expected format before posting. [src1, src3, src4]
- Multi-tag support in Expensify depends on the policy configuration. A "tag" can be a single value or a colon-separated multi-level string like `DeptA:ProjectX:TaskY`. Parse accordingly. [src3]

## Error Handling & Failure Points

### Common Error Codes

| Source | Code | Meaning | Cause | Resolution |
|---|---|---|---|---|
| SAP Concur | 401 | Unauthorized | Expired access token or revoked refresh token | Re-authenticate; check refresh token hasn't expired (6 months non-use) |
| SAP Concur | 404 | Document not found | Report was recalled or deleted after approval | Skip document; log for audit |
| Expensify | 500 | Server error on export | Concurrent export request on same credentials | Wait 60s and retry; serialize exports |
| Brex | 429 | Rate limit exceeded | Too many API calls per minute | Read `Retry-After` header; implement exponential backoff |
| ERP (NetSuite) | 409 | Duplicate record | Journal with same externalId already posted | Log as success (idempotent); do not retry |
| ERP (SAP) | BAPI error | GL account invalid | Expense type mapped to inactive or blocked GL code | Update mapping; validate GL codes monthly |
| Any | Timeout | Request timed out | Large report batch or ERP under load | Reduce batch size; implement circuit breaker |

[src1, src3, src4, src7]

### Failure Points in Production

- **Stale GL account mappings**: Finance closes or renames GL accounts in the ERP but forgets to update the T&E platform. Result: every expense report using that code fails on ERP posting. Fix: `Validate all GL codes against the ERP chart of accounts weekly via automated sync. Alert on any T&E code that maps to an inactive GL account.` [src6]
- **Orphaned corporate card transactions**: Card transactions arrive in the T&E platform but are never matched to an expense report (employee didn't submit). Result: clearing account carries an ever-growing balance. Fix: `Set a policy requiring card transactions to be reported within 60 days. Run monthly aging report on unmatched card transactions. Auto-create expense entries for transactions >90 days old.` [src6, src7]
- **Exchange rate mismatch on multi-currency reports**: T&E system captures rate at transaction date; ERP uses rate at posting date. Result: GL journal doesn't balance in the ERP's functional currency. Fix: `Configure both systems to use the same rate source (e.g., daily ECB rate) and same timing (transaction date, not posting date). Add a FX gain/loss line to absorb residual differences.` [src7]
- **Approval workflow timeout**: Report sits in approval queue for weeks. Manager is on vacation with no delegate. Result: delayed expense reimbursement and stale financial data. Fix: `Configure escalation rules: auto-delegate after 3 business days; auto-approve under $500 after 7 days with audit flag.` [src7]
- **Duplicate journal postings after retry**: Integration retries a failed ERP post, but the first attempt actually succeeded (timeout was on the response, not the request). Result: double-posted journal entries. Fix: `Always use the T&E document ID as externalId/reference. Implement upsert-or-skip logic. Never retry without checking for existing documents first.` [src1, src7]

## Anti-Patterns

### Wrong: Posting Card Transactions Directly to GL Without Expense Report

```
// BAD -- posts raw card feed data to GL as journal entries
// Skips approval workflow, GL coding, policy check, and receipt matching
cardFeed.forEach(txn => {
  postJournal({
    debit: { account: "6200-000", amount: txn.amount },  // Generic "travel" bucket
    credit: { account: "2100-200", amount: txn.amount }
  });
});
```

### Correct: Card Transactions Flow Through T&E Platform First

```
// GOOD -- card transactions are matched to expense entries in T&E platform
// Employee adds business purpose, GL coding, receipt; manager approves
// Only approved, coded, policy-compliant reports export to ERP
approvedReports = pollApprovedReports();
approvedReports.forEach(report => {
  journal = transformToJournal(report);  // Uses proper GL codes per entry
  validateGLCodes(journal);               // Check all codes are active in ERP
  postToERP(journal);                     // Post with externalId for idempotency
  confirmPosting(report.id);              // Lock report in T&E platform
});
```

### Wrong: Real-Time GL Posting Per Individual Expense Entry

```
// BAD -- posts a journal entry every time an employee submits an expense line
// Creates thousands of tiny journals; overwhelms ERP; no approval gate
onExpenseCreated(expense => {
  postJournal(transformSingleExpense(expense));
});
```

### Correct: Batch-Post Approved Reports on a Schedule

```
// GOOD -- polls for approved reports every 30 minutes
// Batches multiple reports into a single ERP posting run
// Respects approval workflow; manageable journal volume
schedule("*/30 * * * *", async () => {
  const approved = await pollApprovedReports();
  const journals = approved.map(transformToJournal);
  const validated = journals.filter(j => validateGLCodes(j));
  await batchPostToERP(validated);  // Posts as batch with idempotency keys
  await confirmPostings(validated.map(j => j.reference));
});
```

### Wrong: Hardcoding GL Account Mappings in Integration Code

```
// BAD -- GL mappings embedded in code; requires deployment to change
function getGLAccount(expenseType) {
  const MAP = { "Airfare": "6200-100", "Hotel": "6200-200", ... };
  return MAP[expenseType] || "6999-999";  // Unknown bucket
}
```

### Correct: GL Mappings in Configurable Table Synced from ERP

```
// GOOD -- GL mappings stored in database/config, synced from ERP chart of accounts
// Finance team can update mappings without code deployment
async function getGLAccount(expenseType) {
  const mapping = await db.query(
    "SELECT gl_code FROM expense_gl_mapping WHERE expense_type = $1 AND active = true",
    [expenseType]
  );
  if (!mapping) throw new Error(`No active GL mapping for: ${expenseType}`);
  return mapping.gl_code;
}
```

## Common Pitfalls

- **Ignoring the clearing account balance**: The corporate card clearing account should trend toward zero each month. If the balance grows, it means card transactions are being settled (cash going out) but not matched to approved expense reports (journal entries not posted). Fix: `Monitor clearing account balance weekly. Aging > 30 days = investigate. Aging > 90 days = write policy for auto-reporting.` [src6]
- **Not validating GL codes before ERP posting**: GL accounts get deactivated, renamed, or restructured during annual chart-of-accounts maintenance. If your integration doesn't validate codes against the live ERP chart before posting, you get batch failures every January. Fix: `Sync GL code list from ERP to T&E platform monthly. Block invalid codes at the T&E platform level so employees can't use them.` [src7]
- **Treating all T&E platforms' amount formats the same**: Concur uses decimal (42.50), Expensify uses cents (4250), Ramp uses cents (4250). A missed conversion means expenses are either 100x too large or too small. Fix: `Write a normalization layer per T&E platform with unit tests for amount conversion.` [src1, src3, src4]
- **Forgetting to handle partial approvals**: Some T&E platforms allow managers to approve a report but reject specific lines. If your integration exports the report as "approved" without checking line-level status, you post rejected expenses to the GL. Fix: `Check both report-level AND line-level approval status. Only export lines with status = approved.` [src1]
- **No idempotency on ERP posting**: Network timeouts cause retries, and without idempotency keys, you get duplicate journal entries that only surface during month-end reconciliation. Fix: `Always set externalId on the ERP journal entry using the T&E document/report ID. Implement upsert-or-skip.` [src7]
- **Skipping posting confirmation back to T&E platform**: If you don't confirm back to Concur/Expensify that the journal was posted, the document remains in the "approved" queue and gets re-exported on the next poll. Fix: `Always close the loop: POST confirmation back to T&E after successful ERP posting.` [src1]

## Diagnostic Commands

```bash
# SAP Concur: Check for pending financial documents (approved but not yet posted)
curl -X GET "https://us2.api.concursolutions.com/financialintegration/fi/v4/companies/transactiontypes/expense/transactions?limit=10" \
  -H "Authorization: Bearer YOUR_TOKEN"
# Expected: JSON array of pending documents; empty = all posted

# SAP Concur: Verify OAuth token validity
curl -X GET "https://us2.api.concursolutions.com/profile/v1/me" \
  -H "Authorization: Bearer YOUR_TOKEN"
# Expected: 200 with user profile; 401 = token expired

# Expensify: Test API credentials and list available reports
curl -X POST "https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations" \
  -d 'requestJobDescription={"type":"get","credentials":{"partnerUserID":"YOUR_ID","partnerUserSecret":"YOUR_SECRET"},"inputSettings":{"type":"reportStatus"}}'
# Expected: JSON with report count by status

# Ramp: Check API connectivity and list recent transactions
curl -X GET "https://demo-api.ramp.com/developer/v1/transactions?page_size=5" \
  -H "Authorization: Bearer YOUR_TOKEN"
# Expected: 200 with transaction list; 401 = token invalid; 429 = rate limited

# ERP (NetSuite): Verify GL account exists and is active
curl -X GET "https://YOUR_ACCOUNT.suitetalk.api.netsuite.com/services/rest/record/v1/account?q=acctNumber IS '6200-100'" \
  -H "Authorization: Bearer YOUR_TOKEN"
# Expected: 200 with account record; empty = account doesn't exist or is inactive

# Check clearing account balance (run in ERP or via API)
# Balance should approach zero after monthly card settlement
# Positive balance = unsettled card transactions awaiting matching
```

## Version History & Compatibility

| Platform | API Version | Release Date | Status | Breaking Changes | Notes |
|---|---|---|---|---|---|
| SAP Concur | Financial Integration API v4 | 2023-06 | Current (GA) | Replaced v3 Extract API | v3 Extract still operational but no new features |
| SAP Concur | Expense Report API v4 | 2022-01 | Current (GA) | User v1 Form Fields sunset June 2026 | Migrate to v4 fields before deadline |
| SAP Concur | Expense API v1-v3 | Legacy | Deprecated | N/A | Use v4 for all new development |
| Expensify | Integration Server v1 | 2015 | Current (GA) | None recent | Stable but limited feature additions |
| Navan | Expense API v1 | 2024 | Current (GA) | N/A | SFTP export remains primary method |
| Brex | Accounting API v1 | 2025-01 | Current (GA) | Legacy API keys incompatible | Re-authenticate with OAuth 2.0 for new API |
| Ramp | Developer API v1 | 2024-06 | Current (GA) | None | Accounting Agent (AI) added 2025 |

[src1, src3, src4, src5]

### Deprecation Policy

SAP Concur provides minimum 12 months notice before API deprecation, with sunset dates published in Developer Center release notes. Expensify has not deprecated its Integration Server API since launch. Brex and Ramp iterate rapidly -- subscribe to their developer changelog for breaking changes. Navan provides migration guides for direct integration updates. [src1, src5]

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Employee expense reports need to post as GL journals with proper coding | Vendor invoices / AP processing (not employee expenses) | AP Automation Integration playbook |
| Corporate card transactions need reconciliation against expense reports | Simple card feed to bank statement reconciliation (no GL coding) | Bank reconciliation tools in your ERP |
| Multi-level approval workflows must gate GL posting | Single-person company with no approval requirements | Direct card feed import in QuickBooks/Xero |
| >50 employees submitting expenses monthly | <10 employees with occasional expenses | Manual entry; automation ROI is negative |
| Multi-entity or multi-currency expense processing | Single entity, single currency, domestic travel only | Native T&E platform export (no custom integration needed) |
| Audit trail required from receipt to GL journal | Informal expense tracking without compliance requirements | Spreadsheet-based tracking |
| Per diem rules, mileage calculations, or GST/VAT reclaim needed | Standard reimbursement without tax complexity | Simpler T&E platform native export |

## Cross-System Comparison

| Capability | SAP Concur | Expensify | Navan | Brex | Ramp |
|---|---|---|---|---|---|
| **ERP Integration API** | Financial Integration API v4 (dedicated) | Integration Server API | SFTP + limited API | Accounting API v1 (bidirectional) | Developer API v1 + Accounting Agent |
| **Pre-built ERP connectors** | SAP, Oracle, NetSuite, D365, Sage | NetSuite, QBO, Xero, Sage | NetSuite, Sage Intacct, QBO | NetSuite, QBO, Xero, Sage | NetSuite, Oracle Fusion, Sage, QBO, Xero |
| **Real-time sync** | Near-real-time (poll) | On-demand (API call) | Batch (SFTP schedule) | Real-time (two-way) | Real-time (auto-sync) |
| **AI auto-coding** | SmartExpense (receipt OCR) | SmartScan (receipt OCR) | Limited | AI accounting (Jan 2026) | Accounting Agent (AI) |
| **Corporate card** | Card feed integration | Expensify Card | Navan Card | Brex Card (native) | Ramp Card (native) |
| **Travel booking** | Concur Travel (integrated) | No | Navan Travel (core product) | No | No |
| **Multi-entity** | Yes (advanced config) | Yes (policy-level) | Yes | Yes | Yes |
| **Multi-currency** | Yes (with exchange rate config) | Yes | Yes | Yes | Yes |
| **Posting confirmation** | Yes (API callback) | No (one-way export) | No (SFTP-based) | Yes (two-way sync) | Yes (sync status) |
| **Best for** | Large enterprise, SAP shops | SMB, simple workflows | Travel-heavy companies | Card-first, real-time finance | Card-first, AI-driven automation |

## Important Caveats

- T&E platform vendor landscape is shifting rapidly: Brex was acquired by Capital One in January 2026, which may affect the Accounting API roadmap. Monitor vendor announcements for changes to integration capabilities.
- SAP Concur's User v1 Form Fields will be decommissioned on June 30, 2026. Integrations using v1 form field references in the Financial Integration API must migrate to v4 fields before this date.
- Pre-built ERP connectors handle 80% of use cases but often lack support for custom GL dimensions, project codes, or intercompany allocations. Budget for custom configuration even with "native" integrations.
- Corporate card reconciliation assumes the T&E platform receives ALL card transactions. If employees use the corporate card for non-expense items (e.g., team purchases routed to procurement), those transactions pollute the clearing account. Implement card controls to restrict usage or create a separate GL flow for non-T&E card spend.
- Rate limits and API capabilities documented here reflect March 2026 status. All five T&E platforms update their APIs quarterly. Always verify against current developer documentation before implementation.

## Related Units

- [AP Automation Integration](/business/erp-integration/ap-automation-integration/2026) -- handles vendor invoices, not employee expenses
- [Payroll Integration](/business/erp-integration/payroll-erp-integration/2026) -- reimbursement via paycheck rather than AP payment
- [NetSuite REST API](/business/erp-integration/netsuite-rest-api/2026) -- common ERP target for T&E integrations
