Guide

Introduction

ModFin provides financial transaction management for platforms and marketplaces. It is a highly flexible, event-driven, transaction-based financial system based on a modern approach to age-old accounting concepts.

The goal of this document is to get you started using ModFin in a few simple steps and get you familiar with the system. We will introduce our approach to managing finances, followed by an example to show how you can start recording and managing transactions for an e-commerce marketplace connecting buyers and sellers, and then get into more complex features such as adjustments and re-balancing.

If you have questions, problems, requests or suggestions at any point, please email support@modfin.io.

Key principles

Finances can get complex but to simplify it ModFin follows a couple of key principles that you should know before we get started.

Each piece of financial information is recorded once. The information is then never deleted or overwritten. Instead, we keep a history of what happened. When a change or adjustment is necessary – be it an error or a deliberate change – we record a compensating transaction with an opposite impact to the original transaction and then record the corrected one.

For example, let's assume we charged a shipping fee erroneously and only realized it much later.

Date Item Amount
1/1/2017 Shipping fee $6
2/4/2017 Shipping fee -$6
2/4/2017 Shipping fee $4

Each transaction has two timestamps. The first one signifies when the transaction was recorded, i.e. when it posted. The second one describes when a transaction should or should have happened, i.e. when it was/will be effective. The distinction between the post date and the effective date allows us to create two differing views of the same financial data that are not at odds with each other.

Post date Effective date Item Amount
1/1/2017 1/1/2017 Shipping fee $6
2/4/2017 1/1/2017 Shipping fee -$6
2/4/2017 1/1/2017 Shipping fee $4

The impact is that if you look at the effective shipping fee on 1/1/2017, the amount is $4, never $6. However, you still know the history

Money does not get created out of thin air – unless of course you are the banking system – and so noting where the money came from and where it is going makes sense. ModFin is based on double-entry bookkeeping principles. Double-entry accounting has been the standard way of recording finances since the 15th century so you could say it is a well-tested technology.

The idea is simple: in a financial transaction debits always equal credits. If you want to know a little bit more, here is a quick primer.

Post date Effective date Debit/credit Item Amount
1/1/2017 1/1/2017 Debit Shipping fee receivable from customer $6
1/1/2017 1/1/2017 Credit Shipping fee payable to provider $6

We use a standardized way to store and explain all monetary data (i.e. money as well as claims on money). Unless you do this, you will never know what you missed. Also, we want to make sure you do not spend time mining your own transactional data.

We record financial information in three layers, business activities, financial transactions and journal entries

  • A journal entry contains a single debit or credit with a number of attributes that describe what the entry is related to. For example, an entry will represent a $100 credit to a buyer's account when her credit card charge is settled
  • A financial transaction is an event recorded at a given time containing a number of (at least two) journal entries that balance, meaning that they have equal amount of debits and credits. For example, a 'credit card payment' transaction will have an entry showing a $100 credit to a buyer's account and a $100 debit to the company's bank account
  • A business activity is a collection of related transactions. They can be related either because they tend to happen together or because they represent the lifecycle of a transaction. For example, a 'payment' activity can have a credit card payment transaction and a corresponding service charge payment transaction. When a chargeback occurs, the transaction reversing the credit card payment also becomes part of the same 'payment' activity.

Following the prior example:

Business activity Transaction Post date Effective date
Order Order item - shipping fee 1/1/2017 1/1/2017

And the journal entries, as before...

Debit/credit Item Amount
Debit Shipping fee receivable from customer $6
Credit Shipping fee payable to provider $6

Traditional accounting is based on the idea of recording transactions against "accounts". Instead, we allow you to create virtual accounts from the metadata associated with each transaction, making analytics a breeze. You can compose virtual accounts showing the amount you earned from various fees or virtual accounts that represent transactions by individual power sellers that you can expose to them as part of your service offering.

Debit/credit Item Amount Metadata
Debit Shipping fee receivable from customer $6 Account: Alice, Journal: Orders, Provider: Bob
Credit Shipping fee payable to provider $6 Account: Bob, Journal: Providers, Customer: Alice, Payment due: no

The ability to re-execute a transaction allows us to dynamically adjust the books when needed. The section about automatic re-balancing has an example of this in action.

1. Treat financial data as immutable

2. Know what happened vs what should have happened

3. Record effect and counter-effect

4. Use a central repository for all your financial data

5. Keep metadata close to the transaction

6. Create "smart" transactions

Getting started

Here is an example how you can use this approach to record a sale on your e-commerce marketplace. In the following example:

  1. a buyer will place an order,
  2. then pay for the order,
  3. you will charge some fees for your service,
  4. pay the seller, and
  5. look at how much money you made.

