Maintenance

Maintenance event history and scheduling.

POST/maintenance

Create a maintenance event

Requires `vesselId`, `scheduledDate`, `description`, and `eventType`. `scope` defaults to `equipment` and determines which FK is required: `equipment` requires `equipmentId`, `system` requires `vesselSystemId`, `vessel` requires neither. On ISM-onboarded vessels, `responsibleUserId` is also required. Supports the `Idempotency-Key` request header (see `IdempotencyKeyHeader` parameter) — a repeat POST with the same key and the same request body within 24h returns the original response unchanged with `Idempotent-Replayed: true`; the same key with a *different* body returns `409 CONFLICT`.

Header parameters
NameInTypeRequiredDescription
Idempotency-KeyheaderstringoptionalClient-generated unique token (e.g. a UUID) scoping this write to be safely retried. Replaying the same key with the same request body within 24h returns the original cached response unchanged (with `Idempotent-Replayed: true`); replaying with a different body returns `409 CONFLICT`. Opt-in — omit for normal (non-idempotent) behavior.
Request body
FieldTypeRequiredDescription
vesselIdstring (uuid)required—
scopeenum(equipment | system | vessel)optional—
equipmentIdstring (uuid)optionalRequired when scope=equipment.
vesselSystemIdstring (uuid)optionalRequired when scope=system.
eventTypeenum(routine | repair | inspection | upgrade | refit | warranty)required—
scheduledDatestring (date-time)required—
descriptionstringrequired—
priorityenum(low | medium | high | critical)optional—
serviceProviderIdstring (uuid)optional—
performedBystringoptional—
currencystringoptional—
responsibleUserIdstring (uuid)optionalRequired on ISM-onboarded vessels.
laborHoursnumberoptional—
laborCoststringoptionalSerialized as string to preserve Decimal precision.
notesstringoptional—
partsUsedarray<object>optional—
partsUsed[].inventoryItemIdstring (uuid)required—
partsUsed[].quantitynumberrequired—
workflowIdstring (uuid)optional—
Response
FieldTypeRequiredDescription
dataobjectrequired—
data.idstring (uuid)optional—
data.vesselIdstring (uuid)optional—
data.equipmentIdstring (uuid) | nulloptional—
data.vesselSystemIdstring (uuid) | nulloptional—
data.scopestringoptionalMaintenanceScope enum: equipment, system, or vessel.
data.eventTypestringoptionalMaintenanceType enum: routine, repair, inspection, upgrade, refit, warranty.
data.statusstringoptionalDerived workflow-bucket status (not a stored column) — computed from `workflowExecution.currentState`.
data.prioritystringoptionalMaintenancePriority enum: low, medium, high, critical.
data.scheduledDatestring (date-time) | nulloptional—
data.completedDatestring (date-time) | nulloptional—
data.descriptionstring | nulloptional—
data.performedBystring | nulloptional—
data.serviceProviderIdstring (uuid) | nulloptional—
data.serviceProviderobject | nulloptional—
data.serviceProvider.idstring (uuid)optional—
data.serviceProvider.businessNamestringoptional—
data.serviceProvider.phonestring | nulloptional—
data.partsUsedarray<object>optional—
data.partsUsed[].inventoryItemIdstring (uuid)optional—
data.partsUsed[].quantitynumberoptional—
data.laborHoursnumber | nulloptional—
data.laborCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data.partsCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data.totalCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data.currencystringoptional—
data.hoursAtServiceinteger | nulloptional—
data.beforePhotosarray<string>optional—
data.afterPhotosarray<string>optional—
data.invoiceAttachmentsarray<string>optional—
data.notesstring | nulloptional—
data.technicianSignaturestring | nulloptional—
data.technicianNamestring | nulloptional—
data.technicianSignedAtstring (date-time) | nulloptional—
data.requestedByIdstring (uuid) | nulloptional—
data.responsibleUserIdstring (uuid) | nulloptional—
data.linkedPermitIdstring (uuid) | nulloptional—
data.equipmentobject | nulloptional—
data.equipment.idstring (uuid)optional—
data.equipment.equipmentTypestringoptional—
data.equipment.makestring | nulloptional—
data.equipment.modelstring | nulloptional—
data.createdAtstring (date-time)optional—
data.updatedAtstring (date-time)optional—
cURL — idempotent create
curl -sS -X POST "https://api.owlmar.com/v1/maintenance" \
-H "Authorization: Bearer $OWLMAR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"vesselId": "'"$VESSEL_ID"'",
"equipmentId": "'"$EQUIPMENT_ID"'",
"eventType": "routine",
"scheduledDate": "2026-09-01T09:00:00.000Z",
"description": "500-hour service — port main engine"
}'
GET/maintenance/{id}

