Inventory Audits
5 API calls in this section.
Endpoints for managing inventory audits and stock verification processes. These APIs support different audit types (cycle counts, full counts, spot checks) for validating physical inventory against recorded quantities. Includes complete workflow from audit creation through completion with stock adjustments.
List Inventory Audits
/warehousing/inventory-auditsRetrieves inventory audit records with comprehensive filtering options. Returns optimized list without audit_items and discrepancies for performance. Use Get Single Inventory Audit for complete details.
User must have 'view:tenant' or 'manage:operations:tenant' permission
Business Rules
statusCountsandstatsuse the same tenant, warehouse, audit type, date, search, notes, creator, and completer filters as the list.Only the selected
statusfilter is excluded from counters, so all tab counts remain available.Counters are grouped in PostgreSQL and are not calculated by downloading all audit rows into the Edge Function.
Frontend integration contract
Continue sending the selected warehouse ID as
warehouse_id.Use
statusCounts.total,scheduled,in_progress,completed, andcancelleddirectly for the tabs.
Response
Returns a paginated list of inventory audit records with basic information
Excludes
audit_itemsand discrepancies for performance optimizationIncludes user information for audit creation and completion
Provides pagination information (total count, current page, limit)
Query parameters
| Parameter | Type | Description |
|---|---|---|
tenant_idRequired | string | UUID of the tenant (required) Example: |
warehouse_idOptional | string | Filter by warehouse (optional) |
audit_typeOptional | string | Filter by audit type ( |
statusOptional | string | Filter by audit status (scheduled, |
scheduled_dateOptional | string | Filter by scheduled date (YYYY-MM-DD) (optional) |
pageOptional | string | Page number for pagination (optional) Page number for pagination (default: 1) Example: |
limitOptional | string | Number of items per page (optional) Number of items per page (default: 20) Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/warehousing/inventory-audits?tenant_id=${TENANT_ID}&warehouse_id=&audit_type=&status=&scheduled_date=&page=1&limit=20" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json"Response examples
1{2 "success": true,3 "message": "Inventory audits retrieved successfully",4 "audits": [5 {6 "id": "audit-uuid-1",7 "created_by_user": {8 "id": "user-uuid-1",9 "full_name": "John Doe"10 },11 "audit_type": "cycle_count",12 "status": "scheduled",13 "created_at": "2023-07-01T10:00:00Z",14 "discrepancy_count": 0,15 "notes": "Monthly cycle count for electronics section",16 "scheduled_date": "2023-07-15",17 "completed_by_user": null,18 "completion_date": null,19 "warehouse": {20 "id": "warehouse-uuid",21 "name": "Main Warehouse",22 "code": "WH001"23 }24 },25 {26 "id": "audit-uuid-2",27 "created_by_user": {28 "id": "user-uuid-1",29 "full_name": "John Doe"30 },31 "audit_type": "spot_check",32 "status": "completed",33 "created_at": "2023-06-19T14:30:00Z",34 "discrepancy_count": 1,35 "notes": "Spot check due to reported discrepancy",36 "scheduled_date": "2023-06-20",37 "completed_by_user": {38 "id": "user-uuid-2",39 "full_name": "Jane Smith"40 },41 "completion_date": "2023-06-20",42 "warehouse": {43 "id": "warehouse-uuid",44 "name": "Main Warehouse",45 "code": "WH001"46 }47 }48 ],49 "page": 1,50 "limit": 20,51 "total": 2,52 "stats": {53 "total": 2,54 "scheduled": 1,55 "in_progress": 0,56 "completed": 1,57 "cancelled": 058 },59 "statusCounts": {60 "total": 2,61 "scheduled": 1,62 "in_progress": 0,63 "completed": 1,64 "cancelled": 065 }66}Get Single Inventory Audit
/warehousing/inventory-audits/{{audit_id}}Retrieves a single inventory audit record with complete details including audit_items and discrepancies. Essential for Conduct Audit Screen and Audit Summary Screen.
User must have 'view:tenant' or 'manage:operations:tenant' permission
Response
Returns complete audit details including all audit items and discrepancies
Every line includes an
itemobject withnameandsku, plus abinobject withnameandcode; IDs remain machine identifiers onlyIncludes
progresswith counted, uncounted, no-difference, shortage, overage, write-off, and marker-only totalsIncludes detailed user information for audit creation and completion
Includes full warehouse information
Large audits and read failures
Item, bin, and exception details cover the complete audit scope, including audits above 1,000 entries; lookups do not use an ID list in the URL or a capped table response.
If the reference-data lookup fails, GET returns HTTP 500 with the existing localized internal-server-error message instead of a successful response with unloaded details.
Frontend integration is unchanged: use each line's
item.name,item.sku,bin.name, andbin.codefor audit-scoped display and search.
Path parameters
| Parameter | Type | Description |
|---|---|---|
audit_idRequired | string | UUID of the audit record |
Query parameters
| Parameter | Type | Description |
|---|---|---|
tenant_idRequired | string | UUID of the tenant (required) Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/warehousing/inventory-audits/${AUDIT_ID}?tenant_id=${TENANT_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json"Response examples
1{2 "success": true,3 "message": "Inventory audit retrieved successfully",4 "audit": {5 "id": "audit-uuid-1",6 "tenant_id": "tenant-uuid",7 "warehouse_id": "warehouse-uuid",8 "audit_type": "cycle_count",9 "status": "in_progress",10 "scheduled_date": "2023-07-15",11 "completed_date": null,12 "created_by": "user-uuid-1",13 "completed_by": null,14 "audit_items": [15 {16 "item_id": "item-uuid-1",17 "bin_id": "bin-uuid-1",18 "expected_quantity": 100,19 "actual_quantity": 98,20 "discrepancy": -2,21 "notes": "Found 2 items missing"22 },23 {24 "item_id": "item-uuid-2",25 "bin_id": "bin-uuid-2",26 "expected_quantity": 50,27 "actual_quantity": null,28 "discrepancy": null,29 "notes": null30 }31 ],32 "discrepancies": [33 {34 "item_id": "item-uuid-1",35 "bin_id": "bin-uuid-1",36 "expected_quantity": 100,37 "actual_quantity": 98,38 "discrepancy": -2,39 "notes": "Found 2 items missing"40 }41 ],42 "discrepancy_count": 1,43 "notes": "Monthly cycle count for electronics section",44 "created_at": "2023-07-01T10:00:00Z",45 "updated_at": "2023-07-15T09:30:00Z",46 "created_by_user": {47 "id": "user-uuid-1",48 "full_name": "John Doe",49 "email": "[email protected]"50 },51 "completed_by_user": null,52 "warehouse": {53 "id": "warehouse-uuid",54 "name": "Main Warehouse",55 "code": "WH001",56 "address": "123 Warehouse St, Industrial District"57 }58 }59}Record Item Count in Audit
/warehousing/inventory-audits/{{audit_id}}/record-countAtomically records one or many item counts. This endpoint is the Save Count and Continue write boundary.
Requires valid authentication token and warehouse mutation access.
Business Rules
actual_quantityis a non-negative whole number.The server locks the audit and submitted stock scopes and compares the count with current book stock.
A shortage requires
exception_type; useGET /warehousing/exceptions/availableand show every returned tenant-defined type.A type with
write_off_stock=truewrites off the shortage through the warehouse-exception owner, clamps invalid reservations, and createsstock_adjustmenttransactions linked to this audit.A type with
write_off_stock=falsecreates a marker-only exception and leaves stock and reservations unchanged.No exception type is accepted when the result is not a shortage. Positive discrepancies are recorded without changing stock.
Every counted stock row is stamped with
last_counted_at. Exact retries are idempotent. Correcting a saved shortage resolves its prior audit-linked exception and creates a replacement only if the corrected count remains short.The full batch is all-or-nothing and the same item/bin may appear only once.
Response
Returns item and bin objects with names/codes, discrepancy exception fields, and
progresscounts for counted, uncounted, shortage, overage, write-off, and marker-only lines.
Important errors
inventory_audit_exception_type_required(400)inventory_audit_exception_type_invalid(400)warehouse_write_off_stock_not_available(409)inventory_audit_item_ambiguous(409)A reference-data lookup failure after the mutation has committed does not turn the successful write into an error. Count state and progress remain authoritative; a subsequent detail GET can reload display details.
Path parameters
| Parameter | Type | Description |
|---|---|---|
audit_idRequired | string | Variable used inside the request path. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
tenant_idRequired | string | UUID of the tenant (required) Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
item_counts | array<object> | — |
item_counts.item_id | string | — |
item_counts.bin_id | string | — |
item_counts.actual_quantity | number | — |
item_counts.exception_type | string | — |
item_counts.notes | string | — |
1curl --globoff --request PUT "https://staging-api.ondi.io/functions/v1/warehousing/inventory-audits/${AUDIT_ID}/record-count?tenant_id=${TENANT_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "item_counts": [6 {7 "item_id": "{{item_id}}",8 "bin_id": "{{bin_id}}",9 "actual_quantity": 0,10 "exception_type": "missing",11 "notes": "Expected parcel is missing"12 },13 {14 "item_id": "item-uuid-2",15 "bin_id": "bin-uuid-2",16 "actual_quantity": 52,17 "notes": "Found 2 extra items"18 }19 ]20}'Replace {{placeholders}} with your own values before sending.
Other request examples (1)
1{2 "item_counts": [3 {4 "item_id": "uuid",5 "bin_id": "uuid",6 "actual_quantity": 0,7 "exception_type": "missing",8 "notes": "Optional note"9 }10 ]11}Response examples
1{2 "success": true,3 "message": "Item counts recorded successfully",4 "audit": {5 "id": "audit-uuid-1",6 "status": "in_progress",7 "audit_items": [8 {9 "item_id": "item-uuid-1",10 "bin_id": "bin-uuid-1",11 "expected_quantity": 1,12 "book_quantity_at_count": 1,13 "actual_quantity": 0,14 "discrepancy": -1,15 "exception_type": "missing",16 "warehouse_exception_id": "exception-uuid",17 "stock_written_off": true,18 "write_off_status": "written_off",19 "counted_by": "user-uuid",20 "counted_at": "2026-09-10T07:00:00Z",21 "item": {22 "id": "item-uuid-1",23 "name": "Ministry of Health",24 "sku": "STAGE-3071-1"25 },26 "bin": {27 "id": "bin-uuid-1",28 "name": "Bin A1",29 "code": "A1"30 }31 }32 ],33 "progress": {34 "total_items": 2,35 "counted_items": 2,36 "uncounted_items": 0,37 "shortage_items": 1,38 "overage_items": 1,39 "write_off_items": 1,40 "marker_only_items": 041 }42 }43}Complete Inventory Audit
/warehousing/inventory-audits/{{audit_id}}/completeFinalizes an inventory audit. Completion is a validation-only state transition and never adjusts stock.
Requires valid authentication token and warehouse mutation access.
The legacy apply_stock_adjustments field is accepted and ignored, regardless of its value. Omitted, true, and false all use the same completion behavior. Older mobile clients do not need to change their request; updated clients should omit the field and remove the checkbox. Stock behavior was already determined by each shortage's selected warehouse exception type during Record Count.
Business Rules
Every audit item must have
actual_quantity.Every shortage must have
warehouse_exception_id.If items remain, HTTP 409 returns code
inventory_audit_has_uncounted_itemsandremaining_count. The audit stays resumable.inventory_audit_shortage_missing_exceptionis returned if a shortage has no exception.Sets status,
completion_date, andcompleted_byonly after validation succeeds.The response keeps item/bin names and returns
progress; marker-only shortages are not described as stock adjustments.A reference-data lookup failure after the mutation has committed does not turn the successful write into an error. Count state and progress remain authoritative; a subsequent detail GET can reload display details.
Path parameters
| Parameter | Type | Description |
|---|---|---|
audit_idRequired | string | Variable used inside the request path. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
tenant_idRequired | string | UUID of the tenant (required) Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
completion_notes | string | — |
1curl --globoff --request PUT "https://staging-api.ondi.io/functions/v1/warehousing/inventory-audits/${AUDIT_ID}/complete?tenant_id=${TENANT_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "completion_notes": "All items counted and reviewed."6}'Other request examples (1)
1{2 "completion_notes": "string"3}Response examples
1{2 "success": true,3 "message": "Inventory audit completed successfully",4 "audit": {5 "id": "audit-uuid-1",6 "status": "completed",7 "completed_by": "user-uuid-2",8 "completion_date": "2026-09-10T07:30:00Z",9 "progress": {10 "total_items": 403,11 "counted_items": 403,12 "uncounted_items": 0,13 "shortage_items": 2,14 "overage_items": 0,15 "write_off_items": 1,16 "marker_only_items": 117 }18 }19}Create Inventory Audit
/warehousing/inventory-auditsCreates a new inventory audit, which is a planned verification of actual stock against recorded quantities. Supports different audit types with varying scopes and item selection methods.
User must have 'manage:operations:tenant' permission
Business Rules
Warehouse must exist and belong to the specified tenant
Audit type must be one of:
cycle_count,full_count, orspot_checkScheduled date must be a valid date
Items behavior depends on audit type:
cycle_count: Automatically selects 20% of inventory items randomlyfull_count: Includes all inventory items in the warehousespot_check: Uses only the specific items provided in the request
For each audit item:
Item must exist in inventory
Bin must exist in the specified warehouse
Bin must be of
location_type"bin"Expected quantity defaults to current stock level if not provided
New audits are created with status "scheduled"
Large audit scope
Automatic full counts read every stock row in the tenant/warehouse before grouping by item and bin; cycle counts sample from that complete grouped scope.
Explicit item/bin requests validate all submitted IDs and include every matching stock row when calculating expected quantities, including scopes above 1,000 rows.
Existing request and response fields, expected-quantity overrides, and stock behavior are unchanged.
A reference-data lookup failure after the mutation has committed does not turn the successful write into an error. Count state and progress remain authoritative; a subsequent detail GET can reload display details.
Query parameters
| Parameter | Type | Description |
|---|---|---|
tenant_idRequired | string | UUID of the tenant (required) Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
warehouse_id | string | — |
audit_type | string | — |
scheduled_date | string | — |
audit_items | array<object> | — |
audit_items.item_id | string | — |
audit_items.bin_id | string | — |
audit_items.expected_quantity | number | — |
notes | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/warehousing/inventory-audits?tenant_id=${TENANT_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "warehouse_id": "{{warehouse_id}}",6 "audit_type": "spot_check",7 "scheduled_date": "2023-07-15",8 "audit_items": [9 {10 "item_id": "{{item_id}}",11 "bin_id": "{{bin_id}}",12 "expected_quantity": 10013 }14 ],15 "notes": "Spot check for high-value electronics"16}'Replace {{placeholders}} with your own values before sending.
Other request examples (1)
1{2 "warehouse_id": "uuid", // required3 "audit_type": "string", // required (one of: "cycle_count", "full_count", "spot_check")4 "scheduled_date": "string", // required, date in YYYY-MM-DD format5 "audit_items": [ // optional for cycle_count and full_count, required for spot_check6 {7 "item_id": "uuid", // required8 "bin_id": "uuid", // required9 "expected_quantity": number // optional, defaults to current stock quantity10 }11 ],12 "notes": "string" // optional13}Response examples
1{2 "success": true,3 "message": "Inventory audit created successfully",4 "audit": {5 "id": "audit-uuid",6 "tenant_id": "tenant-uuid",7 "warehouse_id": "warehouse-uuid",8 "audit_type": "spot_check",9 "status": "scheduled",10 "scheduled_date": "2023-07-15",11 "completed_date": null,12 "created_by": "user-uuid",13 "completed_by": null,14 "audit_items": [15 {16 "item_id": "item-uuid",17 "bin_id": "bin-uuid",18 "expected_quantity": 100,19 "actual_quantity": null,20 "discrepancy": null,21 "notes": null22 }23 ],24 "discrepancies": [],25 "discrepancy_count": 0,26 "notes": "Spot check for high-value electronics",27 "created_at": "2023-07-01T10:00:00Z",28 "updated_at": "2023-07-01T10:00:00Z"29 }30}