Step 1: sign up for an account

If you don't already have one, email us at support@modfin.io to set up an account.

For the following example, we will be part of the acme-market organization and will use the API key YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy. You can try this on the sandbox at https://sandbox.api.modfin.io.

Step 2: set up our product and fees

Let's say you want to sell physical goods and charge shipping fees that are passed through to your provider and then charge your provider a fee for making the sale.

Now we set up items we can add to an order:

  • Merchandise: which will represent the goods sold and their price
  • Shipping fee: a fee charged for shipping by the seller to the buyer
  • Seller fee: a fee paid by the seller to you for completing the sale
$ curl -X PUT https://api.modfin.io/catalog/products/merchandise \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ "method": "pass_through" }'
$ curl -X PUT https://api.modfin.io/catalog/charges/shipping_fee \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ "method": "pass_through" }'
$ curl -X PUT https://api.modfin.io/catalog/charges/seller_fee \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ method": "provider_paid" }'

Step 3: place an order

Assume you have a buyer, Alice, who wants to place an order to buy a $50 genuine ox horn from one of your sellers, Bob. Bob charges $6 to Alice for shipping. You will also collect a $10 fee from Bob for the sale. Note that the customer IDs and item references usually have a meaningful identifier in the calling system already.

First let's create a new order:


We can add a product to the order. Note that the provider is assigned real-time:

Then let's add the fees:

By default all orders are automatically due so we can check how much money Alice owes us now to complete the purchase.

$ curl -X POST https://api.modfin.io/orders \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ "customer": "alice" }'

201 Created
Location: /orders/b2e9c1a6645d

$ curl -X POST https://api.modfin.io/orders/b2e9c1a6645d/items \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{
            "type": "mercandise",
            "reference": "genuine_ox_horn",
            "provider": "bob",
            "amount": "50"
          }'
$ curl -X POST https://api.modfin.io/orders/b2e9c1a6645d/items \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ "type": "shipping_fee", "provider": "bob", "amount": "6" }'
$ curl -X POST https://api.modfin.io/orders/b2e9c1a6645d/items \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ "type": "seller_fee", "provider": "bob", "amount": "10" }'
$ curl https://api.modfin.io/balances?account=alice&due=true \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy
{
  "data": {
    "balance": {
      "account": "alice",
      "due": "true",
      "post_date": "2017-04-01T00:00:00-08:00",
      "debit_credit": "DEBIT",
      "currency": "USD",
      "amount": "56.00"
    }
  }
}

Step 4: collect payment

Alice already provided us with a credit card so we can charge her for the payment of $56. Once the charge settles, we need to record the transaction. Currently only manually recorded transactions are available. We are working on integrating payment gateways.

Now something very important happened behind the scenes. By default, payouts to the sellers are due upon receiving payment from the customer. So in addition to recording the sale, the payment action also triggered invoices to the sellers so now payouts to the sellers are due. With a simple query you can tell how much money you need to transfer to Bob. (In accounting terms, the appropriate sellers had the corresponding sums (less fees) transfered over to a payables due account. Note that there is no explicit math behind this, the transaction is just clearing the accounts set up when we recorded the order.)

Let's verify a couple of things. First of all, we can take a look at the over state of our books, represented by the trial balance.

Your book's trial balance looks like this:

Journal Account Balance type Due Amount Journal Account Balance type Due Amount
Cash Operating cash $56 Providers Bob Seller fee Yes ($10)
Merchandise Yes $50
Shipping fee Yes $6
Fee income Seller fee $10

Look at the various journals: you have $56 in cash and booked $10 in income. When you look at Bob's account in the Providers journal, you can see you also owe Bob $46, $50 for merchandise, $6 for shipping fee minus $10 in seller fee.

$ curl -X POST https://api.modfin.io/payments \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '
        { "account": "alice",
          "gateway": "manual",
          "amount": "56"
        }
$ curl https://api.modfin.io/trialbalance?attributes=journal,account,balance_type,due \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy

Step 5: pay out the seller

Let's pay out Bob, our seller. Once the payment is made, you can record the transaction:

That's it. The order/purchase/payout all went through and if you run the trial balance report again, you see you are left with $10 in cash and, correspondingly, with $10 in booked fee income.

Journal Balance type Amount Journal Balance type Amount
Cash Operating cash $10 Fee income Seller fee $10
$ curl -X POST https://api.modfin.io/payouts \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{
            "account": "bob",
            "gateway": "manual",
            "amount": "46"
          }'
$ curl https://api.modfin.io/trialbalance?groups=journal,balance_type \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy

Reversals, corrections and adjustments

