# Company profiles

Create and update bounded customer and supplier profiles.

Canonical HTML: https://developer.shelfcycle.com/guides/company-profiles

Create and update bounded customer and supplier profiles without exposing private finance, tax, ledger, or workflow fields.

## Supported writes

| Endpoint | Scope | Required header |
| --- | --- | --- |
| `POST /customers` | `customers:write` | `Idempotency-Key` |
| `PATCH /customers/{id}` | `customers:write` | `If-Match` |
| `POST /suppliers` | `suppliers:write` | `Idempotency-Key` |
| `PATCH /suppliers/{id}` | `suppliers:write` | `If-Match` |

POST requests require a stable idempotency key. PATCH requests require the latest `updatedAt` value as `If-Match` and preserve omitted fields. Add `dryRun=true` to the same endpoint when your workflow needs a non-mutating readiness check before execution.

## Customer profiles

Customer profile writes are limited to public identity and the initial API-managed primary location/address bundle. Use the locations and addresses endpoints for additional customer locations or addresses after the customer exists.

```bash
curl "$SHELFCYCLE_API_BASE_URL/customers" \
  -X POST \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: crm:lead-1842:create-customer" \
  -d '{
    "name": "Northstar Chemical",
    "externalId": "NS-1842",
    "pipelineStatus": "PROSPECT",
    "primaryLocation": {
      "name": "Northstar Chemical HQ",
      "email": "ops@northstar.example",
      "phone": "555-0100",
      "address": {
        "name": "Northstar Chemical HQ",
        "street1": "100 Market Street",
        "city": "Chicago",
        "state": "IL",
        "zip": "60601",
        "country": "US"
      }
    }
  }'
```

The public API does not manage customer credit, payment terms, sales reps, tax data, ledger settings, or private workflow defaults.

## Supplier profiles

Supplier profile writes are limited to public identity fields and an optional API-managed ship-from address. Use the supplier ship-from endpoints for additional ship-from locations after the supplier exists.

```bash
curl "$SHELFCYCLE_API_BASE_URL/suppliers/supplier-id" \
  -X PATCH \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "If-Match: 2026-06-04T13:20:21.656Z" \
  -d '{
    "name": "Acme Supply",
    "email": "orders@acme.example",
    "primaryShipFromAddress": {
      "name": "Acme Supply Warehouse",
      "street1": "20 Industrial Way",
      "city": "Houston",
      "state": "TX",
      "zip": "77002",
      "country": "US",
      "defaultSupplierShippingInstructions": "Call before pickup."
    }
  }'
```

The public API does not manage supplier tax ids, ACH, banking, payment terms, credit, ledger data, representative defaults, root supplier address mutation, or general location lifecycle outside the ship-from endpoints.

## Read before update

Use `GET /customers/{id}` or `GET /suppliers/{id}` before a PATCH. The response includes `updatedAt`; send that exact value as `If-Match` so ShelfCycle can reject stale overwrites with `409 stale_record`.

> **Guardrail**: Do not use company profile writes as import sync. Create or update one profile at a time, and stop on duplicate, archived, stale, or permission errors.
