# Archive and restore

Retire and restore selected customer and supplier records safely.

Canonical HTML: https://developer.shelfcycle.com/guides/archive-restore

Keep customer and supplier records current with reversible, record-specific archive and restore actions.

Public API v1.35.2 can archive or restore customers, suppliers, customer and supplier contacts, customer addresses, and supplier ship-from locations. Each action applies to one selected record and returns its resulting archive state.

## Endpoint map

| Record | Archive or restore | Scope |
| --- | --- | --- |
| Customer | `POST /customers/{id}/{archive|unarchive}` | `customers:write` |
| Supplier | `POST /suppliers/{id}/{archive|unarchive}` | `suppliers:write` |
| Customer or supplier contact | `POST /contacts/{id}/{archive|unarchive}` | `contacts:update` |
| Customer address | `POST /customers/{id}/locations/{locationId}/addresses/{addressId}/{archive|unarchive}` | `customers:write` |
| Supplier ship-from location | `POST /suppliers/{id}/ship-from-locations/{locationId}/{archive|unarchive}` | `suppliers:write` |

The key needs the listed scope, and its acting person must have current permission to archive that kind of customer or supplier record. `GET /me` reports `archive` and `unarchive` flags under the matching contact, customer, customer-address, supplier, and ship-from capabilities.

## Preview the action

Add `dryRun=true` to review the selected record and the action without changing it. You may omit `If-Match` from this first preview. The response then includes the current `updatedAt` value needed for execution.

```bash
curl "$SHELFCYCLE_API_BASE_URL/customers/customer-id/archive?dryRun=true" \
  -X POST \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY"
```

```json
{
  "data": {
    "type": "write_readiness",
    "operation": "customers.archive",
    "status": "blocked",
    "wouldWrite": false,
    "checks": [
      { "code": "scope_authorized", "status": "passed" },
      { "code": "target_available", "status": "passed" },
      { "code": "stale_record", "status": "blocked" }
    ],
    "wouldChange": {
      "fieldNames": ["archived"],
      "values": { "archived": true }
    },
    "impactAnalysis": {
      "currentArchived": false,
      "targetArchived": true,
      "currentUpdatedAt": "2026-09-02T14:30:00.000Z"
    },
    "requestId": "request-id"
  }
}
```

A blocked `stale_record` check in this first preview provides the current record version for the next review. When it is the only blocked check, send the returned timestamp to apply the action. You can also include a known current `If-Match` value in the preview and receive `status: "ready"` immediately when every check passes.

Customer and supplier archive previews also confirm whether active commercial records need attention first. Customer checks cover open orders and unpaid invoices; supplier checks cover confirmed purchase orders and unpaid bills. When they need attention, `archive_blocked` returns categories and counts so the workflow can resolve them before continuing.

## Apply the action

Send the same POST without `dryRun=true` and include the current `updatedAt` value as `If-Match`. The request does not need a body.

```bash
curl "$SHELFCYCLE_API_BASE_URL/customers/customer-id/archive" \
  -X POST \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
  -H "If-Match: 2026-09-02T14:30:00.000Z"
```

```json
{
  "data": {
    "type": "lifecycle_receipt",
    "resource": { "type": "customer", "id": "customer-id" },
    "action": "archive",
    "archived": true,
    "changed": true,
    "updatedAt": "2026-09-02T14:31:12.000Z",
    "requestId": "request-id",
    "verification": {
      "available": true,
      "method": "GET",
      "path": "/api/v1/customers/customer-id",
      "pathTemplate": "/api/v1/customers/{id}",
      "requiresScopes": ["customers:read", "search:read"],
      "fallback": "detail_get"
    }
  }
}
```

Use the returned `archived`, `changed`, and `updatedAt` values as the result of the action. Repeating the same desired state with the newly returned timestamp succeeds with `changed: false`; the record is already in that state.

## Restore a record

Restore uses the matching `/unarchive` route and the latest timestamp from the archive receipt, a readable detail, a parent-scoped list that includes archived contacts, or a fresh dry run.

```bash
curl "$SHELFCYCLE_API_BASE_URL/contacts/contact-id/unarchive" \
  -X POST \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
  -H "If-Match: 2026-09-02T14:31:12.000Z"
```

If a request returns `409 stale_record`, preview the same action without `If-Match`, take `impactAnalysis.currentUpdatedAt`, and apply the action again after reviewing the current state.

## Work with child records

Customer addresses and supplier ship-from locations use their complete parent path, so keep the selected customer, location, supplier, and child ids together. A mismatched path returns `404 not_found` without changing a record.

Contacts, customer addresses, and ship-from locations can be archived or restored independently while their parent is archived. In that case, the action receipt is the readback and reports `verification.fallback: "execute_response"`. To find an archived contact and its current timestamp, use the parent-scoped contact list with `includeArchived=true`.

> **Information**: Use one action per selected record, keep the latest returned timestamp, and treat the receipt as the authoritative result when a separate detail read is unavailable.