Get a maintenance event

Returns the full maintenance event with vessel, linked permit summary, recurring-schedule state, and current workflow state/transitions.

Path parameters
NameInTypeRequiredDescription
idpathstring (uuid)required—
Response
FieldTypeRequiredDescription
dataanyrequired—
PATCH/maintenance/{id}

Update a maintenance event

Partial update. Supports the `Idempotency-Key` header on the same terms as create.

Path parameters
NameInTypeRequiredDescription
idpathstring (uuid)required—
Header parameters
NameInTypeRequiredDescription
Idempotency-KeyheaderstringoptionalClient-generated unique token (e.g. a UUID) scoping this write to be safely retried. Replaying the same key with the same request body within 24h returns the original cached response unchanged (with `Idempotent-Replayed: true`); replaying with a different body returns `409 CONFLICT`. Opt-in — omit for normal (non-idempotent) behavior.
Request body
FieldTypeRequiredDescription
eventTypeenum(routine | repair | inspection | upgrade | refit | warranty)optional—
priorityenum(low | medium | high | critical)optional—
scheduledDatestring (date-time) | nulloptional—
completedDatestring (date-time) | nulloptional—
descriptionstring | nulloptional—
notesstring | nulloptional—
laborHoursnumber | nulloptional—
laborCoststring | nulloptionalSerialized as string to preserve Decimal precision.
partsUsedarray<object>optional—
partsUsed[].inventoryItemIdstring (uuid)optional—
partsUsed[].quantitynumberoptional—
Response
FieldTypeRequiredDescription
dataobjectrequired—
data.idstring (uuid)optional—
data.vesselIdstring (uuid)optional—
data.equipmentIdstring (uuid) | nulloptional—
data.vesselSystemIdstring (uuid) | nulloptional—
data.scopestringoptionalMaintenanceScope enum: equipment, system, or vessel.
data.eventTypestringoptionalMaintenanceType enum: routine, repair, inspection, upgrade, refit, warranty.
data.statusstringoptionalDerived workflow-bucket status (not a stored column) — computed from `workflowExecution.currentState`.
data.prioritystringoptionalMaintenancePriority enum: low, medium, high, critical.
data.scheduledDatestring (date-time) | nulloptional—
data.completedDatestring (date-time) | nulloptional—
data.descriptionstring | nulloptional—
data.performedBystring | nulloptional—
data.serviceProviderIdstring (uuid) | nulloptional—
data.serviceProviderobject | nulloptional—
data.serviceProvider.idstring (uuid)optional—
data.serviceProvider.businessNamestringoptional—
data.serviceProvider.phonestring | nulloptional—
data.partsUsedarray<object>optional—
data.partsUsed[].inventoryItemIdstring (uuid)optional—
data.partsUsed[].quantitynumberoptional—
data.laborHoursnumber | nulloptional—
data.laborCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data.partsCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data.totalCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data.currencystringoptional—
data.hoursAtServiceinteger | nulloptional—
data.beforePhotosarray<string>optional—
data.afterPhotosarray<string>optional—
data.invoiceAttachmentsarray<string>optional—
data.notesstring | nulloptional—
data.technicianSignaturestring | nulloptional—
data.technicianNamestring | nulloptional—
data.technicianSignedAtstring (date-time) | nulloptional—
data.requestedByIdstring (uuid) | nulloptional—
data.responsibleUserIdstring (uuid) | nulloptional—
data.linkedPermitIdstring (uuid) | nulloptional—
data.equipmentobject | nulloptional—
data.equipment.idstring (uuid)optional—
data.equipment.equipmentTypestringoptional—
data.equipment.makestring | nulloptional—
data.equipment.modelstring | nulloptional—
data.createdAtstring (date-time)optional—
data.updatedAtstring (date-time)optional—
POST/maintenance/{id}/complete

