Multi-Currency Support

Crane Ledger provides comprehensive multi-currency support for organizations operating internationally. Handle transactions in any currency while maintaining accurate financial records and reporting in your base currency.

Base Currency Setup

Organization Base Currency

Every organization has a primary currency for financial reporting:

{
  "id": "ORG_1234567890abcdef",
  "name": "Global Corporation",
  "base_currency": {
    "code": "USD",
    "name": "US Dollar",
    "symbol": "$",
    "decimal_places": 2
  }
}

Setup during organization creation:

POST /accounts/master
{
  "organization_name": "Global Corp",
  "base_currency_code": "USD",
  "tax_number": "US123456789"
}

Change base currency (requires careful consideration):

PUT /organizations/{org_id}
{
  "base_currency_code": "EUR"
}

Currency Considerations

  • Historical transactions remain in original currencies
  • Exchange rates must be available for conversion
  • Reports recalculate using new base currency
  • Sub-organizations can have different base currencies

Supported Currencies

Currency Catalog

Crane Ledger supports all major world currencies:

// Get all supported currencies
GET /currencies

// Response includes metadata
[
  {
    "id": "CUR_USD",
    "code": "USD",
    "name": "US Dollar",
    "symbol": "$",
    "decimal_places": 2,
    "symbol_first": true,
    "is_active": true
  },
  {
    "id": "CUR_EUR",
    "code": "EUR",
    "name": "Euro",
    "symbol": "€",
    "decimal_places": 2,
    "is_active": true
  },
  {
    "id": "CUR_JPY",
    "code": "JPY",
    "name": "Japanese Yen",
    "symbol": "¥",
    "decimal_places": 0,
    "is_active": true
  }
]

Currency-Specific Rules

Different currencies have unique formatting rules:

CurrencyCodeDecimalsSymbolPosition
US DollarUSD2$Before
EuroEUR2After
Japanese YenJPY0¥Before
British PoundGBP2£Before
Swiss FrancCHF2FrBefore
BitcoinBTC8Before

Exchange Rate Management

Exchange Rate Sources

Exchange rates can come from multiple sources:

// Manual entry
POST /organizations/{org_id}/exchange-rates
{
  "from_currency_id": "CUR_USD",
  "to_currency_id": "CUR_EUR",
  "rate": 0.85,
  "effective_date": "2024-01-15",
  "source": "manual"
}

// External API integration
POST /organizations/{org_id}/exchange-rates/import
{
  "source": "ecb",  // European Central Bank
  "effective_date": "2024-01-15"
}

Rate History

Maintain historical rates for accurate reporting:

{
  "id": "EXR_1234567890abcdef",
  "organization_id": "ORG_1234567890abcdef",
  "from_currency_id": "CUR_USD",
  "to_currency_id": "CUR_EUR",
  "rate": 0.85,
  "effective_date": "2024-01-15",
  "source": "ecb",
  "created_by": "system",
  "created_at": "2024-01-15T08:00:00Z"
}

Rate Lookup

Get current or historical rates:

# Current rate
GET /organizations/{org_id}/exchange-rates/USD/EUR

# Rate for specific date
GET /organizations/{org_id}/exchange-rates/USD/EUR?date=2024-01-15

# All rates for currency pair
GET /organizations/{org_id}/exchange-rates/USD/EUR/history

Currency Conversion in Transactions

Multi-Currency Transaction Structure

Transactions can involve multiple currencies:

{
  "description": "EUR invoice payment",
  "transaction_date": "2024-01-15",
  "currency_id": "CUR_EUR",        // Transaction currency
  "amount": 100.00,                // Amount in EUR
  "entries": [
    {
      "account_id": "ACT_1001",    // USD Cash account
      "entry_type": "debit",
      "amount": 110.00,            // USD equivalent
      "currency_id": "CUR_USD",    // Entry currency
      "currency_rate": 1.10        // USD/EUR rate
    },
    {
      "account_id": "ACT_1101",    // EUR Accounts Receivable
      "entry_type": "credit",
      "amount": 100.00,            // EUR amount
      "currency_id": "CUR_EUR",    // Entry currency
      "currency_rate": 1.10        // USD/EUR rate
    }
  ]
}

Conversion Rules

  1. Entry amounts are always in the entry's currency
  2. Base amounts are calculated using exchange rates
  3. Balance validation ensures total debits = total credits in base currency
  4. Exchange rates are snapshots at transaction time

Automatic Conversion

// System calculates base amounts automatically
function calculateBaseAmount(entryAmount, exchangeRate) {
  return entryAmount / exchangeRate;  // For USD/EUR at 1.10
}

// EUR 100 at rate 1.10 = USD 90.91
calculateBaseAmount(100, 1.10);  // Returns 90.91

Currency Gain/Loss Accounting

