Skip to main content

ERP API Reference

The plugin's ERP modules (Invoicing + myDATA, Inventory/WMS, Purchasing, Accounting/GL, CRM, HR) are exposed over the same WordPress REST namespace as the rest of the commerce API:

/wp-json/ec/v1/…

There is no separate ERP namespace — every route below lives under ec/v1. What sets the ERP routes apart is the three-layer access gate in front of them. This page is the domain-grouped index of the ERP surface plus the exact gate each group enforces.

This page vs. the API overview

The REST API Overview lists the ERP groups as part of the full ec/v1 map. This page is the ERP-focused expansion — same endpoints, but annotated with the license feature and ERP role capability each group requires. For the exhaustive, machine-readable list of paths, methods, parameters, and schemas, always defer to the OpenAPI spec.


The ERP access gate (read this first)

Every ERP route passes through up to three checks, in order. A failure at any layer short-circuits with a 403 before the handler runs.

1. WordPress capability — access_erp

The user must hold the access_erp capability (granted through ERP roles) or manage_options (administrators bypass ERP roles entirely). This is the coarse "can this user touch the ERP at all" gate.

2. License feature — Business tier

Each domain maps to one license feature, and all ERP features require an active Business-tier license. When the store's tier doesn't cover the feature, the route returns:

{
"code": "license_required",
"message": "This feature requires a Business license or higher.",
"data": {
"status": 403,
"required_feature": "erp_inventory",
"required_tier": "business",
"current_tier": "starter"
}
}
ERP domainLicense featureRBAC module
Invoicing + myDATAerp_invoicinginvoicing
Inventory / WMSerp_inventoryinventory
Purchasingerp_purchasingpurchasing
Accounting / GLerp_accountingaccounting
CRMerp_crmcrm
HRerp_hrhr

3. ERP role capability — {module}.{action}

On top of the license check, the user's ERP role must grant the specific module permission. Permissions follow a {module}.{action} shape, where the module is the license feature minus its erp_ prefix and the action is derived from the HTTP method:

  • GET{module}.view
  • any write (POST / PUT / PATCH / DELETE){module}.update (v1 enforcement is module-level — a role that holds a module can perform every write in it; the exact write verb is not separately gated).

A role that lacks the module returns:

{
"code": "erp_role_forbidden",
"message": "Your ERP role does not permit \"inventory.update\".",
"data": {
"status": 403,
"required_permission": "inventory.update",
"role": "sales"
}
}

ERP roles and the modules they manage:

RoleManager access to modules
adminAll modules (bypasses the role matrix)
managerinvoicing, inventory, purchasing, crm
accountantinvoicing, accounting
warehouseinventory, purchasing
salesinvoicing, crm
hr_managerhr
employeeNone — self-service (ESS) only; see HR self-service
viewerRead-only (.view) on all modules except HR

Two cross-cutting resources are not tied to a single module:

  • dashboard — the ERP SPA landing read; .view is available to every authenticated ERP role.
  • customers — shared invoicing + CRM master data; any role holding either invoicing or crm gets it.

HR is deliberately excluded from the viewer read-all blanket — it holds sensitive employee PII (ΑΦΜ/ΑΜΚΑ/IBAN/emergency contacts), so only hr_manager and admin see manager-HR data. Every user sees their own record through the ESS surface.

How the gate is wired in code

ERP controllers compose these checks through the LicenseGatedErp trait (src/Licensing/Traits/LicenseGatedErp.php). The common case is one call — erpModulePermissionCheck('erp_<module>', $request) — as the route's permission_callback, which runs all three layers. Admin-only surfaces (ERP config, ΕΡΓΑΝΗ) use requireErpAdmin(), which requires the ERP role admin explicitly (never the viewer blanket).


Invoicing + myDATA — erp_invoicing

Greek e-invoicing with AADE myDATA transmission. Controller: InvoiceApiController.

