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.
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
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 settledfinancial 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 accountbusiness 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.
Here is an example how you can use this approach to record a sale on your e-commerce marketplace. In the following example:
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.
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:
$ 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" }'
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"
}
}
}
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
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
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 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.
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.
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
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)
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.
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.
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.
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 |
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 |
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 |
ModFin only accepts https
calls. Point all requests to https://api.modfin.io
.
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
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
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": "..."
}
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.
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 |
$ 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" }'
Property | Description |
---|---|
customer |
Specifies who is the order by |
$ curl -X POST https://api.modfin.io/orders \
-u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
-d '{ "customer": "alice" }'
201 Created
Location: /orders/b2e9c1a6645d
{
"id": "b2e9c1a6645d",
"url": "/books/main/orders/b2e9c1a6645d"
"customer": "alice"
"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 |
$ 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"
}'
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"
}
Record a new business activity, such as an invoice, payment, withdrawal, etc.
Property | Description |
---|---|
type |
Type of the activity in the book's template |
$ 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" }'
201 Created
Location: /activities/58c3eb2dee1fec08f0d908b2
{
"status": "success",
"data": {
"activity": {
"type": "invoice"
"id": "58c3eb2dee1fec08f0d908b2",
"url": "/activities/58c3eb2dee1fec08f0d908b2",
"transactions": []
}
}
}
$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy https://api.modfin.io/activities/58c3eb2dee1fec08f0d908b2 \
{
"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"
}
]
]
}
}
}
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:
...and much more.
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) |
$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \ -X GET https://localhost:8080/transactions?q=journal:cash
{ "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" } ] } }
Add additional transactions to an existing activity
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.
$ 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"
}'
202 Accepted
Location: /requests/58c3f3a7fe3e410980610d74
{
"status": "success",
"data": {
"request": {
"status": "PENDING",
"id": "58c3eb2dee1fec08f0d908b2",
"url": "/requests/58c3eb2dee1fec08f0d908b2"
}
}
}
$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy https://api.modfin.io/transactions/58c3eb2dee1fec08f0d908b3 \
{
"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 a transaction
Similar to creating a transaction, reversal is done asynchronously.
When the request completes, a new compensating transaction will be created. This reversal transaction will:
Reversals will also be recorded on any transactions chained to the original transaction.
$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \ -X PUT https://api.modfin.io/transactions/58c3eb2dee1fec08f0d908b8/reversal \
202 Accepted
Location: /requests/58c3f3a7fe3e410980610d76
Returns a full view of a book, broken down by various attributes
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
$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \ https://api.modfin.io/trialbalance?attributes=journal,account,balance_type&post_date=2017-03-01
{ "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" }, ... ] } }
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.
or
$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \ -X GET https://localhost:8080/org
{
"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"
}
]
}
}
}
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 for the authenticated user
$ curl https://api.modfin.io/books \ -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy
{ "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 for the authenticated user. Each org will have a main
book and a test
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. |
$ curl -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy \
-X PUT https://api.modfin.io/books/test \
-d '{ "display_name": "Just another test" }'
Get basic info on a given book
$ curl https://api.modfin.io/books/main \ -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy
{
"status": "success",
"data": {
"book" : {
"name": "main",
"display_name": "Main",
"url": "/books/main"
"template": {
"name": "base",
"url": "/templates/base"
}
}
}
}
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.
Upload a new 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 |
$ 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" }
{
"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 all available templates for your organization
$ curl https://api.modfin.io/templates \ -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy
{
"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 the entire template, including activity types, transaction types and journal setup.
See an example template here.
$ curl https://api.modfin.io/templates/base \ -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy
List all your transaction types
Add a new activity type to the template. If the activity type already exists, this will overwrite the existing activity
View an activity type and, optionally, all the corresponding transaction types
List all your transaction types
Create a new transaction type for the authenticated user, or, if template exists (and new version is different), create a new version
Retrieve a transaction type (optionally specify version in parameter).
Property | Description |
---|---|
version |
(optional) Specify a version, by default the latest version will be returned |
List journals in a given book
Add journals to the given book
Property | Description |
---|---|
ledger_category |
One of
assets
,
liabilities
,
revenues
,
expenses
,
equity |
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.
$ curl https://api.modfin.io/templates \ -u api-key:YzcwNGI0YjMtNTJjYi00MmQ0LWEwNDctMmFhY2MwOTQ4YTUy
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"
}
}
}