Integration Guide — Price Table
Microservice: XDPeople.Soba.WebAPI (Core API)
Authentication: Bearer token (JWT) and tenant context — see Combined Login
Introduction
This guide describes how to integrate with the API to manage price lines (price tables) within the SOBA ecosystem. A price line consists of a header (PriceTableDTO) and lines (PriceTableItemDTO), each associated with an article (Item) or an article family (ItemGroup).
The model distinguishes two table types in the priceTableType field:
| Value | Name (enum) | Meaning |
|---|---|---|
0 | Absolute | Explicit prices per article; may include family-type lines (ItemGroup) as per the model; the API requires at least one line in items. |
1 | Relative | Variation relative to an absolute reference line (absolutePriceLineId); additional rules apply on save. |
Each line in items uses itemType:
| Value | Name (enum) | Meaning |
|---|---|---|
0 | Item | Individual article (itemKeyId = article key). |
1 | ItemGroup | Article family (itemKeyId typically the family identifier as text). |
The goal is to support integrators in correctly using the endpoints, constructing the JSON body, and anticipating validations and errors returned by the server.
Business Rules and Limits
The rules below are applied in the application service before persisting data. Violating any of them returns an error with the indicated code (typical API format — see HTTP error documentation).
| Rule | Detail | Error Code (example) |
|---|---|---|
| Relative table | If priceTableType is Relative (1), absolutePriceLineId cannot be invalid (value strictly less than 0). | PriceTableValidation.InvalidAbsolutePriceLine |
| Absolute table | If priceTableType is Absolute (0), the items list must exist and contain at least one element. | PriceTableValidation.AbsolutePriceLineRequiredItems |
| Date range | startDate cannot be later than endDate. | PriceTableValidation.InvalidDateInterval |
| Identifiers 0–5 | Reserved in the product (cost price and price lines 1 to 5). For new lines configurable by the integrator, prefer the identifier returned by GET /gateway/price-table/next-id (≥ 6). | — see GET /gateway/price-table/next-id |
It is recommended to obtain the next identifier with GET /gateway/price-table/next-id before creating a new line to avoid collisions and respect the minimum configured on the server.
Payload Mandatory Fields and Consistency by priceTableType
The value of priceTableType changes the server validations and the set of fields that must be consistent in the JSON.
Absolute table (priceTableType = 0)
| Aspect | What to ensure |
|---|---|
| Mandatory (API) | items must exist and have at least one element. Otherwise: PriceTableValidation.AbsolutePriceLineRequiredItems. |
| Consistency | Fill discountPercentage1, discountPercentage2, discountPercentage3 in the header when the business model applies global discounts; replicate or complement per line in items as needed. |
| Consistency | Align isTaxIncludedPrice in the header with the pricing criterion in the lines: if the main price includes VAT, use taxIncludedPrice and isTaxIncludedPrice: true in relevant entries; otherwise, prefer netPrice and isTaxIncludedPrice: false. |
| Dates | startDate cannot be later than endDate (validation common to both types). |
Relative table (priceTableType = 1)
| Aspect | What to ensure |
|---|---|
| Mandatory (API) | absolutePriceLineId cannot be less than 0. Otherwise: PriceTableValidation.InvalidAbsolutePriceLine. In practice, it must identify an existing and valid absolute price line in your context (reference for relative calculation). |
| Consistency | Set percentageReference according to the intended global percentage adjustment (value and sign per your convention for increase or discount). The DTO exposes only percentageReference; do not send properties not in the contract. |
| Consistency | In items, each article or family (itemType) must include the percentage discounts (discountPercentage1–3) and other fields required by the relative price flow they implement. Without lines, confirm with your business analyst if a relative table without items is allowed in the product — the current CanSave validation does not require lines for the relative type. |
| Dates | Same rule as in the absolute table (startDate / endDate). |
Fields common to both types
id, description, startDate, endDate, and priceTableType must always be validly defined in the request. Other fields of PriceTableDTO remain in the contract; default values (e.g., 0) are acceptable only if semantically correct for the use case.
Available Endpoints
All paths below assume the public prefix /gateway/price-table (Core API via gateway).
| Method | URL | Brief Description |
|---|---|---|
| GET | /gateway/price-table | Lists price lines with optional pagination. |
| GET | /gateway/price-table/next-id | Returns the next suggested identifier (minimum 6). |
| GET | /gateway/price-table/{id} | Retrieves a line by identifier, including items. |
| POST | /gateway/price-table | Creates a new price line. 201 Created response on success. |
| PUT | /gateway/price-table/{id} | Updates the specified line. 204 No Content response on success. |
| DELETE | /gateway/price-table/{id} | Deletes the specified line. 204 No Content response on success. |
List Price Lines
URL: /gateway/price-table
Method: GET
Query Parameters (optional):
| Parameter | Type | Description |
|---|---|---|
page | int | Page number (base 1), when applicable. |
pageSize | int | Page size. |
Behavior: returns a paginated list of price tables.
Get Next Identifier
URL: /gateway/price-table/next-id
Method: GET
Behavior: returns an integer with the next suggested ID, not less than 6, for new custom price lines.
Get a Line by Identifier
URL: /gateway/price-table/{id}
Method: GET
Route Parameter:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | int | Yes | Price line identifier. |
Behavior: returns PriceTableDTO with the items collection populated when present.
Create Price Line
URL: /gateway/price-table
Method: POST
Body: JSON in the PriceTableDTO model (see field tables below).
Success behavior: 201 Created (no response body in the current controller).
Update Price Line
URL: /gateway/price-table/{id}
Method: PUT
Parameters: id in route; body PriceTableDTO.
Success behavior: 204 No Content.
Delete Price Line
URL: /gateway/price-table/{id}
Method: DELETE
Success behavior: 204 No Content.
Body Structure (PriceTableDTO)
Most relevant fields for integration (other synchronization or cloud fields may be omitted or null depending on the use case). Rules by table type are in Payload Mandatory Fields and Consistency by Type.
| Field | Type | Mandatory (API / validation) | Description |
|---|---|---|---|
id | int | Yes in practice | Line identifier. |
description | string | Yes (max 20 characters) | Short description. |
priceTableType | int (enum) | Yes | 0 Absolute, 1 Relative. |
startDate | date-time | Yes | Effective start date. |
endDate | date-time | Yes | Effective end date (cannot be earlier than startDate). |
absolutePriceLineId | int | Conditional | Mandatory and consistent for relative type (reference to absolute line; server validation disallows negative). |
percentageReference | decimal | No | Global percentage reference (sign may indicate increase or discount per client convention). |
discountPercentage1 | decimal | No | Discount 1 (%). |
discountPercentage2 | decimal | No | Discount 2 (%). |
discountPercentage3 | decimal | No | Discount 3 (%). |
isTaxIncludedPrice | bool | No | Whether prices in lines are treated as tax included. |
inactive | bool | No | Inactive line. |
items | array | Conditional | Must have elements for absolute type. |
Structure of Each Line (PriceTableItemDTO)
| Field | Type | Description |
|---|---|---|
priceLineId | int | Price line identifier within the table context. |
itemKeyId | string | Article key or identifier used for family, according to itemType. |
itemAttributeCode | string | Article attribute code, when applicable. |
itemType | int | 0 Article, 1 Family. |
description | string | Displayable description. |
percentageReference | decimal | Percentage reference at the line level. |
discountPercentage1 | decimal | Discount 1 (%). |
discountPercentage2 | decimal | Discount 2 (%). |
discountPercentage3 | decimal | Discount 3 (%). |
netPrice | decimal | Net price. |
taxIncludedPrice | decimal | Price including tax. |
isTaxIncludedPrice | bool | Whether the line price includes tax. |
itemPriceLineId | int? | Reference price line per article (when used in the product). |
Example Create Request (Absolute Table)
Illustrative JSON body (example values):
{
"id": 14,
"description": "Line 14",
"startDate": "2026-05-13T10:15:58.222Z",
"endDate": "2026-05-14T10:15:58.222Z",
"priceTableType": 0,
"absolutePriceLineId": 0,
"percentageReference": 0,
"discountPercentage1": 1,
"discountPercentage2": 0,
"discountPercentage3": 0,
"isTaxIncludedPrice": true,
"inactive": false,
"items": [
{
"priceLineId": 14,
"itemKeyId": "1",
"itemAttributeCode": "",
"itemType": 0,
"description": "Dom Diogo (Arinto)",
"percentageReference": 0,
"discountPercentage1": 1,
"discountPercentage2": 0,
"discountPercentage3": 0,
"netPrice": 0,
"taxIncludedPrice": 0,
"isTaxIncludedPrice": true,
"itemPriceLineId": null
}
]
}
Example Create Request (Relative Table)
{
"id": 15,
"description": "Line 15",
"startDate": "2026-05-13T10:15:58.222Z",
"endDate": "2026-05-14T10:15:58.222Z",
"priceTableType": 1,
"absolutePriceLineId": 1,
"percentageReference": 10,
"discountPercentage1": 0,
"discountPercentage2": 0,
"discountPercentage3": 0,
"isTaxIncludedPrice": false,
"inactive": false,
"items": [
{
"priceLineId": 15,
"itemKeyId": "3",
"itemAttributeCode": "",
"itemType": 1,
"description": "Meats",
"percentageReference": 0,
"discountPercentage1": 0,
"discountPercentage2": 0,
"discountPercentage3": 0,
"netPrice": 0,
"taxIncludedPrice": 0,
"isTaxIncludedPrice": false,
"itemPriceLineId": null
}
]
}
Notes on the Payload (API Only)
- The integrator must send JSON conforming to
PriceTableDTOandPriceTableItemDTO. The validations described in this guide apply to any API client system. - The section Payload Mandatory Fields and Consistency by Type summarizes what the integrator must send or align per
priceTableType, in addition to the generic validations below. - In a relative table (
priceTableType = 1), fillabsolutePriceLineIdconsistently with the absolute reference line (the API rejects invalid references according to server rules). - In an absolute table (
priceTableType = 0), theitemslist must have at least one entry. - The fields
discountPercentage1,discountPercentage2,discountPercentage3, andpercentageReferenceexist in the contract both in the header and in the lines; they can be used according to your pricing model, provided the set respects server validations. - Bulk load: there is no dedicated resource for file import; build
itemsin your system and usePOSTorPUT.
Common Errors
| Code | Typical Type | Meaning and Suggested Action |
|---|---|---|
PriceTable.NotFound | 404 | Nonexistent identifier in retrieval, update, or deletion. |
PriceTableCreate.Fail | 409 / failure | Creation persistence failed; review data and retry; contact support if it persists. |
PriceTableUpdate.Fail | 409 / failure | Update failed during storage. |
PriceTableDelete.Fail | 409 / failure | Deletion failed during storage. |
PriceTableValidation.InvalidAbsolutePriceLine | 400 | Relative table with invalid absolute reference (absolutePriceLineId negative). |
PriceTableValidation.AbsolutePriceLineRequiredItems | 400 | Absolute table without lines in items. |
PriceTableValidation.InvalidDateInterval | 400 | startDate later than endDate. |
Error responses follow the API HTTP standard (Problem Details / HttpResponseError depending on version). Always validate the HTTP code and error payload.
Conclusion
Managing price lines via Core API boils down to CRUD operations on /gateway/price-table, with clear validations for absolute and relative types and for the date range. It is recommended to test all scenarios in a staging environment (creation with next-id, partial update of items, relative tables with valid reference, and validation errors) before production.
Related Resources
- Paginated list of price lines
- Create price line
- Update price line
- Delete price line
- Get line by identifier
- Get next identifier
Last updated: May 13, 2026