> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rinne.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Ledger entries

> Understanding Rinne's double-entry accounting system for tracking all monetary movements

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

```mermaid theme={null}
graph LR
    T[Transaction] -->|creates| PS[Posting Set]
    R[Refund] -->|creates| PS
    C[Cashout] -->|creates| PS
    PS -->|contains| LE[Ledger Entries]
    LE -->|paired by| PT[Pair Token]
    LE -->|owned by| M[Merchant]
    LE -->|owned by| O[Organization]
    LE -->|owned by| PL[Platform]
    LE -->|owned by| PR[Provider]
    LE -->|settled by| SI[Settlement Items]
    
    style T fill:#5B68EB,color:#fff
    style R fill:#7B89FF,color:#fff
    style C fill:#7B89FF,color:#fff
    style PS fill:#4A56D9,color:#fff
    style LE fill:#5B68EB,color:#fff
    style SI fill:#7B89FF,color:#fff
```

## 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 R$100 (CREDIT) ↔ Provider pays R$100 (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:

```mermaid theme={null}
graph TD
    T[Transaction Approved<br/>R$100] --> P1[Pair 1: Transaction]
    T --> P2[Pair 2: Organization Fee]
    T --> P3[Pair 3: Platform Cost]
    
    P1 --> MC[Merchant CREDIT<br/>+R$100]
    P1 --> PD[Provider DEBIT<br/>-R$100]
    
    P2 --> MD[Merchant DEBIT<br/>-R$2.50]
    P2 --> OC[Organization CREDIT<br/>+R$2.50]
    
    P3 --> OD[Organization DEBIT<br/>-R$1.00]
    P3 --> PLC[Platform CREDIT<br/>+R$1.00]
    
    style T fill:#5B68EB,color:#fff
    style P1 fill:#5B68EB,color:#fff
    style P2 fill:#5B68EB,color:#fff
    style P3 fill:#5B68EB,color:#fff
    style MC fill:#7B89FF,color:#fff
    style OC fill:#7B89FF,color:#fff
    style PLC fill:#7B89FF,color:#fff
    style MD fill:#4A56D9,color:#fff
    style OD fill:#4A56D9,color:#fff
    style PD fill:#4A56D9,color:#fff
```

<AccordionGroup>
  <Accordion title="Transaction" icon="money-bill-wave">
    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)
  </Accordion>

  <Accordion title="Organization fee" icon="building">
    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)
  </Accordion>

  <Accordion title="Platform cost" icon="server">
    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)
  </Accordion>
</AccordionGroup>

### Automatic anticipation

When a credit card transaction is processed through an affiliation with `anticipation_type` set to `AUTOMATIC`, Rinne generates additional ledger entry pairs for anticipation fees and costs. These entries are created **per installment** alongside the standard transaction entries.

Automatic anticipation replaces the standard credit card settlement date (D+30) with an earlier payment date based on the affiliation's `anticipation_days` setting (e.g., D+1). The anticipation fee and cost compensate for this early settlement.

**Anticipation formula per installment:**

```
amount = installment_amount × (anticipation_percentage / 100 / 30) × days_anticipated
```

Where `days_anticipated = standard_payment_date - anticipated_payment_date` (calendar days).

<AccordionGroup>
  <Accordion title="Organization anticipation fee" icon="building">
    Fee charged to the merchant for receiving funds earlier than the standard settlement date.

    **Example**: 1.5% anticipation rate, 29 days anticipated on R\$1,000 installment

    * Merchant: R\$14.50 DEBIT (pays anticipation fee)
    * Organization: R\$14.50 CREDIT (receives anticipation fee)
  </Accordion>

  <Accordion title="Platform anticipation cost" icon="server">
    Cost charged to the organization for early settlement processing.

    **Example**: 0.5% anticipation rate, 29 days anticipated on R\$1,000 installment

    * Organization: R\$4.83 DEBIT (pays anticipation cost)
    * Platform: R\$4.83 CREDIT (receives anticipation cost)
  </Accordion>
</AccordionGroup>

<Note>
  Anticipation entries are only generated for **credit card** transactions with `anticipation_type = AUTOMATIC`. Other payment methods and `SPOT` anticipation are not affected. When anticipation is active, all ledger entries for the transaction (including standard entries) use the anticipated payment date instead of the standard D+30 date.
</Note>

### Fee calculation formulas

Fees and costs are calculated using the following formulas:

```typescript theme={null}
// 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:

<AccordionGroup>
  <Accordion title="Transaction refund" icon="rotate-left">
    Main refund amount returned to customer.

    **Example**: R\$50 refund

    * Merchant: R\$50 DEBIT (returns money)
    * Provider: R\$50 CREDIT (processes refund)
  </Accordion>

  <Accordion title="Organization fee refund" icon="building">
    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)
  </Accordion>

  <Accordion title="Platform refund cost" icon="server">
    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)
  </Accordion>
</AccordionGroup>

<Note>
  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.
</Note>

### 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:

```json theme={null}
{
  "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: R$100 + R$2.50 + R$1.00 = R$103.50
* Debits: R$100 + R$2.50 + R$1.00 = R$103.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](/concepts/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 method                           | Payment date calculation                                                                                                                                                                               |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **PIX / BOLEPIX**                        | Same calendar day as approval (D+0)                                                                                                                                                                    |
| **Debit card**                           | Next business day after approval (skips weekends and FEBRABAN holidays)                                                                                                                                |
| **Credit card (standard)**               | Approval date + 29 calendar days, then next business day (\~D+30) for the 1st installment; approval date + (30 × installment number) calendar days, then next business day for subsequent installments |
| **Credit card (automatic anticipation)** | D+`anticipation_days` (next business day if it falls on a non-business day). Applies when `affiliation.anticipation_type = AUTOMATIC`. All installments share the same anticipated payment date.       |

### Installment support

For credit card transactions with installments, Rinne creates separate ledger entries for each installment:

```json theme={null}
{
  "installment": 1,
  "total_installments": 3,
  "amount": 3333,
  "payment_date": "2025-02-14"
},
{
  "installment": 2,
  "total_installments": 3,
  "amount": 3333,
  "payment_date": "2025-03-17"
},
{
  "installment": 3,
  "total_installments": 3,
  "amount": 3334,
  "payment_date": "2025-04-16"
}
```

<Note>
  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.
</Note>

## Precision and rounding

Rinne uses a remainder-on-last strategy to ensure financial accuracy when splitting amounts across installments, backed by a defensive safety net.

### Installment distribution

For each amount type, the system computes a base per-installment value and assigns the remainder to the **last** installment:

```typescript theme={null}
const base = Math.round(total / numberOfInstallments);
// Installments 1 through n-1 receive `base`
// Last installment receives: total - base × (n - 1)
```

* `Math.round()` (half-up rounding) is applied to compute the base value
* All amounts are integers in **cents** (no floating-point)
* The same logic is applied to all entry types (transaction, organization fee, platform cost, etc.)
* Installments with a zero or negative value are skipped (no ledger entries created for that position)

Because the last installment is computed as `total - base × (n - 1)`, the sum of all installments equals the expected total exactly by construction.

### Balancing safety net

As a defensive guard, the system compares the sum of generated entries against the expected totals after all installments are created. If any discrepancy is detected, the last installment entries are adjusted. Under normal operation this check finds no difference, but it protects against edge cases where the distribution and the entry-creation pipeline could diverge (e.g., skipped installments or concurrent modifications).

#### 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)

Distribution (base × 6 installments + remainder on last):
- Transaction: base = Math.round(99900/7) = 14271, last = 99900 - 14271 × 6 = 14274
- Org fee: base = Math.round(2498/7) = 357, last = 2498 - 357 × 6 = 356
- Platform cost: base = Math.round(999/7) = 143, last = 999 - 143 × 6 = 141

Result:
- Transaction: 14271, 14271, 14271, 14271, 14271, 14271, 14274 = 99900 cents
- Org fees: 357, 357, 357, 357, 357, 357, 356 = 2498 cents
- Platform costs: 143, 143, 143, 143, 143, 143, 141 = 999 cents
```

#### Small-total edge cases (absorb from end)

When a small total is split across many installments, `total - base × (n - 1)` can produce a zero or negative last installment. The distribution function handles this by reducing the effective installment count until the last installment is strictly positive:

* **base rounds to zero**: `Math.round(2/12) = 0` — installments 1-11 produce zero and are skipped; installment 12 receives the full 2 cents.
* **base rounds up**: `Math.round(1/2) = 1` — last installment would be `1 - 1 × 1 = 0`, so it is absorbed and only installment 1 receives 1 cent. Similarly, `Math.round(2/4) = 1` — last installment would be `2 - 1 × 3 = -1`, trailing installments are absorbed until a positive remainder is found, resulting in installments 1-2 receiving 1 cent each.

In both cases the sum of emitted installments equals `total` exactly.

### 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

<CardGroup cols={2}>
  <Card title="Double-entry" icon="scale-balanced">
    Every posting set must balance: credits = debits
  </Card>

  <Card title="Immutable" icon="lock">
    Core fields cannot be changed after creation
  </Card>

  <Card title="Precise" icon="calculator">
    Sophisticated rounding ensures exact totals
  </Card>

  <Card title="Traceable" icon="timeline">
    Full audit trail from creation to settlement
  </Card>
</CardGroup>

## 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:

```bash theme={null}
# 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:

```bash theme={null}
# 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:

| Parameter           | Description                                         |
| ------------------- | --------------------------------------------------- |
| `posting_set_id`    | Filter by posting set ID                            |
| `type`              | Filter by entry type (comma-separated for multiple) |
| `operation`         | Filter by CREDIT or DEBIT                           |
| `payment_date_from` | Start date (inclusive, YYYY-MM-DD)                  |
| `payment_date_to`   | End date (inclusive, YYYY-MM-DD)                    |
| `transaction_id`    | Filter by transaction ID                            |
| `refund_id`         | Filter by refund ID                                 |
| `cashout_id`        | Filter by cashout ID                                |
| `settled`           | Filter by settlement status (true/false)            |

### Sorting

Use the `sort` parameter with field names. Prefix with `-` for descending order:

```bash theme={null}
# 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.

```json theme={null}
{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 100,
    "totalPages": 5,
    "hasNext": true,
    "hasPrev": false
  }
}
```

## Next steps

<CardGroup cols={2}>
  <Card title="Settlement items" icon="check-circle" href="/concepts/settlement-items">
    Learn how ledger entries are settled
  </Card>

  <Card title="Pricing" icon="tag" href="/concepts/pricing">
    Understand fee and cost calculations
  </Card>
</CardGroup>
