Read Your Expenses
List the expenses recorded for your business, filter them by status or date, and fetch a single expense by its id.
Expenses are recorded in Duplo Dashboard by the people who submit and approve them. The API provides a way for your systems to read those same records back, so you can reconcile them against your own ledger or pull them into a report. It is read-only, and nothing here creates or changes an expense.
This guide assumes you already have an API key and can authenticate. If not, start with Getting Started.
Listing expenses
The Fetch expenses endpoint returns one page of your business's expenses.
curl --request GET \
--url 'https://dashboard.tryduplo.com/api/expenses?page=1&limit=20&status=approved' \
--header 'Authorization: Bearer <your-api-key>'Every filter is optional. Send none of them and you get the first page of everything.
| Parameter | Accepts | Notes |
|---|---|---|
page | A number, for example 1 | Which page to return |
limit | A number, for example 20 | How many expenses per page |
startDate | An ISO 8601 timestamp | Only expenses dated on or after this |
endDate | An ISO 8601 timestamp | Only expenses dated on or before this |
status | pending, approved, rejected, saved, N/A | Only expenses in that state |
As with every response on this API, the payload arrives under data in the standard envelope. The sample below shows only that payload, which carries the page of expenses in its own data array and the pagination counters in meta:
{
"data": [
{
"id": "98d34e0c-69dc-4683-9bbe-6e6921ed155c",
"businessId": "0f6b2a52-3f0b-4d1e-9a6f-1f9b6c3d5e88",
"amount": 125000,
"currency": "NGN",
"description": "Team offsite venue",
"status": "approved",
"date": "2026-01-14T00:00:00.000Z",
"claimReimbursement": false,
"receipt": ["https://files.tryduplo.com/receipts/98d34e0c.pdf"],
"payoutId": "3b1c9d77-2a44-4f2e-8c31-77bb1f0a9d21",
"expenseCategory": { "name": "Travel" },
"department": { "name": "Engineering" },
"recipient": { "accountName": "Lagos Venues Limited" },
"createdAt": "2026-01-15T09:22:11.004Z"
}
],
"meta": {
"total": 143,
"page": 1,
"limit": 20,
"count": 20,
"previousPage": null,
"nextPage": 2,
"pageCount": 8,
"totalRecords": 143
}
}To walk the whole set, keep requesting the page in meta.nextPage until there is no next page.
An expense that has already been paid out carries that payout's id in payoutId. Pass it to Get a payout to see how the money actually left, including the destination account. See Read your payouts.
Fetching one expense
When you already have an id, Get an expense by id returns that single record in the same shape as one entry in the list.
curl --request GET \
--url https://dashboard.tryduplo.com/api/expenses/98d34e0c-69dc-4683-9bbe-6e6921ed155c \
--header 'Authorization: Bearer <your-api-key>'Ids are scoped to your business. An id belonging to another business returns 404 with Expense not found for this business, the same as an id that does not exist at all.
Related guides
How is this guide?
Last updated on