Exchange Rate Fluctuations

Currency values change over time, creating gains/losses:

// Invoice created: EUR 100 at rate 1.10 = USD 90.91
// Payment received: EUR 100 at rate 1.05 = USD 95.24
// Result: Currency gain of USD 4.33

// Automatic adjustment entry
{
  "description": "Currency exchange gain",
  "entries": [
    {
      "account_id": "ACT_1101",      // Accounts Receivable
      "entry_type": "debit",
      "amount": 4.33,               // Gain amount
      "currency_id": "CUR_USD"
    },
    {
      "account_id": "ACT_4201",      // Currency Gain account
      "entry_type": "credit",
      "amount": 4.33,
      "currency_id": "CUR_USD"
    }
  ]
}

Gain/Loss Accounts

Set up dedicated accounts for currency adjustments:

// Currency Gain (Revenue account)
{
  "code": "4201",
  "name": "Currency Exchange Gain",
  "type": "revenue"
}

// Currency Loss (Expense account)
{
  "code": "5105",
  "name": "Currency Exchange Loss",
  "type": "expense"
}

Multi-Currency Accounts

Account Currency Assignment

Accounts can hold balances in different currencies:

// Multi-currency bank account
{
  "id": "ACT_1001",
  "code": "1001",
  "name": "Foreign Currency Account",
  "type": "asset",
  "currency_id": "CUR_USD",     // Account currency
  "allow_multi_currency": true  // Allow other currencies
}

// Account balances in multiple currencies
{
  "account_id": "ACT_1001",
  "balances": {
    "USD": 5000.00,
    "EUR": 2500.00,
    "GBP": 1800.00
  },
  "total_base": 9500.00  // Total in base currency
}

Currency-Specific Sub-Accounts

Create separate accounts for each currency:

1001 Cash - USD
1002 Cash - EUR
1003 Cash - GBP
1004 Cash - JPY

Financial Reporting in Multi-Currency

Base Currency Reporting

All reports are generated in the organization's base currency:

// Balance Sheet in USD (base currency)
{
  "assets": {
    "cash_usd": 5000.00,
    "cash_eur": 2272.73,    // EUR 2500 at rate 1.10
    "cash_gbp": 2340.00,    // GBP 1800 at rate 1.30
    "total": 9612.73
  }
}

Currency Breakdown Reports

View balances by currency:

GET /organizations/{org_id}/reports/balance-sheet?by_currency=true

// Response shows balances in each currency
{
  "USD": {
    "assets": 5000.00,
    "liabilities": 2000.00,
    "equity": 3000.00
  },
  "EUR": {
    "assets": 2500.00,
    "liabilities": 1000.00,
    "equity": 1500.00
  }
}

Exchange Rate Impact Analysis

Analyze how currency fluctuations affect financials:

GET /organizations/{org_id}/reports/currency-impact?period=2024-01

// Shows gains/losses by currency pair
{
  "USD_EUR": {
    "transactions": 15,
    "total_gain_loss": 1250.00,
    "rate_change": -0.05
  },
  "USD_GBP": {
    "transactions": 8,
    "total_gain_loss": -350.00,
    "rate_change": 0.02
  }
}

Transaction Examples

Foreign Invoice

// Create invoice in EUR
const invoice = await createInvoice({
  contact_id: "CON_EUR_CUSTOMER",
  currency_id: "CUR_EUR",
  invoice_date: "2024-01-15",
  items: [
    {
      name: "Consulting Services",
      quantity: 10,
      price: 100.00,  // EUR
      currency_id: "CUR_EUR"
    }
  ]
});

// Invoice total: EUR 1,000
// Converted to USD at rate 1.10: USD 909.09

Multi-Currency Payment

// Customer pays in different currency
const payment = await recordInvoicePayment({
  invoice_id: invoice.id,
  amount: 1100.00,        // USD payment
  currency_id: "CUR_USD", // Payment currency
  payment_date: "2024-01-20"
});

// System handles conversion:
// EUR 1,000 invoice at rate 1.10 = USD 909.09
// USD 1,100 payment received
// Result: Overpayment of USD 190.91

Bank Transfer Between Currencies

// Transfer EUR to USD account
const transfer = await createTransfer({
  from_account_id: "ACT_EUR_BANK",
  to_account_id: "ACT_USD_BANK",
  amount: 1000.00,
  currency_id: "CUR_EUR",
  transfer_date: "2024-01-15"
});

// System creates entries:
// Debit EUR Bank: EUR 1,000
// Credit USD Bank: USD 1,100 (at rate 1.10)
// Currency gain/loss: USD 100

Best Practices

Rate Management

  1. Update rates daily - Use reliable sources for current rates
  2. Document sources - Track where rates come from
  3. Set rate policies - Decide when to update (daily, weekly, monthly)
  4. Audit rate changes - Review significant fluctuations

