Threecolts - Hemi OS implementing Unified Billing (UB)
Version | Created By | Date | Notes |
---|---|---|---|
1.0 | Danail Deltchev | 17.10.2024 | First Publish |
1.1 | Danail Deltchev | 4.11.2024 | Cleanup after first real tests |
1.2 | Danail Deltchev | 8.12.2025 | Adding new field and small clarity updates |
The purpose of this page is to describe how we should handle Unified Billing from Hemi to Threecolts.
The whole purpose of Unified Billing is to provide a single and straightforward way for each application in the suite to provide data to a single source that then handles all the billing and processing for data tracking on this
The way this needs to be handled from Hemi is to:
- Cover for the new Hemi OS model
- Cover for the old pure Hemi model
As for both models everything is (predominantly) based on the performance of the previous’ month order count it doesn’t fit into most UB calls as per the current notion documentation so a decision was made to take a different route and have Hemi push on the 1st of each month a custom invoice information to UB via the following call below:
The expectation in Hemi OS is that there will be one invoice per organisation. As we have agencies working by opening up multiple Hemi Accounts under one organisation we need to be able to group those accounts in one invoice. To ensure we are supporting all options though we must allow for the grouping to be chosen and even to group half of account IDs in one invoice and keep all else separate (we will support only one grouping per org and if something is not in the group it is to be invoiced separately on an account by account basis). These understandings and assumptions are leading for the mappings and calculations below
Last but not least - as there is the presumption “HemiOS” will be created as a new “product” in Threecolts Hub we should be prepared to have an understanding per organisation to which ProductID we are sending the information
Swagger Link
https://stage-api.threecolts.com/v1/swagger/index.html#/default/createOrganizationProductInvoice
Call Details
Endpoint: /billing/organizations/{{organizationID}}/products/{{productID}}/invoice
Operation: POST
<v1.1>
Required Header: X-Idempotency-Key
</v1.1>
Parameters:
Parameter | Hemi Mapping |
---|---|
organizationID | Hemi.ai > Org ID (From DB hemi.hemi.ai the ID of the Organisation) |
productID | Product ID sitting together with the Application in hemi.hemi.ai |
Example Payload:
{
"accounts": [
0
],
"currency": "string",
"discount": {
"amount_off": 0,
"percent_off": 100
},
"due_date": 0,
"invoice_month": "string",
"lines": [
{
"amount": 0,
"commissions": [
{
"commission_percentage": 10000,
"user_id": 0
}
],
"description": "string",
"item": "string",
"quantity": 0,
"tax_code": "string",
"unit_amount": 0
}
],
"sales_term": "due_on_receipt",
"send_invoice_at": 0,
"tax_code": "string",
"version": 0
}
Payload Mapping:
Field Name | Hemi Mapping | Hemi Notes | |||
---|---|---|---|---|---|
accounts | Hemi.ai all accounts for the organisation | If there are accounts in an org that are not marked for grouping (see Billing section below for more) they should be processed separately one by one creating an invoice for each one | |||
currency | Billing > Currency | New field in a new Billing section for each Hemi account | |||
discount | N/A | Any kind of discount will be calculated and already applied on Hemi level and provided with the discounted value in the line items of this payload | |||
amount_off | |||||
percent_off | |||||
due date | Billing > Days for payment | New field in the Billing section |
Format is timestamp
. We want to pick the value of the days and add them to the current date when the invoice is being generated. The result date should be use as “by the end of this day” to calculate the exact timestamp. In other words - if we have 15
days set as the value and we issue an invoice on the 1st of November 2024 we expect to have a timestamp showing 1+15 = 16th of November and the time to be till the end of that said day = 1731801599
|
| invoice_month | | | * YYYY-MM-01
| | <v1.2>
The invoice month is supposed to showcase for which month actually is the invoice. In our case we are always invoicing for the previous month so in the case of running the script in January 2025 we are looking to create the invoice for December 2024. So we should always fill this in with the previous month of the current one in the provided format (based on the example above we should send 2024-12-01
</v1.2> |
| lines | | | | | The information for Lines > Hemi Mapping will be split in two columns. Column 1) will show mapping info for those that will be coming from Hemi Accounts with Billing type “Fixed”; Column 2) will show mapping info for those that will be coming from Hemi Accounts with Billing type “Performance”. More on the types bellow in “Billing section” |
| | amount | | calculated
| calculated
| Depending on the Type of the Billing (see more below in “Billing section”) we will have 1 or 2 lines for each Account in the invoice. The amount that needs to be in here is the value from Hemi minus the discount % that needs to be applied times the quantity for that line. For example -for a line coming from “per order” charge- if we have 50p per order, 20% discount and we have 1000 orders we need to provide 40000p in that invoice line
<v1.1>
Please note: all amounts in the db and in payload respectively are to be provided in cents / pennies. If we want to set a minimum to 1000 USD we need to store and pass in the invoice 100000 cents.
</v1.1> |
| | commissions | | | | |
| | | commission_percentage | N/A | | <v1.2>
We are not using this section at the moment
</v1.2> |
| | | user_id | N/A | | <v1.2>
We are not using this section at the moment
</v1.2> |
| | description | | Customer Hemi Instance name - Type of payment
| Customer Hemi Instance name - Type of payment
| <v1.1>
We have only one field to showcase what we are actually charging for and to give a full and rich description of the line in the invoice we want to concatenate two values in here. First will always be the Hemi instance name followed by the Type of payment (Per order
or Monthly
). The two values should be separated by a -
and spaces around it for easy human readability so we expect a final value to look like this: Sportsdirect - Per order
</v1.1> |
| | item | | 19 | 19 | <v1.1>
“19” is an enumeration values in QuickBooks - a payment gateway that UnifiedBilling will use for out invoicing. It means “Transaction fee” and for now all lines we have will be provided with this “type”. The item
in the call acts as a “type” of a sort but we will stick to one value only now to ease on the management in UB and QB itself
</v1.1> |
| | quantity | | 1
OR
count
| 1
OR
count
| If we are providing Fixed line or Monthly Minimum line then quantity 1
. Otherwise just count the number of orders for the given month |
| | tax_code | | Billing Tax Code | Billing Tax Code | TBD if needed |
| | unit_amount | | Billing > Fixed
OR
Billing > Per Order | Billing > Monthly Minimum
OR
Billing > Per Order | Depending on the Type of the Billing (see more below in “Billing section”) we will have 1 or 2 lines for each invoice. The amount that needs to be in here is the value from Hemi minus the discount % that needs to be applied. For example - if we have 50c per order and 20% discount we need to provide 40c in that invoice line
<v1.1>Please note: all amounts in the db and in payload respectively are to be provided in cents / pennies. If we want to set a minimum to 1000 USD we need to store and pass in the invoice 100000 cents.</v1.1> |
| sales_term | | | N/A | | Don’t send |
| send_invoice_at | | | * NOW() + 1h
| | <v1.2>
This field is to actually initiate the sending of the invoice and when this should happen once info gets to UB. At the moment we are to hardcode this as 1h from the time of the sending
</v1.2> |
| tax_code | | | N/A | | Don’t send |
Triggers & Opperation:
- On the 1st of each month we have to run the functionality and based on the below parameters and above mappings create the right invoices for all Hemi OS customers
- Functionality should start 2 hours after midnight
- Functionality should NOT pick orders that are already marked as already exported
- Functionality should pick all orders that are NOT:
- Orders > Order Status = Pending
- Orders > Order Status = Cancelled + Orders > Order Total Amount = 0
- Functionality should always pick orders for the last 35 days (overlap for order processing safeguard) starting from the 00:00:00 mark on the 1st of the current month in which we are running going backwards
- Functionality should always run with the assumption it bills based on UTC server time
- Functionality should mark all successfully exported AND invoiced orders so future invoicing can skip them. Marking should be a date timestamp in the form of MMYYYY (picked from the date of running the functionality) so it can be clear in which month has an order been invoiced for
- Functionality should be making the date time check by Orders > Order Created Time or by
initially_created_date
- whichever developers decide is more safe and secure - There should be safeguards against this functionality failing with the right email notifications if something doesn’t happen (send an email to ddeltchev@threecolts.com with the text “Invoice generation for XX client instance failed”)
Billing section and additional specifications
To achieve the right setup we need to parametrise everything we have as variables in this solution in Hemi so we can combine the right Accounts for the invoice, chose the right type and calculations so we will know what lines to send. The parameters and actions around them explained below:
- Group - parameter showing if we should group marked Accounts in this organisation or not in the same invoice. If we have multiple accounts in the same organisations all those that are marked as Group = Yes should be combined in the same invoice, meaning we should end up with an invoice having all respective lines from the grouped Hemi accounts in one place. Just as a reminder - grouping should happen only on a per organisation level. Safeguards - if one of the line generation fails the whole invoice should fail; if there is different currency among those accounts that are to be combined the invoice should fail.
Applicable values for the field (default is Yes):
- Yes
- No
- Type - type is to distinguish between the two models we have at the moment - the old Hemi model where we have a monthly fixed and then per order cost and the new Hemi OS model where we have only per order cost BUT it has a monthly minimum cap that it needs to reach. For ease we will call the fist one “Fixed” and the second one “Performance” based on their main strengths:
- Fixed - the way the Fixed works is we have a monthly fixed fee which is always payable and everything per order comes on top. To make this cleaner in the Invoicing we will want for every Account that is marked as Fixed to generate 2 lines in the invoice - one for the Fixed cost, one for the Per Order cost. When generating the lines for the invoice for this Account (no matter grouped or separate) we should take the values for the two sections below separately and apply the right calculations to get the right amount (as described in the mapping above)
- Monthly fixed - field to keep the monthly fixed charge
- Per Order - field to keep the monthly per order charge
- Performance - the way the Performance model works is it focuses solely on the Per Order value but forces the customer to go to a specific minimum. For the Performance model we expect to have only one line for this account in the Invoice which is a Per Order line if the monthly minimum is surpassed. In the cases where monthly minimum is not we are to send again two lines where the Monthly minimum line will be the value set in Hemi minus the total amount of the Per Order charge. For example if we have a monthly minimum of 999 and the Per Order charge totals at 400 for example (1600 orders x 0.25 per order) we should send a line for the Per Order charge of 400 with unit cost 0.25 and quantity 1600 and send a second line for the monthly minimum of 999-400=599 with the same unit cost and quantity of 1
- Monthly minimum - field to keep the monthly minimum to be charged
- Per Order - field to keep the monthly per order charge
- Currency - simple field to keep the currency in which we are invoicing. To be enum value at the moment with values GBP and USD
- Discount % - any % added in here is to be applied to the values as we are sending them to the invoice. We need to have a safeguard if this value is less than 0 or more than 100 to fail the calculation (it’d be best if it fails in the storing of the field in the first place as well)
- Days for payment - number of days that is to be used for calculation or direct passing in the invoice as per the mapping in field
due_date
- Tax code - the tax code that needs to be applied as per the mapping
Please note: fields Monthly fixed
and Monthly minimum
are going to be one field in the DB for now. They are left as 2 in the description as they trigger some different calculations and fixed values to be sent as Descriptions