Mark a maintenance event complete

Stamps `completedDate: now()`, optionally deducts `partsUsed` from inventory (if not already deducted), and accepts the same body fields as a PATCH for any final details captured at completion time (labor hours, cost, notes, technician signature, etc.).

Path parameters
NameInTypeRequiredDescription
idpathstring (uuid)required—
Header parameters
NameInTypeRequiredDescription
Idempotency-KeyheaderstringoptionalClient-generated unique token (e.g. a UUID) scoping this write to be safely retried. Replaying the same key with the same request body within 24h returns the original cached response unchanged (with `Idempotent-Replayed: true`); replaying with a different body returns `409 CONFLICT`. Opt-in — omit for normal (non-idempotent) behavior.
Request body
FieldTypeRequiredDescription
partsUsedarray<object>optional—
partsUsed[].inventoryItemIdstring (uuid)required—
partsUsed[].quantitynumberrequired—
laborHoursnumber | nulloptional—
laborCoststring | nulloptionalSerialized as string to preserve Decimal precision.
notesstring | nulloptional—
technicianSignaturestring | nulloptional—
technicianNamestring | nulloptional—
Response
FieldTypeRequiredDescription
dataobjectrequired—
data.idstring (uuid)optional—
data.vesselIdstring (uuid)optional—
data.equipmentIdstring (uuid) | nulloptional—
data.vesselSystemIdstring (uuid) | nulloptional—
data.scopestringoptionalMaintenanceScope enum: equipment, system, or vessel.
data.eventTypestringoptionalMaintenanceType enum: routine, repair, inspection, upgrade, refit, warranty.
data.statusstringoptionalDerived workflow-bucket status (not a stored column) — computed from `workflowExecution.currentState`.
data.prioritystringoptionalMaintenancePriority enum: low, medium, high, critical.
data.scheduledDatestring (date-time) | nulloptional—
data.completedDatestring (date-time) | nulloptional—
data.descriptionstring | nulloptional—
data.performedBystring | nulloptional—
data.serviceProviderIdstring (uuid) | nulloptional—
data.serviceProviderobject | nulloptional—
data.serviceProvider.idstring (uuid)optional—
data.serviceProvider.businessNamestringoptional—
data.serviceProvider.phonestring | nulloptional—
data.partsUsedarray<object>optional—
data.partsUsed[].inventoryItemIdstring (uuid)optional—
data.partsUsed[].quantitynumberoptional—
data.laborHoursnumber | nulloptional—
data.laborCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data.partsCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data.totalCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data.currencystringoptional—
data.hoursAtServiceinteger | nulloptional—
data.beforePhotosarray<string>optional—
data.afterPhotosarray<string>optional—
data.invoiceAttachmentsarray<string>optional—
data.notesstring | nulloptional—
data.technicianSignaturestring | nulloptional—
data.technicianNamestring | nulloptional—
data.technicianSignedAtstring (date-time) | nulloptional—
data.requestedByIdstring (uuid) | nulloptional—
data.responsibleUserIdstring (uuid) | nulloptional—
data.linkedPermitIdstring (uuid) | nulloptional—
data.equipmentobject | nulloptional—
data.equipment.idstring (uuid)optional—
data.equipment.equipmentTypestringoptional—
data.equipment.makestring | nulloptional—
data.equipment.modelstring | nulloptional—
data.createdAtstring (date-time)optional—
data.updatedAtstring (date-time)optional—
GET/maintenance/vessel/{vesselId}

