Skip to main content

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 Audits
GET/warehousing/inventory-audits

Retrieves 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

  • statusCounts and stats use the same tenant, warehouse, audit type, date, search, notes, creator, and completer filters as the list.

  • Only the selected status filter 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, and cancelled directly for the tabs.

Response

  • Returns a paginated list of inventory audit records with basic information

  • Excludes audit_items and discrepancies for performance optimization

  • Includes user information for audit creation and completion

  • Provides pagination information (total count, current page, limit)

Query parameters

ParameterTypeDescription
tenant_idRequiredstring

UUID of the tenant (required)

Example: {{tenant_id}}

warehouse_idOptionalstring

Filter by warehouse (optional)

audit_typeOptionalstring

Filter by audit type (cycle_count, full_count, spot_check) (optional)

statusOptionalstring

Filter by audit status (scheduled, in_progress, completed, cancelled) (optional)

scheduled_dateOptionalstring

Filter by scheduled date (YYYY-MM-DD) (optional)

pageOptionalstring

Page number for pagination (optional) Page number for pagination (default: 1)

Example: 1

limitOptionalstring

Number of items per page (optional) Number of items per page (default: 20)

Example: 20

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Staging
Request
curl
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

200Success Response
Response body
json
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
GET/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 item object with name and sku, plus a bin object with name and code; IDs remain machine identifiers only

  • Includes progress with counted, uncounted, no-difference, shortage, overage, write-off, and marker-only totals

  • Includes 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, and bin.code for audit-scoped display and search.

Path parameters

ParameterTypeDescription
audit_idRequiredstring

UUID of the audit record

Query parameters

ParameterTypeDescription
tenant_idRequiredstring

UUID of the tenant (required)

Example: {{tenant_id}}

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Staging
Request
curl
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

200Success Response
Response body
json
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": "john.doe@example.com"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
PUT/warehousing/inventory-audits/{{audit_id}}/record-count

Atomically 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_quantity is 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; use GET /warehousing/exceptions/available and show every returned tenant-defined type.

  • A type with write_off_stock=true writes off the shortage through the warehouse-exception owner, clamps invalid reservations, and creates stock_adjustment transactions linked to this audit.

  • A type with write_off_stock=false creates 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 progress counts 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

ParameterTypeDescription
audit_idRequiredstring

Variable used inside the request path.

Query parameters

ParameterTypeDescription
tenant_idRequiredstring

UUID of the tenant (required)

Example: {{tenant_id}}

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
item_countsarray<object>—
item_counts.item_idstring—
item_counts.bin_idstring—
item_counts.actual_quantitynumber—
item_counts.exception_typestring—
item_counts.notesstring—
Staging
Request
curl
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)
Request example 1
json
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

200Success Response
Response body
json
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
PUT/warehousing/inventory-audits/{{audit_id}}/complete

Finalizes 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_items and remaining_count. The audit stays resumable.

  • inventory_audit_shortage_missing_exception is returned if a shortage has no exception.

  • Sets status, completion_date, and completed_by only 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

ParameterTypeDescription
audit_idRequiredstring

Variable used inside the request path.

Query parameters

ParameterTypeDescription
tenant_idRequiredstring

UUID of the tenant (required)

Example: {{tenant_id}}

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
completion_notesstring—
Staging
Request
curl
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)
Request example 1
json
1{2  "completion_notes": "string"3}

Response examples

200Success Response
Response body
json
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 Audits
POST/warehousing/inventory-audits

Creates 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, or spot_check

  • Scheduled date must be a valid date

  • Items behavior depends on audit type:

    • cycle_count: Automatically selects 20% of inventory items randomly

    • full_count: Includes all inventory items in the warehouse

    • spot_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

ParameterTypeDescription
tenant_idRequiredstring

UUID of the tenant (required)

Example: {{tenant_id}}

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
warehouse_idstring—
audit_typestring—
scheduled_datestring—
audit_itemsarray<object>—
audit_items.item_idstring—
audit_items.bin_idstring—
audit_items.expected_quantitynumber—
notesstring—
Staging
Request
curl
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)
Request example 1
text
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

201Success Response
Response body
json
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}