eCommerce API (B2B / XBG)¶
The eCommerce API — internally referred to as XBG (the schema files reference C:\XBG\Schemas\...) or B2BSeller — is Prophet 21's original XML message-based integration layer for B2B commerce websites. It predates and is architecturally unrelated to the modern OData, Transaction, Interactive, and Entity APIs documented elsewhere on this site. If you're integrating a storefront, customer portal, or punchout catalog with P21 — rather than building an internal tool or business rule — this is very likely the API your integration already uses or should use.
Source material
This section is reconstructed from two sources: the official eCommerce Services manual (v12.12, Epicor University, 2013) and the actual XSD-backed XML message templates supplied by our eCommerce vendor. The templates are the source of truth for field names — some fields they contain (noted below) postdate the 2013 manual and have no official prose description. Field purposes for those are inferred from naming and context; verify against a live response before relying on them for anything business-critical.
How the API Works¶
Unlike the REST/UI-server APIs, there is no fixed URL-per-resource pattern here. Each operation is a single XML message type — a root element (e.g. GetItemPrice) containing a <Request>, a <Reply>, and a <ReplyStatus> block:
<GetItemPrice xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="C:\XBG\Schemas\XBGGetItemPrice.xsd">
<Request>
<!-- fields you populate -->
</Request>
<Reply>
<!-- P21 populates this on response; leave empty in the request -->
</Reply>
<ReplyStatus>
<Result>0</Result>
<Message />
</ReplyStatus>
</GetItemPrice>
Your storefront builds the XML string, posts it to Epicor's B2B middleware, and gets the same document back with <Reply> and <ReplyStatus> populated. The transport endpoint/URL and whether it's exposed as SOAP or a raw HTTP POST is not present in the source files we have — that's environment-specific configuration on the middleware side. If you're standing up a new integration, get that from whoever manages the B2BSeller/middleware install (see Internal once we have it documented).
Web Service Groupings¶
The manual groups the messages into five logical services. The service names below don't always match the XML root element names 1:1 — the mapping is included because it trips people up when cross-referencing the manual against the schema files:
| Service | Manual's method name | Actual XML message (this doc) |
|---|---|---|
| ItemServices | GetItemLocations | GetItemLocations |
| GetItemPrice | GetItemPrice | |
| OrderServices | OrderImport | OrderImport |
| CalculateCartInfo | GetCartSummary | |
| GetOpenAR | GetMyAccountOpenAR | |
| GetOpenOrders | GetMyAccountOrders | |
| GetOrderDetail | GetMyAccountOrdersDetail | |
| GetOpenAQuote | GetMyAccountOpenQuotes / ...Detail | |
| TrackOrder | no template provided — likely reuses OrdersDetail/shipment data | |
| PurchaseServices | GetPastPurchases | GetMyAccountPurchaseHistory |
| GetPurchaseDetail | GetMyAccountPastPurchaseDetail | |
| InvoiceServices | GetAccountInvoices | GetMyAccountInvoices |
| GetInvoiceDetail | GetMyAccountInvoicesDetail | |
| CustomerServices | CustomerImport | CustomerImport |
| GetCustomerInfo | GetCustomer | |
| GetCustomerShipToInfo | GetCustomerShipTo | |
| GetCustomerControlInfo | GetCustomerControl |
Also present but not grouped in the manual's service list: ShipToImport (create a ship-to independent of an order), GetPriceBreaks, GetRelatedItems, and the four My Account contract messages (GetMyAccountContracts, GetMyAccountContractDetails).
Common Envelope Fields¶
Every request carries a version block and a few identity fields. These are consistent across all 21 message types:
| Field | Purpose |
|---|---|
B2BSellerVersion/MajorVersion, MinorVersion, BuildNumber | Client version identifier. The 2013 manual says to hardcode 5/11/100; treat that as a starting point, not a hard rule — confirm the expected value with the middleware config, since a mismatch can cause requests to be rejected. |
CustomerCode | The P21 customer_id placing the order / whose data is being queried. Must exist in P21. |
StoreName | The P21 company ID (e.g. T), not a literal store name — this is the most common point of confusion for new integrators. |
WebReferenceNumber | A caller-supplied unique number per request. Used as an idempotency/correlation key and, for OrderImport, echoed back to correlate the import with the resulting order. |
Pagination Pattern (all "search" and My Account calls)¶
GetCustomerShipTo, GetItemLocations, and every GetMyAccount* list operation share one pagination scheme:
| Field | Direction | Purpose |
|---|---|---|
PageSize | Request | Max rows to return in this call. |
StartRowID | Request | Opaque cursor for the page to start from. Leave blank for page 1. |
GetTableOfContents | Request | Set TRUE on the first call for a given search. P21 walks the full result set once and returns a RowID marker for the start of every page in ListOfRowIDs — the "table of contents." |
ListOfSortColumns/SortColumn direction="asc|dsc" | Request | Sort field, using the Reply-side tag name (e.g. ItemID, OrderDate) as the value. Each operation documents its own valid values. |
RowCount | Reply | Total rows matching the criteria (not just this page). |
ListOfRowIDs/RowID | Reply | One opaque marker per page. Store these — to jump to page 3, resend the original request with StartRowID set to the 3rd RowID value and GetTableOfContents set to False. RowID is not a row number; it's an internal composite cursor (often literally the sort key values pipe-concatenated, e.g. KS|||Leawood|||1011016 for a ship-to sort) and must be treated as opaque. |
Don't try to compute RowID yourself
We've seen the KS|||Leawood|||1011016 format tempt people into constructing RowID values by hand for deep-linking. Don't — the format isn't documented as stable across operations or P21 versions. Always get it from a prior response.
Result Codes¶
ReplyStatus/Result is 0 on success. Non-zero codes fall into ranges by functional area:
| Range | Area | Examples |
|---|---|---|
1–99 | System / transport | 10 unrecognized document type, 50 unrecognized document, 55 document setup failed, 85 HTTP/SOAP error |
1000–1999 | Validation | 1000 a required field was omitted (message includes the field name), 1010 no records matched the query |
2000–2999 | Order | 2000–2025 import/creation failures (2020 specifically means credit card authorization failed, not a general import error), 2030–2075 "could not find X" lookups (location, order #, quote #, item, shipment #, PO #, UOM) scoped to OrderImport/GetCartSummary |
3000–3999 | Customer | 3000/3025 customer creation failed, 3005–3035 "could not find X" lookups (contact, customer, customer part number, ship-to) |
4000–4999 | Item | 4000/4005/4015 item not found, 4010 location not found, 4020/4025 UOM not found (GetItemPrice), 4030 invalid AgingBasis |
9999 | Misc | Generic warning |
ReplyStatus/Message contains the human-readable detail — it interpolates the actual values from your request (e.g. "Could not find ItemID 1000049 for LocationID 1006840"), so log it in full rather than just the Result code.
Pages in This Section¶
| Page | Covers | Use for |
|---|---|---|
| Item Pricing & Availability | GetItemPrice, GetPriceBreaks, GetItemLocations, GetRelatedItems | Bulk pricing lookups — GetItemPrice accepts a list of items per call |
| Orders & Cart | OrderImport, ShipToImport, GetCartSummary | Submitting orders/quotes, cart pricing/tax preview |
| Customers | CustomerImport, GetCustomer, GetCustomerControl, GetCustomerShipTo | Customer/contact/ship-to lookups and self-registration |
| My Account (Self-Service) | The 11 GetMyAccount* read operations | Order history, invoices, open AR, quotes, contracts, purchase history for a logged-in customer portal |