Saltar al contenido principal

Integración de control de calidad

Integre un sistema externo de QA / laboratorio con Roasthubs mediante webhooks de QC y lecturas heredadas de /api/.

Los valores id_tag de lote se generan como {primeras 3 letras del nombre de zona}-{secuencia} (p. ej. green → GRE-4, roast → ROA-12).


Flujo

Parameter recorded on lot


Target evaluated ──► lot_target_pass | lot_target_fail

▼ (all targets evaluated)
Overall QC ────────► lot_qc_pass | lot_qc_fail


Webhook POST → GET /api/lots/:id + GET /api/lots_targets?lot_id=:id
  1. Suscríbase a los cuatro eventos de QC en System → Webhooks.
  2. Al recibir la entrega, use resource_id como id del lote (confirme con data.lot_id cuando esté presente).
  3. Cargue el detalle del lote / QC con las llamadas /api/ de abajo (hoy no hay GET de lote QC en v2).
  4. Deduplique con el id del webhook; responda 2xx con rapidez.

Sobre del webhook

POST JSON, reintentos con backoff exponencial. id es la clave de idempotencia.

{
"id": 18402,
"type_id": "lot_qc_fail",
"user_id": 4,
"resource_id": 4,
"roasthubs_zone_id": 1,
"data": {}
}
CampoSignificado
idId del evento (dedupe)
type_idNombre del evento abajo
resource_idId del lote para GETs de seguimiento
roasthubs_zone_idZona del lote
dataCarga útil del evento

Eventos de QC

lot_target_pass / lot_target_fail

Se dispara cuando se evalúa un objetivo en un lote (tras POST/PUT /api/lots_parameters, o aprobación booleana).

data es la fila actualizada de lots_targets:

{
"id": 101,
"lot_id": 4,
"target_id": 7,
"target_name": "Moisture",
"parameter_id": 3,
"parameter_name": "Moisture",
"lower_bound": 10,
"upper_bound": 12.5,
"boolean_target": null,
"status": "fail",
"value": null,
"last_evaluated": "2026-09-03T10:15:02.441Z",
"created_at": "2026-09-01T08:05:11.102Z"
}

Use "pass" o "fail" en status según el evento.

La aprobación booleana masiva puede enviar en su lugar:

{ "status": "pass", "target_id": 101 }

En esa ruta resource_id puede ser el id del objetivo — prefiera data.lot_id / un GET /api/lots_targets de seguimiento si no está seguro.


lot_qc_pass / lot_qc_fail

Se dispara cuando todos los objetivos del lote han sido evaluados. Falla si algún objetivo falló (statusqc_failed).

data es el lote incluyendo lots_targets:

{
"id": 4,
"id_tag": "GRE-4",
"number": "BL-2401",
"recipe_id": 10,
"roasthubs_zone_id": 1,
"status": "qc_failed",
"datetime_qc": "2026-09-03T10:20:14.882Z",
"qc_failed": true,
"qc_note": null,
"lots_targets": [
{
"id": 101,
"lot_id": 4,
"target_id": 7,
"target_name": "Moisture",
"parameter_id": 3,
"parameter_name": "Moisture",
"lower_bound": 10,
"upper_bound": 12.5,
"status": "fail",
"last_evaluated": "2026-09-03T10:15:02.441Z"
},
{
"id": 102,
"lot_id": 4,
"target_id": 8,
"target_name": "Water activity",
"parameter_id": 5,
"parameter_name": "Water activity",
"lower_bound": 0.4,
"upper_bound": 0.6,
"status": "pass",
"last_evaluated": "2026-09-03T10:18:44.019Z"
}
]
}

En caso de aprobación, espere "status": "available_for_processing" (o un estado no-fallo sin cambios) y todos los objetivos en "pass".


APIs de lote y QC (/api/)

Se requiere sesión autenticada. Use resource_id del webhook como :id / lot_id.

MétodoEndpointPropósito
GET/api/lots/:idLote + receta + certificados + parámetros medidos
GET/api/lots_targets?lot_id=:idMatriz de objetivos autorizada
GET/api/parametersCatálogo de parámetros (cacheable)
GET/api/targetsCatálogo de especificaciones (cacheable; opcional ?product_id=)
GET/api/targets/:idUna especificación
GET/api/parameters_typesAgrupación de tipo de parámetro / zona
GET/api/recipes/:idReceta completa si el embed del lote no basta
GET/api/lots?rhz=&page=&limit=Listar / sincronizar (opcional)

Escritura de vuelta (opcional; puede volver a emitir webhooks de QC):

MétodoEndpoint
POST/api/lots_parameters
PUT/api/lots_parameters/:id
POST/api/lots/:id/approveallbooleantargets

GET /api/lots/:id

GET /api/lots/:id

Ejemplo de respuesta:

{
"data": {
"id": 4,
"id_tag": "GRE-4",
"number": "BL-2401",
"supplier_id": 3,
"roasthubs_zone_id": 1,
"unit_id": null,
"user_id": 4,
"recipe_id": 10,
"target_plant_node_id": 12,
"status": "qc_failed",
"datetime_qc": "2026-09-03T10:20:14.882Z",
"qc_failed": true,
"qc_note": null,
"erp_id": null,
"erp_url": null,
"production_id": null,
"is_processed_by_plc": false,
"is_in_warehouse": true,
"is_available_for_processing": false,
"needs_cleaning": false,
"remaining_weight_kg": 847.5,
"expected_weight_kg_input": 1000,
"actual_weight_kg_input": 998.2,
"expected_weight_kg_output": 1000,
"actual_weight_kg_output": 998.2,
"note": null,
"eudr_dds_number": null,
"created_at": "2026-09-01T08:00:03.114Z",
"updated_at": "2026-09-03T10:20:14.882Z",
"recipe": {
"id": 10,
"name": "Brazil Cerrado NY2",
"source_roasthubs_zone_id": 1,
"note": null
},
"target_plant_node": { "name": "Silo A3" },
"user": { "first_name": "Ada" },
"certificates": [{ "id": 1, "name": "Organic" }],
"parameters": [
{
"id": 3,
"name": "Moisture",
"data_type": "number",
"parameters_type_id": 1,
"unit_id": 1,
"lot_parameter": {
"id": 9001,
"value": "13.1",
"note": null,
"user_id": 4,
"created_at": "2026-09-03T10:14:55.220Z"
}
},
{
"id": 5,
"name": "Water activity",
"data_type": "number",
"parameters_type_id": 1,
"unit_id": 2,
"lot_parameter": {
"id": 9002,
"value": "0.52",
"note": null,
"user_id": 4,
"created_at": "2026-09-03T10:18:40.091Z"
}
}
]
}
}

Relacione parameters[].lot_parameter.value con los objetivos por parameter_id.


GET /api/lots_targets?lot_id=:id

GET /api/lots_targets?lot_id=:id

Ejemplo de respuesta:

{
"data": [
{
"id": 101,
"lot_id": 4,
"target_id": 7,
"target_name": "Moisture",
"parameter_id": 3,
"parameter_name": "Moisture",
"lower_bound": 10,
"upper_bound": 12.5,
"boolean_target": null,
"status": "fail",
"value": null,
"last_evaluated": "2026-09-03T10:15:02.441Z",
"created_at": "2026-09-01T08:05:11.102Z"
},
{
"id": 102,
"lot_id": 4,
"target_id": 8,
"target_name": "Water activity",
"parameter_id": 5,
"parameter_name": "Water activity",
"lower_bound": 0.4,
"upper_bound": 0.6,
"boolean_target": null,
"status": "pass",
"value": null,
"last_evaluated": "2026-09-03T10:18:44.019Z",
"created_at": "2026-09-01T08:05:11.220Z"
}
]
}

status: not_evaluated | pass | fail.


GET /api/parameters

GET /api/parameters

Ejemplo de respuesta:

{
"data": [
{
"id": 3,
"name": "Moisture",
"data_type": "number",
"parameters_type_id": 1,
"unit_id": 1,
"regex": null,
"regex_message": null,
"parameter_type": {
"id": 1,
"name": "Green intake",
"roasthubs_zone_id": 1
},
"lot_parameter": null
}
]
}

También: GET /api/parameters_types.


GET /api/targets / GET /api/targets/:id

GET /api/targets
GET /api/targets?product_id=
GET /api/targets/:id

Ejemplo de respuesta de lista:

{
"data": [
{
"id": 7,
"parameter_id": 3,
"lower_bound": 10,
"upper_bound": 12.5,
"applies_to_all_lots": false,
"removed": false,
"recipe_id": 10,
"plant_node_id": null,
"recipes_groups_id": null,
"product_id": null,
"value": null,
"parameters": {
"id": 3,
"name": "Moisture",
"data_type": "number",
"parameters_types": {
"id": 1,
"name": "Green intake",
"roasthubs_zone_id": 1
}
}
}
]
}

GET /api/recipes/:id (opcional)

GET /api/recipes/:id

Devuelve { "data": { …recipe…, "lines": [ … ] } } — úselo cuando necesite componentes / campos ERP más allá del embed del lote.


GET /api/lots (lista / sincronización opcional)

GET /api/lots?rhz=&page=&limit=&status=

Ejemplo de respuesta:

{
"meta": { "count": 12 },
"data": [
{
"id": 4,
"id_tag": "GRE-4",
"number": "BL-2401",
"status": "qc_failed",
"recipe": { "id": 10, "name": "Brazil Cerrado NY2" },
"targets_qty": 2,
"targets_qty_pass": 1,
"targets_qty_fail": 1
}
],
"parameters": []
}

Con rhz definido, parameters puede incluir filas de lots_parameters de la página.


Escribir mediciones (opcional)

POST /api/lots_parameters
Content-Type: application/json

{
"lot_id": <lot_id>,
"parameter_id": <parameter_id>,
"value": "<measured_value>",
"note": "<optional_note>",
"user_id": <user_id>
}
PUT /api/lots_parameters/:id
Content-Type: application/json

{
"value": "<measured_value>",
"note": "<optional_note>"
}
POST /api/lots/:id/approveallbooleantargets

Estos reevalúan objetivos y pueden emitir lot_target_* / lot_qc_* — gestione sus propios eventos mediante el id del webhook.


Autenticación

  • Webhooks: System → Webhooks
  • API: sesión autenticada / acceso API de la organización
  • Swagger v2 (no QC): {baseUrl}/api/v2/docs

Relacionado

  • docs/webhook-events.md
  • docs/v2-api.md