Generic CRUD API
OpenBoxes provides a generic REST endpoint that offers uniform CRUD operations across all domain classes. This is useful for accessing entities that do not have a dedicated REST endpoint, or when you need a consistent interface across different object types.
Endpoint Pattern#
GET /api/v1/generic/{domainClass} # List all
GET /api/v1/generic/{domainClass}/{id} # Get by ID
POST /api/v1/generic/{domainClass} # Create
PUT /api/v1/generic/{domainClass}/{id} # Update
DELETE /api/v1/generic/{domainClass}/{id} # Delete
Replace {domainClass} with the camelCase name of the domain object.
Available Domain Classes#
The following domain classes are accessible through the generic API:
| Domain Class | Description | Dedicated Endpoint? |
|---|---|---|
product |
Products in the catalog | Yes (/api/v1/products) |
inventoryItem |
Lot/batch records | No |
shipment |
Shipment records | No |
shipmentItem |
Items within a shipment | No |
requisition |
Internal requests/orders | No |
requisitionItem |
Items within a requisition | No |
transaction |
Inventory transactions | No |
transactionEntry |
Line items within a transaction | No |
category |
Product categories | No |
locationType |
Location type definitions | No |
locationGroup |
Location groupings | No |
person |
People records (contacts); user accounts are not accessible through this API | No |
organization |
Organizations | No |
Security-related objects — user accounts, roles, location roles, documents and document types — are not accessible through the Generic API on the hosted platform, and person is read-only there because user accounts are person records; manage them in the OpenBoxes interface instead.
List Objects#
Retrieve a paginated list of objects for any of the domain classes listed above:
# List inventory items
curl -H "X-API-Key: $OB_API_KEY" \
"https://acme.openboxes.cloud/api/v1/generic/inventoryItem?max=25&offset=0"
# List product categories
curl -H "X-API-Key: $OB_API_KEY" \
"https://acme.openboxes.cloud/api/v1/generic/category?max=50"
# List shipments
curl -H "X-API-Key: $OB_API_KEY" \
"https://acme.openboxes.cloud/api/v1/generic/shipment?max=10&offset=0"
Query Parameters#
| Parameter | Type | Default | Description |
|---|---|---|---|
max |
integer | all | Maximum records to return |
offset |
integer | 0 |
Number of records to skip |
Get by ID#
Retrieve a single object by its ID:
curl -H "X-API-Key: $OB_API_KEY" \
"https://acme.openboxes.cloud/api/v1/generic/inventoryItem/inv-001"
Response#
{
"id": "inv-001",
"lotNumber": "LOT-2025-001",
"expirationDate": "2026-06-30T00:00:00Z",
"product": {
"id": "prod-001",
"name": "Ibuprofen 200mg"
},
"dateCreated": "2025-01-10T08:00:00Z",
"lastUpdated": "2025-03-15T12:30:00Z"
}
Create Object#
Create a new object of any of the domain classes listed above:
# Create a product category
curl -X POST \
-H "X-API-Key: $OB_API_KEY" \
-H "Content-Type: application/json" \
"https://acme.openboxes.cloud/api/v1/generic/category" \
-d '{
"name": "Surgical Supplies",
"description": "Instruments and consumables for surgery"
}'
# Create an inventory item (lot record)
curl -X POST \
-H "X-API-Key: $OB_API_KEY" \
-H "Content-Type: application/json" \
"https://acme.openboxes.cloud/api/v1/generic/inventoryItem" \
-d '{
"product": { "id": "prod-001" },
"lotNumber": "LOT-2025-099",
"expirationDate": "2027-12-31T00:00:00Z"
}'
Update Object#
Update an existing object by ID:
curl -X PUT \
-H "X-API-Key: $OB_API_KEY" \
-H "Content-Type: application/json" \
"https://acme.openboxes.cloud/api/v1/generic/category/cat-005" \
-d '{
"name": "Surgical Supplies & Instruments",
"description": "Updated description"
}'
Only include the fields you want to change. Omitted fields are not modified.
Delete Object#
Delete an object by ID:
curl -X DELETE \
-H "X-API-Key: $OB_API_KEY" \
"https://acme.openboxes.cloud/api/v1/generic/category/cat-005"
Warning: Deletion fails if the object has dependent records (e.g., deleting a category used by products). Deactivate records instead of deleting when possible.
When to Use Generic vs. Dedicated Endpoints#
| Use Generic API When... | Use Dedicated Endpoints When... |
|---|---|
No dedicated endpoint exists (e.g., inventoryItem, category) |
A specific endpoint exists (e.g., /api/v1/products, /api/v1/stockMovements) |
| You need uniform CRUD across multiple domain classes | You need advanced features like search, filtering, or status transitions |
| Building a general-purpose integration layer | Working with stock movements or purchase orders (complex workflows) |
Dedicated endpoints often provide richer query parameters, nested data, and workflow-specific operations (like shipping or receiving) that the generic API does not support.
Response Differences#
The generic API returns objects with a flat structure. Associations are returned as references with id and basic fields:
{
"id": "inv-001",
"product": {
"id": "prod-001",
"name": "Ibuprofen 200mg",
"class": "org.pih.warehouse.product.Product"
}
}
The class field indicates the Grails domain class of associated objects.
Pagination Notes#
Pagination via max and offset works on most domain classes through the generic API. However, behavior may vary:
- Some domain classes return all records regardless of
max - Very large result sets may time out before completing
- Always test pagination for your specific domain class
Error Handling#
{
"errorCode": 400,
"errorMessage": "Property [name] of class [class Category] cannot be null"
}
Common errors:
| Error | Cause |
|---|---|
cannot be null |
Required field was omitted |
must be unique |
A unique constraint was violated |
not found |
Referenced ID does not exist |
optimistic locking |
Object was modified by another request |