Ir al contenido principal

API · v1

ez-recommendations API

Base URL: https://api.ez-recommendations.huggian.com

Quick start

Tres pasos: provisioná una key, emití una venta, consultá recomendaciones.

# 1. emitir venta
curl -X POST https://api.ez-recommendations.huggian.com/v1/ingest/sale \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "00000000-0000-0000-0000-000000000001",
    "sale_id":   "f0a1...-...",
    "items":     ["aaaa-...","bbbb-...","cccc-..."]
  }'

# 2. consultar recomendaciones
curl -X POST https://api.ez-recommendations.huggian.com/v1/recommendations \
  -H "X-API-Key: $KEY" \
  -d '{"basket":["aaaa-..."],"available":["bbbb-...","dddd-..."],"limit":5}'

Autenticación

Header X-API-Key: <plaintext>. Hash de servidor con argon2id; el prefijo de 8 chars indexa el lookup.

Header X-Admin-Reason requerido para cualquier PUT /v1/admin/* — queda en el audit log.

Scopes

ScopeEndpoints
ingestPOST /v1/ingest/sale, POST /v1/ingest/reversal
readPOST /v1/recommendations, /by-category
stockingPOST /v1/stocking-suggestions
adminGET/PUT /v1/admin/*

Tiers y quotas

Tier Ingest/mes Read/mes Stocking/mes Rate/min
free5001001030
basic50.000150.0005.000600
pro500.0001.500.00050.0002.500
enterprise15.000

Quota mensual reset el 1ro de cada mes UTC. Rate limit token-bucket por X-API-Key.

Pre-requisito: ez-recommendations corre por encima de ez-catalog para resolver UUIDs canónicos de productos. Plan Basic de ez-catalog (o superior) es requerido para todos los planes pagos de ez-recommendations.

Errores

RFC 7807 application/problem+json.

{
  "type":   "about:blank",
  "title":  "Validation Failed",
  "status": 400,
  "detail": "basket size 200 exceeds max_basket_size 50"
}

POST /v1/ingest/sale [scope: ingest]

Idempotente: duplicado (api_key_id, sale_id, kind='sale') retorna 409.

{
  "tenant_id": "uuid",
  "sale_id":   "uuid",
  "items":     ["ez-catalog-uuid", ...]    // 2..=100
}
→ 202 Accepted { "outbox_id": 1234 }

POST /v1/ingest/reversal [scope: ingest]

Devuelve 422 Unprocessable si no existe un sale previamente procesado para el mismo (api_key_id, sale_id). Forgery-safe: usa los items ORIGINALES, ignora los que mandás.

POST /v1/recommendations [scope: read]

{
  "basket":    ["uuid", ...],
  "available": ["uuid", ...],
  "limit":     10
}
→ 200 OK
{
  "items": [{ "product_id": "uuid", "score": 0.42 }],
  "k_anon_satisfied": true,
  "cohort_size": 47
}

k_anon_satisfied: false ⟹ cohort gate todavía no clear. UI debe ocultar el rail o caer a un fallback (brand-siblings, trending) hasta que la red crezca.

POST /v1/recommendations/by-category [scope: read]

Returns groups[] en lugar de items[]. Cada grupo es una categoría con hasta limit_per_cat productos. Useful para rails diversificados.

{
  "basket":        ["uuid", ...],
  "available":     ["uuid", ...],
  "limit_per_cat": 3,                // default
  "max_cats":      5                 // default
}

POST /v1/stocking-suggestions [scope: stocking]

Productos NO en current_inventory que se co-compran con reference. "Considerá stockear esto" — dashboard de owner.

{
  "reference":         ["uuid", ...],   // optional
  "current_inventory": ["uuid", ...],
  "limit":             20
}

Endpoints admin [scope: admin]

  • GET /v1/admin/config
  • PUT /v1/admin/config # header X-Admin-Reason
  • GET /v1/admin/metrics
  • GET /v1/admin/usage?api_key_id=<uuid>

GET /v1/health [no auth]

Liveness probe simple para orchestrators. Devuelve { "db": "ok" }.