Locations and addresses
Manage customer locations, customer addresses, and supplier ship-from locations only after selecting the exact visible parent.
Location and address endpoints are parent scoped. They are for confirmed customer and supplier workflows, not broad address export, location sync, or private profile enrichment.
Endpoint map
| Endpoint | Scope | Use it for |
|---|---|---|
GET /customers/{id}/locations | customers:read or search:read | List active customer locations under one customer. |
POST /customers/{id}/locations | customers:write | Create a customer location with its initial billing or shipping address. |
GET /customers/{id}/locations/{locationId} | customers:read or search:read | Read one customer location under its parent customer. |
PATCH /customers/{id}/locations/{locationId} | customers:write | Update safe location fields with optimistic concurrency. |
GET /customers/{id}/locations/{locationId}/addresses | customers:read or search:read | List active addresses under one customer location. |
POST /customers/{id}/locations/{locationId}/addresses | customers:write | Create a billing or shipping address under one location. |
PATCH /customers/{id}/locations/{locationId}/addresses/{addressId} | customers:write | Update safe address fields. The address must remain billing or shipping eligible. |
GET /suppliers/{id}/ship-from-locations | suppliers:read or search:read | List active ship-from locations under one supplier. |
POST /suppliers/{id}/ship-from-locations | suppliers:write | Create a supplier ship-from location. |
PATCH /suppliers/{id}/ship-from-locations/{locationId} | suppliers:write | Update safe ship-from fields with optimistic concurrency. |
POST requests require Idempotency-Key. PATCH requests require If-Match with the latest updatedAt from the detail response. Add dryRun=true to the same POST or PATCH endpoint when your workflow needs a readiness check before execution.
Create a customer location
Customer location create includes the initial address. That address must be billing, shipping, or both.
curl "$SHELFCYCLE_API_BASE_URL/customers/customer-id/locations?dryRun=true" \
-X POST \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: crm:site-742:customer-id:create-location" \
-d '{
"name": "Northstar Rail Dock",
"email": "rail@northstar.example",
"phone": "555-4000",
"address": {
"name": "Northstar Rail Dock",
"street1": "700 Rail Spur",
"city": "Tampa",
"state": "FL",
"zip": "33603",
"country": "US",
"isShipping": true
}
}'
{
"data": {
"type": "write_readiness",
"operation": "customer_locations.create",
"status": "ready",
"wouldWrite": false,
"checks": [
{ "code": "scope_authorized", "status": "passed" },
{ "code": "target_available", "status": "passed" },
{ "code": "idempotency_available", "status": "passed" },
{ "code": "duplicate_check_clear", "status": "passed" }
],
"duplicateCandidates": [],
"verification": {
"available": true,
"path": null,
"pathTemplate": "/api/v1/customers/{customerId}/locations/{locationId}",
"fallback": "detail_get"
},
"requestId": "request-id"
}
}
Execute the same request without dryRun=true when your policy allows it. If the customer has no active primary location, ShelfCycle may make the first created location primary. Clients cannot request primary switching.
Add a customer address
Create additional billing or shipping addresses under the selected location.
curl "$SHELFCYCLE_API_BASE_URL/customers/customer-id/locations/location-id/addresses" \
-X POST \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: crm:site-742:customer-id:location-id:create-bill-to" \
-d '{
"name": "Northstar Billing",
"externalId": "NS-BILL-01",
"street1": "100 Market Street",
"city": "Chicago",
"state": "IL",
"zip": "60601",
"country": "US",
"isBilling": true,
"defaultOrderShippingRemarks": "Use customer PO number on paperwork."
}'
If both isBilling and isShipping are false, the API blocks the write with address_role_required. Duplicate candidates are advisory and bounded; when the key cannot read the duplicate detail, candidate fields can be redacted.
Update child records
Use the current updatedAt value as If-Match.
curl "$SHELFCYCLE_API_BASE_URL/customers/customer-id/locations/location-id/addresses/address-id" \
-X PATCH \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "Content-Type: application/json" \
-H "If-Match: 2026-06-29T16:00:00.000Z" \
-d '{
"phone": "555-4100",
"defaultOrderShippingRemarks": "Use east dock for pickups."
}'
Customer location updates support name, email, website, and phone. Sending primary or makePrimary to change primary state is blocked. Customer address updates support safe address, contact, billing/shipping role, and shipping-remark fields, but the address must remain billing or shipping eligible.
Supplier ship-from locations
Supplier child writes are ship-from only. They do not mutate the supplier root address or private supplier settings.
curl "$SHELFCYCLE_API_BASE_URL/suppliers/supplier-id/ship-from-locations?dryRun=true" \
-X POST \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: supplier-portal:warehouse-22:supplier-id:create-ship-from" \
-d '{
"name": "Acme Houston Warehouse",
"externalId": "ACME-HOU",
"street1": "20 Industrial Way",
"city": "Houston",
"state": "TX",
"zip": "77002",
"country": "US",
"phone": "555-2999",
"defaultSupplierShippingInstructions": "Call before pickup."
}'
Lists and cursors
Child lists accept limit and cursor. Cursors are bound to the resource and parent chain, so a cursor from one customer or address list cannot be replayed against another parent.
Customer location list rows include an address preview. If addressesTruncated is true, call GET /customers/{id}/locations/{locationId}/addresses for the complete active address list under that location.
Do not use child endpoints for broad sync, primary switching, archive/unarchive, supplier root address mutation, tax, credit, payment terms, ledger, workflow defaults, or hidden internal fields.