Finance & Payout Management
This guide covers how to track and reconcile the capital, interest, fees and commissions that Amili collects on your behalf. When debtors make payments, Amili settles the funds and creates financial records that you can query through the API.
Finance data is organized at two levels:
- Payout Specifications (
finance--payout-specifications) — Transaction-level records tied to individual cases. Created immediately when payments are settled. - Payouts (
finance--payouts) — Aggregated summaries grouped by category and period. Created when specifications are scheduled for bank transfer to the creditor.
All API requests require a valid authentication token in the X-API-Key header. For details about the authentication process and token management, see the Authentication documentation.
In this guide, we will use the AuthTokenProvider class (documented in the authentication guide) to handle token management.
Table of Contents
- Track Capital & Fee Payouts — Invoice-level reconciliation of collected debt
- Track Revenue — Interest and commission summaries
- Incremental Fetching — Recommended pattern for scheduled data exports
Track Capital & Fee Payouts
The most common use case is tracking how much capital and fees have been collected per case. Use the finance--payout-specifications endpoint to get transaction-level records that can be matched to individual invoices.
Finance Categories
Each specification has a finance_category that determines what type of money it represents:
| Category | Description |
|---|---|
capital | The principal debt amount collected from the debtor |
creditor_outlay | Fees the creditor charged before sending the case to Amili (reminder fees, invoice fees, etc.) |
interest | Interest charged on overdue payments |
creditor_commission | Commission earned from the collection process |
For case-level reconciliation, capital and creditor_outlay are the most relevant categories.
const token = await auth.getValidToken()
const where = encodeURIComponent(
JSON.stringify({
creditor: '686e6ed854377058c2dd10bd',
finance_category: { $in: ['capital', 'creditor_outlay'] },
})
)
const projection = encodeURIComponent(
JSON.stringify({
_id: 1,
amount: 1,
total_amount: 1,
article: 1,
finance_category: 1,
invoice_number: 1,
reference_number: 1,
booking_date: 1,
'references.case': 1,
})
)
const response = await axios.get(
`https://api-sandbox.amili.se/finance--payout-specifications?where=${where}&projection=${projection}&sort=-_created&max_results=100`,
{
headers: {
'X-API-Key': token,
},
}
)import json
token = auth.get_valid_token()
where = json.dumps({
"creditor": "686e6ed854377058c2dd10bd",
"finance_category": {"$in": ["capital", "creditor_outlay"]},
})
projection = json.dumps({
"_id": 1,
"amount": 1,
"total_amount": 1,
"article": 1,
"finance_category": 1,
"invoice_number": 1,
"reference_number": 1,
"booking_date": 1,
"references.case": 1,
})
response = requests.get(
'https://api-sandbox.amili.se/finance--payout-specifications',
params={
'where': where,
'projection': projection,
'sort': '-_created',
'max_results': 100,
},
headers={'X-API-Key': token}
)
response.raise_for_status()
specifications = response.json()['_items']Example response:
{
"_items": [
{
"_id": "507f1f77bcf86cd799439011",
"amount": 2050.0,
"total_amount": 2050.0,
"article": "capital",
"finance_category": "capital",
"invoice_number": "INV-2025-020",
"reference_number": "25020",
"booking_date": "Wed, 11 Jun 2025 00:00:00 GMT",
"references": { "case": "507f1f77bcf86cd799439050" }
},
{
"_id": "507f1f77bcf86cd799439012",
"amount": 60.0,
"total_amount": 60.0,
"article": "reminder",
"finance_category": "creditor_outlay",
"invoice_number": "INV-2025-020",
"reference_number": "25020",
"booking_date": "Wed, 11 Jun 2025 00:00:00 GMT",
"references": { "case": "507f1f77bcf86cd799439050" }
}
],
"_meta": {
"page": 1,
"max_results": 100,
"total": 2
}
}Key Fields
| Field | Description |
|---|---|
invoice_number | Original invoice number from case registration |
reference_number | Case reference number |
references.case | Case ID — use this to correlate with case data |
booking_date | When the customer's payment was settled |
finance_category | capital for principal amounts, creditor_outlay for fees |
article | Specific type: capital, reminder, invoice_fee, late_payment_fee, etc. |
amount | Amount excluding VAT |
total_amount | Amount including VAT |
Grouping by Customer Payment
Use banking_transaction._id to identify all specification items that originated from the same customer payment. This is useful when reconciling payments — a single banking transaction can span multiple cases if the customer paid several invoices at once (e.g., bundled Kronofogden payments).
About payout lifecycle fields
Some fields are populated later in the payout lifecycle and are not available immediately after settlement:
payout— Set when the specification is linked to a payout during schedulingpayout_reference— The reference Amili uses on the bank transfer to the creditorpayout_date— Set when the payout is exported to the bank
For case tracking and reconciliation purposes, you don't need to wait for these fields.
Track Revenue
For revenue reporting, use the finance--payouts endpoint to get aggregated summaries of interest and commissions earned from the collection process. These payouts are grouped by finance_category and period.
const token = await auth.getValidToken()
const where = encodeURIComponent(
JSON.stringify({
creditor: '686e6ed854377058c2dd10bd',
finance_category: { $in: ['interest', 'creditor_commission'] },
})
)
const response = await axios.get(
`https://api-sandbox.amili.se/finance--payouts?where=${where}&sort=-payout_date&max_results=10`,
{
headers: {
'X-API-Key': token,
},
}
)import json
token = auth.get_valid_token()
where = json.dumps({
"creditor": "686e6ed854377058c2dd10bd",
"finance_category": {"$in": ["interest", "creditor_commission"]},
})
response = requests.get(
'https://api-sandbox.amili.se/finance--payouts',
params={
'where': where,
'sort': '-payout_date',
'max_results': 10,
},
headers={'X-API-Key': token}
)
response.raise_for_status()
payouts = response.json()['_items']Example response:
{
"_items": [
{
"_id": "507f1f77bcf86cd799439098",
"creditor": "686e6ed854377058c2dd10bd",
"currency": "SEK",
"payout_reference": "65432",
"payout_date": "Fri, 13 Jun 2025 00:00:00 GMT",
"amount": 3000.0,
"vat_amount": 0.0,
"total_amount": 3000.0,
"summary": {
"interest": {
"count": 8,
"amount": 3000.0,
"vat_amount": 0.0,
"total_amount": 3000.0
}
},
"finance_category": "interest",
"finance_interval": "daily"
},
{
"_id": "507f1f77bcf86cd799439099",
"creditor": "686e6ed854377058c2dd10bd",
"currency": "SEK",
"payout_reference": "65432",
"payout_date": "Fri, 13 Jun 2025 00:00:00 GMT",
"amount": 450.0,
"vat_amount": 112.5,
"total_amount": 562.5,
"summary": {
"reminder": {
"count": 5,
"amount": 450.0,
"vat_amount": 112.5,
"total_amount": 562.5
}
},
"finance_category": "creditor_commission",
"finance_interval": "daily"
}
]
}The summary field breaks down the aggregated payout by article type. Each payout represents a single finance_category for a given period and creditor.
Incremental Fetching
When building a scheduled job to periodically export finance data (e.g., a daily cron), we recommend filtering by _created to only fetch new records since your last successful run.
// Store the last successful fetch timestamp
let lastFetchTimestamp = loadLastTimestamp() // e.g., "Wed, 11 Jun 2025 00:00:00 GMT"
const where = encodeURIComponent(
JSON.stringify({
creditor: '686e6ed854377058c2dd10bd',
finance_category: { $in: ['capital', 'creditor_outlay'] },
_created: { $gte: lastFetchTimestamp },
})
)
const response = await axios.get(
`https://api-sandbox.amili.se/finance--payout-specifications?where=${where}&sort=_created&max_results=100`,
{ headers: { 'X-API-Key': token } }
)
// Process and deduplicate by _id (in case of job reruns)
const newRecords = deduplicateById(response.data._items)
// Update timestamp only after successful processing
saveLastTimestamp(new Date().toUTCString())# Store the last successful fetch timestamp
last_fetch_timestamp = load_last_timestamp() # e.g., "Wed, 11 Jun 2025 00:00:00 GMT"
query = json.dumps({
"creditor": "686e6ed854377058c2dd10bd",
"finance_category": {"$in": ["capital", "creditor_outlay"]},
"_created": {"$gte": last_fetch_timestamp},
})
response = requests.get(
'https://api-sandbox.amili.se/finance--payout-specifications',
params={'where': query, 'sort': '_created', 'max_results': 100},
headers={'X-API-Key': token}
)
response.raise_for_status()
# Process and deduplicate by _id (in case of job reruns)
new_records = deduplicate_by_id(response.json()['_items'])
# Update timestamp only after successful processing
save_last_timestamp(datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT"))Why _created?
| Field | Recommended | Reason |
|---|---|---|
_created | ✅ Yes | Immutable — set once when the record is created, never changes |
booking_date | ⚠️ Possible | Represents the business date, not creation time |
payout_date | ❌ No | Remains null until bank export — records would be missed during scheduling |
_updated | ❌ No | Changes on any update — could cause records to be fetched multiple times |
Idempotency
Always deduplicate fetched records by _id to handle scenarios where the job runs multiple times in the same period, fails mid-process, or encounters network issues.
Next Steps
- Case Flow Examples — How fees are registered at case creation (
fees_included_in_capital_to_claim,fees_already_claimed) - Case Status Tracking — Track closed cases and identify which ones resulted in payouts
- Creditor Case Actions — Register payments, credits, and cancellations that affect financial records
- Finance Payout Endpoint — Complete API reference
- Finance Payout Specification Endpoint — Complete API reference
