Skip to main content

Locations API

Overview

The Locations API provides comprehensive functionality for managing warehouse locations using a hierarchical structure. This API supports the complete location lifecycle including creation, hierarchy management, operational status control, and tree-based queries optimized for UI components.

Base URL: /api/locations

Key Features

  • Hierarchical Structure: Unlimited depth parent-child relationships
  • Tree Queries: Optimized endpoints for tree components
  • Operational Status: Control location availability for transactions
  • Physical Address Management: Optional address information for locations
  • Location Classification: Type and purpose-based organization
  • Advanced Filtering: Search by type, purpose, status, and term
  • Soft Delete: Archive and restore with history preservation

Core Endpoints

1. Get Locations (with Filtering)

Retrieves locations with advanced filtering capabilities.

GET /api/locations?locationTypeId=1&isOperational=true&searchTerm=warehouse
Accept: application/json

Query Parameters:

  • locationTypeId (optional): Filter by location type ID (int)
  • locationPurposeId (optional): Filter by location purpose ID (int)
  • isOperational (optional): Filter by operational status (bool)
  • searchTerm (optional): Search in code, name, or full path

Response:

[
{
"id": "loc-warehouse-001-id",
"code": "WH-MAIN",
"name": "Main Distribution Center",
"description": "Primary distribution facility - North Region",
"locationTypeId": 1,
"locationTypeName": "Warehouse",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": null,
"parentLocationCode": null,
"parentLocationName": null,
"fullPath": "Main Distribution Center",
"isOperational": true,
"physicalAddress": {
"street": "123 Industrial Parkway",
"city": "Springfield",
"state": "IL",
"postalCode": "62701",
"country": "USA"
},
"createdDate": "2025-01-01T08:00:00Z",
"modifiedDate": "2025-01-15T10:00:00Z"
}
]

Status Codes:

  • 200 OK - Locations retrieved successfully
  • 400 Bad Request - Invalid query parameters

2. Get Root Locations

Retrieves top-level locations (locations without parents).

GET /api/locations/root
Accept: application/json

Response:

[
{
"id": "warehouse-001-id",
"code": "WH-MAIN",
"name": "Main Distribution Center",
"description": "Primary distribution facility",
"locationTypeId": 1,
"locationTypeName": "Warehouse",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": null,
"parentLocationCode": null,
"parentLocationName": null,
"fullPath": "Main Distribution Center",
"isOperational": true,
"physicalAddress": { /* ... */ },
"createdDate": "2025-01-01T08:00:00Z",
"modifiedDate": "2025-01-15T10:00:00Z"
},
{
"id": "warehouse-002-id",
"code": "WH-SOUTH",
"name": "South Distribution Center",
"description": "Secondary facility - South Region",
"locationTypeId": 1,
"locationTypeName": "Warehouse",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": null,
"parentLocationCode": null,
"parentLocationName": null,
"fullPath": "South Distribution Center",
"isOperational": true,
"physicalAddress": null,
"createdDate": "2025-01-10T08:00:00Z",
"modifiedDate": "2025-01-20T10:00:00Z"
}
]

Status Codes:

  • 200 OK - Root locations retrieved successfully

3. Get Location Tree

Retrieves hierarchical tree structure optimized for tree UI components.

GET /api/locations/tree?maxDepth=3&operationalOnly=true
Accept: application/json

Query Parameters:

  • maxDepth (optional): Maximum depth to load (performance optimization)
  • operationalOnly (optional): Include only operational locations (default: true)

Response:

[
{
"id": "warehouse-001-id",
"code": "WH-MAIN",
"name": "Main Distribution Center",
"locationTypeId": 1,
"locationTypeName": "Warehouse",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": null,
"isOperational": true,
"hasChildren": true,
"children": [
{
"id": "zone-a-id",
"code": "ZONE-A",
"name": "Storage Zone A",
"locationTypeId": 2,
"locationTypeName": "Zone",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": "warehouse-001-id",
"isOperational": true,
"hasChildren": true,
"children": [
{
"id": "aisle-a1-id",
"code": "AISLE-A1",
"name": "Aisle A1",
"locationTypeId": 3,
"locationTypeName": "Aisle",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": "zone-a-id",
"isOperational": true,
"hasChildren": false,
"children": []
}
]
}
]
}
]

Status Codes:

  • 200 OK - Tree structure retrieved successfully

Use Cases:

  • Tree view components in UI
  • Location pickers with hierarchy display
  • Navigation menus
  • Warehouse visualization

4. Get Location by ID

Retrieves a specific location with all details.

GET /api/locations/{id}
Accept: application/json

Path Parameters:

  • id: Location ID (Guid)

Response:

