Endpoints
GET /api/v1/accountPlan policy, credential identity, and monthly usage.
GET /api/v1/machinesAuthorized machine, group, and sensor configuration.
GET /api/v1/status-snapshotCompany-wide status evaluated at the delayed cutoff.
GET /api/v1/uptimeUptime, downtime, and offline minutes for one machine.
GET /api/v1/telemetryAggregated energy, sensor, or counter data.
GET /api/v1/egauge/registersEntitled eGauge register catalog.
GET /api/v1/egauge/energyComplete hourly eGauge energy.
GET /api/v1/egauge/comparisonsSaved signed formulas and calculated comparisons.
GET /api/v1/solar/assetsEntitled Solar plant and inverter catalog.
GET /api/v1/solar/status-snapshotDelayed inverter production status.
GET /api/v1/solar/productionComplete daily Solar production.
GET /api/v1/stop-eventsRecorded downtime events with page pagination.
GET /api/v1/stop-events/summaryRecorded event count and duration by machine.
GET
/api/v1/account
usage.read
Returns the authenticated company, credential identity, enforced plan policy, and current monthly usage. It accepts no query parameters.
Request
curl https://www.dynoraptors.ai/api/v1/account \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"company": {"name": "Example Manufacturing", "timezone": "America/Mexico_City"},
"credential": {
"id": "e28e70f4-98c6-4ab4-8f50-5648b38e7906",
"name": "Monthly reporting script",
"prefix": "a1b2c3d4e5f6",
"scopes": ["machines.read", "status.read", "telemetry.read", "solar.read", "egauge.read", "stop_events.read", "usage.read"]
},
"policy": {
"tier": "core", "enabled": true, "available": true,
"freshness_delay_minutes": 15, "minimum_resolution_minutes": 30,
"retention_days": 30, "maximum_range_days": 7,
"maximum_rows": 1000, "maximum_machines_per_query": 15,
"rate_limit_per_minute": 6, "monthly_request_limit": 5000,
"webhooks_enabled": false
},
"usage": {"month_requests": 128, "month_limit": 5000}
}
GET
/api/v1/machines
machines.read
Lists the machines this credential may access. Use each public id in other API requests; internal database identifiers are never returned.
Request
curl https://www.dynoraptors.ai/api/v1/machines \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"data": [{
"id": "7404ab3c-5614-4a23-97bb-725d08d6a436",
"name": "Injection Press 04", "model": "PX-220",
"serial_number": "PX220-004", "year": 2024,
"machine_type": "injection_molding", "description": "North production line",
"groups": ["Injection", "North line"],
"sensors": [{
"key": "slot_1", "name": "Oil temperature", "kind": "temperature",
"unit": "°C", "mode": "periodic", "enabled": true
}]
}]
}
GET
/api/v1/status-snapshot
status.read
Returns one delayed status row for every authorized machine. Status is working, stopped, offline, or unknown.
Request
curl https://www.dynoraptors.ai/api/v1/status-snapshot \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"as_of": "2026-08-06T18:45:00Z",
"freshness_delay_minutes": 15,
"data": [{
"machine_id": "7404ab3c-5614-4a23-97bb-725d08d6a436",
"machine_name": "Injection Press 04", "status": "working",
"status_code": 2, "effective_at": "2026-08-06T18:45:00Z",
"status_started_at": "2026-08-06T16:12:31Z"
}]
}
GET
/api/v1/uptime
status.read
Returns non-overlapping uptime, downtime, and offline totals for one machine. Pass the public machine id returned by /api/v1/machines. Uptime means the machine reported working, downtime means it reported stopped, and offline means no status session covered that part of the requested period.
- machine_id
- Required public machine UUID.
- start / end
- Optional ISO 8601 timestamps with timezone. Defaults to the latest permitted 24 hours. Maximum 7 days per query; data is retained for 30 days.
Request
curl "https://www.dynoraptors.ai/api/v1/uptime?machine_id=7404ab3c-5614-4a23-97bb-725d08d6a436&start=2026-08-05T00:00:00Z&end=2026-08-06T00:00:00Z" \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"data": {
"machine_id": "7404ab3c-5614-4a23-97bb-725d08d6a436",
"machine_name": "Injection Press 04",
"uptime_minutes": 980.0, "downtime_minutes": 275.0,
"offline_minutes": 185.0, "total_minutes": 1440.0,
"uptime_percent": 68.06, "downtime_percent": 19.1,
"offline_percent": 12.85
},
"meta": {
"start": "2026-08-05T00:00:00Z", "end": "2026-08-06T00:00:00Z",
"latest_allowed": "2026-08-06T18:45:00Z",
"freshness_delay_minutes": 15, "retention_days": 30,
"maximum_range_days": 7
}
}
GET
/api/v1/telemetry
telemetry.read
Returns aggregated energy, sensor, or counter rows. section is required and must be energy, sensors, or counters.
- section
- Required telemetry family.
- start / end
- Optional ISO 8601 timestamps with timezone. Defaults to the latest permitted 24 hours.
- machine_ids
- Optional comma-separated public machine UUIDs. Maximum 15 machines.
- resolution_minutes
- Optional bucket size. API Core enforces a minimum of 30.
Request
curl "https://www.dynoraptors.ai/api/v1/telemetry?section=sensors&machine_ids=7404ab3c-5614-4a23-97bb-725d08d6a436&start=2026-08-05T00:00:00Z&end=2026-08-06T00:00:00Z&resolution_minutes=30" \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"data": [{
"timestamp": "2026-08-05T00:00:00Z",
"machine_id": "7404ab3c-5614-4a23-97bb-725d08d6a436",
"metric": "temperature", "samples": 180,
"average": 42.7, "minimum": 39.8, "maximum": 45.2, "sum": 7686.0,
"sensor_key": "slot_1", "telemetry_type": "a_temperature"
}],
"meta": {
"section": "sensors", "start": "2026-08-05T00:00:00Z", "end": "2026-08-06T00:00:00Z",
"latest_allowed": "2026-08-06T18:45:00Z", "freshness_delay_minutes": 15,
"requested_resolution_minutes": 30, "effective_resolution_minutes": 30,
"limited": false, "maximum_rows": 1000, "cache": "miss"
}
}
Energy rows may include source_id; sensor and counter rows may include sensor_key. When meta.limited is true, narrow the time range or machine selection.
GET
/api/v1/egauge/registers
egauge.read
Lists included eGauge registers using stable public UUIDs, along with semantic kind, polarity, connection status, and latest available data time.
Response 200
{"data":[{"id":"b32b99cc-21a7-4cd9-95d7-f01a80445480","name":"Consumo","semantic_kind":"grid_import","polarity":1}]}
GET
/api/v1/egauge/energy
egauge.read
Returns complete hourly buckets. Filter with register_id or comma-separated register_ids, plus optional ISO 8601 start and end.
Response 200
{"data":[{"timestamp":"2026-08-15T10:00:00Z","register_id":"b32b99cc-21a7-4cd9-95d7-f01a80445480","energy_kwh":184.2}],"meta":{"resolution":"hour"}}
GET
/api/v1/egauge/comparisons
egauge.read
Calculates saved signed register formulas and returns the eGauge total, reference total, difference, and coverage for complete hours. Use comparison_id to select one comparison.
Response 200
{"data":[{"name":"Consumo general","formula":[{"sign":"-","register_name":"Red"},{"sign":"+","register_name":"Inversores"}],"egauge_kwh":153389.0,"reference_kwh":99800.0}]}
GET
/api/v1/solar/assets
solar.read
Lists Solar plants and inverters covered by the company’s active Solar capacity. Public UUIDs from this response are used by the other Solar endpoints. An active Solar Hub add-on is required.
Request
curl https://www.dynoraptors.ai/api/v1/solar/assets \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"plants": [{
"id": "85130766-43de-46c7-b639-451d7d56cb29",
"name": "Main Plant", "timezone": "America/Mexico_City",
"installed_capacity_kw": 248.5, "inverter_count": 12
}],
"inverters": [{
"id": "c286067e-3718-4f83-915e-14f233ae965d",
"plant_id": "85130766-43de-46c7-b639-451d7d56cb29",
"name": "Inverter 01", "serial_number": "INV-001",
"model": "SUN2000", "installed_capacity_kw": 20.0, "enabled": true
}],
"meta": {"limited": false, "entitled_plants": 1, "entitled_inverters": 12}
}
GET
/api/v1/solar/status-snapshot
solar.read
Returns delayed production status derived from the latest eligible 15-minute bucket. Use plant_id, inverter_id, or comma-separated inverter_ids to narrow the selection.
Request
curl "https://www.dynoraptors.ai/api/v1/solar/status-snapshot?plant_id=85130766-43de-46c7-b639-451d7d56cb29" \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"as_of": "2026-08-14T16:45:00Z", "freshness_delay_minutes": 15,
"data": [{
"plant_id": "85130766-43de-46c7-b639-451d7d56cb29",
"inverter_id": "c286067e-3718-4f83-915e-14f233ae965d",
"inverter_name": "Inverter 01", "status": "producing", "stale": false,
"bucket_at": "2026-08-14T16:30:00Z", "average_power_kw": 14.8,
"minimum_power_kw": 13.9, "maximum_power_kw": 15.4,
"energy_kwh": 3.7, "samples": 3
}]
}
GET
/api/v1/solar/production
solar.read
Returns complete daily production from stored Solar history. Current partial days are excluded. It accepts start, end, plant_id, inverter_id, and comma-separated inverter_ids. API plan retention, maximum range, row, and selection limits apply.
Request
curl "https://www.dynoraptors.ai/api/v1/solar/production?inverter_id=c286067e-3718-4f83-915e-14f233ae965d&start=2026-08-10T00:00:00-06:00&end=2026-08-14T00:00:00-06:00" \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"data": [{
"date": "2026-08-10",
"plant_id": "85130766-43de-46c7-b639-451d7d56cb29",
"inverter_id": "c286067e-3718-4f83-915e-14f233ae965d",
"inverter_name": "Inverter 01", "energy_kwh": 118.42, "samples": 1
}],
"summary": {"energy_kwh": 118.42, "row_count": 1},
"meta": {"resolution": "day", "complete_days_only": true, "limited": false}
}
GET
/api/v1/stop-events
stop_events.read
Returns recorded downtime events, newest first, with page-based pagination.
- start / end
- Optional ISO 8601 timestamps with timezone.
- machine_id
- Optional public machine UUID when requesting stops for one machine.
- machine_ids
- Optional comma-separated public machine UUIDs for multiple machines. Do not combine with
machine_id.
- page
- Page number from 1 to 100. Default 1.
- page_size
- Rows per page from 1 to 100. Default 50.
Request
curl "https://www.dynoraptors.ai/api/v1/stop-events?machine_id=7404ab3c-5614-4a23-97bb-725d08d6a436&start=2026-08-05T00:00:00Z&end=2026-08-06T00:00:00Z&page=1&page_size=50" \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"data": [{
"id": "abf81ba0-df54-4ba4-a5f2-fea763f2728b",
"machine_id": "7404ab3c-5614-4a23-97bb-725d08d6a436",
"machine_name": "Injection Press 04",
"start": "2026-08-05T14:10:00Z", "end": "2026-08-05T14:27:20Z",
"duration_seconds": 1040, "description": "Material change",
"state": "registered", "department": "Production",
"event_type": "Planned stop", "tags": ["material_change"]
}],
"meta": {"page": 1, "page_size": 50, "next_page": null, "latest_allowed": "2026-08-06T18:45:00Z"}
}
GET
/api/v1/stop-events/summary
stop_events.read
Summarizes recorded stop count and overlapping stopped seconds. Use machine_id for one machine or machine_ids for multiple machines. It accepts the same start and end filters as the event list.
Request
curl "https://www.dynoraptors.ai/api/v1/stop-events/summary?machine_id=7404ab3c-5614-4a23-97bb-725d08d6a436&start=2026-08-05T00:00:00Z&end=2026-08-06T00:00:00Z" \
--header "Authorization: Bearer $DYNORAPTOR_API_KEY"
Response 200
{
"data": [{
"machine_id": "7404ab3c-5614-4a23-97bb-725d08d6a436",
"machine_name": "Injection Press 04",
"stop_event_count": 3, "recorded_stop_seconds": 2860
}],
"meta": {
"start": "2026-08-05T00:00:00Z", "end": "2026-08-06T00:00:00Z",
"latest_allowed": "2026-08-06T18:45:00Z"
}
}
DynoRaptors OEE customer API v1
The OEE add-on supports production operations through authenticated HTTP requests
and the tablet panel. Both use the same production services and PostgreSQL facts.
API Core's delayed, read-only telemetry contract is a separate service; it does
not describe OEE writes. This document describes the release candidate; production
availability follows deployment and customer activation.
Credentials and discovery
An OEE administrator creates the key in Configuration → Integrations / API.
Select explicit machines, permissions and expiration; save the one-time secret
in the caller's credential store. Do not put it in URLs or log it. Requests use
Authorization: Bearer <secret> over HTTPS; browser cookies do not authenticate
integration calls. Active/trial OEE entitlement is required, not base API access.
Outside local development (DEBUG=False), the authenticator rejects non-HTTPS
requests before looking up credentials. Deployments behind a proxy must retain
the project's trusted forwarded-protocol configuration. Never test this by
sending a real key over HTTP: server rejection cannot undo transport exposure.
Revocation and expiration take effect on subsequent requests. Issuer removal,
deactivation or loss of required administrator access also disables use.
Paths below are relative to the DynoRaptors mount: / on its own domain, or
/api/dyno_raptor/ on the shared staging/local host.
Catalog editors, CSV imports and API discovery
Catalog creation and CSV uploads use authenticated browser endpoints; an OEE bearer
key does not grant catalog writes. Developers can read authorized setup data using
GET api/oee/v1/machines/<machine UUID>/setup/?kind=products,
kind=standards or kind=orders, with oee.read.
Product results include id,code,name,unit,description,revision,active.
Standard results include the ideal targets, units_per_event,
expected_setup_minutes, planning_efficiency_percent, revision
and effective dates. Order results include product/standard IDs, quantity, state,
planned_start,planned_end,due_at,priority,customer_reference,lot_reference,notes.
CSV standards accept existing product_code,
machine_asset_id and tooling_asset_id. CSV orders accept
required product_code and optional standard_id.
Direct references need no prerequisite imports. Standards have 15 supported columns and
orders have 13. Unsupported CSV columns are rejected, including alternative product UUID
and external-reference columns. Product UUIDs remain valid in JSON API operations; this
restriction applies to the catalog CSV format.
Manual and CSV standard saves use the same defaults: units/event 1, throughput
period 3600 seconds, setup 0 minutes, planning efficiency 85%, revision 1. Event/batch
requires positive ideal seconds; quantity requires positive ideal quantity. Inactive
measurement fields are ignored. Manual mode has no ideal target. Name or at least one
context is required. Setup minutes must be whole and nonnegative. Blank effective date
uses now for new records and preserves it on updates. CSV timestamps use ISO 8601
with timezone; date pickers use the company timezone. Saved standards are approved.
Products preserve omitted optional fields on updates; blank text clears them.
Orders require a product and positive target quantity; priority defaults to 2 and
state to draft. Optional dates, notes, references, priority and state preserve existing
values when omitted. Planned end must follow start. MO planning dates do not create
planner reservations. CSV external_id provides repeatable import identity.
Discover machine and asset IDs
Call GET /api/oee/v1/context/ with
Authorization: Bearer <OEE key> and scope oee.read.
Each machines entry returns id (the machine UUID used
as machine_id in OEE requests), name, and
asset_id (the existing company asset UUID used in asset CSV mappings).
These are different identifiers. Serial numbers are not guaranteed unique.
{"machines": [{"id": "<machine UUID>", "name": "Press", "asset_id": "<asset UUID>"}]}
Only enrolled machines authorized by the key are returned. A null
asset_id means no company asset is linked; this endpoint does not create assets.
To register an external machine reference, an administrator uploads the asset CSV with
external_id,name,kind,asset_id and a consistent source such as csv.
Unknown, foreign-company, archived or conflicting asset identities fail validation.
The browser catalog GET /dashboard/assets/ returns the asset UUID as
id, but requires a signed-in browser session, not an OEE bearer key.
| Request |
Scope |
Purpose |
GET api/oee/v1/context/ |
oee.read |
Authorized enabled machine UUIDs and linked asset UUIDs |
GET api/oee/v1/machines/<machine UUID>/setup/ |
oee.read |
Paginated setup references for one authorized machine |
GET api/oee/v1/runs/ |
oee.read |
Run UUIDs, state, order and current standard/output snapshots |
POST api/oee/v1/runs/ |
oee.runs.write |
Start, report a completed interval, change setup, pause, resume or finish a run |
GET api/oee/v1/results/ |
oee.read |
Rebuilt machine and authorized-factory results |
GET api/oee/v1/captures/ |
oee.read |
Accepted revision history |
POST api/oee/v1/captures/ |
oee.captures.write |
New capture or replacement revision |
DELETE api/oee/v1/captures/ |
oee.captures.void |
Void capture or record deletion tombstone |
Replacing a live capture requires oee.captures.void as well as write scope.
Reads paginate at 50 entries with page, returning count, pages, page and
results. Runs accept state, run_id, and machine_id; UUID filters stay
inside the credential’s authorized machines. Capture history accepts source and external_id.
An optional revision requires both identity filters and an integer from 1 to
9007199254740991; it selects that exact accepted revision before pagination.
Invalid exact-lookup parameters return HTTP 400 invalid_revision_lookup.
An empty scoped result does not prove the identity never existed outside the
credential's current machine access. An accepted historical revision is not
necessarily the current total: a later revision may replace or void it.
Use latest=1 with both source and external_id (and without revision) to
read the identity's latest accepted revision and its contribution: active,
void or reversed, with quantity/unit/kind. Native reversals reduce that
identity's contribution to zero even if its last integration operation was a
capture. This is the identity's contribution, not the whole machine's output.
If the latest revision belongs to a machine outside the key's access, the API
returns 403 rather than substituting an older accessible revision. A capture
missing its underlying fact returns 409 capture_contribution_unavailable;
it is not assumed to contribute zero. Invalid latest lookup parameters return
400 invalid_latest_lookup. The result describes the observed state and may
change after the request.
If a native OEE correction already reversed the latest integration fact, a later
same-run source replacement or void preserves that reversal instead of reversing
twice. The replacement contributes its newly reviewed quantity; a void records
the new source revision with no additional negative fact. Cross-run reassignment
requires an active original capture and is rejected after a native reversal.
Only machine-authorized, enabled OEE runs are available. Integration requests
use atomic fixed-window admission budgets: 10/second and 120/minute per key,
30/second and 600/minute per company, and 100/second and 3,000/minute across the
OEE integration API. These limits apply to reads, captures and voids, including
retries. A batch quantity is one request; do not send one request per unit when a
scan represents a batch. 429 includes Retry-After; retain the same identity and
revision when retrying. Windows reset on second/minute boundaries, so adjacent
windows can permit a boundary burst. Denied requests may consume earlier budget
counters conservatively; clients must not continuously poll a denied request.
Production requires the shared Redis cache. Admission-cache failures return 503
with Retry-After: 5 before production processing. The sender should use bounded
concurrency, exponential backoff and jitter. Rate admission follows authentication;
it is not a replacement for edge-level invalid-credential/connection protection.
Staging must validate Redis capacity/eviction behavior, worker clock alignment,
end-to-end latency and delivery recovery before these budgets establish release
capacity. OEE_API_KEY_BURST_LIMIT may tune the per-key burst from 1 through 120
through Django settings; minute/company/global budgets remain fixed.
Starting a run
POST runs with exactly source, command_id (UUID), machine_id (the
DynoRaptors machine UUID, not its serial), action (start), occurred_at,
reason, operator_external_id, standard_id, tooling_asset_id,
active_outputs, order_id, and counter_binding_id.
Tooling/order IDs are UUIDs or null; active outputs are a product UUID-to-quantity
object (empty for nominal outputs). Counter binding is an integer ID or null.
If the machine has enabled production counters, select one explicitly; null
does not silently bypass automatic counting. An active linked company asset and
approved, effective, compatible standard are required. Active or historical run
overlaps are rejected. Timestamps require a timezone and cannot be future.
Commands return run ID, state and version. Retry with the original command UUID
and identical payload to retrieve its receipt without creating another run.
Discover references using the machine setup endpoint with kind=standards
(default), tools, orders, counters, or defects, and page (50 rows per page).
Optional at is an aware, nonfuture production timestamp; standards and counters
are filtered by effective dates. Standards exclude unapproved revisions and
archived tools; orders exclude completed/cancelled states. Tools are active
company tooling assets. References are candidates, not a guarantee that every
combination is compatible: start/setup revalidate product, machine and tooling
relationships at submission. UUIDs belong to DynoRaptors, not the source ERP.
Existing-run lifecycle commands
POST runs accepts exactly source, command_id (UUID), run_id (UUID),
action (pause, resume, finish, setup), occurred_at, reason,
operator_external_id, and expected_run_version. Use the version returned by
GET runs or the preceding successful command; do not generate it yourself.
Production time requires a timezone, cannot be future, and must follow the current
run/setup/pause boundaries. Source/reason/operator limits are 80/300/160 characters.
Each new operation uses a new command UUID. Retry an unconfirmed operation with
the exact original payload. Accepted command receipts remain replayable after
later state changes and key rotation within the same authorized company/machines.
Reusing a command ID with changed content or submitting a stale version returns
409. Review current state before preparing a new command; never blindly substitute
the new version. Commands use native workflows and persist their audit/rebuild
jobs transactionally. A setup command additionally requires standard_id,
tooling_asset_id (UUID or null to retain current tooling), and active_outputs
(object mapping product UUIDs to active units, empty if no overrides). The standard
must be approved/effective at production time; tools must be active company
assets. Unknown products and invalid active quantities are rejected. Setup creates
an effective-dated segment without rewriting prior snapshots.
Capture request payload
Reject captures may include defect_code, resolved case-insensitively against
the company's active defect catalog (discover with setup kind=defects). Omit
it for unclassified rejects. It is not accepted for good/output captures or
DELETE requests. Existing receipts replay after catalog deactivation; new
captures/replacements require an active code. Changing classification requires a
new revision and replacement permission, preserving the original via reversal.
Use JSON (Content-Type: application/json). Example placeholders must be
replaced by a discovered run UUID and its actual production timestamp/unit:
{
"source": "inoquos",
"external_id": "production-registration:100",
"revision": 1,
"run_id": "<run UUID>",
"kind": "good",
"quantity": "240",
"unit": "pcs",
"occurred_at": "2026-09-07T08:15:00-06:00",
"operator_external_id": "employee:12",
"reason": "Box registration"
}
All fields shown are required for timestamped captures; an explicit interval
may replace occurred_at as described below. Unknown fields are rejected. Source and external
ID have limits of 80/255 characters, operator reference 160, reason 300. Revision
is a positive integer no larger than 9007199254740991. Quantity is positive with
at most six decimals and less than 10^12. Kinds are good, reject, output.
Use stable source-record IDs, not mutable display names or generated retry IDs.
occurred_at is production time, not necessarily scan time. It must include
a timezone, not be in the future, and belong to the run's half-open interval
[start, end). Unit must exactly match its effective standard; kilograms are not
implicitly converted into pieces. Do not invent precise production timestamps
from a later packaging scan; supply an explicit interval instead.
The external operator reference is retained separately from the credential's
authenticated issuer; it does not grant that operator platform permissions.
output is evidence/manual output under the same reconciliation policy as the
native workspace. It is not added on top of a machine counter. Never mirror the
same box as both additional machine output and accepted output to inflate totals.
Production intervals and allocation
When production time is known only as a period, replace occurred_at with:
"production_interval": {
"start": "2026-09-07T06:00:00-06:00",
"end": "2026-09-07T14:00:00-06:00",
"method": "counter_proportional"
}
Provide exactly start, end, and method. Timestamps must have timezones;
the interval must be nonempty, no longer than 24 hours, not future, contained in
the run, and covered by setup history without a change of output unit. Split
longer periods or periods spanning different output units into separate source
records. occurred_at and production_interval are mutually exclusive.
| Method |
Meaning |
unallocated |
Keep the known interval total. Finer periods withhold affected metrics until allocation is supplied. |
uniform_time |
Explicitly estimate an even distribution over the interval's elapsed time. |
counter_proportional |
Explicitly estimate distribution in proportion to measured production output, using historical setup/counter snapshots. Requires a configured production counter throughout the interval; missing telemetry leaves allocation pending. |
Neither estimate proves when individual good pieces or defects were produced.
The dashboard/tablet disclose estimated allocation, and affected calculations
remain provisional. A calculation covering an entire interval uses its exact
captured quantity. For partial periods, cumulative rounding conserves the
original total across adjacent buckets to six decimal places. Ordinary output
captures remain excluded when a machine counter already supplies total output.
Receipts and capture history return the interval. Revisions and voids preserve
the old interval through reversal and recalculate its full range, as well as the
replacement range. Do not include timing fields in DELETE requests. API receipt
time remains separate from production time. Native capture history exposes the
period and allocation method; it does not present the legacy storage timestamp
as a precise production event for interval captures.
Inoquos delivery preparation accepts an explicit timestamp or an explicit
production interval. Prepared timing and allocation method are immutable across
retries. Source shift/date-to-interval mapping and operator review are still
required; the sender does not infer them or enable live delivery automatically.
A source DELETE for an already prepared barcode is prepared automatically against
that identity's latest prepared run, including a reviewed reassignment destination.
It does not require a new production timestamp or
valid replacement quantity. Its earlier revisions must still be acknowledged
before the durable sender dispatches the DELETE. An unknown/unprepared barcode
identity remains unresolved.
Revisions, deletion and retries
Historical run discovery: GET api/oee/v1/runs/ accepts a scoped
machine_id plus either production_at or both production_start and
production_end. Times must include an offset, cannot be future, and intervals
must be positive and at most 24 hours. A point uses the run's half-open interval;
a production interval must fit entirely within one run (ending exactly at its
end is allowed). Cancelled runs are excluded. Existing 50-row pagination applies.
The Inoquos read_production_run_for_time helper requires exactly one matching
run, verifies the machine identity, then fetches full historical setup evidence.
It returns an unresolved error for zero or multiple matches. Each HTTPS read has
the existing deadline/body bounds. This lookup supplies no scan timing policy
and does not itself prepare or send production. Local implementation pending
deployment after v4025.
Identity is (company/workspace, source, external_id), independent of API key.
Reusing that identity after key rotation does not duplicate production. A revision
is a full replacement, not an increment; send the corrected total for that record.
- New POST: 201, durable accepted event UUID and revision.
- Optional
expected_run_version pins reviewed setup evidence. A new capture
with a stale version returns 409 before writing any facts. Identical retries of
an accepted revision return its receipt even after the run changes. The source
uses this for reviewed/automatic preparation. A separate
X-OEE-Reviewed-Run-Version header can supply a freshly reviewed version for the
identical version-pinned POST. It must match the locked run's current version;
it never changes the capture body, revision/hash or required API permissions.
The receiver records original/reviewed versions in capture audit metadata.
Inoquos exposes an administrator preview/confirmation flow that verifies
historical compatibility and records who authorized this retry and why. Each
outbound attempt links to its review. This recovery path is local pending
deployment and end-to-end staging acceptance.
- Same revision and normalized payload: 200 with
replayed: true; no new capture.
- Same revision with changed contents: 409; correct the client or use a new revision.
- Previously unseen revision lower than the latest: 409; do not resurrect stale data.
- Higher replacement revision: reverses the previous entry at its original time
and records the new quantity/time atomically, preserving both in audit history.
- DELETE sends the same identity, revision, run, reason and operator fields, but
omits kind/quantity/unit/occurred_at. Use a higher revision. Repeated DELETE is
idempotent. DELETE before creation records a tombstone that rejects older POSTs.
- A higher POST after a void is an explicit restoration. An acknowledged retry
of an older revision returns that prior receipt without changing the latest state.
An ordinary replacement cannot change a record's run identity. For an explicitly
reviewed reassignment, POST a higher revision with the same source/external ID,
the destination run_id, valid destination quantity/unit/time, a correction
reason, and reassignment: {"from_run_id": "<original run UUID>", "from_revision": 1}.
The referenced revision must be the latest active capture. Both write and void
scopes and access to both enrolled machines are required. The receiver reverses
the original on its original run/time, writes the replacement on the destination,
and queues both historical rebuilds in one PostgreSQL transaction. A replacement
failure rolls back the reversal and both rebuild requests. Receipts/history expose
the reassignment evidence, and retrying the exact revision never moves it twice.
Subsequent ordinary corrections/deletion reference the destination run. A voided
identity cannot be moved using reassignment; review its intended restoration first.
Inoquos administrators can prepare this through the existing correction form:
enter the destination run, explicit production timing and a reason. Preview and
confirmation verify both runs over the scoped HTTPS API; a changed original or
destination run invalidates the review. The source ledger appends a preparation
audit and immutable revision, preserving its source observation hash. Ordered
delivery waits for earlier revisions to be acknowledged. A subsequent source
DELETE follows the latest prepared destination. These changes are deployed on
staging v4025. Bounded source-view/HTTPS acceptance verified reassignment, replay
and deletion across two runs on an isolated machine, with preserved history and
completed rebuilds. Automatic source mapping and live synchronization remain off.
Queries expose revision history, not an unqualified claim that every old receipt
is the current state. Reports recalculate asynchronously; an accepted receipt is
not proof that a KPI has refreshed. Native captures/reversals now persist rebuild
requests transactionally; Redis delivery failure leaves the request pending for
five-minute recovery. Workers process at most 12 buckets per request invocation.
Context exposes recalculation.pending_jobs, retrying_jobs, and
oldest_pending_at within the key's machine scope. Counter-query failures retain
the pending job. Real worker-restart/load acceptance remains a release gate;
schedule/import invalidation and telemetry arrival must also be verified.
Handle 400 as validation failure; 401 as missing/invalid/expired/revoked key; 403
as missing scope, entitlement or machine access; 409 as revision/domain conflict.
Retry network failures and 5xx with the same payload/revision. Persist outbound
events atomically with source changes before asynchronous delivery. The planned
Inoquos sender must not block production registration on HTTP or delete its local
event until acknowledgment is durable.
Completed reports without a tablet
POST to api/oee/v1/runs/ with the same fields as action: start,
using action: report and two additional required fields: ended_at and
product_code. occurred_at is the actual start of the reported production
interval. The interval must have ended, be at most 24 hours, and not overlap any
non-cancelled run. A later active run does not block an earlier non-overlapping
report. Product must match the single-product approved setup; the selected
standard and counter must remain effective throughout the interval. Report
separate setup intervals when a shift changed products or setup.
The receiver atomically creates a completed run and its immutable setup snapshot,
records the command receipt and requests historical recalculation. It does not
invent quantities, downtime, planning, or calibration. Submit production/quality
captures separately using the returned run_id and version. Reuse the same
source, command_id and exact content after a timeout; the receipt is replayed.
Changing content under an existing command ID returns 409. This also permits
recovery when the server committed but the client did not receive its response.
Inoquos keeps its own source ledger and run-command receipts. Its administrator
can opt in a machine's completed-shift report mapping: one product, approved
DynoRaptors standard UUID and configured counter ID. The mapping declares a
single setup for that complete shift; no source cycle measurement becomes an
ideal standard. This optional sender path waits for shift completion, then
creates a missing run through HTTP and submits each barcode's batch quantity.
Existing real-time runs can receive scans immediately. Native API start/setup/
finish is available to external clients throughout the shift. Ambiguous runs,
changed mappings and mixed-product shifts remain visible for review.
Source quantity corrections and deletions use capture revisions and voids; they
keep the run and audit history, then rebuild the affected historical intervals.
They do not erase telemetry or delete a run's planning history. A changed source
production date is an assignment correction requiring review of the destination
run and original contribution. Automatic run provisioning never rewrites an
uncertain command after a setup mapping changes.
Machine and factory results
GET api/oee/v1/results/?start=<ISO time>&end=<ISO time> with
oee.read. Supply timezone-aware five-minute boundaries, a completed range up to
31 days, and optionally machine_id. A request is capped at 100,000 stored
buckets; narrow the interval or machine selection after 422.
factory contains the aggregate of only the key's authorized, enrolled
machines. It is not necessarily the customer's entire factory. machines
returns external machine UUIDs, names, bucket counts and each aggregate. The
response uses persisted recalculation results and includes computation times,
source warnings, planning sources, estimated/pending allocation and provisional
state. Pending recalculation counts are available from the context endpoint.
Availability uses running/planned time. Performance uses ideal productive time
against running time. Quality and factory aggregation use compatible quantities
or ideal production time as appropriate; percentages are never averaged.
Counter output takes precedence over barcode/operator production quantities.
Production captures reconcile against that output; they do not add a second
copy. Missing counter evidence, unapproved standards, unallocated reports or
unresolved quality can produce null factors. A null is not zero production.
Workspace units and ERP conversions
Unit fields use workspace catalog codes, not a fixed abbreviation enum. Discover
units with GET api/oee/v1/machines/<machine UUID>/setup/?kind=units
and an oee.read key authorized for that machine. Optional code
filters by exact code; results are paginated (50/page). Each unit includes
id, code, name, active, source, external_id, measurement.
Use code in CSV unit/output_unit, standards and capture requests; show
name to people. Odoo identity is connection + ERP unit ID. Renaming Pce
in Odoo does not change its identity. Products imported before this catalog retain
their existing unit codes: always use the product's returned unit.
Built-in codes remain valid and are not automatically merged with ERP labels.
In the workspace Units catalog, supervisors/admins can create custom units with
an immutable code (1–20 ASCII letters/digits, dots, underscores or
hyphens; first character alphanumeric) and a descriptive name (240
characters maximum). The u_ prefix is reserved. Cookie-authenticated
production/units/ accepts POST {code,name} to create, POST {id,code,name}
to rename a custom unit, and GET with optional paged=1, page and search. Manage
imported units in the ERP. Integration keys use setup discovery instead.
Native units work without conversion metadata when the MO and product share
an ERP unit ID. Differing MO units convert to the product unit only with compatible
ERP references: category for Odoo ≤18, common root for Odoo 19. Measurement metadata
contains group, to_reference (reference quantity per source
unit), and rounding (ERP precision). Original MO quantities and
conversion definitions are retained. Targets must fit six decimal places; no
silent rounding to the ERP increment occurs.
unit_conversion_required: configure compatible units in the ERP
or provide quantities in the product unit.
unit_precision_loss: conversion cannot fit the stored precision.
invalid_unit_metadata: invalid reference, ratio or rounding.
unit_definition_changed: upstream definition changed; review before
resuming. Existing quantities and historical snapshots remain unchanged.
Custom units imply no automatic conversion. The caller must explicitly handle
product-specific packaging, mass-to-piece conversion and yield assumptions.
Capture endpoints still require the run's snapshotted output unit, and counters
must be calibrated in the standard's output unit. ERP MO conversion does not
convert production, defects or kilogram scrap submitted through capture endpoints.