Conecta tu web con ONEXFY

Muestra el catálogo del comercio en tu sitio con precios y stock reales, y envía los pedidos directo al ERP como ventas online. Una API REST con JSON y un token por comercio.

URL basehttps://api.onexfy.com/api/public/v1

Inicio rápido

  1. El comercio entra a ONEXFY y genera un token en Perfil → Integraciones → API pública. Elige los permisos (catalog:read para leer el catálogo, orders:write para crear pedidos), la lista de precios y la bodega que verá la web.
  2. Te comparte el token. Empieza por onxapi_ y se muestra una sola vez; si se pierde, se genera otro y se revoca el anterior.
  3. Verifica que funciona con una llamada a /store:
curl
curl https://api.onexfy.com/api/public/v1/store \
  -H "X-Api-Key: onxapi_TU_TOKEN"

Si responde 200 con los datos del comercio, ya puedes leer productos y crear pedidos.

Autenticación

Envía el token en cada solicitud con el header X-Api-Key. También se acepta Authorization: Bearer onxapi_…. El token solo da acceso a los datos del comercio que lo generó.

El token va solo en tu servidorNunca lo pongas en JavaScript del navegador, en el HTML ni en una app móvil. Quien lo tenga puede leer el catálogo y crear pedidos a nombre del comercio. Haz las llamadas desde tu backend (PHP, Node, Python…) y guarda el token en una variable de entorno.
PermisoQué habilita
catalog:read/store, /categories, /products, /payment-methods
orders:writeCrear pedidos y consultarlos: POST /orders, GET /orders/{ref}

Cada token tiene asignada una lista de precios (por ejemplo, precio detal o mayorista) y opcionalmente una bodega. Los precios y el stock que devuelve la API, y los que se aplican al pedido, salen de esa configuración.

Convenciones

FormatoJSON en UTF-8. Envía Content-Type: application/json en los POST.
RespuestasLos datos vienen en data; los listados paginados añaden meta.
DineroPesos colombianos (COP), números sin separadores, IVA incluido. Ej.: 59900.
FechasISO-8601 con zona horaria. Ej.: 2026-10-22T09:30:00-05:00.
Paginación?page=2&per_page=50 (máximo 100). meta.last_page dice cuántas páginas hay.
Límite120 solicitudes por minuto por token. Al superarlo recibes 429; espera unos segundos y reintenta.

Errores

Todos los errores tienen la misma forma. Usa error.code en tu lógica; message es texto para personas y puede cambiar.

json
{
  "error": {
    "code": "invalid_items",
    "message": "Hay items que no se pueden vender.",
    "details": { "items.1": "Sin stock suficiente para 3 unidad(es)." }
  }
}
HTTPcodeQué hacer
401unauthenticated, invalid_tokenFalta el token o fue revocado. Pide uno nuevo al comercio.
403insufficient_scopeEl token no tiene el permiso de ese endpoint.
403module_disabled, account_inactiveLa API no está activa para el comercio o su cuenta está inactiva. El comercio debe contactar a ONEXFY.
404not_foundEl producto o pedido no existe (o no está publicado en el catálogo).
422validation_errorRevisa details: trae el error por campo, p. ej. customer.dni.
422invalid_itemsAlgún producto no existe, no tiene stock o le falta la variante. El pedido no se creó.
409out_of_stockEl stock se agotó justo al confirmar (otra venta al mismo tiempo). No se creó nada. Vuelve a consultar el producto antes de reintentar.
429rate_limitedEspera y reintenta.
500server_errorReintenta con la misma reference; nunca se duplica el pedido.

Conectar una tienda web

El flujo que recomendamos para una tienda con carrito:

1. Sincroniza el catálogo

Carga todo con /products una vez y guárdalo en tu base o caché. Luego, cada 5–15 minutos, pide solo lo modificado con updated_since.

2. Muestra la ficha

Usa /products/{id} para descripción, galería y variantes. Muestra sale_price tachando price cuando exista. En productos con variantes esos dos valores son "desde" (el menor de las variantes); al elegir una variante muestra su price y sale_price, que es lo que se cobra.

3. Valida antes de pagar

Antes del checkout vuelve a leer el producto: stock y precio cambian en la tienda física también.

4. Crea el pedido

