Skip to content
Current State: ALPHA - Use at your own risk / Work in Progress

API Payload Reference

This document provides exact payload schemas, field constraints, and copy-paste examples for every API endpoint. Use this as a quick reference when integrating with the Eryxon API.


  1. Jobs API
  2. Parts API
  3. Operations API
  4. Issues / NCR API
  5. Substeps API
  6. Webhooks API
  7. Job Lifecycle API
  8. Operation Lifecycle API
  9. Other APIs
  10. Common Patterns

Endpoint: POST /functions/v1/api-jobs

POST - Create Job (with nested parts & operations)

Section titled “POST - Create Job (with nested parts & operations)”

This is the primary endpoint for ERP integration. Creates a job with all parts and operations in a single call.

{
"job_number": "JOB-2024-001",
"customer": "ACME Corp",
"due_date": "2024-12-31",
"priority": 1,
"notes": "Rush order - customer priority",
"metadata": {
"po_number": "PO-12345",
"erp_ref": "SAP-001"
},
"parts": [
{
"part_number": "PART-001",
"material": "Aluminum 6061-T6",
"quantity": 10,
"description": "Main housing",
"drawing_no": "DWG-001-A",
"cnc_program_name": "HOUSING_V2",
"operations": [
{
"operation_name": "CNC Milling",
"sequence": 1,
"estimated_time_minutes": 120,
"setup_time_minutes": 15,
"instructions": "Use 0.5 inch end mill, coolant on"
},
{
"operation_name": "Deburr",
"sequence": 2,
"estimated_time_minutes": 30
}
]
},
{
"part_number": "PART-002",
"material": "Steel 4140",
"quantity": 5,
"operations": [
{
"operation_name": "Turning",
"sequence": 1,
"estimated_time_minutes": 60
}
]
}
]
}
FieldTypeRequiredConstraintsNotes
job_numberstringYes1-255 chars, unique per tenantPrimary identifier
customerstringNomax 255 charsCustomer name
due_datestringNoISO 8601 datee.g. "2024-12-31"
priorityintegerNo>= 0Higher = more urgent
notesstringNo-Free text
statusstringNoenumnot_started (default), in_progress, on_hold, completed
metadataobjectNoJSON objectArbitrary key-value data
current_cell_idUUIDNomust exist in cellsCurrent work cell
partsarrayYesmin 1 itemSee Parts fields below
FieldTypeRequiredConstraints
part_numberstringYes1-255 chars, unique within job
quantityintegerYes>= 1
materialstringNo-
descriptionstringNo-
drawing_nostringNomax 255 chars
cnc_program_namestringNomax 255 chars
parent_part_idUUIDNomust exist, same job
current_cell_idUUIDNomust exist in cells
material_idUUIDNomust exist in materials
operationsarrayYesmin 1 item

Nested Operation Fields (within Part creation)

Section titled “Nested Operation Fields (within Part creation)”
FieldTypeRequiredConstraints
operation_namestringYes1-255 chars
sequenceintegerYes>= 1, unique within part
cell_idUUIDNomust exist in cells
assigned_operator_idUUIDNomust exist in profiles
estimated_time_minutesnumberNo>= 0
setup_time_minutesnumberNo>= 0
instructionsstringNo-
{
"success": true,
"data": {
"job": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"job_number": "JOB-2024-001",
"customer": "ACME Corp",
"status": "not_started",
"parts": [
{
"id": "...",
"part_number": "PART-001",
"operations": [
{
"id": "...",
"operation_name": "CNC Milling"
}
]
}
]
}
}
}
GET /functions/v1/api-jobs?status=in_progress&customer=ACME&limit=50&offset=0&sort=due_date&order=asc
ParamTypeDefaultNotes
idUUID-Get single job by ID
statusstring-not_started, in_progress, on_hold, completed
customerstring-Fuzzy match (partial)
job_numberstring-Fuzzy match (partial)
priorityinteger-Exact match
searchstring-Full-text across job_number, customer
sortstringcreated_atjob_number, customer, due_date, created_at, status, priority
orderstringdescasc or desc
limitinteger1001-1000
offsetinteger0Pagination offset
PATCH /functions/v1/api-jobs?id=<job-id>
{
"status": "in_progress",
"customer": "Updated Customer",
"due_date": "2025-01-15",
"notes": "Updated notes",
"metadata": {"updated": true}
}

Allowed update fields: status, customer, due_date, due_date_override, notes, metadata

DELETE /functions/v1/api-jobs?id=<job-id>

Sets deleted_at timestamp. Job no longer appears in queries.

PUT /sync - Sync single job by external ID