Annulling a transaction

Making adjustments is easy but a lot happens below the surface in order to adhere to the key principles outlined above. Generally when some item, charge, credit, payment or payout is "deleted", what happens is that a compensating transaction is created that has the effect of negating the original transaction.

To follow the example from the #2 principle above, let's say we booked a shipping fee on January 1st which we now want to change on February 3rd. First, we need to record a reversal. Note that the effective date always remains 1/1:

Post date Effective date Item Debit/Credit Amount
1/1/2017 1/1/2017 Shipping fee Debit $6
2/4/2017 1/1/2017 Shipping fee Credit $6

This has the effect of negating the charge but keeping a clean record of it. Assuming monthly statements are generated for the customer, the January and February statements might look something like this:

January:

Post date Activity Details Amount
1/1 Order Merchandise $100
Shipping fee $6
1/2 Payment Thank you! ($106)

February:

Post date Activity Details Amount
2/4 Order Shipping fee adjustment ($6)

However, for any internal computations or metrics we need to use the effective view, using the effective dates on the transaction. Querying the shipping fee as of 1/1 post date will show a balance of $6 while querying with a 1/1 effective date will return a balance of $0.

We will talk about what happens to the payment already made later, but in short it's composition changes from $100 paid for merchandise and $6 paid for shipping to $100 paid for merchandise and a $6 credit that can be used for future orders and deducted from future payments or reimbursed. Similarly, metrics will adjust to reflect that no shipping fee was charged on this order.

For the specifics of how to remove items, payments or payout records, please take a look at the specific APIs. In general, doing a DELETE on the resource will do the trick.

Adjusting a transaction

Adjusting a transaction is a similar process to reversing. In fact, in order to keep clean records and traceable computations, the preferred way to adjust is to reverse first and then book the adjusted amounts (as opposed to booking a transaction with the difference in amounts).

To follow our example from above, let's say with needed to charge only $4 for shipping instead of $6:

Post date Effective date Item Debit/Credit Amount
1/1/2017 1/1/2017 Shipping fee Debit $6
2/4/2017 1/1/2017 Shipping fee Credit $6
2/4/2017 1/1/2017 Shipping fee Debit $4

The customer statement will now show:

January:

Post date Activity Details Amount
1/1 Order Merchandise $100
Shipping fee $6
1/2 Payment Thank you! ($106)

February:

Post date Activity Details Amount
2/4 Order Shipping fee adjustment ($2)

Querying the amount of shipping fee charged on 1/1 post date will show $6 but the effective view on 1/1 will show a charge of $4. The composition of the payment also changed to $100 for the merchandise, $4 for shipping and $2 unused credit.

Metrics will adjust to reflect a $4 charge.

The API call to make an adjustment is generally a PATCH call on the resource. See the API reference for details.

Automatic re-balancing

Adjusting a transaction might have a cascading effect. In the example above, changing the amount of a fee on the order impacts the composition of what was paid for, which in turn impacts what gets invoiced and paid out to the provider.

Assuming the provider for the order gets paid at the end or February, we need to know that only $104 is due instead of $106. Automatic re-balancing is a feature that allows us to "rewind and redo" transactions that might have been affected by an adjustment.

Basically, if a transaction is adjusted, all transactions that happened after the adjusted transaction and are related, i.e. operate on the same underlying accounts or is part of the same implicit contract between customer and provider, gets reversed and rerun.

  1. In the above example, the payment used to represent a $100 of merchandise and a $6 shipping fee but now it now represents a $100 for the merchandise, $4 for shipping and $2 in unused credit

  2. Assume a new order came in from the same customer on 2/3 but it has not been paid for. Now we have:

January:

Post date ID Activity Details Amount
1/1 123 Order Merchandise $100
Shipping fee $6
1/2 456 Payment Thank you! ($106)

February:

Post date ID Activity Details Amount
2/3 789 Order Merchandise $200
Shipping fee $10
2/4 123 Order Shipping fee adjustment ($2)

Querying the due balance at this point will give us $210 if we didn't re-balance the transactions following the adjustment but it will give us $208 is we properly re-balanced the books. Hence you can make the customer happy and let them immediately use their credit. Also, there is no need for unnecessary reimbursements.

2/4 | 345 | Payment | Thank you! | ($208)

  1. Let's assume that you need to make a payout to the provider at the end on February for all prior orders. Without re-balancing, you would owe them $106+$210 = $316. With the re-balancing the amount owed is $314.

When executing a reversal or adjustment the system by default re-balance but you can choose not to cascade through the impacted transactions by passing in {cascade: false} in the respective APIs.

Examples

Currencies and commodities

