APIBatch

Create or update a batch

POST
/public/v1/batches

Create or update a single batch. Omit id to create a new batch; pass the id of an existing batch to update it. Either way the whole operation is atomic — if any field is rejected, nothing is written and the batch is left unchanged.

A batch is Distru's lot for a batch-tracked product: it is the unit that inventory quantity, cost, test results, and (optionally) bins hang off of. You can only create a batch under a product whose inventory-tracking method is batch-tracked; pointing product_id at any other product is rejected. Products that track inventory as compliance packages are managed through their package endpoints, not here.

On create, the batch's inventory records are initialized so quantity and cost can begin accumulating against it (a brand-new batch starts with no on-hand quantity — receive a purchase, run an assembly, or adjust stock to add inventory). The write is recorded to the batch's activity history. This endpoint does not push to or pull from any state traceability system (Metrc / BioTrack); a 200 reflects the Distru batch record only.

Update is a targeted patch, not a full replace: only the fields you send are changed, and any field you omit keeps its current value. product_id is fixed after creation — a batch cannot be moved to a different product. See each field below for its create-time default and its null-vs-omit behavior (notably bin_ids).

Required permission: products_permissions_create to create, products_permissions_edit to update.

Authorization

Bearer
headerAuthorizationBearer <token>

API token generated in Distru (Settings → Distru API). Send it on every request as Authorization: Bearer YOUR_API_TOKEN.

Request Body

application/json
  1. body
id?string

The Distru batch ID to update. Omit to create a new batch. When present, it must reference a batch in your company or the request is rejected.

product_id?string

The Distru product ID this batch belongs to. Required on create, and the product must be a batch-tracked product in your company (pointing at a product tracked any other way is rejected). Immutable once the batch exists — on update, omit it or resend the batch's current product; sending a different product id is rejected rather than silently ignored, and a batch can never be moved to another product.

batch_number?string

The user-facing lot / batch number label (e.g. LOT-1241291). This is where your own batch identifier belongs. Free-form and not required to be unique. Nullable; leave omitted or null if the batch has no external lot number.

thc?string

A free-form THC label for the batch, as displayed in Distru (e.g. "18.5%"). This is a static value stored on the batch record; it does not set or derive from any lab result — the batch's primary test result tracks potency separately.

cbd?string

A free-form CBD label for the batch, as displayed in Distru (e.g. "0.3%"). This is a static value stored on the batch record; it does not set or derive from any lab result — the batch's primary test result tracks potency separately.

expiration_datetime?string

When the batch expires, as an ISO 8601 datetime (e.g. 2026-01-31T00:00:00Z). Nullable; omit or send null if the batch has no expiration.

harvest_datetime?string

When the batch's material was harvested, as an ISO 8601 datetime (e.g. 2025-09-15T00:00:00Z). Nullable and optional; surfaced in the response as harvest_datetime.

manufactured_datetime?string

When the batch was manufactured, as an ISO 8601 datetime (e.g. 2025-09-20T00:00:00Z). If omitted on create, defaults to the time the batch is created. Surfaced in the response as manufactured_datetime.

owner_id?string

The Distru user ID of the batch's designated owner. Must be an active user in your company that the authenticated user is allowed to assign to, otherwise the request is rejected. Nullable; omit or send null for no owner.

description?string

Free-form notes about the batch. Nullable and optional.

custom_data?

A map of custom field IDs to their values. Use GET /public/v1/custom-fields?parent_object=batch to retrieve available custom fields, their IDs, and their types. The value format depends on the field's type: a text field takes a string, a date field takes a full ISO8601 datetime, and a checkbox field takes an array of its selected options.

bin_ids?array<string>

The IDs of the bins this batch is stored in. Behaviour: omit bin_ids to leave the batch's bins unchanged; pass null or an empty array to clear all bins; pass a non-empty array to replace the batch's bins with exactly those. Ignored unless bin inventory tracking is enabled for your company.

Response Body

A single batch

*/*
  1. response

A single batch

data?

A lot of a product with all its details — a group of inventory sharing a harvest/production run, expiration date, potency, lab results, and cost. Used for batch-tracked products.

Example Request
curl -X POST 'https://app.distru.com/public/v1/batches' \  -H 'Content-Type: application/json' \  -d '{  "batch_number": "LOT-1241291",  "cbd": "0.3%",  "custom_data": {    "97": [      "A",      "B"    ]  },  "description": "Test batch",  "expiration_datetime": "2025-01-01T00:00:00.000000Z",  "harvest_datetime": "2024-06-15T00:00:00.000000Z",  "manufactured_datetime": "2025-01-02T03:04:05.000000Z",  "owner_id": "00000000-0000-0000-0000-000000000eb6",  "product_id": "a5e519ec-3008-4afc-bdbd-9c8687b47cdc",  "thc": "18.5%"}'
Example Response
{  "data": {    "batch_number": "LOT-1241291",    "cbd": "0.3%",    "creator": {      "banned": false,      "deleted_at": null,      "email": "[email protected]",      "full_name": "FirstName6426 LastName6427",      "id": "00000000-0000-0000-0000-000000000c70",      "inserted_datetime": "2026-10-13T15:03:33.036534Z",      "role": {        "id": "00000000-0000-0000-0000-000000000ce0",        "name": "Admin 3295"      },      "updated_datetime": "2026-10-13T15:03:33.036534Z"    },    "custom_data": [      {        "id": 81,        "name": "Custom Field 55",        "value": "A,B"      }    ],    "deleted_at": null,    "description": "Test batch",    "expiration_date": "2025-01-01T00:00:00.000000Z",    "expiration_datetime": "2025-01-01T00:00:00.000000Z",    "harvest_datetime": "2024-06-15T00:00:00.000000Z",    "id": "00000000-0000-0000-0000-0000000001b9",    "inserted_datetime": "2026-10-13T15:03:33.091421Z",    "manufactured_datetime": "2025-01-02T03:04:05.000000Z",    "name": "B1",    "owner_id": "00000000-0000-0000-0000-000000000c81",    "product": {      "id": "da07af0c-cde7-4cd4-85dc-d9a3d0e092fc",      "name": "Product 1361",      "sku": "sku 1362",      "updated_datetime": "2026-10-13T15:03:33.065481Z"    },    "product_id": "da07af0c-cde7-4cd4-85dc-d9a3d0e092fc",    "quantity_active": "0",    "quantity_active_by_location": [],    "tasks": [],    "thc": "18.5%",    "updated_datetime": "2026-10-13T15:03:33.091421Z"  }}