Download OpenAPI specification:
REST API for forge-erp, a single-tenant manufacturing ERP. The modules integrate around one flow: Sales Order → Production Order (via BOM) → Purchase Orders for materials → Goods Receipt → Inventory → production through Work Centers → Quality → Delivery → Invoice → Payment → auto-posted Journal Entries.
Authentication. All endpoints require a JWT bearer access token except POST /auth/login and POST /auth/refresh. Obtain a token from /auth/login, then send Authorization: Bearer <accessToken> on every other request. Access tokens expire after 20 minutes; use /auth/refresh with the refresh token to obtain a new pair.
Authorization. Access is permission-based, not role-based. Each write/read is gated by a fine-grained permission (e.g. MASTERDATA_WRITE, PO_APPROVE); a role is a bundle of permissions. The required permission is stated in each operation's description. A missing permission returns 403.
Errors. Every error is an RFC 7807 problem document (application/problem+json) with the shape shown in the ProblemDetail schema. See the Frontend Integration Guide for the full status-code taxonomy.
Pagination & sorting. List endpoints return a PagedResponse and accept page (0-based), size (default 20, max 100, clamped), and sort=field,dir. Each endpoint allows sorting only on a declared set of fields; an unknown field returns 400.
Author. Designed and built by Ramraj Patil — ramrajpatil24@gmail.com.
Exchange a username and password for an access/refresh token pair. This is one of only two endpoints that do not require a bearer token. On success, send the returned accessToken as Authorization: Bearer <accessToken> on all other requests. Invalid credentials return 401.
| username required | string Account username. |
| password required | string <password> Account password. |
{- "username": "ramraj.system",
- "password": "local-dev-admin-change-me"
}{- "accessToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhcnVuLnN5c3RlbSIsInVpZCI6Mzg3NDAxfQ...",
- "refreshToken": "9f2c1e7a4b3d4f8e9a0b1c2d3e4f5a6b",
- "tokenType": "Bearer",
- "expiresIn": 1200
}Exchange a valid, unexpired refresh token for a new access/refresh token pair (rotation). The old refresh token is consumed. A missing, expired, revoked, or already-used token returns 401. Does not require a bearer token.
| refreshToken required | string The raw refresh token returned at login/refresh time. |
{- "refreshToken": "9f2c1e7a4b3d4f8e9a0b1c2d3e4f5a6b"
}{- "accessToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhcnVuLnN5c3RlbSJ9...",
- "refreshToken": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
- "tokenType": "Bearer",
- "expiresIn": 1200
}Ends a device's session by revoking the supplied refresh token (same request body as /auth/refresh). Like the other auth endpoints it is public — no bearer token is required, so a user whose access token has already expired can still log out. Revoking an unknown, expired, or already-revoked token is a deliberate no-op: the endpoint always returns 204 and never reveals whether the token was valid. After it returns, discard both tokens on the client and send the user back to login.
| refreshToken required | string The raw refresh token returned at login/refresh time. |
{- "refreshToken": "9f2c1e7a4b3d4f8e9a0b1c2d3e4f5a6b"
}{- "type": "about:blank",
- "title": "Validation failed",
- "status": 400,
- "detail": "One or more fields are invalid.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z",
- "errors": {
- "sku": "must not be blank"
}
}Returns a paged list of materials — things consumed to build: raw materials, consumables, and manufacturable sub-assemblies (Phase 10 split product into material + product). Optionally filter by a free-text search term (case-insensitive LIKE over SKU and name) and/or an exact type. Requires permission: MASTERDATA_READ. Sortable fields (allow-list): sku, name, type, createdAt; default sort is createdAt,desc. Sorting by any other field returns 400.
| search | string Example: search=SS316 Case-insensitive substring matched against SKU or name. Omit to match all. |
| type | string (MaterialType) Enum: "RAW_MATERIAL" "WIP" Exact material-type filter. Omit to include all types. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 88,
- "sku": "SS316-TUBE-19",
- "name": "Stainless Steel Tube SS316, 19mm OD",
- "type": "RAW_MATERIAL",
- "hsnCode": "7304",
- "categoryId": 5,
- "categoryName": "Tubes & Piping",
- "uomId": 2,
- "uomCode": "M",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a material. sku must be unique. uomId must reference an existing unit of measure; categoryId, when supplied, must reference an existing category. Requires permission: MASTERDATA_WRITE.
| sku required | string <= 60 characters Stock-keeping unit. Unique across all materials. |
| name required | string <= 200 characters Human-readable material name. |
| type required | string (MaterialType) Enum: "RAW_MATERIAL" "WIP" Kind of material: a purchased raw material or consumable ( |
| hsnCode | string <= 8 characters Optional HSN classification code for GST, printed on purchase-invoice lines. Validated loosely (4-8 digits) — editable master data. |
| categoryId | integer <int64> Optional category reference. Must exist when supplied. |
| uomId required | integer <int64> Required unit-of-measure reference. Must exist. |
{- "sku": "SS316-TUBE-19",
- "name": "Stainless Steel Tube SS316, 19mm OD",
- "type": "RAW_MATERIAL",
- "categoryId": 5,
- "uomId": 2
}{- "id": 88,
- "sku": "SS316-TUBE-19",
- "name": "Stainless Steel Tube SS316, 19mm OD",
- "type": "RAW_MATERIAL",
- "hsnCode": "7304",
- "categoryId": 5,
- "categoryName": "Tubes & Piping",
- "uomId": 2,
- "uomCode": "M",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one material by id. Requires permission: MASTERDATA_READ.
| id required | integer <int64> Material id. |
{- "id": 88,
- "sku": "SS316-TUBE-19",
- "name": "Stainless Steel Tube SS316, 19mm OD",
- "type": "RAW_MATERIAL",
- "hsnCode": "7304",
- "categoryId": 5,
- "categoryName": "Tubes & Piping",
- "uomId": 2,
- "uomCode": "M",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Updates an existing material. sku must remain unique; uomId (and categoryId when supplied) must reference existing rows. Subject to optimistic locking — a concurrent modification returns 409. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Material id. |
| sku required | string <= 60 characters Stock-keeping unit. Unique across all materials. |
| name required | string <= 200 characters Human-readable material name. |
| type required | string (MaterialType) Enum: "RAW_MATERIAL" "WIP" Kind of material: a purchased raw material or consumable ( |
| hsnCode | string <= 8 characters Optional HSN classification code for GST, printed on purchase-invoice lines. Validated loosely (4-8 digits) — editable master data. |
| categoryId | integer <int64> Optional category reference. Must exist when supplied. |
| uomId required | integer <int64> Required unit-of-measure reference. Must exist. |
{- "sku": "SS316-TUBE-19",
- "name": "Stainless Steel Tube SS316, 19mm OD",
- "type": "RAW_MATERIAL",
- "categoryId": 5,
- "uomId": 2
}{- "id": 88,
- "sku": "SS316-TUBE-19",
- "name": "Stainless Steel Tube SS316, 19mm OD",
- "type": "RAW_MATERIAL",
- "hsnCode": "7304",
- "categoryId": 5,
- "categoryName": "Tubes & Piping",
- "uomId": 2,
- "uomCode": "M",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a material. A material still referenced by any other record (a BOM component, supplier catalog entry, purchase-order or goods-receipt line, a design/production target, stock, or an AP invoice line) cannot be deleted and returns 422 — remove or reassign the references first. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Material id. |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a paged list of products. Optionally filter by a free-text search term (case-insensitive LIKE over SKU and name) and/or an exact product type. Requires permission: MASTERDATA_READ. Sortable fields (allow-list): sku, name, type, createdAt; default sort is createdAt,desc. Sorting by any other field returns 400.
| search | string Example: search=HX Case-insensitive substring matched against SKU or name. Omit to match all. |
| type | string (ProductType) Enum: "RAW_MATERIAL" "WIP" "FINISHED_GOOD" Exact product-type filter. Omit to include all types. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 42,
- "sku": "FG-ST-001",
- "name": "Shell & Tube HX, SS316 Tubes, 4.5 m2, BEM Type",
- "type": "RAW_MATERIAL",
- "hsnCode": "8419",
- "categoryId": 3,
- "categoryName": "Shell & Tube Exchangers",
- "uomId": 1,
- "uomCode": "NOS",
- "materialId": 88,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a product. sku must be unique. uomId must reference an existing unit of measure; categoryId, when supplied, must reference an existing category. Requires permission: MASTERDATA_WRITE.
| sku required | string <= 60 characters Stock-keeping unit. Unique across all products. |
| name required | string <= 200 characters Human-readable product name. |
| type required | string (ProductType) Enum: "RAW_MATERIAL" "WIP" "FINISHED_GOOD" Where a product sits in the manufacturing flow: a purchased input ( |
| hsnCode | string <= 8 characters Optional HSN classification code for GST, printed on tax-invoice lines. Validated loosely (4-8 digits) — editable master data. |
| categoryId | integer <int64> Optional product-category reference. Must exist when supplied. |
| uomId required | integer <int64> Required unit-of-measure reference. Must exist. |
| materialId | integer <int64> Optional spare-face link — the material this product is the sellable face of. When set, the product carries no BOM and its stock draws from the linked material. Create-only: ignored on update. |
{- "sku": "FG-ST-001",
- "name": "Shell & Tube HX, SS316 Tubes, 4.5 m2, BEM Type",
- "type": "FINISHED_GOOD",
- "categoryId": 3,
- "uomId": 1
}{- "id": 42,
- "sku": "FG-ST-001",
- "name": "Shell & Tube HX, SS316 Tubes, 4.5 m2, BEM Type",
- "type": "RAW_MATERIAL",
- "hsnCode": "8419",
- "categoryId": 3,
- "categoryName": "Shell & Tube Exchangers",
- "uomId": 1,
- "uomCode": "NOS",
- "materialId": 88,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one product by id. Requires permission: MASTERDATA_READ.
| id required | integer <int64> Product id. |
{- "id": 42,
- "sku": "FG-ST-001",
- "name": "Shell & Tube HX, SS316 Tubes, 4.5 m2, BEM Type",
- "type": "RAW_MATERIAL",
- "hsnCode": "8419",
- "categoryId": 3,
- "categoryName": "Shell & Tube Exchangers",
- "uomId": 1,
- "uomCode": "NOS",
- "materialId": 88,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Updates an existing product. sku must remain unique; uomId (and categoryId when supplied) must reference existing rows. Subject to optimistic locking — a concurrent modification returns 409. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Product id. |
| sku required | string <= 60 characters Stock-keeping unit. Unique across all products. |
| name required | string <= 200 characters Human-readable product name. |
| type required | string (ProductType) Enum: "RAW_MATERIAL" "WIP" "FINISHED_GOOD" Where a product sits in the manufacturing flow: a purchased input ( |
| hsnCode | string <= 8 characters Optional HSN classification code for GST, printed on tax-invoice lines. Validated loosely (4-8 digits) — editable master data. |
| categoryId | integer <int64> Optional product-category reference. Must exist when supplied. |
| uomId required | integer <int64> Required unit-of-measure reference. Must exist. |
| materialId | integer <int64> Optional spare-face link — the material this product is the sellable face of. When set, the product carries no BOM and its stock draws from the linked material. Create-only: ignored on update. |
{- "sku": "FG-ST-001",
- "name": "Shell & Tube HX, SS316 Tubes, 4.5 m2, BEM Type",
- "type": "FINISHED_GOOD",
- "categoryId": 3,
- "uomId": 1
}{- "id": 42,
- "sku": "FG-ST-001",
- "name": "Shell & Tube HX, SS316 Tubes, 4.5 m2, BEM Type",
- "type": "RAW_MATERIAL",
- "hsnCode": "8419",
- "categoryId": 3,
- "categoryName": "Shell & Tube Exchangers",
- "uomId": 1,
- "uomCode": "NOS",
- "materialId": 88,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a product. A product still referenced by any other record (inventory, procurement, manufacturing, sales, or finance) cannot be deleted and returns 422 — remove or reassign the references first. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Product id. |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a paged list of product categories. Optionally filter by a free-text search term (case-insensitive LIKE over the category name). Requires permission: MASTERDATA_READ. Sortable fields (allow-list): name, createdAt; default sort is name,asc. Sorting by any other field returns 400.
| search | string Example: search=Exchangers Case-insensitive substring matched against the category name. Omit to match all. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 3,
- "name": "Shell & Tube Exchangers",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a product category. name must be unique. Requires permission: MASTERDATA_WRITE.
| name required | string <= 120 characters Category name. Unique across all categories. |
{- "name": "Shell & Tube Exchangers"
}{- "id": 3,
- "name": "Shell & Tube Exchangers",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one product category by id. Requires permission: MASTERDATA_READ.
| id required | integer <int64> Product category id. |
{- "id": 3,
- "name": "Shell & Tube Exchangers",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Updates a product category. name must remain unique. Subject to optimistic locking — a concurrent modification returns 409. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Product category id. |
| name required | string <= 120 characters Category name. Unique across all categories. |
{- "name": "Shell & Tube Exchangers"
}{- "id": 3,
- "name": "Shell & Tube Exchangers",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a product category. A category still assigned to one or more products cannot be deleted and returns 422 — reassign or remove those products first. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Product category id. |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a paged list of units of measure. Optionally filter by a free-text search term (case-insensitive LIKE over code and name). Requires permission: MASTERDATA_READ. Sortable fields (allow-list): code, name; default sort is code,asc. Sorting by any other field returns 400.
| search | string Example: search=KG Case-insensitive substring matched against code or name. Omit to match all. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 1,
- "code": "NOS",
- "name": "Numbers",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a unit of measure. code must be unique. Requires permission: MASTERDATA_WRITE.
| code required | string <= 20 characters Short unit code. Unique across all units. |
| name required | string <= 80 characters Full unit name. |
{- "code": "NOS",
- "name": "Numbers"
}{- "id": 1,
- "code": "NOS",
- "name": "Numbers",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one unit of measure by id. Requires permission: MASTERDATA_READ.
| id required | integer <int64> Unit-of-measure id. |
{- "id": 1,
- "code": "NOS",
- "name": "Numbers",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Updates a unit of measure. code must remain unique. Subject to optimistic locking — a concurrent modification returns 409. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Unit-of-measure id. |
| code required | string <= 20 characters Short unit code. Unique across all units. |
| name required | string <= 80 characters Full unit name. |
{- "code": "NOS",
- "name": "Numbers"
}{- "id": 1,
- "code": "NOS",
- "name": "Numbers",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a unit of measure. A unit still used by one or more products cannot be deleted and returns 422 — reassign or remove those products first. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Unit-of-measure id. |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a paged list of warehouses. Optionally filter by a free-text search term (case-insensitive LIKE over name and location). Requires permission: MASTERDATA_READ. Sortable fields (allow-list): name, location, createdAt; default sort is name,asc. Sorting by any other field returns 400.
| search | string Example: search=Chennai Case-insensitive substring matched against name or location. Omit to match all. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 1,
- "name": "Main Raw Material Store",
- "location": "Ambattur Industrial Estate, Chennai, TN",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a warehouse. name must be unique. Requires permission: MASTERDATA_WRITE.
| name required | string <= 120 characters Warehouse name. Unique across all warehouses. |
| location | string <= 255 characters Optional free-text physical location. |
{- "name": "Main Raw Material Store",
- "location": "Ambattur Industrial Estate, Chennai, TN"
}{- "id": 1,
- "name": "Main Raw Material Store",
- "location": "Ambattur Industrial Estate, Chennai, TN",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one warehouse by id. Requires permission: MASTERDATA_READ.
| id required | integer <int64> Warehouse id. |
{- "id": 1,
- "name": "Main Raw Material Store",
- "location": "Ambattur Industrial Estate, Chennai, TN",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Updates a warehouse. name must remain unique. Subject to optimistic locking — a concurrent modification returns 409. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Warehouse id. |
| name required | string <= 120 characters Warehouse name. Unique across all warehouses. |
| location | string <= 255 characters Optional free-text physical location. |
{- "name": "Main Raw Material Store",
- "location": "Ambattur Industrial Estate, Chennai, TN"
}{- "id": 1,
- "name": "Main Raw Material Store",
- "location": "Ambattur Industrial Estate, Chennai, TN",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a warehouse. A warehouse referenced by stock levels/movements, goods receipts, or orders cannot be deleted and returns 422 — remove or reassign those references first. Requires permission: MASTERDATA_WRITE.
| id required | integer <int64> Warehouse id. |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Stock levels (on-hand / reserved / QC-hold projection) and the append-only stock-movement ledger.
Paginated projection of current stock levels, one row per (item, warehouse). Each row exposes the three independent quantity dimensions: quantityOnHand (physically available and issuable), reserved (committed to confirmed sales orders, moved out of on-hand at confirm), and quantityQcHold (produced but not yet released by quality — invisible to availability until a quality PASS). Levels are always derived from the append-only movement ledger, never written directly.
Since the Phase-10 product/material split there are two parallel ledgers. kind (material/product, case-insensitive) selects which ledger to list, so each can be browsed in full without naming an item. When kind is absent it resolves from the item: productId here is a generic item id that routes to the material ledger when a material has that id, otherwise the product ledger (with neither kind nor productId, the product ledger is listed). A material row's id/sku/name come back in the productId/productSku/productName fields. Optionally filtered by productId and/or warehouseId (independent AND filters). Sortable fields: quantityOnHand, updatedAt (default updatedAt,desc); any other sort field returns 400.
Requires permission: INVENTORY_READ.
| kind | string Enum: "material" "product" Example: kind=material Which ledger to list — |
| productId | integer <int64> Example: productId=42 Restrict to a single item (material or product id). |
| warehouseId | integer <int64> Example: warehouseId=3 Restrict to a single warehouse. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 512,
- "productId": 42,
- "productSku": "FG-ST-001",
- "productName": "Structural Steel Bracket",
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "quantityOnHand": 1240,
- "reserved": 120,
- "quantityQcHold": 0,
- "updatedAt": "2026-07-09T11:02:44.113Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Returns the single stock-level row for the given (item, warehouse) pair — its on-hand, reserved, and QC-hold quantities. productId is a generic item id (Phase-10 split): a material id routes to the material ledger, otherwise the product ledger, and a material's id/sku/name come back in the product* fields. Returns 404 when no movement has ever been recorded for that pair (no level row exists yet). Both query parameters are required; a missing one is a 400.
Requires permission: INVENTORY_READ.
| productId required | integer <int64> Example: productId=42 The item to look up (material or product id). |
| warehouseId required | integer <int64> Example: warehouseId=3 The warehouse to look up. |
{- "id": 512,
- "productId": 42,
- "productSku": "FG-ST-001",
- "productName": "Structural Steel Bracket",
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "quantityOnHand": 1240,
- "reserved": 120,
- "quantityQcHold": 0,
- "updatedAt": "2026-07-09T11:02:44.113Z"
}Returns every warehouse in which the given material currently has positive on-hand stock (on-hand > 0), each with its on-hand quantity — the lookup behind a production planner's per-component source-warehouse picker, so only the stores that can actually supply a component are offered. Reads the material ledger only (a production component is always drawn from material stock). A material with no on-hand anywhere returns an empty array. The result is a plain array, not a paged response.
Requires permission: INVENTORY_READ or MASTERDATA_READ.
| materialId required | integer <int64> Example: materialId=42 The material to look up on-hand stock for, per warehouse. |
[- {
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "quantityOnHand": 1240
}, - {
- "warehouseId": 5,
- "warehouseName": "Overflow Store",
- "quantityOnHand": 60
}
]Paginated view of the append-only stock-movement ledger — the immutable, insert-only record of every quantity change (there is no update or delete). Each row carries a signed quantity (inbound positive, outbound negative), its movementType, and optional refType/refId lineage back to the source document (goods receipt, delivery, production or quality event) plus an optional lotNumber (heat number) for traceability.
Since the Phase-10 split there are two parallel ledgers. kind (material/product, case-insensitive) selects which ledger to list, so a whole ledger can be browsed without naming an item. When kind is absent it resolves from the item: productId is a generic item id that routes to the material ledger when a material has that id, otherwise the product ledger (with neither kind nor productId, the product ledger is listed), and a material row's id/sku/name come back in the productId/productSku/productName fields. Optionally filtered by productId, warehouseId, movementType, and/or the source-document reference (refType + refId) — independent AND filters. Filtering by refType/refId lists exactly the movements one document produced (e.g. a production order's issues and output). An unrecognised movementType value is a 400. Sortable fields: createdAt, movementType, quantity (default createdAt,desc); any other sort field returns 400.
Requires permission: INVENTORY_READ.
| kind | string Enum: "material" "product" Example: kind=material Which ledger to list — |
| productId | integer <int64> Example: productId=42 Restrict to a single item (material or product id). |
| warehouseId | integer <int64> Example: warehouseId=3 Restrict to a single warehouse. |
| movementType | string Enum: "RECEIPT" "ISSUE" "ADJUSTMENT" "PRODUCTION_ISSUE" "PRODUCTION_OUTPUT" "QC_RELEASE" "QC_REJECT" "SALES_SHIPMENT" Example: movementType=ADJUSTMENT Restrict to a single movement type. An unrecognised value returns 400. |
| refType | string Example: refType=PRODUCTION_ORDER Source-document type of the movement's lineage (e.g. |
| refId | integer <int64> Example: refId=7100 Source-document id of the movement's lineage; typically used together with |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 90233,
- "movementType": "ADJUSTMENT",
- "productId": 42,
- "productSku": "FG-ST-001",
- "productName": "Structural Steel Bracket",
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "quantity": -12,
- "refType": "ADJUSTMENT",
- "refId": null,
- "note": "Cycle count write-off — damaged units",
- "lotNumber": null,
- "createdBy": 387401,
- "createdAt": "2026-07-09T11:08:19.870Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Records an inbound RECEIPT movement: the positive quantity is added to on-hand for the (product, warehouse) pair. The ledger row and the atomic on-hand upsert happen in one transaction, so concurrent movements cannot lose an update. Inbound movements can never breach the no-negative-stock rule, so a receipt is always accepted. refType/refId optionally link the movement to a source document.
This is the manual entry point; the system-driven receipt from a goods receipt runs through an internal, non-HTTP entry point that stamps its own lineage. An unknown product or warehouse returns 404.
Requires permission: INVENTORY_WRITE.
| productId required | integer <int64> Item being moved (Phase-10 split) — a material id routes to material stock, otherwise product stock. |
| warehouseId required | integer <int64> Warehouse the movement applies to. |
| quantity required | number > 0 Positive amount to move (up to 15 integer digits, 4 fraction digits). |
| refType | string <= 30 characters Optional source-document type for lineage. |
| refId | integer <int64> Optional source-document identifier. |
{- "productId": 42,
- "warehouseId": 3,
- "quantity": 500,
- "refType": "GOODS_RECEIPT",
- "refId": 8801
}{- "id": 90231,
- "movementType": "RECEIPT",
- "productId": 42,
- "productSku": "FG-ST-001",
- "productName": "Structural Steel Bracket",
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "quantity": 500,
- "refType": "GOODS_RECEIPT",
- "refId": 8801,
- "note": null,
- "lotNumber": null,
- "createdBy": 387401,
- "createdAt": "2026-07-09T11:05:12.004Z"
}Records an outbound ISSUE movement: the positive quantity in the request is stored as a negative delta and subtracted from on-hand for the (product, warehouse) pair, atomically alongside the ledger insert. Guarded by the no-negative-stock rule — if the issue would drive on-hand below zero the whole transaction rolls back (no phantom movement is persisted) and the request returns 422. refType/refId optionally link the movement to a source document. An unknown product or warehouse returns 404.
Requires permission: INVENTORY_WRITE.
| productId required | integer <int64> Item being moved (Phase-10 split) — a material id routes to material stock, otherwise product stock. |
| warehouseId required | integer <int64> Warehouse the movement applies to. |
| quantity required | number > 0 Positive amount to move (up to 15 integer digits, 4 fraction digits). |
| refType | string <= 30 characters Optional source-document type for lineage. |
| refId | integer <int64> Optional source-document identifier. |
{- "productId": 42,
- "warehouseId": 3,
- "quantity": 20,
- "refType": "DELIVERY",
- "refId": 4410
}{- "id": 90232,
- "movementType": "ISSUE",
- "productId": 42,
- "productSku": "FG-ST-001",
- "productName": "Structural Steel Bracket",
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "quantity": -20,
- "refType": "DELIVERY",
- "refId": 4410,
- "note": null,
- "lotNumber": null,
- "createdBy": 387401,
- "createdAt": "2026-07-09T11:06:41.552Z"
}Records a manual ADJUSTMENT movement — a signed correction such as a write-off (negative) or a recount correction (positive). Unlike a receipt or issue, quantity here is a signed delta and MAY drive on-hand to any value, including negative, so the no-negative-stock rule does not apply. The quantity must be non-zero (a zero adjustment returns 422). The optional reason is recorded on the ledger row for the audit trail; refType is stamped as ADJUSTMENT. An unknown product or warehouse returns 404.
This is the segregated, higher-privilege write: it is gated by STOCK_ADJUST, separate from the ordinary INVENTORY_WRITE used for receipts and issues.
Requires permission: STOCK_ADJUST.
| productId required | integer <int64> Item being adjusted (Phase-10 split) — a material id routes to material stock, otherwise product stock. |
| warehouseId required | integer <int64> Warehouse the adjustment applies to. |
| quantity required | number Signed, non-zero delta (up to 15 integer digits, 4 fraction digits). Negative writes off, positive corrects up. |
| reason | string <= 255 characters Optional reason recorded on the ledger row for the audit trail. |
{- "productId": 42,
- "warehouseId": 3,
- "quantity": -12,
- "reason": "Cycle count write-off — damaged units"
}{- "id": 90233,
- "movementType": "ADJUSTMENT",
- "productId": 42,
- "productSku": "FG-ST-001",
- "productName": "Structural Steel Bracket",
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "quantity": -12,
- "refType": "ADJUSTMENT",
- "refId": null,
- "note": "Cycle count write-off — damaged units",
- "lotNumber": null,
- "createdBy": 387401,
- "createdAt": "2026-07-09T11:08:19.870Z"
}Returns a paginated page of engineering design documents (drawings/specs). Optionally filter by target (productId or materialId — a document targets a product XOR a material) and/or status (independent AND filters). Sortable fields: revision, status, createdAt (default sort createdAt,desc); an unlisted sort field returns 400. Requires permission: DESIGN_READ.
| productId | integer <int64> Only documents targeting this product. |
| materialId | integer <int64> Only documents targeting this material (sub-assembly). |
| status | string (DesignStatus) Enum: "DRAFT" "IN_REVIEW" "CHANGES_REQUESTED" "RELEASED" Example: status=DRAFT Only documents in this lifecycle state. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 501,
- "productId": 42,
- "productSku": "HX-1200",
- "materialId": 88,
- "materialSku": "SS316-TUBE-19",
- "revision": "1.0",
- "title": "Shell & Tube HX GA Drawing",
- "status": "DRAFT",
- "createdBy": 51001,
- "createdByName": "dana.designer",
- "submittedBy": 51001,
- "submittedByName": "dana.designer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 51007,
- "approvedByName": "raj.designmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "changesRequestedBy": 51007,
- "changesRequestedByName": "raj.designmgr",
- "changesRequestedAt": "2019-08-24T14:15:22Z",
- "createdAt": "2026-07-09T14:12:03.221Z",
- "updatedAt": "2026-07-09T14:12:03.221Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a new design document. It is always created in DRAFT status; the status cannot be set through this payload — a document moves through its review lifecycle only via the submit / release / request-changes / revise endpoints. The revision is assigned by the system (1.0 for the target item's first document, then the next whole number) and cannot be supplied. The referenced product must exist (else 404). Requires permission: DESIGN_WRITE.
| productId | integer <int64> Product target (exactly one of productId / materialId). Set when the document designs a sellable product. |
| materialId | integer <int64> Material target (exactly one of productId / materialId). Set when the document designs a manufacturable material (sub-assembly). |
| title required | string <= 200 characters Human-readable document title. |
{- "productId": 42,
- "title": "Shell & Tube HX GA Drawing"
}{- "id": 501,
- "productId": 42,
- "productSku": "HX-1200",
- "revision": "1.0",
- "title": "Shell & Tube HX GA Drawing",
- "status": "DRAFT",
- "createdAt": "2026-07-09T14:12:03.221Z",
- "updatedAt": "2026-07-09T14:12:03.221Z"
}The revision a create would assign for a target item — 1.0 for its first design document, then the next whole number (2.0, 3.0, …). Supply exactly one of productId / materialId (zero or both is a 422). Lets the create form show the read-only revision before saving; it uses the same computation as create. Requires permission: DESIGN_WRITE.
| productId | integer <int64> Product target (exactly one of productId / materialId). |
| materialId | integer <int64> Material target (exactly one of productId / materialId). |
{- "revision": "2.0"
}Returns a single design document by id. Requires permission: DESIGN_READ.
| id required | integer <int64> Design document id. |
{- "id": 501,
- "productId": 42,
- "productSku": "HX-1200",
- "materialId": 88,
- "materialSku": "SS316-TUBE-19",
- "revision": "1.0",
- "title": "Shell & Tube HX GA Drawing",
- "status": "DRAFT",
- "createdBy": 51001,
- "createdByName": "dana.designer",
- "submittedBy": 51001,
- "submittedByName": "dana.designer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 51007,
- "approvedByName": "raj.designmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "changesRequestedBy": 51007,
- "changesRequestedByName": "raj.designmgr",
- "changesRequestedAt": "2019-08-24T14:15:22Z",
- "createdAt": "2026-07-09T14:12:03.221Z",
- "updatedAt": "2026-07-09T14:12:03.221Z"
}Updates a design document — allowed only while it is DRAFT. Once submitted it is under review, and a RELEASED document is a controlled record; editing in any non-draft state returns 422 (revise a CHANGES_REQUESTED document back to DRAFT, or supersede a release with a new revision, first). The referenced product must exist (else 404). Requires permission: DESIGN_WRITE.
| id required | integer <int64> Design document id. |
| productId | integer <int64> Product target (exactly one of productId / materialId). Set when the document designs a sellable product. |
| materialId | integer <int64> Material target (exactly one of productId / materialId). Set when the document designs a manufacturable material (sub-assembly). |
| title required | string <= 200 characters Human-readable document title. |
{- "productId": 42,
- "title": "Shell & Tube HX GA Drawing (updated)"
}{- "id": 501,
- "productId": 42,
- "productSku": "HX-1200",
- "materialId": 88,
- "materialSku": "SS316-TUBE-19",
- "revision": "1.0",
- "title": "Shell & Tube HX GA Drawing",
- "status": "DRAFT",
- "createdBy": 51001,
- "createdByName": "dana.designer",
- "submittedBy": 51001,
- "submittedByName": "dana.designer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 51007,
- "approvedByName": "raj.designmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "changesRequestedBy": 51007,
- "changesRequestedByName": "raj.designmgr",
- "changesRequestedAt": "2019-08-24T14:15:22Z",
- "createdAt": "2026-07-09T14:12:03.221Z",
- "updatedAt": "2026-07-09T14:12:03.221Z"
}Deletes a design document — allowed only while it is DRAFT. A document under review is mid-decision, and a RELEASED document is a controlled record that may be referenced by downstream production, quality, or procurement records; deleting in any non-draft state returns 422. Requires permission: DESIGN_WRITE.
| id required | integer <int64> Design document id. |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Approves and releases a document under review, transitioning it IN_REVIEW → RELEASED. Segregation of duties is enforced two ways: DESIGN_APPROVE is required (a DESIGN_WRITE author gets 403) and a user may not release a document they authored (self-release → 422). Only a document currently IN_REVIEW can be released — any other state returns 422. Once released the document is immutable and its BOM locks. Requires permission: DESIGN_APPROVE.
| id required | integer <int64> Design document id. |
{- "id": 501,
- "productId": 42,
- "productSku": "HX-1200",
- "revision": "1.0",
- "title": "Shell & Tube HX GA Drawing",
- "status": "RELEASED",
- "createdAt": "2026-07-09T14:12:03.221Z",
- "updatedAt": "2026-07-09T15:02:41.108Z"
}Submits a draft for review, transitioning it DRAFT → IN_REVIEW and stamping the submitter. Only a DRAFT document can be submitted — any other state returns 422. Requires permission: DESIGN_WRITE.
| id required | integer <int64> Design document id. |
{- "id": 501,
- "productId": 42,
- "productSku": "HX-1200",
- "materialId": 88,
- "materialSku": "SS316-TUBE-19",
- "revision": "1.0",
- "title": "Shell & Tube HX GA Drawing",
- "status": "DRAFT",
- "createdBy": 51001,
- "createdByName": "dana.designer",
- "submittedBy": 51001,
- "submittedByName": "dana.designer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 51007,
- "approvedByName": "raj.designmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "changesRequestedBy": 51007,
- "changesRequestedByName": "raj.designmgr",
- "changesRequestedAt": "2019-08-24T14:15:22Z",
- "createdAt": "2026-07-09T14:12:03.221Z",
- "updatedAt": "2026-07-09T14:12:03.221Z"
}A reviewer sends a document under review back for rework, transitioning it IN_REVIEW → CHANGES_REQUESTED. The decision must carry a justification (body, non-blank), recorded as a review remark in the same transaction. Only an IN_REVIEW document is eligible — any other state returns 422. Requires permission: DESIGN_APPROVE.
| id required | integer <int64> Design document id. |
| body required | string <= 4000 characters The remark text. |
{- "body": "Wall thickness on nozzle N2 is below the design pressure requirement; revise and resubmit."
}{- "id": 501,
- "productId": 42,
- "productSku": "HX-1200",
- "materialId": 88,
- "materialSku": "SS316-TUBE-19",
- "revision": "1.0",
- "title": "Shell & Tube HX GA Drawing",
- "status": "DRAFT",
- "createdBy": 51001,
- "createdByName": "dana.designer",
- "submittedBy": 51001,
- "submittedByName": "dana.designer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 51007,
- "approvedByName": "raj.designmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "changesRequestedBy": 51007,
- "changesRequestedByName": "raj.designmgr",
- "changesRequestedAt": "2019-08-24T14:15:22Z",
- "createdAt": "2026-07-09T14:12:03.221Z",
- "updatedAt": "2026-07-09T14:12:03.221Z"
}Reopens a document that had changes requested, transitioning it CHANGES_REQUESTED → DRAFT so the author can edit and resubmit. Only a CHANGES_REQUESTED document is eligible — any other state returns 422. Requires permission: DESIGN_WRITE.
| id required | integer <int64> Design document id. |
{- "id": 501,
- "productId": 42,
- "productSku": "HX-1200",
- "materialId": 88,
- "materialSku": "SS316-TUBE-19",
- "revision": "1.0",
- "title": "Shell & Tube HX GA Drawing",
- "status": "DRAFT",
- "createdBy": 51001,
- "createdByName": "dana.designer",
- "submittedBy": 51001,
- "submittedByName": "dana.designer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 51007,
- "approvedByName": "raj.designmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "changesRequestedBy": 51007,
- "changesRequestedByName": "raj.designmgr",
- "changesRequestedAt": "2019-08-24T14:15:22Z",
- "createdAt": "2026-07-09T14:12:03.221Z",
- "updatedAt": "2026-07-09T14:12:03.221Z"
}Returns a paginated page of review remarks on a design document, each with its resolved author username (default sort newest first). Requires permission: DESIGN_READ.
| documentId required | integer <int64> Design document id. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 8801,
- "designDocumentId": 501,
- "body": "Approved subject to the corrosion allowance being called out on sheet 2.",
- "author": 51007,
- "authorName": "raj.designmgr",
- "createdAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Posts a free-text review remark against a design document (a reviewer decision). The body is required and non-blank. Requires permission: DESIGN_APPROVE.
| documentId required | integer <int64> Design document id. |
| body required | string <= 4000 characters The remark text. |
{- "body": "Approved subject to the corrosion allowance being called out on sheet 2."
}{- "id": 8801,
- "designDocumentId": 501,
- "body": "Approved subject to the corrosion allowance being called out on sheet 2.",
- "author": 51007,
- "authorName": "raj.designmgr",
- "createdAt": "2019-08-24T14:15:22Z"
}Returns a paginated page of attachment metadata for one owning entity, identified by ownerType + ownerId. Bytes are not returned here — only metadata; use the download endpoint for the file itself. Sortable fields: fileName, sizeBytes, createdAt (default sort createdAt,desc); an unlisted sort field returns 400. Authorization is derived from the owning entity: requires that owner's view permission — DESIGN_READ for a DESIGN_DOCUMENT owner, MASTERDATA_READ for a PRODUCT owner.
| ownerType required | string Example: ownerType=DESIGN_DOCUMENT Owning entity type, e.g. |
| ownerId required | integer <int64> Example: ownerId=501 Id of the owning entity. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 9001,
- "ownerType": "DESIGN_DOCUMENT",
- "ownerId": 501,
- "fileName": "HX-GA-RevA.pdf",
- "contentType": "application/pdf",
- "sizeBytes": 284913,
- "checksum": "9f2c1e7a4b3d4f8e9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f",
- "uploadedBy": 387401,
- "createdAt": "2026-07-09T14:12:03.221Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Uploads a file and attaches it to the owning entity identified by ownerType + ownerId. The bytes are streamed to object storage; only metadata (name, content type, size, SHA-256 checksum, storage key, uploader) is persisted in the database. The owning entity must exist (else 404) and the uploaded file must be non-empty (an empty file, or an unsupported ownerType, returns 422). Authorization is derived from the owning entity: requires that owner's manage permission — DESIGN_WRITE for a DESIGN_DOCUMENT owner, MASTERDATA_WRITE for a PRODUCT owner.
| file required | string <binary> The file bytes to store. |
| ownerType required | string Owning entity type, e.g. |
| ownerId required | integer <int64> Id of the owning entity. |
{- "id": 9001,
- "ownerType": "DESIGN_DOCUMENT",
- "ownerId": 501,
- "fileName": "HX-GA-RevA.pdf",
- "contentType": "application/pdf",
- "sizeBytes": 284913,
- "checksum": "9f2c1e7a4b3d4f8e9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f",
- "uploadedBy": 387401,
- "createdAt": "2026-07-09T14:12:03.221Z"
}Streams the raw file bytes for an attachment. The response is the binary content with a Content-Disposition: attachment header carrying the original file name; the content type is the stored MIME type (falling back to application/octet-stream). Authorization is derived from the owning entity: requires the same view permission as viewing that entity — DESIGN_READ for a DESIGN_DOCUMENT owner, MASTERDATA_READ for a PRODUCT owner — so a user who cannot see the parent cannot reach its files even by guessing an attachment id.
| id required | integer <int64> Attachment id. |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Deletes an attachment's metadata and its stored bytes. Authorization is derived from the owning entity: requires that owner's manage permission — DESIGN_WRITE for a DESIGN_DOCUMENT owner, MASTERDATA_WRITE for a PRODUCT owner.
| id required | integer <int64> Attachment id. |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Return a paged list of suppliers. Requires permission: PROCUREMENT_READ. Sortable fields: name, active, createdAt (default createdAt,desc); any other sort field returns 400.
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 42,
- "name": "Bharat Steel Tubes Pvt Ltd",
- "email": "sales@bharatsteeltubes.example",
- "phone": "+91 22 4000 1234",
- "stateCode": "27",
- "gstin": "27ABCDE1234F1Z5",
- "pan": "AABCB1234C",
- "isIndividual": false,
- "defaultTdsSectionId": 4,
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Create a supplier. Requires permission: SUPPLIER_WRITE. The supplier name must be unique (duplicate → 409). pan, isIndividual and defaultTdsSectionId drive TDS on this vendor's payments (Phase 7D).
| name required | string <= 200 characters Supplier name; must be unique. |
string <email> <= 255 characters Contact email. | |
| phone | string <= 40 characters Contact phone. |
| stateCode | string = 2 characters Two-digit GST state code of the supplier. |
| gstin | string <= 15 characters Optional 15-character GST registration number, printed on purchase invoices. Validated loosely (15 alphanumerics) — editable master data. |
| pan | string <= 20 characters Vendor PAN; drives TDS on payments (Phase 7D). |
| isIndividual | boolean Whether the vendor is an individual (affects the applicable TDS rate). |
| defaultTdsSectionId | integer <int64> Default TDS section applied to this vendor's payments. |
| active | boolean Whether the supplier is active. |
{- "name": "Bharat Steel Tubes Pvt Ltd",
- "email": "sales@bharatsteeltubes.example",
- "phone": "+91 22 4000 1234",
- "stateCode": "27",
- "pan": "AABCB1234C",
- "isIndividual": false,
- "active": true
}{- "id": 42,
- "name": "Bharat Steel Tubes Pvt Ltd",
- "email": "sales@bharatsteeltubes.example",
- "phone": "+91 22 4000 1234",
- "stateCode": "27",
- "gstin": "27ABCDE1234F1Z5",
- "pan": "AABCB1234C",
- "isIndividual": false,
- "defaultTdsSectionId": 4,
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Fetch one supplier by id. Requires permission: PROCUREMENT_READ.
| id required | integer <int64> |
{- "id": 42,
- "name": "Bharat Steel Tubes Pvt Ltd",
- "email": "sales@bharatsteeltubes.example",
- "phone": "+91 22 4000 1234",
- "stateCode": "27",
- "gstin": "27ABCDE1234F1Z5",
- "pan": "AABCB1234C",
- "isIndividual": false,
- "defaultTdsSectionId": 4,
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replace a supplier's fields. Requires permission: SUPPLIER_WRITE. The name must stay unique (duplicate → 409); a concurrent modification of the same row fails optimistic locking (409, reload and retry). Omitting active/isIndividual leaves the current value unchanged.
| id required | integer <int64> |
| name required | string <= 200 characters Supplier name; must be unique. |
string <email> <= 255 characters Contact email. | |
| phone | string <= 40 characters Contact phone. |
| stateCode | string = 2 characters Two-digit GST state code of the supplier. |
| gstin | string <= 15 characters Optional 15-character GST registration number, printed on purchase invoices. Validated loosely (15 alphanumerics) — editable master data. |
| pan | string <= 20 characters Vendor PAN; drives TDS on payments (Phase 7D). |
| isIndividual | boolean Whether the vendor is an individual (affects the applicable TDS rate). |
| defaultTdsSectionId | integer <int64> Default TDS section applied to this vendor's payments. |
| active | boolean Whether the supplier is active. |
{- "name": "Bharat Steel Tubes Pvt Ltd",
- "email": "accounts@bharatsteeltubes.example",
- "phone": "+91 22 4000 5678",
- "stateCode": "27",
- "active": true
}{- "id": 42,
- "name": "Bharat Steel Tubes Pvt Ltd",
- "email": "sales@bharatsteeltubes.example",
- "phone": "+91 22 4000 1234",
- "stateCode": "27",
- "gstin": "27ABCDE1234F1Z5",
- "pan": "AABCB1234C",
- "isIndividual": false,
- "defaultTdsSectionId": 4,
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Delete a supplier. Requires permission: SUPPLIER_WRITE. A supplier referenced by any purchase order is part of that order's record and cannot be deleted — deactivate it instead (422). Deleting a supplier with no orders cascade-removes its catalog rows.
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Return a paged list of the supplier's product catalog entries (supplier SKU, unit price, lead time). Requires permission: PROCUREMENT_READ. Scoped to the supplier — an entry belonging to another supplier is a 404. Sortable fields: unitPrice, leadTimeDays, createdAt (default createdAt,desc); any other sort field returns 400.
| supplierId required | integer <int64> |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 128,
- "supplierId": 42,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "uomCode": "M",
- "supplierSku": "BST-SS304-25NB",
- "unitPrice": 4500,
- "leadTimeDays": 14,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Add a product to the supplier's catalog with its commercial terms. Requires permission: SUPPLIER_WRITE. A product may appear at most once per supplier (duplicate supplier+product → 409). The product must exist (else 404).
| supplierId required | integer <int64> |
| materialId required | integer <int64> The material this catalog entry prices; fixed once created. |
| supplierSku | string <= 60 characters The supplier's own SKU for the material. |
| unitPrice required | number >= 0 Catalogued unit price for the material from this supplier. |
| leadTimeDays | integer >= 0 Quoted lead time in days. |
{- "materialId": 305,
- "supplierSku": "BST-SS304-25NB",
- "unitPrice": 4500,
- "leadTimeDays": 14
}{- "id": 128,
- "supplierId": 42,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "uomCode": "M",
- "supplierSku": "BST-SS304-25NB",
- "unitPrice": 4500,
- "leadTimeDays": 14,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Revise a catalog entry's commercial terms (supplier SKU, unit price, lead time). Requires permission: SUPPLIER_WRITE. The entry's product is fixed once created — changing productId returns 422 (remove the entry and add a new one). A concurrent modification of the same row fails optimistic locking (409).
| supplierId required | integer <int64> |
| entryId required | integer <int64> |
| materialId required | integer <int64> The material this catalog entry prices; fixed once created. |
| supplierSku | string <= 60 characters The supplier's own SKU for the material. |
| unitPrice required | number >= 0 Catalogued unit price for the material from this supplier. |
| leadTimeDays | integer >= 0 Quoted lead time in days. |
{- "materialId": 305,
- "supplierSku": "BST-SS304-25NB",
- "unitPrice": 4650,
- "leadTimeDays": 10
}{- "id": 128,
- "supplierId": 42,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "uomCode": "M",
- "supplierSku": "BST-SS304-25NB",
- "unitPrice": 4500,
- "leadTimeDays": 14,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Remove a product from the supplier's catalog. Requires permission: SUPPLIER_WRITE. Scoped to the supplier — an entry belonging to another supplier is a 404.
| supplierId required | integer <int64> |
| entryId required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Return a paged list of purchase-order summaries (header plus derived total, without the line array). Requires permission: PROCUREMENT_READ. Optionally filter by supplierId and/or status. Sortable fields: orderDate, status, createdAt (default createdAt,desc); any other sort field returns 400.
| supplierId | integer <int64> Filter to purchase orders for this supplier. |
| status | string (PurchaseOrderStatus) Enum: "DRAFT" "SUBMITTED" "APPROVED" "PARTIALLY_RECEIVED" "CLOSED" "CANCELLED" Example: status=DRAFT Filter to purchase orders in this lifecycle state. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 1234,
- "supplierId": 42,
- "supplierName": "Bharat Steel Tubes Pvt Ltd",
- "status": "DRAFT",
- "orderDate": "2026-06-15",
- "total": 540000,
- "createdBy": 38740,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Raise a new purchase order in DRAFT. Requires permission: PROCUREMENT_WRITE. A PO must carry at least one line, and every line may only order a product that exists in the ordering supplier's catalog — a product not in the catalog is rejected (422). A line's unitPrice defaults to the catalogued price when omitted, and is then fixed on the line. The supplier must exist (else 404).
| supplierId required | integer <int64> The supplier to order from. |
| orderDate required | string <date> The order date. |
required | Array of objects (PurchaseOrderLineRequest) non-empty The order lines (at least one). |
{- "supplierId": 42,
- "orderDate": "2026-06-15",
- "lines": [
- {
- "materialId": 305,
- "orderedQuantity": 120,
- "unitPrice": 4500
}, - {
- "materialId": 307,
- "orderedQuantity": 40
}
]
}{- "id": 1234,
- "supplierId": 42,
- "supplierName": "Bharat Steel Tubes Pvt Ltd",
- "status": "DRAFT",
- "orderDate": "2026-06-15",
- "total": 540000,
- "createdBy": 38740,
- "createdByName": "ravi.buyer",
- "submittedBy": 38741,
- "submittedByName": "ravi.buyer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 38742,
- "approvedByName": "meena.procmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "lines": [
- {
- "id": 5001,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "orderedQuantity": 120,
- "unitPrice": 4500,
- "receivedQuantity": 0,
- "lineTotal": 540000
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Fetch one purchase order in full — header, derived total, the lines, and the full who-did-what trail (raiser, submitter, and approver, each with a resolved username and the submit/approve timestamps). Requires permission: PROCUREMENT_READ.
| id required | integer <int64> |
{- "id": 1234,
- "supplierId": 42,
- "supplierName": "Bharat Steel Tubes Pvt Ltd",
- "status": "DRAFT",
- "orderDate": "2026-06-15",
- "total": 540000,
- "createdBy": 38740,
- "createdByName": "ravi.buyer",
- "submittedBy": 38741,
- "submittedByName": "ravi.buyer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 38742,
- "approvedByName": "meena.procmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "lines": [
- {
- "id": 5001,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "orderedQuantity": 120,
- "unitPrice": 4500,
- "receivedQuantity": 0,
- "lineTotal": 540000
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replace a purchase order's header and lines. Requires permission: PROCUREMENT_WRITE. Only a DRAFT order is editable — a SUBMITTED or APPROVED order is locked and returns 422 (cancel and re-raise instead). Every line's product must be in the supplier's catalog (else 422). A concurrent modification of the same row fails optimistic locking (409).
| id required | integer <int64> |
| supplierId required | integer <int64> The supplier to order from. |
| orderDate required | string <date> The order date. |
required | Array of objects (PurchaseOrderLineRequest) non-empty The order lines (at least one). |
{- "supplierId": 42,
- "orderDate": "2026-06-15",
- "lines": [
- {
- "materialId": 305,
- "orderedQuantity": 150,
- "unitPrice": 4500
}
]
}{- "id": 1234,
- "supplierId": 42,
- "supplierName": "Bharat Steel Tubes Pvt Ltd",
- "status": "DRAFT",
- "orderDate": "2026-06-15",
- "total": 540000,
- "createdBy": 38740,
- "createdByName": "ravi.buyer",
- "submittedBy": 38741,
- "submittedByName": "ravi.buyer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 38742,
- "approvedByName": "meena.procmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "lines": [
- {
- "id": 5001,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "orderedQuantity": 120,
- "unitPrice": 4500,
- "receivedQuantity": 0,
- "lineTotal": 540000
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Transition a purchase order DRAFT → SUBMITTED, committing it for approval. Requires permission: PROCUREMENT_WRITE. Only a DRAFT order can be submitted; any other state returns 422. A concurrent modification of the same row fails optimistic locking (409).
| id required | integer <int64> |
{- "id": 1234,
- "supplierId": 42,
- "supplierName": "Bharat Steel Tubes Pvt Ltd",
- "status": "DRAFT",
- "orderDate": "2026-06-15",
- "total": 540000,
- "createdBy": 38740,
- "createdByName": "ravi.buyer",
- "submittedBy": 38741,
- "submittedByName": "ravi.buyer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 38742,
- "approvedByName": "meena.procmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "lines": [
- {
- "id": 5001,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "orderedQuantity": 120,
- "unitPrice": 4500,
- "receivedQuantity": 0,
- "lineTotal": 540000
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Transition a purchase order SUBMITTED → APPROVED. Requires permission: PO_APPROVE — a buyer holding only PROCUREMENT_WRITE is rejected with 403. Segregation of duties: a user may not approve a purchase order they raised themselves (self-approval → 422), forcing a different approver. Only a SUBMITTED order can be approved; any other state returns 422. Once APPROVED the order is immutable (edit → 422; cancel instead). A concurrent modification of the same row fails optimistic locking (409).
| id required | integer <int64> |
{- "id": 1234,
- "supplierId": 42,
- "supplierName": "Bharat Steel Tubes Pvt Ltd",
- "status": "DRAFT",
- "orderDate": "2026-06-15",
- "total": 540000,
- "createdBy": 38740,
- "createdByName": "ravi.buyer",
- "submittedBy": 38741,
- "submittedByName": "ravi.buyer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 38742,
- "approvedByName": "meena.procmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "lines": [
- {
- "id": 5001,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "orderedQuantity": 120,
- "unitPrice": 4500,
- "receivedQuantity": 0,
- "lineTotal": 540000
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Transition a purchase order to CANCELLED. Requires permission: PROCUREMENT_WRITE. Cancellable only before any goods are received — a PARTIALLY_RECEIVED, CLOSED, or already CANCELLED order cannot be cancelled (422). Cancel is the way to retire an APPROVED order, since APPROVED orders are immutable. A concurrent modification of the same row fails optimistic locking (409).
| id required | integer <int64> |
{- "id": 1234,
- "supplierId": 42,
- "supplierName": "Bharat Steel Tubes Pvt Ltd",
- "status": "DRAFT",
- "orderDate": "2026-06-15",
- "total": 540000,
- "createdBy": 38740,
- "createdByName": "ravi.buyer",
- "submittedBy": 38741,
- "submittedByName": "ravi.buyer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 38742,
- "approvedByName": "meena.procmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "lines": [
- {
- "id": 5001,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "orderedQuantity": 120,
- "unitPrice": 4500,
- "receivedQuantity": 0,
- "lineTotal": 540000
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Return a paged list of goods-receipt summaries (header without the line array). Requires permission: PROCUREMENT_READ. Optionally filter by poId. Sortable fields: receivedDate, createdAt (default createdAt,desc); any other sort field returns 400.
| poId | integer <int64> Filter to receipts recorded against this purchase order. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 900,
- "poId": 1234,
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "receivedDate": "2026-06-20",
- "createdBy": 38740,
- "createdAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Record a delivery received against a purchase order into a destination warehouse. Requires permission: GOODS_RECEIPT_WRITE. Goods can only be received against an APPROVED or PARTIALLY_RECEIVED order (any other state → 422). The whole receive flow is one transaction: it writes the immutable, append-only receipt, atomically accumulates each PO line's received quantity (receiving more than the ordered quantity → 422, and rolls the whole receipt back), raises RECEIPT stock movements into the warehouse through the inventory service (stamped with this receipt's ref), and auto-transitions the PO to PARTIALLY_RECEIVED or CLOSED once every line is fully received. Goods receipts are immutable once recorded (no edit/delete; corrections via reversal are deferred). The PO and warehouse must exist (else 404); a receipt line whose poLineId does not belong to the PO → 422.
| poId required | integer <int64> The purchase order being received against (must be APPROVED or PARTIALLY_RECEIVED). |
| warehouseId required | integer <int64> Destination warehouse for the received stock. |
| receivedDate required | string <date> The date the goods were received. |
required | Array of objects (GoodsReceiptLineRequest) non-empty The received lines (at least one). |
{- "poId": 1234,
- "warehouseId": 3,
- "receivedDate": "2026-06-20",
- "lines": [
- {
- "poLineId": 5001,
- "receivedQuantity": 120
}
]
}{- "id": 900,
- "poId": 1234,
- "supplierId": 42,
- "supplierName": "Bharat Steel Tubes Pvt Ltd",
- "orderDate": "2026-06-15",
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "receivedDate": "2026-06-20",
- "createdBy": 38743,
- "filedByName": "ravi.buyer",
- "submittedByName": "ravi.buyer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedByName": "meena.procmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "receivedByName": "kiran.clerk",
- "lines": [
- {
- "id": 7001,
- "poLineId": 5001,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "receivedQuantity": 120,
- "unitPrice": 4500,
- "lineTotal": 540000
}
], - "createdAt": "2019-08-24T14:15:22Z"
}Fetch one goods receipt in full — the GRN: its header, the purchase-order context it was received against (supplier, order date, priced lines), and the who-did-what trail (who filed, submitted, approved, and received). Requires permission: PROCUREMENT_READ. Unknown id → 404.
| id required | integer <int64> |
{- "id": 900,
- "poId": 1234,
- "supplierId": 42,
- "supplierName": "Bharat Steel Tubes Pvt Ltd",
- "orderDate": "2026-06-15",
- "warehouseId": 3,
- "warehouseName": "Main Raw Material Store",
- "receivedDate": "2026-06-20",
- "createdBy": 38743,
- "filedByName": "ravi.buyer",
- "submittedByName": "ravi.buyer",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedByName": "meena.procmgr",
- "approvedAt": "2019-08-24T14:15:22Z",
- "receivedByName": "kiran.clerk",
- "lines": [
- {
- "id": 7001,
- "poLineId": 5001,
- "materialId": 305,
- "materialSku": "SS304-25NB",
- "materialName": "Stainless Steel Tube 304 25NB",
- "receivedQuantity": 120,
- "unitPrice": 4500,
- "lineTotal": 540000
}
], - "createdAt": "2019-08-24T14:15:22Z"
}Generate the goods-receipt note (GRN) for this receipt on the fly and stream it as a downloadable PDF. Requires permission: PROCUREMENT_READ — the same permission as viewing the receipt, so no file is reachable without it. The response is application/pdf with a Content-Disposition: attachment; filename="GRN-{id}.pdf" header. Unknown id → 404. Nothing is stored: the PDF is rendered per request from the current receipt data.
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a page of bills of materials (summary rows with a derived line count). Requires permission: DESIGN_READ. Filter by designDocumentId, active, and/or the target being produced (productId or materialId — a BOM produces a product XOR a material, resolved through its design document).
| designDocumentId | integer <int64> |
| active | boolean |
| productId | integer <int64> Only BOMs that produce this product. |
| materialId | integer <int64> Only BOMs that produce this material (sub-assembly). |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "designDocumentId": 0,
- "designDocumentRevision": "string",
- "productId": 0,
- "productSku": "string",
- "materialId": 0,
- "materialSku": "string",
- "designStatus": "DRAFT",
- "active": true,
- "lineCount": 0,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a bill of materials under a design document. Requires permission: DESIGN_WRITE. The BOM is authored/edited only while its design document is DRAFT; it locks when the document is RELEASED. Must have at least one component line. Duplicate version for the same document → 409.
| designDocumentId required | integer <int64> Owning design document (must be DRAFT to edit; one BOM per document). |
| active | boolean Optional; defaults active on create, unchanged on update. |
required | Array of objects (BomLineRequest) non-empty |
{- "designDocumentId": 387300,
- "active": true,
- "lines": [
- {
- "componentMaterialId": 387120,
- "quantityPerUnit": 120,
- "sourceWarehouseId": 387060
}, - {
- "componentMaterialId": 387124,
- "quantityPerUnit": 2
}
]
}{- "id": 0,
- "designDocumentId": 0,
- "designDocumentRevision": "string",
- "designStatus": "DRAFT",
- "productId": 0,
- "productSku": "string",
- "materialId": 0,
- "materialSku": "string",
- "active": true,
- "lines": [
- {
- "id": 0,
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantityPerUnit": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one BOM with its component lines and the owning document's release status. Requires permission: DESIGN_READ.
| id required | integer <int64> |
{- "id": 0,
- "designDocumentId": 0,
- "designDocumentRevision": "string",
- "designStatus": "DRAFT",
- "productId": 0,
- "productSku": "string",
- "materialId": 0,
- "materialSku": "string",
- "active": true,
- "lines": [
- {
- "id": 0,
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantityPerUnit": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a BOM's version/active flag and lines (as a set). Requires permission: DESIGN_WRITE. Permitted only while the owning design document is DRAFT — once the document leaves DRAFT (in review, changes-requested, or released) the BOM is locked (422). designDocumentId must match the BOM's existing document (a BOM cannot be re-parented).
| id required | integer <int64> |
| designDocumentId required | integer <int64> Owning design document (must be DRAFT to edit; one BOM per document). |
| active | boolean Optional; defaults active on create, unchanged on update. |
required | Array of objects (BomLineRequest) non-empty |
{- "designDocumentId": 0,
- "active": true,
- "lines": [
- {
- "componentMaterialId": 0,
- "quantityPerUnit": 0,
- "sourceWarehouseId": 0
}
]
}{- "id": 0,
- "designDocumentId": 0,
- "designDocumentRevision": "string",
- "designStatus": "DRAFT",
- "productId": 0,
- "productSku": "string",
- "materialId": 0,
- "materialSku": "string",
- "active": true,
- "lines": [
- {
- "id": 0,
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantityPerUnit": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a BOM. Requires permission: DESIGN_WRITE. A BOM whose design document has left DRAFT (in review, changes-requested, or released) is locked and cannot be deleted; nor can one referenced by a production order (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a page of work centers. Optionally filter by search (case-insensitive substring match on the work-center name) and/or status — independent AND filters. Requires permission: MANUFACTURING_READ.
| search | string Example: search=cutting Case-insensitive substring match on the work-center name. |
| status | string Enum: "ACTIVE" "INACTIVE" "MAINTENANCE" Example: status=ACTIVE Restrict to a single operational state. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "name": "string",
- "capacityPerHour": 0,
- "status": "ACTIVE",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a work center (shop-floor resource). Requires permission: MANUFACTURING_WRITE. name is unique (409).
| name required | string <= 200 characters Work center name (unique). |
| capacityPerHour | number Optional throughput per hour (>= 0). |
| status | string Enum: "ACTIVE" "INACTIVE" "MAINTENANCE" Optional; defaults ACTIVE on create, unchanged on update. |
{- "name": "Tube Cutting & Bending",
- "capacityPerHour": 40,
- "status": "ACTIVE"
}{- "id": 0,
- "name": "string",
- "capacityPerHour": 0,
- "status": "ACTIVE",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one work center. Requires permission: MANUFACTURING_READ.
| id required | integer <int64> |
{- "id": 0,
- "name": "string",
- "capacityPerHour": 0,
- "status": "ACTIVE",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a work center's fields. Requires permission: MANUFACTURING_WRITE. name uniqueness enforced (409).
| id required | integer <int64> |
| name required | string <= 200 characters Work center name (unique). |
| capacityPerHour | number Optional throughput per hour (>= 0). |
| status | string Enum: "ACTIVE" "INACTIVE" "MAINTENANCE" Optional; defaults ACTIVE on create, unchanged on update. |
{- "name": "string",
- "capacityPerHour": 0,
- "status": "ACTIVE"
}{- "id": 0,
- "name": "string",
- "capacityPerHour": 0,
- "status": "ACTIVE",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a work center. Requires permission: MANUFACTURING_WRITE. A work center referenced by an operation or maintenance order cannot be deleted (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a page of production orders (summary rows). Optionally filter by productId, status, salesOrderId (the linked make-to-order sales order), and/or a planned-start date range (dateFrom/dateTo, inclusive) — independent AND filters. Requires permission: MANUFACTURING_READ.
| productId | integer <int64> Restrict to a single product. |
| status | string Enum: "DRAFT" "SUBMITTED" "APPROVED" "IN_PROGRESS" "PARTIALLY_COMPLETED" "COMPLETED" "CANCELLED" Restrict to a single lifecycle state. |
| salesOrderId | integer <int64> Restrict to orders linked to one sales order (make-to-order). |
| dateFrom | string <date> Example: dateFrom=2026-07-01 Inclusive lower bound on the planned start date. |
| dateTo | string <date> Example: dateTo=2026-07-31 Inclusive upper bound on the planned start date. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "materialId": 0,
- "materialSku": "string",
- "bomId": 0,
- "bomRevision": "string",
- "status": "DRAFT",
- "orderedQuantity": 0,
- "producedQuantity": 0,
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "salesOrderId": 0,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a production order in DRAFT. Requires permission: MANUFACTURING_WRITE. The BOM must belong to a RELEASED design document (else 422); the product is derived from the BOM. components are the component lines to issue at start (seeded from the BOM on the client), each with its own source warehouse — a warehouse where the material currently has stock (else 422); there is no order-level source warehouse. salesOrderId is an optional make-to-order link.
| bomId required | integer <int64> BOM to produce (must be under a RELEASED design document). |
| salesOrderId | integer or null <int64> Optional make-to-order link. |
| destinationWarehouseId required | integer <int64> Warehouse finished goods land in (QC-hold). |
| orderedQuantity required | number Quantity to produce (> 0). |
| plannedStart | string <date> |
| jobNumber | string <= 50 characters Optional unique job/traceability number. |
required | Array of objects (ProductionOrderComponentRequest) The component lines to issue at start, each drawn from its own source warehouse. |
Array of objects (ProductionOrderOperationRequest) Optional routing (may be empty). |
{- "bomId": 387340,
- "salesOrderId": null,
- "destinationWarehouseId": 387062,
- "orderedQuantity": 5,
- "plannedStart": "2026-07-15",
- "jobNumber": "JOB-2026-0042",
- "components": [
- {
- "materialId": 387040,
- "sourceWarehouseId": 387060,
- "quantity": 50
}, - {
- "materialId": 387042,
- "sourceWarehouseId": 387060,
- "quantity": 10
}
], - "operations": [
- {
- "workCenterId": 387360,
- "sequence": 10
}, - {
- "workCenterId": 387362,
- "sequence": 20
}
]
}{- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "bomId": 0,
- "bomRevision": "string",
- "salesOrderId": 0,
- "destinationWarehouseId": 0,
- "destinationWarehouseName": "string",
- "orderedQuantity": 0,
- "producedQuantity": 0,
- "status": "DRAFT",
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "operations": [
- {
- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "sequence": 0,
- "status": "PENDING"
}
], - "components": [
- {
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantity": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdByName": "string",
- "submittedBy": 0,
- "submittedByName": "string",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 0,
- "approvedByName": "string",
- "approvedAt": "2019-08-24T14:15:22Z",
- "startedBy": 0,
- "startedByName": "string",
- "startedAt": "2019-08-24T14:15:22Z",
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one production order with its routing operations and produced/ordered progress. Requires permission: MANUFACTURING_READ.
| id required | integer <int64> |
{- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "bomId": 0,
- "bomRevision": "string",
- "salesOrderId": 0,
- "destinationWarehouseId": 0,
- "destinationWarehouseName": "string",
- "orderedQuantity": 0,
- "producedQuantity": 0,
- "status": "DRAFT",
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "operations": [
- {
- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "sequence": 0,
- "status": "PENDING"
}
], - "components": [
- {
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantity": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdByName": "string",
- "submittedBy": 0,
- "submittedByName": "string",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 0,
- "approvedByName": "string",
- "approvedAt": "2019-08-24T14:15:22Z",
- "startedBy": 0,
- "startedByName": "string",
- "startedAt": "2019-08-24T14:15:22Z",
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a production order's fields and routing. Requires permission: MANUFACTURING_WRITE. Permitted only while the order is DRAFT (422 otherwise).
| id required | integer <int64> |
| bomId required | integer <int64> BOM to produce (must be under a RELEASED design document). |
| salesOrderId | integer or null <int64> Optional make-to-order link. |
| destinationWarehouseId required | integer <int64> Warehouse finished goods land in (QC-hold). |
| orderedQuantity required | number Quantity to produce (> 0). |
| plannedStart | string <date> |
| jobNumber | string <= 50 characters Optional unique job/traceability number. |
required | Array of objects (ProductionOrderComponentRequest) The component lines to issue at start, each drawn from its own source warehouse. |
Array of objects (ProductionOrderOperationRequest) Optional routing (may be empty). |
{- "bomId": 0,
- "salesOrderId": 0,
- "destinationWarehouseId": 0,
- "orderedQuantity": 0,
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "components": [
- {
- "materialId": 0,
- "sourceWarehouseId": 0,
- "quantity": 0
}
], - "operations": [
- {
- "workCenterId": 0,
- "sequence": 0
}
]
}{- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "bomId": 0,
- "bomRevision": "string",
- "salesOrderId": 0,
- "destinationWarehouseId": 0,
- "destinationWarehouseName": "string",
- "orderedQuantity": 0,
- "producedQuantity": 0,
- "status": "DRAFT",
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "operations": [
- {
- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "sequence": 0,
- "status": "PENDING"
}
], - "components": [
- {
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantity": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdByName": "string",
- "submittedBy": 0,
- "submittedByName": "string",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 0,
- "approvedByName": "string",
- "approvedAt": "2019-08-24T14:15:22Z",
- "startedBy": 0,
- "startedByName": "string",
- "startedAt": "2019-08-24T14:15:22Z",
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Submits a DRAFT production order for approval (→ SUBMITTED) and stamps the submitter. Only a DRAFT order can be submitted — any other state → 422. Requires permission: MANUFACTURING_WRITE.
| id required | integer <int64> |
{- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "bomId": 0,
- "bomRevision": "string",
- "salesOrderId": 0,
- "destinationWarehouseId": 0,
- "destinationWarehouseName": "string",
- "orderedQuantity": 0,
- "producedQuantity": 0,
- "status": "DRAFT",
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "operations": [
- {
- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "sequence": 0,
- "status": "PENDING"
}
], - "components": [
- {
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantity": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdByName": "string",
- "submittedBy": 0,
- "submittedByName": "string",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 0,
- "approvedByName": "string",
- "approvedAt": "2019-08-24T14:15:22Z",
- "startedBy": 0,
- "startedByName": "string",
- "startedAt": "2019-08-24T14:15:22Z",
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Approves a SUBMITTED production order (→ APPROVED). Requires permission: PRODUCTION_ORDER_APPROVE (a planner with only MANUFACTURING_WRITE is 403). A user cannot approve an order they raised (self-approval → 422); approving a non-submitted order → 422.
| id required | integer <int64> |
{- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "bomId": 0,
- "bomRevision": "string",
- "salesOrderId": 0,
- "destinationWarehouseId": 0,
- "destinationWarehouseName": "string",
- "orderedQuantity": 0,
- "producedQuantity": 0,
- "status": "DRAFT",
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "operations": [
- {
- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "sequence": 0,
- "status": "PENDING"
}
], - "components": [
- {
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantity": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdByName": "string",
- "submittedBy": 0,
- "submittedByName": "string",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 0,
- "approvedByName": "string",
- "approvedAt": "2019-08-24T14:15:22Z",
- "startedBy": 0,
- "startedByName": "string",
- "startedAt": "2019-08-24T14:15:22Z",
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Cancels a production order. Requires permission: MANUFACTURING_WRITE. A completed order (or an illegal transition) → 422.
| id required | integer <int64> |
{- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "bomId": 0,
- "bomRevision": "string",
- "salesOrderId": 0,
- "destinationWarehouseId": 0,
- "destinationWarehouseName": "string",
- "orderedQuantity": 0,
- "producedQuantity": 0,
- "status": "DRAFT",
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "operations": [
- {
- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "sequence": 0,
- "status": "PENDING"
}
], - "components": [
- {
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantity": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdByName": "string",
- "submittedBy": 0,
- "submittedByName": "string",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 0,
- "approvedByName": "string",
- "approvedAt": "2019-08-24T14:15:22Z",
- "startedBy": 0,
- "startedByName": "string",
- "startedAt": "2019-08-24T14:15:22Z",
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Starts an APPROVED production order (→ IN_PROGRESS) and backflushes all component materials at once as PRODUCTION_ISSUE movements. Requires permission: PRODUCTION_EXECUTE. A hard availability check reads on-hand only; insufficient stock for any component → 422 and nothing is issued (the whole start rolls back). Starting a non-approved order → 422.
| id required | integer <int64> |
{- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "bomId": 0,
- "bomRevision": "string",
- "salesOrderId": 0,
- "destinationWarehouseId": 0,
- "destinationWarehouseName": "string",
- "orderedQuantity": 0,
- "producedQuantity": 0,
- "status": "DRAFT",
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "operations": [
- {
- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "sequence": 0,
- "status": "PENDING"
}
], - "components": [
- {
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantity": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdByName": "string",
- "submittedBy": 0,
- "submittedByName": "string",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 0,
- "approvedByName": "string",
- "approvedAt": "2019-08-24T14:15:22Z",
- "startedBy": 0,
- "startedByName": "string",
- "startedAt": "2019-08-24T14:15:22Z",
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Reports a produced quantity for an IN_PROGRESS order; finished goods land in QC-hold as a PRODUCTION_OUTPUT movement. Requires permission: PRODUCTION_EXECUTE. Cumulative produced quantity may not exceed the ordered quantity (over-completion → 422). An optional lotNumber (heat number) is captured for traceability.
| id required | integer <int64> |
| quantity required | number Quantity produced in this report (> 0; cumulative may not exceed ordered). |
| lotNumber | string <= 60 characters Optional lot / heat number (traceability). |
{- "quantity": 2,
- "lotNumber": "HEAT-7734"
}{- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "bomId": 0,
- "bomRevision": "string",
- "salesOrderId": 0,
- "destinationWarehouseId": 0,
- "destinationWarehouseName": "string",
- "orderedQuantity": 0,
- "producedQuantity": 0,
- "status": "DRAFT",
- "plannedStart": "2019-08-24",
- "jobNumber": "string",
- "operations": [
- {
- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "sequence": 0,
- "status": "PENDING"
}
], - "components": [
- {
- "componentMaterialId": 0,
- "componentMaterialSku": "string",
- "componentMaterialName": "string",
- "quantity": 0,
- "sourceWarehouseId": 0,
- "sourceWarehouseName": "string"
}
], - "createdBy": 0,
- "createdByName": "string",
- "submittedBy": 0,
- "submittedByName": "string",
- "submittedAt": "2019-08-24T14:15:22Z",
- "approvedBy": 0,
- "approvedByName": "string",
- "approvedAt": "2019-08-24T14:15:22Z",
- "startedBy": 0,
- "startedByName": "string",
- "startedAt": "2019-08-24T14:15:22Z",
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns a page of quality inspections (append-only records). Optionally filter by productionOrderId, result, and/or an inspection-date range (dateFrom/dateTo, inclusive) — independent AND filters. Requires permission: MANUFACTURING_READ.
| productionOrderId | integer <int64> Restrict to inspections of one production order. |
| result | string Enum: "PASS" "FAIL" Restrict to a single outcome. |
| dateFrom | string <date> Example: dateFrom=2026-07-01 Inclusive lower bound on the inspection date. |
| dateTo | string <date> Example: dateTo=2026-07-31 Inclusive upper bound on the inspection date. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "productionOrderId": 0,
- "quantity": 0,
- "result": "PASS",
- "notes": "string",
- "inspectedAt": "2019-08-24T14:15:22Z",
- "createdBy": 0
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Inspects a produced quantity in QC-hold. Requires permission: QUALITY_WRITE. A PASS releases the quantity from QC-hold into on-hand (QC_RELEASE); a FAIL scraps it (QC_REJECT). The quantity must be available in QC-hold for the order (else 422). Inspections are append-only.
| productionOrderId required | integer <int64> |
| quantity required | number Quantity inspected (> 0; must be available in QC-hold). |
| result required | string Enum: "PASS" "FAIL" PASS releases QC-hold → on-hand; FAIL scraps it. |
| notes | string <= 500 characters Optional free-text inspection detail. |
{- "productionOrderId": 387500,
- "quantity": 2,
- "result": "PASS",
- "notes": "Visual and dimensional check per QP-07; all within tolerance."
}{- "id": 0,
- "productionOrderId": 0,
- "quantity": 0,
- "result": "PASS",
- "notes": "string",
- "inspectedAt": "2019-08-24T14:15:22Z",
- "createdBy": 0
}Returns one quality inspection. Requires permission: MANUFACTURING_READ.
| id required | integer <int64> |
{- "id": 0,
- "productionOrderId": 0,
- "quantity": 0,
- "result": "PASS",
- "notes": "string",
- "inspectedAt": "2019-08-24T14:15:22Z",
- "createdBy": 0
}Returns a page of maintenance orders. Optionally filter by workCenterId, status, and/or type — independent AND filters. Requires permission: MANUFACTURING_READ.
| workCenterId | integer <int64> Restrict to maintenance on one work center. |
| status | string Enum: "SCHEDULED" "IN_PROGRESS" "COMPLETED" "CANCELLED" Restrict to a single status. |
| type | string Enum: "PREVENTIVE" "CORRECTIVE" Restrict to planned upkeep ( |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "type": "PREVENTIVE",
- "status": "SCHEDULED",
- "scheduledFor": "2019-08-24",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Schedules maintenance on a work center. Requires permission: MAINTENANCE_WRITE. status defaults to SCHEDULED.
| workCenterId required | integer <int64> |
| type required | string Enum: "PREVENTIVE" "CORRECTIVE" |
| status | string Enum: "SCHEDULED" "IN_PROGRESS" "COMPLETED" "CANCELLED" Optional; defaults SCHEDULED on create, unchanged on update. |
| scheduledFor | string <date> |
{- "workCenterId": 387360,
- "type": "PREVENTIVE",
- "status": "SCHEDULED",
- "scheduledFor": "2026-08-01"
}{- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "type": "PREVENTIVE",
- "status": "SCHEDULED",
- "scheduledFor": "2019-08-24",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one maintenance order. Requires permission: MANUFACTURING_READ.
| id required | integer <int64> |
{- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "type": "PREVENTIVE",
- "status": "SCHEDULED",
- "scheduledFor": "2019-08-24",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a maintenance order's fields (including status). Requires permission: MAINTENANCE_WRITE.
| id required | integer <int64> |
| workCenterId required | integer <int64> |
| type required | string Enum: "PREVENTIVE" "CORRECTIVE" |
| status | string Enum: "SCHEDULED" "IN_PROGRESS" "COMPLETED" "CANCELLED" Optional; defaults SCHEDULED on create, unchanged on update. |
| scheduledFor | string <date> |
{- "workCenterId": 0,
- "type": "PREVENTIVE",
- "status": "SCHEDULED",
- "scheduledFor": "2019-08-24"
}{- "id": 0,
- "workCenterId": 0,
- "workCenterName": "string",
- "type": "PREVENTIVE",
- "status": "SCHEDULED",
- "scheduledFor": "2019-08-24",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a maintenance order. Requires permission: MAINTENANCE_WRITE.
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Customers, quotations, sales orders (confirm reserves stock), deliveries, and milestone billing.
Returns a page of customers. Optionally filter by search (case-insensitive substring match on name, email, or phone) and/or active — independent AND filters. Requires permission: SALES_READ.
| search | string Example: search=acme Case-insensitive substring match on customer name, email, or phone. |
| active | boolean Restrict to active ( |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "name": "string",
- "email": "user@example.com",
- "phone": "string",
- "stateCode": "string",
- "gstin": "29ABCDE1234F1Z5",
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a customer. Requires permission: SALES_WRITE. stateCode is the 2-digit GST state code (place of supply), needed before an invoice can be posted.
| name required | string <= 200 characters |
string <email> <= 255 characters | |
| phone | string <= 40 characters |
| stateCode | string = 2 characters 2-digit GST state code (place of supply). |
| gstin | string <= 15 characters Optional 15-character GST registration number, printed on tax invoices. Validated loosely (15 alphanumerics) — editable master data. |
| active | boolean Optional; defaults active on create, unchanged on update. |
{- "name": "Reliance Petrochemicals Ltd",
- "email": "procurement@relpetro.example.in",
- "phone": "+91 22 4477 1200",
- "stateCode": "27",
- "active": true
}{- "id": 0,
- "name": "string",
- "email": "user@example.com",
- "phone": "string",
- "stateCode": "string",
- "gstin": "29ABCDE1234F1Z5",
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one customer. Requires permission: SALES_READ.
| id required | integer <int64> |
{- "id": 0,
- "name": "string",
- "email": "user@example.com",
- "phone": "string",
- "stateCode": "string",
- "gstin": "29ABCDE1234F1Z5",
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a customer's fields. Requires permission: SALES_WRITE. Send active: false to retire a customer referenced by history.
| id required | integer <int64> |
| name required | string <= 200 characters |
string <email> <= 255 characters | |
| phone | string <= 40 characters |
| stateCode | string = 2 characters 2-digit GST state code (place of supply). |
| gstin | string <= 15 characters Optional 15-character GST registration number, printed on tax invoices. Validated loosely (15 alphanumerics) — editable master data. |
| active | boolean Optional; defaults active on create, unchanged on update. |
{- "name": "string",
- "email": "user@example.com",
- "phone": "string",
- "stateCode": "st",
- "gstin": "29ABCDE1234F1Z5",
- "active": true
}{- "id": 0,
- "name": "string",
- "email": "user@example.com",
- "phone": "string",
- "stateCode": "string",
- "gstin": "29ABCDE1234F1Z5",
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a customer. Requires permission: SALES_WRITE. A customer referenced by a quotation or order cannot be deleted — deactivate instead (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a page of quotations (summary rows with derived total). Requires permission: SALES_READ. Filter by customerId and/or status.
| customerId | integer <int64> |
| status | string Enum: "DRAFT" "SENT" "ACCEPTED" "REJECTED" "EXPIRED" |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "status": "DRAFT",
- "validUntil": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a quotation (DRAFT) with at least one line. Requires permission: SALES_WRITE.
| customerId required | integer <int64> |
| validUntil | string <date> |
required | Array of objects (QuotationLineRequest) non-empty |
{- "customerId": 387600,
- "validUntil": "2026-08-31",
- "lines": [
- {
- "productId": 387001,
- "quantity": 3,
- "unitPrice": 285000
}
]
}{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "status": "DRAFT",
- "validUntil": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "quantity": 0,
- "unitPrice": 0,
- "lineTotal": 0
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one quotation with its lines and derived total. Requires permission: SALES_READ.
| id required | integer <int64> |
{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "status": "DRAFT",
- "validUntil": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "quantity": 0,
- "unitPrice": 0,
- "lineTotal": 0
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a quotation's fields and lines. Requires permission: SALES_WRITE. Permitted only while the quotation is DRAFT (422 otherwise).
| id required | integer <int64> |
| customerId required | integer <int64> |
| validUntil | string <date> |
required | Array of objects (QuotationLineRequest) non-empty |
{- "customerId": 0,
- "validUntil": "2019-08-24",
- "lines": [
- {
- "productId": 0,
- "quantity": 0,
- "unitPrice": 0
}
]
}{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "status": "DRAFT",
- "validUntil": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "quantity": 0,
- "unitPrice": 0,
- "lineTotal": 0
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Transitions a DRAFT quotation to SENT. Requires permission: SALES_WRITE. Illegal transition → 422.
| id required | integer <int64> |
{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "status": "DRAFT",
- "validUntil": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "quantity": 0,
- "unitPrice": 0,
- "lineTotal": 0
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Marks a SENT quotation ACCEPTED (a sales order may then be seeded from it). Requires permission: SALES_WRITE. Illegal transition → 422.
| id required | integer <int64> |
{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "status": "DRAFT",
- "validUntil": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "quantity": 0,
- "unitPrice": 0,
- "lineTotal": 0
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Marks a quotation REJECTED. Requires permission: SALES_WRITE. Illegal transition → 422.
| id required | integer <int64> |
{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "status": "DRAFT",
- "validUntil": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "quantity": 0,
- "unitPrice": 0,
- "lineTotal": 0
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Marks a quotation EXPIRED. Requires permission: SALES_WRITE. Illegal transition → 422.
| id required | integer <int64> |
{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "status": "DRAFT",
- "validUntil": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "quantity": 0,
- "unitPrice": 0,
- "lineTotal": 0
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns a page of sales orders (summary rows). Optionally filter by customerId, status, quotationId, and/or an inclusive order-date range (dateFrom/dateTo) — independent AND filters. Requires permission: SALES_READ.
| customerId | integer <int64> Restrict to orders for one customer. |
| status | string Enum: "DRAFT" "CONFIRMED" "PARTIALLY_SHIPPED" "SHIPPED" "CLOSED" "CANCELLED" Restrict to a single lifecycle state. |
| quotationId | integer <int64> Restrict to the order created from one quotation. |
| dateFrom | string <date> Example: dateFrom=2026-07-01 Inclusive lower bound on the order date. |
| dateTo | string <date> Example: dateTo=2026-07-31 Inclusive upper bound on the order date. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "status": "DRAFT",
- "orderDate": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a sales order (DRAFT) with at least one line. Requires permission: SALES_WRITE. warehouseId is optional on a draft but required before confirm.
| customerId required | integer <int64> |
| warehouseId | integer <int64> Fulfilment warehouse; optional on a draft, required before confirm. |
| orderDate required | string <date> |
required | Array of objects (SalesOrderLineRequest) non-empty |
{- "customerId": 387600,
- "warehouseId": 387062,
- "orderDate": "2026-06-20",
- "lines": [
- {
- "productId": 387001,
- "quantity": 3,
- "unitPrice": 285000
}
]
}{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "warehouseId": 0,
- "warehouseName": "string",
- "quotationId": 0,
- "status": "DRAFT",
- "orderDate": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "orderedQuantity": 0,
- "unitPrice": 0,
- "reservedQuantity": 0,
- "shippedQuantity": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one sales order with its lines (ordered/reserved/shipped quantities) and derived total. Requires permission: SALES_READ.
| id required | integer <int64> |
{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "warehouseId": 0,
- "warehouseName": "string",
- "quotationId": 0,
- "status": "DRAFT",
- "orderDate": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "orderedQuantity": 0,
- "unitPrice": 0,
- "reservedQuantity": 0,
- "shippedQuantity": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a sales order's fields and lines. Requires permission: SALES_WRITE. Permitted only while the order is DRAFT (422 otherwise).
| id required | integer <int64> |
| customerId required | integer <int64> |
| warehouseId | integer <int64> Fulfilment warehouse; optional on a draft, required before confirm. |
| orderDate required | string <date> |
required | Array of objects (SalesOrderLineRequest) non-empty |
{- "customerId": 0,
- "warehouseId": 0,
- "orderDate": "2019-08-24",
- "lines": [
- {
- "productId": 0,
- "quantity": 0,
- "unitPrice": 0
}
]
}{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "warehouseId": 0,
- "warehouseName": "string",
- "quotationId": 0,
- "status": "DRAFT",
- "orderDate": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "orderedQuantity": 0,
- "unitPrice": 0,
- "reservedQuantity": 0,
- "shippedQuantity": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Confirms a DRAFT sales order (→ CONFIRMED) and reserves stock, moving on-hand → reserved for each line from the order's fulfilment warehouse. Requires permission: SALES_APPROVE (a rep with only SALES_WRITE is 403). A user cannot confirm an order they created (self-approval → 422). An atomic availability guard reads on-hand only; a shortfall on any line → 422 and the order stays DRAFT (nothing reserved). Confirming without a fulfilment warehouse → 422.
| id required | integer <int64> |
{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "warehouseId": 0,
- "warehouseName": "string",
- "quotationId": 0,
- "status": "DRAFT",
- "orderDate": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "orderedQuantity": 0,
- "unitPrice": 0,
- "reservedQuantity": 0,
- "shippedQuantity": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Cancels a sales order; if it was confirmed (not yet shipped), releases the reservation (reserved → on-hand). Requires permission: SALES_WRITE. Cancelling a shipped order → 422.
| id required | integer <int64> |
{- "id": 0,
- "customerId": 0,
- "customerName": "string",
- "warehouseId": 0,
- "warehouseName": "string",
- "quotationId": 0,
- "status": "DRAFT",
- "orderDate": "2019-08-24",
- "total": 0,
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "orderedQuantity": 0,
- "unitPrice": 0,
- "reservedQuantity": 0,
- "shippedQuantity": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns a page of deliveries (append-only). Optionally filter by salesOrderId and/or an inclusive dispatch-date range (dateFrom/dateTo) — independent AND filters. Requires permission: SALES_READ.
| salesOrderId | integer <int64> Restrict to deliveries against one sales order. |
| dateFrom | string <date> Example: dateFrom=2026-07-01 Inclusive lower bound on the dispatch date. |
| dateTo | string <date> Example: dateTo=2026-07-31 Inclusive upper bound on the dispatch date. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "salesOrderId": 0,
- "dispatchedDate": "2019-08-24",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Dispatches a delivery against a CONFIRMED (or PARTIALLY_SHIPPED) sales order. Requires permission: SALES_WRITE. Converts reserved → shipped and writes negative SALES_SHIPMENT stock movements. A line cannot ship more than its outstanding reserved quantity (over-ship → 422). Deliveries are append-only.
| salesOrderId required | integer <int64> |
| dispatchedDate required | string <date> |
required | Array of objects (DeliveryLineRequest) non-empty |
{- "salesOrderId": 387700,
- "dispatchedDate": "2026-07-05",
- "lines": [
- {
- "soLineId": 387701,
- "shippedQuantity": 2
}
]
}{- "id": 0,
- "salesOrderId": 0,
- "dispatchedDate": "2019-08-24",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "soLineId": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "shippedQuantity": 0
}
], - "createdAt": "2019-08-24T14:15:22Z"
}Returns one delivery with its shipped lines. Requires permission: SALES_READ.
| id required | integer <int64> |
{- "id": 0,
- "salesOrderId": 0,
- "dispatchedDate": "2019-08-24",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "soLineId": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "shippedQuantity": 0
}
], - "createdAt": "2019-08-24T14:15:22Z"
}Returns the milestone schedule for a sales order. Requires permission: SALES_READ. Sortable field: sequence (default).
| soId required | integer <int64> |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "salesOrderId": 0,
- "sequence": 0,
- "name": "string",
- "percentage": 0,
- "status": "PENDING",
- "invoiceId": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Replaces the whole milestone schedule for a sales order. Requires permission: SALES_WRITE. The milestone percentages must sum to exactly 100 (99/101 → 422). The schedule locks once any milestone is INVOICED or referenced by an advance/invoice (422).
| soId required | integer <int64> |
required | Array of objects (MilestoneItemRequest) non-empty |
{- "milestones": [
- {
- "sequence": 1,
- "name": "Advance",
- "percentage": 30
}, - {
- "sequence": 2,
- "name": "On Dispatch",
- "percentage": 60
}, - {
- "sequence": 3,
- "name": "On Commissioning",
- "percentage": 10
}
]
}[- {
- "id": 0,
- "salesOrderId": 0,
- "sequence": 0,
- "name": "string",
- "percentage": 0,
- "status": "PENDING",
- "invoiceId": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
]Creates a DRAFT AR invoice for a milestone (one line = the milestone percentage of the sales order value). Requires permission: FINANCE_WRITE. taxCodeId is required (the sales order carries none). The invoice then flows through the normal invoice lifecycle (post/cancel). The milestone must still be PENDING.
| soId required | integer <int64> |
| milestoneId required | integer <int64> |
| taxCodeId required | integer <int64> GST tax code to apply (required — the SO carries none). |
| productId | integer <int64> Optional; defaults to the first order line's product. |
| invoiceDate | string <date> Optional; defaults to today. |
{- "taxCodeId": 387260,
- "productId": 387001,
- "invoiceDate": "2026-07-06"
}{- "id": 0,
- "type": "AR",
- "invoiceNumber": "string",
- "invoiceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "placeOfSupply": "string",
- "supplyType": "INTRA",
- "status": "DRAFT",
- "subtotal": 0,
- "totalCgst": 0,
- "totalSgst": 0,
- "totalIgst": 0,
- "roundingAdjustment": 0,
- "totalAmount": 0,
- "journalEntryId": 0,
- "settled": true,
- "salesOrderId": 0,
- "milestoneId": 0,
- "note": "string",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "hsnCode": "string",
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "quantity": 0,
- "unitPrice": 0,
- "taxableAmount": 0,
- "ratePct": 0,
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Chart of accounts, journal entries, tax master data, invoices (AR/AP), payments, and advances.
Returns a page of chart-of-accounts entries. Requires permission: FINANCE_READ. Filter by type.
| type | string Enum: "ASSET" "LIABILITY" "EQUITY" "INCOME" "EXPENSE" |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "code": "string",
- "name": "string",
- "type": "ASSET",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a chart-of-accounts entry. Requires permission: FINANCE_WRITE. code is unique (409).
| code required | string <= 20 characters Account code (unique). |
| name required | string <= 120 characters |
| type required | string Enum: "ASSET" "LIABILITY" "EQUITY" "INCOME" "EXPENSE" |
| active | boolean Optional; defaults active on create, unchanged on update. |
{- "code": "1100",
- "name": "Accounts Receivable",
- "type": "ASSET",
- "active": true
}{- "id": 0,
- "code": "string",
- "name": "string",
- "type": "ASSET",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one account. Requires permission: FINANCE_READ.
| id required | integer <int64> |
{- "id": 0,
- "code": "string",
- "name": "string",
- "type": "ASSET",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces an account's fields. Requires permission: FINANCE_WRITE. code uniqueness enforced (409).
| id required | integer <int64> |
| code required | string <= 20 characters Account code (unique). |
| name required | string <= 120 characters |
| type required | string Enum: "ASSET" "LIABILITY" "EQUITY" "INCOME" "EXPENSE" |
| active | boolean Optional; defaults active on create, unchanged on update. |
{- "code": "string",
- "name": "string",
- "type": "ASSET",
- "active": true
}{- "id": 0,
- "code": "string",
- "name": "string",
- "type": "ASSET",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes an account. Requires permission: FINANCE_WRITE. An account referenced by a journal line cannot be deleted — deactivate instead (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a page of GST tax codes. Requires permission: FINANCE_READ.
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "code": "string",
- "name": "string",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a GST tax code. Requires permission: FINANCE_WRITE. code is unique (409). Rates are attached separately via tax rates.
| code required | string <= 20 characters Tax code (unique), e.g. GST18. |
| name required | string <= 120 characters |
| active | boolean |
{- "code": "GST18",
- "name": "GST 18%",
- "active": true
}{- "id": 0,
- "code": "string",
- "name": "string",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one tax code. Requires permission: FINANCE_READ.
| id required | integer <int64> |
{- "id": 0,
- "code": "string",
- "name": "string",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a tax code's fields. Requires permission: FINANCE_WRITE. code uniqueness enforced (409).
| id required | integer <int64> |
| code required | string <= 20 characters Tax code (unique), e.g. GST18. |
| name required | string <= 120 characters |
| active | boolean |
{- "code": "string",
- "name": "string",
- "active": true
}{- "id": 0,
- "code": "string",
- "name": "string",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a tax code. Requires permission: FINANCE_WRITE. A tax code that has rates cannot be deleted — deactivate instead (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a page of effective-dated tax rates. Requires permission: FINANCE_READ. Filter by taxCodeId.
| taxCodeId | integer <int64> |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "totalRatePct": 0,
- "validFrom": "2019-08-24",
- "validTo": "2019-08-24",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Adds an effective-dated rate for a tax code. Requires permission: FINANCE_WRITE. Date windows for one code may not overlap (409/422). A rate change is a new row, not an edit.
| taxCodeId required | integer <int64> |
| totalRatePct required | number Full GST rate percent (>= 0). The CGST/SGST/IGST split is derived at posting time. |
| validFrom required | string <date> Inclusive start of the window. |
| validTo | string <date> Inclusive end; null = open-ended. Windows for one code may not overlap. |
{- "taxCodeId": 387260,
- "totalRatePct": 18,
- "validFrom": "2025-09-22"
}{- "id": 0,
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "totalRatePct": 0,
- "validFrom": "2019-08-24",
- "validTo": "2019-08-24",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns the single tax rate in effect for a tax code on a given date. Requires permission: FINANCE_READ. No rate covering the date → 422.
| taxCodeId required | integer <int64> |
| onDate required | string <date> |
{- "id": 0,
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "totalRatePct": 0,
- "validFrom": "2019-08-24",
- "validTo": "2019-08-24",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes an effective-dated tax rate. Requires permission: FINANCE_WRITE.
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a page of TDS section rules. Requires permission: FINANCE_READ.
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "internalCode": "string",
- "description": "string",
- "ratePct": 0,
- "ratePctIndividual": 0,
- "thresholdSingle": 0,
- "thresholdAnnual": 0,
- "section393Code": "string",
- "penalRateNoPan": 0,
- "thresholdMode": "FULL",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a TDS section rule. Requires permission: FINANCE_WRITE. internalCode is unique (409). thresholdMode FULL taxes the whole base once a threshold is crossed; EXCESS (194Q) taxes only the slice above the annual threshold.
| internalCode required | string <= 30 characters Stable key (unique), e.g. TDS_CONTRACTOR. |
| description required | string <= 200 characters |
| ratePct required | number Default (non-individual) rate percent (>= 0). |
| ratePctIndividual | number Optional lower individual/HUF rate. |
| thresholdSingle | number Optional per-transaction trigger. |
| thresholdAnnual required | number Annual aggregate threshold (>= 0). |
| section393Code | string <= 20 characters Filing code (data). |
| penalRateNoPan required | number Rate applied when the payee has no PAN (>= 0). |
| thresholdMode | string Enum: "FULL" "EXCESS" Optional; FULL taxes the whole base past a threshold, EXCESS (194Q) only the slice above the annual threshold. |
| active | boolean |
{- "internalCode": "TDS_CONTRACTOR",
- "description": "Contractor / works / transport / labour (old 194C)",
- "ratePct": 2,
- "ratePctIndividual": 1,
- "thresholdSingle": 30000,
- "thresholdAnnual": 100000,
- "section393Code": "1001",
- "penalRateNoPan": 20,
- "thresholdMode": "FULL",
- "active": true
}{- "id": 0,
- "internalCode": "string",
- "description": "string",
- "ratePct": 0,
- "ratePctIndividual": 0,
- "thresholdSingle": 0,
- "thresholdAnnual": 0,
- "section393Code": "string",
- "penalRateNoPan": 0,
- "thresholdMode": "FULL",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one TDS section rule. Requires permission: FINANCE_READ.
| id required | integer <int64> |
{- "id": 0,
- "internalCode": "string",
- "description": "string",
- "ratePct": 0,
- "ratePctIndividual": 0,
- "thresholdSingle": 0,
- "thresholdAnnual": 0,
- "section393Code": "string",
- "penalRateNoPan": 0,
- "thresholdMode": "FULL",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a TDS section rule. Requires permission: FINANCE_WRITE. internalCode uniqueness enforced (409).
| id required | integer <int64> |
| internalCode required | string <= 30 characters Stable key (unique), e.g. TDS_CONTRACTOR. |
| description required | string <= 200 characters |
| ratePct required | number Default (non-individual) rate percent (>= 0). |
| ratePctIndividual | number Optional lower individual/HUF rate. |
| thresholdSingle | number Optional per-transaction trigger. |
| thresholdAnnual required | number Annual aggregate threshold (>= 0). |
| section393Code | string <= 20 characters Filing code (data). |
| penalRateNoPan required | number Rate applied when the payee has no PAN (>= 0). |
| thresholdMode | string Enum: "FULL" "EXCESS" Optional; FULL taxes the whole base past a threshold, EXCESS (194Q) only the slice above the annual threshold. |
| active | boolean |
{- "internalCode": "string",
- "description": "string",
- "ratePct": 0,
- "ratePctIndividual": 0,
- "thresholdSingle": 0,
- "thresholdAnnual": 0,
- "section393Code": "string",
- "penalRateNoPan": 0,
- "thresholdMode": "FULL",
- "active": true
}{- "id": 0,
- "internalCode": "string",
- "description": "string",
- "ratePct": 0,
- "ratePctIndividual": 0,
- "thresholdSingle": 0,
- "thresholdAnnual": 0,
- "section393Code": "string",
- "penalRateNoPan": 0,
- "thresholdMode": "FULL",
- "active": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a TDS section rule. Requires permission: FINANCE_WRITE. A section referenced by a payment or ledger cannot be deleted (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns the singleton company configuration (home GST state and tax-applicability flags). Requires permission: FINANCE_READ.
{- "id": 0,
- "stateCode": "string",
- "gstin": "string",
- "tds194qApplicable": true,
- "gstRegistered": true,
- "updatedAt": "2019-08-24T14:15:22Z"
}Updates the singleton company configuration. Requires permission: FINANCE_WRITE.
| stateCode required | string = 2 characters Home-state 2-digit GST code. |
| gstin | string <= 15 characters Optional 15-character GST registration number, printed on tax invoices. Validated loosely (15 alphanumerics) — editable master data. |
| tds194qApplicable required | boolean |
| gstRegistered required | boolean |
{- "stateCode": "27",
- "tds194qApplicable": false,
- "gstRegistered": true
}{- "id": 0,
- "stateCode": "string",
- "gstin": "string",
- "tds194qApplicable": true,
- "gstRegistered": true,
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns the full reference list of the 37 India GST states/UTs (2-digit code, name, optional alpha), ordered by code. Readable by any authenticated user — the same list feeds the place-of-supply / state pickers on customers, suppliers, invoices, advances and company config. Read-only; the list is seeded.
[- {
- "code": "27",
- "name": "Maharashtra",
- "alphaCode": "MH"
}, - {
- "code": "29",
- "name": "Karnataka",
- "alphaCode": "KA"
}
]Returns a page of journal entries (summary rows). Requires permission: FINANCE_READ. Filter by status, fromDate, toDate.
| status | string Enum: "DRAFT" "POSTED" |
| fromDate | string <date> |
| toDate | string <date> |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "entryDate": "2019-08-24",
- "description": "string",
- "status": "DRAFT",
- "refType": "string",
- "reversalOfId": 0,
- "totalDebit": 0,
- "totalCredit": 0,
- "postedAt": "2019-08-24T14:15:22Z",
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a DRAFT journal entry. Requires permission: FINANCE_WRITE. Each line posts to exactly one side (debit XOR credit > 0). A draft may be unbalanced while being built; balance is enforced on post.
| entryDate required | string <date> |
| description | string |
required | Array of objects (JournalEntryLineRequest) non-empty |
{- "entryDate": "2026-07-09",
- "description": "Manual reclass",
- "lines": [
- {
- "accountId": 387230,
- "debit": 10000,
- "credit": 0,
- "lineDescription": "Dr Bank"
}, - {
- "accountId": 387232,
- "debit": 0,
- "credit": 10000,
- "lineDescription": "Cr AR"
}
]
}{- "id": 0,
- "entryDate": "2019-08-24",
- "description": "string",
- "status": "DRAFT",
- "refType": "string",
- "refId": 0,
- "reversalOfId": 0,
- "totalDebit": 0,
- "totalCredit": 0,
- "postedAt": "2019-08-24T14:15:22Z",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "accountId": 0,
- "accountCode": "string",
- "accountName": "string",
- "debit": 0,
- "credit": 0,
- "lineDescription": "string"
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one journal entry with its lines and debit/credit totals. Requires permission: FINANCE_READ.
| id required | integer <int64> |
{- "id": 0,
- "entryDate": "2019-08-24",
- "description": "string",
- "status": "DRAFT",
- "refType": "string",
- "refId": 0,
- "reversalOfId": 0,
- "totalDebit": 0,
- "totalCredit": 0,
- "postedAt": "2019-08-24T14:15:22Z",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "accountId": 0,
- "accountCode": "string",
- "accountName": "string",
- "debit": 0,
- "credit": 0,
- "lineDescription": "string"
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a DRAFT entry's fields and lines. Requires permission: FINANCE_WRITE. A POSTED entry is immutable (422).
| id required | integer <int64> |
| entryDate required | string <date> |
| description | string |
required | Array of objects (JournalEntryLineRequest) non-empty |
{- "entryDate": "2019-08-24",
- "description": "string",
- "lines": [
- {
- "accountId": 0,
- "debit": 0,
- "credit": 0,
- "lineDescription": "string"
}
]
}{- "id": 0,
- "entryDate": "2019-08-24",
- "description": "string",
- "status": "DRAFT",
- "refType": "string",
- "refId": 0,
- "reversalOfId": 0,
- "totalDebit": 0,
- "totalCredit": 0,
- "postedAt": "2019-08-24T14:15:22Z",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "accountId": 0,
- "accountCode": "string",
- "accountName": "string",
- "debit": 0,
- "credit": 0,
- "lineDescription": "string"
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a DRAFT journal entry. Requires permission: FINANCE_WRITE. A POSTED entry cannot be deleted — reverse it instead (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Posts a DRAFT entry (→ POSTED, stamps postedAt). Requires permission: JOURNAL_POST. Debits must equal credits and there must be at least one line (else 422). A posted entry is immutable.
| id required | integer <int64> |
{- "id": 0,
- "entryDate": "2019-08-24",
- "description": "string",
- "status": "DRAFT",
- "refType": "string",
- "refId": 0,
- "reversalOfId": 0,
- "totalDebit": 0,
- "totalCredit": 0,
- "postedAt": "2019-08-24T14:15:22Z",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "accountId": 0,
- "accountCode": "string",
- "accountName": "string",
- "debit": 0,
- "credit": 0,
- "lineDescription": "string"
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Creates a new POSTED entry with debits and credits swapped, linked via reversalOfId. Requires permission: JOURNAL_POST. Only a POSTED entry can be reversed (422).
| id required | integer <int64> |
{- "id": 0,
- "entryDate": "2019-08-24",
- "description": "string",
- "status": "DRAFT",
- "refType": "string",
- "refId": 0,
- "reversalOfId": 0,
- "totalDebit": 0,
- "totalCredit": 0,
- "postedAt": "2019-08-24T14:15:22Z",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "accountId": 0,
- "accountCode": "string",
- "accountName": "string",
- "debit": 0,
- "credit": 0,
- "lineDescription": "string"
}
], - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns a page of invoices (summary rows). Optionally filter by type (AR/AP), status, counterpartyId, and/or an inclusive invoice-date range (dateFrom/dateTo) — independent AND filters. Requires permission: FINANCE_READ.
| type | string Enum: "AR" "AP" Restrict to receivable ( |
| status | string Enum: "DRAFT" "POSTED" "CANCELLED" Restrict to a single lifecycle state. |
| counterpartyId | integer <int64> Restrict to one counterparty — the customer on an AR invoice or the supplier on an AP one. |
| dateFrom | string <date> Example: dateFrom=2026-07-01 Inclusive lower bound on the invoice date. |
| dateTo | string <date> Example: dateTo=2026-07-31 Inclusive upper bound on the invoice date. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "type": "AR",
- "invoiceNumber": "string",
- "invoiceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "status": "DRAFT",
- "totalAmount": 0,
- "settled": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a DRAFT invoice. Requires permission: FINANCE_WRITE. An AR invoice must name a customer, an AP invoice a supplier (matching the type; else 422). Tax amounts are computed and frozen at post, not here.
| type required | string Enum: "AR" "AP" |
| invoiceDate required | string <date> |
| customerId | integer <int64> Required for AR (and must be null for AP). |
| supplierId | integer <int64> Required for AP (and must be null for AR). |
| placeOfSupply | string = 2 characters 2-digit GST state code; defaults from the counterparty at post. |
| note | string <= 500 characters |
required | Array of objects (InvoiceLineRequest) non-empty |
{- "type": "AR",
- "invoiceDate": "2026-07-06",
- "customerId": 387600,
- "placeOfSupply": "27",
- "note": "Milestone 1 - advance",
- "lines": [
- {
- "productId": 387001,
- "taxCodeId": 387260,
- "quantity": 1,
- "unitPrice": 855000
}
]
}{- "id": 0,
- "type": "AR",
- "invoiceNumber": "string",
- "invoiceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "placeOfSupply": "string",
- "supplyType": "INTRA",
- "status": "DRAFT",
- "subtotal": 0,
- "totalCgst": 0,
- "totalSgst": 0,
- "totalIgst": 0,
- "roundingAdjustment": 0,
- "totalAmount": 0,
- "journalEntryId": 0,
- "settled": true,
- "salesOrderId": 0,
- "milestoneId": 0,
- "note": "string",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "hsnCode": "string",
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "quantity": 0,
- "unitPrice": 0,
- "taxableAmount": 0,
- "ratePct": 0,
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Aggregate money and counts across all invoices for the finance overview, split into receivables (receivable, AR — what customers owe us) and payables (payable, AP — what we owe suppliers). Each side reports four buckets: billed (posted total), of which paid (posted and settled) and outstanding (posted, not yet settled) — so billed = paid + outstanding — plus draft (not yet posted). CANCELLED invoices are void and excluded from every bucket. Amounts are rupee-scaled (2 dp) and computed over the whole invoice set, so the figures are exact regardless of row count. Takes no parameters.
Requires permission: FINANCE_READ.
{- "receivable": {
- "billedCount": 12,
- "billedTotal": 1450000,
- "paidCount": 7,
- "paidTotal": 820000,
- "outstandingCount": 5,
- "outstandingTotal": 630000,
- "draftCount": 2,
- "draftTotal": 90000
}, - "payable": {
- "billedCount": 9,
- "billedTotal": 610000,
- "paidCount": 6,
- "paidTotal": 410000,
- "outstandingCount": 3,
- "outstandingTotal": 200000,
- "draftCount": 1,
- "draftTotal": 15000
}
}Returns one invoice with its lines and frozen tax snapshot. Requires permission: FINANCE_READ.
| id required | integer <int64> |
{- "id": 0,
- "type": "AR",
- "invoiceNumber": "string",
- "invoiceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "placeOfSupply": "string",
- "supplyType": "INTRA",
- "status": "DRAFT",
- "subtotal": 0,
- "totalCgst": 0,
- "totalSgst": 0,
- "totalIgst": 0,
- "roundingAdjustment": 0,
- "totalAmount": 0,
- "journalEntryId": 0,
- "settled": true,
- "salesOrderId": 0,
- "milestoneId": 0,
- "note": "string",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "hsnCode": "string",
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "quantity": 0,
- "unitPrice": 0,
- "taxableAmount": 0,
- "ratePct": 0,
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a DRAFT invoice's fields and lines. Requires permission: FINANCE_WRITE. A POSTED or CANCELLED invoice is immutable (422).
| id required | integer <int64> |
| type required | string Enum: "AR" "AP" |
| invoiceDate required | string <date> |
| customerId | integer <int64> Required for AR (and must be null for AP). |
| supplierId | integer <int64> Required for AP (and must be null for AR). |
| placeOfSupply | string = 2 characters 2-digit GST state code; defaults from the counterparty at post. |
| note | string <= 500 characters |
required | Array of objects (InvoiceLineRequest) non-empty |
{- "type": "AR",
- "invoiceDate": "2019-08-24",
- "customerId": 0,
- "supplierId": 0,
- "placeOfSupply": "st",
- "note": "string",
- "lines": [
- {
- "productId": 0,
- "materialId": 0,
- "taxCodeId": 0,
- "quantity": 0,
- "unitPrice": 0
}
]
}{- "id": 0,
- "type": "AR",
- "invoiceNumber": "string",
- "invoiceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "placeOfSupply": "string",
- "supplyType": "INTRA",
- "status": "DRAFT",
- "subtotal": 0,
- "totalCgst": 0,
- "totalSgst": 0,
- "totalIgst": 0,
- "roundingAdjustment": 0,
- "totalAmount": 0,
- "journalEntryId": 0,
- "settled": true,
- "salesOrderId": 0,
- "milestoneId": 0,
- "note": "string",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "hsnCode": "string",
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "quantity": 0,
- "unitPrice": 0,
- "taxableAmount": 0,
- "ratePct": 0,
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a DRAFT invoice. Requires permission: FINANCE_WRITE. A POSTED invoice cannot be deleted — cancel it instead (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Generate the GST tax invoice for this invoice on the fly and stream it as a downloadable PDF. Requires permission: FINANCE_READ — the same permission as viewing the invoice, so no file is reachable without it. The response is application/pdf with a Content-Disposition: attachment; filename="AR-000089.pdf" header (the invoice number). Everything is read from the frozen posted snapshot (place of supply, supply type, the CGST/SGST or IGST split, totals) — nothing is recomputed. Only a posted or cancelled invoice has a frozen snapshot to print; a DRAFT is rejected (422 — post it first). Unknown id → 404. Nothing is stored: the PDF is rendered per request.
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Posts a DRAFT invoice (→ POSTED) and auto-posts its balanced journal entry. Requires permission: JOURNAL_POST. The GST split (CGST+SGST vs IGST) is derived from place of supply vs the company state and frozen onto the lines; rounding posts to the Rounding account. A missing counterparty state or no resolvable tax rate → 422.
| id required | integer <int64> |
{- "id": 0,
- "type": "AR",
- "invoiceNumber": "string",
- "invoiceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "placeOfSupply": "string",
- "supplyType": "INTRA",
- "status": "DRAFT",
- "subtotal": 0,
- "totalCgst": 0,
- "totalSgst": 0,
- "totalIgst": 0,
- "roundingAdjustment": 0,
- "totalAmount": 0,
- "journalEntryId": 0,
- "settled": true,
- "salesOrderId": 0,
- "milestoneId": 0,
- "note": "string",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "hsnCode": "string",
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "quantity": 0,
- "unitPrice": 0,
- "taxableAmount": 0,
- "ratePct": 0,
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Cancels a POSTED invoice (→ CANCELLED) and reverses its journal entry. Requires permission: JOURNAL_POST. Cancelling a DRAFT → 422 (delete it instead).
| id required | integer <int64> |
{- "id": 0,
- "type": "AR",
- "invoiceNumber": "string",
- "invoiceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "placeOfSupply": "string",
- "supplyType": "INTRA",
- "status": "DRAFT",
- "subtotal": 0,
- "totalCgst": 0,
- "totalSgst": 0,
- "totalIgst": 0,
- "roundingAdjustment": 0,
- "totalAmount": 0,
- "journalEntryId": 0,
- "settled": true,
- "salesOrderId": 0,
- "milestoneId": 0,
- "note": "string",
- "createdBy": 0,
- "lines": [
- {
- "id": 0,
- "productId": 0,
- "productSku": "string",
- "productName": "string",
- "materialId": 0,
- "materialSku": "string",
- "materialName": "string",
- "hsnCode": "string",
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "quantity": 0,
- "unitPrice": 0,
- "taxableAmount": 0,
- "ratePct": 0,
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "lineTotal": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns a page of payments (summary rows). Optionally filter by type (IN/OUT), status, counterpartyId, and/or an inclusive payment-date range (dateFrom/dateTo) — independent AND filters. Requires permission: FINANCE_READ.
| type | string Enum: "IN" "OUT" Restrict to incoming ( |
| status | string Enum: "DRAFT" "POSTED" "CANCELLED" Restrict to a single lifecycle state. |
| counterpartyId | integer <int64> Restrict to one counterparty — the customer on an IN payment or the supplier on an OUT one. |
| dateFrom | string <date> Example: dateFrom=2026-07-01 Inclusive lower bound on the payment date. |
| dateTo | string <date> Example: dateTo=2026-07-31 Inclusive upper bound on the payment date. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "type": "IN",
- "paymentNumber": "string",
- "paymentDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "status": "DRAFT",
- "grossAmount": 0,
- "tdsAmount": 0,
- "netAmount": 0,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a DRAFT payment allocated to one or more posted invoices. Requires permission: FINANCE_WRITE. An IN payment names a customer, an OUT payment a supplier (matching type; else 422). bankAccountId must be a Cash/Bank ASSET account. v1 requires FULL settlement of each allocated invoice. For OUT, TDS is resolved at post; for IN, tdsAmount is the amount the customer withheld.
| type required | string Enum: "IN" "OUT" |
| paymentDate required | string <date> |
| customerId | integer <int64> Required for IN. |
| supplierId | integer <int64> Required for OUT. |
| bankAccountId required | integer <int64> Cash/Bank ASSET account. |
| tdsSectionId | integer <int64> Optional TDS section override (OUT). |
| tdsAmount | number For IN, the amount the customer withheld (>= 0); for OUT it is resolved at post. |
| note | string <= 500 characters |
required | Array of objects (PaymentAllocationRequest) non-empty |
{- "type": "OUT",
- "paymentDate": "2026-07-10",
- "supplierId": 387500,
- "bankAccountId": 387202,
- "tdsSectionId": 387280,
- "note": "Vendor settlement",
- "allocations": [
- {
- "invoiceId": 387900,
- "allocatedAmount": 118000
}
]
}{- "id": 0,
- "type": "IN",
- "paymentNumber": "string",
- "paymentDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "tdsSectionId": 0,
- "tdsSectionCode": "string",
- "grossAmount": 0,
- "tdsAmount": 0,
- "tdsBaseAmount": 0,
- "netAmount": 0,
- "status": "DRAFT",
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "allocations": [
- {
- "id": 0,
- "invoiceId": 0,
- "invoiceNumber": "string",
- "allocatedAmount": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one payment with its allocations and TDS breakdown. Requires permission: FINANCE_READ.
| id required | integer <int64> |
{- "id": 0,
- "type": "IN",
- "paymentNumber": "string",
- "paymentDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "tdsSectionId": 0,
- "tdsSectionCode": "string",
- "grossAmount": 0,
- "tdsAmount": 0,
- "tdsBaseAmount": 0,
- "netAmount": 0,
- "status": "DRAFT",
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "allocations": [
- {
- "id": 0,
- "invoiceId": 0,
- "invoiceNumber": "string",
- "allocatedAmount": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a DRAFT payment's fields and allocations. Requires permission: FINANCE_WRITE. A POSTED or CANCELLED payment is immutable (422).
| id required | integer <int64> |
| type required | string Enum: "IN" "OUT" |
| paymentDate required | string <date> |
| customerId | integer <int64> Required for IN. |
| supplierId | integer <int64> Required for OUT. |
| bankAccountId required | integer <int64> Cash/Bank ASSET account. |
| tdsSectionId | integer <int64> Optional TDS section override (OUT). |
| tdsAmount | number For IN, the amount the customer withheld (>= 0); for OUT it is resolved at post. |
| note | string <= 500 characters |
required | Array of objects (PaymentAllocationRequest) non-empty |
{- "type": "IN",
- "paymentDate": "2019-08-24",
- "customerId": 0,
- "supplierId": 0,
- "bankAccountId": 0,
- "tdsSectionId": 0,
- "tdsAmount": 0,
- "note": "string",
- "allocations": [
- {
- "invoiceId": 0,
- "allocatedAmount": 0
}
]
}{- "id": 0,
- "type": "IN",
- "paymentNumber": "string",
- "paymentDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "tdsSectionId": 0,
- "tdsSectionCode": "string",
- "grossAmount": 0,
- "tdsAmount": 0,
- "tdsBaseAmount": 0,
- "netAmount": 0,
- "status": "DRAFT",
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "allocations": [
- {
- "id": 0,
- "invoiceId": 0,
- "invoiceNumber": "string",
- "allocatedAmount": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a DRAFT payment. Requires permission: FINANCE_WRITE. A POSTED payment cannot be deleted — cancel it instead (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Posts a DRAFT payment (→ POSTED), resolves TDS (for OUT), settles the allocated invoice(s), and auto-posts the journal entry. Requires permission: PAYMENT_APPROVE. A second payment settling an already-settled or mismatched-type invoice → 422.
| id required | integer <int64> |
{- "id": 0,
- "type": "IN",
- "paymentNumber": "string",
- "paymentDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "tdsSectionId": 0,
- "tdsSectionCode": "string",
- "grossAmount": 0,
- "tdsAmount": 0,
- "tdsBaseAmount": 0,
- "netAmount": 0,
- "status": "DRAFT",
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "allocations": [
- {
- "id": 0,
- "invoiceId": 0,
- "invoiceNumber": "string",
- "allocatedAmount": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Cancels a POSTED payment (→ CANCELLED), reverses its journal entry, unsettles the invoice, and rolls back the TDS ledger. Requires permission: PAYMENT_APPROVE. Cancelling a DRAFT → 422.
| id required | integer <int64> |
{- "id": 0,
- "type": "IN",
- "paymentNumber": "string",
- "paymentDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "supplierId": 0,
- "supplierName": "string",
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "tdsSectionId": 0,
- "tdsSectionCode": "string",
- "grossAmount": 0,
- "tdsAmount": 0,
- "tdsBaseAmount": 0,
- "netAmount": 0,
- "status": "DRAFT",
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "allocations": [
- {
- "id": 0,
- "invoiceId": 0,
- "invoiceNumber": "string",
- "allocatedAmount": 0
}
], - "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns a page of customer advance receipts (summary rows). Requires permission: FINANCE_READ. Filter by customerId and/or status.
| customerId | integer <int64> |
| status | string Enum: "DRAFT" "POSTED" "CANCELLED" |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "advanceNumber": "string",
- "advanceDate": "2019-08-24",
- "customerId": 0,
- "milestoneId": 0,
- "amount": 0,
- "grossAmount": 0,
- "status": "DRAFT",
- "adjusted": true,
- "createdBy": 0,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a DRAFT customer advance against a milestone. Requires permission: FINANCE_WRITE. amount is pre-tax; a service advance (gstOnAdvance) also collects output GST and must name a taxCodeId. bankAccountId must be an ASSET account.
| advanceDate required | string <date> |
| customerId required | integer <int64> |
| salesOrderId required | integer <int64> |
| milestoneId required | integer <int64> |
| bankAccountId required | integer <int64> Cash/Bank ASSET account. |
| amount required | number Pre-tax amount (> 0). |
| gstOnAdvance | boolean A service advance collects output GST at receipt. |
| taxCodeId | integer <int64> Required when gstOnAdvance is true. |
| placeOfSupply | string = 2 characters |
| note | string <= 500 characters |
{- "advanceDate": "2026-07-02",
- "customerId": 387600,
- "salesOrderId": 387700,
- "milestoneId": 387710,
- "bankAccountId": 387202,
- "amount": 256500,
- "gstOnAdvance": true,
- "taxCodeId": 387260,
- "placeOfSupply": "27",
- "note": "Advance for milestone 1"
}{- "id": 0,
- "advanceNumber": "string",
- "advanceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "salesOrderId": 0,
- "milestoneId": 0,
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "amount": 0,
- "gstOnAdvance": true,
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "placeOfSupply": "string",
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "grossAmount": 0,
- "status": "DRAFT",
- "adjusted": true,
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one advance receipt with its frozen GST split. Requires permission: FINANCE_READ.
| id required | integer <int64> |
{- "id": 0,
- "advanceNumber": "string",
- "advanceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "salesOrderId": 0,
- "milestoneId": 0,
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "amount": 0,
- "gstOnAdvance": true,
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "placeOfSupply": "string",
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "grossAmount": 0,
- "status": "DRAFT",
- "adjusted": true,
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a DRAFT advance's fields. Requires permission: FINANCE_WRITE. A POSTED or CANCELLED advance is immutable (422).
| id required | integer <int64> |
| advanceDate required | string <date> |
| customerId required | integer <int64> |
| salesOrderId required | integer <int64> |
| milestoneId required | integer <int64> |
| bankAccountId required | integer <int64> Cash/Bank ASSET account. |
| amount required | number Pre-tax amount (> 0). |
| gstOnAdvance | boolean A service advance collects output GST at receipt. |
| taxCodeId | integer <int64> Required when gstOnAdvance is true. |
| placeOfSupply | string = 2 characters |
| note | string <= 500 characters |
{- "advanceDate": "2019-08-24",
- "customerId": 0,
- "salesOrderId": 0,
- "milestoneId": 0,
- "bankAccountId": 0,
- "amount": 0,
- "gstOnAdvance": true,
- "taxCodeId": 0,
- "placeOfSupply": "st",
- "note": "string"
}{- "id": 0,
- "advanceNumber": "string",
- "advanceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "salesOrderId": 0,
- "milestoneId": 0,
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "amount": 0,
- "gstOnAdvance": true,
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "placeOfSupply": "string",
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "grossAmount": 0,
- "status": "DRAFT",
- "adjusted": true,
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a DRAFT advance receipt. Requires permission: FINANCE_WRITE. A POSTED advance cannot be deleted — cancel it instead (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Posts a DRAFT advance (→ POSTED) and auto-posts the journal entry (Dr Bank / Cr Customer Advances, plus output GST for a service advance). Requires permission: PAYMENT_APPROVE. The amount must not exceed the milestone's taxable value and the milestone must still be PENDING (else 422).
| id required | integer <int64> |
{- "id": 0,
- "advanceNumber": "string",
- "advanceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "salesOrderId": 0,
- "milestoneId": 0,
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "amount": 0,
- "gstOnAdvance": true,
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "placeOfSupply": "string",
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "grossAmount": 0,
- "status": "DRAFT",
- "adjusted": true,
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Cancels a POSTED advance (→ CANCELLED) and reverses its journal entry. Requires permission: PAYMENT_APPROVE. Only permitted while the advance is unadjusted — cancel the milestone invoice first if it has been adjusted (422).
| id required | integer <int64> |
{- "id": 0,
- "advanceNumber": "string",
- "advanceDate": "2019-08-24",
- "customerId": 0,
- "customerName": "string",
- "salesOrderId": 0,
- "milestoneId": 0,
- "bankAccountId": 0,
- "bankAccountCode": "string",
- "amount": 0,
- "gstOnAdvance": true,
- "taxCodeId": 0,
- "taxCodeCode": "string",
- "placeOfSupply": "string",
- "cgstAmt": 0,
- "sgstAmt": 0,
- "igstAmt": 0,
- "grossAmount": 0,
- "status": "DRAFT",
- "adjusted": true,
- "journalEntryId": 0,
- "note": "string",
- "createdBy": 0,
- "cancelledBy": 0,
- "cancelledAt": "2019-08-24T14:15:22Z",
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns a page of departments. Requires permission: HR_READ. Sortable fields: name (default) and code.
| active | boolean Filter by active flag. Omit to return both active and inactive departments. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "name": "string",
- "code": "string",
- "description": "string",
- "managerId": 0,
- "managerName": "string",
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates a department. Requires permission: HR_WRITE. name and (if given) code are unique — a duplicate returns 409. managerId, if given, must reference an existing employee.
| name required | string <= 150 characters Department name (unique). |
| code | string <= 40 characters Optional short code (unique when present). |
| description | string <= 500 characters |
| managerId | integer <int64> Optional employee who leads the department. |
| active | boolean Optional. Absent leaves the default (active) on create or the current value on update. |
{- "name": "Production",
- "code": "PROD",
- "description": "Fabrication and assembly of heat exchangers.",
- "managerId": 387412,
- "active": true
}{- "id": 0,
- "name": "string",
- "code": "string",
- "description": "string",
- "managerId": 0,
- "managerName": "string",
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one department by id. Requires permission: HR_READ.
| id required | integer <int64> |
{- "id": 0,
- "name": "string",
- "code": "string",
- "description": "string",
- "managerId": 0,
- "managerName": "string",
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces a department's fields. Requires permission: HR_WRITE. name/code uniqueness is enforced (409). Send managerId: null to clear the manager link.
| id required | integer <int64> |
| name required | string <= 150 characters Department name (unique). |
| code | string <= 40 characters Optional short code (unique when present). |
| description | string <= 500 characters |
| managerId | integer <int64> Optional employee who leads the department. |
| active | boolean Optional. Absent leaves the default (active) on create or the current value on update. |
{- "name": "Production",
- "code": "PROD",
- "description": "Fabrication, welding, and assembly.",
- "managerId": 387412,
- "active": true
}{- "id": 0,
- "name": "string",
- "code": "string",
- "description": "string",
- "managerId": 0,
- "managerName": "string",
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes a department. Requires permission: HR_WRITE. A department that still has employees cannot be deleted — deactivate it instead (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}Returns a page of employees (summary rows with the resolved department name). Requires permission: HR_READ. Sortable fields: employeeCode (default), lastName, hireDate.
| departmentId | integer <int64> Filter to employees in this department. |
| active | boolean Filter by active flag. Omit to return both active and inactive employees. |
| page | integer >= 0 Default: 0 Zero-based page index. |
| size | integer [ 1 .. 100 ] Default: 20 Page size. Defaults to 20; requests above 100 are clamped to 100. |
| sort | string Example: sort=name,asc Sort clause as |
{- "content": [
- {
- "id": 0,
- "employeeCode": "string",
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "jobTitle": "string",
- "hireDate": "2019-08-24",
- "departmentId": 0,
- "departmentName": "string",
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "page": 0,
- "size": 20,
- "totalElements": 137,
- "totalPages": 7,
- "sort": [
- {
- "field": "name",
- "direction": "asc"
}
]
}Creates an employee. Requires permission: HR_WRITE. employeeCode, email, and userId are each unique (duplicate → 409). departmentId and userId are optional links; a userId may be linked to at most one employee.
| employeeCode required | string <= 40 characters Employee code (unique). |
| firstName required | string <= 100 characters |
| lastName required | string <= 100 characters |
| email required | string <email> <= 255 characters Email address (unique). |
| phone | string <= 40 characters |
| jobTitle | string <= 150 characters |
| hireDate required | string <date> Hire date. Future dates are allowed for onboarding. |
| departmentId | integer <int64> Optional department link (send null to clear). |
| userId | integer <int64> Optional login-user link (unique; at most one employee per user; send null to clear). |
| active | boolean Optional. Absent leaves the default (active) on create or the current value on update. |
{- "employeeCode": "EMP013",
- "firstName": "Sanjay",
- "lastName": "Kulkarni",
- "email": "sanjay.kulkarni@forgethermal.co.in",
- "phone": "+91 98200 11334",
- "jobTitle": "Production Manager",
- "hireDate": "2019-04-01",
- "departmentId": 387405,
- "userId": 387360,
- "active": true
}{- "id": 0,
- "employeeCode": "string",
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "phone": "string",
- "jobTitle": "string",
- "hireDate": "2019-08-24",
- "departmentId": 0,
- "departmentName": "string",
- "userId": 0,
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Returns one employee by id, with the resolved department name. Requires permission: HR_READ.
| id required | integer <int64> |
{- "id": 0,
- "employeeCode": "string",
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "phone": "string",
- "jobTitle": "string",
- "hireDate": "2019-08-24",
- "departmentId": 0,
- "departmentName": "string",
- "userId": 0,
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Replaces an employee's fields. Requires permission: HR_WRITE. employeeCode/email/userId uniqueness is enforced (409). Send departmentId: null or userId: null to clear those links.
| id required | integer <int64> |
| employeeCode required | string <= 40 characters Employee code (unique). |
| firstName required | string <= 100 characters |
| lastName required | string <= 100 characters |
| email required | string <email> <= 255 characters Email address (unique). |
| phone | string <= 40 characters |
| jobTitle | string <= 150 characters |
| hireDate required | string <date> Hire date. Future dates are allowed for onboarding. |
| departmentId | integer <int64> Optional department link (send null to clear). |
| userId | integer <int64> Optional login-user link (unique; at most one employee per user; send null to clear). |
| active | boolean Optional. Absent leaves the default (active) on create or the current value on update. |
{- "employeeCode": "EMP013",
- "firstName": "Sanjay",
- "lastName": "Kulkarni",
- "email": "sanjay.kulkarni@forgethermal.co.in",
- "phone": "+91 98200 11334",
- "jobTitle": "Senior Production Manager",
- "hireDate": "2019-04-01",
- "departmentId": 387405,
- "userId": 387360,
- "active": true
}{- "id": 0,
- "employeeCode": "string",
- "firstName": "string",
- "lastName": "string",
- "email": "user@example.com",
- "phone": "string",
- "jobTitle": "string",
- "hireDate": "2019-08-24",
- "departmentId": 0,
- "departmentName": "string",
- "userId": 0,
- "active": true,
- "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z"
}Deletes an employee. Requires permission: HR_WRITE. An employee who manages a department cannot be deleted — reassign the department's manager or deactivate the employee instead (422).
| id required | integer <int64> |
{- "type": "about:blank",
- "title": "Unauthorized",
- "status": 401,
- "detail": "Authentication is required to access this resource.",
- "instance": "/products",
- "timestamp": "2026-07-09T14:12:03.221Z"
}