API Reference
Transactions
Record income, expenses, and transfers against the user's accounts. The API includes duplicate detection and an offline-sync endpoint for batch upload.
/api/transactions
List transactions
Returns the authenticated user's transactions, ordered by transaction_date descending, paginated 50 per page. Each row is eager-loaded with its account, toAccount, and category.
Response
{
"current_page": 1,
"data": [
{
"id": 42,
"user_id": 1,
"account_id": 1,
"to_account_id": null,
"category_id": 2,
"type": "expense",
"amount": "25.50",
"description": "Lunch with team",
"reference": null,
"transaction_date": "2026-06-03",
"is_synced": true,
"created_at": "2026-06-03T12:00:00Z",
"updated_at": "2026-06-03T12:00:00Z",
"account": { "id": 1, "name": "GTBank Checking", "type": "bank" },
"to_account": null,
"category": { "id": 2, "name": "Groceries", "type": "expense" }
}
],
"per_page": 50,
"total": 1,
"last_page": 1
}
{ "message": "Unauthenticated." }
/api/transactions
Create a transaction
Records a new income, expense, or transfer. The user must have at least one account before creating a transaction.
Request body
| Name | Type | Required | Description |
|---|---|---|---|
account_id |
integer | Required | ID of the account the transaction is recorded against. |
to_account_id |
integer | Optional | Destination account for transfer transactions. |
type |
string | Required | One of: income, expense, transfer. |
category_id |
integer | Optional | Category ID. Required for income/expense, optional for transfer. |
amount |
number | Required | Transaction amount. Always positive. |
description |
string | Optional | Short description. Max 255 characters. |
reference |
string | Optional | External reference (e.g. bank transaction ID). Max 255 characters. |
transaction_date |
date | Required | Date the transaction occurred. YYYY-MM-DD. |
force |
boolean | Optional | Set to true to skip the duplicate-detection check. |
Request body example
{
"account_id": 1,
"category_id": 2,
"type": "expense",
"amount": 25.50,
"description": "Lunch with team",
"transaction_date": "2026-06-03"
}
Responses
{
"id": 42,
"user_id": 1,
"account_id": 1,
"to_account_id": null,
"category_id": 2,
"type": "expense",
"amount": "25.50",
"description": "Lunch with team",
"reference": null,
"transaction_date": "2026-06-03",
"is_synced": true,
"created_at": "2026-06-03T12:00:00Z",
"updated_at": "2026-06-03T12:00:00Z"
}
{ "message": "You must create at least one account before adding transactions." }
{
"message": "Potential duplicate detected.",
"is_duplicate": true
}
{
"message": "The given data was invalid.",
"errors": {
"type": ["The selected type is invalid."]
}
}
/api/transactions/sync
requires verified email
Bulk sync (offline)
Accepts a batch of transactions recorded offline and dispatches them to a background queue job (App\Jobs\ProcessSync) for processing. Requires a verified email — the batch-write surface is gated by the verified middleware so we have a way to reach the user if the import misbehaves.
Request body
| Name | Type | Required | Description |
|---|---|---|---|
transactions |
array | Required | Array of transaction objects. Each must include account_id, type, amount, and transaction_date. |
Request body example
{
"transactions": [
{
"account_id": 1,
"type": "expense",
"amount": 12.00,
"description": "Coffee",
"transaction_date": "2026-06-02"
},
{
"account_id": 1,
"type": "expense",
"amount": 4.50,
"description": "Bus fare",
"transaction_date": "2026-06-02"
}
]
}
Responses
{ "message": "Sync process started in the background." }
{
"message": "Your email address is not verified.",
"requires_verified_email": true
}
/api/transactions/{id}
Retrieve a transaction
Returns a single transaction with its account, toAccount, and category relations loaded.
/api/transactions/{id}
Update a transaction
Updates one or more fields of an existing transaction. All fields are optional — only the fields you send are updated.
Request body
| Name | Type | Required | Description |
|---|---|---|---|
account_id | integer | Optional | New source account. |
to_account_id | integer | Optional | New destination account for transfers. |
category_id | integer | Optional | New category. |
type | string | Optional | One of: income, expense, transfer. |
amount | number | Optional | New amount. |
description | string | Optional | New description. Max 255 characters. |
reference | string | Optional | New reference. Max 255 characters. |
transaction_date | date | Optional | New date. YYYY-MM-DD. |
/api/transactions/{id}
Delete a transaction
Permanently removes a transaction and recalculates the affected account balances.
Response
HTTP/1.1 204 No Content