Transaction Recording

  1. Use transaction currency - Record in the currency of the actual transaction
  2. Lock exchange rates - Use rates at time of transaction
  3. Document conversions - Include rate information in descriptions
  4. Separate currency accounts - Consider dedicated accounts per currency

Reporting

  1. Monitor currency exposure - Track balances in foreign currencies
  2. Analyze gain/loss patterns - Identify significant currency impacts
  3. Use base currency for consolidation - Standardize reporting currency
  4. Consider hedge accounting - For significant currency risks

Account Setup

  1. Create currency-specific accounts - Separate accounts for each currency
  2. Use consistent naming - Include currency codes in account names
  3. Set up gain/loss accounts - Dedicated accounts for exchange differences
  4. Enable multi-currency flags - Allow mixed currency entries

Common Challenges

Rate Fluctuation Impact

Challenge: Currency values change between invoice and payment

Solutions:

  • Lock rates at invoice time - Use consistent rates
  • Accept over/under payments - Handle small differences
  • Require payment in invoice currency - Minimize conversions
  • Use forward contracts - Hedge major currency risks

Reporting Complexity

Challenge: Multiple currencies complicate financial analysis

Solutions:

  • Standardize on base currency - All reports in USD/EUR/etc.
  • Provide currency breakdowns - Show original currencies
  • Use exchange rate tables - Document rates used
  • Implement currency controls - Separate currency responsibilities

Compliance Issues

Challenge: Different countries have different currency rules

Solutions:

  • Set organization base currencies - Per local requirements
  • Use appropriate tax currencies - Match local tax authorities
  • Maintain currency trails - Complete audit trails
  • Implement currency restrictions - Limit available currencies

Integration Issues

Challenge: External systems may not support multi-currency

Solutions:

  • Convert at boundaries - Handle conversions at API level
  • Use base currency interfaces - Simplify external integrations
  • Provide currency metadata - Include conversion information
  • Support multiple formats - Accept various currency inputs

Integration Examples

Currency Rate Import

// Import rates from external API
async function importRates() {
  const rates = await fetch('https://api.exchangerate-api.com/v4/latest/USD')
    .then(r => r.json());

  for (const [currency, rate] of Object.entries(rates.rates)) {
    await createExchangeRate({
      from_currency_id: "CUR_USD",
      to_currency_id: `CUR_${currency}`,
      rate: rate,
      source: "exchangerate-api",
      effective_date: new Date().toISOString().split('T')[0]
    });
  }
}

Transaction with Currency Conversion

// Handle payment in different currency
async function processMultiCurrencyPayment(invoiceId, payment) {
  const invoice = await getInvoice(invoiceId);
  const currentRate = await getExchangeRate(
    payment.currency_id,
    invoice.currency_id,
    payment.date
  );

  // Convert payment to invoice currency
  const convertedAmount = payment.amount * currentRate;

  // Record payment with conversion details
  return await recordPayment({
    invoice_id: invoiceId,
    amount: convertedAmount,
    original_amount: payment.amount,
    original_currency: payment.currency_id,
    exchange_rate: currentRate,
    exchange_rate_date: payment.date
  });
}

Currency Gain/Loss Calculation

// Calculate currency adjustments
async function calculateCurrencyAdjustments(transaction) {
  const adjustments = [];

  for (const entry of transaction.entries) {
    if (entry.currency_id !== transaction.currency_id) {
      const currentRate = await getCurrentExchangeRate(
        entry.currency_id,
        transaction.currency_id
      );

      const originalValue = entry.amount / entry.currency_rate;
      const currentValue = originalValue * currentRate;
      const adjustment = currentValue - entry.amount;

      if (Math.abs(adjustment) > 0.01) { // Threshold for small differences
        adjustments.push({
          account_id: entry.account_id,
          amount: adjustment,
          type: adjustment > 0 ? 'gain' : 'loss'
        });
      }
    }
  }

  return adjustments;
}

Performance Considerations

Rate Caching

  • Cache exchange rates - Reduce API calls to external services
  • Set cache expiration - Balance freshness with performance
  • Fallback rates - Use last known rates if external services fail

Query Optimization

  • Pre-calculate base amounts - Store converted values
  • Index currency fields - Optimize currency-based queries
  • Use materialized views - For complex multi-currency reports

Batch Processing

  • Bulk rate updates - Update multiple rates at once
  • Batch conversions - Process multiple transactions together
  • Async processing - Handle large currency recalculations

Multi-currency support enables global business operations while maintaining accurate financial records. Proper exchange rate management and transaction handling ensure compliance and accurate reporting across currencies.


Need help?

Create a free account to access our support portal. Once signed in, use the Support tab in your dashboard to submit a support ticket — our team typically responds within 24 hours.