Section titled “PUT /sync - Sync single job by external ID”
PUT /functions/v1/api-jobs/sync
{
"external_id": "SAP-JOB-001",
"external_source": "sap",
"job_number": "JOB-2024-001",
"customer": "ACME Corp",
"parts": [...]
}

Required: external_id, external_source

POST /functions/v1/api-jobs/bulk-sync
{
"items": [
{
"external_id": "SAP-JOB-001",
"external_source": "sap",
"job_number": "JOB-2024-001",
"customer": "ACME"
},
{
"external_id": "SAP-JOB-002",
"external_source": "sap",
"job_number": "JOB-2024-002",
"customer": "Widgets Inc"
}
]
}

Endpoint: /functions/v1/api-parts

{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"part_number": "PART-003",
"material": "Aluminum 6061",
"quantity": 10,
"description": "Bracket assembly",
"drawing_no": "DWG-003",
"cnc_program_name": "BRACKET_V1",
"is_bullet_card": false,
"material_lot": "LOT-2024-A1",
"material_supplier": "MetalCo",
"material_cert_number": "CERT-12345",
"notes": "Heat treat required",
"metadata": {"revision": "B"},
"file_paths": ["drawings/bracket.pdf"]
}
FieldTypeRequiredConstraints
job_idUUIDYesmust exist in jobs
part_numberstringYes1-255 chars, unique within job
quantityintegerYes>= 1
materialstringNo-
descriptionstringNo-
drawing_nostringNomax 255 chars
cnc_program_namestringNomax 255 chars
is_bullet_cardbooleanNodefault false
material_lotstringNo-
material_supplierstringNo-
material_cert_numberstringNo-
parent_part_idUUIDNomust exist, same job, not self
current_cell_idUUIDNomust exist in cells
material_idUUIDNomust exist in materials
notesstringNo-
metadataobjectNoJSON object
file_pathsarrayNoarray of strings
GET /functions/v1/api-parts?job_id=<uuid>&status=in_progress&material=Aluminum&limit=50
ParamTypeNotes
idUUIDGet single part
job_idUUIDFilter by job
job_numberstringFilter by job number (fuzzy, requires join)
part_numberstringFuzzy match
materialstringExact match
material_lotstringExact match
statusstringnot_started, in_progress, completed
searchstringFull-text across part_number, notes
sortstringpart_number, material, status, created_at, quantity
orderstringasc or desc
limitinteger1-1000 (default 100)
offsetintegerPagination offset
PATCH /functions/v1/api-parts?id=<part-id>

Standard CRUD update. Any field except tenant_id, id, created_at.

DELETE /functions/v1/api-parts?id=<part-id>

Validation: Cannot delete if part has child parts. Operations are cascade-deleted.


Endpoint: /functions/v1/api-operations

{
"part_id": "550e8400-e29b-41d4-a716-446655440000",
"operation_name": "Welding",
"sequence": 3,
"cell_id": "550e8400-e29b-41d4-a716-446655440001",
"assigned_operator_id": "550e8400-e29b-41d4-a716-446655440002",
"estimated_time_minutes": 60,
"setup_time_minutes": 10,
"instructions": "TIG weld only, inspect after"
}
FieldTypeRequiredConstraints
part_idUUIDYesmust exist in parts
operation_namestringYes1-255 chars
sequenceintegerNo>= 1, auto-assigned if omitted
cell_idUUIDNomust exist in cells
assigned_operator_idUUIDNomust exist in profiles
estimated_time_minutesnumberNo>= 0
setup_time_minutesnumberNo>= 0
instructionsstringNomapped to notes field
statusstringNonot_started (default), in_progress, paused, completed

Note: If sequence is omitted, it is auto-calculated as max(existing) + 1.

GET /functions/v1/api-operations?part_id=<uuid>&status=in_progress&sort=sequence&order=asc
ParamTypeNotes
idUUIDGet single operation
part_idUUIDFilter by part
job_idUUIDFilter by job (finds parts first)
cell_idUUIDExact match
cell_namestringFuzzy match (requires join)
statusstringnot_started, in_progress, paused, completed
assigned_operator_idUUIDFilter by operator
operation_namestringFuzzy match
searchstringFull-text across operation_name, notes
sortstringsequence, created_at, estimated_time, actual_time, status, completion_percentage
orderstringasc or desc
limitinteger1-1000 (default 100)
offsetintegerPagination offset
PATCH /functions/v1/api-operations?id=<operation-id>
{
"status": "completed",
"completion_percentage": 100,
"notes": "Done, QA passed",
"actual_time": 45,
"cell_id": "...",
"assigned_operator_id": "..."
}

Allowed update fields: status, completion_percentage, notes, assigned_operator_id, actual_time, cell_id

Auto-behavior: Setting status to completed auto-sets completed_at timestamp.

