Skip to main content
Ledger entries are the foundation of Rinne’s financial accounting system. Every monetary movement in the platform—whether a transaction, fee, cost, or refund—is recorded as immutable ledger entries following double-entry bookkeeping principles.

What are ledger entries?

A ledger entry is an immutable accounting record that represents a single monetary movement. Each entry contains:
  • Amount: The monetary value (always positive, stored in cents)
  • Operation: Either CREDIT (money received) or DEBIT (money owed/paid)
  • Type: The economic subject (what the money represents)
  • Owner: Who the entry belongs to (company, platform, or provider)
  • Payment date: When the money is expected to move (date-only format: YYYY-MM-DD)
Ledger entries are always created in balanced pairs or groups called posting sets, where the sum of all credits equals the sum of all debits.

Entity relationships

Core concepts

Posting sets

A posting set is a balanced group of ledger entries created by a single business event (like a transaction approval). Every posting set must net to zero:
Σ(credits) = Σ(debits)
This ensures the integrity of the double-entry accounting system.

Idempotency

Each posting set includes an idempotency_key to prevent duplicate ledger entries when events are replayed. The idempotency key follows the pattern:
  • Transaction approval: transaction-{id}-approved
  • Refund completion: refund-{id}-completed
  • Cashout completion: cashout-{id}-completed
If an event is processed multiple times (e.g., due to retries or system replays), Rinne will detect the existing posting set by its idempotency key and reuse it instead of creating duplicates. This ensures that ledger entries are created exactly once per business event.

Pair tokens

Ledger entries are linked in pairs using a pair_token. Each pair represents a complete accounting transaction with one CREDIT and one DEBIT entry. For example:
  • Merchant receives R100(CREDIT)ProviderpaysR100 (CREDIT) ↔ Provider pays R100 (DEBIT)

Owner types

Ledger entries can belong to three types of owners:
  • COMPANY: Organizations and merchants in your platform
  • PLATFORM: Rinne platform itself
  • PROVIDER: Payment providers (the system records provider-related entries internally)

Ledger entry types

Transaction processing

When a transaction is approved, Rinne creates three public pairs of ledger entries:
The main transaction amount owed to the merchant.Example: R$100 PIX transaction
  • Merchant: R$100 CREDIT (receives money)
  • Provider: R$100 DEBIT (pays merchant)
Commercial fee owed to the organization (parent company).Example: 2.5% fee on R$100 transaction
  • Merchant: R$2.50 DEBIT (pays fee)
  • Organization: R$2.50 CREDIT (receives fee)
Processing fee owed to Rinne platform.Example: 1.0% cost on R$100 transaction
  • Organization: R$1.00 DEBIT (pays cost)
  • Platform: R$1.00 CREDIT (receives cost)

Fee calculation formulas

Fees and costs are calculated using the following formulas:
// Organization fee
organizationFee = Math.round(amount * fee_percentage / 100) + fee_flat
// If fee_minimum_price is set, the fee is at least that amount

// Platform cost  
platformCost = Math.round(amount * cost_percentage / 100) + cost_flat
// If cost_minimum_price is set, the cost is at least that amount
All amounts are integers in cents (no floating-point arithmetic).

Supported payment methods

Rinne creates ledger entries for the following payment methods:
  • PIX: Instant payment, settled same day (D+0)
  • BOLEPIX: Creates the same ledger entry pairs as PIX. Settlement depends on how the BOLEPIX was paid—PIX method when paid via PIX, BOLETO method when paid via boleto.
  • Credit card: Supports installments with separate entries per installment
  • Debit card: Single-installment payment

Refund processing

When a refund is processed, Rinne creates similar pairs but with reversed operations:
Main refund amount returned to customer.Example: R$50 refund
  • Merchant: R$50 DEBIT (returns money)
  • Provider: R$50 CREDIT (processes refund)
Fee returned to the merchant for the refund.Example: 2.5% fee refund on R$50
  • Merchant: R$1.25 CREDIT (receives fee back)
  • Organization: R$1.25 DEBIT (returns fee)
Platform cost for performing the refund operation.Example: 1.0% refund cost on R$50
  • Organization: R$0.50 DEBIT (pays refund cost)
  • Platform: R$0.50 CREDIT (receives refund cost)
Additional refund-related entry types exist in the system:
  • PLATFORM_COST_REFUND: Refund of the original platform cost from the transaction
  • TRANSACTION_REFUND_REVERSAL: Reversal of a refund (e.g., if the refund fails)