There is multi-currency support in ModFin. However, there is currently no support for conversions. What this means is that it is possible that, say, an order or invoice gets booked as a CAD 100 receivable and the payment that come in to pay for the order is USD 75. In that case the transactions will not offset and the account will continue to have a debit balance of CAD 100 and a credit balance of USD 75.

Each currency is designated by their ISO 4217 currency code. The exception is that when the currency code is omitted or specified only by a $ sign, ModFin will assume that the intended currency is USD.

API Reference

Overview

The following is reference manual that describes the ModFin API. The current version is v1. We are in beta mode so this document still is a draft.

The API is located at api.modfin.io.

The API has multiple layers. ModFin is built on top of a robust and highly flexible accounting system, some of which is exposed through the Accounting APIs. The Marketplace APIs help manage common marketplace transactions. The Management APIs help with setting up users and access keys as well exposing some system functionality such as checking the status of a request.

Marketplace APIs

The marketplace APIs are the high level APIs that manage financial transactions for a marketplace. It provides the following key resources:

Resource Description
Catalog Adding products, services, charges and credits that can be part of an order.
Orders An order is specific to a customer and incorporates the specific products, services, charges and credits associated with an order.
Items The specific product, service, charge or credit that is either part of the order or a standalone charge/credit.
Invoices Invoices are representations of what is due from a customer or to a provider. In most cases, invoicing can be set up to be automatic.
Payments Taking and recording payments from customers (or potentially providers).
Payouts Making and recording payouts to providers (or in some cases customers).
Description API
Catalog
Add to catalog PUT /catalog/:name
Remove from catalog DELETE /catalog/:name
View catalog GET /catalog
Get specific item from catalog GET /catalog/:name
Orders
Start new order POST /orders
Add item to order POST /orders/:order/items
Remove order DELETE /orders/:order
Find orders GET /orders?q=...
View order GET /orders/:order
List items in order GET /orders/:order/items
Standalone charges and credits
Add standalone charge or credit POST /items
Invoice standalone charge or credit PUT /items/:item/invoice
Items and adjustments
Remove item DELETE /items/:item
Change amount on item PATCH /items/:item
Find items GET /items?q=...
View specific item GET /items/:item
Invoices
View invoice for specific account GET /invoices?q=account:...
Payments
New payment POST /payments
Cancel payment DELETE /payments/:payment
Change payment amount PATCH /payments/:payment
List payments GET /payments
View specific payment GET /payments/:payment
Payouts
New payout POST /payouts
Cancel payout DELETE /payouts/:payout
Change paid amount PATCH /payouts/:payout
List payouts GET /payouts
View specific payout GET /payouts/:payout

Summary

Accounting APIs

Accounting APIs expose some of the underlying accounting system and are primarily used for reporting, querying balances, finding and listing transactions or generating entries for the company's general ledger. These APIs also allow for some administrator level troubleshooting and overrides. The key resources:

Resource Description
Activities These are an accounting representation of common business activities, such orders, payments and payouts.
Transactions Find and query transactions. It also allows for manual updates for individual transactions given the right access level.
Balances Provides balances on accounts, group of accounts.
Trial balance Provides a full view of the entire book at the chosen level of detail.
Description API
Activities
Book new activity POST /activities
Add transaction to activity POST /activities/:activity/transactions
Find activities GET /activities?q=...
View specific activity GET /activities/:activity
Find transactions under given activity GET /activities/:activity/transactions/q=...
Transactions
Reverse a transaction PUT /transactions/:transaction/reversal
Query the books GET /transactions?q=...
Balances
Retrieve balance on accounts GET /balances?q=...
Trial balance
Explore the entire book GET /trialbalance

Summary

Management APIs

Resource Description
Organizations Central place for managing users and access.
Books A book is what contains all the various financial data for a given organization or a business line within an organization. The API helps manage multiple books.
Templates A template describes the allowed activity and transaction types as well as what sub-journals a book contains.
Requests Manage long-running operations
Description API
Organizations
View current organization GET /org
View specific organization GET /organizations/:org
Retrieve API keys for organization GET /organizations/:org/apikeys
Books
Open a new book PUT /books/:book
List books for the organization GET /books
View a specific book GET /books/:book
Templates
List templates for the organization GET /templates
View specific template GET /templates/:template
List activity types GET /templates/:template/activitytypes
View specific activity type GET /templates/:template/activitytypes/:type
List transaction types GET /templates/:template/transactiontypes
View specific transaction type GET /templates/:template/transactiontypes/:type
List journals GET /templates/:template/journals
Requests
Get status of a long-running operation GET /requests/:request

Summary

Protocol

