API Reference
Warka's custom backend is a set of whitelisted Python methods in the
cyber_zeb_erp app: 55 methods in cyber_zeb_erp/cyber_zeb_erp/api.py and 6 in
cyber_zeb_erp/cyber_zeb_erp/careers.py, 61 in total. Each is reachable at
/api/method/<dotted.path> and returns its result inside a {"message": ...}
envelope. This reference groups the endpoints by module, gives the HTTP method,
whether guests are allowed, the role guard enforced, the key parameters, and
what each returns. The role model itself is documented in
Security and RBAC; the doctypes behind these calls are in
Data Model.
Role guards
Every protected method calls a _require_* guard as its first line. Each guard
checks the caller's roles against a role set defined near the top of api.py:
| Guard | Role set | Members |
|---|---|---|
_require_login | (any authenticated user) | Any non-Guest session |
_require_hr | HR_ROLES | HR Manager, HR User, System Manager, Administrator |
_require_hr_manager | HR_MANAGER_ROLES | HR Manager, System Manager, Administrator |
_require_admin | ADMIN_ROLES | System Manager, Administrator |
_require_accounts | ACCOUNTS_ROLES | Accounts Manager, Accounts User, System Manager, Administrator |
_require_accounts_manager | ACCOUNTS_MANAGER_ROLES | Accounts Manager, System Manager, Administrator |
_require_selling | SELLING_ROLES | Sales Manager, Sales User, Sales Master Manager, System Manager, Administrator |
_require_buying | BUYING_ROLES | Purchase Manager, Purchase User, Stock Manager, System Manager, Administrator |
_require_stock | STOCK_ROLES | Stock Manager, Stock User, System Manager, Administrator |
_require_projects | PROJECT_ROLES | Projects Manager, Projects User, System Manager, Administrator |
The manager-tier guards (_require_hr_manager, _require_accounts_manager)
deliberately exclude the plain user role so that a single junior account cannot,
for example, approve its own leave, run payroll, or post a raw journal entry.
This is segregation of duties enforced in code.
How to call it
Every whitelisted method is called through the Next.js proxy at
/api/method/<method>, and the real return value is under the message key.
# GET (read), no body
curl "https://your-site.example.com/api/method/cyber_zeb_erp.api.get_finance_overview" \
-H "Cookie: sid=<session>"
# POST (write), JSON body
curl -X POST "https://your-site.example.com/api/method/cyber_zeb_erp.api.create_sales_invoice" \
-H "Content-Type: application/json" -H "Cookie: sid=<session>" \
-d '{"customer":"Acme Corporation","items":"[{\"item\":\"Consulting\",\"qty\":1,\"rate\":1000}]","tax_rate":15}'
Both return the same envelope shape:
{ "message": { "name": "SINV-0001", "grand_total": 1150.0, "submitted": true, "warnings": [] } }
From the frontend
Components never build these URLs by hand. frontend/lib/frappe.ts provides
frappeCall(method, body), which issues a GET when there is no body and a
POST with a JSON body otherwise, then returns data.message. The cyber
helper prefixes the app namespace so callers pass only the method name:
import { cyber } from "@/lib/frappe";
// GET
const overview = await cyber.call("get_finance_overview");
// POST, list parameters are JSON-encoded strings
const res = await cyber.call("create_sales_invoice", {
customer: "Acme Corporation",
items: JSON.stringify([{ item: "Consulting", qty: 1, rate: 1000 }]),
tax_rate: 15,
});
The same module exposes frappeList, frappeGet, frappeCreate,
frappeUpdate, and frappeDelete over ERPNext's REST resource API for plain
doctype access, and a FrappeError that carries the HTTP status so a 403 can
be rendered as an access-denied state.
List parameters (
items,users,roles) are accepted as a JSON string or a native list; the server parses them defensively and rejects malformed payloads with a clear error rather than a 500. Dates are validated and turn bad input into a friendly message. Many create endpoints auto-create missing masters (a Customer, Supplier, Lead, or service Item) so a form never dead-ends on a missing record.
Account and profile
All require an authenticated session; sign-up helpers are guest-accessible.
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
get_current_user_profile | GET | No | login | none | Email, name, mobile, roles, avatar data URL |
update_current_user_profile | POST | No | login | first_name, last_name, mobile_no, user_image | The refreshed profile |
update_current_user_avatar | POST | No | login | user_image or (filename, content_type, content_base64) | The refreshed profile |
change_current_user_password | POST | No | login | current_password, new_password | {status: "password_updated"} |
sign_up | POST | Yes | none (rate limited 5 / 15 min) | email, full_name, password | {email, full_name, roles} |
signup_enabled | GET | Yes | none | none | {enabled} |
Notes: avatars are validated so a user can only point their image at a file they
can read (_validate_own_avatar_url), and uploads are capped at 2 MB and must be
images. sign_up never grants an admin role and can be disabled entirely with
the disable_signup site-config flag; it returns a generic message whether the
email is taken or invalid so it cannot be used to enumerate accounts.
HR and Payroll
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
get_hr_overview | GET | No | _require_hr | none | Cached HR snapshot: headcount, leave, celebrations, distributions |
get_hr_meta | GET | No | _require_hr | none | Every HR dropdown source (departments, leave types, structures, and more) |
get_employee_360 | GET | No | _require_hr | employee | One employee's leave, attendance, payroll, appraisals, documents |
set_leave_status | POST | No | _require_hr_manager | name, status (Approved/Rejected) | Leave application name, status, docstatus |
allocate_leave | POST | No | _require_hr_manager | employee, leave_type, from_date, to_date, new_leaves_allocated, carry_forward | The submitted Leave Allocation |
mark_attendance | POST | No | _require_hr | employee, attendance_date, status, shift, working_hours | The submitted Attendance |
set_employee_status | POST | No | _require_hr_manager | employee, status (Active/Inactive/Suspended/Left) | {employee, status} |
employee_punch | POST | No | _require_hr | employee, log_type (IN/OUT, inferred if omitted) | The Employee Checkin |
assign_salary_structure | POST | No | _require_hr_manager | employee, salary_structure, from_date, base | The submitted assignment |
run_payroll | POST | No | _require_hr_manager | start_date, end_date, payroll_frequency, company | Payroll result, or a queued handle above 30 employees |
get_payroll_status | GET | No | _require_hr | payroll_entry | Progress: slips created, submitted, net pay, complete flag |
submit_payroll_slips | POST | No | _require_hr_manager | payroll_entry | Progress after submitting the draft slips |
set_expense_claim_status | POST | No | _require_hr_manager | name, status (Approved/Rejected) | Claim name, status, docstatus |
submit_doc | POST | No | _require_hr | doctype, name | {doctype, name, docstatus} |
get_lifecycle | GET | No | _require_hr | none | Onboarding/offboarding lists with progress plus templates |
get_boarding | GET | No | _require_hr | doctype, name | One lifecycle record's full checklist |
toggle_boarding_activity | POST | No | _require_hr | doctype, name, idx, completed | Updated progress |
start_onboarding | POST | No | _require_hr_manager | applicant_name, designation, department, date_of_joining, template, email | The new draft Employee Onboarding |
start_offboarding | POST | No | _require_hr_manager | employee, boarding_begins_on, template | The new draft Employee Separation |
finish_boarding | POST | No | _require_hr_manager | doctype, name, date_of_birth, gender | Created Employee (onboarding) or the departed employee + disabled login |
delete_boarding | POST | No | _require_hr_manager | doctype, name | {ok: true} |
Payroll: the two-phase pattern
run_payroll reuses HRMS Payroll Entry logic end to end. HRMS switches slip
creation and submission to background workers above 30 employees, so a
synchronous request would time out on any real company. The endpoint therefore
splits:
- Small runs (30 or fewer) return the finished result directly, with
queued: false, the slip counts, and total net pay. - Large runs return
{queued: true, payroll_entry, employees}. The client then pollsget_payroll_statusuntilcreation_complete, callssubmit_payroll_slips, and polls again untilcomplete.
const run = await cyber.call("run_payroll", { start_date, end_date });
if (run.queued) {
// poll get_payroll_status until creation_complete, then:
await cyber.call("submit_payroll_slips", { payroll_entry: run.payroll_entry });
// poll get_payroll_status until complete
}
Lifecycle: onboarding and offboarding
start_onboarding auto-creates the Job Applicant and an accepted Job Offer it
needs, then a draft Employee Onboarding seeded from a template.
finish_boarding for onboarding creates the actual Employee record (using the
real date of birth and gender HR supplies) and provisions a login;
for offboarding it marks the employee Left, sets a relieving date, and disables
their linked login while dropping active sessions. submit_doc is restricted to
a fixed allowlist of submittable HR doctypes (Expense Claim, Shift Assignment,
Salary Structure and its Assignment, Job Offer, Appraisal, Employee Onboarding,
Employee Separation).
Administration: users and roles
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
get_assignable_roles | GET | No | _require_admin | none | The roles the console may grant (that exist on the site) |
list_users | GET | No | _require_admin | none | System users with their roles and status |
create_user | POST | No | _require_admin | email, first_name, last_name, roles, password, send_welcome_email, and profile fields | The created user with granted roles |
set_user_roles | POST | No | _require_admin | user, roles | The user's roles after the change |
set_user_enabled | POST | No | _require_admin | user, enabled | {user, enabled} |
Only roles in the fixed ASSIGNABLE_ROLES list can be granted, and only those
are touched on edit, leaving system-internal roles intact. Admins cannot remove
their own System Manager role or disable their own account, and the Administrator
account cannot be edited or disabled through the console. Welcome emails are only
attempted when outgoing mail is actually configured.
Finance
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
get_finance_overview | GET | No | _require_accounts | none | Cached finance snapshot: receivables, payables, cash, trend, top customers |
get_finance_accounts | GET | No | _require_accounts | none | Chart of accounts with balances, plus customers, suppliers, payment modes |
create_sales_invoice | POST | No | _require_accounts | customer, items or amount, tax_rate, posting_date, due_date, cost_center, project, submit | Invoice name, grand total, submitted flag, warnings |
create_purchase_invoice | POST | No | _require_accounts | supplier, items or amount, tax_rate, bill_no, bill_date, plus dates and dimensions | Invoice name, grand total, submitted flag, warnings |
record_invoice_payment | POST | No | _require_accounts | invoice_type, invoice_name, amount, mode_of_payment, reference_no, reference_date | Payment Entry name, paid amount, payment type, submitted flag |
create_journal_entry | POST | No | _require_accounts_manager | debit_account, credit_account, amount, posting_date, remark, cost_center, project, voucher_type | {name, amount} |
get_financial_statement | GET | No | _require_accounts | statement, from_date, to_date | Columns and rows for P and L, Balance Sheet, or Trial Balance |
get_financial_statement_pdf | GET | No | _require_accounts | statement, from_date, to_date | A branded PDF download of the statement |
get_aging | GET | No | _require_accounts | party_type (Receivable/Payable), report_date | Aged buckets (0-30 / 31-60 / 61-90 / 91-120 / 120+) by party |
get_bank_summary | GET | No | _require_accounts | none | Bank and cash balances plus recent ledger movement |
Notes: invoice endpoints accept either a multi-line items list or a single
amount for backward compatibility, auto-create the party and any service
items, and try to submit but survive a failed submit as a draft (returning a
short submit_error). Requested tax is applied only when a tax account exists,
otherwise the call succeeds with a warnings entry rather than silently
under-taxing. record_invoice_payment uses ERPNext's standard payment-entry
builder and validates that the invoice is submitted, not cancelled, and not
overpaid. The financial statements translate ERPNext's raw FiscalYearError into
a clear "no open fiscal year covers this range" message.
Business dashboard
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
get_business_dashboard | GET | No | any operational role | none | Weekly sales / purchase / profit / expense KPIs, 7-day trend, counts, recent transactions, top products |
The guard is the union of HR_ROLES, ACCOUNTS_ROLES, SELLING_ROLES,
BUYING_ROLES, STOCK_ROLES, and PROJECT_ROLES, so any operational role can
see the company-wide overview. The payload is cached per company for 60 seconds
and every section is defensive, so a missing module never breaks the view.
Sales and CRM
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
create_sales_order | POST | No | _require_selling | customer, items, delivery_date, tax_rate, order_type, cost_center, project, submit | Order name, customer, grand total, submitted flag, warnings |
create_quotation | POST | No | _require_selling | party, quotation_to (Customer/Lead), items, valid_till, tax_rate | Quotation name, party, grand total, warnings |
create_opportunity | POST | No | _require_selling | party, opportunity_from (Customer/Lead), opportunity_amount, expected_closing, status | {name, party} |
get_sales_overview | GET | No | _require_selling | none | Pipeline snapshot: open leads, opportunities, quotations, orders, funnel |
The CRM screen (components/crm/crm-manager.tsx) reads and writes Customer,
Contact, Issue, and Customer Group directly through the REST resource API rather
than custom endpoints. Sales endpoints resolve a party by name or display name,
creating a minimal Customer or Lead when it is new, which is what prevents
"could not find party" errors when quoting a fresh lead.
Procurement
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
create_material_request | POST | No | _require_buying | items, schedule_date, material_request_type, target_warehouse | Request name, submitted flag |
create_purchase_order | POST | No | _require_buying | supplier, items, schedule_date, tax_rate, cost_center, project, target_warehouse, submit | Order name, supplier, grand total, submitted flag, warnings |
get_procurement_overview | GET | No | _require_buying | none | Suppliers, open requests, open orders, PO value, payables |
Purchase invoices are created through the shared create_purchase_invoice
endpoint listed under Finance.
Inventory
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
get_inventory_overview | GET | No | _require_stock | none | Item counts, valuation, per-warehouse value, low-stock items |
Projects
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
get_projects_overview | GET | No | _require_projects | none | Project and task counts by status |
Documents
Method (cyber_zeb_erp.api.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
list_shareable_users | GET | No | login | none | Enabled desk users a file can be shared with |
list_documents | GET | No | login | limit | Files visible to the user, each annotated with who it is shared with |
share_file_with_users | POST | No | login (plus ownership) | file, users | {file, shared_with, is_private, file_url} |
share_file_with_users makes the file private and grants read-only access to the
named users. Only the file's owner, a user with write access, or an administrator
may change sharing, so no account can grant itself access to arbitrary private
files.
Careers (public portal)
Defined in careers.py. The public read and apply endpoints allow guests; the
HR controls require HR roles.
Method (cyber_zeb_erp.careers.) | HTTP | Guest | Guard | Key parameters | Returns |
|---|---|---|---|---|---|
get_site_settings | GET | Yes | none | none | The customer company's careers branding (name, headline, tagline, about, logo, website) |
list_openings | GET | Yes | none | department | Open, published job openings plus the department list |
get_opening | GET | Yes | none | name | One published opening, with sanitized rich-text description |
apply | POST | Yes | none (rate limited 10 / hour) | job_opening, applicant_name, email, phone, cover_letter, resume_filename, resume_base64 | {applied: true, job_title} |
set_careers_settings | POST | No | _require_hr | headline, tagline, about | The updated site settings |
set_opening_published | POST | No | _require_hr | name, publish | {name, publish} |
The public endpoints only ever expose published, not-yet-closed openings; salary
ranges appear only when HR explicitly opted in. apply validates the email,
enforces resume type (.pdf, .doc, .docx) and a 5 MB cap, stores the resume
as a private File, and rejects duplicate applications. All free text is
HTML-escaped or sanitized before storage. Applications land as Job Applicant
records in the HR recruitment pipeline. See
Configuration and Customization for how the
public page is branded to the customer company.