<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Formance</title>
    <description>The latest articles on DEV Community by Formance (@formance).</description>
    <link>https://dev.to/formance</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F5704%2F7a862a62-7eba-492e-bf0f-6376cecb9acb.png</url>
      <title>DEV Community: Formance</title>
      <link>https://dev.to/formance</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/formance"/>
    <language>en</language>
    <item>
      <title>Structuring Invoices</title>
      <dc:creator>Clément Salaün</dc:creator>
      <pubDate>Wed, 12 Mar 2025 13:48:11 +0000</pubDate>
      <link>https://dev.to/formance/structuring-invoices-420a</link>
      <guid>https://dev.to/formance/structuring-invoices-420a</guid>
      <description>&lt;p&gt;Invoices are an important part of any business, as they provide the accounting justification for the movement of money. If you’re a merchant dealing directly with your customers, there’s really no question of how to issue or interpret invoices. But—more likely—if you’re a platform mediating the sales of goods or services between merchants and buyers, there are several different ways to handle invoicing, and it can be quite confusing to understand the various benefits and risks associated with each of the possible invoicing models.&lt;/p&gt;

&lt;p&gt;In this article, let’s dive into three different models for invoicing as a platform and look closely at the implications for each. Some of those implications will depend on the region or regions you are operating in, your relationship with your merchants, and the degree of complexity for each of the three parties; It’s best to keep an open mind, and consider using a mix of these models to optimally handle the kinds of commercial situations you might encounter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Scenario
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6quqxa72q65w2e7nv33.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6quqxa72q65w2e7nv33.png" alt="The scenario: We are moving $100 from the buyer to our platform, and $80 from our platform to the merchant." width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let’s suppose you are a platform facilitating sales of goods, and you charge a flat percentage commission on all sales. You have a merchant with a listing on your platform for which they want to charge $80. And you have a buyer who is purchasing the product for a total of $100—the $80 plus your commission of $20. You collect the entire $100 purchase price, keep the $20 commission, and disburse the remaining $80 to the merchant on behalf of the buyer. How do you structure the invoices for that transaction? There are three options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model A: Customer Commission
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7w8outtfk2bh8b7bc6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7w8outtfk2bh8b7bc6p.png" alt="Model A" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On this model, both you and the merchant generate invoices to the buyer. The buyer receives an invoice from you for your fee of $20, and an invoice from the merchant for $80 for the product. On this model, the buyer is a customer of both you and the merchant.&lt;/p&gt;

&lt;p&gt;This model simplifies your invoicing process, as you are only ever generating invoices on your own behalf, and passing responsibility to the merchant to invoice for the product sale itself. It also reduces the burden on the merchant by keeping their invoicing structure straightforward—the money they receive matches the amount on the invoice they generate.&lt;/p&gt;

&lt;p&gt;On the other hand, the two invoices make the commission structure explicit to the buyer, which you might or might not want to do depending on your relationship with your buyers—it creates a risk that they might bypass your platform in the future.&lt;/p&gt;

&lt;p&gt;There is an additional complication for the merchant, in that they are receiving funds from you, but invoicing the customer, which could create accounting difficulties for them depending on the accounting and taxation rules where they operate.&lt;/p&gt;