Path (under ec/v1)MethodsPurpose
/invoicesGET, POSTList / create invoices
/invoices/statsGETAggregate invoice stats
/invoices/{id}GET, PUT, DELETERead / update / delete an invoice
/invoices/{id}/issuePOSTFinalize (issue) a draft
/invoices/{id}/cancelPOSTCancel an issued invoice
/invoices/from-order/{orderId}POSTGenerate an invoice from an order
/invoices/{id}/transmitPOSTTransmit to myDATA (AADE)
/invoices/{id}/cancel-mydataPOSTCancel a prior myDATA transmission
/invoices/{id}/mydata-logGETmyDATA transmission log for the invoice
/invoices/{id}/mydata-previewGETPreview the myDATA XML payload
/invoices/{id}/pdfGETDownload the invoice PDF
/invoices/{id}/pdf/generatePOST(Re)generate the PDF
/invoice-seriesGET, POSTList / create numbering series
/invoice-series/{id}PUT, DELETEUpdate / delete a series
/invoices/settingsGET, PUTInvoicing + myDATA settings
/invoices/mydata/testPOSTTest the myDATA connection (admin — manage_options)
/invoices/reference-dataGETmyDATA reference tables (VAT categories, types, etc.)

Gate: access_erp + erp_invoicing (Business) + invoicing.{view|update}. The myDATA connection test additionally requires manage_options.


Inventory / WMS — erp_inventory

Multi-warehouse stock, movements, transfers, stocktakes. Controllers: WarehouseApiController, StockApiController.

Path (under ec/v1)MethodsPurpose
/warehousesGET, POSTList / create warehouses
/warehouses/{id}GET, PUT, DELETERead / update / delete a warehouse
/warehouses/{id}/set-defaultPOSTMark as the default warehouse
/warehouses/{id}/activatePOSTActivate
/warehouses/{id}/deactivatePOSTDeactivate
/stock/levelsGETStock levels across warehouses
/stock/levels/{product_id}GETStock levels for one product
/stock/adjustPOSTAdjust stock (with a reason/movement)
/stock/transferPOSTTransfer stock between warehouses
/stock/stocktakePOSTSubmit a stocktake / reconciliation
/stock/movementsGETMovement ledger
/stock/movements/{product_id}GETMovement ledger for one product
/stock/statsGETInventory KPIs

Gate: access_erp + erp_inventory (Business) + inventory.{view|update}.


Purchasing — erp_purchasing

Suppliers, purchase orders, goods received, supplier pricing. Controllers: SupplierApiController, PurchaseApiController.

Path (under ec/v1)MethodsPurpose
/suppliersGET, POSTList / create suppliers
/suppliers/{id}GET, PUT, DELETERead / update / delete a supplier
/suppliers/{id}/pricesGETSupplier price list
/purchase-ordersGET, POSTList / create purchase orders
/purchase-orders/statsGETPO KPIs
/purchase-orders/auto-reorderPOSTGenerate POs from reorder points
/purchase-orders/{id}GET, PUT, DELETERead / update / delete a PO
/purchase-orders/{id}/sendPOSTEmail the PO to the supplier
/purchase-orders/{id}/resendPOSTRe-send the PO email
/purchase-orders/{id}/receivePOSTRecord receipt (creates a goods-received note)
/goods-receivedGET, POSTList / create goods-received notes
/goods-received/{id}GETRead a goods-received note
/supplier-pricesGET, POSTSupplier-price CRUD
/supplier-prices/{id}PUT, DELETEUpdate / delete a supplier price

Gate: access_erp + erp_purchasing (Business) + purchasing.{view|update}.


Accounting / GL — erp_accounting

Chart of accounts, fiscal years, double-entry journal, and the six financial reports. Controller: AccountingApiController.