ModFin only accepts https calls. Point all requests to https://api.modfin.io.

Authentication

All requests must be authenticated. We use Basic authentication where the username is always api-key and the password is the API key provided to the organization/user.

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy https://api.modfin.io

Versioning

The current version is v1 and there are no legacy versions supported. In the future, versioning of the specific calls will be done through the Accept header.

To request a specific version, use the application/vnd.modfin.v1+json media type. Inclusion of the header by default is encouraged.

Accept: application/vnd.modfin.v1+json

Format

All request bodies and responses are in JSON format.

In case the request was successful, the API will return a corresponding status code and requested resource.

If there is an error, the API will return an error status and a message with the details.

{
  "status": "error",
  "message": "..."
}

Marketplace APIs

Catalog

The catalog contains the type of items a customer or provider can charged for or credited. There are three categories of items, products which is the product or service offers, charges which designate the different fees and credits which denote any type of credit to the customer, promotion or discount.

Most of these items will be part of an order. The product offered and any associated charges, whether paid by the customer or the provider, should be part of an order.

Some of these charges can be standalone items that are not part of the order. Examples are a subscription fee, a maintenance fee, a management fee, a goodwill credit, etc. These can be added through the standalone resource.

Add to the catalog

PUT
/catalog/:name
Property Description
method Specifies who pays and receives the payment for the item:
pass_through designates that the funds go from customer to provider
customer_paid means that the customer will be charged and the corresponding amount will be booked as income
provider_paid means that the provider will be charged and the amount will be treated as income
customer_credit means that the customer will receive a credit that will be booked as an expense
provider_credit means that the provider will receive a credit that will be booked as an expense
display_name (optional) Display name of the book. If not provided, the item's name will be automatically humanized (e.g. 'shipping_fee' will become 'Shipping fee')
category Can be products , charges or credits

Examples

$ curl -X PUT https://api.modfin.io/catalog/merchandise \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ "method": "pass_through", "category": "products" }'
$ curl -X PUT https://api.modfin.io/catalog/shipping_fee \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ "method": "pass_through", "category": "charges" }'
$ curl -X PUT https://api.modfin.io/catalog/refer_a_friend \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ method": "customer_credit", "category": "credits"  }'

View the catalog

GET
/catalog

Orders

Start new order

POST
/orders
Property Description
customer Specifies who is the order by

Example

$ curl -X POST https://api.modfin.io/orders \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{ "customer": "alice" }'

Response

201 Created
Location: /orders/b2e9c1a6645d

{
  "id": "b2e9c1a6645d",
  "url": "/books/main/orders/b2e9c1a6645d"
  "customer": "alice"
  "items": []
}

Add item to order

POST
/orders/:order/items
Property Description
type Specifies the catalog item that goes in the order
provider Who is the provider. Needed when the method is pass_through , provider_paid or provider_credit
reference An external reference to the item, e.g. a product ID
currency The currency used
amount The amount for the item

Example

$ curl -X POST https://api.modfin.io/books/main/orders/b2e9c1a6645d/items \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -d '{
            "type": "mercandise",
            "reference": "genuine_ox_horn",
            "provider": "bob",
            "currency": "EUR",
            "amount": "50"
          }'

Response

201 Created
Location: /items/b3e9c1a6645d

{
  "id": "b3e9c1a6645d",
  "url": "/items/b3e9c1a6645d"
  "type": "mercandise",
  "reference": "genuine_ox_horn",
  "customer": "alice",
  "provider": "bob",
  "currency": "EUR",
  "amount": "50.00000000000"
}

Accounting APIs

Activities

New business activity

Record a new business activity, such as an invoice, payment, withdrawal, etc.

POST
/books/:book/activities
Property Description
type Type of the activity in the book's template

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -X POST https://api.modfin.io/books/test/activities \
       -H "Content-Type: application/vnd.modfin.v1+json" \
       -d '{ "type": "invoice" }'

Response

201 Created
Location: /activities/58c3eb2dee1fec08f0d908b2

{
  "status": "success",
  "data": {
    "activity": {
      "type": "invoice"
      "id": "58c3eb2dee1fec08f0d908b2",
      "url": "/activities/58c3eb2dee1fec08f0d908b2",
      "transactions": []
    }
  }
}

Retrieve an activity

GET
/activities/:id

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy
       https://api.modfin.io/activities/58c3eb2dee1fec08f0d908b2 \

Response