Cuando el comprador confirma (o tu pasarela aprueba el pago), envía POST /orders desde tu servidor con tu número de pedido como reference.

Productos con variantes

Si type es variable, el producto tiene variantes (talla, color…). El comprador debe elegir una y en el pedido envías el variant_id (o el SKU de la variante). El stock de un producto variable es la suma de sus variantes.

Stock sin control

Si stock viene en null, el comercio no lleva inventario de ese producto (por ejemplo, combos o servicios): muéstralo como disponible y acepta el pedido. in_stock siempre te dice si se puede vender.

Qué se cobra

ONEXFY calcula el precio de cada línea con la misma regla que ves en el catálogo: sale_price si existe, si no price. No envías precios en el pedido. El total final del pedido es grand_total = productos + shipping.

GET

/store

catalog:read

Datos del comercio y de la configuración del token. Úsalo para probar la conexión y para mostrar teléfono o dirección en tu sitio.

respuesta 200
{
  "data": {
    "id": 1260,
    "name": "Tienda Ejemplo",
    "phone": "3001234567",
    "email": "ventas@tiendaejemplo.com",
    "address": "Cl 10 # 43-20",
    "city": "Medellín",
    "currency": "COP",
    "token": { "name": "Tienda web", "scopes": ["catalog:read", "orders:write"], "price_list_id": null, "storage_id": 31 }
  }
}
GET

/categories

catalog:read

Todas las categorías del comercio, ordenadas por nombre. parent_id indica la categoría padre para armar un menú en árbol.

respuesta 200
{ "data": [
  { "id": 12, "name": "Camisetas", "slug": "camisetas", "description": null, "parent_id": null },
  { "id": 15, "name": "Polos", "slug": "polos", "description": null, "parent_id": 12 }
] }
GET

/products

catalog:read

Productos que el comercio publicó en su catálogo (opción Mostrar en catálogo en ONEXFY). Un producto que no aparece aquí no se puede vender por la API.

ParámetroDescripción
pagePágina, desde 1.
per_pageResultados por página, 1 a 100. Por defecto 20.
searchBusca en nombre y SKU.
category_idSolo productos de esa categoría.
in_stocktrue para ocultar agotados.
updated_sinceSolo productos modificados desde esa fecha. Ideal para sincronizar.
sortname (defecto), -name, newest, updated.
curl
curl "https://api.onexfy.com/api/public/v1/products?category_id=12&in_stock=true&per_page=50" \
  -H "X-Api-Key: onxapi_TU_TOKEN"
respuesta 200
{
  "data": [
    {
      "id": 1532,
      "sku": "CAM-001",
      "name": "Camiseta básica",
      "slug": "camiseta-basica",
      "type": "variable",
      "price": 59900,
      "sale_price": 49900,
      "tax_rate": 19,
      "stock": 14,
      "in_stock": true,
      "image": "https://…/camiseta-basica.webp",
      "categories": [{ "id": 12, "name": "Camisetas", "slug": "camisetas" }],
      "variants_count": 3,
      "updated_at": "2026-10-21T16:02:11-05:00"
    }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 134, "last_page": 3 }
}
GET

/products/{id}

catalog:read

Detalle completo. {id} acepta el id numérico o el SKU. Además de los campos del listado trae description (puede tener HTML), short_description, barcode, unit, todas las images (la principal primero) y las variants.

respuesta 200 (extracto)
{
  "data": {
    "id": 1532,
    "name": "Camiseta básica",
    "type": "variable",
    "price": 59900,
    "sale_price": 49900,
    "images": ["https://…/frente.webp", "https://…/espalda.webp"],
    "variants": [
      { "id": 8811, "sku": "CAM-001-NEG-S", "name": "Negro / S", "price": 59900, "sale_price": 49900, "stock": 0, "in_stock": false },
      { "id": 8812, "sku": "CAM-001-NEG-M", "name": "Negro / M", "price": 59900, "sale_price": 49900, "stock": 4, "in_stock": true }
    ]
  }
}
GET

/payment-methods

catalog:read

Medios de pago que acepta POST /orders en payment_method_id. Mapea cada método de tu checkout (contra entrega, pasarela, transferencia…) a uno de estos ids una sola vez y guárdalo en tu configuración.

