Intercompany billing API creates rounding discrepancies in euro-to-yen exchange rate conversions

We’re seeing persistent rounding discrepancies when posting intercompany invoices through the Billing API for EUR to JPY conversions. The API applies exchange rates differently than manual posting in FB60, resulting in 1-3 yen differences per line item that accumulate to significant variances on large invoices.

Example:

  • Manual FB60 posting: EUR 1,234.56 × 163.45 = JPY 201,789
  • API posting: EUR 1,234.56 × 163.45 = JPY 201,791 (2 yen difference)

Our API call:


POST /API_BILLING_DOCUMENT_SRV/A_BillingDocument
{"BillingDocumentType": "F2",
 "SoldToParty": "IC-2000",
 "TransactionCurrency": "EUR",
 "TotalNetAmount": "1234.56"}

I suspect the issue relates to decimal precision configuration, exchange rate rounding rules, or the currency conversion logic applied by the API versus the standard posting transaction. We haven’t implemented explicit reconciliation validation yet, and I’m unclear how to configure the API to match the manual posting behavior. Has anyone resolved similar currency rounding issues with intercompany APIs?

The 1-3 yen discrepancies are typical when dealing with zero-decimal currencies and multi-line invoices. The issue is line-level versus document-level rounding. FB60 calculates each line in EUR, converts to JPY with rounding per line, then sums the totals. The API might be summing EUR amounts first, then converting the total. Both are mathematically valid but produce different results. You need to match the API’s calculation sequence to FB60’s behavior.

Check table TCURR for your exchange rate entries. Verify that the ratio fields (UKURS, FFACT, TFACT) are correctly maintained for EUR/JPY. Also look at transaction OB09 to see if there’s a rounding difference configuration specifically for intercompany postings. Sometimes companies set up special rounding rules for IC transactions that differ from standard customer billing.

Your rounding discrepancies stem from a combination of decimal precision handling, exchange rate calculation sequence, and currency-specific rounding rules. Here’s how to achieve consistent results between API and manual postings:

1. Decimal Precision Configuration

Verify your currency configuration in transaction OB08:


Currency: JPY
Decimals: 0 (zero decimal places)
Rounding: Commercial (0.5 rounds up)

For EUR:


Currency: EUR
Decimals: 2
Rounding: Commercial

In transaction OB22 (Exchange Rate Type configuration), verify:

  • Exchange Rate Type: M (standard)
  • Decimal Places: 5 (for rate precision)
  • Inverted Rate: Not selected for EUR/JPY

The API uses these settings, but the calculation sequence matters more than the configuration.

2. Exchange Rate Rounding Logic

The key difference is WHEN rounding occurs in the calculation chain:

FB60 Manual Posting (Line-by-Line):


Line 1: EUR 1,234.56 × 163.45000 = JPY 201,788.732 → rounds to JPY 201,789
Line 2: EUR 567.89 × 163.45000 = JPY 92,821.6405 → rounds to JPY 92,822
Line 3: EUR 890.12 × 163.45000 = JPY 145,488.114 → rounds to JPY 145,488
Total: JPY 440,099

API Posting (Potential Total-First):


Total EUR: 1,234.56 + 567.89 + 890.12 = EUR 2,692.57
Convert: EUR 2,692.57 × 163.45000 = JPY 440,098.4865 → rounds to JPY 440,098
Difference: 1 JPY due to rounding sequence

To force line-level rounding in the API, include line items explicitly:


POST /API_BILLING_DOCUMENT_SRV/A_BillingDocument
{
  "BillingDocumentType": "F2",
  "SoldToParty": "IC-2000",
  "DocumentCurrency": "EUR",
  "DocumentDate": "2025-07-11",
  "ExchangeRateDate": "2025-07-11",
  "ExchangeRateType": "M",
  "ExchangeRate": "163.45000",
  "to_Item": [
    {
      "BillingDocumentItem": "10",
      "NetAmount": "1234.56",
      "TransactionCurrency": "EUR",
      "AccountingExchangeRate": "163.45000"
    },
    {
      "BillingDocumentItem": "20",
      "NetAmount": "567.89",
      "TransactionCurrency": "EUR",
      "AccountingExchangeRate": "163.45000"
    }
  ]
}