{
  "status": "success",
  "data": {
    "activity" : {
      "type": "invoice",
      "id": "58c3eb2dee1fec08f0d908b2",
      "url": "/activities/58c3eb2dee1fec08f0d908b2",
      "transactions": [
        "id": "58c3eb2dee1fec08f0d908b3",
        "url": "/transactions/58c3eb2dee1fec08f0d908b3"
        "type": "merchandise",
        "display_type": "Merchandise",
        "post_date": "2017-03-13T12:58:20-08:00",
        "effective_date": "2017-03-13T12:58:20-08:00",
        "reversal": false,
        "entries": [
          {
            "currency": "USD",
            "amount": "100.00",
            "debit_credit": "DEBIT",
            "journal": "invoices",
            "ledger_category": "assets",
            "ledger_side": "left",
            "balance_type": "merchandise",
            "customer_account": "alice",
            "contract": "4321",
            "item": "genuine_ox_horn",
            "seller_account": "bob"
          },
          {
            "currency": "USD",
            "amount": "100.00",
            "debit_credit": "CREDIT",
            "journal": "sellers",
            "ledger_category": "liabilities",
            "ledger_side": "right",
            "balance_type": "merchandise",
            "customer_account": "bob",
            "contract": "4321",
            "due": false,
            "item": "genuine_ox_horn",
            "buyer_account": "alice"
          }
        ]
      ]
    }
  }
}

Transactions

Queries

Queries can be constructed to get a list of journal entries/transactions/activities. The format is very simple, just provide the filter for the dates and the attributes. This can be extremely powerful as it can give you a variety of different view of the data, such as:

  • customer statements or dashboards
  • analytics on volume, gross sales, income
  • accounting entries
  • cash flows

...and much more.

GET
/transactions
Property Description
q (Optional) Comma-separated list of attributes:values. Apart from journal attributes, you can provide values for activity_type , transaction_type , debit_credit and currency
from
to
(optional) List activities that have transactions with a post date between the specified dates (inclusive)
from_effective
to_effective
(optional) List activities that have transactions with a post date between the specified dates (inclusive)

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -X GET https://localhost:8080/transactions?q=journal:cash

Response

{
  "transactions": [
   {
    "activity_id": "299b776b295e",
    "activity_type": "purchase",
    "activity_display_type": "Purchase",
    "transaction_id": "013669838053",
    "transaction_type": "buyer_payment",
    "transaction_display_type": "Buyer payment",
    "post_date": "2017-01-05",
    "effective_date": "2017-01-05",
    "entries": [
     {
      "amount": 56,
      "journal": "cash",
      "currency": "USD",
      "balance_type": "operating_cash",
      "debit_credit": "DEBIT",
      "signed_amount": 56
     }
    ],
    "total_amount": "56.0000000000",
    "total_debits": "56.0000000000",
    "total_credits": "0.0000000000"
   },
   {
    "activity_id": "dfa69efc1195",
    "activity_type": "payout",
    "activity_display_type": "Payout",
    "transaction_id": "5cd2abe4cebe",
    "transaction_type": "seller_payout",
    "transaction_display_type": "Seller payout",
    "post_date": "2017-01-16",
    "effective_date": "2017-01-16",
    "entries": [
     {
      "amount": 46,
      "journal": "cash",
      "currency": "USD",
      "balance_type": "operating_cash",
      "debit_credit": "CREDIT",
      "signed_amount": -46
     }
    ],
    "total_amount": "-46.0000000000",
    "total_debits": "0.0000000000",
    "total_credits": "46.0000000000"
   }
  ]
 }
}

New transactions (admin)

Add additional transactions to an existing activity

POST
/activities/:id/transactions
Property Description
type The transaction type to be recorded

Also include, any additional parameters specific to the transaction.

To see what are the possible parameters, you can GET /activities/:activity/transactions/types which is a synonym for GET /templates/:template/transactiontypes.

Booking transactions is done asynchronously. The response will contain a Location header indicating the request. The request will eventually resolve to contain the newly created transaction and 303 redirect to the new transaction.

Creating a transaction can result in creating other, chained transactions. These will be indicated when you retrieve a transaction.

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -X POST https://api.modfin.io/activities/58c3eb2dee1fec08f0d908b2/transactions \
       -H "Content-Type: application/vnd.modfin.v1+json" \
       -d ' 
        {
          "type": "expedited_shipping_fee",
          "amount": "15",
          "buyer_account": "alice", 
          "seller_account": "bob", 
          "contract": "123"        
        }'

Response

202 Accepted
Location: /requests/58c3f3a7fe3e410980610d74

{
  "status": "success",
  "data": {
    "request": {
      "status": "PENDING",
      "id": "58c3eb2dee1fec08f0d908b2",
      "url": "/requests/58c3eb2dee1fec08f0d908b2"
    }
  }
}

View transaction