Internal entries for provider costs are also recorded but not visible to merchants or organizations.

Cashout processing

Cashouts also generate ledger entries. Unlike transactions, cashouts only create fee/cost pairs (3 pairs) since the transaction amount was already accounted for in previous transactions. The cashout ledger entries track the fees and costs associated with withdrawing funds.

Complete transaction example

Here’s a complete R$100 PIX transaction with the visible ledger entries:
{
  "posting_set": {
    "id": "ps_123",
    "event_name": "transaction.status-changed",
    "idempotency_key": "transaction-tx_123-approved",
    "created_at": "2025-01-15T10:30:00Z"
  },
  "ledger_entries": [
    // 1. Transaction pair (R$100)
    {
      "owner_type": "COMPANY",
      "owner_id": "merchant_123",
      "amount": 10000,
      "operation": "CREDIT",
      "type": "TRANSACTION"
    },
    {
      "owner_type": "PROVIDER",
      "owner_id": "provider",
      "amount": 10000,
      "operation": "DEBIT",
      "type": "TRANSACTION"
    },
    // 2. Organization fee pair (R$2.50)
    {
      "owner_type": "COMPANY",
      "owner_id": "merchant_123",
      "amount": 250,
      "operation": "DEBIT",
      "type": "ORGANIZATION_FEE"
    },
    {
      "owner_type": "COMPANY",
      "owner_id": "org_456",
      "amount": 250,
      "operation": "CREDIT",
      "type": "ORGANIZATION_FEE"
    },
    // 3. Platform cost pair (R$1.00)
    {
      "owner_type": "COMPANY",
      "owner_id": "org_456",
      "amount": 100,
      "operation": "DEBIT",
      "type": "PLATFORM_COST"
    },
    {
      "owner_type": "PLATFORM",
      "owner_id": "RINNE",
      "amount": 100,
      "operation": "CREDIT",
      "type": "PLATFORM_COST"
    }
  ]
}
Balance verification:
  • Credits: R100+R100 + R2.50 + R1.00=R1.00 = R103.50
  • Debits: R100+R100 + R2.50 + R1.00=R1.00 = R103.50 ✓

Settlement tracking

Each ledger entry tracks its settlement status:
  • outstanding_amount: How much is still unsettled
  • settled: Whether the entry is fully settled
  • fully_settled_at: When it became fully settled
  • last_clearing_at: Most recent settlement
Ledger entries start with outstanding_amount = amount and settled = false. As settlement items are created, the outstanding amount decreases until the entry is fully settled.

Payment dates and installments

Payment date calculation

Payment dates are calculated based on the transaction approval date and payment method. “Business day” excludes weekends and official FEBRABAN banking holidays for Brazil.
Payment methodPayment date calculation
PIX / BOLEPIXSame calendar day as approval (D+0)
Debit cardNext business day after approval (skips weekends and FEBRABAN holidays)
Credit card (1st installment)Approval date + 29 calendar days, then next business day (~D+30)
Credit card (subsequent)Approval date + (30 × installment number) calendar days, then next business day

Installment support

For credit card transactions with installments, Rinne creates separate ledger entries for each installment:
{
  "installment": 1,
  "total_installments": 3,
  "amount": 3334,
  "payment_date": "2025-02-14"
},
{
  "installment": 2,
  "total_installments": 3,
  "amount": 3333,
  "payment_date": "2025-03-17"
},
{
  "installment": 3,
  "total_installments": 3,
  "amount": 3333,
  "payment_date": "2025-04-16"
}
The payment_date field is returned in date-only format (YYYY-MM-DD) without time information, as these dates represent calendar days rather than specific timestamps.

Precision and rounding

Rinne uses a two-phase rounding strategy to ensure financial accuracy when splitting amounts across installments.

Math.round with first-installment correction

Phase 1: Per-installment calculation using Math.round

For each installment, the system computes the per-installment value using half-up rounding:
// For each installment, compute the per-installment value:
const installmentValue = Math.round(totalTransactionAmount / numberOfInstallments);
const installmentOrganizationFee = Math.round(organizationFee / numberOfInstallments);
const installmentPlatformCost = Math.round(platformCost / numberOfInstallments);
  • Math.round() (half-up rounding) is applied to every amount type for every installment
  • All amounts are integers in cents (no floating-point)
  • The same logic is applied to all entry types