DELETE /functions/v1/api-operations?id=<operation-id>

Validation: Cannot delete if operation has time entries.


Endpoint: /functions/v1/api-issues

{
"operation_id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Surface finish out of spec",
"description": "Ra measured 3.2, spec requires 1.6",
"severity": "high",
"status": "open"
}

POST - Create NCR (Non-Conformance Report)

Section titled “POST - Create NCR (Non-Conformance Report)”
{
"operation_id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Dimensional Out of Tolerance",
"description": "Part hole diameter measured 0.505 inch, spec is 0.500 +/- 0.002",
"severity": "high",
"issue_type": "ncr",
"ncr_category": "process",
"affected_quantity": 5,
"ncr_disposition": "rework",
"root_cause": "Tool wear - end mill exceeded replacement interval",
"corrective_action": "Replaced tool, re-machined 5 parts",
"preventive_action": "Implemented tool life tracking in system",
"verification_required": true,
"reported_by_id": "550e8400-e29b-41d4-a716-446655440002"
}
FieldTypeRequiredConstraints
operation_idUUIDYesmust exist in operations
titlestringYes1-255 chars
descriptionstringYesmin 1 char
severitystringNolow, medium, high, critical
statusstringNoopen (default), in_progress, resolved, closed
issue_typestringNogeneral (default), ncr
reported_by_idUUIDNomust exist in profiles
resolved_by_idUUIDNomust exist in profiles
verified_by_idUUIDNomust exist in profiles

NCR-specific fields (when issue_type = "ncr"):

FieldTypeRequiredConstraints
ncr_numberstringNomax 50 chars, auto-generated if omitted
ncr_categorystringNomaterial, process, equipment, design, supplier, documentation, other
ncr_dispositionstringNouse_as_is, rework, repair, scrap, return_to_supplier
root_causestringNo-
corrective_actionstringNo-
preventive_actionstringNo-
affected_quantityintegerNo-
verification_requiredbooleanNo-
GET /functions/v1/api-issues?severity=high&status=open&issue_type=ncr
ParamTypeNotes
idUUIDGet single issue
severitystringlow, medium, high, critical
statusstringopen, in_progress, resolved, closed
reported_byUUIDFilter by reporter
assigned_toUUIDFilter by assignee
job_idUUIDFilter by job
part_idUUIDFilter by part
operation_idUUIDFilter by operation
searchstringFull-text across title, description
sortstringcreated_at, severity, status, resolved_at
PATCH /functions/v1/api-issues?id=<issue-id>
{
"status": "resolved",
"resolution_notes": "Parts re-machined and verified"
}

Endpoint: /functions/v1/api-substeps

{
"operation_id": "550e8400-e29b-41d4-a716-446655440000",
"description": "Measure hole diameter with caliper",
"sequence": 1
}
FieldTypeRequiredConstraints
operation_idUUIDYesmust exist
descriptionstringYes-
sequenceintegerYes>= 1
completedbooleanNodefault false
PATCH /functions/v1/api-substeps?id=<substep-id>
{
"completed": true
}
GET /functions/v1/api-substeps?operation_id=<uuid>&completed=false
ParamTypeNotes
operation_idUUIDFilter by operation
completedbooleantrue or false
sortstringsequence, created_at, completed

Endpoint: /functions/v1/api-webhooks

{
"url": "https://your-erp.com/webhooks/eryxon",
"event_type": "job.completed",
"active": true
}
FieldTypeRequiredConstraints
urlstringYesValid URL
event_typestringYesSee webhook events list
activebooleanNodefault true

Available event types: job.created, job.started, job.stopped, job.resumed, job.completed, job.updated, part.created, part.updated, part.started, part.completed, operation.started, operation.paused, operation.resumed, operation.completed, issue.created, ncr.created, ncr.verified, step.added, step.completed

GET /functions/v1/api-webhooks?event_type=job.completed&active=true
PATCH /functions/v1/api-webhooks?id=<webhook-id>
{
"active": false
}

Endpoint: /functions/v1/api-job-lifecycle

All lifecycle operations use POST with the operation as the URL path segment.

POST /functions/v1/api-job-lifecycle/start?id=<job-id>

Precondition: Status must be not_started or on_hold Result: Status becomes in_progress, sets started_at (first time only) Webhook: job.started

POST /functions/v1/api-job-lifecycle/stop?id=<job-id>

Precondition: Status must be in_progress Result: Status becomes on_hold, sets paused_at Webhook: job.stopped

POST /functions/v1/api-job-lifecycle/complete?id=<job-id>

Precondition: Status must be in_progress Result: Status becomes completed, sets completed_at, calculates actual_duration Webhook: job.completed

