Saltar al contenido principal

API de entidades

API REST para gestionar entidades personalizadas y sus registros.

Todos los endpoints de esta página son relativos a la URL base: https://api-eu1.joryio.com/api. Consulta el resumen de la API.

Resumen​

La API de entidades te permite mediante programación:

  • Crear y gestionar definiciones de entidad (esquemas).
  • Añadir, actualizar y eliminar registros de entidad (datos).
  • Consultar y buscar registros.
  • Gestionar campos y relaciones de entidad.

Autenticación​

Todos los endpoints requieren autenticación mediante token Bearer:

Authorization: Bearer YOUR_API_KEY

Y el contexto de espacio de trabajo mediante encabezado:

X-Workspace-Id: YOUR_WORKSPACE_ID

Definiciones de entidad​

Listar todas las entidades​

Obtiene todas las definiciones de entidad del espacio de trabajo actual.

GET /entities

Respuesta:

[
{
"id": "uuid",
"organizationId": "uuid",
"workspaceId": "uuid",
"name": "products",
"displayName": "Products",
"description": "Product catalog",
"collectionName": "entity_products",
"primaryKey": "_id",
"displayField": "name",
"settings": {
"allowDuplicates": false,
"enableAudit": true,
"enableVersioning": false,
"softDelete": true
},
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
]

Obtener una entidad por ID​

Recupera una definición de entidad concreta.

GET /entities/:entityId

Respuesta:

{
"id": "uuid",
"name": "products",
"displayName": "Products",
...
}

Crear una entidad​

Crea una definición de entidad nueva con campos.

POST /entities

Cuerpo de la solicitud:

{
"name": "products",
"displayName": "Products",
"description": "Product catalog with pricing",
"displayField": "name",
"fields": [
{
"name": "sku",
"displayName": "SKU",
"fieldType": "string",
"validation": {
"required": true,
"unique": true,
"minLength": 5,
"maxLength": 20
},
"indexed": true,
"displayOrder": 0
},
{
"name": "name",
"displayName": "Product Name",
"fieldType": "string",
"validation": {
"required": true,
"maxLength": 255
},
"displayOrder": 1
},
{
"name": "price",
"displayName": "Price",
"fieldType": "currency",
"validation": {
"required": true,
"min": 0
},
"displayOrder": 2
},
{
"name": "description",
"displayName": "Description",
"fieldType": "markdown",
"displayOrder": 3
},
{
"name": "active",
"displayName": "Active",
"fieldType": "boolean",
"validation": {
"default": true
},
"displayOrder": 4
}
],
"settings": {
"allowDuplicates": false,
"enableAudit": true,
"enableVersioning": false,
"softDelete": true
}
}

Tipos de campo:

  • string, email, phone, url
  • number, integer, currency, percentage
  • boolean
  • date, datetime
  • markdown, html, json
  • image_url, file_url

Respuesta:

{
"id": "uuid",
"name": "products",
...
}

Actualizar una entidad​

Actualiza la definición de entidad (nombre, descripción y configuración).

PUT /entities/:entityId

Cuerpo de la solicitud:

{
"displayName": "Updated Products",
"description": "Updated description",
"displayField": "sku",
"settings": {
"enableAudit": false
}
}

Eliminar una entidad​

Elimina una entidad y todos sus registros.

DELETE /entities/:entityId

Respuesta: 204 No Content

Advertencia: Esto elimina permanentemente el esquema de entidad y todos los registros.

Campos de entidad​

Listar campos​

Obtiene todos los campos de una entidad.

GET /entities/:entityId/fields

Respuesta:

[
{
"id": "uuid",
"entityDefinitionId": "uuid",
"name": "sku",
"displayName": "SKU",
"description": "Product SKU",
"fieldType": "string",
"validation": {
"required": true,
"unique": true,
"minLength": 5,
"maxLength": 20
},
"indexed": true,
"indexType": "btree",
"displayOrder": 0,
"hidden": false,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
]

Añadir un campo​

Añade un campo nuevo a una entidad.

POST /entities/:entityId/fields

Cuerpo de la solicitud:

{
"name": "category",
"displayName": "Category",
"fieldType": "string",
"validation": {
"required": false
},
"indexed": true,
"displayOrder": 5
}

Eliminar un campo​

Elimina un campo de una entidad.

DELETE /entities/:entityId/fields/:fieldId

Respuesta: 204 No Content

Advertencia: Esto elimina la definición de campo. Los datos de registros existentes no se borran, pero quedan inaccesibles.

Registros de entidad​

Listar registros​

Recupera registros de una entidad con filtrado opcional.

GET /entities/:entityId/records

Parámetros de consulta:

  • filter: objeto de filtro JSON (codificado para URL).
  • sort: objeto de orden JSON (codificado para URL).
  • limit: máximo de registros que se devolverán (predeterminado: 50).
  • offset: número de registros que se omitirán (predeterminado: 0).

Ejemplos:

# Todos los productos activos
GET /entities/ENTITY_ID/records?filter={"active":true}

# Productos ordenados por precio descendente
GET /entities/ENTITY_ID/records?sort={"price":-1}

# Resultados paginados
GET /entities/ENTITY_ID/records?limit=20&offset=40

Respuesta:

{
"data": [
{
"_id": "665f1c0a9b2e4d0012ab34cd",
"sku": "PROD-001",
"name": "Widget",
"price": 29.99,
"description": "A great widget",
"active": true,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
],
"total": 150
}

Obtener un registro por ID​

Recupera un registro concreto.

GET /entities/:entityId/records/:recordId

Respuesta:

{
"_id": "665f1c0a9b2e4d0012ab34cd",
"sku": "PROD-001",
"name": "Widget",
...
}

Crear un registro​

Añade un registro nuevo a una entidad.

POST /entities/:entityId/records

Cuerpo de la solicitud:

{
"sku": "PROD-001",
"name": "Widget",
"price": 29.99,
"description": "A great widget",
"active": true
}

Validación:

  • Los campos obligatorios deben estar presentes.
  • Los campos únicos deben ser únicos.
  • Los valores deben coincidir con los tipos de campo.
  • Se aplican las restricciones mín./máx.

Respuesta:

{
"_id": "665f1c0a9b2e4d0012ab34cd",
"sku": "PROD-001",
...
}

Actualizar un registro​

Actualiza un registro existente.

PUT /entities/:entityId/records/:recordId

Cuerpo de la solicitud:

{
"price": 34.99,
"description": "An even better widget"
}

Se admiten actualizaciones parciales: incluye solo los campos que quieras cambiar.

Eliminar un registro​

Elimina un registro de una entidad.

DELETE /entities/:entityId/records/:recordId

Respuesta: 204 No Content

Si está activada la eliminación reversible, el registro se marca como eliminado. De lo contrario, se elimina de forma permanente.

Crear registros masivamente (cuerpo de matriz)​

No hay un endpoint masivo independiente: POST /entities/:entityId/records acepta un objeto de registro único o una matriz JSON de objetos de registro, sin objeto envoltorio. El formato de matriz crea hasta 1000 registros en una solicitud.

POST /entities/:entityId/records

Parámetros de consulta:

  • triggerAlerts: define true para activar alertas de relaciones (reposición y similares) para registros que cambian en esta importación (predeterminado: false).

Cuerpo de la solicitud:

Una matriz JSON de hasta 1000 elementos; una matriz vacía o con más de 1000 devuelve 400. Cada elemento usa el mismo envoltorio data que el objeto único.

El envoltorio de cada elemento se valida individualmente: un elemento sin objeto data se informa en failed mediante su índice de matriz, nunca se acepta silenciosamente, y los elementos válidos restantes se insertan de todos modos. La validación de definición de campo (campos obligatorios, tipos, mín./máx.) se aplica a todo el lote igual que en las creaciones individuales.

[
{
"data": {
"sku": "PROD-001",
"name": "Widget A",
"price": 29.99
}
},
{
"data": {
"sku": "PROD-002",
"name": "Widget B",
"price": 39.99
}
}
]

Respuesta:

A diferencia del formato de objeto, que devuelve el registro creado, el formato de matriz devuelve un resumen agregado:

{
"processed": 2,
"inserted": 2,
"insertedIds": ["id-1", "id-2"],
"failed": []
}
CampoDescripción
processedNúmero de elementos recibidos en la matriz de solicitud.
insertedRegistros creados realmente.
insertedIdsID de los registros creados, en orden de inserción.
failedErrores de envoltorio por elemento: index (posición en la matriz de solicitud) y reason.

Búsqueda​

Buscar registros​

Búsqueda de texto completo en los campos indicados.

GET /entities/:entityId/search

Parámetros de consulta:

  • q: consulta de búsqueda (obligatoria).
  • fields: nombres de campo separados por comas en los que se buscará (opcional).
  • limit: máximo de resultados (predeterminado: 10).

Ejemplos:

# Busca en todos los campos indexados
GET /entities/ENTITY_ID/search?q=widget

# Busca en campos concretos
GET /entities/ENTITY_ID/search?q=PROD-001&fields=sku,name

# Limita resultados
GET /entities/ENTITY_ID/search?q=widget&limit=5

Respuesta:

[
{
"_id": "id",
"sku": "PROD-001",
"name": "Widget",
...
}
]

Consultas avanzadas​

Agregación​

Realiza agregaciones en los registros de entidad.

POST /entities/:entityId/aggregate

Cuerpo de la solicitud:

{
"groupBy": "category",
"aggregations": [
{
"field": "price",
"operation": "avg",
"as": "avgPrice"
},
{
"field": "price",
"operation": "sum",
"as": "totalValue"
},
{
"operation": "count",
"as": "productCount"
}
]
}

Operaciones:

  • count: contar registros.
  • sum: sumar valores.
  • avg: media de valores.
  • min: valor mínimo.
  • max: valor máximo.

Respuesta:

{
"results": [
{
"category": "Electronics",
"avgPrice": 45.99,
"totalValue": 2299.50,
"productCount": 50
},
{
"category": "Clothing",
"avgPrice": 29.99,
"totalValue": 1499.50,
"productCount": 50
}
]
}

Consultas complejas​

Ejecuta consultas complejas con sintaxis de estilo MongoDB.

POST /entities/query

Cuerpo de la solicitud:

{
"entity": "products",
"pipeline": [
{
"$match": {
"price": { "$gte": 20, "$lte": 50 },
"active": true
}
},
{
"$group": {
"_id": "$category",
"count": { "$sum": 1 },
"avgPrice": { "$avg": "$price" }
}
},
{
"$sort": { "avgPrice": -1 }
}
]
}

Operadores de filtro​

Al usar filtros, puedes utilizar operadores de consulta de MongoDB:

Comparación​

  • $eq: igual a.
  • $ne: distinto de.
  • $gt: mayor que.
  • $gte: mayor o igual que.
  • $lt: menor que.
  • $lte: menor o igual que.
  • $in: valor incluido en la matriz.
  • $nin: valor no incluido en la matriz.

Lógicos​

  • $and: AND lógico.
  • $or: OR lógico.
  • $not: NOT lógico.
  • $nor: NOR lógico.

Elemento​

  • $exists: el campo existe.
  • $type: comprobación del tipo de campo.

Cadena​

  • $regex: coincidencia de expresión regular.

Ejemplos:

// Precio entre 10 y 100
{
"price": { "$gte": 10, "$lte": 100 }
}

// Productos activos en categorías específicas
{
"active": true,
"category": { "$in": ["Electronics", "Computers"] }
}

// Condición compleja
{
"$or": [
{ "price": { "$lte": 20 } },
{ "onSale": true }
],
"active": true
}

Respuestas de error​

400 Solicitud incorrecta​

{
"statusCode": 400,
"message": "Validation failed",
"errors": [
{
"field": "price",
"message": "price must be greater than or equal to 0"
}
]
}

401 No autorizado​

{
"statusCode": 401,
"message": "Unauthorized"
}

404 No encontrado​

{
"statusCode": 404,
"message": "Entity not found"
}

409 Conflicto​

{
"statusCode": 409,
"message": "Duplicate value for unique field 'sku'"
}

Límites de frecuencia​

La API de entidades no tiene hoy límites de frecuencia fijos por endpoint. Consulta resumen de la API: límites de frecuencia para conocer el comportamiento de toda la plataforma y cómo gestionar respuestas 429.

Prácticas recomendadas​

Rendimiento​

  1. Usa índices: indexa los campos por los que filtras o buscas con frecuencia.
  2. Pagina los resultados: no recuperes todos los registros de una vez.
  3. Limita la selección de campos: recupera solo los campos que necesites.
  4. Almacena respuestas en caché: guarda en caché los datos a los que accedes con frecuencia.
  5. Agrupa operaciones: usa endpoints masivos cuando sea posible.

Calidad de datos​

  1. Valida antes de insertar: comprueba los datos del lado cliente.
  2. Gestiona errores: implementa una gestión de errores adecuada.
  3. Usa transacciones: para operaciones de varios registros.
  4. Limpia regularmente: archiva o elimina los registros antiguos.

Seguridad​

  1. Nunca expongas claves de API: mantenlas del lado servidor.
  2. Valida la entrada de usuario: sanitízala antes de enviarla a la API.
  3. Usa solo HTTPS: nunca uses HTTP.
  4. Rota las claves regularmente: actualiza las claves de API periódicamente.
  5. Implementa límites de frecuencia: también de tu lado.

Ejemplos de código​

JavaScript/Node.js​

const axios = require('axios');

const api = axios.create({
baseURL: 'https://api-eu1.joryio.com/api',
headers: {
'Authorization': `Bearer ${process.env.HIPPO_API_KEY}`,
'X-Workspace-Id': process.env.WORKSPACE_ID
}
});

// Crea una entidad
const entity = await api.post('/entities', {
name: 'products',
displayName: 'Products',
fields: [/* ... */]
});

// Crea un registro
const record = await api.post(`/entities/${entity.data.id}/records`, {
sku: 'PROD-001',
name: 'Widget',
price: 29.99
});

// Busca registros
const results = await api.get(`/entities/${entity.data.id}/search`, {
params: { q: 'widget' }
});

Python​

import requests
import os

api_key = os.getenv('HIPPO_API_KEY')
workspace_id = os.getenv('WORKSPACE_ID')

headers = {
'Authorization': f'Bearer {api_key}',
'X-Workspace-Id': workspace_id
}

# Crea una entidad
response = requests.post(
'https://api-eu1.joryio.com/api/entities',
json={
'name': 'products',
'displayName': 'Products',
'fields': [...]
},
headers=headers
)
entity = response.json()

# Crea un registro
response = requests.post(
f'https://api-eu1.joryio.com/api/entities/{entity["id"]}/records',
json={
'sku': 'PROD-001',
'name': 'Widget',
'price': 29.99
},
headers=headers
)

Relaciones y selecciones de productos​

Relaciones​

GET /entities/relationships
POST /entities/relationships

Una relación declara que un tipo de entidad apunta a otro: un pedido a un cliente, una suscripción a un plan. Declararla permite que los filtros y la personalización recorran el enlace en vez de duplicar los datos en ambos lados. type es one_to_one, many_to_one o many_to_many, y foreignKey es el campo de la entidad origen que guarda el id.

{ "from": "subscription", "to": "plan", "type": "many_to_one", "foreignKey": "planId" }

Selecciones de productos​

GET /entities/product-selections
POST /entities/product-selections
GET /entities/product-selections/:selectionId/match-count

match-count devuelve el número real de productos que la selección coincide ahora mismo ({ matchCount, cap }). La vista previa devuelve como máximo cap filas - el límite de la selección, máximo 50 - así que no puede indicar el tamaño de la coincidencia.

Una consulta guardada sobre una entidad que se resuelve en una lista de registros en el momento del envío: "los 5 primeros por ingresos en esta categoría". Los bloques de recomendación y los nodos de recorrido referencian la selección, así que el contenido se mantiene al día sin volver a redactarlo.

{
"name": "Bestsellers - outerwear",
"entityType": "product",
"filters": { "operator": "AND", "conditions": [
{ "field": "category", "operator": "equals", "value": "outerwear" }
] },
"sort": { "field": "unitsSold", "direction": "desc" },
"limit": 5
}

Documentación relacionada​