Phase 2: Balancing adjustments (first-installment correction)

After all installment entries are generated, the system compares the sum of generated entries against the expected totals. Any rounding discrepancy is applied as a correction to the first installment entries. Steps (in correct order):
  1. Calculate expected totals (transaction amount, organization fee, platform cost, etc.)
  2. Sum actual amounts from generated CREDIT entries by type
  3. Compute the difference: expected - actual for each type
  4. If any difference is non-zero, adjust the first installment entries by adding the difference to both amount and outstanding_amount
This ensures that Σ(installments) = expected_total exactly.

Concrete example

Transaction: R$999.00 (99900 cents), 7 installments
- Organization fee: 2.5% = R$24.98 (2498 cents)
- Platform cost: 1.0% = R$9.99 (999 cents)

Math.round per installment:
- Transaction: Math.round(99900/7) = 14271 per installment → 14271 × 7 = 99897 (3 cents short)
- Org fee: Math.round(2498/7) = 357 per installment → 357 × 7 = 2499 (1 cent over)
- Platform cost: Math.round(999/7) = 143 per installment → 143 × 7 = 1001 (2 cents over)

After first-installment correction:
- Transaction: 14274, 14271, 14271, 14271, 14271, 14271, 14271 = 99900 cents (+3 to first)
- Org fees: 356, 357, 357, 357, 357, 357, 357 = 2498 cents (-1 from first)
- Platform costs: 141, 143, 143, 143, 143, 143, 143 = 999 cents (-2 from first)

Zero-amount edge case

When a small total (e.g., 2 cents) is split across many installments (e.g., 12), Math.round(2/12) = 0. The system always creates first-installment entries when the total is greater than 0, and the correction mechanism adds the full amount to that first installment. Result: Installment 1 gets 2 cents, installments 2-12 get no entries for that type.

Refund rounding (different algorithm)

Refund fee distribution uses a different algorithm: Math.floor() for proportional distribution with the last item receiving the remainder (total - accumulated). This ensures exact totals without rounding errors.

Immutability and corrections

Ledger entries are immutable once created. You cannot modify the core fields:
  • amount
  • operation
  • type
  • owner information
  • payment_date
  • business linkages (transaction_id, refund_id, etc.)
If a correction is needed, create new ledger entries in a new posting set to represent the correction.

Key principles

Double-entry

Every posting set must balance: credits = debits

Immutable

Core fields cannot be changed after creation

Precise

Sophisticated rounding ensures exact totals

Traceable

Full audit trail from creation to settlement

Querying ledger entries

Rinne provides API endpoints to retrieve ledger entries with filtering, pagination, and sorting capabilities.

Company ledger entries

Companies can query their own ledger entries:
# List ledger entries for your company
GET /v1/ledger-entries

# Get a specific ledger entry
GET /v1/ledger-entries/{ledgerEntryId}

Merchant ledger entries (organization scope)

Organizations can query ledger entries across all their merchants:
# List ledger entries for all merchants
GET /v1/merchants/ledger-entries

# List ledger entries for a specific merchant
GET /v1/merchants/{merchantId}/ledger-entries

# Get a specific ledger entry
GET /v1/merchants/ledger-entries/{ledgerEntryId}

Filtering options

You can filter ledger entries by:
ParameterDescription
posting_set_idFilter by posting set ID
typeFilter by entry type (comma-separated for multiple)
operationFilter by CREDIT or DEBIT
payment_date_fromStart date (inclusive, YYYY-MM-DD)
payment_date_toEnd date (inclusive, YYYY-MM-DD)
transaction_idFilter by transaction ID
refund_idFilter by refund ID
cashout_idFilter by cashout ID
settledFilter by settlement status (true/false)

Sorting

Use the sort parameter with field names. Prefix with - for descending order:
# Sort by created_at descending (default)
GET /v1/ledger-entries?sort=-created_at

# Sort by payment_date ascending, then amount descending
GET /v1/ledger-entries?sort=payment_date,-amount
Available sort fields: created_at, payment_date, amount

Pagination

All list endpoints return paginated results with page and limit query parameters.
{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 100,
    "totalPages": 5,
    "hasNext": true,
    "hasPrev": false
  }
}

Next steps

Settlement items

Learn how ledger entries are settled

Pricing

Understand fee and cost calculations