Path (under ec/v1)MethodsPurpose
/accountsGET, POSTList / create GL accounts
/accounts/treeGETChart of accounts as a tree
/accounts/seed-elpPOSTSeed the Greek chart of accounts (ΕΛΠ)
/accounts/{id}GET, PUT, DELETERead / update / delete an account
/fiscal-yearsGET, POSTList / create fiscal years
/fiscal-years/currentGETThe active fiscal year
/fiscal-years/{id}GET, PUTRead / update a fiscal year
/fiscal-years/{id}/closePOSTClose a fiscal year
/journal-entriesGET, POSTList / create journal entries
/journal-entries/statsGETJournal KPIs
/journal-entries/{id}GET, PUT, DELETERead / update / delete an entry
/journal-entries/{id}/postPOSTPost (finalize) an entry
/journal-entries/{id}/reversePOSTReverse a posted entry

The six financial reports (all GET):

PathReport
/reports/trial-balanceTrial balance
/reports/profit-lossProfit & loss (income statement)
/reports/balance-sheetBalance sheet
/reports/vat-returnVAT return (ΦΠΑ)
/reports/accounts-receivableAccounts receivable ageing
/reports/accounts-payableAccounts payable ageing

Gate: access_erp + erp_accounting (Business) + accounting.{view|update}. Reports are GETaccounting.view.


CRM — erp_crm

Contacts, leads/pipeline, activities, and segmentation. Controller: CrmApiController.

Path (under ec/v1)MethodsPurpose
/contactsGET, POSTList / create contacts
/contacts/statsGETContact KPIs
/contacts/tagsGETContact tag list
/contacts/import-customersPOSTImport store customers as contacts
/contacts/{id}GET, PUT, DELETERead / update / delete a contact
/contacts/{id}/activitiesGETActivities for a contact
/contacts/{id}/leadsGETLeads for a contact
/leadsGET, POSTList / create leads
/leads/statsGETLead KPIs
/leads/pipelineGETPipeline view
/leads/by-stageGETLeads grouped by stage
/leads/{id}GET, PUT, DELETERead / update / delete a lead
/leads/{id}/move-stagePOSTMove a lead to another stage
/leads/{id}/convertPOSTConvert a lead
/activitiesGET, POSTList / create activities
/activities/statsGETActivity KPIs
/activities/upcomingGETUpcoming activities
/activities/overdueGETOverdue activities
/activities/{id}GET, PUT, DELETERead / update / delete an activity
/activities/{id}/completePOSTMark an activity complete
/crm/dashboardGETCRM dashboard aggregates
/crm/segmentsGETCustomer segments
/crm/rfmGETRFM (recency/frequency/monetary) analysis

Gate: access_erp + erp_crm (Business) + crm.{view|update}.


HR — erp_hr

Employees, departments, leave, time entries, documents — plus an employee self-service surface. Controller: HrApiController.

Manager-facing (require hr.{view|update} — in v1 only hr_manager and admin hold the hr module):

Path (under ec/v1)MethodsPurpose
/employeesGET, POSTList / create employees
/employees/statsGETEmployee KPIs
/employees/{id}GET, PUT/PATCH, DELETERead / update / delete an employee
/employees/{id}/leave-balanceGETLeave balance for an employee
/employees/{id}/provision-essPOSTLink a WP account for self-service
/departments, /departments/{id}GET, POST, PUT/PATCH, DELETEDepartment CRUD
/leave-types, /leave-types/{id}GET, POST, PUT/PATCH, DELETELeave-type CRUD (the GET read is looser than the manage gate)
/leave-requests, /leave-requests/{id}GET, POST, …Leave-request management
/leave-requests/{id}/approvePOSTApprove a request
/leave-requests/{id}/rejectPOSTReject a request
/leave-requests/{id}/cancelPOSTCancel a request
/time-entries, /time-entries/{id}GET, POST, …Time-entry management
/employee-documents, /employee-documents/{id}GET, POST, …Employee document management
/hr/dashboardGETHR dashboard aggregates
/hr/who-is-outGETWho is on leave

HR self-service (ESS)