GET
transactions/:id

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy
       https://api.modfin.io/transactions/58c3eb2dee1fec08f0d908b3 \

Response

{
  "status": "success",
  "data": {
    "transaction" : {
      "id": "58c3eb2dee1fec08f0d908b3",
      "url": "/transactions/58c3eb2dee1fec08f0d908b3"
      "type": "merchandise",
      "display_type": "Merchandise",
      "post_date": "2017-03-13T12:58:20-08:00",
      "effective_date": "2017-03-13T12:58:20-08:00",
      "reversal": false,
      "entries": [
        {
          "currency": "USD",
          "amount": "100.00",
          "debit_credit": "DEBIT",
          "journal": "invoices",
          "ledger_category": "assets",
          "ledger_side": "left",
          "balance_type": "merchandise",
          "customer_account": "alice",
          "contract": "4321",
          "item": "genuine_ox_horn",
          "seller_account": "bob"
        },
        {
          "currency": "USD",
          "amount": "100.00",
          "debit_credit": "CREDIT",
          "journal": "sellers",
          "ledger_category": "liabilities",
          "ledger_side": "right",
          "balance_type": "merchandise",
          "customer_account": "bob",
          "contract": "4321",
          "due": false,
          "item": "genuine_ox_horn",
          "buyer_account": "alice"
        }
      ],
      "activity": {
        "id": "58c3eb2dee1fec08f0d908b2",
        "url": "/books/test/activities/58c3eb2dee1fec08f0d908b2"
      },
      "chained_transactions": [
        {
          "id": "58c3eb2dee1fec08f0d908b9",
          "url": "/transactions/58c3eb2dee1fec08f0d908b9"
        }
      ]
    }
  }
}

Reverse transaction (admin)

Reverse a transaction

PUT
/transactions/:id/reversal

Similar to creating a transaction, reversal is done asynchronously.

When the request completes, a new compensating transaction will be created. This reversal transaction will:

  • By default belong to the same business activity
  • Have an effective date identical to the original transaction
  • Have a post date as of today
  • Have each journal entry from the original transaction replicated but with debits and credits flipped (canceling out the original transaction from an effective point of view)
  • Appear as a chained transaction to the original transaction

Reversals will also be recorded on any transactions chained to the original transaction.

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -X PUT https://api.modfin.io/transactions/58c3eb2dee1fec08f0d908b8/reversal \

Response

202 Accepted
Location: /requests/58c3f3a7fe3e410980610d76

Trial balance

Returns a full view of a book, broken down by various attributes

GET
/trialbalance
Property Description
attributes (optional) Comma-separated list of attributes. By default, all attributes will be used. These can produce large data sets so explicitly setting the requested attributes is preferred
post_date (optional) Run trial balance as of the given post date. By default, today's date is used
effective_date (optional) Run trial balance as of the given effective date. This will return an effective view of the book, including back- and future-dated transactions

You can provide comma-separated lists for the following highlighted attributes, or any custom attributes:

  • activity_type
  • transaction_type
  • journal
  • balance_type
  • customer_account
  • due

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       https://api.modfin.io/trialbalance?attributes=journal,account,balance_type&post_date=2017-03-01

Response

{
  "trial_balance": [
    {
      "journal": "cash",
      "ledger_category": "ASSETS",
      "ledger_side": "LEFT",
      "balance_type": "operating_cash",
      "debit_credit": "DEBIT",
      "currency": "USD",
      "amount": "56"
      "signed_amount": "56"
    },
    {
      "journal": "sellers",
      "ledger_category": "LIABILITIES",
      "ledger_side": "RIGHT",
      "customer_account": "bob",
      "balance_type": "commission",
      "debit_credit": "DEBIT",
      "currency": "USD",
      "amount": "10.00",
      "signed_amount": "10.00",
      "display_amount": "-10.00"
    },
    ...
  ]
}
}

Management APIs

Organizations

View your organization

View your organization. You can either use the the implicit org resource, which always refers to the authenticated organization or the explicit organizations resource. Requests to unauthenticated organizations will be rejected.

GET
/organizations/:org

or

GET
/org

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -X GET https://localhost:8080/org

Response

{
  "status": "success",
  "data": {
    "organization": {
      "name": "acme-market",
      "display_name": "ACME Marketplace"
      "url": "/organizations/acme-market"
      "books" : [
        {
          "name": "main",
          "url": "/books/main"
        },
        {
          "name": "test",
          "url": "/books/main"
        }
      ],
      "templates" : [
        {
          "name": "base",
          "url": "/templates/base"
        }
      ]
    }
  }
}

Books

