Reference
Operations
Work orders — create them, assign them, move them, call them off.
An operation is a unit of maintenance work: a repair, an inspection, a preventive visit. It is what the technician sees in their app, what the calendar shows, and what every maintenance KPI is computed from.
Most integrations use this resource in one of two directions. Inbound: a monitoring system, a helpdesk or an ERP opens an operation when something needs doing. Outbound: a BI tool reads completed operations to report on cost and downtime. Both are supported; the second is easier, so start there if you are new to the API.
The operation object
iduuid- Opaque. Do not parse it.
objectstring- Always "operation".
titlestring- What needs doing.
descriptionstring · nullable- Detail.
statusstring- new, assigned, pending_start, in_progress, start_disputed, pending_completion, completion_disputed, completed, done, cancelled. Read-only.
required_skillstring · nullable- The trade this needs, for example mechanical, electrical or plumbing. See the create endpoint for the full list.
placestring · nullable- Free-text location. Filled in from the asset's room → floor → building when you supply an asset and omit this.
asset_iduuid · nullable- The machine or item this is about.
assignee_typestring · nullable- "technician" for your own staff, "vendor" for a partner firm.
technician_iduuid · nullable- The technician profile id. Matches an id from /v1/technicians.
vendor_iduuid · nullable- The partner firm, when delegated.
scheduled_fortimestamp · nullable- ISO 8601, UTC. Null means unscheduled.
agreed_amountstring · nullable- A decimal STRING, not a number.
notesstring · nullable- Internal notes.
created_attimestamp- ISO 8601, UTC.
updated_attimestamp- ISO 8601, UTC.
{
"id": "8c1e93a0-2d7f-4b8c-9b3d-5f2c1a7e4c81",
"object": "operation",
"title": "Line 2 conveyor — bearing noise",
"description": "Operator reports intermittent grinding at the drive end.",
"status": "assigned",
"required_skill": "mechanical",
"place": "Plant 1 — Line 2",
"asset_id": "b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"vendor_id": null,
"scheduled_for": "2026-09-24T07:30:00.000Z",
"agreed_amount": null,
"notes": null,
"created_at": "2026-09-23T10:04:00.000Z",
"updated_at": "2026-09-23T10:04:00.000Z"
}Endpoints
List operations
/operationsoperations:readPaginatedNewest first.
Query parameters
statusstring- Filter by status. An unknown value returns 400.
asset_iduuid- Only operations on this asset.
building_iduuid- Only operations in this building, via their asset.
technician_iduuid- Only operations assigned to this technician.
vendor_iduuid- Only operations delegated to this vendor.
assignee_typestring- technician or vendor.
searchstring- Matches the title, place, skill and people involved.
curl https://nexa.com.tn/api/v1/operations \
-H "Authorization: Bearer $NEXA_API_KEY"const response = await fetch(
"https://nexa.com.tn/api/v1/operations",
{
headers: {
Authorization: `Bearer ${process.env.NEXA_API_KEY}`,
},
},
);
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();import os
import requests
headers = {
"Authorization": f"Bearer {os.environ['NEXA_API_KEY']}",
}
response = requests.get(
"https://nexa.com.tn/api/v1/operations",
headers=headers,
)
response.raise_for_status()
data = response.json()["data"]Response
{
"data": [
{
"id": "8c1e93a0-2d7f-4b8c-9b3d-5f2c1a7e4c81",
"object": "operation",
"title": "Line 2 conveyor — bearing noise",
"description": "Operator reports intermittent grinding at the drive end.",
"status": "assigned",
"required_skill": "mechanical",
"place": "Plant 1 — Line 2",
"asset_id": "b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"vendor_id": null,
"scheduled_for": "2026-09-24T07:30:00.000Z",
"agreed_amount": null,
"notes": null,
"created_at": "2026-09-23T10:04:00.000Z",
"updated_at": "2026-09-23T10:04:00.000Z"
}
],
"pagination": {
"limit": 50,
"has_more": true,
"next_cursor": "eyJvIjo1MH0"
}
}Retrieve an operation
/operations/{taskId}operations:readPath parameters
taskIduuidrequired- The operation.
curl https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef \
-H "Authorization: Bearer $NEXA_API_KEY"const response = await fetch(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
{
headers: {
Authorization: `Bearer ${process.env.NEXA_API_KEY}`,
},
},
);
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();import os
import requests
headers = {
"Authorization": f"Bearer {os.environ['NEXA_API_KEY']}",
}
response = requests.get(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
headers=headers,
)
response.raise_for_status()
data = response.json()["data"]Response
{
"data": {
"id": "8c1e93a0-2d7f-4b8c-9b3d-5f2c1a7e4c81",
"object": "operation",
"title": "Line 2 conveyor — bearing noise",
"description": "Operator reports intermittent grinding at the drive end.",
"status": "assigned",
"required_skill": "mechanical",
"place": "Plant 1 — Line 2",
"asset_id": "b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"vendor_id": null,
"scheduled_for": "2026-09-24T07:30:00.000Z",
"agreed_amount": null,
"notes": null,
"created_at": "2026-09-23T10:04:00.000Z",
"updated_at": "2026-09-23T10:04:00.000Z"
}
}Create an operation
/operationsoperations:writeRequires Idempotency-KeyRequires an `Idempotency-Key` header — without it, a retried request dispatches a technician to the same machine twice. Assign to one of your own technicians or delegate to a partner vendor; the required id differs, so send `assignee_type` and the matching field. Emits `operation.created`.
Body
assignee_typestringrequired- "technician" or "vendor".
technician_iduuidrequired- Required when assignee_type is "technician". An id from /v1/technicians. Must be on your team.
vendor_iduuid- Required when assignee_type is "vendor". Must be a firm you have an accepted partnership with.
titlestringrequired- What needs doing. At least 3 characters.
required_skillstringrequired- The trade, one of the 25 below (e.g. mechanical, electrical, plumbing; other when no trade fits). The codes used before October 2026 (electricite, mecanique_industrielle, …) are still accepted and stored as their new code. Anything else returns 400.
descriptionstring- Detail for the technician.
asset_iduuid- The machine. Must be one of yours. Fills in the location automatically.
placestring- Overrides the location derived from the asset.
scheduled_fortimestamp- ISO 8601.
prioritystring- lowest, low, medium, high, highest.
agreed_amountnumber- Agreed cost.
notesstring- Internal notes.
curl -X POST https://nexa.com.tn/api/v1/operations \
-H "Authorization: Bearer $NEXA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"title": "Line 2 conveyor — bearing noise",
"required_skill": "mechanical"
}'const response = await fetch(
"https://nexa.com.tn/api/v1/operations",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NEXA_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"title": "Line 2 conveyor — bearing noise",
"required_skill": "mechanical"
}),
},
);
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();import os
import uuid
import requests
headers = {
"Authorization": f"Bearer {os.environ['NEXA_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
}
response = requests.post(
"https://nexa.com.tn/api/v1/operations",
headers=headers,
json={
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"title": "Line 2 conveyor — bearing noise",
"required_skill": "mechanical"
},
)
response.raise_for_status()
data = response.json()["data"]Response
{
"data": {
"id": "8c1e93a0-2d7f-4b8c-9b3d-5f2c1a7e4c81",
"object": "operation",
"title": "Line 2 conveyor — bearing noise",
"description": "Operator reports intermittent grinding at the drive end.",
"status": "assigned",
"required_skill": "mechanical",
"place": "Plant 1 — Line 2",
"asset_id": "b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"vendor_id": null,
"scheduled_for": "2026-09-24T07:30:00.000Z",
"agreed_amount": null,
"notes": null,
"created_at": "2026-09-23T10:04:00.000Z",
"updated_at": "2026-09-23T10:04:00.000Z"
}
}Update an operation's details
/operations/{taskId}operations:writeField edits only. `status` is refused — see the note at the top of this page. Emits `operation.updated`.
Path parameters
taskIduuidrequired- The operation.
Body
titlestring- What needs doing.
descriptionstring- Detail.
placestring- Location.
required_skillstring- The trade.
agreed_amountnumber- Agreed cost.
notesstring- Internal notes.
curl -X PATCH https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef \
-H "Authorization: Bearer $NEXA_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'const response = await fetch(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
{
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.NEXA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
},
);
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();import os
import requests
headers = {
"Authorization": f"Bearer {os.environ['NEXA_API_KEY']}",
}
response = requests.patch(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
headers=headers,
json={},
)
response.raise_for_status()
data = response.json()["data"]Response
{
"data": {
"id": "8c1e93a0-2d7f-4b8c-9b3d-5f2c1a7e4c81",
"object": "operation",
"title": "Line 2 conveyor — bearing noise",
"description": "Operator reports intermittent grinding at the drive end.",
"status": "assigned",
"required_skill": "mechanical",
"place": "Plant 1 — Line 2",
"asset_id": "b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"vendor_id": null,
"scheduled_for": "2026-09-24T07:30:00.000Z",
"agreed_amount": null,
"notes": null,
"created_at": "2026-09-23T10:04:00.000Z",
"updated_at": "2026-09-23T10:04:00.000Z"
}
}Assign or reassign an operation
/operations/{taskId}/assignoperations:writeMoves the work to a different technician or delegates it to a vendor. Emits `operation.assigned`.
Path parameters
taskIduuidrequired- The operation.
Body
assignee_typestringrequired- "technician" or "vendor".
technician_iduuidrequired- Required when assignee_type is "technician".
vendor_iduuid- Required when assignee_type is "vendor".
curl -X POST https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef/assign \
-H "Authorization: Bearer $NEXA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122"
}'const response = await fetch(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef/assign",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NEXA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122"
}),
},
);
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();import os
import requests
headers = {
"Authorization": f"Bearer {os.environ['NEXA_API_KEY']}",
}
response = requests.post(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef/assign",
headers=headers,
json={
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122"
},
)
response.raise_for_status()
data = response.json()["data"]Response
{
"data": {
"id": "8c1e93a0-2d7f-4b8c-9b3d-5f2c1a7e4c81",
"object": "operation",
"title": "Line 2 conveyor — bearing noise",
"description": "Operator reports intermittent grinding at the drive end.",
"status": "assigned",
"required_skill": "mechanical",
"place": "Plant 1 — Line 2",
"asset_id": "b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"vendor_id": null,
"scheduled_for": "2026-09-24T07:30:00.000Z",
"agreed_amount": null,
"notes": null,
"created_at": "2026-09-23T10:04:00.000Z",
"updated_at": "2026-09-23T10:04:00.000Z"
}
}Move an operation's scheduled time
/operations/{taskId}/rescheduleoperations:reschedulePass null to take it off the calendar without closing it. Emits `operation.rescheduled`.
Path parameters
taskIduuidrequired- The operation.
Body
scheduled_fortimestamprequired- ISO 8601, or null to un-schedule.
curl -X POST https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef/reschedule \
-H "Authorization: Bearer $NEXA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"scheduled_for": "2026-09-26T13:00:00.000Z"
}'const response = await fetch(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef/reschedule",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NEXA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"scheduled_for": "2026-09-26T13:00:00.000Z"
}),
},
);
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();import os
import requests
headers = {
"Authorization": f"Bearer {os.environ['NEXA_API_KEY']}",
}
response = requests.post(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef/reschedule",
headers=headers,
json={
"scheduled_for": "2026-09-26T13:00:00.000Z"
},
)
response.raise_for_status()
data = response.json()["data"]Response
{
"data": {
"id": "8c1e93a0-2d7f-4b8c-9b3d-5f2c1a7e4c81",
"object": "operation",
"title": "Line 2 conveyor — bearing noise",
"description": "Operator reports intermittent grinding at the drive end.",
"status": "assigned",
"required_skill": "mechanical",
"place": "Plant 1 — Line 2",
"asset_id": "b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"vendor_id": null,
"scheduled_for": "2026-09-26T13:00:00.000Z",
"agreed_amount": null,
"notes": null,
"created_at": "2026-09-23T10:04:00.000Z",
"updated_at": "2026-09-23T10:04:00.000Z"
}
}Cancel an operation
/operations/{taskId}/canceloperations:cancelTerminal — a cancelled operation cannot be reopened. Emits `operation.cancelled`.
Path parameters
taskIduuidrequired- The operation.
Body
reasonstring- Why. Recorded and shown to the assignee.
curl -X POST https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef/cancel \
-H "Authorization: Bearer $NEXA_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'const response = await fetch(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef/cancel",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NEXA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
},
);
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();import os
import requests
headers = {
"Authorization": f"Bearer {os.environ['NEXA_API_KEY']}",
}
response = requests.post(
"https://nexa.com.tn/api/v1/operations/b7d41f0a-6e52-4a19-8c33-90ab12cd34ef/cancel",
headers=headers,
json={},
)
response.raise_for_status()
data = response.json()["data"]Response
{
"data": {
"id": "8c1e93a0-2d7f-4b8c-9b3d-5f2c1a7e4c81",
"object": "operation",
"title": "Line 2 conveyor — bearing noise",
"description": "Operator reports intermittent grinding at the drive end.",
"status": "cancelled",
"required_skill": "mechanical",
"place": "Plant 1 — Line 2",
"asset_id": "b7d41f0a-6e52-4a19-8c33-90ab12cd34ef",
"assignee_type": "technician",
"technician_id": "3a91cc70-1b44-4e9f-bb02-77de55aa1122",
"vendor_id": null,
"scheduled_for": "2026-09-24T07:30:00.000Z",
"agreed_amount": null,
"notes": null,
"created_at": "2026-09-23T10:04:00.000Z",
"updated_at": "2026-09-23T10:04:00.000Z"
}
}