The /hr/me/* routes are the employee self-service surface. They use a different gate: canAccessEss — an active erp_hr license plus a WordPress account linked to an employee record (provisioned via /employees/{id}/provision-ess). Every ESS handler scopes strictly to the caller's own record, so a plain employee role (no manager modules) can still reach these.

Path (under ec/v1)MethodsPurpose
/hr/meGETThe caller's own employee record
/hr/me/leave-balanceGETOwn leave balance
/hr/me/leave-requestsGET, POSTOwn leave requests (view / submit)
/hr/me/leave-requests/{id}/cancelPOSTCancel own request
/hr/me/time-entriesGET, POSTOwn time entries
/hr/me/documentsGETOwn documents

Gate: manager routes → access_erp + erp_hr (Business) + hr.{view|update} (only hr_manager/admin in v1). ESS routes → erp_hr (Business) + linked employee record (canAccessEss).


ΕΡΓΑΝΗ (Ergani) — erp_hr, ERP-admin only

Submissions to the Greek labour authority (ΕΡΓΑΝΗ). Controller: ErganiApiController.

Path (under ec/v1)MethodsPurpose
/ergani/settingsGET, PUTΕΡΓΑΝΗ credentials + settings
/ergani/test-connectionPOSTTest the ΕΡΓΑΝΗ connection
/ergani/submissionsGETSubmission history
/ergani/submissions/{id}/retryPOSTRetry a failed submission

Gate: requireErpAdmin('erp_hr') — the ERP admin role (or manage_options) plus erp_hr (Business). This is stricter than the hr.* module role: a plain hr_manager can manage employees but cannot touch ΕΡΓΑΝΗ (it writes WP-stored credentials, so it's admin-gated like ERP config).


ERP configuration & administration (admin-only)

Activation, credentials, ERP users/roles, data migration, inventory backfill, and onboarding. Controller: ErpConfigApiController. These routes are gated on the ERP admin role (or manage_options) via requireErpAdmin() / canManageErp — not the per-module RBAC matrix. Write routes that touch licensed features additionally require the license (canManageErpLicensed).

Path (under ec/v1)Purpose
/erp/statusERP activation + config status
/erp/activate, /erp/deactivateTurn the ERP on/off
/erp/test-connection, /erp/save-credentialsSeparate-ERP-DB connection (see ERP architecture)
/erp/users, /erp/users/{id}, /erp/users/{id}/remove, /erp/users/{id}/reactivateERP user management
/erp/rolesThe ERP role catalog
/erp/migrate-data/preview, /erp/migrate-data/run, /erp/migrate-data/cleanupSame-DB → separate-ERP-DB migration
/erp/inventory/backfill/status, /erp/inventory/backfill/runBackfill stock levels from existing products
/erp/onboarding/checklist, /erp/onboarding/checklist/hide, /erp/onboarding/checklist/showSetup checklist state
/erp/products/apply-cost-sourceBulk cost-source assignment
/erp/portal-settingsBranded ERP portal / standalone-login settings

The OpenAPI spec (authoritative)

The plugin generates its own OpenAPI 3.0 spec covering the whole ec/v1 surface, including every ERP operation with exact parameters and schemas. Prefer it over any hand-written list (including this page).

Enable Settings → Developer → API Documentation, then fetch (admin-authenticated):

curl -u "admin:xxxx xxxx xxxx xxxx" \
https://your-site.com/wp-json/ec/v1/docs/openapi.json

The endpoint requires manage_options and the toggle. See the REST API Overview → OpenAPI spec for the in-admin viewer and playground, and for authentication (nonce vs. Application Passwords) and the common response/error envelopes — those apply identically to the ERP routes.

Where to go next

  • ERP Architecture for Developers — how the entity → repository → service → controller layers connect, ERP-DB routing, and the commerce↔ERP integration-listener contract.
  • REST API Overview — the full three-namespace map and shared conventions.