A book is a placeholder for all transactions, orders, payments, payouts, etc. related to a business or line of business. You can set up a book for segregating transactions, either because the structure is is different or the lines of business are unrelated. There is a book set up by default which is the main book.

List books

List books for the authenticated user

GET
/books

Example

$ curl https://api.modfin.io/books \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy

Response

{
  "status": "success",
  "data": {
    "books" : [
      {
        "name": "main",
        "display_name": "Main",
        "url": "/books/main",
        "template": {
          "name": "base",
          "url": "/templates/base"
      },
      {
        "name": "test",
        "display_name": "Test",
        "url": "/books/test",
        "template": {
          "name": "base",
          "url": "/templates/base"
      }
    ]
  }
}

Create a new book

Create a new book for the authenticated user. Each org will have a main book and a test book

PUT
/books/:book
Property Description
display_name (optional) Display name of the book. If not provided, the book's name will be automatically humanized (e.g. 'main_book' will become 'Main book')
template (optional) Associate a template with the new book. By default, it will be the base template.

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -X PUT https://api.modfin.io/books/test \
       -d '{ "display_name": "Just another test" }'

View a book

Get basic info on a given book

GET
/books/:book

Example

$ curl https://api.modfin.io/books/main \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy

Response

{
  "status": "success",
  "data": {
    "book" : {
      "name": "main",
      "display_name": "Main",
      "url": "/books/main"
      "template": {
        "name": "base",
        "url": "/templates/base"  
      }
    }
  }
}

Templates

Templates contain definitions for activity and transaction types. Templates also describe what journals a book contains. The preferred way to edit templates is through the ModFin template editor.

Create a new template

Upload a new template

PUT
/templates/:template
Property Description
copy (optional) Pre-populate the template (activity types, transaction types and journal definitions) from another template
display_name (optional) Specify the display name of the template. If not provided, the humanized name will be stored

Example

$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
       -X PUT https://api.modfin.io/templates/test \
       -H "Content-Type: application/vnd.modfin.v1+json" \
       -d `{ "copy": "modfin/ecommerce" }

Response

{
  "status": "success",
  "data": {
    "organization": {
      "name": "acme-market",
      "display_name": "ACME Marketplace",
      "url": "/organizations/acme-market"
    },
    "template" : {
      "name": "base",
      "display_name": "Base",
      "url": "/templates/base"
    }
  }
}

List your templates

List all available templates for your organization

GET
/templates

Example

$ curl https://api.modfin.io/templates \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy

Response

{
  "status": "success",
  "data": {
    "organization": {
      "name": "acme-market",
      "display_name": "ACME Marketplace",
      "url": "/organizations/acme-market"
    },
    "templates" : [
      {
        "name": "base",
        "display_name": "Base",
        "url": "/templates/base"
      }
    ]
  }
}

Retrieve a template

Retrieve the entire template, including activity types, transaction types and journal setup.

GET
/templates/:template

See an example template here.

Example

$ curl https://api.modfin.io/templates/base \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy

Response

List activity types

List all your transaction types

GET
/templates/:template/transactiontypes

Add/modify activity type

Add a new activity type to the template. If the activity type already exists, this will overwrite the existing activity

PUT
/templates/:template/activitytypes/:type

View activity type

View an activity type and, optionally, all the corresponding transaction types

GET
/templates/:template/activitytypes/:type

List transaction types

List all your transaction types

GET
/templates/:template/transactiontypes

Add/modify transaction type

Create a new transaction type for the authenticated user, or, if template exists (and new version is different), create a new version

PUT
/templates/:template/transactiontypes/:type

View transaction type

Retrieve a transaction type (optionally specify version in parameter).

GET
/templates/:template/transactiontypes/:type
Property Description
version (optional) Specify a version, by default the latest version will be returned

List journals

List journals in a given book

GET
/templates/:template/journals

Add/modify journals

Add journals to the given book

PUT
/templates/:template/journals/:journal
Property Description
ledger_category One of assets , liabilities , revenues , expenses , equity

Requests

View request status

View the status of a request. The request can be PENDING if it's still processing, CREATED if the requested resource was created and FAILED if there was an error processing the request.

GET
/requests/:request

Example

$ curl https://api.modfin.io/templates \
       -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy

Response

303 See Other
Location: /transactions/92bf87ff-c994-4cb2-bb9f-8773b6fb3253

{
  "status": "success",
  "data": {
    "request": {
      "status": "CREATED",
      "id": "58c3eb2dee1fec08f0d908b2",
      "url": "/requests/58c3eb2dee1fec08f0d908b2",
      "resource_url": "/transactions/92bf87ff-c994-4cb2-bb9f-8773b6fb3253"
    }
  }
}
Show examples in:
Developer