{
"id": "zone-a-id",
"code": "ZONE-A",
"name": "Storage Zone A",
"description": "Primary storage area for general goods",
"locationTypeId": 2,
"locationTypeName": "Zone",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": "warehouse-001-id",
"parentLocationCode": "WH-MAIN",
"parentLocationName": "Main Distribution Center",
"fullPath": "Main Distribution Center / Storage Zone A",
"isOperational": true,
"physicalAddress": null,
"createdDate": "2025-01-02T08:00:00Z",
"modifiedDate": "2025-01-15T10:00:00Z"
}

Status Codes:

  • 200 OK - Location found and returned
  • 404 Not Found - Location not found

5. Get Location by Code

Retrieves a location by its unique code.

GET /api/locations/by-code/{code}
Accept: application/json

Path Parameters:

  • code: Location code (string)

Response:

{
"id": "zone-a-id",
"code": "ZONE-A",
"name": "Storage Zone A",
"description": "Primary storage area for general goods",
"locationTypeId": 2,
"locationTypeName": "Zone",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": "warehouse-001-id",
"parentLocationCode": "WH-MAIN",
"parentLocationName": "Main Distribution Center",
"fullPath": "Main Distribution Center / Storage Zone A",
"isOperational": true,
"physicalAddress": null,
"createdDate": "2025-01-02T08:00:00Z",
"modifiedDate": "2025-01-15T10:00:00Z"
}

Status Codes:

  • 200 OK - Location found
  • 404 Not Found - Location with specified code not found

6. Get Location Children

Retrieves immediate children of a location.

GET /api/locations/{id}/children
Accept: application/json

Path Parameters:

  • id: Parent location ID (Guid)

Response:

[
{
"id": "aisle-a1-id",
"code": "AISLE-A1",
"name": "Aisle A1",
"description": "First aisle in Zone A",
"locationTypeId": 3,
"locationTypeName": "Aisle",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": "zone-a-id",
"parentLocationCode": "ZONE-A",
"parentLocationName": "Storage Zone A",
"fullPath": "Main Distribution Center / Storage Zone A / Aisle A1",
"isOperational": true,
"physicalAddress": null,
"createdDate": "2025-01-03T08:00:00Z",
"modifiedDate": "2025-01-15T10:00:00Z"
},
{
"id": "aisle-a2-id",
"code": "AISLE-A2",
"name": "Aisle A2",
"description": "Second aisle in Zone A",
"locationTypeId": 3,
"locationTypeName": "Aisle",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": "zone-a-id",
"parentLocationCode": "ZONE-A",
"parentLocationName": "Storage Zone A",
"fullPath": "Main Distribution Center / Storage Zone A / Aisle A2",
"isOperational": true,
"physicalAddress": null,
"createdDate": "2025-01-03T08:00:00Z",
"modifiedDate": "2025-01-15T10:00:00Z"
}
]

Status Codes:

  • 200 OK - Children retrieved successfully (empty array if no children)
  • 404 Not Found - Parent location not found

7. Create Location

Creates a new location with optional parent.

POST /api/locations
Content-Type: application/json

Request Body:

{
"code": "AISLE-A1",
"name": "Aisle A1",
"description": "First aisle in Zone A",
"locationTypeId": 3,
"locationPurposeId": 1,
"parentLocationId": "zone-a-id",
"physicalAddress": {
"street": "123 Industrial Parkway",
"city": "Springfield",
"state": "IL",
"postalCode": "62701",
"country": "USA"
}
}

Field Descriptions:

  • code (required): Unique location code (auto-uppercased)
  • name (required): Display name
  • description (optional): Additional details
  • locationTypeId (required): Location type (Warehouse, Zone, Aisle, etc.)
  • locationPurposeId (required): Location purpose (Storage, Receiving, Shipping, etc.)
  • parentLocationId (optional): Parent location ID (null for root locations)
  • physicalAddress (optional): Physical address information

Response:

{
"id": "newly-created-location-id",
"code": "AISLE-A1",
"name": "Aisle A1",
"description": "First aisle in Zone A",
"locationTypeId": 3,
"locationTypeName": "Aisle",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": "zone-a-id",
"parentLocationCode": "ZONE-A",
"parentLocationName": "Storage Zone A",
"fullPath": "Main Distribution Center / Storage Zone A / Aisle A1",
"isOperational": true,
"physicalAddress": {
"street": "123 Industrial Parkway",
"city": "Springfield",
"state": "IL",
"postalCode": "62701",
"country": "USA"
},
"createdDate": "2025-01-24T10:00:00Z",
"modifiedDate": "2025-01-24T10:00:00Z"
}

Status Codes:

  • 201 Created - Location created successfully
  • 400 Bad Request - Validation errors
  • 409 Conflict - Location code already exists
  • 404 Not Found - Parent location not found

8. Update Location Basic Info

Updates location name and description.

