# Formula imports

Import reviewed formulas with ingredients, outputs, substitutes, process steps, and per-formula results.

Canonical HTML: https://developer.shelfcycle.com/guides/formulas

Import reviewed production formulas with ingredients, outputs, substitute products, and process steps, then keep a separate result for each formula.

## Access and preparation

Use `POST /formulas/batch` with `formulas:write` and the acting person's current Work Order update permission. The organization's Work Orders must be enabled for that person. `GET /me` reports scope and permission availability; the import request also checks Work Order availability.

Prepare the products in ShelfCycle first. Formula lines use exact product codes, matched case-insensitively within the organization. The first code on each line is the preferred product; later codes are substitutes in priority order.

## Preview an import

Send 1 to 50 items, each with a unique, stable `clientItemId` and a `payload`. Preview with `dryRun=true` to receive ordered `ready` or `failed` results without saving formulas. A preview does not require an `Idempotency-Key`.

Replace the example product codes with existing active products appropriate to your formula.

```bash
curl "$SHELFCYCLE_API_BASE_URL/formulas/batch?dryRun=true" \
  -X POST \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "clientItemId": "formula-001",
        "payload": {
          "name": "Northstar cleaning blend",
          "description": "Reviewed standard blend",
          "ingredients": [
            { "label": "Base", "quantity": "80", "unit": "kg", "productCodes": ["BASE-A", "BASE-B"] },
            { "label": "Additive", "quantity": "20", "unit": "kg", "productCodes": ["ADDITIVE-A"] }
          ],
          "outputs": [
            { "label": "Finished blend", "quantity": "100", "unit": "kg", "productCodes": ["BLEND-A"], "kind": "PRODUCT" }
          ],
          "processSteps": [
            { "name": "Blend", "attrs": [{ "key": "Instruction", "value": "Mix until uniform." }] }
          ]
        }
      }
    ]
  }'
```

## Describe the formula

Each payload requires `name`, `ingredients`, and `outputs`. Optional fields are `description`, `autotag`, and `processSteps`.

- Every ingredient or output has `label`, `quantity`, `unit`, and at least one `productCodes` value.
- Units are `g`, `kg`, `lb`, `ml`, `L`, `gal`, or `each`. Quantities must satisfy the formula's normal save rules.
- Ingredients can set `isPackage`; outputs can set `kind` to `PRODUCT` or `WASTE`.
- Process steps have a `name` and `attrs`, with each attribute expressed as `key` and `value`.

Each formula can contain up to 100 product-code entries across ingredients and outputs, counting repeats. The name after trimming and the optional description each support up to 2400 UTF-8 bytes; count bytes rather than characters for non-ASCII text. Keep the complete request at or below 2 MB.

## Save and retain results

After reviewing the preview, submit the same body without `dryRun=true` and add a stable `Idempotency-Key`, such as `formula-library:approved-import-001`. Execution returns `data.results` in input order with `clientItemId`, `mode: "createFormula"`, and `status: "succeeded"` or `"failed"`. A saved item includes `data.id`, `name`, `number`, and `resultAction: "created"`; `data.counts` summarizes the results.

A failed formula does not undo successful formulas. Its `failures` and `error` explain what to correct, including unknown or archived products, unsuitable quantities or units, an existing formula name, or oversized content. Missing or repeated item IDs, missing names, or duplicate trimmed names within a request are request-level errors, so correct those before submission.

This endpoint saves reusable formulas. It does not start a work order or receive, consume, or produce inventory.

## Resume safely

If a request is interrupted, repeat the identical body, item order, `clientItemId` values, and `Idempotency-Key`. Recorded outcomes are returned and only pending items continue. A completed retry reports `idempotencyStatus: "replayed"`. Correcting a failed formula is a new intended request and uses a new stable key; omit already successful formulas from that corrected request.

`X-RateLimit-Cost` reports the submitted item count. Divide larger approved libraries into requests of at most 50 formulas and keep each request's identity and results together.
