Create Production Logs
Required scope: production_logs.create.
Create one or many Production Logs. The body is a JSON array, even for a single record.
This is the endpoint an MES, ERP or shop-floor terminal uses to push production into
Pulsar. machine and sku are references that accept either an id or a name, so a
system that only knows line names and product codes does not have to resolve Pulsar ids
first.
A Production Log describes a closed interval: start and end are both required, end
is at or after start, and both fall inside a single shift of the machine. Past shifts are
accepted, so logs can be sent days after production. To record what is happening in the
shift a machine is running right now, use the realtime endpoints instead.
Defects (type: "defects") are additive. Several defects logs may cover the same range,
in one request or across requests, and each one is recorded, so sending the same batch twice
records it twice. Send each batch once, and retry it only as described under Retries and
Idempotency-Key below. start and end may be the same instant for defects found at one
point in time:
[
{"type": "defects", "count": 3, "nominalSpeed": 60, "machine": {"name": "Press 4"},
"sku": {"name": "GAL-1042"}, "start": "2026-10-12T14:00:00Z", "end": "2026-10-12T22:00:00Z"},
{"type": "defects", "count": 1, "nominalSpeed": 60, "machine": {"name": "Press 4"},
"sku": {"name": "GAL-1042"}, "start": "2026-10-12T17:42:10Z", "end": "2026-10-12T17:42:10Z"}
]
total and correct logs may not overlap another log of the same type, machine and SKU.
The response lists the logs of this request. Quality and OEE for the affected shifts are
recalculated in the background, usually within minutes.
Retries and Idempotency-Key. Whether a failed call recorded anything depends on how it failed:
- A
4xxresponse means the request was rejected and nothing was recorded. Fix it and send it again. - A timeout, a dropped connection or a
5xxresponse leaves the outcome unknown: the request may have been recorded even though you never got the response. Sent again without anIdempotency-Key, it can be recorded twice, so first check whether it was recorded, for example withPOST /v1/production-logs/filters.
To retry safely instead, send an Idempotency-Key header with a unique value you generate for each request, such
as a UUID, and send the same key and the same body on every retry of that request. The key is stored together
with what the request recorded, so a retry never records it twice:
- If the original request was recorded, the retry records nothing and returns the original response, with the
header
Idempotent-Replayed: true. - If the original was not recorded, whether it was rejected or failed, the retry is processed as a new request.
- Reusing a key with a different request, another body or URL, returns
409. - In the rare case that the original is still being processed, the retry returns
409. Retry again shortly.
Keys are scoped to your company, so all of its API keys share them, and each key is kept for 24 hours after the request that recorded it. After that, a request with the same key is processed as a new one, so retry within that window.
Header Parameters
Optional. A unique value you generate for this request, such as a UUID, of up to 255 printable ASCII characters without spaces. Send the same key when you retry the request: if the original was recorded, its response is returned again instead of recording it twice. See Retries and Idempotency-Key above.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
A JSON array. Each item has these fields:
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/production-logs" \ -H "Content-Type: application/json" \ -d '[ { "count": 1000, "nominalSpeed": 60, "start": "2024-01-01T08:00:00", "end": "2024-01-01T16:00:00", "machine": {}, "sku": {} } ]'[ { "id": "36f7b519-d93e-4ec8-8245-7f4b8c123456", "type": "correct", "sensorCount": 500, "count": 1000, "nominalSpeed": 60, "countingFactor": 1, "start": "2024-01-01T00:00:00", "end": "2024-01-01T08:00:00", "isReviewed": true, "isAutomated": true, "machineId": 12, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "deletedAt": "2019-08-24T14:15:22Z", "live": true, "machine": { "id": 0, "name": "string", "isCountEnabled": true, "externalName": "string" }, "company": { "id": 0, "name": "string", "timezone": "string" }, "shift": { "id": 0, "name": "string", "start": "2019-08-24T14:15:22Z", "end": "2019-08-24T14:15:22Z", "isConsidered": true }, "operator": { "id": 0, "firstName": "string", "lastName": "string", "email": "string" }, "sku": { "id": "string", "name": "string", "description": "string", "unit": "string" }, "workOrder": { "id": "string", "name": "string", "description": "string", "status": "InProgress" }, "simpleWorkOrder": { "id": "string", "name": "string" } }]Delete an operator DELETE
Delete an operator from the roster. Production logs and shifts that reference the operator are left pointing at a record that no longer resolves, so for someone who has simply left, leaving the record in place preserves the history their shifts are attached to.
Search Production Logs POST
Search Production Logs by machine, shift, SKU, date, quantity or review state. A POST because the filter body nests, but it only reads: the production_logs.read scope is sufficient. Send {} to get the first page with the defaults (page 1, limit 10). Filters are optional and combine with AND. Pages. Logs are ordered by start, then by id. The response gives totalCount and totalPages; request page 1, 2, … up to totalPages with the same filters and limit to read them all. A log written while you page can shift later pages by one. Dates. startDate filters on when a log starts and endDate on when it ends. after and before exclude the time itself, between includes both ends, and equal matches the exact time. Give times with a UTC offset. A shift's logs. To read back what a shift holds, for example after adding defects to it, filter by its id from GET /v1/shifts: `json {"shifts": {"include": [48213]}, "type": {"include": ["defects"]}, "limit": 100, "page": 1} ` A log is in a shift when it is on the shift's machine and lies within the shift. For only the defects, GET /v1/shifts/{shift_id}/defects returns the same logs in one unpaginated list.