Locations and addresses
Manage customer locations, commercial setup details, source-identified customer addresses, and supplier ship-from locations after selecting the exact 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. |
POST /customers/{id}/locations/{locationId}/addresses/{addressId}/archive or /unarchive | customers:write | Archive or restore one selected customer address. |
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 /suppliers/{id}/ship-from-locations/{locationId}/archive or /unarchive | suppliers:write | Archive or restore one selected supplier ship-from location. |
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",
"accountOwnerId": "salesperson-id",
"paymentTermsId": "payment-term-id",
"customerServiceRepresentativeId": "customer-service-id",
"creditLimit": { "amountCents": 1000000, "currencyCode": "USD" },
"address": {
"name": "Northstar Rail Dock",
"externalId": "CRM-ADDRESS-742",
"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, phone, accountOwnerId, paymentTermsId, customerServiceRepresentativeId, and creditLimit. Resolve representatives and payment terms before assignment. Sending primary or makePrimary to change primary state is blocked. Customer address updates support source externalId, address, contact, billing/shipping role, and shipping-remark fields, and 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.
Preserve separate source addresses
Customer addresses and supplier ship-from locations accept externalId on create and update. Store that source ID with the returned ShelfCycle ID and updatedAt value.
If a new customer address, combined customer location and address, or supplier ship-from location resembles an existing record but is a separate legitimate source record, add top-level duplicateResolution: "create_distinct" to the create request. This permits a separate record for reviewable similarity matches. Exact source-ID and customer-location-name conflicts still require correction.
Archive and restore child records
Customer addresses and supplier ship-from locations can be archived or restored with their complete parent path and the latest updatedAt value in If-Match. Add dryRun=true to preview the action or retrieve the current timestamp first. These child records can be managed independently while their customer or supplier is archived. See Archive and restore for the complete action flow.
Use child endpoints for the selected customer or supplier. Resolve commercial references first, preserve source IDs, and verify the saved child record before continuing.