POST /functions/v1/api-job-lifecycle/resume?id=<job-id>

Precondition: Status must be on_hold Result: Status becomes in_progress, sets resumed_at, clears paused_at Webhook: job.resumed

not_started ──start──> in_progress ──stop──> on_hold
│ │
│ │
complete resume
│ │
v v
completed in_progress
{
"success": false,
"error": {
"code": "INVALID_STATE_TRANSITION",
"message": "Cannot complete job with status 'not_started'. Job must be 'in_progress'."
}
}

Endpoint: /functions/v1/api-operation-lifecycle

POST /functions/v1/api-operation-lifecycle/start?id=<operation-id>&user_id=<user-id>

Precondition: Status must be not_started or on_hold Result: Status becomes in_progress, creates time entry if user_id provided Webhook: operation.started

POST /functions/v1/api-operation-lifecycle/pause?id=<operation-id>

Precondition: Status must be in_progress Result: Status becomes on_hold, ends active time entries, updates actual_time Webhook: operation.paused

POST /functions/v1/api-operation-lifecycle/resume?id=<operation-id>&user_id=<user-id>

Precondition: Status must be on_hold Result: Status becomes in_progress, creates new time entry Webhook: operation.resumed

POST /functions/v1/api-operation-lifecycle/complete?id=<operation-id>

Precondition: Status must be in_progress Result: Status becomes completed, completion_percentage set to 100, ends all time entries Webhook: operation.completed

not_started ──start──> in_progress ──pause──> on_hold
│ │
│ │
complete resume
│ │
v v
completed in_progress

Endpoint: /functions/v1/api-cells - Standard CRUD for work cells.

Endpoint: /functions/v1/api-materials - Standard CRUD for materials.

Endpoint: /functions/v1/api-resources - Standard CRUD for resources.

Endpoint: /functions/v1/api-assignments - Standard CRUD for operator assignments.

Endpoint: /functions/v1/api-time-entries - Standard CRUD for time entries.

Endpoint: /functions/v1/api-scrap-reasons - Standard CRUD for scrap reasons.

Endpoint: /functions/v1/api-templates - Standard CRUD for job templates.

Endpoint: /functions/v1/api-webhook-logs - Read-only logs of webhook deliveries.

Endpoint: /functions/v1/api-operation-quantities - Track good/scrap quantities per operation.

Endpoint: /functions/v1/api-parts-images - Manage part image attachments.

Endpoint: /functions/v1/api-upload-url - Generate pre-signed upload URLs for file storage.

Endpoint: /functions/v1/api-export - Export data in CSV/JSON format.

Endpoint: /functions/v1/api-erp-sync - Bidirectional ERP synchronization.

Endpoint: /functions/v1/api-key-generate - Generate new API keys.


Every request must include an API key:

Terminal window
# Method 1: Bearer token (recommended)
curl -H "Authorization: Bearer ery_live_xxxxxxxxxx" ...
# Method 2: X-API-Key header
curl -H "X-API-Key: ery_live_xxxxxxxxxx" ...

All list endpoints support pagination:

?limit=50&offset=100

Response includes:

{
"success": true,
"data": {
"jobs": [...],
"pagination": {
"total": 250,
"offset": 100,
"limit": 50
}
}
}
?sort=created_at&order=desc

Exact match:

?status=in_progress

Fuzzy match (for text fields like customer, job_number, part_number):

?customer=ACME

Internally uses ILIKE %value%.

?search=milling

Searches across configured search fields for the endpoint.

All errors follow this structure:

{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message",
"statusCode": 422,
"details": [...]
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "3 validation error(s) in job",
"details": [
{
"field": "job_number",
"message": "Missing required field: job_number",
"value": null,
"constraint": "NOT_NULL",
"entityType": "job",
"entityIndex": 0
}
],
"statusCode": 422
}
}
ConstraintMeaning
NOT_NULLRequired field is missing
FK_CONSTRAINTForeign key references non-existent record
FK_REQUIREDRequired foreign key is missing
UUID_FORMATInvalid UUID format
TYPE_MISMATCHWrong data type
MIN_VALUENumber below minimum
MAX_VALUENumber above maximum
MIN_LENGTHString too short / Array too few items
MAX_LENGTHString too long / Array too many items
ENUM_CONSTRAINTValue not in allowed set
DATE_FORMATInvalid date format
UNIQUE_CONSTRAINTDuplicate value
CIRCULAR_REFERENCESelf-referential foreign key

Rate limit errors include retry information:

{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"statusCode": 429,
"rateLimitInfo": {
"remaining": 0,
"resetAt": "2024-01-15T10:05:00Z",
"retryAfter": 60
}
}
}

Headers: X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After