Skip to content

Transactions

The transactions module is a read-only ledger for every money movement in Moria. Each transaction row has a polymorphic reference_type + reference_id that links to the originating product (saving goal, donation, investment, etc.). FE can only list and get-by-id — create/update/delete are intentionally not exposed (transactions are only created by the service-layer from payment handlers).

PropertyValue
Base URL{HOST}/v1
AuthBearer JWT (header Authorization) or cookie access_token
Content-Typeapplication/json
Error envelope{ "message": string | string[], "statusCode": number, "error": string }
ValidationGlobal ValidationPipe · whitelist: true, forbidNonWhitelisted: true
Related modulespayments, payment-gateway, accounts, saving-goals, saving-circles, charitable-cause, commodity-financing
Document versionv1 · 2026-05-20
AudienceInternal FE devs (mobile + web)

Users can only access their own transactions — the service-layer enforces a filter by user_id from the Bearer token. Query param filters refine the list (e.g. show only transactions for a specific saving goal).

MethodPathAuthSummary
GET/v1/transactionsbearerList transactions with filter + pagination
GET/v1/transactions/:idbearerDetail of a single transaction

List transactions with optional filters. Only the logged-in user’s transactions are returned. Standard pagination is supported.

bearer read-transaction event · RESOURCE_FETCHED
ParamTypeDefaultNotes
pagenumber (string)1Page number. Validators IsNumberString + IsNotZero.
limitnumber (string)10Records per page.
product_idstringoptionalFilter by product ID (saving goal id, circle id, etc.).
reference_typeenum ReferenceType (common)optionaldonation, saving_goal, saving_circle, investment, commodity_financing, account_top_up
typeenum TransactionTypeoptionalprice, fee, tax
user_idstringoptionalFilter by user. Overridden server-side for non-admins.
GET /v1/transactions?page=1&limit=10&reference_type=saving_goal&product_id=550e8400-e29b-41d4-a716-446655440000
{
"status": "success",
"statusCode": 200,
"message": "Transactions retrieved successfully",
"data": {
"limit": 10,
"count": 24,
"currentPage": 1,
"totalPages": 3,
"transactions": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"amount": "50000.0000",
"status": "successful",
"date": "2026-05-20T08:30:00.000Z",
"source_account_id": "9e8a1d2c-4b5f-4c6d-8e7a-1b2c3d4e5f60",
"destination_account_id": null,
"type": "price",
"reference_type": "saving_goal",
"reference_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"batch_id": "550e8400-e29b-41d4-a716-446655440001",
"purpose": "topup_product",
"payment_order_id": "fcd8dc3b-9f1b-46e8-91ca-402147556022",
"created_by": "550e8400-e29b-41d4-a716-446655440000",
"updated_by": "550e8400-e29b-41d4-a716-446655440000",
"deleted_by": null,
"created_at": "2026-05-20T08:30:00.000Z",
"updated_at": "2026-05-20T08:30:00.000Z"
}
]
}
}
StatusWhen
400 Bad RequestInvalid filter (unknown enum, page/limit non-numeric or zero)
401 UnauthorizedBearer/cookie invalid
403 ForbiddenMissing read-transaction

GET /v1/transactions/:id bearer

Section titled “GET /v1/transactions/:id ”

Detail of a single transaction. Users can only fetch their own transactions (enforced at the service-layer).

bearer read-transaction
ParamTypeNotes
idUUIDTransaction ID
{
"status": "success",
"statusCode": 200,
"message": "Transaction retrieved successfully",
"data": {
"transaction": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"amount": "50000.0000",
"status": "successful",
"date": "2026-05-20T08:30:00.000Z",
"source_account_id": "9e8a1d2c-4b5f-4c6d-8e7a-1b2c3d4e5f60",
"destination_account_id": null,
"type": "price",
"reference_type": "saving_goal",
"reference_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"batch_id": "550e8400-e29b-41d4-a716-446655440001",
"purpose": "topup_product",
"payment_order_id": "fcd8dc3b-9f1b-46e8-91ca-402147556022",
"created_by": "550e8400-e29b-41d4-a716-446655440000",
"updated_by": "550e8400-e29b-41d4-a716-446655440000",
"deleted_by": null,
"created_at": "2026-05-20T08:30:00.000Z",
"updated_at": "2026-05-20T08:30:00.000Z"
}
}
}
StatusWhen
401 UnauthorizedBearer/cookie invalid
403 ForbiddenUser attempting to access another’s transaction
404 Not FoundTransaction not found

  • price — main transaction amount
  • fee — cost / admin fee
  • tax — tax
  • pending
  • successful
  • failed
  • reversed
  • topup_pocket
  • topup_product
  • external_withdrawal
  • internal_withdrawal
  • product_transfer
  • pocket_transfer
  • donation
  • saving_goal
  • saving_circle
  • investment
  • commodity_financing
  • account_top_up
{
"message": "Transaction not found",
"statusCode": 404,
"error": "Not Found"
}
  • 400 invalid filter
  • 401 Bearer invalid
  • 403 accessing another user’s transaction
  • 404 transaction not found
  • 500 internal — generic toast
  • No POST / PATCH / DELETE endpoints — transactions are only created from payment handlers (the payments module) or the Amdigipay callback.
  • For gateway top-up transactions, payment_order_id is set after the completed callback arrives.
  • The destination_account_id field is only set for inter-account transfers.