PATCH /api/locations/{id}/basic-info
Content-Type: application/json

Path Parameters:

  • id: Location ID (Guid)

Request Body:

{
"name": "Storage Zone A - Expanded",
"description": "Primary storage area for general goods - recently expanded"
}

Response:

{
"id": "zone-a-id",
"code": "ZONE-A",
"name": "Storage Zone A - Expanded",
"description": "Primary storage area for general goods - recently expanded",
"locationTypeId": 2,
"locationTypeName": "Zone",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": "warehouse-001-id",
"parentLocationCode": "WH-MAIN",
"parentLocationName": "Main Distribution Center",
"fullPath": "Main Distribution Center / Storage Zone A - Expanded",
"isOperational": true,
"physicalAddress": null,
"createdDate": "2025-01-02T08:00:00Z",
"modifiedDate": "2025-01-24T15:30:00Z"
}

Status Codes:

  • 200 OK - Location updated successfully
  • 400 Bad Request - Validation errors
  • 404 Not Found - Location not found

9. Update Location Purpose

Changes the location's functional purpose.

PATCH /api/locations/{id}/purpose
Content-Type: application/json

Path Parameters:

  • id: Location ID (Guid)

Request Body:

{
"locationPurposeId": 2
}

Response:

{
"locationPurposeId": 2,
"locationPurposeName": "Receiving"
}

Status Codes:

  • 200 OK - Purpose updated successfully
  • 400 Bad Request - Invalid purpose ID
  • 404 Not Found - Location not found

10. Update Location Address

Updates or removes physical address.

PATCH /api/locations/{id}/address
Content-Type: application/json

Path Parameters:

  • id: Location ID (Guid)

Request Body (Add/Update):

{
"street": "456 New Street",
"city": "Springfield",
"state": "IL",
"postalCode": "62702",
"country": "USA"
}

Request Body (Remove):

{
"street": null,
"city": null,
"state": null,
"postalCode": null,
"country": null
}

Response (Address Set):

{
"street": "456 New Street",
"city": "Springfield",
"state": "IL",
"postalCode": "62702",
"country": "USA"
}

Response (Address Cleared):

null

Status Codes:

  • 200 OK - Address updated successfully
  • 404 Not Found - Location not found

11. Update Operational Flags

Changes location operational status.

PATCH /api/locations/{id}/operational-flags
Content-Type: application/json

Path Parameters:

  • id: Location ID (Guid)

Request Body:

{
"isOperational": false
}

Response:

{
"isOperational": false
}

Status Codes:

  • 200 OK - Status updated successfully
  • 404 Not Found - Location not found

Business Impact:

  • Setting isOperational: false prevents location from being used in new transactions
  • Existing inventory at location remains (read-only)
  • Location can be reactivated by setting isOperational: true

12. Move Location

Moves a location to a new parent or to root level.

POST /api/locations/{id}/move
Content-Type: application/json

Path Parameters:

  • id: Location ID (Guid)

Request Body (Move to new parent):

{
"newParentLocationId": "new-parent-id"
}

Request Body (Move to root level):

{
"newParentLocationId": null
}

Response:

204 No Content

Status Codes:

  • 204 No Content - Location moved successfully
  • 400 Bad Request - Would create circular reference
  • 404 Not Found - Location or new parent not found

13. Archive Location

Archives a location (soft delete).

DELETE /api/locations/{id}

Path Parameters:

  • id: Location ID (Guid)

Response:

204 No Content

Status Codes:

  • 204 No Content - Location archived successfully
  • 404 Not Found - Location not found
  • 409 Conflict - Location has active inventory or open transactions

14. Unarchive Location

Restores an archived location.

POST /api/locations/{id}/unarchive

Path Parameters:

  • id: Location ID (Guid)

Response:

204 No Content

Status Codes:

  • 204 No Content - Location restored successfully
  • 404 Not Found - Location not found
  • 400 Bad Request - Location is not archived

15. Get Archived Locations

Retrieves all archived locations.

GET /api/locations/archived
Accept: application/json

Response:

[
{
"id": "archived-location-id",
"code": "OLD-ZONE",
"name": "Old Storage Zone",
"description": "Decommissioned storage area",
"locationTypeId": 2,
"locationTypeName": "Zone",
"locationPurposeId": 1,
"locationPurposeName": "General Storage",
"parentLocationId": "warehouse-001-id",
"parentLocationCode": "WH-MAIN",
"parentLocationName": "Main Distribution Center",
"fullPath": "Main Distribution Center / Old Storage Zone",
"isOperational": false,
"physicalAddress": null,
"createdDate": "2024-01-01T00:00:00Z",
"modifiedDate": "2025-01-20T00:00:00Z"
}
]

Status Codes:

  • 200 OK - Archived locations retrieved successfully