&lt;p&gt;Moreover some regions have strict rules on platforms handling money on behalf of merchants (such as &lt;a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=celex%3A32015L2366" rel="noopener noreferrer"&gt;PSD2&lt;/a&gt; in Europe), something other commission models handle much better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model B: Seller Commission
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1kj3ev3dv35tpammo5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1kj3ev3dv35tpammo5t.png" alt="Model B" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another option is to have the merchant invoice the customer directly for the entire purchase price. You then invoice the merchant for the commission. The buyer is only a customer of the merchant now, and the merchant is your customer. This invoicing model is fairly common for platforms operating in Europe.&lt;/p&gt;

&lt;p&gt;This is a much cleaner situation from the buyer’s point of view, as they receive only one invoice, and that invoice doesn’t disclose your commission model. It’s also cleaner from your perspective, because your only customers are your merchants.&lt;/p&gt;

&lt;p&gt;However, it can place some burden on the merchants, depending on the tax structure where they operate, as they are likely required to recognize the entire $100 price as revenue, and the $20 commission as an expense which they might not be able to apply fully against their revenue. Additionally you will still run into regional rules, like PSD2, on handling funds on behalf of merchants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model C: Merchant Mode
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bivluxwopcr8olfxbw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bivluxwopcr8olfxbw6.png" alt="Model C" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a third option to consider, a more traditional approach (with a modern twist). On this model, you purchase the goods from the merchant, who invoice you. You then sell the goods directly to the buyer, invoicing them for the full amount. This is the usual model for brick-and-mortar stores that purchase an inventory from merchants for resale in a retail environment. The modern twist is that rather than keeping inventory, you make the purchase from the merchant just as the buyer is making the purchase from you—that is, using a just-in-time logistics model.&lt;/p&gt;

&lt;p&gt;The advantage to this model is that invoicing is simple and clean for every party involved. In particular, you are not handling funds on behalf of the merchant. This model works well universally from an accounting and taxation perspective.&lt;/p&gt;

&lt;p&gt;However, the downside is that you become the merchant of record for the sale. If the goods need to be returned or repaired, you as the platform become the responsible party for handling that. You can then pass along this responsibility to the original merchant, but you need to trust your merchants for this to work—it is entirely possible for them to fraudulently disappear after the sale is made, and you are left holding the bag. Implementing this model is therefore risky unless you have a demonstrably good relationship with your merchants.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Choose an Invoicing Model
&lt;/h2&gt;

&lt;p&gt;Each of the three models presented above presents a different tradeoff of benefits and risks. Almost certainly you should consider your jurisdiction, the jurisdiction of your merchants, the complexity of the transactions, and your level of trust in your merchants on a case-by-case basis, and choose the appropriate model dynamically.&lt;/p&gt;

&lt;p&gt;Model C, although straightforward from an accounting perspective, presents the greatest risks to you. Because you are responsible for the goods or services sold, you need to be able to trust your merchants. Moreover, employing this model means that the nature of your business activity might be rather different from a financial reporting perspective—you aren’t transacting as a platform in this case. On the other hand, Model C makes it easier to structure transactions involving multiple merchants because you are not handling funds on their behalf.&lt;/p&gt;

&lt;p&gt;Models A and B trade off simplicity to reduce the risks to you of being held liable when a merchant disappears. However, as mentioned above, things get more complicated when multiple merchants are involved in a single transaction. In order to meet certain regional requirements, such as PSD2 in Europe, you will need to use a payment processor to handle the funds on your behalf. This can pose a problem if in a given multi-merchant transaction there is no common payment processor among the merchants. In these cases you will have to create a more complex set of transactions to comply with local regulations.&lt;/p&gt;

&lt;p&gt;Model B presents the additional difficulty that it can be unfriendly to smaller merchants. For example, sole proprietors in France are required to report the full $100 of the transaction as income, increasing their tax liability.&lt;/p&gt;

&lt;p&gt;Model A might be a better choice over Model B in that it is friendlier to merchants. However, it exposes your fee structure to your buyers, which may or may not be desirable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Ultimately you will need to look closely at the details of your own situation to decide which trade offs are better for your business needs. But there’s no need to lock yourself into a particular invoicing model—you can dynamically determine which is better on a transaction-by-transaction basis. For example you could choose to default to Model A or Model B, and switch to Model C for merchants who have established trust with you.&lt;/p&gt;

</description>
      <category>finance</category>
      <category>marketplaces</category>
      <category>startup</category>
    </item>
    <item>
      <title>How Not to Build a Ledger</title>
      <dc:creator>Clément Salaün</dc:creator>
      <pubDate>Wed, 05 Mar 2025 15:10:00 +0000</pubDate>
      <link>https://dev.to/formance/how-not-to-build-a-ledger-cfg</link>
      <guid>https://dev.to/formance/how-not-to-build-a-ledger-cfg</guid>
      <description>&lt;p&gt;So you’re an engineer, and you’ve been tasked with building a ledger to record funds movements across your platform. Building a robust, reliable ledgering system might not seem like a difficult engineering challenge, but a good understanding of accounting practices can help you avoid certain hidden traps that could derail your accounting.&lt;/p&gt;

&lt;p&gt;In this article, we want to walk through some common anti-patterns in ledger design we’ve seen, point out those hidden traps, and arm you with the accounting basics you need to avoid those traps. You’ll be implementing more robust, reliable, and auditable ledgering systems in no time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Scenario
&lt;/h2&gt;

&lt;p&gt;Let’s suppose we’re building an online marketplace for people to buy and sell their second-hand goods. Sellers can list an item for sale for free, and we take a 10% commission from the sale price when someone else buys it.&lt;/p&gt;

&lt;p&gt;Suppose moreover that Bob has a guitar listed for $100, and Alice—our first customer!—wants to buy it. She will transfer $100 to us through a payment processor, and once she confirms receipt of the guitar, we will release $90 to Bob and take our $10 commission. How should we represent these transactions internally?&lt;/p&gt;

&lt;h2&gt;
  
  
  Zero-Entry Ledgers
&lt;/h2&gt;

&lt;p&gt;Perhaps one of the most common ways to go about managing transactions is to have a table with account balances for each user. Here is an example of what such a table might look like. At the very start, all accounts will have a zero balance.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Account&lt;/th&gt;
&lt;th&gt;Balance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commission&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For Alice to buy Bob’s guitar, she first needs to make a payment to the platform for the total sale amount. We will update her account balance once we receive confirmation from the payment processor:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Account&lt;/th&gt;
&lt;th&gt;Balance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commission&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two days later, Alice confirms receipt of the guitar, and we can release the funds to the seller, plus our commission. To record the result of the sale, we update Alice’s account balance to $0,  Bob’s account balance to $90, and increase commission account balance by $10.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Account&lt;/th&gt;
&lt;th&gt;Balance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;$90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commission&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One of the reasons this model is so commonly deployed is that it is simple and straightforward—there is never any question of what each account balance is at any given time, it’s right there in the table!&lt;/p&gt;

&lt;h3&gt;
  
  
  Yes, But…
&lt;/h3&gt;

&lt;p&gt;This is called zero-entry ledgering because we do not record the details of individual transactions, only the final results. It’s easy, but…this accounting model is deeply flawed, and represents a significant business risk.&lt;/p&gt;

&lt;p&gt;Why? Because the balances are &lt;em&gt;mutable&lt;/em&gt;. There is nothing in the design of this ledger to prevent a bug in your code (or a malicious actor, for that matter) from simply updating an account balance incorrectly.&lt;/p&gt;

&lt;p&gt;Suppose for example, there was a bug in the commission calculation, and it was calculating a 10% commission when updating the seller’s account balance, but a 12% when updating the commission account balance, so we end up with final balances after the guitar sale that like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Account&lt;/th&gt;
&lt;th&gt;Balance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;$90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commission&lt;/td&gt;
&lt;td&gt;$12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is an extra $2 in the system now, which we won’t detect until we reconcile the balance with what’s in our actual bank account. And once we do find that we have an extra $2 in our ledger, we are utterly unable to answer important questions like: Where did this $2 come from? Which account or accounts is it in? How did it get there? Was it a mistake, or is this fraud?&lt;/p&gt;

&lt;p&gt;Basically, with a zero-entry ledger, we’re flying blind. We cannot detect drift in our ledger before reconciliation. And we simply aren’t storing enough information about our transactions to understand how to correct any drift. This is a very risky situation we’ve put ourselves in.&lt;/p&gt;

&lt;p&gt;But we can solve a lot of these problems by recording individual transactions rather than account balances in our ledger. Let’s see how this might work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single-Entry Ledgers
&lt;/h2&gt;

&lt;p&gt;The next logical step many developers will take is to upgrade the system to a single-entry ledger, a ledger that stores information about individual transactions.&lt;/p&gt;

&lt;p&gt;Instead of account balances, a single-entry ledger records information about individual transactions into and out of an account. Account balances are computed on the basis of all the transactions involving that account.&lt;/p&gt;

&lt;p&gt;If you’ve ever had to balance a checkbook, or done household budgeting, these are examples of single-entry ledgers. Most small businesses—especially those that operate on a cash-only basis—use single-entry ledgers to manage their accounting.&lt;/p&gt;

&lt;p&gt;Let’s retrace the example of Alice buying a guitar from Bob, and see how we would record that in a single-entry ledger.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Account&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Balance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;+$100&lt;/td&gt;
&lt;td&gt;20 Feb 2025&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;-$100&lt;/td&gt;
&lt;td&gt;22 Feb 2025&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;+$90&lt;/td&gt;
&lt;td&gt;22 Feb 2025&lt;/td&gt;
&lt;td&gt;$90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commissions&lt;/td&gt;
&lt;td&gt;+$10&lt;/td&gt;
&lt;td&gt;22 Feb 2025&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now we have some more information. We can see that Alice initiated the sale on 20 February, when we charged her card for $100. Then, Alice verified receipt of the guitar on 22 February, at which point we released the funds from her account, and &lt;a href="https://www.formance.com/blog/engineering/debits-and-credits-for-the-befuddled" rel="noopener noreferrer"&gt;credited&lt;/a&gt; Bob’s account $90, and our commissions account $10.&lt;/p&gt;

&lt;p&gt;Moreover, we can see the flow of money reasonably clearly. Unlike a zero-entry ledger, a single-entry ledger is &lt;em&gt;immutable&lt;/em&gt;. Adding a new transaction creates a new line, rather than overwriting existing data. This allows us to attach timestamps to each transaction, so we can see how the ledger has evolved over time. This allows us to do some rudimentary tracing of funds, which is important for detecting and correcting drift in the ledger when we do reconciliation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not Out of the Woods
&lt;/h2&gt;

&lt;p&gt;Although we are recording additional information that allows us to mitigate the worst problems of zero-entry ledgering, single-entry ledger still has some significant limitations. In particular, as our source of truth about the transactions that pass through our system, it is still susceptible to errors in entry that cannot be detected until reconciliation.&lt;/p&gt;

&lt;p&gt;Let’s return to the example above where we mistakenly calculate our commission at 12%. After reconciliation, we can spot that the excess $2 is in the Commissions account, because we recorded that transaction. This can still happen because there are no constraints on how we record our transactions. And, real world ledgers tend to be a bit messier, and it won’t always be so easy to find once you have millions of accounts transacting with each other.&lt;/p&gt;

&lt;p&gt;Moreover, we still don’t have a way to detect this error until we’ve done reconciliation. It would be nice if we could detect (and correct) it earlier. We need more data still.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Account&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Balance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;+$100&lt;/td&gt;
&lt;td&gt;20 Feb 2025&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;-$100&lt;/td&gt;
&lt;td&gt;22 Feb 2025&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;+$90&lt;/td&gt;
&lt;td&gt;22 Feb 2025&lt;/td&gt;
&lt;td&gt;$90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commissions&lt;/td&gt;
&lt;td&gt;+$12&lt;/td&gt;
&lt;td&gt;22 Feb 2025&lt;/td&gt;
&lt;td&gt;$12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is another question we cannot answer, one that our finance people very much need to be able to answer: Which balances are assets, and which are liabilities? We’re holding $100 in the bank—that’s an asset. But we owe Bob $90 (and the Commissions account $10)—these are liabilities. But this isn’t encoded in any way in our ledger, so our accountants cannot generate balance sheets for our business, and they cannot tell us whether our books are out of balance. We might appear to be flush with cash, when in fact we’re operating in the red.&lt;/p&gt;

&lt;h2&gt;
  
  
  Double-Entry Ledgers
&lt;/h2&gt;

&lt;p&gt;Double-entry ledgers take the idea of recording transaction individually, but add a critical constraint that must be applied to each transaction as recorded: A change on one account must always be balanced by an opposite change on another account. This constraint ensures that we will never record a transaction that makes money appear out of or disappear into thin air, unlike the simpler models discussed above.&lt;/p&gt;

&lt;p&gt;To do this, we’ll add two details to our ledger. First, we split the “Amount” column into “Debit” and “Credit” columns. Second, we label each account as being an asset or a liability. Any account that is holding money for someone else, like our customers, is a liability. Any account that holds revenue, like our commissions account, is also considered a liability (at least until we’ve paid out the vendors). Any account that represents actual cash in our hands is an asset.&lt;/p&gt;

&lt;p&gt;Next, we need to note two important rules for recording transactions.&lt;/p&gt;

&lt;p&gt;The first rule is that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Assets = Liabilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put slightly differently, every transaction must contain one or more debits, one or more credits, and the total of those debits must equal the total of those credits.&lt;/p&gt;

&lt;p&gt;This ensures that after each transaction has been recorded, when we sum the assets and sum the liabilities, those will be equal to each other. This is how we ensure that no errors have been made when recording a transaction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.formance.com/blog/engineering/debits-and-credits-for-the-befuddled" rel="noopener noreferrer"&gt;The second rule is that&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;• A *debit* increases an asset, or decreases a liability.

• A *credit* decreases an asset, or increases a liability.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This rule tells us how to record each transaction properly, and how to properly sum assets and liabilities.&lt;/p&gt;

&lt;p&gt;Finally, a little additional terminology. An account that represents an asset is called “debit normal”, because debits increase the value of the account. An account that represents a liability is called “credit normal”, because credits increase the value of the account. So, let’s note that the Payments account is our only debit-normal account; the remainder are credit-normal.&lt;/p&gt;

&lt;p&gt;Let’s put these ideas to work!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Account&lt;/th&gt;
&lt;th&gt;Debit&lt;/th&gt;
&lt;th&gt;Credit&lt;/th&gt;
&lt;th&gt;Transaction&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bank (Debit)&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;0001&lt;/td&gt;
&lt;td&gt;20 Feb 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alice (Credit)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;td&gt;0001&lt;/td&gt;
&lt;td&gt;20 Feb 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On 20 February, Alice makes a card payment to us in the amount of $100. But we can’t just record that Alice’s balance has increased by $100—we must balance credits and debits! So we introduce a new account, our bank account, where that money has been deposited. And because this is cold, hard cash in our bank account, it is thus an asset. That said, the money belongs to Alice, it’s not our money. So we record her credit card payment as a debit to the Bank account (an increase in $100 in assets), and a credit to Alice (an increase in $100 in liabilities—because we owe this money to Alice).&lt;/p&gt;

&lt;p&gt;So far so good! Our debits ($100) equal our credits ($100).&lt;/p&gt;

&lt;p&gt;Next, Alice receives the guitar, and we release the funds to Bob (and take our commission). Because we want to remove money from Alice’s account, which is credit-normal, we mark the $100 payment as a debit on her account. We deposit $90 into Bob’s account, which since it is also credit-normal, is marked as a credit. Likewise, our $10 commission is marked as a credit in the Commission account, because it is also credit-normal.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Account&lt;/th&gt;
&lt;th&gt;Debit&lt;/th&gt;
&lt;th&gt;Credit&lt;/th&gt;
&lt;th&gt;Transaction&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bank (Debit)&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;0001&lt;/td&gt;
&lt;td&gt;20 Feb 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alice (Credit)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;td&gt;0001&lt;/td&gt;
&lt;td&gt;20 Feb 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alice (Credit)&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;0002&lt;/td&gt;
&lt;td&gt;22 Feb 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob (Credit)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;$90&lt;/td&gt;
&lt;td&gt;0002&lt;/td&gt;
&lt;td&gt;22 Feb 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commissions (Credit)&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;0002&lt;/td&gt;
&lt;td&gt;22 Feb 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In this transaction, we debited $100 from Alice’s account, and we credited $90 to Bob’s account and $10 to the Commissions account. Our debits ($100) equal our credits ($100) for this transaction, so it is valid.&lt;/p&gt;

&lt;p&gt;Moreover, we can see after these two transactions that our assets equal our liabilities. After the first transaction our assets were $100, and our liabilities were also $100. In the second transaction, the debit to Alice’s account adds $100 to our assets (because we no longer owe her that money, as she no longer owns it, having exchanged that money for the guitar). The credits to Bob’s account and the Commissions accounts are a liability, so we add $90 and $10 to our liabilities.&lt;/p&gt;

&lt;p&gt;Now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Assets = $100 + $100 = $200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Liabilities = $100 + $90 + $10 = $200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our Assets remain the same as our liabilities, so we know everything is correct!&lt;/p&gt;

&lt;h3&gt;
  
  
  What Have We Gained?
&lt;/h3&gt;

&lt;p&gt;We can now answer a very broad range of important questions about the money movements recorded in our ledger. In particular, we can make strong guarantees that our ledger is free of drift resulting from the incorrect entry of transactions, because the constraints of double-entry ledgering make it is impossible to create or destroy money with an invalid transaction. Of course, drift can still happen if a transaction isn’t recorded, or is recorded more than once, but this isn’t a problem with the ledger itself.&lt;/p&gt;

&lt;p&gt;Moreover, we can see both sides of a transaction very clearly, which makes funds traceability much easier. We know with certainty that the $90 in Bob’s account came from Alice’s account, because of how transactions are recorded. Even with millions of accounts transacting, there is never a question of where the money in each account came from and why.&lt;/p&gt;

&lt;p&gt;Moreover, because we have a very clear picture of our assets and liabilities, our accountants can create balance sheets and other documents to show investors and regulators that everything is being accounted for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Creating a robust, scalable, auditable ledgering system requires more than sound engineering principles, it also requires a basic understanding of accounting principles as well.&lt;/p&gt;

&lt;p&gt;Zero-entry ledgers are the easiest to implement, but offer no assurances against errors or fraud—it is trivially easy to create or destroy money when writing an account balance. They also offer no information about how accounts change over time, making it impossible to trace the movements of funds.&lt;/p&gt;

&lt;p&gt;Single-entry ledgers are only slightly more complex to implement, as you are recording a chain of individual account balance changes over time. This historical data makes it somewhat easier to spot errors and fraud, and offers a rudimentary possibility for tracing the movements of funds.&lt;/p&gt;

&lt;p&gt;Double-entry ledgers are the gold standard for recording transactions. The constrained structure of entries offers built-in assurance that each transaction is being recorded correctly, and makes it clear where the money is coming from and where it is headed. The possibility of errors and fraud hiding in the ledger is eliminated from the ledger (though obviously there are plenty of other ways for this to happen!), funds traceability is greatly increased. And our accountants can now produce the documents they need to reassure investors and regulators that our business is operating properly.&lt;/p&gt;

</description>
      <category>fintech</category>
      <category>accounting</category>
      <category>backend</category>
    </item>
    <item>
      <title>Level up your secrets management in Kubernetes using AWS Secret Manager and Helm</title>
      <dc:creator>Julie Hourcade</dc:creator>
      <pubDate>Mon, 26 Dec 2022 09:04:11 +0000</pubDate>
      <link>https://dev.to/formance/level-up-your-secrets-management-in-kubernetes-using-aws-secret-manager-and-helm-c80</link>
      <guid>https://dev.to/formance/level-up-your-secrets-management-in-kubernetes-using-aws-secret-manager-and-helm-c80</guid>
      <description>&lt;p&gt;Engineers' biggest struggle when writing Kubernetes resources is to keep all secrets secure. To be honest, the secrets k8s resource is not secured at all because base64 is not encryption!&lt;/p&gt;

&lt;p&gt;Required skills: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding basic concepts about Kubernetes&lt;/li&gt;
&lt;li&gt;Cloud providers resources knowledge&lt;/li&gt;
&lt;li&gt;Helm &lt;strong&gt;v3&lt;/strong&gt; installed on a Kubernetes cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding Helm
&lt;/h2&gt;

&lt;p&gt;For this article and for Formance infrastructure we chose to use Helm as a templating system for our k8s resources. This software is commonly known as the package manager for Kubernetes but they also provide a good system for deploying many versions of the same Charts, like for production and staging environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize the application
&lt;/h3&gt;

&lt;p&gt;First, we have to create a new application using the Helm CLI. You could find how to install it here: &lt;a href="https://helm.sh/docs/intro/quickstart/" rel="noopener noreferrer"&gt;https://helm.sh/docs/intro/quickstart/&lt;/a&gt;. Once all is installed correctly, you could run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm create &lt;span class="s2"&gt;"&amp;lt;your_application_name&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The directory Helm creates should look like this ⬇️&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpot60aquqs1bviodsjo7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpot60aquqs1bviodsjo7.png" alt="Tree of the directory" width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we’re going to stay basic and remove some templates to keep it simple. We’re only keeping: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The deployment template&lt;/li&gt;
&lt;li&gt;The service template&lt;/li&gt;
&lt;li&gt;The service account template&lt;/li&gt;
&lt;li&gt;The helpers, Notes, and Tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, we will create a file named &lt;code&gt;secret.yaml&lt;/code&gt; for the template of our SecretProvider object. &lt;/p&gt;

&lt;p&gt;If you’re not familiar with the Helm templating language, I recommend you take a look at the documentation: &lt;a href="https://helm.sh/docs/chart_template_guide/" rel="noopener noreferrer"&gt;https://helm.sh/docs/chart_template_guide/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The secret provider object
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Concept
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What are CSI Drivers?
&lt;/h4&gt;

&lt;p&gt;To perform what we want, we’re going to use a Kubernetes resource named SecretProviderClass from the API &lt;code&gt;secrets-store.csi.x-k8s.io/v1alpha1&lt;/code&gt;.  The secret store is provided by the Kubernetes Container Storage Interface which here helps us to connect basic resources like volumes or secrets to cloud providers' services. &lt;/p&gt;

&lt;p&gt;The main problem of Secrets resources on Kubernetes is the lack of security and if I want to share some private values as database passwords to my application deployment, I need more than just a base64 encryption.&lt;/p&gt;

&lt;p&gt;Here at Formance we use Amazon Web Services as cloud provider so I will use the service AWS Secret Manager (docs: &lt;a href="https://docs.aws.amazon.com/secretsmanager/?id=docs_gateway" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/secretsmanager/?id=docs_gateway&lt;/a&gt;). When we have created our Relational Database Service with MariaDB or PostgreSQL or whatever, using InfraAsCode tools Terraform, we have automatically created a Secret with the database login information. The problem is to retrieve those values directly on my application container automatically. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Simplified overview of the workflow&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuaowdoz6zu6vzohti99t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuaowdoz6zu6vzohti99t.png" alt="Simplified overview of the workflow" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Installing the Secret Store CSI driver
&lt;/h4&gt;

&lt;p&gt;That’s here where Kubernetes CSI enters in action ! It will create an interface between our Secret object on AWS and our application deployment. First of all, we have to install the Secret Store CSI driver using helm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add secrets-store-CSI-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm &lt;span class="nb"&gt;install &lt;/span&gt;csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver &lt;span class="nt"&gt;--namespace&lt;/span&gt; kube-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could find an alternative installation here: &lt;a href="https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html" rel="noopener noreferrer"&gt;https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will install things like the operator, and service account with the right RBAC permissions and most important, it will declare the Custom Resources Definition of the SecretProviderClass. Without this, the Kubernetes Scheduler will not understand the API version and the object kind. &lt;/p&gt;

&lt;p&gt;Secret store CSI driver also supports GCP, Azure, and Vault secrets providers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deep dive into the secret template
&lt;/h3&gt;

&lt;p&gt;The requirement is to make a template where we could inject some specific values like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The name obviously&lt;/li&gt;
&lt;li&gt;The secret provider (note that this example is only tested on AWS)&lt;/li&gt;
&lt;li&gt;And the secrets to retrieve using the secret name or in AWS its Amazon Resource Name (ARN)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep in mind that this example is a simple template with multiple secrets but you personalize it as you wish. You can find various &lt;/p&gt;

&lt;p&gt;Let’s take a look at the template and its values:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fule95nfdlewdrs9octzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fule95nfdlewdrs9octzt.png" alt="secret yaml" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sfnn04spy7d5674sbdk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sfnn04spy7d5674sbdk.png" alt="extract of values.yaml" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you create all templates, all you have to do is to apply the command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helm install &amp;lt;application name&amp;gt; .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And you're all done!&lt;/p&gt;

&lt;p&gt;Image credits: &lt;a href="https://www.midjourney.com/home/" rel="noopener noreferrer"&gt;Midjourney&lt;/a&gt; &lt;/p&gt;

</description>
      <category>security</category>
      <category>cloud</category>
      <category>aws</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building an Uber Eats Clone</title>
      <dc:creator>Julie Hourcade</dc:creator>
      <pubDate>Thu, 02 Jun 2022 11:43:29 +0000</pubDate>
      <link>https://dev.to/formance/building-an-uber-eats-clone-38j8</link>
      <guid>https://dev.to/formance/building-an-uber-eats-clone-38j8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Initialy published on &lt;a href="https://32b6.com/articles/uber-eats-clone-1" rel="noopener noreferrer"&gt;https://32b6.com&lt;/a&gt; by Clément Salaün&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Templating money flows with Numscript
&lt;/h3&gt;

&lt;p&gt;We explore in this article the money problem behind creating a food delivery platform, focusing on building the core money movements using the Formance &lt;a href="https://github.com/numary/ledger" rel="noopener noreferrer"&gt;ledger&lt;/a&gt; and Numscript as the foundation of our real-time accounting system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three-sided Platform
&lt;/h2&gt;

&lt;p&gt;From a money flow perspective, Eats is a classic &lt;a href="https://a16z.com/2020/02/18/marketplace-glossary/" rel="noopener noreferrer"&gt;n-sided marketplace&lt;/a&gt; (where N=3). It is a machine that reads your credit card details, materializes a pizza on your porch and a platform, facilitates a transaction between three parties: the customer, the restaurant and the rider.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5z1ky1c840l5txnlfgb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl5z1ky1c840l5txnlfgb.png" alt="graph" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some payments services providers give us constructs to route an incoming payment, to a certain extent. Stripe Connect for example has &lt;a href="https://stripe.com/docs/connect/destination-charges" rel="noopener noreferrer"&gt;destination charges&lt;/a&gt;, which give you the ability to provide the end destination account and your commission amount at payment. This is not super helpful for our food delivery app given that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have more than 1 destination (the restaurant and rider)&lt;/li&gt;
&lt;li&gt;We don’t know, at payment time, who is going to be the rider&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To these issues, Stripe answers with another turnkey solution called &lt;a href="https://stripe.com/docs/connect/charges-transfers" rel="noopener noreferrer"&gt;separate charges and transfers&lt;/a&gt;. It basically solves all our concerns, at one cost: we are now responsible for tracking what is owed to whom. Ledger systems are a good candidate for achieving this, as we’ll attempt to demonstrate in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Templating our flow
&lt;/h2&gt;

&lt;p&gt;Not bothering with unique values (for now), let’s start to encode our money flow in Numscript using hardcoded values. If you want to follow along, Numscript files can be executed against a locally running Formance ledger directly from the cli:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;numary exec "eats-clone-demo" example.num
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The payment
&lt;/h3&gt;

&lt;p&gt;Using an intermediate payment ledger account helps us divide our flow into multiple sub-problems. Prior to splitting, our first mission is to properly track how much we collected from our customer. Let’s start with a simple case by assuming we managed to collect $59 through Stripe:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhocgnks6nwm33q5xe8g7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhocgnks6nwm33q5xe8g7.png" alt="code" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use here the &lt;code&gt;@world&lt;/code&gt; account to introduce money into our ledger (as per the &lt;a href="https://docs.formance.com/docs/creating-money" rel="noopener noreferrer"&gt;spec&lt;/a&gt;). If its USD balance was zero before this transaction, it will now be negative 59. We can note as well that we use here &lt;code&gt;USD/2&lt;/code&gt; instead of &lt;code&gt;USD&lt;/code&gt;, which is basically a &lt;a href="https://docs.formance.com/oss/ledger/reference/unambiguous-monetary-notation" rel="noopener noreferrer"&gt;notation&lt;/a&gt; for USD scaled to 10^-2 i.e. USD cents.&lt;/p&gt;

&lt;p&gt;We conclude the payment by flushing the funds we collected to an order account, which will receive the funds without ever bothering about their origin:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15elg98dgraqcg1l96ao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15elg98dgraqcg1l96ao.png" alt="code" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Philosophically, we consider stripe as an external ledger that now owes money to our local ledger. In the real world, money hasn’t moved but we penciled in that this money is now dedicated to this order.&lt;/p&gt;

&lt;h3&gt;
  
  
  The split
&lt;/h3&gt;

&lt;p&gt;Moving further in the flow, we now task ourselves with splitting the customer payment to the rider, restaurant and our platform. This splitting script is typically where we would encode our platform commission logic. We make the decision here of taking a 15% cut on each amount we pay the restaurant, leaving the delivery fee entirely to the rider.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuczqiqw5zeyzugb1v5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkuczqiqw5zeyzugb1v5z.png" alt="code" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The payout
&lt;/h3&gt;

&lt;p&gt;We now have riders and and restaurants accounts in our ledger with a positive balance, whose purpose is to eventually be paid out to their owners’ banks.On the rider and restaurant views of our app, we’ll typically display these balances as “available for payout” funds.&lt;/p&gt;

&lt;p&gt;Sticking to Stripe, one way to achive the processing of these balances can be to move the balance from a &lt;code&gt;restaurants:001&lt;/code&gt; account to a &lt;code&gt;restaurants:001:payouts:001&lt;/code&gt; account, initiating a &lt;a href="https://stripe.com/docs/api/transfers/create" rel="noopener noreferrer"&gt;transfer&lt;/a&gt; and a &lt;a href="https://stripe.com/docs/api/payouts/create" rel="noopener noreferrer"&gt;payout&lt;/a&gt; on Stripe of that amount, and eventually moving the balance from &lt;code&gt;restaurants:001:payouts:001&lt;/code&gt; back to &lt;code&gt;world&lt;/code&gt; once we successfully processed the payout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating our flow
&lt;/h2&gt;

&lt;p&gt;Using hardcoded values in Numscript will only get us so far. As we start to execute our templates automatically from a backend, we will typically start to use variables, passing them along with the script on the &lt;a href="https://docs.formance.com/oss/ledger/reference/api#operation/runScript" rel="noopener noreferrer"&gt;/script&lt;/a&gt; endpoint&lt;/p&gt;

&lt;h3&gt;
  
  
  Using execution variables
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdqwauh3ae2utt32hihl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdqwauh3ae2utt32hihl.png" alt="code" width="800" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a commission from metadata
&lt;/h3&gt;

&lt;p&gt;As we iterate with our platform economics, we’ll likely end up with different commission rates per restaurant. We can inject this commission as a variable as well, fetching it the example below from the restaurant account metadata:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcq1r39at41vop5otyac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcq1r39at41vop5otyac.png" alt="code" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More complexity
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Coupons
&lt;/h3&gt;

&lt;p&gt;Inundating the buy side with generous coupons is a common strategy to break the chicken and egg problem platforms face. If you’re really going for an Eats clone, you may subsidize the buy side so much that you’ll end up spending more for a purchase in discount than the commission you’ll get out of it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxahyuje82ty02i7knxca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxahyuje82ty02i7knxca.png" alt="graph" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the grand scheme of the above example, as a platform, we are $8 short overall. If this was the only payment flow to ever happen on our Stripe account, we wouldn’t be able to cover payouts to the rider and restaurant.&lt;/p&gt;

&lt;p&gt;As we rinse and repeat this process for thousands of sales, it becomes critical to properly track these marketing losses to avoid putting ourselves at risk of ever defaulting payouts.&lt;/p&gt;

&lt;p&gt;Numscript comes with multi-sources transactions which we can use to model our marketing expense. Let’s first credit $15k to a coupon account for a specific campaign:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn07n2xmnt4g51npihlvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn07n2xmnt4g51npihlvx.png" alt="code" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then in script executing at payment time, we’ll use this coupons as a source of marketing funds, from which we’ll draw up to $19.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswon75hmd7nc5d42kqzv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswon75hmd7nc5d42kqzv.png" alt="code" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Refunds at loss
&lt;/h3&gt;

&lt;p&gt;So, the food arrived colder than it left the freezer at the restaurant. Customer files a ticket and you can’t know for sure wether the weather, rider, or restaurant is at fault here. As a platform you may decide to eat the loss, issuing a partial refund to your customer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6ac51fw9sr31s7hkcti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu6ac51fw9sr31s7hkcti.png" alt="graph" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Properly registering this loss as a money movement in our ledger will, in addition to keeping the books in check, once again help us prevent defaulting risk as we’ll be able to create routine processes of topping-up your Stripe platform account to cover for losses.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reconciliation
&lt;/h2&gt;

&lt;p&gt;The internal flow we defined in blue sits between &lt;em&gt;input&lt;/em&gt; and &lt;em&gt;output&lt;/em&gt;. It tracks what is owed to whom, and only makes sense if it eventually supports actual money movements in the real world, which we achieve through payments processors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fheoekexgjyabydf52in3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fheoekexgjyabydf52in3.png" alt="graph" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recon is a complex payments 101 problem. We want to make sure that assumptions we make in our system, e.g. that we received $59 from our customer, hold true in the external systems we use over time. As an example, your customer may charge back their payment after a few weeks, breaking your reconciliation. Ideally, every payment on your provider should be linked to an internal ledger transaction. In a further article, we’ll cover techniques and scripts to continuously reconcile our flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes on legal design and compliance
&lt;/h2&gt;

&lt;p&gt;We mentioned defaulting risk a few times in this piece. I’ve heard objections to this concern, usually quoting perpetual growth combined with positive cash float as a mechanism to make up for platform losses and marketing expenses. This can only be true if properly measured with a ledgering strategy and to the surprise of no one, auditors are not particularily fond of this scheme, no matter how exciting the idea of a fractional-reserve marketplace sounds on paper.&lt;/p&gt;

&lt;p&gt;In any case, your local lawyers are the best advisors on what you can and cannot do with your payments flows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As a platform, having a holistic view of your money flows and being able to know at any point in time what is owed to whom is critical. Using a ledger-oriented programmation model will help us achieve both reliability and visibility, as immutable transactions become the fundamental construct of state in our system.&lt;/p&gt;

</description>
      <category>payment</category>
      <category>ledger</category>
      <category>go</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
