Marketplace example

Meet Firecnc, a fictional apartment-rental marketplace — think Airbnb. A guest pays Firecnc for a stay; Firecnc keeps a service fee, pays the payment processor, and pays the host the rest. Money moves constantly between you, your hosts, and your processor, and you have to know — to the cent — what you've earned and what you owe. This page builds that ledger end to end: design the accounts, post a booking, pay the host, and read the result. It's the pattern most Ledfra integrations follow.

Firecnc isn't real — we use a marketplace because it touches every part of the model at once: assets, liabilities, income, and expenses.

1. Design the structure

First you design Firecnc's chart of accounts in the Ledfra app (the ledger editor). The API doesn't create accounts — it refers to them by slug. Firecnc needs four:

SlugKindNormal balanceTracks
assets:stripeControlDebitCash held at your payment processor
income:service-feesControlCreditFirecnc's commission on each booking
expenses:processing-feesControlDebitWhat the processor charges to move the money
liabilities:hostsTemplateCreditWhat you owe each host — one account per host

The first three are control accounts: a small, fixed set that Firecnc as a whole shares. liabilities:hosts is a template: you define it once, and Ledfra creates a per-host account like liabilities:hosts/42 automatically the first time host 42 appears in a transaction — so you never pre-create an account per host. See Accounts for how the two kinds differ.

2. Write transactions

With the structure in place, you record what happens by posting transactions. Each entry names an account by slug, a DEBIT or CREDIT, and an amount. The one rule: within a transaction, debits must equal credits — that's double-entry (see Transactions).

A guest books a stay

A guest pays $230 for a booking. Of that, $200 is the host's and $30 is Firecnc's service fee. One transaction records the whole thing — cash comes in, and we split it between our revenue and what we now owe the host.

bash
curl 'https://ledfra.com/api/ledgers/{ledgerId}/transactions' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Idempotency-Key: booking-7af3-charge' \
  -H 'Content-Type: application/json' \
  -d '{
    "description": "Booking #7af3 — guest payment",
    "entries": [
      { "account": "assets:stripe",       "operation": "DEBIT",  "amount": "USD:230.00" },
      { "account": "income:service-fees", "operation": "CREDIT", "amount": "USD:30.00" },
      { "account": "liabilities:hosts/42", "operation": "CREDIT", "amount": "USD:200.00" }
    ]
  }'

The one debit ($230 in) equals the two credits ($30 + $200), so the transaction balances:

One booking, balancedThe booking transaction debits assets:stripe $230.00, which equals the credits to income:service-fees $30.00 and liabilities:hosts/42 $200.00.Debitsassets:stripe$230.00Total$230.00=Creditsincome:service-fees$30.00liabilities:hosts/42$200.00Total$230.00
Every transaction balances — total debits equal total credits.
Make writes retry-safe
The Idempotency-Key header means a network retry can't post the booking twice — the second call returns the original transaction. Use one stable key per real-world event.

Stripe takes its fee

The processor charges $7 to move the money. That lowers our cash and records an expense. It's a separate transaction posted to the same endpoint — from here on we show just the request body:

json
{
  "description": "Booking #7af3 — Stripe processing fee",
  "entries": [
    { "account": "expenses:processing-fees", "operation": "DEBIT",  "amount": "USD:7.00" },
    { "account": "assets:stripe",            "operation": "CREDIT", "amount": "USD:7.00" }
  ]
}

Pay out the host

At checkout you pay host 42 the $200 you were holding. That settles what you owed and moves cash out.

Firecnc pays out directly here to keep things simple. Real marketplaces usually hold a host's earnings until the stay completes and then release them — see the holding-funds pattern in Transactions.

json
{
  "description": "Booking #7af3 — payout to host 42",
  "entries": [
    { "account": "liabilities:hosts/42", "operation": "DEBIT",  "amount": "USD:200.00" },
    { "account": "assets:stripe",        "operation": "CREDIT", "amount": "USD:200.00" }
  ]
}

3. Reports

You never add up balances yourself — Ledfra derives them from the entries as they're posted. After the three transactions, Firecnc's accounts read:

AccountBalanceHow it got there
assets:stripe$23.00230 in − 7 fee − 200 payout
income:service-fees$30.00Your cut of the booking
expenses:processing-fees$7.00The processor's cut
liabilities:hosts/42$0.00Owed $200, then paid it out

Those balances roll straight into the standard reports:

  • Profit & loss — income $30 − expenses $7 = $23 profit.
  • Balance sheet — assets $23 = liabilities $0 + equity $23. The books balance, and the $23 you earned is sitting in cash.

Ledfra builds the balance sheet, P&L, and cash-flow reports from these balances automatically and keeps them live, so the numbers never drift from what was posted.

What the API exposes today
Reports and account balances live in the Ledfra app right now — they aren't part of the public REST API yet. Through the API you read the underlying history with GET /ledgers/{ledgerId}/transactions:
bash
# Read back everything that happened on the ledger
curl 'https://ledfra.com/api/ledgers/{ledgerId}/transactions' \
  -H 'Authorization: Bearer YOUR_API_KEY'

Where to go next

Try this flow against a sandbox before you touch production. For the building blocks, see Accounts and Money, and the full endpoint details in the API reference.