Elilta ERP API
A multi-tenant ERP API — one tenant per business, one business type per tenant (Product, Service, or Manufacturing). This guide covers everything shared across all three, and is your starting point for integrating any client against the API.
3
Business Types
300+
Product Endpoints
150+
Common/Shared Endpoints
2
Role Tiers (Owner / Employee)
Base URLs
http://localhost:8000/api/v1
https://product.elilta.cloud/api/v1
/product, /service, /manufacturing, /crm, /banking, /hr, /auth — there are no bare, ungrouped resource paths. The onboarding endpoints under /tenant/* are the one deliberate exception (they run before a tenant/session exists).
Multi-Tenant Setup — the X-Tenant header
Every business ("tenant") has its own isolated database. Once a user is authenticated, every subsequent request must identify which tenant it belongs to by sending an X-Tenant header set to the tenant's id (e.g. choami_product) — the same value returned as tenant on the logged-in user object. Omitting it on a protected endpoint will fail to resolve tenancy and the request will be rejected.
GET /api/v1/product/items HTTP/1.1 Host: localhost:8000 Authorization: Bearer 92|zOdLosVaYPdaz8DQUOs4XXoavWvK1gV8bsikXbWX50c0bd41 X-Tenant: choami_product Accept: application/json
API Standards
RESTful JSON
All requests/responses use application/json. Standard verbs: GET (read), POST (create), PUT/PATCH (update), DELETE (soft-delete).
Sanctum Bearer Tokens
Stateless personal-access tokens (Laravel Sanctum). No expiry/refresh cycle — a token is valid until POST /auth/logout revokes it.
Consistent Envelope
Every response includes success and message; list endpoints add pagination in meta.
Standard Response Envelope
{
"success": true,
"message": "Items retrieved successfully",
"data": { /* resource / list */ },
"meta": {
"current_page": 1,
"per_page": 15,
"total": 248,
"last_page": 17
}
}
{
"success": false,
"message": "Validation failed",
"errors": {
"phone": ["This field is required."]
}
}
Registration & OTP Verification
Elilta is passwordless — no password is ever collected. Every phone number is verified with an OTP before an account is created or a session is issued. These are the first endpoints any client integration touches.
New Company Sign-up Flow
Check availability
check-registration
User enters OTP
sent via SMS (mock: 1234)
Register
creates tenant + owner
Token issued
tenant DB seeded
/tenant/check-registration
Public
Optional pre-submit check — reports whether the phone or company name is already taken, so the sign-up form can flag the specific conflicting field without losing the user's input.
Request Body
{
"phone": "0911909090",
"company_name": "choami_product"
}
Response 200
{
"phone_exists": false,
"company_exists": false
}
/tenant/register
Public · rate-limited
Creates a new tenant (company), provisions its isolated database, seeds it based on service_type, creates the first user with the Owner role, and returns a session token — all gated by a verified OTP, no password involved.
Request Body
{
"name": "Abebe Kebede",
"company_name": "choami_product",
"phone": "0911909090",
"service_type": "products",
"otp": "1234"
}
Response 200
{
"user": {
"id": 1,
"name": "Abebe Kebede",
"phone": "0911909090",
"tenant": "choami_product",
"company_code": "78268",
"service_type": "products",
"role": { "name": "owner", "displayName": "Super Admin" },
"permissions": [ "item-create", /* ...all permissions for this business type */ ]
},
"token": "92|zOdLosVaYPdaz8DQUOs4XXoavWvK1gV8bsikXbWX50c0bd41",
"service_type": "products"
}
Fields
| Field | Type | Notes |
|---|---|---|
| service_type | string | One of products, service, manufacturing — permanently fixes which module set the tenant gets. |
| company_name | string | Must be a single unbroken token (no spaces) — becomes the tenant id. |
| otp | string | Mock OTP is 1234 in this environment; real SMS delivery is not yet wired. |
company_code is generated at registration — unrelated to the tenant id/database name. This is what employees use, alongside their phone, to log in (see below), since their phone is never searched for across tenants.
Login
Existing users (owners and employees) authenticate with phone + OTP. An employee's phone lives only inside their own tenant's database and is never scanned for across tenants — the company code is what identifies which one to check.
/tenant/login-otp
Public · rate-limited
Verifies the OTP and issues a Sanctum token. company_code is optional for the company owner (resolved directly via a central phone↔tenant match) but required for employees — without it, only the owner shortcut is checked; no tenant database is scanned.
Request Body
{
"phone": "0911909090",
"otp": "1234",
"company_code": "78268" // optional for owner
}
Response 200
{
"user": { /* same shape as register */ },
"token": "93|7wEnZ5Pk9IFXoZ5zE52fmGhs6HNFn4Da2HCpC7Qefa771a50",
"tenant_id": "choami_product"
}
Error Responses
otp field did not match.
/tenant/check-phone
Public
Optional — checks whether a phone belongs to a company owner (central, O(1) lookup only; never scans tenant databases). Body: { phone, company_code? } → { exists: boolean }.
Authenticated Requests
Every request after login must carry both headers below. Missing either one will fail to authenticate/resolve tenancy.
curl -X GET "http://localhost:8000/api/v1/auth/user" \ -H "Authorization: Bearer {token}" \ -H "X-Tenant: {tenant_id}" \ -H "Accept: application/json"
/auth/logout
Bearer Token Required
Revokes the current Sanctum token server-side. No request body.
Product Integration Flow
The Product module is the primary implementation target right now. Once you've completed Registration/Login above, this is the recommended order to build a Product-type integration — each step links straight to its full reference on the Product page.
Fetch session context
GET /auth/user for the logged-in user's role/permissions, GET /auth/roles + GET /auth/permissions if building role management UI.
Set up the catalog foundation
Warehouses (/product/warehouses) → Item Units (/product/item-units) → Item Categories (/product/item-categories). A default warehouse and base units already exist from seeding.
Create Items
POST /product/items with pricing, then opening stock via POST /product/items/{item}/stocks.
Add Parties (customers/suppliers)
POST /crm/parties — Common/shared, not under /product, since Service & Manufacturing also use it.
Transact: Sales & Purchases
POST /product/sales and POST /product/purchases — both support orders, proformas/GRNs, confirmations and returns.
Record payments & reconcile
/product/payment-ins, /product/payment-outs, plus /banking/* for bank/cash/cheque handling.
Report & monitor
GET /analytics/dashboard for the summary widgets, /product/reports/* for the full 36-endpoint reporting suite.
Common / Shared Endpoints
These endpoints are identical no matter the tenant's business type — used by Product today, and by Service/Manufacturing once those go live.
Auth, Roles & Users — prefix /auth
/auth/roles
permission: role-read
List roles. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Roles retrieved successfully",
"data": {
"roles": [
{
"id": 5,
"name": "cashier",
"display_name": "Cashier",
"users_count": 4,
"permissions": [
{
"id": 10,
"display_name": "Create Party",
"name": "party-create"
}
]
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/auth/roles
permission: role-create
Create a new role.
Request Body
{
"display_name": "Cashier",
"permissions": [
10,
11,
22,
23
]
}
Response 201
{
"success": true,
"message": "Role created successfully",
"data": {
"id": 5,
"name": "cashier",
"display_name": "Cashier",
"users_count": 4,
"permissions": [
{
"id": 10,
"display_name": "Create Party",
"name": "party-create"
}
]
}
}
/auth/roles/{role}
permission: role-read
Get a single role by id.
Response 200
{
"success": true,
"message": "Role retrieved successfully",
"data": {
"id": 5,
"name": "cashier",
"display_name": "Cashier",
"users_count": 4,
"permissions": [
{
"id": 10,
"display_name": "Create Party",
"name": "party-create"
}
]
}
}
/auth/roles/{role}
permission: role-update
Update an existing role.
Request Body
{
"display_name": "Cashier",
"permissions": [
10,
11,
22,
23
]
}
Response 200
{
"success": true,
"message": "Role updated successfully",
"data": {
"id": 5,
"name": "cashier",
"display_name": "Cashier",
"users_count": 4,
"permissions": [
{
"id": 10,
"display_name": "Create Party",
"name": "party-create"
}
]
}
}
/auth/roles/{role}
permission: role-delete
Soft-delete a role (recoverable via restore).
Response 200
{
"success": true,
"message": "Role deleted successfully",
"data": null
}
/auth/permissions
permission: role-read
List every permission available to this tenant's business type — used to populate role-creation checkboxes.
Response 200
{
"success": true,
"message": "Permissions retrieved successfully",
"data": {
"permissions": [
{
"id": 10,
"display_name": "Create Party",
"name": "party-create"
}
]
}
}
/auth/invite
permission: user-create
Invite a new employee by phone — creates their user account and assigns a role. No password; they sign in via OTP + company code.
Request Body
{
"name": "Selamawit Tesfaye",
"phone": "0911909090",
"role": 3
}
Response 200
{
"success": true,
"message": "User invited successfully",
"data": {
"user": {
"id": 12,
"name": "Selamawit Tesfaye",
"phone": "0911909090"
},
"token": "3|abcdef...",
"tenant_id": "blue-nile-trading",
"password_generated": false
}
}
/auth/users/{user}
permission: user-update
Update another user's name/phone/role (owner/admin action, not self-service profile editing).
Request Body
{
"name": "Selamawit Tesfaye",
"phone": "0911909090",
"role": 3
}
Response 200
{
"success": true,
"message": "User updated successfully",
"data": {
"id": 12,
"name": "Selamawit Tesfaye"
}
}
/auth/tenant-users
permission: user-read
List every user account in this tenant, with their assigned role.
Response 200
{
"success": true,
"message": "Tenant users retrieved successfully",
"data": {
"users": [
{
"id": 12,
"name": "Selamawit Tesfaye",
"phone": "0911909090",
"role": {
"id": 1,
"name": "owner"
}
}
]
}
}
User Profile
/auth/profile
permission: profile-read
Get the caller's own profile.
Response 200
{
"success": true,
"message": "Profile retrieved successfully",
"data": {
"id": 12,
"name": "Selamawit Tesfaye",
"phone": "0911909090",
"email": "0911909090@elilta.cloud"
}
}
/auth/profile
permission: profile-update
Update the caller's own profile (name/phone; no password field exists).
Request Body
{
"name": "Selamawit Tesfaye",
"phone": "0911909090"
}
Response 200
{
"success": true,
"message": "Profile updated successfully",
"data": {
"id": 12,
"name": "Selamawit Tesfaye"
}
}
/auth/user
permission: Bearer Token Required
Full session object — user + role + permissions + tenant + company_code. Called on every app load to hydrate the client session.
Response 200
{
"id": 12,
"name": "Selamawit Tesfaye",
"email": "0911909090@elilta.cloud",
"phone": "0911909090",
"otp_verified": true,
"tenant": "blue-nile-trading",
"company_code": "78268",
"service_type": "products",
"tenant_service_type": "products",
"income_expense_balance": 15230.5,
"role": {
"id": 1,
"name": "owner",
"displayName": "Owner"
},
"permissions": [
"party-read",
"item-create",
// ...full permission list for this business type
]
}
HR & Payroll — prefix /hr
/hr/employees
permission: employee-read
List employees. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Employees retrieved successfully",
"data": {
"employees": [
{
"id": 7,
"user_id": 12,
"user": {
"id": 12,
"name": "Selamawit Tesfaye",
"email": "0911909090@elilta.cloud",
"phone": "0911909090",
"role": {
"id": 3,
"name": "cashier",
"displayName": "Cashier"
}
},
"tin_no": "0012345678",
"basic_salary": 8500,
"formatted_basic_salary": "8,500.00",
"job_title": "Cashier",
"position_allowance": 500,
"transport_allowance": 600,
"employment_status": "active",
"hourly_rate": 47.22,
"created_at": "Jul 18, 2026"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/hr/employees
permission: employee-create
Create a new employee.
Request Body
{
"name": "Selamawit Tesfaye",
"phone": "0911909090",
"role_id": 3,
"tin_no": "0012345678",
"basic_salary": 8500,
"job_title": "Cashier",
"position_allowance": 500,
"transport_allowance": 600,
"transport_taxable": 0,
"employment_status": "active"
}
Response 201
{
"success": true,
"message": "Employee created successfully",
"data": {
"id": 7,
"user_id": 12,
"user": {
"id": 12,
"name": "Selamawit Tesfaye",
"email": "0911909090@elilta.cloud",
"phone": "0911909090",
"role": {
"id": 3,
"name": "cashier",
"displayName": "Cashier"
}
},
"tin_no": "0012345678",
"basic_salary": 8500,
"formatted_basic_salary": "8,500.00",
"job_title": "Cashier",
"position_allowance": 500,
"transport_allowance": 600,
"employment_status": "active",
"hourly_rate": 47.22,
"created_at": "Jul 18, 2026"
}
}
/hr/employees/{employee}
permission: employee-read
Get a single employee by id.
Response 200
{
"success": true,
"message": "Employee retrieved successfully",
"data": {
"id": 7,
"user_id": 12,
"user": {
"id": 12,
"name": "Selamawit Tesfaye",
"email": "0911909090@elilta.cloud",
"phone": "0911909090",
"role": {
"id": 3,
"name": "cashier",
"displayName": "Cashier"
}
},
"tin_no": "0012345678",
"basic_salary": 8500,
"formatted_basic_salary": "8,500.00",
"job_title": "Cashier",
"position_allowance": 500,
"transport_allowance": 600,
"employment_status": "active",
"hourly_rate": 47.22,
"created_at": "Jul 18, 2026"
}
}
/hr/employees/{employee}
permission: employee-update
Update an existing employee.
Request Body
{
"name": "Selamawit Tesfaye",
"phone": "0911909090",
"role_id": 3,
"tin_no": "0012345678",
"basic_salary": 8500,
"job_title": "Cashier",
"position_allowance": 500,
"transport_allowance": 600,
"transport_taxable": 0,
"employment_status": "active"
}
Response 200
{
"success": true,
"message": "Employee updated successfully",
"data": {
"id": 7,
"user_id": 12,
"user": {
"id": 12,
"name": "Selamawit Tesfaye",
"email": "0911909090@elilta.cloud",
"phone": "0911909090",
"role": {
"id": 3,
"name": "cashier",
"displayName": "Cashier"
}
},
"tin_no": "0012345678",
"basic_salary": 8500,
"formatted_basic_salary": "8,500.00",
"job_title": "Cashier",
"position_allowance": 500,
"transport_allowance": 600,
"employment_status": "active",
"hourly_rate": 47.22,
"created_at": "Jul 18, 2026"
}
}
/hr/employees/{employee}
permission: employee-delete
Soft-delete a employee (recoverable via restore).
Response 200
{
"success": true,
"message": "Employee deleted successfully",
"data": null
}
/hr/employees/active/count
permission: employee-read
Count of currently-active employees.
Response 200
{
"success": true,
"message": "Count retrieved successfully",
"data": {
"count": 15
}
}
/hr/employees/{employee}/send-invite
permission: employee-update
Send (or resend) the login-instructions SMS to this employee — phone, company code, and OTP instructions.
Response 200
{
"success": true,
"message": "Invitation sent successfully",
"data": null
}
/hr/employees/{employee}/salary-histories
permission: employee-read
This employee's payroll history across all salary months.
Response 200
{
"success": true,
"message": "Histories retrieved successfully",
"data": {
"histories": [
{
"id": 22,
"salary_month_id": 4,
"employee_id": 7,
"is_editable": true,
"employee": {
"id": 7,
"job_title": "Cashier",
"user": {
"id": 12,
"name": "Selamawit Tesfaye"
}
},
"basic_salary": 8500,
"position_allowance": 500,
"transport_allowance": 600,
"days_of_month": 30,
"gross_salary": 9600,
"income_tax": 1145,
"total_deduction": 1740,
"net_pay": 7860,
"formatted": {
"net_pay": "7,860.00",
"gross_salary": "9,600.00"
},
"created_at": "Jul 18, 2026"
}
]
}
}
/hr/salary-months
permission: salary_month-read
List salary months. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Salary Months retrieved successfully",
"data": {
"salary_months": [
{
"id": 4,
"title": "July 2026 Payroll",
"month": 7,
"month_name": "July",
"year": 2026,
"status": "open",
"is_editable": true,
"total_net_pay": "182,340.00",
"bank_account": {
"id": 2,
"name": "Commercial Bank of Ethiopia"
},
"created_by_user": {
"id": 1,
"name": "Selamawit Tesfaye"
},
"salary_histories_count": 12,
"created_at": "Jul 18, 2026"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/hr/salary-months
permission: salary_month-create
Create a new salary month.
Request Body
{
"title": "July 2026 Payroll",
"month": 7,
"year": 2026
}
Response 201
{
"success": true,
"message": "Salary Month created successfully",
"data": {
"id": 4,
"title": "July 2026 Payroll",
"month": 7,
"month_name": "July",
"year": 2026,
"status": "open",
"is_editable": true,
"total_net_pay": "182,340.00",
"bank_account": {
"id": 2,
"name": "Commercial Bank of Ethiopia"
},
"created_by_user": {
"id": 1,
"name": "Selamawit Tesfaye"
},
"salary_histories_count": 12,
"created_at": "Jul 18, 2026"
}
}
/hr/salary-months/{salary_month}
permission: salary_month-read
Get a single salary month by id.
Response 200
{
"success": true,
"message": "Salary Month retrieved successfully",
"data": {
"id": 4,
"title": "July 2026 Payroll",
"month": 7,
"month_name": "July",
"year": 2026,
"status": "open",
"is_editable": true,
"total_net_pay": "182,340.00",
"bank_account": {
"id": 2,
"name": "Commercial Bank of Ethiopia"
},
"created_by_user": {
"id": 1,
"name": "Selamawit Tesfaye"
},
"salary_histories_count": 12,
"created_at": "Jul 18, 2026"
}
}
/hr/salary-months/{salary_month}
permission: salary_month-delete
Soft-delete a salary month (recoverable via restore).
Response 200
{
"success": true,
"message": "Salary Month deleted successfully",
"data": null
}
/hr/salary-months/{salaryMonthId}/histories
permission: salary_month-read
All payroll entries within this salary month.
Response 200
{
"success": true,
"message": "Histories retrieved successfully",
"data": {
"histories": [
{
"id": 22,
"salary_month_id": 4,
"employee_id": 7,
"is_editable": true,
"employee": {
"id": 7,
"job_title": "Cashier",
"user": {
"id": 12,
"name": "Selamawit Tesfaye"
}
},
"basic_salary": 8500,
"position_allowance": 500,
"transport_allowance": 600,
"days_of_month": 30,
"gross_salary": 9600,
"income_tax": 1145,
"total_deduction": 1740,
"net_pay": 7860,
"formatted": {
"net_pay": "7,860.00",
"gross_salary": "9,600.00"
},
"created_at": "Jul 18, 2026"
}
]
}
}
/hr/salary-months/{salaryMonth}/pay
permission: salary_month-read
Mark this salary month as paid — disburses net pay to every employee via the linked bank account.
Request Body
{
"bank_account_id": 2
}
Response 200
{
"success": true,
"message": "Salary month paid successfully",
"data": null
}
/hr/salary-months/{salaryMonth}/save-all
permission: salary_month-update
Bulk-save every payroll entry for this salary month in a single call.
Request Body
{
"entries": [
{
"employee_id": 7,
"day_hour": 8,
"overtime": 0
}
]
}
Response 200
{
"success": true,
"message": "Payroll saved successfully",
"data": null
}
/hr/salary-months/{salaryMonth}/summary
permission: salary_month-read
Aggregate payroll totals for this salary month (gross, deductions, net).
Response 200
{
"success": true,
"message": "Summary retrieved successfully",
"data": {
"total_gross": 182340,
"total_deductions": 34120,
"total_net_pay": 148220
}
}
/hr/salary-histories
permission: salary_history-create
Create a new salary history.
Request Body
{
"salary_month_id": 4,
"employee_id": 7,
"days_of_month": 30,
"night_hour": 0,
"day_hour": 8,
"weekend_hour": 0,
"holiday_hour": 0
}
Response 201
{
"success": true,
"message": "Salary History created successfully",
"data": {
"id": 22,
"salary_month_id": 4,
"employee_id": 7,
"is_editable": true,
"employee": {
"id": 7,
"job_title": "Cashier",
"user": {
"id": 12,
"name": "Selamawit Tesfaye"
}
},
"basic_salary": 8500,
"position_allowance": 500,
"transport_allowance": 600,
"days_of_month": 30,
"gross_salary": 9600,
"income_tax": 1145,
"total_deduction": 1740,
"net_pay": 7860,
"formatted": {
"net_pay": "7,860.00",
"gross_salary": "9,600.00"
},
"created_at": "Jul 18, 2026"
}
}
/hr/salary-histories/{salaryHistory}/recalculate
permission: salary_history-create
Create a new salary history.
Request Body
{
"salary_month_id": 4,
"employee_id": 7,
"days_of_month": 30,
"night_hour": 0,
"day_hour": 8,
"weekend_hour": 0,
"holiday_hour": 0
}
Response 201
{
"success": true,
"message": "Salary History created successfully",
"data": {
"id": 22,
"salary_month_id": 4,
"employee_id": 7,
"is_editable": true,
"employee": {
"id": 7,
"job_title": "Cashier",
"user": {
"id": 12,
"name": "Selamawit Tesfaye"
}
},
"basic_salary": 8500,
"position_allowance": 500,
"transport_allowance": 600,
"days_of_month": 30,
"gross_salary": 9600,
"income_tax": 1145,
"total_deduction": 1740,
"net_pay": 7860,
"formatted": {
"net_pay": "7,860.00",
"gross_salary": "9,600.00"
},
"created_at": "Jul 18, 2026"
}
}
/hr/salary-histories/{salary_history}
permission: salary_history-read
Get a single salary history by id.
Response 200
{
"success": true,
"message": "Salary History retrieved successfully",
"data": {
"id": 22,
"salary_month_id": 4,
"employee_id": 7,
"is_editable": true,
"employee": {
"id": 7,
"job_title": "Cashier",
"user": {
"id": 12,
"name": "Selamawit Tesfaye"
}
},
"basic_salary": 8500,
"position_allowance": 500,
"transport_allowance": 600,
"days_of_month": 30,
"gross_salary": 9600,
"income_tax": 1145,
"total_deduction": 1740,
"net_pay": 7860,
"formatted": {
"net_pay": "7,860.00",
"gross_salary": "9,600.00"
},
"created_at": "Jul 18, 2026"
}
}
/hr/salary-histories/{salary_history}
permission: salary_history-update
Update an existing salary history.
Request Body
{
"salary_month_id": 4,
"employee_id": 7,
"days_of_month": 30,
"night_hour": 0,
"day_hour": 8,
"weekend_hour": 0,
"holiday_hour": 0
}
Response 200
{
"success": true,
"message": "Salary History updated successfully",
"data": {
"id": 22,
"salary_month_id": 4,
"employee_id": 7,
"is_editable": true,
"employee": {
"id": 7,
"job_title": "Cashier",
"user": {
"id": 12,
"name": "Selamawit Tesfaye"
}
},
"basic_salary": 8500,
"position_allowance": 500,
"transport_allowance": 600,
"days_of_month": 30,
"gross_salary": 9600,
"income_tax": 1145,
"total_deduction": 1740,
"net_pay": 7860,
"formatted": {
"net_pay": "7,860.00",
"gross_salary": "9,600.00"
},
"created_at": "Jul 18, 2026"
}
}
CRM / Parties — prefix /crm
A "party" is a customer or supplier (or both). Shared across every business type.
/crm/parties
permission: party-read
List partys. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Partys retrieved successfully",
"data": {
"parties": [
{
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"tax_reg_type": "vat_registered",
"currency": "Birr",
"country_default": "Ethiopia",
"balance": 12500.75,
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "Jan 1, 2026",
"is_active": true,
"billing_address": "Bole, Addis Ababa",
"created_at": "Jul 18, 2026"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/crm/parties
permission: party-create
Create a new party.
Request Body
{
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"currency": "Birr",
"country_default": "Ethiopia",
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "2026-01-01",
"settlement_direction": "receive",
"billing_address": "Bole, Addis Ababa",
"is_active": true
}
Response 201
{
"success": true,
"message": "Party created successfully",
"data": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"tax_reg_type": "vat_registered",
"currency": "Birr",
"country_default": "Ethiopia",
"balance": 12500.75,
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "Jan 1, 2026",
"is_active": true,
"billing_address": "Bole, Addis Ababa",
"created_at": "Jul 18, 2026"
}
}
/crm/parties/{party}
permission: party-read
Get a single party by id.
Response 200
{
"success": true,
"message": "Party retrieved successfully",
"data": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"tax_reg_type": "vat_registered",
"currency": "Birr",
"country_default": "Ethiopia",
"balance": 12500.75,
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "Jan 1, 2026",
"is_active": true,
"billing_address": "Bole, Addis Ababa",
"created_at": "Jul 18, 2026"
}
}
/crm/parties/{party}
permission: party-update
Update an existing party.
Request Body
{
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"currency": "Birr",
"country_default": "Ethiopia",
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "2026-01-01",
"settlement_direction": "receive",
"billing_address": "Bole, Addis Ababa",
"is_active": true
}
Response 200
{
"success": true,
"message": "Party updated successfully",
"data": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"tax_reg_type": "vat_registered",
"currency": "Birr",
"country_default": "Ethiopia",
"balance": 12500.75,
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "Jan 1, 2026",
"is_active": true,
"billing_address": "Bole, Addis Ababa",
"created_at": "Jul 18, 2026"
}
}
/crm/parties/{party}
permission: party-delete
Soft-delete a party (recoverable via restore).
Response 200
{
"success": true,
"message": "Party deleted successfully",
"data": null
}
/crm/parties/autocomplete
permission: party-read
Lightweight id+name list for autocomplete/typeahead party pickers.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"parties": [
{
"id": 15,
"display_name": "Blue Nile Trading"
}
]
}
}
/crm/parties/filter
permission: party-read
Advanced filtered party list (type, balance range, active status).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"parties": [
{
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"tax_reg_type": "vat_registered",
"currency": "Birr",
"country_default": "Ethiopia",
"balance": 12500.75,
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "Jan 1, 2026",
"is_active": true,
"billing_address": "Bole, Addis Ababa",
"created_at": "Jul 18, 2026"
}
]
}
}
/crm/parties/search
permission: party-read
Full-text party search by name, phone, or TIN.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"parties": [
{
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"tax_reg_type": "vat_registered",
"currency": "Birr",
"country_default": "Ethiopia",
"balance": 12500.75,
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "Jan 1, 2026",
"is_active": true,
"billing_address": "Bole, Addis Ababa",
"created_at": "Jul 18, 2026"
}
]
}
}
/crm/parties/{party}/history
permission: party-read
Audit-history entries for this party.
Response 200
{
"success": true,
"message": "History retrieved successfully",
"data": {
"history": []
}
}
/crm/parties/{party}/transactions
permission: party-read
Every ledger transaction (sales, purchases, payments) recorded against this party.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"transactions": [
{
"id": 512,
"transaction_no": "TXN-2026-000452",
"transaction_date": "2026-07-18 10:30:00",
"amount": 9025,
"type": "sale",
"direction": "in",
"description": "Payment received for INV-2026-0042",
"reference_number": "RCPT-2026-0033",
"status": "completed",
"party_balance_before": 21525.75,
"party_balance_after": 12500.75,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"display_name": "Blue Nile Trading"
}
}
]
}
}
/crm/parties/{party}/contacts
permission: party_contact-read
List party contacts. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Party Contacts retrieved successfully",
"data": {
"contacts": [
{
"id": 3,
"party_id": 15,
"name": "Abebe Kebede",
"designation": "Purchasing Manager",
"email": "abebe@bluenile.com",
"phone": "0911909090",
"is_primary": true,
"preferred_contact": "phone",
"created_at": "Jul 18, 2026"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/crm/parties/{party}/contacts
permission: party_contact-create
Create a new party contact.
Request Body
{
"name": "Abebe Kebede",
"designation": "Purchasing Manager",
"email": "abebe@bluenile.com",
"phone": "0911909090",
"is_primary": true,
"preferred_contact": "phone"
}
Response 201
{
"success": true,
"message": "Party Contact created successfully",
"data": {
"id": 3,
"party_id": 15,
"name": "Abebe Kebede",
"designation": "Purchasing Manager",
"email": "abebe@bluenile.com",
"phone": "0911909090",
"is_primary": true,
"preferred_contact": "phone",
"created_at": "Jul 18, 2026"
}
}
/crm/contacts/{contact}
permission: party_contact-update
Update an existing party contact.
Request Body
{
"name": "Abebe Kebede",
"designation": "Purchasing Manager",
"email": "abebe@bluenile.com",
"phone": "0911909090",
"is_primary": true,
"preferred_contact": "phone"
}
Response 200
{
"success": true,
"message": "Party Contact updated successfully",
"data": {
"id": 3,
"party_id": 15,
"name": "Abebe Kebede",
"designation": "Purchasing Manager",
"email": "abebe@bluenile.com",
"phone": "0911909090",
"is_primary": true,
"preferred_contact": "phone",
"created_at": "Jul 18, 2026"
}
}
/crm/contacts/{contact}
permission: party_contact-delete
Soft-delete a party contact (recoverable via restore).
Response 200
{
"success": true,
"message": "Party Contact deleted successfully",
"data": null
}
/crm/parties/{party}/credit-settings
permission: party_financial-read
List party credit settingss. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Party Credit Settingss retrieved successfully",
"data": {
"credit_settings": [
{
"id": 6,
"party_id": 15,
"credit_limit_enabled": true,
"credit_limit_amount": 50000,
"no_limit": false,
"settlement_direction": "receive",
"current_balance_amount": 12500.75,
"balance_currency": "Birr",
"allow_overdue_transactions": false,
"created_at": "Jul 18, 2026"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/crm/parties/{party}/credit-settings
permission: party_financial-create
Create a new party credit settings.
Request Body
{
"credit_limit_enabled": true,
"credit_limit_amount": 50000,
"no_limit": false,
"settlement_direction": "receive",
"allow_overdue_transactions": false
}
Response 201
{
"success": true,
"message": "Party Credit Settings created successfully",
"data": {
"id": 6,
"party_id": 15,
"credit_limit_enabled": true,
"credit_limit_amount": 50000,
"no_limit": false,
"settlement_direction": "receive",
"current_balance_amount": 12500.75,
"balance_currency": "Birr",
"allow_overdue_transactions": false,
"created_at": "Jul 18, 2026"
}
}
/crm/parties/{party}/credit-settings
permission: party_financial-*
Per-party credit limit & settlement terms.
Response 200
{
"success": true,
"message": "Operation completed successfully",
"data": // shape depends on the specific action — see description above
}
/crm/parties/{party}/credit-settings
permission: party_financial-*
Per-party credit limit & settlement terms.
Response 200
{
"success": true,
"message": "Operation completed successfully",
"data": // shape depends on the specific action — see description above
}
/crm/parties/{party}/settings
permission: party_setting-read
List party settings. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Party Settings retrieved successfully",
"data": {
"settings": [
{
"id": 9,
"party_id": 15,
"enable_billing_address": true,
"enable_payment_reminder": true,
"payment_reminder_days": 7,
"additional_field_1_label": "License No.",
"additional_field_1_print": true,
"enable_loyalty_point": false,
"created_at": "Jul 18, 2026"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/crm/parties/{party}/settings
permission: party_setting-create
Create a new party setting.
Request Body
{
"enable_billing_address": true,
"enable_payment_reminder": true,
"payment_reminder_days": 7,
"additional_field_1_label": "License No.",
"additional_field_1_print": true
}
Response 201
{
"success": true,
"message": "Party Setting created successfully",
"data": {
"id": 9,
"party_id": 15,
"enable_billing_address": true,
"enable_payment_reminder": true,
"payment_reminder_days": 7,
"additional_field_1_label": "License No.",
"additional_field_1_print": true,
"enable_loyalty_point": false,
"created_at": "Jul 18, 2026"
}
}
/crm/parties/{party}/settings
permission: party_setting-*
Per-item settings (tax applicability, stock-maintenance flags, etc.).
Response 200
{
"success": true,
"message": "Operation completed successfully",
"data": // shape depends on the specific action — see description above
}
/crm/parties/{party}/settings
permission: party_setting-*
Per-item settings (tax applicability, stock-maintenance flags, etc.).
Response 200
{
"success": true,
"message": "Operation completed successfully",
"data": // shape depends on the specific action — see description above
}
Cash, Bank & Cheques — prefix /banking
/banking/bank-accounts
permission: bank_account-read
List bank accounts. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Bank Accounts retrieved successfully",
"data": {
"bank_accounts": [
{
"id": 2,
"uuid": "a1b2c3d4-...",
"bank_name": "Commercial Bank of Ethiopia",
"opening_balance": 100000,
"opening_balance_date": "Jan 1, 2026",
"account_holder_name": "Elilta Trading PLC",
"account_number": "1000234567890",
"branch_name": "Bole Branch",
"current_balance": 148230.5,
"is_active": true,
"created_at": "Jul 18, 2026"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/banking/bank-accounts
permission: bank_account-create
Create a new bank account.
Request Body
{
"bank_name": "Commercial Bank of Ethiopia",
"opening_balance": 100000,
"opening_balance_date": "2026-01-01",
"print_detail_on_invoice": true,
"account_holder_name": "Elilta Trading PLC",
"account_number": "1000234567890",
"branch_name": "Bole Branch"
}
Response 201
{
"success": true,
"message": "Bank Account created successfully",
"data": {
"id": 2,
"uuid": "a1b2c3d4-...",
"bank_name": "Commercial Bank of Ethiopia",
"opening_balance": 100000,
"opening_balance_date": "Jan 1, 2026",
"account_holder_name": "Elilta Trading PLC",
"account_number": "1000234567890",
"branch_name": "Bole Branch",
"current_balance": 148230.5,
"is_active": true,
"created_at": "Jul 18, 2026"
}
}
/banking/bank-accounts/{bank_account}
permission: bank_account-read
Get a single bank account by id.
Response 200
{
"success": true,
"message": "Bank Account retrieved successfully",
"data": {
"id": 2,
"uuid": "a1b2c3d4-...",
"bank_name": "Commercial Bank of Ethiopia",
"opening_balance": 100000,
"opening_balance_date": "Jan 1, 2026",
"account_holder_name": "Elilta Trading PLC",
"account_number": "1000234567890",
"branch_name": "Bole Branch",
"current_balance": 148230.5,
"is_active": true,
"created_at": "Jul 18, 2026"
}
}
/banking/bank-accounts/{bank_account}
permission: bank_account-update
Update an existing bank account.
Request Body
{
"bank_name": "Commercial Bank of Ethiopia",
"opening_balance": 100000,
"opening_balance_date": "2026-01-01",
"print_detail_on_invoice": true,
"account_holder_name": "Elilta Trading PLC",
"account_number": "1000234567890",
"branch_name": "Bole Branch"
}
Response 200
{
"success": true,
"message": "Bank Account updated successfully",
"data": {
"id": 2,
"uuid": "a1b2c3d4-...",
"bank_name": "Commercial Bank of Ethiopia",
"opening_balance": 100000,
"opening_balance_date": "Jan 1, 2026",
"account_holder_name": "Elilta Trading PLC",
"account_number": "1000234567890",
"branch_name": "Bole Branch",
"current_balance": 148230.5,
"is_active": true,
"created_at": "Jul 18, 2026"
}
}
/banking/bank-accounts/{bank_account}
permission: bank_account-delete
Soft-delete a bank account (recoverable via restore).
Response 200
{
"success": true,
"message": "Bank Account deleted successfully",
"data": null
}
/banking/bank-accounts/{bank_account}/update-balance
permission: bank_account-update
Reconcile this bank account's balance against actual bank records.
Request Body
{
"current_balance": 148230.5,
"notes": "Reconciled against July bank statement"
}
Response 200
{
"success": true,
"message": "Balance updated successfully",
"data": {
"id": 2,
"uuid": "a1b2c3d4-...",
"bank_name": "Commercial Bank of Ethiopia",
"opening_balance": 100000,
"opening_balance_date": "Jan 1, 2026",
"account_holder_name": "Elilta Trading PLC",
"account_number": "1000234567890",
"branch_name": "Bole Branch",
"current_balance": 148230.5,
"is_active": true,
"created_at": "Jul 18, 2026"
}
}
/banking/bank-adjustments
permission: bank_adjustment-read
List bank adjustments. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Bank Adjustments retrieved successfully",
"data": {
"bank_adjustments": [
{
"id": 44,
"transfer_date": "2026-07-18",
"type": "debit",
"bank_account_id": 2,
"amount": 5000,
"description": "Supplier payment adjustment",
"bank_account": {
"bank_account_id": 2,
"bank_name": "Commercial Bank of Ethiopia"
},
"adjusted_by_user": {
"user_id": 12,
"name": "Selamawit Tesfaye"
},
"created_at": "2026-07-18T09:00:00.000000Z"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/banking/bank-adjustments
permission: bank_adjustment-create
Create a new bank adjustment.
Request Body
{
"transfer_date": "2026-07-18",
"type": "debit",
"bank_account_id": 2,
"amount": 5000,
"description": "Supplier payment adjustment"
}
Response 201
{
"success": true,
"message": "Bank Adjustment created successfully",
"data": {
"id": 44,
"transfer_date": "2026-07-18",
"type": "debit",
"bank_account_id": 2,
"amount": 5000,
"description": "Supplier payment adjustment",
"bank_account": {
"bank_account_id": 2,
"bank_name": "Commercial Bank of Ethiopia"
},
"adjusted_by_user": {
"user_id": 12,
"name": "Selamawit Tesfaye"
},
"created_at": "2026-07-18T09:00:00.000000Z"
}
}
/banking/bank-adjustments/{bank_adjustment}
permission: bank_adjustment-read
Get a single bank adjustment by id.
Response 200
{
"success": true,
"message": "Bank Adjustment retrieved successfully",
"data": {
"id": 44,
"transfer_date": "2026-07-18",
"type": "debit",
"bank_account_id": 2,
"amount": 5000,
"description": "Supplier payment adjustment",
"bank_account": {
"bank_account_id": 2,
"bank_name": "Commercial Bank of Ethiopia"
},
"adjusted_by_user": {
"user_id": 12,
"name": "Selamawit Tesfaye"
},
"created_at": "2026-07-18T09:00:00.000000Z"
}
}
/banking/bank-adjustments/{bank_adjustment}
permission: bank_adjustment-update
Update an existing bank adjustment.
Request Body
{
"transfer_date": "2026-07-18",
"type": "debit",
"bank_account_id": 2,
"amount": 5000,
"description": "Supplier payment adjustment"
}
Response 200
{
"success": true,
"message": "Bank Adjustment updated successfully",
"data": {
"id": 44,
"transfer_date": "2026-07-18",
"type": "debit",
"bank_account_id": 2,
"amount": 5000,
"description": "Supplier payment adjustment",
"bank_account": {
"bank_account_id": 2,
"bank_name": "Commercial Bank of Ethiopia"
},
"adjusted_by_user": {
"user_id": 12,
"name": "Selamawit Tesfaye"
},
"created_at": "2026-07-18T09:00:00.000000Z"
}
}
/banking/bank-adjustments/{bank_adjustment}
permission: bank_adjustment-delete
Soft-delete a bank adjustment (recoverable via restore).
Response 200
{
"success": true,
"message": "Bank Adjustment deleted successfully",
"data": null
}
/banking/bank-transfers
permission: bank_transfer-read
List bank transfers. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Bank Transfers retrieved successfully",
"data": {
"bank_transfers": [
{
"id": 8,
"transfer_date": "2026-07-18",
"amount": 20000,
"source_type": "bank",
"source_id": 2,
"destination_type": "cash",
"destination_id": 5,
"description": "Cash withdrawal for petty cash",
"reference_number": "TRF-0008",
"source": {
"id": 2,
"type": "bank",
"name": "Commercial Bank of Ethiopia",
"current_balance": 128230.5
},
"destination": {
"id": 5,
"type": "cash",
"name": "Cash Account",
"current_balance": 20000
},
"created_at": "2026-07-18T09:00:00.000000Z"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/banking/bank-transfers
permission: bank_transfer-create
Create a new bank transfer.
Request Body
{
"transfer_date": "2026-07-18",
"amount": 20000,
"source_type": "bank",
"destination_type": "cash",
"source_id": 2,
"description": "Cash withdrawal for petty cash",
"reference_number": "TRF-0008"
}
Response 201
{
"success": true,
"message": "Bank Transfer created successfully",
"data": {
"id": 8,
"transfer_date": "2026-07-18",
"amount": 20000,
"source_type": "bank",
"source_id": 2,
"destination_type": "cash",
"destination_id": 5,
"description": "Cash withdrawal for petty cash",
"reference_number": "TRF-0008",
"source": {
"id": 2,
"type": "bank",
"name": "Commercial Bank of Ethiopia",
"current_balance": 128230.5
},
"destination": {
"id": 5,
"type": "cash",
"name": "Cash Account",
"current_balance": 20000
},
"created_at": "2026-07-18T09:00:00.000000Z"
}
}
/banking/bank-transfers/{bank_transfer}
permission: bank_transfer-read
Get a single bank transfer by id.
Response 200
{
"success": true,
"message": "Bank Transfer retrieved successfully",
"data": {
"id": 8,
"transfer_date": "2026-07-18",
"amount": 20000,
"source_type": "bank",
"source_id": 2,
"destination_type": "cash",
"destination_id": 5,
"description": "Cash withdrawal for petty cash",
"reference_number": "TRF-0008",
"source": {
"id": 2,
"type": "bank",
"name": "Commercial Bank of Ethiopia",
"current_balance": 128230.5
},
"destination": {
"id": 5,
"type": "cash",
"name": "Cash Account",
"current_balance": 20000
},
"created_at": "2026-07-18T09:00:00.000000Z"
}
}
/banking/bank-transfers/{bank_transfer}
permission: bank_transfer-update
Update an existing bank transfer.
Request Body
{
"transfer_date": "2026-07-18",
"amount": 20000,
"source_type": "bank",
"destination_type": "cash",
"source_id": 2,
"description": "Cash withdrawal for petty cash",
"reference_number": "TRF-0008"
}
Response 200
{
"success": true,
"message": "Bank Transfer updated successfully",
"data": {
"id": 8,
"transfer_date": "2026-07-18",
"amount": 20000,
"source_type": "bank",
"source_id": 2,
"destination_type": "cash",
"destination_id": 5,
"description": "Cash withdrawal for petty cash",
"reference_number": "TRF-0008",
"source": {
"id": 2,
"type": "bank",
"name": "Commercial Bank of Ethiopia",
"current_balance": 128230.5
},
"destination": {
"id": 5,
"type": "cash",
"name": "Cash Account",
"current_balance": 20000
},
"created_at": "2026-07-18T09:00:00.000000Z"
}
}
/banking/bank-transfers/{bank_transfer}
permission: bank_transfer-delete
Soft-delete a bank transfer (recoverable via restore).
Response 200
{
"success": true,
"message": "Bank Transfer deleted successfully",
"data": null
}
/banking/cash-adjustments
permission: cash_adjustment-read
List cash adjustments. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Cash Adjustments retrieved successfully",
"data": {
"cash_adjustments": [
{
"id": 5,
"type": "add",
"adjustment_date": "2026-07-18",
"amount": 20000,
"description": "Petty cash top-up",
"adjusted_by_user": {
"user_id": 12,
"name": "Selamawit Tesfaye"
},
"bank_transfer_id": 8,
"created_at": "Jul 18, 2026"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/banking/cash-adjustments
permission: cash_adjustment-create
Create a new cash adjustment.
Request Body
{
"type": "add",
"adjustment_date": "2026-07-18",
"amount": 20000,
"description": "Petty cash top-up",
"bank_transfer_id": 8
}
Response 201
{
"success": true,
"message": "Cash Adjustment created successfully",
"data": {
"id": 5,
"type": "add",
"adjustment_date": "2026-07-18",
"amount": 20000,
"description": "Petty cash top-up",
"adjusted_by_user": {
"user_id": 12,
"name": "Selamawit Tesfaye"
},
"bank_transfer_id": 8,
"created_at": "Jul 18, 2026"
}
}
/banking/cash-adjustments/{cash_adjustment}
permission: cash_adjustment-read
Get a single cash adjustment by id.
Response 200
{
"success": true,
"message": "Cash Adjustment retrieved successfully",
"data": {
"id": 5,
"type": "add",
"adjustment_date": "2026-07-18",
"amount": 20000,
"description": "Petty cash top-up",
"adjusted_by_user": {
"user_id": 12,
"name": "Selamawit Tesfaye"
},
"bank_transfer_id": 8,
"created_at": "Jul 18, 2026"
}
}
/banking/cash-adjustments/{cash_adjustment}
permission: cash_adjustment-update
Update an existing cash adjustment.
Request Body
{
"type": "add",
"adjustment_date": "2026-07-18",
"amount": 20000,
"description": "Petty cash top-up",
"bank_transfer_id": 8
}
Response 200
{
"success": true,
"message": "Cash Adjustment updated successfully",
"data": {
"id": 5,
"type": "add",
"adjustment_date": "2026-07-18",
"amount": 20000,
"description": "Petty cash top-up",
"adjusted_by_user": {
"user_id": 12,
"name": "Selamawit Tesfaye"
},
"bank_transfer_id": 8,
"created_at": "Jul 18, 2026"
}
}
/banking/cash-adjustments/{cash_adjustment}
permission: cash_adjustment-delete
Soft-delete a cash adjustment (recoverable via restore).
Response 200
{
"success": true,
"message": "Cash Adjustment deleted successfully",
"data": null
}
/banking/cheques
permission: cheque-read
List cheques. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Cheques retrieved successfully",
"data": {
"cheques": [
{
"id": 19,
"ref_number": "CHQ-000123",
"amount": 30000,
"type": "receivable",
"status": "open",
"cheque_date": "Jul 25, 2026",
"description": "Cheque from Blue Nile Trading",
"updated_at": "Jul 18, 2026",
"chequable": {
"type": "SalesInvoice",
"id": 44
}
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/banking/cheques
permission: cheque-create
Create a new cheque.
Request Body
{
"ref_number": "CHQ-000123",
"amount": 30000,
"cheque_date": "2026-07-25",
"party_id": 15,
"chequable_type": "App\Modules\Product\Models\SalesInvoice",
"chequable_id": 44,
"type": "receivable",
"description": "Cheque from Blue Nile Trading"
}
Response 201
{
"success": true,
"message": "Cheque created successfully",
"data": {
"id": 19,
"ref_number": "CHQ-000123",
"amount": 30000,
"type": "receivable",
"status": "open",
"cheque_date": "Jul 25, 2026",
"description": "Cheque from Blue Nile Trading",
"updated_at": "Jul 18, 2026",
"chequable": {
"type": "SalesInvoice",
"id": 44
}
}
}
/banking/cheques/{cheque}
permission: cheque-read
Get a single cheque by id.
Response 200
{
"success": true,
"message": "Cheque retrieved successfully",
"data": {
"id": 19,
"ref_number": "CHQ-000123",
"amount": 30000,
"type": "receivable",
"status": "open",
"cheque_date": "Jul 25, 2026",
"description": "Cheque from Blue Nile Trading",
"updated_at": "Jul 18, 2026",
"chequable": {
"type": "SalesInvoice",
"id": 44
}
}
}
/banking/cheques/{cheque}
permission: cheque-update
Update an existing cheque.
Request Body
{
"ref_number": "CHQ-000123",
"amount": 30000,
"cheque_date": "2026-07-25",
"party_id": 15,
"chequable_type": "App\Modules\Product\Models\SalesInvoice",
"chequable_id": 44,
"type": "receivable",
"description": "Cheque from Blue Nile Trading"
}
Response 200
{
"success": true,
"message": "Cheque updated successfully",
"data": {
"id": 19,
"ref_number": "CHQ-000123",
"amount": 30000,
"type": "receivable",
"status": "open",
"cheque_date": "Jul 25, 2026",
"description": "Cheque from Blue Nile Trading",
"updated_at": "Jul 18, 2026",
"chequable": {
"type": "SalesInvoice",
"id": 44
}
}
}
/banking/cheques/{cheque}
permission: cheque-delete
Soft-delete a cheque (recoverable via restore).
Response 200
{
"success": true,
"message": "Cheque deleted successfully",
"data": null
}
/banking/cheques/{cheque}/cash
permission: cheque-update
Mark a cheque as cashed/deposited — moves the amount into the linked cash or bank account.
Request Body
{
"deposit_type": "bank",
"bank_account_id": 2,
"date": "2026-07-25"
}
Response 200
{
"success": true,
"message": "Cheque cashed successfully",
"data": {
"id": 19,
"ref_number": "CHQ-000123",
"amount": 30000,
"type": "receivable",
"status": "open",
"cheque_date": "Jul 25, 2026",
"description": "Cheque from Blue Nile Trading",
"updated_at": "Jul 18, 2026",
"chequable": {
"type": "SalesInvoice",
"id": 44
}
}
}
/banking/cheques/statistics/overview
permission: cheque-read
Summary counts and totals of receivable/payable cheques by status.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"open_receivable": 45000,
"open_payable": 12000,
"overdue_count": 2
}
}
Notifications — prefix /notifications
/notifications
permission: notification-read
List the current user's notifications, newest first.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"notifications": [
{
"id": "9c4e2f1a-91b2-4b3c-8f10-000000000001",
"type": "App\Modules\Common\Notifications\ChequeDueNotification",
"data": {
"type": "cheque_due",
"cheque_id": 19,
"ref_number": "CHQ-000123",
"amount": 30000,
"due_date": "2026-07-25",
"message": "Cheque CHQ-000123 of 30000 is due on 2026-07-25."
},
"read_at": null,
"created_at": "2026-07-18T09:00:00.000000Z"
}
],
"pagination": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
}
/notifications/read-all
permission: notification-update
Mark every notification as read.
Response 200
{
"success": true,
"message": "Marked as read",
"data": {
"unread_count": 0
}
}
/notifications/unread-count
permission: notification-read
Unread notification count, for the header bell badge.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"unread_count": 7
}
}
/notifications/{id}
permission: notification-delete
Delete a notification.
Response 200
{
"success": true,
"message": "Deleted successfully",
"data": null
}
/notifications/{id}/read
permission: notification-update
Mark a single notification as read.
Response 200
{
"success": true,
"message": "Marked as read",
"data": {
"unread_count": 6
}
}
/notifications/settings
permission: notification_setting-read
List configured notification rules (e.g. cheque-due reminders).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"settings": [
{
"id": 3,
"key": "cheque_due_reminder",
"enabled": true,
"roles": [
"owner"
],
"days_before": 3
}
]
}
}
/notifications/settings
permission: notification_setting-create
Create a notification rule.
Request Body
{
"key": "cheque_due_reminder",
"enabled": true,
"roles": [
"owner"
],
"days_before": 3
}
Response 200
{
"success": true,
"message": "Created successfully",
"data": {
"id": 3,
"key": "cheque_due_reminder"
}
}
/notifications/settings/{setting}
permission: notification_setting-read
Get a single notification rule by key.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"id": 3,
"key": "cheque_due_reminder",
"enabled": true
}
}
/notifications/settings/{setting}
permission: notification_setting-update
Update a notification rule.
Request Body
{
"enabled": false,
"days_before": 5
}
Response 200
{
"success": true,
"message": "Updated successfully",
"data": null
}
/notifications/settings/{setting}
permission: notification_setting-delete
Delete a notification rule.
Response 200
{
"success": true,
"message": "Deleted successfully",
"data": null
}
Company Profile & Settings
/company-profile
permission: company_profile-read
Get the tenant's company profile (name, TIN, logo, contact info) shown on invoices.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"id": 1,
"logo": "https://.../logos/company1.png",
"company_name": "Elilta Trading PLC",
"tin_number": "0012345678",
"receipt_code": "RC-00981",
"address": "Bole Road, Addis Ababa",
"phone": "0911909090",
"email": "info@elilta.com",
"created_at": "Jul 18, 2026"
}
}
/company-profile
permission: company_profile-create
Create the company profile (first-time setup).
Request Body
{
"company_name": "Elilta Trading PLC",
"tin_number": "0012345678",
"receipt_code": "RC-00981",
"address": "Bole Road, Addis Ababa",
"phone": "0911909090",
"email": "info@elilta.com"
}
Response 201
{
"success": true,
"message": "Created successfully",
"data": {
"id": 1,
"logo": "https://.../logos/company1.png",
"company_name": "Elilta Trading PLC",
"tin_number": "0012345678",
"receipt_code": "RC-00981",
"address": "Bole Road, Addis Ababa",
"phone": "0911909090",
"email": "info@elilta.com",
"created_at": "Jul 18, 2026"
}
}
/company-profile
permission: company_profile-update
Update the company profile.
Request Body
{
"company_name": "Elilta Trading PLC",
"tin_number": "0012345678",
"receipt_code": "RC-00981",
"address": "Bole Road, Addis Ababa",
"phone": "0911909090",
"email": "info@elilta.com"
}
Response 200
{
"success": true,
"message": "Updated successfully",
"data": {
"id": 1,
"logo": "https://.../logos/company1.png",
"company_name": "Elilta Trading PLC",
"tin_number": "0012345678",
"receipt_code": "RC-00981",
"address": "Bole Road, Addis Ababa",
"phone": "0911909090",
"email": "info@elilta.com",
"created_at": "Jul 18, 2026"
}
}
/company-profile/logo
permission: company_profile-update
Remove the uploaded company logo.
Response 200
{
"success": true,
"message": "Logo removed successfully",
"data": null
}
/settings/general
permission: setting_general-read
Get tenant-wide general settings (currency, negative-stock policy, which optional modules are enabled).
Response 200
{
"payments": {
"enable_passcode": true,
"business_currency": "ETB",
"tin_number": true,
"stop_sales_on_negative_stock": false,
"estimate_quotation": true,
"proforma_invoices": true,
"sales_purchase_order": true,
"other_income": true,
"stock_transfer": true
}
}
"payments" key — a naming holdover in the backend, not billing-related./settings/general/update
permission: setting_general-update
Update general settings — accepts any subset of the boolean fields above.
Request Body
{
"business_currency": "ETB",
"stop_sales_on_negative_stock": true
}
Response 200
{
"success": true,
"message": "Settings updated successfully",
"data": null
}
/settings/transaction
permission: setting_transaction-read
Get transaction-form behavior settings (tax display, quick entry, discount rules, etc.).
Response 200
{
"payments": {
"invoice_bill_number": true,
"transaction_wise_tax": true,
"transaction_wise_discount": true,
"due_dates_and_payment_terms": true,
"billing_type": true
}
}
/settings/transaction/prefix
permission: setting_transaction_prefix-read
Get the configured document-number prefixes (invoices, orders, estimates, etc.).
Response 200
{
"transactions": {
"id": 1,
"firm": "ETL",
"sales": "INV-",
"purchase_order": "PO-",
"estimate": "EST-",
"proforma_invoice": "PF-",
"payment_in": "PMT-"
}
}
/settings/transaction/prefix/update
permission: setting_transaction_prefix-update
Update document-number prefixes.
Request Body
{
"sales": "INV-",
"purchase_order": "PO-"
}
Response 200
{
"success": true,
"message": "Prefixes updated successfully",
"data": null
}
/settings/transaction/update
permission: setting_transaction-update
Update transaction-form behavior settings — accepts any subset of the boolean fields above.
Request Body
{
"transaction_wise_tax": true,
"quick_entry": false
}
Response 200
{
"success": true,
"message": "Settings updated successfully",
"data": null
}
Dashboard Analytics — prefix /analytics
Error Handling
Errors always use the same envelope shape (success: false, message, optional errors map) with the appropriate HTTP status code.
| Code | Meaning | Common cause |
|---|---|---|
| 200 | OK | Success |
| 201 | Created | Resource created |
| 400 | Bad Request | Malformed/inconsistent request (e.g. business-rule conflict) |
| 401 | Unauthenticated | Missing/invalid/revoked Bearer token |
| 403 | Forbidden | Authenticated, but missing the required permission (or a protected resource, e.g. the Owner role) |
| 404 | Not Found | Resource id doesn't exist (or belongs to another tenant) |
| 422 | Validation Failed | See the errors map for per-field messages |
| 429 | Too Many Requests | Rate limit hit on OTP/auth-check endpoints |
| 500 | Server Error | Unexpected failure — message includes detail in development |
Roles & Permissions
Every tenant gets exactly two starting roles. Permissions follow a {module}-{create|read|update|delete} naming convention (e.g. item-create, sales_invoice-read) and are scoped to the tenant's business type.
Unrestricted — every permission for the tenant's business type. Creator-only: cannot be assigned to another user, cannot be edited or deleted.
Ships with a minimal read-only baseline (own profile, reports, parties, notifications, company profile). Fully customizable per-tenant via PUT /auth/roles/2 — its name is protected, but permissions are not.
Additional custom roles can be created via POST /auth/roles with any subset of the tenant's available permissions (GET /auth/permissions).
Product API Reference
Inventory, sales, purchases, warehousing, payments and reporting for Product-type tenants (service_type: "products"). All endpoints below live under the /product prefix unless noted. Haven't set up auth yet? Start on the Home page.
305
Product Endpoints
11
Modules
36
Report Endpoints
✓
Soft-delete + restore everywhere
GET (list, paginated + filterable), POST (create), GET /{id} (show), PUT/PATCH /{id} (update), DELETE /{id} (soft-delete), POST /{id}/restore, DELETE /{id}/force (permanent), and GET /{id}/history (audit trail). Learning one module gets you 80% of the rest for free.
Dashboard & Analytics
Powers the Product dashboard's summary cards and charts. Shared infrastructure (prefix /analytics), not /product-prefixed.
/analytics/dashboard
permission: report-read
Top-level dashboard summary — sales/purchase totals, receivables/payables, recent activity.
{
"success": true,
"data": {
"total_sales": 184500.00,
"total_purchases": 92300.00,
"receivables": 21450.00,
"payables": 8900.00
}
}
Items & Catalog
The core product catalog — items, per-item pricing, stock levels, stock adjustments and unit mappings.
Items — full reference
/product/items
permission: item-read
List items. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Items retrieved successfully",
"data": {
"items": [
{
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/items
permission: item-create
Create a new item.
Request Body
{
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"item_category_id": 3,
"description": "OPC 42.5 grade cement bag",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"units": [
{
"level": "primary",
"unit_id": 3,
"custom_factor": null
}
],
"warehouse_id": 1,
"batch_no": "BATCH-2026-001",
"opening_stock": 100,
"reorder_level": 20,
"allow_negative_stock": false
}
Response 201
{
"success": true,
"message": "Item created successfully",
"data": {
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
}
/product/items/{item}
permission: item-read
Get a single item by id.
Response 200
{
"success": true,
"message": "Item retrieved successfully",
"data": {
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
}
/product/items/{item}
permission: item-update
Update an existing item.
Request Body
{
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"item_category_id": 3,
"description": "OPC 42.5 grade cement bag",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"units": [
{
"level": "primary",
"unit_id": 3,
"custom_factor": null
}
],
"warehouse_id": 1,
"batch_no": "BATCH-2026-001",
"opening_stock": 100,
"reorder_level": 20,
"allow_negative_stock": false
}
Response 200
{
"success": true,
"message": "Item updated successfully",
"data": {
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
}
/product/items/{item}
permission: item-delete
Soft-delete a item (recoverable via restore).
Response 200
{
"success": true,
"message": "Item deleted successfully",
"data": null
}
/product/items/{item}/transactions
permission: item-read
List items. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Items retrieved successfully",
"data": {
"items": [
{
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/items/autocomplete
permission: item-read
Lightweight id+name list for autocomplete/typeahead item pickers.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"items": [
{
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
]
}
}
/product/items/filter
permission: item-read
Advanced filtered item list (category, price range, stock status).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"items": [
{
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
]
}
}
/product/items/search
permission: item-read
Full-text item search by name, SKU, or barcode.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"items": [
{
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
]
}
}
/product/items/{item}/transactions
permission: item-read
Ledger transactions involving this item.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"transactions": [
{
"id": 512,
"transaction_no": "TXN-2026-000452",
"transaction_date": "2026-07-18 10:30:00",
"amount": 9025,
"type": "sale",
"direction": "in",
"description": "Payment received for INV-2026-0042",
"reference_number": "RCPT-2026-0033",
"status": "completed",
"party_balance_before": 21525.75,
"party_balance_after": 12500.75,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"display_name": "Blue Nile Trading"
}
}
]
}
}
Item Prices & Stocks
/product/item-prices/{item_price}
permission: item_price-update
Update an existing item price.
Request Body
{
"price_type": "selling",
"amount": 950,
"currency": "Birr",
"effective_from": "2026-07-01",
"effective_to": null,
"is_active": true
}
Response 200
{
"success": true,
"message": "Item Price updated successfully",
"data": {
"id": 21,
"uuid": "d8b1c3f7-...",
"price_type": "selling",
"amount": 950,
"currency": "Birr",
"effective_from": "2026-07-01",
"effective_to": null,
"is_active": true,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/item-prices/{item_price}
permission: item_price-delete
Soft-delete a item price (recoverable via restore).
Response 200
{
"success": true,
"message": "Item Price deleted successfully",
"data": null
}
/product/items/{item}/prices
permission: item_price-read
Price list (selling/purchase/MRP, with effective date ranges) for this item.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"prices": [
{
"id": 21,
"uuid": "d8b1c3f7-...",
"price_type": "selling",
"amount": 950,
"currency": "Birr",
"effective_from": "2026-07-01",
"effective_to": null,
"is_active": true,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
}
}
/product/items/{item}/prices
permission: item_price-create
Add a price entry for this item.
Request Body
{
"price_type": "selling",
"amount": 950,
"currency": "Birr",
"effective_from": "2026-07-01",
"effective_to": null,
"is_active": true
}
Response 201
{
"success": true,
"message": "Price added successfully",
"data": {
"id": 21,
"uuid": "d8b1c3f7-...",
"price_type": "selling",
"amount": 950,
"currency": "Birr",
"effective_from": "2026-07-01",
"effective_to": null,
"is_active": true,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/items/{item}/prices/history
permission: item_price-read
Price change history for this item.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"history": []
}
}
/product/item-stocks/{item_stock}
permission: item_stock-update
Update an existing item stock.
Request Body
{
"warehouse_id": 1,
"current_stock": 240,
"reserved_stock": 0,
"opening_stock": 100,
"opening_stock_value": 78000,
"average_cost": 780,
"last_purchase_price": 800,
"reorder_level": 20,
"allow_negative_stock": false,
"valuation_method": "fifo"
}
Response 200
{
"success": true,
"message": "Item Stock updated successfully",
"data": {
"id": 55,
"uuid": "b6f9a1d5-...",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"batch_no": "BATCH-2026-001",
"current_stock": 240,
"reserved_stock": 10,
"available_stock": 230,
"opening_stock": 100,
"average_cost": 780,
"last_purchase_price": 800,
"reorder_level": 20,
"allow_negative_stock": false,
"valuation_method": "fifo",
"selling_price": 950,
"purchase_price": 800,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/item-stocks/{item_stock}
permission: item_stock-delete
Soft-delete a item stock (recoverable via restore).
Response 200
{
"success": true,
"message": "Item Stock deleted successfully",
"data": null
}
/product/items/{item}/stocks
permission: item_stock-read
Stock levels for this item, by warehouse and batch.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"stocks": [
{
"id": 55,
"uuid": "b6f9a1d5-...",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"batch_no": "BATCH-2026-001",
"current_stock": 240,
"reserved_stock": 10,
"available_stock": 230,
"opening_stock": 100,
"average_cost": 780,
"last_purchase_price": 800,
"reorder_level": 20,
"allow_negative_stock": false,
"valuation_method": "fifo",
"selling_price": 950,
"purchase_price": 800,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
}
}
/product/items/{item}/stocks
permission: item_stock-create
Create a stock record for this item in a warehouse (e.g. opening stock for a new batch).
Request Body
{
"warehouse_id": 1,
"current_stock": 240,
"reserved_stock": 0,
"opening_stock": 100,
"opening_stock_value": 78000,
"average_cost": 780,
"last_purchase_price": 800,
"reorder_level": 20,
"allow_negative_stock": false,
"valuation_method": "fifo"
}
Response 201
{
"success": true,
"message": "Stock created successfully",
"data": {
"id": 55,
"uuid": "b6f9a1d5-...",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"batch_no": "BATCH-2026-001",
"current_stock": 240,
"reserved_stock": 10,
"available_stock": 230,
"opening_stock": 100,
"average_cost": 780,
"last_purchase_price": 800,
"reorder_level": 20,
"allow_negative_stock": false,
"valuation_method": "fifo",
"selling_price": 950,
"purchase_price": 800,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/items/{item}/stocks/history
permission: item_stock-read
Stock-level change history for this item.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"history": []
}
}
/product/items/{item}/stock-adjustments
permission: stock_adjustment-read
List stock adjustments. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Stock Adjustments retrieved successfully",
"data": {
"adjustments": [
{
"id": 88,
"uuid": "c7a0b2e6-...",
"item_stock": {
"id": 55,
"current_stock": 240,
"available_stock": 230
},
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"adjustment_type": "add",
"quantity": 50,
"unit_cost": 780,
"total_value": 39000,
"stock_before": 190,
"stock_after": 240,
"batch_no": "BATCH-2026-001",
"reason": "stock_correction",
"notes": "Physical count adjustment",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/items/{item}/stock-adjustments
permission: stock_adjustment-create
Create a new stock adjustment.
Request Body
{
"warehouse_id": 1,
"adjustment_type": "add",
"quantity": 50,
"unit_cost": 780,
"reason": "stock_correction",
"batch_no": "BATCH-2026-001",
"notes": "Physical count adjustment"
}
Response 201
{
"success": true,
"message": "Stock Adjustment created successfully",
"data": {
"id": 88,
"uuid": "c7a0b2e6-...",
"item_stock": {
"id": 55,
"current_stock": 240,
"available_stock": 230
},
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"adjustment_type": "add",
"quantity": 50,
"unit_cost": 780,
"total_value": 39000,
"stock_before": 190,
"stock_after": 240,
"batch_no": "BATCH-2026-001",
"reason": "stock_correction",
"notes": "Physical count adjustment",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/items/{item}/stock-adjustments/{stock_adjustment}
permission: stock_adjustment-read
Get a single stock adjustment by id.
Response 200
{
"success": true,
"message": "Stock Adjustment retrieved successfully",
"data": {
"id": 88,
"uuid": "c7a0b2e6-...",
"item_stock": {
"id": 55,
"current_stock": 240,
"available_stock": 230
},
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"adjustment_type": "add",
"quantity": 50,
"unit_cost": 780,
"total_value": 39000,
"stock_before": 190,
"stock_after": 240,
"batch_no": "BATCH-2026-001",
"reason": "stock_correction",
"notes": "Physical count adjustment",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/items/{item}/stock-adjustments/{stock_adjustment}
permission: stock_adjustment-update
Update an existing stock adjustment.
Request Body
{
"warehouse_id": 1,
"adjustment_type": "add",
"quantity": 50,
"unit_cost": 780,
"reason": "stock_correction",
"batch_no": "BATCH-2026-001",
"notes": "Physical count adjustment"
}
Response 200
{
"success": true,
"message": "Stock Adjustment updated successfully",
"data": {
"id": 88,
"uuid": "c7a0b2e6-...",
"item_stock": {
"id": 55,
"current_stock": 240,
"available_stock": 230
},
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"adjustment_type": "add",
"quantity": 50,
"unit_cost": 780,
"total_value": 39000,
"stock_before": 190,
"stock_after": 240,
"batch_no": "BATCH-2026-001",
"reason": "stock_correction",
"notes": "Physical count adjustment",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/items/{item}/stock-adjustments/{stock_adjustment}
permission: stock_adjustment-delete
Soft-delete a stock adjustment (recoverable via restore).
Response 200
{
"success": true,
"message": "Stock Adjustment deleted successfully",
"data": null
}
/product/items/{item}/settings
permission: item_setting-read
List items. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Items retrieved successfully",
"data": {
"settings": [
{
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/items/{item}/settings
permission: item_setting-create
Create a new item.
Request Body
{
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"item_category_id": 3,
"description": "OPC 42.5 grade cement bag",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"units": [
{
"level": "primary",
"unit_id": 3,
"custom_factor": null
}
],
"warehouse_id": 1,
"batch_no": "BATCH-2026-001",
"opening_stock": 100,
"reorder_level": 20,
"allow_negative_stock": false
}
Response 201
{
"success": true,
"message": "Item created successfully",
"data": {
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
}
/product/items/{item}/settings
permission: item-*
Per-item settings (tax applicability, stock-maintenance flags, etc.).
Response 200
{
"success": true,
"message": "Operation completed successfully",
"data": // shape depends on the specific action — see description above
}
/product/items/{item}/settings
permission: item-*
Per-item settings (tax applicability, stock-maintenance flags, etc.).
Response 200
{
"success": true,
"message": "Operation completed successfully",
"data": // shape depends on the specific action — see description above
}
/product/items/{item}/unit-mappings
permission: item_unit_mapping-read
List unit mappings. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Unit Mappings retrieved successfully",
"data": {
"mappings": [
{
"id": 12,
"uuid": "f4d7e9b3-...",
"item_id": 101,
"unit_id": 5,
"level": "secondary",
"custom_factor": 12,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"unit": {
"id": 5,
"name": "Box",
"short_code": "box"
},
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/items/{item}/unit-mappings
permission: item_unit_mapping-create
Create a new unit mapping.
Request Body
{
"unit_id": 5,
"level": "secondary",
"custom_factor": 12
}
Response 201
{
"success": true,
"message": "Unit Mapping created successfully",
"data": {
"id": 12,
"uuid": "f4d7e9b3-...",
"item_id": 101,
"unit_id": 5,
"level": "secondary",
"custom_factor": 12,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"unit": {
"id": 5,
"name": "Box",
"short_code": "box"
},
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
Item Categories
Hierarchical categorization for items. Prefix /product/item-categories.
/product/item-categories
permission: item_category-read
List item categorys. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Item Categorys retrieved successfully",
"data": {
"categories": [
{
"id": 3,
"uuid": "c1a4b6e2-...",
"name": "Building Materials",
"description": "Cement, rebar, and other construction materials",
"is_active": true,
"items_count": 24,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/item-categories
permission: item_category-create
Create a new item category.
Request Body
{
"name": "Building Materials",
"description": "Cement, rebar, and other construction materials",
"is_active": true
}
Response 201
{
"success": true,
"message": "Item Category created successfully",
"data": {
"id": 3,
"uuid": "c1a4b6e2-...",
"name": "Building Materials",
"description": "Cement, rebar, and other construction materials",
"is_active": true,
"items_count": 24,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/item-categories/{item_category}
permission: item_category-read
Get a single item category by id.
Response 200
{
"success": true,
"message": "Item Category retrieved successfully",
"data": {
"id": 3,
"uuid": "c1a4b6e2-...",
"name": "Building Materials",
"description": "Cement, rebar, and other construction materials",
"is_active": true,
"items_count": 24,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/item-categories/{item_category}
permission: item_category-update
Update an existing item category.
Request Body
{
"name": "Building Materials",
"description": "Cement, rebar, and other construction materials",
"is_active": true
}
Response 200
{
"success": true,
"message": "Item Category updated successfully",
"data": {
"id": 3,
"uuid": "c1a4b6e2-...",
"name": "Building Materials",
"description": "Cement, rebar, and other construction materials",
"is_active": true,
"items_count": 24,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/item-categories/{item_category}
permission: item_category-delete
Soft-delete a item category (recoverable via restore).
Response 200
{
"success": true,
"message": "Item Category deleted successfully",
"data": null
}
Units & Conversions
Units of measure, unit-to-unit conversion rules, and per-item unit mappings (e.g. selling both by "box" and "piece").
Item Units — /product/item-units
/product/item-units
permission: item_unit-read
List item units. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Item Units retrieved successfully",
"data": {
"units": [
{
"id": 3,
"uuid": "d2b5c7f1-...",
"name": "Kilogram",
"short_code": "kg",
"is_base": true,
"is_active": true,
"items_count": 41,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/item-units
permission: item_unit-create
Create a new item unit.
Request Body
{
"name": "Kilogram",
"short_code": "kg",
"is_base": true,
"is_active": true
}
Response 201
{
"success": true,
"message": "Item Unit created successfully",
"data": {
"id": 3,
"uuid": "d2b5c7f1-...",
"name": "Kilogram",
"short_code": "kg",
"is_base": true,
"is_active": true,
"items_count": 41,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/item-units/{item_unit}
permission: item_unit-read
Get a single item unit by id.
Response 200
{
"success": true,
"message": "Item Unit retrieved successfully",
"data": {
"id": 3,
"uuid": "d2b5c7f1-...",
"name": "Kilogram",
"short_code": "kg",
"is_base": true,
"is_active": true,
"items_count": 41,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/item-units/{item_unit}
permission: item_unit-update
Update an existing item unit.
Request Body
{
"name": "Kilogram",
"short_code": "kg",
"is_base": true,
"is_active": true
}
Response 200
{
"success": true,
"message": "Item Unit updated successfully",
"data": {
"id": 3,
"uuid": "d2b5c7f1-...",
"name": "Kilogram",
"short_code": "kg",
"is_base": true,
"is_active": true,
"items_count": 41,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/item-units/{item_unit}
permission: item_unit-delete
Soft-delete a item unit (recoverable via restore).
Response 200
{
"success": true,
"message": "Item Unit deleted successfully",
"data": null
}
/product/item-units/base-units
permission: item_unit-read
List base (root, non-derived) units.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"units": [
{
"id": 3,
"uuid": "d2b5c7f1-...",
"name": "Kilogram",
"short_code": "kg",
"is_base": true,
"is_active": true,
"items_count": 41,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
}
}
/product/item-units/bulk-with-conversions
permission: item_unit-create
Create multiple units together with their conversion rules in a single call.
Request Body
{
"units": [
{
"name": "Box",
"short_code": "box",
"conversions": [
{
"to_unit_id": 3,
"factor": 12
}
]
}
]
}
Response 201
{
"success": true,
"message": "Units created successfully",
"data": null
}
/product/item-units/conversion-path
permission: item_unit-read
Resolve the conversion path/factor between two units.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"from_unit_id": 5,
"to_unit_id": 3,
"factor": 12
}
}
/product/item-units/hierarchy
permission: item_unit-read
Full unit hierarchy tree (base units with their derived conversions).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"units": [
{
"id": 3,
"uuid": "d2b5c7f1-...",
"name": "Kilogram",
"short_code": "kg",
"is_base": true,
"is_active": true,
"items_count": 41,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"children": []
}
]
}
}
/product/item-units/validation
permission: item_unit-read
Validate a proposed unit configuration before saving.
Response 200
{
"success": true,
"message": "Valid",
"data": null
}
Unit Conversions — /product/unit-conversions
/product/unit-conversions
permission: unit_conversion-read
List unit conversions. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Unit Conversions retrieved successfully",
"data": {
"conversions": [
{
"id": 7,
"uuid": "e3c6d8a2-...",
"from_unit_id": 3,
"to_unit_id": 4,
"factor": 1000,
"is_bidirectional": true,
"from_unit": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"to_unit": {
"id": 4,
"name": "Gram",
"short_code": "g"
},
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/unit-conversions
permission: unit_conversion-create
Create a new unit conversion.
Request Body
{
"from_unit_id": 3,
"to_unit_id": 4,
"factor": 1000,
"is_bidirectional": true
}
Response 201
{
"success": true,
"message": "Unit Conversion created successfully",
"data": {
"id": 7,
"uuid": "e3c6d8a2-...",
"from_unit_id": 3,
"to_unit_id": 4,
"factor": 1000,
"is_bidirectional": true,
"from_unit": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"to_unit": {
"id": 4,
"name": "Gram",
"short_code": "g"
},
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/unit-conversions/{unit_conversion}
permission: unit_conversion-read
Get a single unit conversion by id.
Response 200
{
"success": true,
"message": "Unit Conversion retrieved successfully",
"data": {
"id": 7,
"uuid": "e3c6d8a2-...",
"from_unit_id": 3,
"to_unit_id": 4,
"factor": 1000,
"is_bidirectional": true,
"from_unit": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"to_unit": {
"id": 4,
"name": "Gram",
"short_code": "g"
},
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/unit-conversions/{unit_conversion}
permission: unit_conversion-update
Update an existing unit conversion.
Request Body
{
"from_unit_id": 3,
"to_unit_id": 4,
"factor": 1000,
"is_bidirectional": true
}
Response 200
{
"success": true,
"message": "Unit Conversion updated successfully",
"data": {
"id": 7,
"uuid": "e3c6d8a2-...",
"from_unit_id": 3,
"to_unit_id": 4,
"factor": 1000,
"is_bidirectional": true,
"from_unit": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"to_unit": {
"id": 4,
"name": "Gram",
"short_code": "g"
},
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/unit-conversions/{unit_conversion}
permission: unit_conversion-delete
Soft-delete a unit conversion (recoverable via restore).
Response 200
{
"success": true,
"message": "Unit Conversion deleted successfully",
"data": null
}
Unit Mappings — /product/unit-mappings
/product/unit-mappings/{item_unit_mapping}
permission: item_unit_mapping-update
Update an existing unit mapping.
Request Body
{
"unit_id": 5,
"level": "secondary",
"custom_factor": 12
}
Response 200
{
"success": true,
"message": "Unit Mapping updated successfully",
"data": {
"id": 12,
"uuid": "f4d7e9b3-...",
"item_id": 101,
"unit_id": 5,
"level": "secondary",
"custom_factor": 12,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"unit": {
"id": 5,
"name": "Box",
"short_code": "box"
},
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/unit-mappings/{item_unit_mapping}
permission: item_unit_mapping-delete
Soft-delete a unit mapping (recoverable via restore).
Response 200
{
"success": true,
"message": "Unit Mapping deleted successfully",
"data": null
}
Warehouses & Stock
Physical/logical storage locations, and moving stock between them.
Warehouses — /product/warehouses
/product/warehouses
permission: warehouse-read
List warehouses. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Warehouses retrieved successfully",
"data": {
"warehouses": [
{
"id": 1,
"uuid": "a5e8f0c4-...",
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01",
"address": "Merkato Industrial Zone",
"city": "Addis Ababa",
"country": "Ethiopia",
"contact_person": "Dawit Mekonnen",
"phone": "0911909090",
"email": "warehouse@elilta.com",
"is_default": true,
"is_active": true,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/warehouses
permission: warehouse-create
Create a new warehouse.
Request Body
{
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01",
"address": "Merkato Industrial Zone",
"city": "Addis Ababa",
"country": "Ethiopia",
"contact_person": "Dawit Mekonnen",
"phone": "0911909090",
"email": "warehouse@elilta.com",
"is_default": false,
"is_active": true
}
Response 201
{
"success": true,
"message": "Warehouse created successfully",
"data": {
"id": 1,
"uuid": "a5e8f0c4-...",
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01",
"address": "Merkato Industrial Zone",
"city": "Addis Ababa",
"country": "Ethiopia",
"contact_person": "Dawit Mekonnen",
"phone": "0911909090",
"email": "warehouse@elilta.com",
"is_default": true,
"is_active": true,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/warehouses/{warehouse}
permission: warehouse-read
Get a single warehouse by id.
Response 200
{
"success": true,
"message": "Warehouse retrieved successfully",
"data": {
"id": 1,
"uuid": "a5e8f0c4-...",
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01",
"address": "Merkato Industrial Zone",
"city": "Addis Ababa",
"country": "Ethiopia",
"contact_person": "Dawit Mekonnen",
"phone": "0911909090",
"email": "warehouse@elilta.com",
"is_default": true,
"is_active": true,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/warehouses/{warehouse}
permission: warehouse-update
Update an existing warehouse.
Request Body
{
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01",
"address": "Merkato Industrial Zone",
"city": "Addis Ababa",
"country": "Ethiopia",
"contact_person": "Dawit Mekonnen",
"phone": "0911909090",
"email": "warehouse@elilta.com",
"is_default": false,
"is_active": true
}
Response 200
{
"success": true,
"message": "Warehouse updated successfully",
"data": {
"id": 1,
"uuid": "a5e8f0c4-...",
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01",
"address": "Merkato Industrial Zone",
"city": "Addis Ababa",
"country": "Ethiopia",
"contact_person": "Dawit Mekonnen",
"phone": "0911909090",
"email": "warehouse@elilta.com",
"is_default": true,
"is_active": true,
"status": "active",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/warehouses/{warehouse}
permission: warehouse-delete
Soft-delete a warehouse (recoverable via restore).
Response 200
{
"success": true,
"message": "Warehouse deleted successfully",
"data": null
}
/product/warehouses/items/{warehouse}
permission: warehouse-read
Items currently stocked in this warehouse.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"items": [
{
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
}
]
}
}
Stock Transfers — /product/stock-transfers
/product/stock-transfers
permission: stock_transfer-read
List stock transfers. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Stock Transfers retrieved successfully",
"data": {
"transfers": [
{
"id": 14,
"uuid": "e9c2d4a8-...",
"from_warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"to_warehouse": {
"id": 2,
"name": "Adama Branch Warehouse",
"code": "WH-AD-01"
},
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"transfer_date": "2026-07-18",
"quantity": 30,
"notes": "Restocking branch",
"can_process": true,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/stock-transfers
permission: stock_transfer-create
Create a new stock transfer.
Request Body
{
"from_warehouse_id": 1,
"to_warehouse_id": 2,
"item_id": 101,
"transfer_date": "2026-07-18",
"quantity": 30,
"from_batch_no": "BATCH-2026-001",
"to_batch_no": "BATCH-2026-001",
"notes": "Restocking branch"
}
Response 201
{
"success": true,
"message": "Stock Transfer created successfully",
"data": {
"id": 14,
"uuid": "e9c2d4a8-...",
"from_warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"to_warehouse": {
"id": 2,
"name": "Adama Branch Warehouse",
"code": "WH-AD-01"
},
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"transfer_date": "2026-07-18",
"quantity": 30,
"notes": "Restocking branch",
"can_process": true,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/stock-transfers/{stock_transfer}
permission: stock_transfer-read
Get a single stock transfer by id.
Response 200
{
"success": true,
"message": "Stock Transfer retrieved successfully",
"data": {
"id": 14,
"uuid": "e9c2d4a8-...",
"from_warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"to_warehouse": {
"id": 2,
"name": "Adama Branch Warehouse",
"code": "WH-AD-01"
},
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"transfer_date": "2026-07-18",
"quantity": 30,
"notes": "Restocking branch",
"can_process": true,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/stock-transfers/{stock_transfer}
permission: stock_transfer-update
Update an existing stock transfer.
Request Body
{
"from_warehouse_id": 1,
"to_warehouse_id": 2,
"item_id": 101,
"transfer_date": "2026-07-18",
"quantity": 30,
"from_batch_no": "BATCH-2026-001",
"to_batch_no": "BATCH-2026-001",
"notes": "Restocking branch"
}
Response 200
{
"success": true,
"message": "Stock Transfer updated successfully",
"data": {
"id": 14,
"uuid": "e9c2d4a8-...",
"from_warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
},
"to_warehouse": {
"id": 2,
"name": "Adama Branch Warehouse",
"code": "WH-AD-01"
},
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"transfer_date": "2026-07-18",
"quantity": 30,
"notes": "Restocking branch",
"can_process": true,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/stock-transfers/{stock_transfer}
permission: stock_transfer-delete
Soft-delete a stock transfer (recoverable via restore).
Response 200
{
"success": true,
"message": "Stock Transfer deleted successfully",
"data": null
}
Parties (Customers / Suppliers)
/crm). Listed here because every Sales/Purchase transaction requires a party_id.
Sales
Sales Invoices, Sales Orders, Proformas and Sales Returns. Prefix /product/sales and /product/sales-returns.
Sales Invoices & Orders — full reference
/product/sales
permission: sales_invoice-read
List sales invoices. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Sales Invoices retrieved successfully",
"data": {
"sales": [
{
"id": 44,
"is_credit": true,
"invoice_no": "INV-2026-0042",
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"status": "unpaid",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"grand_total_in_words": "Nine Thousand Twenty Five Birr",
"paid_amount": 0,
"balance_amount": 9025,
"notes": "Delivered to site",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/sales
permission: sales_invoice-create
Create a new sales invoice.
Request Body
{
"is_credit": true,
"invoice_no": "INV-2026-0042",
"party_id": 15,
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"paid_amount": 0,
"advance": false,
"balance_amount": 9025,
"lines": [
{
"item_id": 101,
"uom_id": 3,
"quantity": 10,
"rate": 950,
"sub_total": 9500,
"discount_value": 475,
"tax_amount": 0,
"total_amount": 9025,
"batch_no": "BATCH-2026-001",
"warehouse_id": 1
}
]
}
Response 201
{
"success": true,
"message": "Sales Invoice created successfully",
"data": {
"id": 44,
"is_credit": true,
"invoice_no": "INV-2026-0042",
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"status": "unpaid",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"grand_total_in_words": "Nine Thousand Twenty Five Birr",
"paid_amount": 0,
"balance_amount": 9025,
"notes": "Delivered to site",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/{salesInvoice}
permission: sales_invoice-read
Get a single sales invoice by id.
Response 200
{
"success": true,
"message": "Sales Invoice retrieved successfully",
"data": {
"id": 44,
"is_credit": true,
"invoice_no": "INV-2026-0042",
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"status": "unpaid",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"grand_total_in_words": "Nine Thousand Twenty Five Birr",
"paid_amount": 0,
"balance_amount": 9025,
"notes": "Delivered to site",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/{salesInvoice}
permission: sales_invoice-update
Update an existing sales invoice.
Request Body
{
"is_credit": true,
"invoice_no": "INV-2026-0042",
"party_id": 15,
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"paid_amount": 0,
"advance": false,
"balance_amount": 9025,
"lines": [
{
"item_id": 101,
"uom_id": 3,
"quantity": 10,
"rate": 950,
"sub_total": 9500,
"discount_value": 475,
"tax_amount": 0,
"total_amount": 9025,
"batch_no": "BATCH-2026-001",
"warehouse_id": 1
}
]
}
Response 200
{
"success": true,
"message": "Sales Invoice updated successfully",
"data": {
"id": 44,
"is_credit": true,
"invoice_no": "INV-2026-0042",
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"status": "unpaid",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"grand_total_in_words": "Nine Thousand Twenty Five Birr",
"paid_amount": 0,
"balance_amount": 9025,
"notes": "Delivered to site",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/{salesInvoice}
permission: sales_invoice-delete
Soft-delete a sales invoice (recoverable via restore).
Response 200
{
"success": true,
"message": "Sales Invoice deleted successfully",
"data": null
}
/product/sales/by-number/{invoice_no}
permission: sales_invoice-read
Look up a sales invoice by its invoice number.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"id": 44,
"is_credit": true,
"invoice_no": "INV-2026-0042",
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"status": "unpaid",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"grand_total_in_words": "Nine Thousand Twenty Five Birr",
"paid_amount": 0,
"balance_amount": 9025,
"notes": "Delivered to site",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/create-return
permission: sales_return-create
Create a return against an existing sales invoice (no invoice id required in the path — invoice is identified in the body).
Request Body
{
"reference_invoice_id": 44,
"lines": [
{
"item_id": 101,
"quantity": 1
}
]
}
Response 201
{
"success": true,
"message": "Return created successfully",
"data": {
"id": 3,
"is_credit": true,
"return_no": "SR-2026-0003",
"return_date": "2026-07-18",
"invoice_date": "2026-07-10",
"invoice_no": "INV-2026-0038",
"sub_total": 950,
"discount_total": 0,
"tax_total": 0,
"grand_total": 950,
"paid_amount": 950,
"balance_amount": 0,
"payment_type": "cash",
"reason": "damaged goods",
"total_refund": 950,
"status": "confirmed",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 1,
"unit": "kg",
"price_per_unit": 950,
"amount": 950,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/sales/revert-return/{returnId}
permission: sales_return-update
Revert a previously confirmed sales return, restoring the original invoice balance.
Response 200
{
"success": true,
"message": "Return reverted successfully",
"data": null
}
/product/sales/search-by-number
permission: sales_invoice-read
Search sales invoices by number (query param q).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"sales": [
{
"id": 44,
"is_credit": true,
"invoice_no": "INV-2026-0042",
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"status": "unpaid",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"grand_total_in_words": "Nine Thousand Twenty Five Birr",
"paid_amount": 0,
"balance_amount": 9025,
"notes": "Delivered to site",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
]
}
}
/product/sales/{invoiceNo}/available-return-lines
permission: sales_return-read
Line items on this invoice still eligible to be returned.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"lines": [
{
"item_id": 101,
"returnable_quantity": 9
}
]
}
}
/product/sales/{salesInvoice}/confirm
permission: sales_invoice-update
Confirm/finalize this invoice — locks it and applies stock & ledger effects. Cannot be undone.
Response 200
{
"success": true,
"message": "Invoice confirmed successfully",
"data": {
"id": 44,
"is_credit": true,
"invoice_no": "INV-2026-0042",
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"status": "unpaid",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"grand_total_in_words": "Nine Thousand Twenty Five Birr",
"paid_amount": 0,
"balance_amount": 9025,
"notes": "Delivered to site",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/{salesInvoice}/payments
permission: sales_payment-read
Payments recorded against this invoice.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"payments": [
{
"id": 33,
"party_id": 15,
"is_opening_balance": false,
"payment_type": "bank",
"bank_account_id": 2,
"receipt_number": "RCPT-2026-0033",
"payment_date": "2026-07-18",
"description": "Payment for INV-2026-0042",
"received_amount": 9025,
"status": "used",
"attachments": [],
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
}
}
]
}
}
/product/sales/{salesInvoice}/payments
permission: sales_payment-create
Record a payment directly against this invoice.
Request Body
{
"amount": 9025,
"payment_type": "cash",
"payment_date": "2026-07-18"
}
Response 201
{
"success": true,
"message": "Payment recorded successfully",
"data": {
"id": 33,
"party_id": 15,
"is_opening_balance": false,
"payment_type": "bank",
"bank_account_id": 2,
"receipt_number": "RCPT-2026-0033",
"payment_date": "2026-07-18",
"description": "Payment for INV-2026-0042",
"received_amount": 9025,
"status": "used",
"attachments": [],
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
}
}
}
/product/sales/orders
permission: sales_order-read
List sales orders. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Sales Orders retrieved successfully",
"data": {
"orders": [
{
"id": 9,
"order_date": "2026-07-18",
"order_number": "SO-2026-0009",
"due_date": "2026-07-28",
"payment_type": "cash",
"reference_no": "PO-BN-118",
"advance_amount": 0,
"balance_due": 9025,
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"paid_amount": 0,
"balance_amount": 9025,
"net_amount": 9025,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/sales/orders
permission: sales_order-create
Create a new sales order.
Request Body
{
"party_id": 15,
"reference_no": "PO-BN-118",
"order_date": "2026-07-18",
"due_date": "2026-07-28",
"payment_type": "cash",
"advance_amount": 0,
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"balance_due": 9025,
"lines": [
{
"item_id": 101,
"quantity": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 475,
"sub_total": 9500,
"tax_total": 0,
"total_amount": 9025,
"uom_id": 3,
"warehouse_id": 1
}
]
}
Response 201
{
"success": true,
"message": "Sales Order created successfully",
"data": {
"id": 9,
"order_date": "2026-07-18",
"order_number": "SO-2026-0009",
"due_date": "2026-07-28",
"payment_type": "cash",
"reference_no": "PO-BN-118",
"advance_amount": 0,
"balance_due": 9025,
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"paid_amount": 0,
"balance_amount": 9025,
"net_amount": 9025,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/orders/{sales_order}
permission: sales_order-read
Get a single sales order by id.
Response 200
{
"success": true,
"message": "Sales Order retrieved successfully",
"data": {
"id": 9,
"order_date": "2026-07-18",
"order_number": "SO-2026-0009",
"due_date": "2026-07-28",
"payment_type": "cash",
"reference_no": "PO-BN-118",
"advance_amount": 0,
"balance_due": 9025,
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"paid_amount": 0,
"balance_amount": 9025,
"net_amount": 9025,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/orders/{sales_order}
permission: sales_order-update
Update an existing sales order.
Request Body
{
"party_id": 15,
"reference_no": "PO-BN-118",
"order_date": "2026-07-18",
"due_date": "2026-07-28",
"payment_type": "cash",
"advance_amount": 0,
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"balance_due": 9025,
"lines": [
{
"item_id": 101,
"quantity": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 475,
"sub_total": 9500,
"tax_total": 0,
"total_amount": 9025,
"uom_id": 3,
"warehouse_id": 1
}
]
}
Response 200
{
"success": true,
"message": "Sales Order updated successfully",
"data": {
"id": 9,
"order_date": "2026-07-18",
"order_number": "SO-2026-0009",
"due_date": "2026-07-28",
"payment_type": "cash",
"reference_no": "PO-BN-118",
"advance_amount": 0,
"balance_due": 9025,
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"paid_amount": 0,
"balance_amount": 9025,
"net_amount": 9025,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/orders/{sales_order}
permission: sales_order-delete
Soft-delete a sales order (recoverable via restore).
Response 200
{
"success": true,
"message": "Sales Order deleted successfully",
"data": null
}
/product/sales/orders/bulk-convert-to-invoice
permission: sales_invoice-create
Bulk-convert multiple selected sales orders into invoices in one call.
Request Body
{
"order_ids": [
9,
10,
11
]
}
Response 200
{
"success": true,
"message": "Orders converted successfully",
"data": null
}
/product/sales/orders/{sales_order}/convert-to-invoice
permission: sales_invoice-create
Convert this sales order into a sales invoice.
Response 201
{
"success": true,
"message": "Converted to invoice successfully",
"data": {
"id": 44,
"is_credit": true,
"invoice_no": "INV-2026-0042",
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"status": "unpaid",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"grand_total_in_words": "Nine Thousand Twenty Five Birr",
"paid_amount": 0,
"balance_amount": 9025,
"notes": "Delivered to site",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/proformas
permission: sales_proforma-read
List sales proformas. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Sales Proformas retrieved successfully",
"data": {
"proformas": [
{
"id": 6,
"invoice_number": "PF-2026-0006",
"invoice_date": "2026-07-18",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"validity_days": 30,
"validity_expiry_date": "2026-08-17",
"validity_status": "valid",
"is_valid": true,
"days_remaining": 25,
"is_converted": false,
"can_convert": true,
"net_amount": 9025,
"payment_status": "unpaid",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/sales/proformas
permission: sales_proforma-create
Create a new sales proforma.
Request Body
{
"party_id": 15,
"invoice_date": "2026-07-18",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"validity_days": 30,
"lines": [
{
"item_id": 101,
"quantity": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 475,
"sub_total": 9500,
"tax_total": 0,
"total_amount": 9025,
"uom_id": 3,
"warehouse_id": 1
}
]
}
Response 201
{
"success": true,
"message": "Sales Proforma created successfully",
"data": {
"id": 6,
"invoice_number": "PF-2026-0006",
"invoice_date": "2026-07-18",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"validity_days": 30,
"validity_expiry_date": "2026-08-17",
"validity_status": "valid",
"is_valid": true,
"days_remaining": 25,
"is_converted": false,
"can_convert": true,
"net_amount": 9025,
"payment_status": "unpaid",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/proformas/{salesProforma}
permission: sales_proforma-read
Get a single sales proforma by id.
Response 200
{
"success": true,
"message": "Sales Proforma retrieved successfully",
"data": {
"id": 6,
"invoice_number": "PF-2026-0006",
"invoice_date": "2026-07-18",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"validity_days": 30,
"validity_expiry_date": "2026-08-17",
"validity_status": "valid",
"is_valid": true,
"days_remaining": 25,
"is_converted": false,
"can_convert": true,
"net_amount": 9025,
"payment_status": "unpaid",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/proformas/{salesProforma}
permission: sales_proforma-update
Update an existing sales proforma.
Request Body
{
"party_id": 15,
"invoice_date": "2026-07-18",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"validity_days": 30,
"lines": [
{
"item_id": 101,
"quantity": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 475,
"sub_total": 9500,
"tax_total": 0,
"total_amount": 9025,
"uom_id": 3,
"warehouse_id": 1
}
]
}
Response 200
{
"success": true,
"message": "Sales Proforma updated successfully",
"data": {
"id": 6,
"invoice_number": "PF-2026-0006",
"invoice_date": "2026-07-18",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"validity_days": 30,
"validity_expiry_date": "2026-08-17",
"validity_status": "valid",
"is_valid": true,
"days_remaining": 25,
"is_converted": false,
"can_convert": true,
"net_amount": 9025,
"payment_status": "unpaid",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/proformas/{salesProforma}
permission: sales_proforma-delete
Soft-delete a sales proforma (recoverable via restore).
Response 200
{
"success": true,
"message": "Sales Proforma deleted successfully",
"data": null
}
/product/sales/proformas/{salesProforma}/convert-to-sales
permission: sales_invoice-create
Convert this proforma into a sales invoice.
Response 201
{
"success": true,
"message": "Converted to invoice successfully",
"data": {
"id": 44,
"is_credit": true,
"invoice_no": "INV-2026-0042",
"invoice_date": "2026-07-18",
"due_date": "2026-08-17",
"invoice_type": "standard",
"status": "unpaid",
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 9025,
"grand_total_in_words": "Nine Thousand Twenty Five Birr",
"paid_amount": 0,
"balance_amount": 9025,
"notes": "Delivered to site",
"reference_no": "PO-BN-118",
"currency": "ETB",
"payment_type": "cash",
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
/product/sales/proformas/{salesProforma}/convert-to-sales-order
permission: sales_order-create
Convert this proforma into a sales order.
Response 201
{
"success": true,
"message": "Converted to order successfully",
"data": {
"id": 9,
"order_date": "2026-07-18",
"order_number": "SO-2026-0009",
"due_date": "2026-07-28",
"payment_type": "cash",
"reference_no": "PO-BN-118",
"advance_amount": 0,
"balance_due": 9025,
"sub_total": 9500,
"discount_total": 475,
"tax_total": 0,
"round_off": 0,
"grand_total": 9025,
"paid_amount": 0,
"balance_amount": 9025,
"net_amount": 9025,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"qty": 10,
"rate": 950,
"discount_type": "percentage",
"discount_value": 5,
"line_discount_total": 475,
"line_sub_total": 9025,
"tax_total": 0,
"line_total": 9025,
"batch_no": "BATCH-2026-001",
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
]
}
}
Sales Returns
/product/sales-returns
permission: sales_return-read
List sales returns. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Sales Returns retrieved successfully",
"data": {
"returns": [
{
"id": 3,
"is_credit": true,
"return_no": "SR-2026-0003",
"return_date": "2026-07-18",
"invoice_date": "2026-07-10",
"invoice_no": "INV-2026-0038",
"sub_total": 950,
"discount_total": 0,
"tax_total": 0,
"grand_total": 950,
"paid_amount": 950,
"balance_amount": 0,
"payment_type": "cash",
"reason": "damaged goods",
"total_refund": 950,
"status": "confirmed",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 1,
"unit": "kg",
"price_per_unit": 950,
"amount": 950,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/sales-returns
permission: sales_return-create
Create a new sales return.
Request Body
{
"party_id": 15,
"paid_amount": 950,
"reference_invoice_id": 38,
"return_date": "2026-07-18",
"invoice_date": "2026-07-10",
"invoice_no": "INV-2026-0038",
"payment_type": "cash",
"sub_total": 950,
"discount_total": 0,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 950,
"balance_amount": 0,
"reason": "damaged goods",
"total_refund": 950,
"lines": [
{
"item_id": 101,
"warehouse_id": 1,
"batch_no": "BATCH-2026-001",
"quantity": 1,
"unit": "kg",
"price_per_unit": 950,
"amount": 950
}
]
}
Response 201
{
"success": true,
"message": "Sales Return created successfully",
"data": {
"id": 3,
"is_credit": true,
"return_no": "SR-2026-0003",
"return_date": "2026-07-18",
"invoice_date": "2026-07-10",
"invoice_no": "INV-2026-0038",
"sub_total": 950,
"discount_total": 0,
"tax_total": 0,
"grand_total": 950,
"paid_amount": 950,
"balance_amount": 0,
"payment_type": "cash",
"reason": "damaged goods",
"total_refund": 950,
"status": "confirmed",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 1,
"unit": "kg",
"price_per_unit": 950,
"amount": 950,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/sales-returns/{sales_return}
permission: sales_return-read
Get a single sales return by id.
Response 200
{
"success": true,
"message": "Sales Return retrieved successfully",
"data": {
"id": 3,
"is_credit": true,
"return_no": "SR-2026-0003",
"return_date": "2026-07-18",
"invoice_date": "2026-07-10",
"invoice_no": "INV-2026-0038",
"sub_total": 950,
"discount_total": 0,
"tax_total": 0,
"grand_total": 950,
"paid_amount": 950,
"balance_amount": 0,
"payment_type": "cash",
"reason": "damaged goods",
"total_refund": 950,
"status": "confirmed",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 1,
"unit": "kg",
"price_per_unit": 950,
"amount": 950,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/sales-returns/{sales_return}
permission: sales_return-update
Update an existing sales return.
Request Body
{
"party_id": 15,
"paid_amount": 950,
"reference_invoice_id": 38,
"return_date": "2026-07-18",
"invoice_date": "2026-07-10",
"invoice_no": "INV-2026-0038",
"payment_type": "cash",
"sub_total": 950,
"discount_total": 0,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 950,
"balance_amount": 0,
"reason": "damaged goods",
"total_refund": 950,
"lines": [
{
"item_id": 101,
"warehouse_id": 1,
"batch_no": "BATCH-2026-001",
"quantity": 1,
"unit": "kg",
"price_per_unit": 950,
"amount": 950
}
]
}
Response 200
{
"success": true,
"message": "Sales Return updated successfully",
"data": {
"id": 3,
"is_credit": true,
"return_no": "SR-2026-0003",
"return_date": "2026-07-18",
"invoice_date": "2026-07-10",
"invoice_no": "INV-2026-0038",
"sub_total": 950,
"discount_total": 0,
"tax_total": 0,
"grand_total": 950,
"paid_amount": 950,
"balance_amount": 0,
"payment_type": "cash",
"reason": "damaged goods",
"total_refund": 950,
"status": "confirmed",
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 1,
"unit": "kg",
"price_per_unit": 950,
"amount": 950,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/sales-returns/{sales_return}
permission: sales_return-delete
Soft-delete a sales return (recoverable via restore).
Response 200
{
"success": true,
"message": "Sales Return deleted successfully",
"data": null
}
Purchases
Purchase Bills, Purchase Orders (with GRNs) and Purchase Returns. Prefix /product/purchases, /product/purchase-orders, /product/purchase-returns.
Purchase Bills — full reference
/product/purchases
permission: purchase_invoice-read
List purchase invoices. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Purchase Invoices retrieved successfully",
"data": {
"purchases": [
{
"id": 91,
"is_credit": true,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"cheque_reference_no": "CHQ-000123",
"discount": 0,
"tax": 0,
"total": 78000,
"paid_amount": 0,
"payable_amount": 78000,
"status": "confirmed",
"balance_amount": 78000,
"grand_total": 78000,
"description": "Monthly cement restock",
"created_at": "2026-07-18 10:30:00",
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC",
"phone": "0922334455"
}
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/purchases
permission: purchase_invoice-create
Create a new purchase invoice.
Request Body
{
"is_credit": true,
"advance": false,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"tax": 0,
"total": 78000,
"paid_amount": 0,
"description": "Monthly cement restock",
"lines": [
{
"item_id": 101,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"batch_no": "BATCH-2026-001",
"warehouse_id": 1
}
]
}
Response 201
{
"success": true,
"message": "Purchase Invoice created successfully",
"data": {
"id": 91,
"is_credit": true,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"cheque_reference_no": "CHQ-000123",
"discount": 0,
"tax": 0,
"total": 78000,
"paid_amount": 0,
"payable_amount": 78000,
"status": "confirmed",
"balance_amount": 78000,
"grand_total": 78000,
"description": "Monthly cement restock",
"created_at": "2026-07-18 10:30:00",
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC",
"phone": "0922334455"
}
}
}
/product/purchases/{purchase}
permission: purchase_invoice-read
Get a single purchase invoice by id.
Response 200
{
"success": true,
"message": "Purchase Invoice retrieved successfully",
"data": {
"id": 91,
"is_credit": true,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"cheque_reference_no": "CHQ-000123",
"discount": 0,
"tax": 0,
"total": 78000,
"paid_amount": 0,
"payable_amount": 78000,
"status": "confirmed",
"balance_amount": 78000,
"grand_total": 78000,
"description": "Monthly cement restock",
"created_at": "2026-07-18 10:30:00",
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC",
"phone": "0922334455"
}
}
}
/product/purchases/{purchase}
permission: purchase_invoice-update
Update an existing purchase invoice.
Request Body
{
"is_credit": true,
"advance": false,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"tax": 0,
"total": 78000,
"paid_amount": 0,
"description": "Monthly cement restock",
"lines": [
{
"item_id": 101,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"batch_no": "BATCH-2026-001",
"warehouse_id": 1
}
]
}
Response 200
{
"success": true,
"message": "Purchase Invoice updated successfully",
"data": {
"id": 91,
"is_credit": true,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"cheque_reference_no": "CHQ-000123",
"discount": 0,
"tax": 0,
"total": 78000,
"paid_amount": 0,
"payable_amount": 78000,
"status": "confirmed",
"balance_amount": 78000,
"grand_total": 78000,
"description": "Monthly cement restock",
"created_at": "2026-07-18 10:30:00",
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC",
"phone": "0922334455"
}
}
}
/product/purchases/{purchase}
permission: purchase_invoice-delete
Soft-delete a purchase invoice (recoverable via restore).
Response 200
{
"success": true,
"message": "Purchase Invoice deleted successfully",
"data": null
}
/product/purchases/auto-match-invoice
permission: purchase_invoice-read
Attempt to auto-match an uploaded bill against an existing purchase order by number/amount.
Request Body
{
"bill_no": "BILL-2026-0011",
"total": 78000
}
Response 200
{
"success": true,
"message": "Match found",
"data": {
"purchase_order_id": 17
}
}
/product/purchases/by-number/{bill_no}
permission: purchase_invoice-read
Look up a purchase bill by its bill number.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"id": 91,
"is_credit": true,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"cheque_reference_no": "CHQ-000123",
"discount": 0,
"tax": 0,
"total": 78000,
"paid_amount": 0,
"payable_amount": 78000,
"status": "confirmed",
"balance_amount": 78000,
"grand_total": 78000,
"description": "Monthly cement restock",
"created_at": "2026-07-18 10:30:00",
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC",
"phone": "0922334455"
}
}
}
/product/purchases/create-return
permission: purchase_return-create
Create a return against an existing purchase bill.
Request Body
{
"purchase_invoice_id": 91,
"lines": [
{
"item_id": 101,
"quantity": 10
}
]
}
Response 201
{
"success": true,
"message": "Return created successfully",
"data": {
"id": 5,
"is_credit": true,
"purchase_invoice_id": 91,
"return_no": "PR-2026-0005",
"return_date": "2026-07-18",
"bill_date": "2026-07-18",
"bill_no": "BILL-2026-0011",
"sub_total": 7800,
"grand_total": 7800,
"received_amount": 7800,
"balance_amount": 0,
"payment_type": "cheque",
"reason": "wrong item delivered",
"total_refund": 7800,
"status": "confirmed",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 10,
"unit": "kg",
"price_per_unit": 780,
"amount": 7800,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/purchases/returns/{return}
permission: purchase_return-read
Get a single purchase return by id.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"id": 5,
"is_credit": true,
"purchase_invoice_id": 91,
"return_no": "PR-2026-0005",
"return_date": "2026-07-18",
"bill_date": "2026-07-18",
"bill_no": "BILL-2026-0011",
"sub_total": 7800,
"grand_total": 7800,
"received_amount": 7800,
"balance_amount": 0,
"payment_type": "cheque",
"reason": "wrong item delivered",
"total_refund": 7800,
"status": "confirmed",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 10,
"unit": "kg",
"price_per_unit": 780,
"amount": 7800,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/purchases/returns/{return}/confirm
permission: purchase_return-update
Confirm/finalize this purchase return — locks it and applies stock & ledger effects.
Response 200
{
"success": true,
"message": "Return confirmed successfully",
"data": {
"id": 5,
"is_credit": true,
"purchase_invoice_id": 91,
"return_no": "PR-2026-0005",
"return_date": "2026-07-18",
"bill_date": "2026-07-18",
"bill_no": "BILL-2026-0011",
"sub_total": 7800,
"grand_total": 7800,
"received_amount": 7800,
"balance_amount": 0,
"payment_type": "cheque",
"reason": "wrong item delivered",
"total_refund": 7800,
"status": "confirmed",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 10,
"unit": "kg",
"price_per_unit": 780,
"amount": 7800,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/purchases/revert-return/{returnId}
permission: purchase_return-update
Revert a previously confirmed purchase return, restoring the original bill balance.
Response 200
{
"success": true,
"message": "Return reverted successfully",
"data": null
}
/product/purchases/search-by-number
permission: purchase_invoice-read
Search purchase bills by number (query param q).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"purchases": [
{
"id": 91,
"is_credit": true,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"cheque_reference_no": "CHQ-000123",
"discount": 0,
"tax": 0,
"total": 78000,
"paid_amount": 0,
"payable_amount": 78000,
"status": "confirmed",
"balance_amount": 78000,
"grand_total": 78000,
"description": "Monthly cement restock",
"created_at": "2026-07-18 10:30:00",
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC",
"phone": "0922334455"
}
}
]
}
}
/product/purchases/validate-credit-limit
permission: purchase_invoice-create
Check a proposed purchase against the supplier's credit limit before committing.
Request Body
{
"party_id": 22,
"amount": 78000
}
Response 200
{
"success": true,
"message": "Within credit limit",
"data": {
"within_limit": true,
"available_credit": 122000
}
}
/product/purchases/{billNo}/available-return-lines
permission: purchase_return-read
Line items on this bill still eligible to be returned.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"lines": [
{
"item_id": 101,
"returnable_quantity": 90
}
]
}
}
/product/purchases/{purchase}/attachments
permission: purchase_invoice-read
File attachments on this purchase bill.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"attachments": []
}
}
/product/purchases/{purchase}/attachments
permission: purchase_invoice-update
Upload a file attachment to this purchase bill (multipart/form-data).
Response 201
{
"success": true,
"message": "Attachment uploaded successfully",
"data": null
}
/product/purchases/{purchase}/confirm
permission: purchase_invoice-update
Confirm/finalize this purchase bill — locks it and applies stock & ledger effects.
Response 200
{
"success": true,
"message": "Purchase confirmed successfully",
"data": {
"id": 91,
"is_credit": true,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"cheque_reference_no": "CHQ-000123",
"discount": 0,
"tax": 0,
"total": 78000,
"paid_amount": 0,
"payable_amount": 78000,
"status": "confirmed",
"balance_amount": 78000,
"grand_total": 78000,
"description": "Monthly cement restock",
"created_at": "2026-07-18 10:30:00",
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC",
"phone": "0922334455"
}
}
}
/product/purchases/{purchase}/create-bill-from-po
permission: purchase_invoice-create
Generate a purchase bill from this approved purchase order.
Response 201
{
"success": true,
"message": "Bill created successfully",
"data": {
"id": 91,
"is_credit": true,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"cheque_reference_no": "CHQ-000123",
"discount": 0,
"tax": 0,
"total": 78000,
"paid_amount": 0,
"payable_amount": 78000,
"status": "confirmed",
"balance_amount": 78000,
"grand_total": 78000,
"description": "Monthly cement restock",
"created_at": "2026-07-18 10:30:00",
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC",
"phone": "0922334455"
}
}
}
/product/purchases/{purchase}/lines
permission: purchase_invoice-update
Add a line item to this purchase bill.
Request Body
{
"item_id": 101,
"quantity": 10,
"price_per_unit": 780,
"warehouse_id": 1
}
Response 201
{
"success": true,
"message": "Line added successfully",
"data": null
}
/product/purchases/{purchase}/lines/{line}
permission: purchase_invoice-update
Update a line item on this purchase bill.
Request Body
{
"quantity": 12,
"price_per_unit": 780
}
Response 200
{
"success": true,
"message": "Line updated successfully",
"data": null
}
/product/purchases/{purchase}/lines/{line}
permission: purchase_invoice-update
Remove a line item from this purchase bill.
Response 200
{
"success": true,
"message": "Line removed successfully",
"data": null
}
/product/purchases/{purchase}/payments
permission: purchase_payment-create
Record a payment directly against this purchase bill.
Request Body
{
"amount": 78000,
"payment_type": "cheque"
}
Response 201
{
"success": true,
"message": "Payment recorded successfully",
"data": {
"id": 18,
"party_id": 22,
"payment_type": "cheque",
"receipt_number": "RCPT-OUT-2026-0018",
"payment_date": "2026-07-18",
"description": "Payment for BILL-2026-0011",
"paid_amount": 78000,
"status": "used",
"attachments": [],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
}
}
}
/product/purchases/{purchase}/payments
permission: purchase_payment-read
Payments recorded against this purchase bill.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"payments": [
{
"id": 18,
"party_id": 22,
"payment_type": "cheque",
"receipt_number": "RCPT-OUT-2026-0018",
"payment_date": "2026-07-18",
"description": "Payment for BILL-2026-0011",
"paid_amount": 78000,
"status": "used",
"attachments": [],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
}
}
]
}
}
Purchase Orders
/product/purchase-orders
permission: purchase_order-read
List purchase orders. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Purchase Orders retrieved successfully",
"data": {
"orders": [
{
"id": 17,
"party_id": 22,
"phone_no": "0911909090",
"po_no": "PO-2026-0007",
"po_date": "2026-07-18",
"status": "issued",
"is_converted": false,
"discount": 0,
"tax": 0,
"total": 78000,
"advance_amount": 0,
"payable_amount": 78000,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"grns": []
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/purchase-orders
permission: purchase_order-create
Create a new purchase order.
Request Body
{
"party_id": 22,
"phone_no": "0911909090",
"po_no": "PO-2026-0007",
"payment_type": "cheque",
"po_date": "2026-07-18",
"tax": 0,
"total": 78000,
"advance_amount": 0,
"lines": [
{
"item_id": 101,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"warehouse_id": 1,
"amount": 78000
}
]
}
Response 201
{
"success": true,
"message": "Purchase Order created successfully",
"data": {
"id": 17,
"party_id": 22,
"phone_no": "0911909090",
"po_no": "PO-2026-0007",
"po_date": "2026-07-18",
"status": "issued",
"is_converted": false,
"discount": 0,
"tax": 0,
"total": 78000,
"advance_amount": 0,
"payable_amount": 78000,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"grns": []
}
}
/product/purchase-orders/{purchaseOrder}
permission: purchase_order-read
Get a single purchase order by id.
Response 200
{
"success": true,
"message": "Purchase Order retrieved successfully",
"data": {
"id": 17,
"party_id": 22,
"phone_no": "0911909090",
"po_no": "PO-2026-0007",
"po_date": "2026-07-18",
"status": "issued",
"is_converted": false,
"discount": 0,
"tax": 0,
"total": 78000,
"advance_amount": 0,
"payable_amount": 78000,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"grns": []
}
}
/product/purchase-orders/{purchaseOrder}
permission: purchase_order-update
Update an existing purchase order.
Request Body
{
"party_id": 22,
"phone_no": "0911909090",
"po_no": "PO-2026-0007",
"payment_type": "cheque",
"po_date": "2026-07-18",
"tax": 0,
"total": 78000,
"advance_amount": 0,
"lines": [
{
"item_id": 101,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"warehouse_id": 1,
"amount": 78000
}
]
}
Response 200
{
"success": true,
"message": "Purchase Order updated successfully",
"data": {
"id": 17,
"party_id": 22,
"phone_no": "0911909090",
"po_no": "PO-2026-0007",
"po_date": "2026-07-18",
"status": "issued",
"is_converted": false,
"discount": 0,
"tax": 0,
"total": 78000,
"advance_amount": 0,
"payable_amount": 78000,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"grns": []
}
}
/product/purchase-orders/{purchaseOrder}
permission: purchase_order-delete
Soft-delete a purchase order (recoverable via restore).
Response 200
{
"success": true,
"message": "Purchase Order deleted successfully",
"data": null
}
/product/purchase-orders/{purchaseOrder}/convert-to-invoice
permission: purchase_invoice-create
Convert this purchase order into a purchase bill.
Response 201
{
"success": true,
"message": "Converted to invoice successfully",
"data": {
"id": 91,
"is_credit": true,
"party_id": 22,
"phone_no": "0911909090",
"bill_no": "BILL-2026-0011",
"bill_date": "2026-07-18",
"payment_type": "cheque",
"cheque_reference_no": "CHQ-000123",
"discount": 0,
"tax": 0,
"total": 78000,
"paid_amount": 0,
"payable_amount": 78000,
"status": "confirmed",
"balance_amount": 78000,
"grand_total": 78000,
"description": "Monthly cement restock",
"created_at": "2026-07-18 10:30:00",
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC",
"phone": "0922334455"
}
}
}
/product/purchase-orders/{purchaseOrder}/grns
permission: purchase_grn-read
List goods received notes. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Goods Received Notes retrieved successfully",
"data": {
"grns": [
{
"id": 4,
"purchase_order_id": 17,
"grn_no": "GRN-2026-0004",
"grn_date": "2026-07-18",
"status": "received",
"remarks": "Full delivery received in good condition",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/purchase-orders/{purchaseOrder}/grns
permission: purchase_grn-create
Create a new goods received note.
Request Body
{
"grn_no": "GRN-2026-0004",
"grn_date": "2026-07-18",
"remarks": "Full delivery received in good condition"
}
Response 201
{
"success": true,
"message": "Goods Received Note created successfully",
"data": {
"id": 4,
"purchase_order_id": 17,
"grn_no": "GRN-2026-0004",
"grn_date": "2026-07-18",
"status": "received",
"remarks": "Full delivery received in good condition",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/purchase-orders/{purchaseOrder}/issue
permission: purchase_order-update
Issue this purchase order to the supplier — locks it for editing.
Response 200
{
"success": true,
"message": "Order issued successfully",
"data": {
"id": 17,
"party_id": 22,
"phone_no": "0911909090",
"po_no": "PO-2026-0007",
"po_date": "2026-07-18",
"status": "issued",
"is_converted": false,
"discount": 0,
"tax": 0,
"total": 78000,
"advance_amount": 0,
"payable_amount": 78000,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"quantity": 100,
"unit": "kg",
"price_per_unit": 780,
"amount": 78000,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
},
"batch_no": "BATCH-2026-001",
"uom": {
"id": 3,
"name": "Kilogram",
"short_code": "kg"
},
"warehouse": {
"id": 1,
"name": "Addis Ababa Main Warehouse",
"code": "WH-AA-01"
}
}
],
"grns": []
}
}
/product/purchase-orders/{purchaseOrder}/lines
permission: purchase_order-update
Add a line item to this purchase order.
Request Body
{
"item_id": 101,
"quantity": 100,
"price_per_unit": 780,
"warehouse_id": 1
}
Response 201
{
"success": true,
"message": "Line added successfully",
"data": null
}
/product/purchase-orders/{purchaseOrder}/lines/{poLine}
permission: purchase_order-update
Update a line item on this purchase order.
Request Body
{
"quantity": 120
}
Response 200
{
"success": true,
"message": "Line updated successfully",
"data": null
}
/product/purchase-orders/{purchaseOrder}/lines/{poLine}
permission: purchase_order-update
Remove a line item from this purchase order.
Response 200
{
"success": true,
"message": "Line removed successfully",
"data": null
}
Purchase Returns
/product/purchase-returns
permission: purchase_return-read
List purchase returns. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Purchase Returns retrieved successfully",
"data": {
"returns": [
{
"id": 5,
"is_credit": true,
"purchase_invoice_id": 91,
"return_no": "PR-2026-0005",
"return_date": "2026-07-18",
"bill_date": "2026-07-18",
"bill_no": "BILL-2026-0011",
"sub_total": 7800,
"grand_total": 7800,
"received_amount": 7800,
"balance_amount": 0,
"payment_type": "cheque",
"reason": "wrong item delivered",
"total_refund": 7800,
"status": "confirmed",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 10,
"unit": "kg",
"price_per_unit": 780,
"amount": 7800,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/purchase-returns
permission: purchase_return-create
Create a new purchase return.
Request Body
{
"party_id": 22,
"received_amount": 7800,
"purchase_invoice_id": 91,
"return_date": "2026-07-18",
"bill_date": "2026-07-18",
"bill_no": "BILL-2026-0011",
"payment_type": "cheque",
"sub_total": 7800,
"discount_total": 0,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 7800,
"balance_amount": 0,
"reason": "wrong item delivered",
"total_refund": 7800,
"lines": [
{
"item_id": 101,
"warehouse_id": 1,
"batch_no": "BATCH-2026-001",
"quantity": 10,
"unit": "kg",
"price_per_unit": 780,
"amount": 7800
}
]
}
Response 201
{
"success": true,
"message": "Purchase Return created successfully",
"data": {
"id": 5,
"is_credit": true,
"purchase_invoice_id": 91,
"return_no": "PR-2026-0005",
"return_date": "2026-07-18",
"bill_date": "2026-07-18",
"bill_no": "BILL-2026-0011",
"sub_total": 7800,
"grand_total": 7800,
"received_amount": 7800,
"balance_amount": 0,
"payment_type": "cheque",
"reason": "wrong item delivered",
"total_refund": 7800,
"status": "confirmed",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 10,
"unit": "kg",
"price_per_unit": 780,
"amount": 7800,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/purchase-returns/{purchase_return}
permission: purchase_return-read
Get a single purchase return by id.
Response 200
{
"success": true,
"message": "Purchase Return retrieved successfully",
"data": {
"id": 5,
"is_credit": true,
"purchase_invoice_id": 91,
"return_no": "PR-2026-0005",
"return_date": "2026-07-18",
"bill_date": "2026-07-18",
"bill_no": "BILL-2026-0011",
"sub_total": 7800,
"grand_total": 7800,
"received_amount": 7800,
"balance_amount": 0,
"payment_type": "cheque",
"reason": "wrong item delivered",
"total_refund": 7800,
"status": "confirmed",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 10,
"unit": "kg",
"price_per_unit": 780,
"amount": 7800,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/purchase-returns/{purchase_return}
permission: purchase_return-update
Update an existing purchase return.
Request Body
{
"party_id": 22,
"received_amount": 7800,
"purchase_invoice_id": 91,
"return_date": "2026-07-18",
"bill_date": "2026-07-18",
"bill_no": "BILL-2026-0011",
"payment_type": "cheque",
"sub_total": 7800,
"discount_total": 0,
"tax_total": 0,
"shipping_total": 0,
"round_off": 0,
"grand_total": 7800,
"balance_amount": 0,
"reason": "wrong item delivered",
"total_refund": 7800,
"lines": [
{
"item_id": 101,
"warehouse_id": 1,
"batch_no": "BATCH-2026-001",
"quantity": 10,
"unit": "kg",
"price_per_unit": 780,
"amount": 7800
}
]
}
Response 200
{
"success": true,
"message": "Purchase Return updated successfully",
"data": {
"id": 5,
"is_credit": true,
"purchase_invoice_id": 91,
"return_no": "PR-2026-0005",
"return_date": "2026-07-18",
"bill_date": "2026-07-18",
"bill_no": "BILL-2026-0011",
"sub_total": 7800,
"grand_total": 7800,
"received_amount": 7800,
"balance_amount": 0,
"payment_type": "cheque",
"reason": "wrong item delivered",
"total_refund": 7800,
"status": "confirmed",
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
},
"lines": [
{
"id": 1,
"item_id": 101,
"quantity": 10,
"unit": "kg",
"price_per_unit": 780,
"amount": 7800,
"item": {
"id": 101,
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001"
}
}
]
}
}
/product/purchase-returns/{purchase_return}
permission: purchase_return-delete
Soft-delete a purchase return (recoverable via restore).
Response 200
{
"success": true,
"message": "Purchase Return deleted successfully",
"data": null
}
Payments & Transactions
Recording money received against sales (Payment-In) and paid against purchases (Payment-Out), plus the unified ledger view.
Payment In — /product/payment-ins
/product/payment-ins
permission: payment_in-read
List payment ins. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Payment Ins retrieved successfully",
"data": {
"payment_ins": [
{
"id": 33,
"party_id": 15,
"is_opening_balance": false,
"payment_type": "bank",
"bank_account_id": 2,
"receipt_number": "RCPT-2026-0033",
"payment_date": "2026-07-18",
"description": "Payment for INV-2026-0042",
"received_amount": 9025,
"status": "used",
"attachments": [],
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
}
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/payment-ins
permission: payment_in-create
Create a new payment in.
Request Body
{
"party_id": 15,
"payment_type": "bank",
"receipt_number": "RCPT-2026-0033",
"payment_date": "2026-07-18",
"bank_account_id": 2,
"description": "Payment for INV-2026-0042",
"received_amount": 9025,
"allocations": [
{
"invoiceable_type": "App\Modules\Product\Models\SalesInvoice",
"invoiceable_id": 44,
"amount": 9025,
"notes": "Full settlement"
}
]
}
Response 201
{
"success": true,
"message": "Payment In created successfully",
"data": {
"id": 33,
"party_id": 15,
"is_opening_balance": false,
"payment_type": "bank",
"bank_account_id": 2,
"receipt_number": "RCPT-2026-0033",
"payment_date": "2026-07-18",
"description": "Payment for INV-2026-0042",
"received_amount": 9025,
"status": "used",
"attachments": [],
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
}
}
}
/product/payment-ins/{paymentIn}
permission: payment_in-read
Get a single payment in by id.
Response 200
{
"success": true,
"message": "Payment In retrieved successfully",
"data": {
"id": 33,
"party_id": 15,
"is_opening_balance": false,
"payment_type": "bank",
"bank_account_id": 2,
"receipt_number": "RCPT-2026-0033",
"payment_date": "2026-07-18",
"description": "Payment for INV-2026-0042",
"received_amount": 9025,
"status": "used",
"attachments": [],
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
}
}
}
/product/payment-ins/{paymentIn}
permission: payment_in-update
Update an existing payment in.
Request Body
{
"party_id": 15,
"payment_type": "bank",
"receipt_number": "RCPT-2026-0033",
"payment_date": "2026-07-18",
"bank_account_id": 2,
"description": "Payment for INV-2026-0042",
"received_amount": 9025,
"allocations": [
{
"invoiceable_type": "App\Modules\Product\Models\SalesInvoice",
"invoiceable_id": 44,
"amount": 9025,
"notes": "Full settlement"
}
]
}
Response 200
{
"success": true,
"message": "Payment In updated successfully",
"data": {
"id": 33,
"party_id": 15,
"is_opening_balance": false,
"payment_type": "bank",
"bank_account_id": 2,
"receipt_number": "RCPT-2026-0033",
"payment_date": "2026-07-18",
"description": "Payment for INV-2026-0042",
"received_amount": 9025,
"status": "used",
"attachments": [],
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"phone": "0911909090",
"balance": 12500.75
}
}
}
/product/payment-ins/{paymentIn}
permission: payment_in-delete
Soft-delete a payment in (recoverable via restore).
Response 200
{
"success": true,
"message": "Payment In deleted successfully",
"data": null
}
Payment Out — /product/payment-outs
/product/payment-outs
permission: payment_out-read
List payment outs. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Payment Outs retrieved successfully",
"data": {
"payment_outs": [
{
"id": 18,
"party_id": 22,
"payment_type": "cheque",
"receipt_number": "RCPT-OUT-2026-0018",
"payment_date": "2026-07-18",
"description": "Payment for BILL-2026-0011",
"paid_amount": 78000,
"status": "used",
"attachments": [],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
}
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/payment-outs
permission: payment_out-create
Create a new payment out.
Request Body
{
"party_id": 22,
"payment_type": "cheque",
"receipt_number": "RCPT-OUT-2026-0018",
"payment_date": "2026-07-18",
"description": "Payment for BILL-2026-0011",
"paid_amount": 78000,
"allocations": [
{
"invoiceable_type": "App\Modules\Product\Models\PurchaseInvoice",
"invoiceable_id": 91,
"amount": 78000,
"notes": "Full settlement"
}
]
}
Response 201
{
"success": true,
"message": "Payment Out created successfully",
"data": {
"id": 18,
"party_id": 22,
"payment_type": "cheque",
"receipt_number": "RCPT-OUT-2026-0018",
"payment_date": "2026-07-18",
"description": "Payment for BILL-2026-0011",
"paid_amount": 78000,
"status": "used",
"attachments": [],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
}
}
}
/product/payment-outs/{payment_out}
permission: payment_out-read
Get a single payment out by id.
Response 200
{
"success": true,
"message": "Payment Out retrieved successfully",
"data": {
"id": 18,
"party_id": 22,
"payment_type": "cheque",
"receipt_number": "RCPT-OUT-2026-0018",
"payment_date": "2026-07-18",
"description": "Payment for BILL-2026-0011",
"paid_amount": 78000,
"status": "used",
"attachments": [],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
}
}
}
/product/payment-outs/{payment_out}
permission: payment_out-update
Update an existing payment out.
Request Body
{
"party_id": 22,
"payment_type": "cheque",
"receipt_number": "RCPT-OUT-2026-0018",
"payment_date": "2026-07-18",
"description": "Payment for BILL-2026-0011",
"paid_amount": 78000,
"allocations": [
{
"invoiceable_type": "App\Modules\Product\Models\PurchaseInvoice",
"invoiceable_id": 91,
"amount": 78000,
"notes": "Full settlement"
}
]
}
Response 200
{
"success": true,
"message": "Payment Out updated successfully",
"data": {
"id": 18,
"party_id": 22,
"payment_type": "cheque",
"receipt_number": "RCPT-OUT-2026-0018",
"payment_date": "2026-07-18",
"description": "Payment for BILL-2026-0011",
"paid_amount": 78000,
"status": "used",
"attachments": [],
"party": {
"id": 22,
"display_name": "Ethio Cement Suppliers PLC"
}
}
}
/product/payment-outs/{payment_out}
permission: payment_out-delete
Soft-delete a payment out (recoverable via restore).
Response 200
{
"success": true,
"message": "Payment Out deleted successfully",
"data": null
}
Transactions Ledger
/product/transactions
permission: report-read
Unified ledger — every money movement (sales, purchases, payments, adjustments) in one paginated feed.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"transactions": [
{
"id": 512,
"transaction_no": "TXN-2026-000452",
"transaction_date": "2026-07-18 10:30:00",
"amount": 9025,
"type": "sale",
"direction": "in",
"description": "Payment received for INV-2026-0042",
"reference_number": "RCPT-2026-0033",
"status": "completed",
"party_balance_before": 21525.75,
"party_balance_after": 12500.75,
"created_at": "2026-07-18 10:30:00",
"party": {
"id": 15,
"display_name": "Blue Nile Trading"
}
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 512,
"last_page": 35
}
}
Expenses & Other Income
Business expenses (with categories/items) and one-off other-income/expense entries outside the sales/purchase cycle.
Expenses — /product/expenses
/product/expenses
permission: expense-read
List expenses. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Expenses retrieved successfully",
"data": {
"expenses": [
{
"id": 27,
"expense_category_id": 4,
"expense_number": "EXP-2026-0019",
"payment_type": "cash",
"description": "Office electricity bill",
"total": 3200,
"paid_amount": 3200,
"subtotal": 3200,
"vat_amount": 0,
"created_at": "2026-07-18 10:30:00",
"category": {
"id": 4,
"name": "Utilities"
},
"items": [
{
"id": 1,
"expense_item_id": 8,
"quantity": 1,
"price_per_unit": 3200,
"amount": 3200,
"item": {
"id": 8,
"item": "Electricity"
}
}
]
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/expenses
permission: expense-create
Create a new expense.
Request Body
{
"expense_category_id": 4,
"expense_number": "EXP-2026-0019",
"payment_type": "cash",
"description": "Office electricity bill",
"total": 3200,
"paid_amount": 3200,
"subtotal": 3200,
"items": [
{
"expense_item_id": 8,
"quantity": 1,
"price_per_unit": 3200,
"amount": 3200
}
]
}
Response 201
{
"success": true,
"message": "Expense created successfully",
"data": {
"id": 27,
"expense_category_id": 4,
"expense_number": "EXP-2026-0019",
"payment_type": "cash",
"description": "Office electricity bill",
"total": 3200,
"paid_amount": 3200,
"subtotal": 3200,
"vat_amount": 0,
"created_at": "2026-07-18 10:30:00",
"category": {
"id": 4,
"name": "Utilities"
},
"items": [
{
"id": 1,
"expense_item_id": 8,
"quantity": 1,
"price_per_unit": 3200,
"amount": 3200,
"item": {
"id": 8,
"item": "Electricity"
}
}
]
}
}
/product/expenses/{expense}
permission: expense-read
Get a single expense by id.
Response 200
{
"success": true,
"message": "Expense retrieved successfully",
"data": {
"id": 27,
"expense_category_id": 4,
"expense_number": "EXP-2026-0019",
"payment_type": "cash",
"description": "Office electricity bill",
"total": 3200,
"paid_amount": 3200,
"subtotal": 3200,
"vat_amount": 0,
"created_at": "2026-07-18 10:30:00",
"category": {
"id": 4,
"name": "Utilities"
},
"items": [
{
"id": 1,
"expense_item_id": 8,
"quantity": 1,
"price_per_unit": 3200,
"amount": 3200,
"item": {
"id": 8,
"item": "Electricity"
}
}
]
}
}
/product/expenses/{expense}
permission: expense-update
Update an existing expense.
Request Body
{
"expense_category_id": 4,
"expense_number": "EXP-2026-0019",
"payment_type": "cash",
"description": "Office electricity bill",
"total": 3200,
"paid_amount": 3200,
"subtotal": 3200,
"items": [
{
"expense_item_id": 8,
"quantity": 1,
"price_per_unit": 3200,
"amount": 3200
}
]
}
Response 200
{
"success": true,
"message": "Expense updated successfully",
"data": {
"id": 27,
"expense_category_id": 4,
"expense_number": "EXP-2026-0019",
"payment_type": "cash",
"description": "Office electricity bill",
"total": 3200,
"paid_amount": 3200,
"subtotal": 3200,
"vat_amount": 0,
"created_at": "2026-07-18 10:30:00",
"category": {
"id": 4,
"name": "Utilities"
},
"items": [
{
"id": 1,
"expense_item_id": 8,
"quantity": 1,
"price_per_unit": 3200,
"amount": 3200,
"item": {
"id": 8,
"item": "Electricity"
}
}
]
}
}
/product/expenses/{expense}
permission: expense-delete
Soft-delete a expense (recoverable via restore).
Response 200
{
"success": true,
"message": "Expense deleted successfully",
"data": null
}
/product/expenses/{expense}/items
permission: expense-create
Create a new expense.
Request Body
{
"expense_category_id": 4,
"expense_number": "EXP-2026-0019",
"payment_type": "cash",
"description": "Office electricity bill",
"total": 3200,
"paid_amount": 3200,
"subtotal": 3200,
"items": [
{
"expense_item_id": 8,
"quantity": 1,
"price_per_unit": 3200,
"amount": 3200
}
]
}
Response 201
{
"success": true,
"message": "Expense created successfully",
"data": {
"id": 27,
"expense_category_id": 4,
"expense_number": "EXP-2026-0019",
"payment_type": "cash",
"description": "Office electricity bill",
"total": 3200,
"paid_amount": 3200,
"subtotal": 3200,
"vat_amount": 0,
"created_at": "2026-07-18 10:30:00",
"category": {
"id": 4,
"name": "Utilities"
},
"items": [
{
"id": 1,
"expense_item_id": 8,
"quantity": 1,
"price_per_unit": 3200,
"amount": 3200,
"item": {
"id": 8,
"item": "Electricity"
}
}
]
}
}
/product/expenses/payments
permission: expense_payment-create
Record a standalone expense payment (not tied to one specific expense).
Request Body
{
"expense_id": 27,
"amount": 3200,
"payment_mode": "cash"
}
Response 201
{
"success": true,
"message": "Payment recorded successfully",
"data": null
}
/product/expenses/payments/{expensePayment}
permission: expense_payment-read
Get a single expense payment by id.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"id": 1,
"expense_id": 27,
"amount": 3200
}
}
/product/expenses/payments/{payment}
permission: expense_payment-read
Get a single expense payment by id.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"id": 1,
"expense_id": 27,
"amount": 3200
}
}
/product/expenses/payments/{payment}/allocate
permission: expense_payment-update
Allocate this payment across one or more expenses.
Request Body
{
"allocations": [
{
"expense_id": 27,
"amount": 3200
}
]
}
Response 200
{
"success": true,
"message": "Allocated successfully",
"data": null
}
/product/expenses/{expense}/attachments
permission: expense-read
File attachments on this expense.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"attachments": []
}
}
/product/expenses/{expense}/attachments
permission: expense-update
Upload a file attachment to this expense (multipart/form-data).
Response 201
{
"success": true,
"message": "Attachment uploaded successfully",
"data": null
}
/product/expenses/{expense}/items
permission: expense_expense_item-create
Add a line item to this expense.
Request Body
{
"expense_item_id": 8,
"quantity": 1,
"price_per_unit": 3200
}
Response 201
{
"success": true,
"message": "Line added successfully",
"data": null
}
/product/expenses/{expense}/items/{item}
permission: expense_expense_item-update
Update a line item on this expense.
Request Body
{
"quantity": 2
}
Response 200
{
"success": true,
"message": "Line updated successfully",
"data": null
}
/product/expenses/{expense}/items/{item}
permission: expense_expense_item-delete
Remove a line item from this expense.
Response 200
{
"success": true,
"message": "Line removed successfully",
"data": null
}
/product/expenses/{expense}/payments
permission: expense_payment-create
Record a payment against this specific expense.
Request Body
{
"amount": 3200,
"payment_mode": "cash"
}
Response 201
{
"success": true,
"message": "Payment recorded successfully",
"data": null
}
/product/expenses/{expense}/payments
permission: expense_payment-read
Payments recorded against this expense.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"payments": []
}
}
Expense Categories & Items
/product/expense-categories
permission: expense_category-read
List expense categorys. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Expense Categorys retrieved successfully",
"data": {
"categories": [
{
"id": 4,
"name": "Utilities",
"description": "Electricity, water, internet",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/expense-categories
permission: expense_category-create
Create a new expense category.
Request Body
{
"name": "Utilities",
"description": "Electricity, water, internet"
}
Response 201
{
"success": true,
"message": "Expense Category created successfully",
"data": {
"id": 4,
"name": "Utilities",
"description": "Electricity, water, internet",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/expense-categories/{expense_category}
permission: expense_category-update
Update an existing expense category.
Request Body
{
"name": "Utilities",
"description": "Electricity, water, internet"
}
Response 200
{
"success": true,
"message": "Expense Category updated successfully",
"data": {
"id": 4,
"name": "Utilities",
"description": "Electricity, water, internet",
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/expense-categories/{expense_category}
permission: expense_category-delete
Soft-delete a expense category (recoverable via restore).
Response 200
{
"success": true,
"message": "Expense Category deleted successfully",
"data": null
}
/product/expense-items
permission: expense_item-read
List expense items. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Expense Items retrieved successfully",
"data": {
"items": [
{
"id": 8,
"item": "Electricity",
"price_per_unit": 3200,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/expense-items
permission: expense_item-create
Create a new expense item.
Request Body
{
"item": "Electricity",
"price_per_unit": 3200
}
Response 201
{
"success": true,
"message": "Expense Item created successfully",
"data": {
"id": 8,
"item": "Electricity",
"price_per_unit": 3200,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/expense-items/{expense_item}
permission: expense_item-read
Get a single expense item by id.
Response 200
{
"success": true,
"message": "Expense Item retrieved successfully",
"data": {
"id": 8,
"item": "Electricity",
"price_per_unit": 3200,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/expense-items/{expense_item}
permission: expense_item-update
Update an existing expense item.
Request Body
{
"item": "Electricity",
"price_per_unit": 3200
}
Response 200
{
"success": true,
"message": "Expense Item updated successfully",
"data": {
"id": 8,
"item": "Electricity",
"price_per_unit": 3200,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00"
}
}
/product/expense-items/{expense_item}
permission: expense_item-delete
Soft-delete a expense item (recoverable via restore).
Response 200
{
"success": true,
"message": "Expense Item deleted successfully",
"data": null
}
Other Income / Expense — /product/incomes-expenses
/product/incomes-expenses
permission: other_income_expense-read
List other income/expenses. Paginated; supports search, page, per_page query params.
Response 200
{
"success": true,
"message": "Other Income/Expenses retrieved successfully",
"data": {
"entries": [
{
"id": 12,
"type": "income",
"name": "Bank Interest Income",
"description": "Q2 interest on savings account",
"amount": 640,
"formatted_amount": "640.00",
"date": "2026-07-18",
"created_at": "2026-07-18 10:30:00"
}
]
},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42,
"last_page": 3
}
}
/product/incomes-expenses
permission: other_income_expense-create
Create a new other income/expense.
Request Body
{
"type": "income",
"name": "Bank Interest Income",
"description": "Q2 interest on savings account",
"amount": 640,
"date": "2026-07-18"
}
Response 201
{
"success": true,
"message": "Other Income/Expense created successfully",
"data": {
"id": 12,
"type": "income",
"name": "Bank Interest Income",
"description": "Q2 interest on savings account",
"amount": 640,
"formatted_amount": "640.00",
"date": "2026-07-18",
"created_at": "2026-07-18 10:30:00"
}
}
/product/incomes-expenses/{otherIncomeExpense}
permission: other_income_expense-read
Get a single other income/expense by id.
Response 200
{
"success": true,
"message": "Other Income/Expense retrieved successfully",
"data": {
"id": 12,
"type": "income",
"name": "Bank Interest Income",
"description": "Q2 interest on savings account",
"amount": 640,
"formatted_amount": "640.00",
"date": "2026-07-18",
"created_at": "2026-07-18 10:30:00"
}
}
/product/incomes-expenses/{otherIncomeExpense}
permission: other_income_expense-update
Update an existing other income/expense.
Request Body
{
"type": "income",
"name": "Bank Interest Income",
"description": "Q2 interest on savings account",
"amount": 640,
"date": "2026-07-18"
}
Response 200
{
"success": true,
"message": "Other Income/Expense updated successfully",
"data": {
"id": 12,
"type": "income",
"name": "Bank Interest Income",
"description": "Q2 interest on savings account",
"amount": 640,
"formatted_amount": "640.00",
"date": "2026-07-18",
"created_at": "2026-07-18 10:30:00"
}
}
/product/incomes-expenses/{otherIncomeExpense}
permission: other_income_expense-delete
Soft-delete a other income/expense (recoverable via restore).
Response 200
{
"success": true,
"message": "Other Income/Expense deleted successfully",
"data": null
}
/product/incomes-expenses/summary
permission: other_income_expense-read
Totals of other income vs. other expense for the period.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"total_income": 12400,
"total_expense": 3100
}
}
Cash, Bank & Cheques
/banking, 48 endpoints: bank accounts, bank/cash adjustments, bank transfers, cheques).
Reports
36 read-only reporting endpoints, all under /product/reports, gated by report-read.
/product/reports/bank/statement
permission: report-read
Bank account statement — every transaction posted to a bank account over a date range. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/bank/summary
permission: report-read
Bank balances summary across all bank accounts. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/cash-flow
permission: report-read
Cash-in vs cash-out over a date range. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/day-book
permission: report-read
Every transaction recorded on a given day, across all types. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/expense-aging
permission: report-read
Unpaid expenses grouped by how overdue they are. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/expense-ledger
permission: report-read
Full expense ledger, chronological. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/expenses
permission: report-read
Expense totals grouped by category over a date range. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/expenses-by-category
permission: report-read
Expense totals broken down by category. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/item-report-by-party
permission: report-read
Which items a specific party has bought/sold. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/item-wise-discount
permission: report-read
Discount given, broken down by item. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/item-wise-profit-loss
permission: report-read
Profit/loss per item (selling price vs. cost). Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/items-by-party
permission: report-read
Items associated with a given party's transaction history. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/low-stock-summary
permission: report-read
Items at or below their reorder level. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/low-stock-summary-optimized
permission: report-read
Performance-optimized variant of the low-stock summary for large catalogs. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/order-item-transaction
permission: report-read
Item-level detail for sales/purchase orders. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/order-transaction
permission: report-read
Order-level transaction summary. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/parties-with-financials
permission: report-read
Every party with their current balance and credit status. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/party-sales-report
permission: report-read
Read-only report endpoint. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/purchase-aging
permission: report-read
Unpaid purchase bills grouped by how overdue they are. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/purchase-by-item
permission: report-read
Purchase totals grouped by item. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/purchase-ledger
permission: report-read
Full purchase ledger, chronological. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/sale-purchase-by-category
permission: report-read
Sales vs. purchases, grouped by item category. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/sales-aging
permission: report-read
Unpaid sales invoices grouped by how overdue they are. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/sales-purchase-by-category
permission: report-read
Sales vs. purchases, grouped by item category. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/sales-purchase-discount
permission: report-read
Discount given across sales and purchases. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/stock-detail
permission: report-read
Detailed per-batch stock listing. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/stock-details
permission: report-read
Detailed per-batch stock listing. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/stock-summary
permission: report-read
Stock summary across all items and warehouses. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/stock-summary-by-category
permission: report-read
Stock summary grouped by item category. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/tax-rate-report
permission: report-read
Transactions grouped by applied tax rate. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/tax-report
permission: report-read
Tax collected/paid summary for the period. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/top-parties-by-sales
permission: report-read
Highest-value customers by total sales. Accepts optional filter query params (warehouse_id, item_category_id, search, date range).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// report-specific columns
],
"summary": {
"total": 184500
}
}
}
/product/reports/item-details/{item}
permission: report-read
Full detail report for a single item — stock, pricing, and transaction history.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"item": {
"id": 101,
"uuid": "b6e2c1a4-...",
"item_type": "goods",
"name": "Cement 50kg",
"sku_code": "CEM-50KG-001",
"barcode": "8901030875021",
"description": "OPC 42.5 grade cement bag",
"image": "https://.../item_images/cem.jpg",
"hsn_code": "2523",
"tin_applicable": true,
"selling_price": 950,
"purchase_price": 800,
"mrp_price": 1000,
"discount_type": "percentage",
"discount_value": 5,
"is_active": true,
"notes": "Bulk discount available",
"total_stock": 500,
"available_stock": 480,
"created_at": "2026-07-18 10:30:00",
"updated_at": "2026-07-18 10:30:00",
"category": {
"id": 3,
"name": "Building Materials",
"code": "BLD"
}
},
"movements": []
}
}
/product/reports/party-financials/{party}
permission: report-read
Full financial report for a single party — balance, aging, transaction history.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"tax_reg_type": "vat_registered",
"currency": "Birr",
"country_default": "Ethiopia",
"balance": 12500.75,
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "Jan 1, 2026",
"is_active": true,
"billing_address": "Bole, Addis Ababa",
"created_at": "Jul 18, 2026"
},
"aging": {}
}
}
/product/reports/party-sales-detail/{party}
permission: report-read
Detailed sales history for a single party.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"party": {
"id": 15,
"uuid": "9f2c1a3e-...",
"party_type": "customer",
"legal_name": "Blue Nile Trading PLC",
"display_name": "Blue Nile Trading",
"email": "info@bluenile.com",
"phone": "0911909090",
"tin_number": "0012345678",
"vat_no": "VAT-00981",
"tax_reg_type": "vat_registered",
"currency": "Birr",
"country_default": "Ethiopia",
"balance": 12500.75,
"opening_balance_amount": 5000,
"opening_balance_type": "debit",
"opening_date": "Jan 1, 2026",
"is_active": true,
"billing_address": "Bole, Addis Ababa",
"created_at": "Jul 18, 2026"
},
"sales": []
}
}
/product/reports/party-sales-report
permission: report-read
Sales totals grouped by party.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"rows": [
// per-party sales totals
]
}
}
/product/reports/stock/transfers
permission: report-read
Report of all stock transfers between warehouses over a date range.
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"transfers": []
}
}
Bulk Import
Spreadsheet-based bulk import for onboarding existing data. Each accepts a multipart/form-data file upload.
Not documented in this pass.
Settings
Per-item settings plus the tenant-wide general/transaction settings (Common/shared, prefix /settings — see Home page).
/product/items/{item}/settings
permission: item_setting-read
Get per-item settings (e.g. tax applicability, stock-maintenance flags).
Response 200
{
"success": true,
"message": "Retrieved successfully",
"data": {
"item_id": 101,
"tin_applicable": true,
"enable_stock_maintenance": true
}
}
/product/items/{item}/settings
permission: item_setting-create
Create per-item settings.
Request Body
{
"tin_applicable": true,
"enable_stock_maintenance": true
}
Response 201
{
"success": true,
"message": "Settings created successfully",
"data": null
}
/product/items/{item}/settings
permission: item_setting-update
Update per-item settings.
Request Body
{
"tin_applicable": false
}
Response 200
{
"success": true,
"message": "Settings updated successfully",
"data": null
}
/product/items/{item}/settings
permission: item_setting-delete
Soft-delete per-item settings, reverting to tenant defaults.
Response 200
{
"success": true,
"message": "Settings deleted successfully",
"data": null
}
Documentation coming soon
The Service module API (catalog, job orders, service invoices & purchases) is fully built and live — this reference page is being written next, once the Product docs are in developers' hands. This nav item stays active so the link is ready as soon as it ships.
Documentation coming soon
The Manufacturing module API (raw materials, BOM, production & sales orders, pricing) is fully built and live — this reference page is being written next. This nav item stays active so the link is ready as soon as it ships.