FarmaDoc API para Aliados

API publica para aliados

Integra pedidos e inventario en minutos

Esta documentacion esta pensada para ser clara y practica. Puedes consumir la API con cualquier lenguaje de programacion porque todo funciona con HTTP y JSON.

Base URL

/api/external

Formato

JSON UTF-8

Auth

Bearer Token

Flujo recomendado

  1. 1Opcional: consulta GET /api/external/status para verificar que la API está activa sin token (reduce carga si el servicio no está disponible).
  2. 2Crea tu cliente API en el panel y copia el secreto que empieza por fd_ (no la huella truncada).
  3. 3Agrega el header Authorization: Bearer TOKEN en las operaciones con datos.
  4. 4Obtén el código de compañía aliada en el panel (partner_companies.code) y envíalo como partner_company en inventario, listado de sucursales, inventario por sucursal, pedidos y órdenes de servicio.
  5. 5Consume los endpoints con JSON o query. Maneja errores 401, 403 y 422.

Autenticacion y reglas

Header requerido

Las operaciones con datos (inventario global, inventario por sucursal, sucursales, pedidos, órdenes de servicio) deben enviar token Bearer. La excepción es GET /api/external/status: no usa token ni partner_company.

Authorization: Bearer fd_tu_secreto_del_panel

Códigos de error frecuentes

  • 401 - Token ausente o invalido
  • 403 - IP no autorizada para el cliente
  • 422 - Error de validacion de campos
  • 429 - Demasiadas peticiones (p. ej. limite en GET /status)

Token correcto (evita el 401 «Token inválido o inactivo»)

  • El valor en Authorization: Bearer … debe ser el secreto en texto plano que te entrega el panel al crear o regenerar el cliente API.
  • Ese secreto siempre empieza por fd_ y tiene unos 67 caracteres (prefijo + hex).
  • No uses la «huella» que ves en la ficha del cliente (texto truncado): es solo referencia del hash guardado en el servidor.
  • No envíes los 64 caracteres hexadecimales del hash SHA-256: el servidor aplica de nuevo el hash a lo que envías; si mandas el hash como si fuera el secreto, la autenticación falla.
  • Si perdiste el secreto, pide en el panel Regenerar token y distribuye el nuevo valor por un canal seguro.

Si el servidor detecta un Bearer de 64 hex (típico error), la respuesta 401 puede incluir el campo hint con esta aclaración.

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.

GET

/api/external/status

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 Código del aliado; debe existir en partner_companies.code
active_ingredient Query string string 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
idintegerID del producto
skustring|nullSKU del producto
namestringNombre comercial
barcodestring|nullCódigo de barras
active_ingredientarray|stringPrincipio(s) activo(s) según catálogo
concentrationstring|nullConcentración
presentationstring|nullPresentación
presentation_typestring|nullTipo de presentación
sale_pricenumberPrecio de venta
requires_prescriptionbooleanRequiere fórmula
is_controlled_substancebooleanSustancia controlada
health_registration_numberstring|nullRegistro sanitario
total_available_quantitynumberSuma 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 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
idintegerID de la sucursal (usar como branch_id en otros endpoints)
codestring|nullCódigo interno (p. ej. SUC-1)
namestringNombre comercial de la sucursal
citystring|nullCiudad
statestring|nullDepartamento / estado
countrystring|nullPaís
is_headquartersbooleanIndica 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 Código del aliado; debe existir en partner_companies.code
branch_id Query string integer 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_idintegerID de la fila de inventario
product_idintegerID del producto
skustring|nullSKU
namestring|nullNombre del producto (null si el producto ya no existe)
barcodestring|nullCódigo de barras
product_category_idinteger|nullID de categoría en catálogo
product_category_namestring|nullNombre de la categoría
active_ingredientarray|nullPrincipio(s) activo(s) según catálogo
concentrationstring|nullConcentración
presentation_typestring|nullTipo de presentación
product_is_activeboolean|nullSi el producto está activo en catálogo
quantitynumberExistencias en sucursal
reserved_quantitynumberCantidad reservada
available_quantitynumberDisponible para venta (según reglas de stock negativo)
sale_pricenumberPrecio de lista en sucursal
effective_sale_unit_pricenumberPrecio unitario tras descuento % de la sucursal
discount_percentnumberDescuento % en sucursal
allow_negative_stockbooleanPermite 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_companystringCódigo del aliado; debe existir en partner_companies.code
client_idintegerDebe existir en tabla clients
itemsarrayMínimo 1 elemento
order_numberstring|nullNoSi se envía, único en orders.order_number
branch_idinteger|nullNoID de sucursal existente en branches
statusstring|nullNoEnum: pendiente, en-proceso, finalizado
convenio_typestring|nullNoEnum: particular, seguro-privado, eps, medicina-prepagada, convenio-corporativo, otro
convenio_partner_namestring|nullNoMáx. 255
convenio_referencestring|nullNoMáx. 255
convenio_notesstring|nullNoTexto libre
delivery_recipient_namestring|nullNoMáx. 255
delivery_phonestring|nullNoMáx. 40
delivery_addressstring|nullNoMáx. 255
delivery_citystring|nullNoMáx. 100
delivery_statestring|nullNoMáx. 100
delivery_notesstring|nullNoTexto libre
scheduled_delivery_atstring|nullNoFecha/hora parseable
dispatched_atstring|nullNoFecha/hora parseable
delivered_atstring|nullNoFecha/hora parseable
delivery_assigneestring|nullNoMáx. 255
notesstring|nullNoNotas del pedido

Cada elemento de items[]

Parámetro Tipo Obligatorio Validación / notas
product_idintegerDebe existir en products
quantitynumberMayor que 0
unit_pricenumber≥ 0
inventory_idinteger|nullNoDebe existir en inventories
discount_amountnumber|nullNo≥ 0
product_name_snapshotstring|nullNoMáx. 255
sku_snapshotstring|nullNoMá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_companystringCódigo del aliado; debe existir en partner_companies.code
statusstringMáx. 255 (ej. en-proceso, borrador)
prioritystringMáx. 255 (ej. media, alta)
service_typestringMáx. 255
external_referencestringMáx. 255 — referencia en el sistema del aliado
patient_namestringMáx. 255
patient_documentstringMáx. 255
patient_phonestringSolo dígitos; el servidor elimina espacios y símbolos si los envías
patient_emailstringCorreo válido, máx. 255
diagnosisstringTexto (diagnóstico o motivo)
itemsarrayMínimo 1 objeto; ver tabla siguiente

Cada elemento de items[]

Parámetro Tipo Obligatorio Validación
namestringMáx. 500 — nombre del medicamento
indicacionstringMí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
  }
}

Playground interactivo

Para GET estado no necesitas token. Para el resto, pega tu token Bearer del panel y sustituye ALDO-2026-001 por el código real de compañía aliada (partner_companies.code). Los ejemplos usan la misma URL base que esta página.