Response Schemas

LocationDto

interface LocationDto {
id: string; // Guid
code: string; // Unique code (uppercase)
name: string; // Display name
description: string | null; // Optional details

// Type and Purpose
locationTypeId: number; // Location type ID
locationTypeName: string; // Type display name
locationPurposeId: number; // Purpose ID
locationPurposeName: string; // Purpose display name

// Hierarchy
parentLocationId: string | null; // Guid or null for root
parentLocationCode: string | null; // Parent code
parentLocationName: string | null; // Parent name
fullPath: string; // Full hierarchical path

// Status
isOperational: boolean; // Operational status

// Address
physicalAddress: AddressDto | null; // Optional address

// Audit
createdDate: string; // ISO 8601 datetime
modifiedDate: string; // ISO 8601 datetime
}

interface AddressDto {
street: string;
city: string;
state: string;
postalCode: string;
country: string;
}

interface LocationTreeDto {
id: string;
code: string;
name: string;
locationTypeId: number;
locationTypeName: string;
locationPurposeId: number;
locationPurposeName: string;
parentLocationId: string | null;
isOperational: boolean;
hasChildren: boolean;
children: LocationTreeDto[]; // Recursive structure
}

Use Cases and Examples

Use Case 1: Create Multi-Level Warehouse Structure

# Step 1: Create warehouse (root)
POST /api/locations
{
"code": "WH-MAIN",
"name": "Main Distribution Center",
"locationTypeId": 1,
"locationPurposeId": 1,
"physicalAddress": { /* full address */ }
}
# Response: { "id": "warehouse-id", ... }

# Step 2: Create zone
POST /api/locations
{
"code": "ZONE-A",
"name": "Storage Zone A",
"locationTypeId": 2,
"locationPurposeId": 1,
"parentLocationId": "warehouse-id"
}
# Response: { "id": "zone-id", ... }

# Step 3: Create aisle
POST /api/locations
{
"code": "AISLE-A1",
"name": "Aisle A1",
"locationTypeId": 3,
"locationPurposeId": 1,
"parentLocationId": "zone-id"
}
# Result: Warehouse > Zone > Aisle hierarchy created

Use Case 2: Mark Location for Maintenance

# Set location non-operational
PATCH /api/locations/{id}/operational-flags
{
"isOperational": false
}

# Location now unavailable for new transactions
# Existing inventory remains (read-only)

# After maintenance, reactivate
PATCH /api/locations/{id}/operational-flags
{
"isOperational": true
}

Use Case 3: Reorganize Warehouse Structure

# Move aisle from Zone A to Zone B
POST /api/locations/{aisle-id}/move
{
"newParentLocationId": "zone-b-id"
}

# Aisle hierarchy path automatically updated
# Inventory locations remain consistent

Use Case 4: Load Location Picker for Transaction

# Get tree structure for UI picker
GET /api/locations/tree?operationalOnly=true&maxDepth=4

# Response: Complete tree structure
# UI renders hierarchical picker
# User selects leaf location for transaction

Error Handling

Common Error Responses

Location Code Already Exists (409 Conflict):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.8",
"title": "Conflict",
"status": 409,
"detail": "A location with code 'WH-MAIN' already exists."
}

Circular Reference Detected (400 Bad Request):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Bad Request",
"status": 400,
"detail": "Moving location 'ZONE-A' to 'AISLE-A1' would create a circular reference."
}

Location Not Found (404 Not Found):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404,
"detail": "Location with ID 'a1b2c3d4-...' was not found."
}

Cannot Archive Location with Inventory (409 Conflict):

{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.8",
"title": "Conflict",
"status": 409,
"detail": "Cannot archive location 'ZONE-A' because it contains active inventory."
}

Best Practices

1. Location Hierarchy Design

  • Warehouse (root) → ZoneAisleShelfBin
  • Keep hierarchy depth reasonable (4-6 levels max)
  • Use meaningful codes (WH-MAIN, ZONE-A, AISLE-A1)
  • Set operational status at appropriate level

2. Operational Status Management

  • Mark locations non-operational for maintenance
  • Non-operational locations retain existing inventory
  • Prevent new transactions to non-operational locations
  • Use for temporary closures, renovations, or decommissioning

3. Tree Loading Optimization

  • Use maxDepth parameter for large hierarchies
  • Use operationalOnly: true for transaction pickers
  • Cache tree structure on client side
  • Reload only when structure changes

4. Location Purpose Strategy

  • General Storage: Default multi-purpose storage
  • Receiving: Dock doors and receiving areas
  • Shipping: Staging and shipping areas
  • Quarantine: Quality hold areas
  • Returns: RMA and returns processing
  • Production: Manufacturing floor locations


Last Updated: 2025-10-24 | API Version: 1.0 | Status: Active