By specifying AccountingExchangeRate at the line item level, you force the API to:

  1. Convert each line individually
  2. Round each result to JPY (0 decimals)
  3. Sum the rounded line totals

This matches FB60’s calculation sequence exactly.

3. Currency Conversion Logic Alignment

Ensure these fields are populated in your API request:

  • ExchangeRateType: Must match FB60 (typically “M” for standard rates)
  • ExchangeRateDate: Date for rate lookup (usually document date)
  • ExchangeRate: Explicit rate value with 5 decimal precision (163.45000)
  • DocumentCurrency: Source currency (EUR)
  • CompanyCodeCurrency: Target currency (JPY) - if different from document currency

The API’s currency conversion follows this logic:


// Pseudocode for API conversion:
1. Lookup exchange rate from TCURR table using ExchangeRateType and ExchangeRateDate
2. For each line item:
   a. Amount_EUR × ExchangeRate = Amount_JPY_unrounded
   b. Apply currency-specific rounding (0 decimals for JPY)
   c. Store rounded Amount_JPY for line
3. Sum all line-level Amount_JPY values for document total
4. Validate sum matches header TotalNetAmount (if provided)

To ensure the API uses the same rate as FB60:

  • Query the rate first: `GET /API_EXCHANGERATE_SRV/A_ExchangeRate?$filter=SourceCurrency eq ‘EUR’ and TargetCurrency eq ‘JPY’ and ExchangeRateDate eq datetime’2025-07-11’
  • Use the returned rate explicitly in your billing document post
  • Include all 5 decimal places (163.45000, not 163.45)

4. Reconciliation Validation

Implement automated reconciliation to catch any remaining discrepancies:


// Pseudocode for validation:
1. After API posting, retrieve the created billing document
   GET /A_BillingDocument('{DocumentNumber}')?$expand=to_Item

2. For each line item, validate:
   a. EUR_amount × Exchange_rate = Expected_JPY_amount (rounded)
   b. Compare Expected_JPY_amount to Actual_JPY_amount from API
   c. Flag if difference > 0 JPY

3. Validate document total:
   a. Sum all line-level JPY amounts
   b. Compare to document header TotalNetAmount in JPY
   c. Acceptable variance: 0 JPY (must be exact)

4. If discrepancy found:
   a. Log the document number and difference
   b. Trigger manual review workflow
   c. Optionally reverse and repost with corrected values

Implement this validation immediately after each API post to catch issues in real-time.

Additional Configuration Checks:

  • Transaction OB09: Verify intercompany-specific rounding rules don’t override standard behavior
  • Transaction OBBS: Check posting period variant allows the document date
  • Transaction OBY6: Confirm company code currency is JPY for the receiving entity
  • Table TCURR: Verify exchange rate entry has correct ratio fields (UKURS=1, FFACT=1, TFACT=1 for direct EUR/JPY rates)

Common Pitfalls to Avoid:

  1. Using TotalNetAmount in header without line items: This forces total-first conversion
  2. Omitting ExchangeRate field: API uses system default which may differ from FB60’s lookup
  3. Wrong decimal precision: Using 163.45 instead of 163.45000 can cause calculation differences
  4. Mixing currency in line items: All lines must use same TransactionCurrency as header
  5. Not specifying ExchangeRateType: Different rate types (M, B, G) yield different rates

Testing Approach:

Create a test case with known values:


Line 1: EUR 100.00 × 163.45000 = JPY 16,345
Line 2: EUR 0.01 × 163.45000 = JPY 1.6345 → rounds to JPY 2
Line 3: EUR 0.01 × 163.45000 = JPY 1.6345 → rounds to JPY 2
Total: JPY 16,349

Post this via API with explicit line items and rates. Compare the resulting JPY amounts to manual FB60 posting of the same data. They should match exactly.

By implementing line-level exchange rate specification, using 5-decimal precision rates, forcing line-by-line conversion sequence, and validating results immediately after posting, you’ll eliminate the rounding discrepancies. The key is matching the API’s calculation flow to FB60’s line-level-then-sum approach rather than sum-then-convert.

JPY is a zero-decimal currency, so rounding happens at the integer level. The difference is likely in when the rounding occurs - before or after multiplying quantity times price. Check if your API is rounding each line item separately versus rounding the total after summing all lines.