Acumatica · Customization

Acumatica Self-Service Portal — Configuration

How to set up the Acumatica Self-Service Portal for customers and vendors — branding, menus, GI exposure, access rights, and the upgrade-safe patterns that keep it maintainable.

John Kihiu12 min read

A distributor client wanted their customers to log in, see only their own open invoices and order history, and place reorders, without touching their internal ERP users' license count. That is the self-service portal use case in one sentence, and getting there in Acumatica is mostly configuration, restriction groups, and a customer-portal-specific user type, rather than a bespoke build, provided you set the security model up correctly from the start.

Portal users are a genuinely different user category

Self-service portal access is built on the Customer Portal user type, which is licensed and restricted differently from an internal employee user. A portal user is associated with a specific Business Account (typically a customer, sometimes a vendor for AP-facing self-service), and every screen exposed to that user needs to be filtered, at the data level, to only that account's records. This is not a UI-only restriction, if the filtering is done wrong, a portal user with a crafted GI request or a misconfigured screen can potentially see another customer's data through the same screen, which is the single most damaging class of bug a self-service portal can ship with.

Never rely on UI-level filtering alone for portal data isolation

A grid that only displays rows matching the logged-in customer, without an actual BQL-level restriction tied to that customer's Business Account, is not a security boundary, it is a suggestion. Any screen exposed to portal users needs the row-level restriction enforced in the graph's data view or the GI's filter condition, using the portal user's associated Business Account as the actual join key, not just a client-side or presentation-layer filter that a determined user could route around via the REST API using the same portal credentials.

Tying the portal user to their own data

The standard mechanism restricts a portal user's visible rows via the Business Account associated with their portal contact, enforced through restriction groups and, for custom screens, an explicit condition in the graph's primary view:

C#
// Custom portal-facing graph: filter every row to the logged-in
// portal user's own Business Account, never trust the UI alone.
public PXSelect<ARInvoice,
    Where<ARInvoice.customerID, Equal<Current<AccessInfo.businessAccountID>>>> MyInvoices;

AccessInfo.businessAccountID resolves to the Business Account tied to the currently authenticated portal user, and building every portal-facing view around that current-value join, rather than a filter the user could theoretically edit, is what makes the isolation real instead of cosmetic.

Generic Inquiries as the fastest path to a working portal screen

For read-mostly portal needs, order history, invoice status, statement download, publishing a Generic Inquiry directly to the portal is usually faster and safer than building a bespoke graph, because the GI publishing wizard has its own portal-scoped restriction configuration built in, provided you actually configure it rather than accepting the default of showing all rows. I default every portal-published GI's filter to the current portal user's Business Account explicitly, then verify by logging in as a real restricted portal test account, not an internal admin account with elevated visibility, before it ships.

Portal branding and navigation live in a different configuration surface

Beyond data security, the portal's actual look, its navigation menu, branding, and which screens appear for which portal role, is configured through the portal's own site map and role assignment, separate from the internal ERP's site map. It is easy to publish a screen for portal use and forget to also assign it to the correct portal-facing role, which produces the common symptom of "the screen works when I test it as an internal admin, but the actual customer can't find it," because the admin account's role visibility hid the missing portal-role assignment during testing.

Write access from the portal needs the same scrutiny as reads

Letting portal users create reorders or submit cases is a step up in risk from read-only visibility, because now a portal user's actions execute business logic, not just display data. Every action exposed to a portal graph needs the same current-Business-Account scoping as the data views, and any action that could plausibly affect another account's records (changing a ship-to address shared across a corporate hierarchy, for instance) needs an explicit ownership check inside the action itself, not an assumption that the surrounding screen's filtering already covers it.

Test portal actions with two separate portal accounts, not one

The isolation bug that slips through most often only shows up when you have two real portal test accounts and deliberately try to make one see or affect the other's data, an ID guessed or bookmarked from one account's session, tried against the other's login. Testing with a single portal account, however thoroughly, cannot surface this class of bug, because there is no second account to leak into.

Wrapping up

A self-service portal in Acumatica is built from ordinary platform pieces, the Customer Portal user type, Business-Account-scoped restrictions, and GI publishing, but the entire project succeeds or fails on whether data isolation is enforced at the query level rather than the UI level. Scope every view and action to the authenticated portal user's own Business Account explicitly, publish GIs with their portal filter actually configured rather than defaulted, and test with two separate real portal accounts before treating any portal screen as done.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.