List a vessel's maintenance events

Returns maintenance events for a vessel with derived `status`, linked equipment, service provider, permit, schedule, and workflow-state info. Supports `?cursor=` pagination on the default (status-priority) sort path only — the `status=hours_due` filter branch (JS-side post-filter, no materialized sort column) does not support cursor and silently falls back to `?page=` semantics if combined with `?cursor=`.

Path parameters
NameInTypeRequiredDescription
vesselIdpathstring (uuid)required—
Query parameters
NameInTypeRequiredDescription
cursorquerystringoptionalOpaque pagination cursor from a previous response's `pagination.cursor`. Omit this param entirely for the first page of cursor mode; pass `cursor=` (empty) is also accepted as "start from the beginning in cursor mode." Omitting `cursor` altogether (not even as an empty string) falls back to legacy `?page=` semantics on endpoints that still support it.
limitqueryintegeroptional—
Response
FieldTypeRequiredDescription
dataarray<object>required—
data[].idstring (uuid)optional—
data[].vesselIdstring (uuid)optional—
data[].equipmentIdstring (uuid) | nulloptional—
data[].vesselSystemIdstring (uuid) | nulloptional—
data[].scopestringoptionalMaintenanceScope enum: equipment, system, or vessel.
data[].eventTypestringoptionalMaintenanceType enum: routine, repair, inspection, upgrade, refit, warranty.
data[].statusstringoptionalDerived workflow-bucket status (not a stored column) — computed from `workflowExecution.currentState`.
data[].prioritystringoptionalMaintenancePriority enum: low, medium, high, critical.
data[].scheduledDatestring (date-time) | nulloptional—
data[].completedDatestring (date-time) | nulloptional—
data[].descriptionstring | nulloptional—
data[].performedBystring | nulloptional—
data[].serviceProviderIdstring (uuid) | nulloptional—
data[].serviceProviderobject | nulloptional—
data[].serviceProvider.idstring (uuid)optional—
data[].serviceProvider.businessNamestringoptional—
data[].serviceProvider.phonestring | nulloptional—
data[].partsUsedarray<object>optional—
data[].partsUsed[].inventoryItemIdstring (uuid)optional—
data[].partsUsed[].quantitynumberoptional—
data[].laborHoursnumber | nulloptional—
data[].laborCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data[].partsCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data[].totalCoststring | nulloptionalSerialized as string to preserve Decimal precision.
data[].currencystringoptional—
data[].hoursAtServiceinteger | nulloptional—
data[].beforePhotosarray<string>optional—
data[].afterPhotosarray<string>optional—
data[].invoiceAttachmentsarray<string>optional—
data[].notesstring | nulloptional—
data[].technicianSignaturestring | nulloptional—
data[].technicianNamestring | nulloptional—
data[].technicianSignedAtstring (date-time) | nulloptional—
data[].requestedByIdstring (uuid) | nulloptional—
data[].responsibleUserIdstring (uuid) | nulloptional—
data[].linkedPermitIdstring (uuid) | nulloptional—
data[].equipmentobject | nulloptional—
data[].equipment.idstring (uuid)optional—
data[].equipment.equipmentTypestringoptional—
data[].equipment.makestring | nulloptional—
data[].equipment.modelstring | nulloptional—
data[].createdAtstring (date-time)optional—
data[].updatedAtstring (date-time)optional—
paginationobjectoptionalCanonical cursor-pagination block. On endpoints not yet retrofitted for true cursor support, `cursor` is a best-effort display-only value (not decodable, no `?cursor=` branch accepts it back) — see each endpoint's description for whether it has full cursor support.
pagination.cursorstring | nulloptionalOpaque token for the next page, or `null` when `hasMore` is `false`.
pagination.limitintegerrequired—
pagination.hasMorebooleanrequired—
pagination.totalintegerrequiredTotal row count matching the filter (not just this page).