respuesta 200
{ "data": [
  { "id": 1000011, "name": "Contra entrega" },
  { "id": 101, "name": "Pago en línea" }
] }

Los nombres e ids de este ejemplo son ilustrativos; usa los que devuelva la API.

POST

/orders

orders:write

Crea una venta online en el ERP del comercio: descuenta inventario, registra o actualiza al cliente y queda lista para despacho y facturación.

  • Todo o nada. Si un item no existe o no tiene stock, se responde 422 invalid_items y no se crea nada.
  • Sin duplicados. reference es tu número de pedido. Si la envías otra vez recibes 200 con el pedido que ya existe. Ante un timeout o un 500, reintenta con la misma referencia. Solo se compara con pedidos que creaste por la API.
  • Pago confirmado. Envía paid: true cuando tu pasarela ya aprobó el pago; el pedido queda aprobado y pagado. Con false queda pendiente (por ejemplo, contra entrega).

Cuerpo

CampoDescripción
referenceobligatorioTu número de pedido, máx. 60 caracteres. Único por comercio.
payment_method_idobligatorioId de /payment-methods.
paidtrue si el pago ya está confirmado. Por defecto false.
shippingValor del envío cobrado al cliente. Por defecto 0.
notesObservaciones del comprador, máx. 1000 caracteres.
customer.nameobligatorioNombre completo.
customer.dniCédula o NIT, solo números. Obligatorio para compradores de Colombia.
customer.document_type_id3 Cédula (defecto), 6 NIT.
customer.phoneobligatorioCelular de contacto para la entrega.
customer.emailCorreo del comprador.
customer.addressobligatorioDirección de entrega.
customer.address_noteBarrio, apartamento, indicaciones.
customer.cityobligatorioCiudad o municipio.
customer.stateDepartamento.
customer.countryCódigo ISO de 2 letras. Por defecto CO.
itemsobligatorioDe 1 a 100 líneas. Cada una con quantity y una de: product_id, variant_id o sku.
curl -X POST https://api.onexfy.com/api/public/v1/orders \
  -H "X-Api-Key: onxapi_TU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "WEB-10045",
    "payment_method_id": 1000011,
    "paid": false,
    "shipping": 12000,
    "notes": "Entregar en portería",
    "customer": {
      "name": "Laura Gómez",
      "dni": "1036951937",
      "email": "laura@example.com",
      "phone": "3001234567",
      "address": "Cra 43A # 1-50 apto 302",
      "city": "Medellín",
      "state": "Antioquia"
    },
    "items": [
      { "product_id": 1532, "variant_id": 8812, "quantity": 2 },
      { "sku": "GORRA-AZ", "quantity": 1 }
    ]
  }'
respuesta 201
{
  "data": {
    "id": 205871,
    "reference": "WEB-10045",
    "paid": false,
    "approved": false,
    "items_total": 134700,
    "shipping": 12000,
    "grand_total": 146700,
    "subtotal": 113193,
    "tax_total": 21506.67,
    "payment_method": { "id": 1000011, "name": "Contra entrega" },
    "invoice_number": null,
    "tracking_number": null,
    "customer": { "name": "Laura Gómez", "dni": "1036951937", "email": "laura@example.com", "phone": "3001234567" },
    "items": [
      { "product_id": 1532, "variant_id": 8812, "sku": "CAM-001-NEG-M", "name": "Camiseta básica Negro / M", "quantity": 2, "unit_price": 59900, "total": 119800 },
      { "product_id": 1610, "variant_id": null, "sku": "GORRA-AZ", "name": "Gorra azul", "quantity": 1, "unit_price": 14900, "total": 14900 }
    ],
    "created_at": "2026-10-22T10:14:03-05:00"
  }
}
GET

/orders/{reference}

orders:write

Consulta un pedido creado por la API con tu misma reference. Devuelve la misma estructura que la creación. Úsalo para mostrar al comprador el estado: paid, invoice_number cuando se factura y tracking_number cuando se despacha con guía.

curl
curl https://api.onexfy.com/api/public/v1/orders/WEB-10045 \
  -H "X-Api-Key: onxapi_TU_TOKEN"

Para no exceder el límite, consulta el estado cuando el comprador lo pida o como máximo cada pocos minutos por pedido abierto.