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:

GuardRole setMembers
_require_login(any authenticated user)Any non-Guest session
_require_hrHR_ROLESHR Manager, HR User, System Manager, Administrator
_require_hr_managerHR_MANAGER_ROLESHR Manager, System Manager, Administrator
_require_adminADMIN_ROLESSystem Manager, Administrator
_require_accountsACCOUNTS_ROLESAccounts Manager, Accounts User, System Manager, Administrator
_require_accounts_managerACCOUNTS_MANAGER_ROLESAccounts Manager, System Manager, Administrator
_require_sellingSELLING_ROLESSales Manager, Sales User, Sales Master Manager, System Manager, Administrator
_require_buyingBUYING_ROLESPurchase Manager, Purchase User, Stock Manager, System Manager, Administrator
_require_stockSTOCK_ROLESStock Manager, Stock User, System Manager, Administrator
_require_projectsPROJECT_ROLESProjects 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.)HTTPGuestGuardKey parametersReturns
get_current_user_profileGETNologinnoneEmail, name, mobile, roles, avatar data URL
update_current_user_profilePOSTNologinfirst_name, last_name, mobile_no, user_imageThe refreshed profile
update_current_user_avatarPOSTNologinuser_image or (filename, content_type, content_base64)The refreshed profile
change_current_user_passwordPOSTNologincurrent_password, new_password{status: "password_updated"}
sign_upPOSTYesnone (rate limited 5 / 15 min)email, full_name, password{email, full_name, roles}
signup_enabledGETYesnonenone{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.)HTTPGuestGuardKey parametersReturns
get_hr_overviewGETNo_require_hrnoneCached HR snapshot: headcount, leave, celebrations, distributions
get_hr_metaGETNo_require_hrnoneEvery HR dropdown source (departments, leave types, structures, and more)
get_employee_360GETNo_require_hremployeeOne employee's leave, attendance, payroll, appraisals, documents
set_leave_statusPOSTNo_require_hr_managername, status (Approved/Rejected)Leave application name, status, docstatus
allocate_leavePOSTNo_require_hr_manageremployee, leave_type, from_date, to_date, new_leaves_allocated, carry_forwardThe submitted Leave Allocation
mark_attendancePOSTNo_require_hremployee, attendance_date, status, shift, working_hoursThe submitted Attendance
set_employee_statusPOSTNo_require_hr_manageremployee, status (Active/Inactive/Suspended/Left){employee, status}
employee_punchPOSTNo_require_hremployee, log_type (IN/OUT, inferred if omitted)The Employee Checkin
assign_salary_structurePOSTNo_require_hr_manageremployee, salary_structure, from_date, baseThe submitted assignment
run_payrollPOSTNo_require_hr_managerstart_date, end_date, payroll_frequency, companyPayroll result, or a queued handle above 30 employees
get_payroll_statusGETNo_require_hrpayroll_entryProgress: slips created, submitted, net pay, complete flag
submit_payroll_slipsPOSTNo_require_hr_managerpayroll_entryProgress after submitting the draft slips
set_expense_claim_statusPOSTNo_require_hr_managername, status (Approved/Rejected)Claim name, status, docstatus
submit_docPOSTNo_require_hrdoctype, name{doctype, name, docstatus}
get_lifecycleGETNo_require_hrnoneOnboarding/offboarding lists with progress plus templates
get_boardingGETNo_require_hrdoctype, nameOne lifecycle record's full checklist
toggle_boarding_activityPOSTNo_require_hrdoctype, name, idx, completedUpdated progress
start_onboardingPOSTNo_require_hr_managerapplicant_name, designation, department, date_of_joining, template, emailThe new draft Employee Onboarding
start_offboardingPOSTNo_require_hr_manageremployee, boarding_begins_on, templateThe new draft Employee Separation
finish_boardingPOSTNo_require_hr_managerdoctype, name, date_of_birth, genderCreated Employee (onboarding) or the departed employee + disabled login
delete_boardingPOSTNo_require_hr_managerdoctype, 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 polls get_payroll_status until creation_complete, calls submit_payroll_slips, and polls again until complete.
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.)HTTPGuestGuardKey parametersReturns
get_assignable_rolesGETNo_require_adminnoneThe roles the console may grant (that exist on the site)
list_usersGETNo_require_adminnoneSystem users with their roles and status
create_userPOSTNo_require_adminemail, first_name, last_name, roles, password, send_welcome_email, and profile fieldsThe created user with granted roles
set_user_rolesPOSTNo_require_adminuser, rolesThe user's roles after the change
set_user_enabledPOSTNo_require_adminuser, 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.)HTTPGuestGuardKey parametersReturns
get_finance_overviewGETNo_require_accountsnoneCached finance snapshot: receivables, payables, cash, trend, top customers
get_finance_accountsGETNo_require_accountsnoneChart of accounts with balances, plus customers, suppliers, payment modes
create_sales_invoicePOSTNo_require_accountscustomer, items or amount, tax_rate, posting_date, due_date, cost_center, project, submitInvoice name, grand total, submitted flag, warnings
create_purchase_invoicePOSTNo_require_accountssupplier, items or amount, tax_rate, bill_no, bill_date, plus dates and dimensionsInvoice name, grand total, submitted flag, warnings
record_invoice_paymentPOSTNo_require_accountsinvoice_type, invoice_name, amount, mode_of_payment, reference_no, reference_datePayment Entry name, paid amount, payment type, submitted flag
create_journal_entryPOSTNo_require_accounts_managerdebit_account, credit_account, amount, posting_date, remark, cost_center, project, voucher_type{name, amount}
get_financial_statementGETNo_require_accountsstatement, from_date, to_dateColumns and rows for P and L, Balance Sheet, or Trial Balance
get_financial_statement_pdfGETNo_require_accountsstatement, from_date, to_dateA branded PDF download of the statement
get_agingGETNo_require_accountsparty_type (Receivable/Payable), report_dateAged buckets (0-30 / 31-60 / 61-90 / 91-120 / 120+) by party
get_bank_summaryGETNo_require_accountsnoneBank 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.)HTTPGuestGuardKey parametersReturns
get_business_dashboardGETNoany operational rolenoneWeekly 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.)HTTPGuestGuardKey parametersReturns
create_sales_orderPOSTNo_require_sellingcustomer, items, delivery_date, tax_rate, order_type, cost_center, project, submitOrder name, customer, grand total, submitted flag, warnings
create_quotationPOSTNo_require_sellingparty, quotation_to (Customer/Lead), items, valid_till, tax_rateQuotation name, party, grand total, warnings
create_opportunityPOSTNo_require_sellingparty, opportunity_from (Customer/Lead), opportunity_amount, expected_closing, status{name, party}
get_sales_overviewGETNo_require_sellingnonePipeline 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.)HTTPGuestGuardKey parametersReturns
create_material_requestPOSTNo_require_buyingitems, schedule_date, material_request_type, target_warehouseRequest name, submitted flag
create_purchase_orderPOSTNo_require_buyingsupplier, items, schedule_date, tax_rate, cost_center, project, target_warehouse, submitOrder name, supplier, grand total, submitted flag, warnings
get_procurement_overviewGETNo_require_buyingnoneSuppliers, 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.)HTTPGuestGuardKey parametersReturns
get_inventory_overviewGETNo_require_stocknoneItem counts, valuation, per-warehouse value, low-stock items

Projects

Method (cyber_zeb_erp.api.)HTTPGuestGuardKey parametersReturns
get_projects_overviewGETNo_require_projectsnoneProject and task counts by status

Documents

Method (cyber_zeb_erp.api.)HTTPGuestGuardKey parametersReturns
list_shareable_usersGETNologinnoneEnabled desk users a file can be shared with
list_documentsGETNologinlimitFiles visible to the user, each annotated with who it is shared with
share_file_with_usersPOSTNologin (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.)HTTPGuestGuardKey parametersReturns
get_site_settingsGETYesnonenoneThe customer company's careers branding (name, headline, tagline, about, logo, website)
list_openingsGETYesnonedepartmentOpen, published job openings plus the department list
get_openingGETYesnonenameOne published opening, with sanitized rich-text description
applyPOSTYesnone (rate limited 10 / hour)job_opening, applicant_name, email, phone, cover_letter, resume_filename, resume_base64{applied: true, job_title}
set_careers_settingsPOSTNo_require_hrheadline, tagline, aboutThe updated site settings
set_opening_publishedPOSTNo_require_hrname, 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.