# Locations and addresses

Manage customer locations, customer addresses, and supplier ship-from locations.

Canonical HTML: https://developer.shelfcycle.com/guides/location-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.

```bash
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
    }
  }'
```

```json
{
  "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.

```bash
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`.

```bash
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.

```bash
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](/guides/archive-restore) for the complete action flow.

> **Guardrail**: Use child endpoints for the selected customer or supplier. Resolve commercial references first, preserve source IDs, and verify the saved child record before continuing.
