Prefijo común: /api/external. En inventario (global y por sucursal), listado de sucursales, pedidos y órdenes de servicio debes enviar partner_company (código en partner_companies.code). El inventario por sucursal además requiere branch_id (id numérico de una sucursal activa). Excepción: GET /status no lleva token ni partner_company. POST: cuerpo JSON con Content-Type: application/json. Errores 422: cuerpo con message y errors (objeto por campo).
Endpoints disponibles
Los nombres de parámetros coinciden con la validación del servidor (Laravel FormRequest). Usa las tablas como referencia al armar tu integración.
Estado / salud
Comprueba en tiempo real si la API de integración está activa. Úsalo antes de reintentos o para monitoreo liviano: no requiere token Bearer ni partner_company, así reduces tráfico innecesario a los endpoints que sí consultan base de datos.
- HTTP 200 y
"status": "active" → servicio operativo.
- Si no obtienes respuesta o hay error de red, evita spamear inventario/pedidos hasta recuperar conectividad.
- Límite: hasta 120 peticiones por minuto por IP (HTTP 429 si te excedes).
Respuesta HTTP 200 — ejemplo
{
"status": "active",
"api": "external",
"message": "La API de integración para aliados está operativa.",
"checked_at": "2026-03-24T18:30:00+00:00",
"app": "Farmadoc"
}
Ejemplo: curl -sS "https://farmasysdoc.farmadoc.net/api/external/status"
GET
/api/external/inventory
Inventario
Lista productos tipo medicamento activos cuyo arreglo de principio(s) activo(s) contiene el término buscado (búsqueda parcial, sin distinguir mayúsculas). Suma el inventario disponible entre sucursales.
| Parámetro |
Dónde |
Tipo |
Obligatorio |
Reglas / notas |
| partner_company |
Query string |
string |
Sí |
Código del aliado; debe existir en partner_companies.code |
| active_ingredient |
Query string |
string |
Sí |
Mínimo 2 caracteres, máximo 2000. Ejemplo: ?partner_company=ALDO-2026-001&active_ingredient=paracetamol |
Ejemplo URL completa: GET /api/external/inventory?partner_company=ALDO-2026-001&active_ingredient=paracetamol
Campos en cada elemento de data[]
| Campo |
Tipo |
Descripción |
| id | integer | ID del producto |
| sku | string|null | SKU del producto |
| name | string | Nombre comercial |
| barcode | string|null | Código de barras |
| active_ingredient | array|string | Principio(s) activo(s) según catálogo |
| concentration | string|null | Concentración |
| presentation | string|null | Presentación |
| presentation_type | string|null | Tipo de presentación |
| sale_price | number | Precio de venta |
| requires_prescription | boolean | Requiere fórmula |
| is_controlled_substance | boolean | Sustancia controlada |
| health_registration_number | string|null | Registro sanitario |
| total_available_quantity | number | Suma de cantidad disponible en inventarios |
Respuesta HTTP 200 — cuerpo de ejemplo
{
"data": [
{
"id": 15,
"sku": "MED-500-A",
"name": "Acetaminofen 500 mg",
"barcode": "001234",
"active_ingredient": ["Paracetamol"],
"concentration": "500 mg",
"presentation": "Tableta",
"presentation_type": "Tableta",
"sale_price": 1200.5,
"requires_prescription": false,
"is_controlled_substance": false,
"health_registration_number": null,
"total_available_quantity": 90
}
]
}
GET
/api/external/branches
Sucursales
Lista las sucursales activas registradas en el sistema (identificador, código interno, nombre y ubicación básica). Úsalo para obtener branch_id antes de consultar inventario por sucursal.
| Parámetro |
Dónde |
Tipo |
Obligatorio |
Reglas / notas |
| partner_company |
Query string |
string |
Sí |
Código del aliado; debe existir en partner_companies.code |
Ejemplo: GET /api/external/branches?partner_company=ALDO-2026-001
Campos en cada elemento de data[]
| Campo |
Tipo |
Descripción |
| id | integer | ID de la sucursal (usar como branch_id en otros endpoints) |
| code | string|null | Código interno (p. ej. SUC-1) |
| name | string | Nombre comercial de la sucursal |
| city | string|null | Ciudad |
| state | string|null | Departamento / estado |
| country | string|null | País |
| is_headquarters | boolean | Indica si es sede principal |
Respuesta HTTP 200 — ejemplo
{
"data": [
{
"id": 1,
"code": "SUC-1",
"name": "Farmacia Centro",
"city": "Bogotá",
"state": "Cundinamarca",
"country": "CO",
"is_headquarters": true
}
]
}
GET
/api/external/inventory-by-branch
Inventario / sucursal
Devuelve todas las filas de inventario de una sucursal concreta (existencias, reservado, precios e impuestos a nivel sucursal) y datos del producto asociado. La sucursal debe estar activa.
| Parámetro |
Dónde |
Tipo |
Obligatorio |
Reglas / notas |
| partner_company |
Query string |
string |
Sí |
Código del aliado; debe existir en partner_companies.code |
| branch_id |
Query string |
integer |
Sí |
ID de sucursal activa (p. ej. obtenido con GET /branches) |
Ejemplo: GET /api/external/inventory-by-branch?partner_company=ALDO-2026-001&branch_id=1
Objeto branch (cabecera)
id, code, name, city, state, country.
Campos en cada elemento de data[]
| Campo |
Tipo |
Descripción |
| inventory_id | integer | ID de la fila de inventario |
| product_id | integer | ID del producto |
| sku | string|null | SKU |
| name | string|null | Nombre del producto (null si el producto ya no existe) |
| barcode | string|null | Código de barras |
| product_category_id | integer|null | ID de categoría en catálogo |
| product_category_name | string|null | Nombre de la categoría |
| active_ingredient | array|null | Principio(s) activo(s) según catálogo |
| concentration | string|null | Concentración |
| presentation_type | string|null | Tipo de presentación |
| product_is_active | boolean|null | Si el producto está activo en catálogo |
| quantity | number | Existencias en sucursal |
| reserved_quantity | number | Cantidad reservada |
| available_quantity | number | Disponible para venta (según reglas de stock negativo) |
| sale_price | number | Precio de lista en sucursal |
| effective_sale_unit_price | number | Precio unitario tras descuento % de la sucursal |
| discount_percent | number | Descuento % en sucursal |
| allow_negative_stock | boolean | Permite saldo negativo en esta fila |
Respuesta HTTP 200 — ejemplo (fragmento)
{
"branch": {
"id": 1,
"code": "SUC-1",
"name": "Farmacia Centro",
"city": "Bogotá",
"state": "Cundinamarca",
"country": "CO"
},
"data": [
{
"inventory_id": 10,
"product_id": 15,
"sku": "MED-500-A",
"name": "Acetaminofen 500 mg",
"barcode": "001234",
"product_category_id": 3,
"product_category_name": "Medicamentos",
"active_ingredient": ["Paracetamol"],
"concentration": "500 mg",
"presentation_type": "Tableta",
"product_is_active": true,
"quantity": 100,
"reserved_quantity": 5,
"available_quantity": 95,
"sale_price": 1200.5,
"effective_sale_unit_price": 1140.48,
"discount_percent": 5,
"allow_negative_stock": false
}
]
}
POST
/api/external/orders
Pedidos
Crea un pedido de venta con líneas de producto, precios y descuentos por línea. El servidor recalcula subtotales y totales (sin IVA por línea; tax_total queda en 0).
Cuerpo JSON — campos raíz
| Parámetro |
Tipo |
Obligatorio |
Validación / notas |
| partner_company | string | Sí | Código del aliado; debe existir en partner_companies.code |
| client_id | integer | Sí | Debe existir en tabla clients |
| items | array | Sí | Mínimo 1 elemento |
| order_number | string|null | No | Si se envía, único en orders.order_number |
| branch_id | integer|null | No | ID de sucursal existente en branches |
| status | string|null | No | Enum: pendiente, en-proceso, finalizado |
| convenio_type | string|null | No | Enum: particular, seguro-privado, eps, medicina-prepagada, convenio-corporativo, otro |
| convenio_partner_name | string|null | No | Máx. 255 |
| convenio_reference | string|null | No | Máx. 255 |
| convenio_notes | string|null | No | Texto libre |
| delivery_recipient_name | string|null | No | Máx. 255 |
| delivery_phone | string|null | No | Máx. 40 |
| delivery_address | string|null | No | Máx. 255 |
| delivery_city | string|null | No | Máx. 100 |
| delivery_state | string|null | No | Máx. 100 |
| delivery_notes | string|null | No | Texto libre |
| scheduled_delivery_at | string|null | No | Fecha/hora parseable |
| dispatched_at | string|null | No | Fecha/hora parseable |
| delivered_at | string|null | No | Fecha/hora parseable |
| delivery_assignee | string|null | No | Máx. 255 |
| notes | string|null | No | Notas del pedido |
Cada elemento de items[]
| Parámetro |
Tipo |
Obligatorio |
Validación / notas |
| product_id | integer | Sí | Debe existir en products |
| quantity | number | Sí | Mayor que 0 |
| unit_price | number | Sí | ≥ 0 |
| inventory_id | integer|null | No | Debe existir en inventories |
| discount_amount | number|null | No | ≥ 0 |
| product_name_snapshot | string|null | No | Máx. 255 |
| sku_snapshot | string|null | No | Máx. 255 |
Respuesta HTTP 201 — ejemplo
{
"message": "Pedido creado correctamente.",
"data": {
"order_id": 1002,
"order_number": "EXT-20260322123000-4321",
"partner_company": "ALDO-2026-001",
"status": "pendiente",
"items_count": 1,
"subtotal": 24000,
"tax_total": 0,
"discount_total": 0,
"total": 24000
}
}
POST
/api/external/service-orders
Orden de servicio
Registra una orden de servicio para un paciente y medicamentos con indicaciones. La fecha de emisión ordered_at la asigna el servidor al crear el registro (no se envía en el JSON).
| Parámetro |
Tipo |
Obligatorio |
Validación / notas |
| partner_company | string | Sí | Código del aliado; debe existir en partner_companies.code |
| status | string | Sí | Máx. 255 (ej. en-proceso, borrador) |
| priority | string | Sí | Máx. 255 (ej. media, alta) |
| service_type | string | Sí | Máx. 255 |
| external_reference | string | Sí | Máx. 255 — referencia en el sistema del aliado |
| patient_name | string | Sí | Máx. 255 |
| patient_document | string | Sí | Máx. 255 |
| patient_phone | string | Sí | Solo dígitos; el servidor elimina espacios y símbolos si los envías |
| patient_email | string | Sí | Correo válido, máx. 255 |
| diagnosis | string | Sí | Texto (diagnóstico o motivo) |
| items | array | Sí | Mínimo 1 objeto; ver tabla siguiente |
Cada elemento de items[]
| Parámetro |
Tipo |
Obligatorio |
Validación |
| name | string | Sí | Máx. 500 — nombre del medicamento |
| indicacion | string | Sí | Mínimo 1 carácter — posología / indicaciones |
Respuesta HTTP 201 — ejemplo
{
"message": "Orden de servicio registrada correctamente.",
"data": {
"order_service_id": 42,
"service_order_number": "ORD-0042",
"partner_company_code": "ALDO-2026-001",
"status": "en-proceso",
"priority": "media",
"ordered_at": "2026-03-24T15:30:00-05:00",
"items_count": 1
}
}