Skip to content

Productos

CRUD sobre los productos de tu catálogo (servicios, productos simples, con variantes, compuestos). Todas las requests requieren Authorization: Bearer finova_sk_<secret>.

El objeto Product

json
{
  "id":                "65a0c0f1234567890abcdef0",
  "name":              "Lentes oftálmicos premium",
  "slug":              "lentes-oftalmicos-premium",
  "sku":               "LEN-PREM-001",
  "description":       "Lentes graduados con armazón de titanio.",
  "product_type":      "simple",
  "is_active":         true,
  "tags":              ["lentes", "premium"],
  "category_name":     "Lentes",
  "product_category": {
    "id":   "65c2b2c234567890abcdef22",
    "name": "Lentes",
    "slug": "lentes"
  },
  "brand": {
    "id":   "65b1a1b234567890abcdef00",
    "name": "Polaroid",
    "slug": "polaroid"
  },
  "gtin":              "0049000028911",
  "mpn":               "POL-PREM-12345",
  "condition":         "new",
  "prices_cents":      { "mxn": 450000, "usd": 25000 },
  "inventory_enabled": false,
  "inventory_mode":    "materials",
  "taxable":           true,
  "tax_rate_percent":  16.0,
  "image_url":         "https://cdn.fi-nova.com/cdn/products/65a0…/image?exp=…&sig=…",
  "thumbnail_url":     "https://cdn.fi-nova.com/cdn/products/65a0…/image?exp=…&sig=…",
  "images": [
    { "url": "https://cdn.fi-nova.com/cdn/products/65a0…/image?exp=…&sig=…", "alt": "Lentes oftálmicos premium", "position": 0 },
    { "url": "https://cdn.fi-nova.com/…/1.jpg", "alt": "Vista lateral", "position": 1 }
  ],
  "material":    "Titanio",
  "graduado":    true,
  "voltaje":     110,
  "colores":     ["rojo", "azul"],
  "dimensiones": { "alto_mm": 40, "ancho_mm": 140 },
  "ficha_tecnica": { "asset_id": "65e…", "url": "https://cdn.fi-nova.com/…/ficha.pdf", "name": "Ficha técnica", "content_type": "application/pdf" },
  "seo": {
    "seo_title":               "Lentes oftálmicos premium — Óptica XYZ",
    "seo_title_translations":  { "es": "Lentes oftálmicos premium — Óptica XYZ", "en": "Premium prescription glasses — XYZ Optics" },
    "meta_description":              "Lentes premium con armazón de titanio. Envío gratis.",
    "meta_description_translations": { "es": "Lentes premium…", "en": "Premium glasses…" },
    "meta_keywords":              "lentes, premium, titanio",
    "meta_keywords_translations": { "es": "lentes, premium", "en": "glasses, premium" },
    "short_description":              "Resumen breve para listados.",
    "short_description_translations": { "es": "Resumen breve…", "en": "Short summary…" },
    "description":              "<p>Contenido HTML largo…</p>",
    "description_translations": { "es": "<p>…</p>", "en": "<p>…</p>" },
    "og_title":               "Lentes premium",
    "og_title_translations":  { "es": "Lentes premium", "en": "Premium glasses" },
    "og_description":              "Compártelos en redes sociales.",
    "og_description_translations": { "es": "Compártelos…", "en": "Share them…" },
    "indexable": true,
    "og_image":  { "url": "https://cdn.fi-nova.com/…/og.jpg", "alt_translations": { "es": "Lentes premium" } },
    "banner":    { "url": "https://cdn.fi-nova.com/…/banner.jpg" },
    "video":     { "url": "https://cdn.fi-nova.com/…/spot.mp4", "content_type": "video/mp4" },
    "gallery":   [{ "url": "https://cdn.fi-nova.com/…/1.jpg", "alt_translations": {} }],
    "og_image_url": "https://cdn.fi-nova.com/…/og.jpg",
    "banner_url":   "https://cdn.fi-nova.com/…/banner.jpg",
    "gallery_urls": ["https://cdn.fi-nova.com/…/1.jpg"]
  },
  "variants": [
    {
      "id":          "65c2d2c345678901abcdef00",
      "name":         "Armazón rojo / Talla M",
      "sku":          "LEN-PREM-R-M",
      "prices_cents": { "mxn": 470000 },
      "is_active":    true,
      "options":     { "color": "red", "size": "M" },
      "image_url":   "https://cdn.fi-nova.com/cdn/products/65a0…/variants/65c2…/image?exp=…&sig=…"
    }
  ],
  "option_types": [
    {
      "name": "color", "presentation": "Color", "position": 1,
      "values": [
        { "name": "Rojo", "value": "red", "presentation": "Rojo", "position": 1, "extra_price_cents": 0 }
      ]
    }
  ],
  "components": [
    { "id": "65c2…", "name": "Estuche rígido", "component_product_id": "65aa…", "quantity": 1, "is_required": true, "extra_prices_cents": { "mxn": 0 } }
  ],
  "inventory": {
    "enabled":       true,
    "unit":          "pcs",
    "on_hand_qty":   "120.0",
    "reserved_qty":  "8.0",
    "available_qty": "112.0",
    "by_location": [
      {
        "warehouse_id":   "65d0…", "warehouse_name": "Bodega Central",
        "rack_id":        "65d1…", "rack_name":      "A-12",
        "on_hand_qty":    "120.0", "reserved_qty":   "8.0", "available_qty": "112.0"
      }
    ]
  },
  "created_at":        "2026-01-15T14:23:11Z",
  "updated_at":        "2026-05-14T09:01:42Z"
}

Lista vs detalle

variants, option_types, components e inventory solo se incluyen en GET /products/:id (detalle). El listado (GET /products) omite estos campos para mantener cada fila ligera, pero sí incluye image_url, thumbnail_url e images.

URLs de imagen firmadas

image_url, thumbnail_url, las URLs en images[] y variants[].image_url son URLs firmadas de corta duración (HMAC + expiración). No las guardes de forma permanente: vuelve a leer el producto para obtener URLs frescas. thumbnail_url apunta a la imagen completa (no se genera un derivado); redimensiona del lado de tu sitio.

Campos

CampoTipoDescripción
idstringObjectId.
namestringNombre comercial.
slugstringIdentificador amigable opcional. Define la URL pública del producto en tu sitio.
skustringSKU principal (para simple / service).
descriptionstringDescripción libre (no localizada). Para el contenido SEO localizado usa seo.description.
product_typeenumsimple, service, variable, composite.
is_activeboolSi está visible/comprable.
tagsstring[]Etiquetas libres.
category_namestring(deprecado, pero presente) Nombre de la categoría de catálogo (denormalizado). Usa product_category para la referencia estructurada.
product_categoryobject{ id, name, slug } — referencia denormalizada a la categoría de catálogo. Edita la categoría completa en /product-categories. Ver Categorías de producto. No confundir con la categoría financiera de ingresos/egresos.
brandobject{ id, name, slug } — referencia denormalizada. Edita la marca completa en /brands.
gtinstringGTIN / EAN / UPC / ISBN (8, 12, 13 o 14 dígitos). Útil para Google Merchant.
mpnstringManufacturer Part Number.
conditionenumnew, used, refurbished, damaged. Default new.
prices_centsobjectMapa multi-moneda { <iso4217_lowercase>: <centavos> }, ej. { "mxn": 450000, "usd": 25000 }. Reemplaza a los antiguos currency/price_cents escalares.
inventory_enabledboolSi lleva control de inventario.
inventory_modeenummaterials, self, hybrid.
taxableboolSi causa impuesto.
tax_rate_percentfloatTasa de impuesto (ej. 16.0).
image_urlstring | nullURL firmada de la imagen principal. null si no hay imagen.
thumbnail_urlstring | nullIgual que image_url (no se genera un derivado; redimensiona en tu sitio).
imagesobject[]Galería plana: { url, alt, position }. La imagen principal va en position: 0, seguida de la galería SEO.
(campos personalizados)anyCada campo personalizado se devuelve aplanado como una clave de primer nivel del producto (ej. "voltaje": 110), no dentro de un array custom_properties. Ver Campos personalizados.
seoobjectContenido localizado + multimedia para tu sitio público. Ver El objeto SEO.
variantsobject[](solo detalle) Variantes del producto. Ver Variantes, opciones y componentes.
option_typesobject[](solo detalle) Tipos de opción (ej. color, talla) y sus valores.
componentsobject[](solo detalle) Componentes de un producto composite.
inventoryobject | null(solo detalle) Disponibilidad: total y desglose por almacén/rack. null si el producto no lleva inventario. Nunca incluye costos.
created_at / updated_atstringISO 8601 UTC.

Datos no expuestos. Por privacidad, el API público nunca devuelve cifras de venta (sold_units, sold_amount), costos fijos (fixed_costs) ni la lista de materiales/costos (material_requirements). El objeto inventory expone solo cantidades disponibles, no valores monetarios.

El objeto SEO

Anidado bajo seo. Diseñado para alimentar el <head> y el cuerpo de la página pública del producto en tu sitio.

CampoTipoDescripción
seo_titlestringSEO title resuelto al locale actual.
seo_title_translationsobject{ "es": "…", "en": "…" }.
meta_description / _translationsstring / objectMeta description para buscadores.
meta_keywords / _translationsstring / objectKeywords (legacy SEO, opcional).
short_description / _translationsstring / objectResumen corto para listados.
description / _translationsstring / objectContenido largo (HTML permitido).
og_title / _translationsstring / objectOpen Graph title para redes sociales.
og_description / _translationsstring / objectOpen Graph description.
indexableboolfalse → emite <meta name="robots" content="noindex,nofollow">.
og_imageobject{ asset_id, url, name, content_type, size_bytes, file_filename, alt_translations }.
bannerobjectMismo shape que og_image.
videoobjectMismo shape que og_image. Útil para schema.org/Product.video.
galleryobject[]Array con el mismo shape que og_image.
og_image_url / banner_url / gallery_urlsstring / string[]Legacy URL-only. Espejos del campo enriquecido — preferí los objetos.

Al escribir vía POST o PATCH, pasa el objeto seo como hijo de data. Los campos localizados se escriben vía *_translations (un hash { locale: valor }). Pasar null/string vacío en una traducción borra esa entrada.

Campos personalizados (specs)

Los campos personalizados son atributos estructurados definidos por el usuario — pensados para la tabla de "Especificaciones técnicas" de la ficha del producto (dimensiones, material, voltaje, etc.).

En la lectura se devuelven aplanados: cada campo aparece como una clave de primer nivel del producto, con su valor directo.

json
{
  "id": "65a0…",
  "name": "Lentes oftálmicos premium",
  "voltaje": 110,
  "material": "Titanio",
  "colores": ["rojo", "azul"],
  "ficha_tecnica": { "asset_id": "65e…", "url": "https://…/ficha.pdf", "name": "Ficha técnica" }
}

Claves reservadas

La key es un identificador estilo variable (minúsculas, números y guion bajo; sin espacios ni acentos). Si una clave personalizada coincide con un campo propio del recurso (id, name, slug, sku, prices_cents, seo, brand, …) se descarta al serializar: un campo personalizado nunca puede sobrescribir ni duplicar un campo real. Elige claves propias (ej. voltaje_maximo, material_marco).

En la escritura se pasan como el array custom_properties dentro de data. Cada entrada lleva:

CampoTipoDescripción
keystringRequerido. Identificador del atributo. Las entradas con key vacío se descartan.
typeenumCómo interpretar value (ver abajo). Si se omite, se infiere del value.
valueanyEl dato; su forma depende de type.

Tipos (type) y la forma de value:

typevalue
stringTexto.
numberEntero o decimal.
booleantrue / false.
arrayLista de escalares (["rojo", "azul"]).
objectObjeto JSON ({ "alto_mm": 40 }).
object_arrayLista de objetos.
fileUn media item: { asset_id, url, name, content_type, size_bytes, file_filename, alt_translations } — mismo shape que la multimedia de SEO.
file_arrayLista de media items.

Es reemplazo completo: el array que mandas sustituye al anterior; un array vacío [] los borra; omitir la clave los deja intactos. Los valores se sanitizan en el servidor (estructuras anidadas se limpian a JSON seguro; máximo 200 propiedades).

json
{
  "data": {
    "custom_properties": [
      { "key": "material", "type": "string", "value": "Titanio" },
      { "key": "voltaje", "type": "number", "value": 110 },
      { "key": "ficha_tecnica", "type": "file", "value": { "asset_id": "65e…", "url": "https://…/ficha.pdf", "name": "Ficha técnica" } }
    ]
  }
}

Variantes, opciones y componentes

Estas colecciones se leen en el detalle del producto y se escriben (crear/actualizar) anidadas dentro de data, con semántica de nested attributes:

  • Crear un item: inclúyelo sin id.
  • Actualizar un item existente: inclúyelo con su id (los demás items no enviados quedan intactos).
  • Eliminar un item: envíalo con { "id": "…", "_destroy": true }.

Los id se preservan entre actualizaciones, por lo que la imagen de una variante (ligada a su id) sobrevive a las ediciones.

variants (para product_type: "variable")

CampoTipoDescripción
idstringOmitir para crear.
namestringNombre de la variante.
skustringSKU de la variante.
prices_centsobjectMapa multi-moneda { <iso4217>: <centavos> }. Si se omite (o falta una moneda), hereda el precio del producto en esa moneda.
is_activeboolVisibilidad.
optionsobjectMapa { tipo: valor }, ej. { "color": "red", "size": "M" }.
image_urlstring(solo lectura) Súbela con el endpoint de imagen de variante.

option_types

CampoTipoDescripción
namestringClave interna (ej. color).
presentationstringEtiqueta para UI (ej. Color).
positionintegerOrden.
valuesobject[]{ id?, name, value, presentation, position, extra_price_cents, _destroy? }.

components (para product_type: "composite")

CampoTipoDescripción
idstringOmitir para crear.
namestringNombre del componente.
component_product_idstringProducto referenciado (opcional).
quantityintegerCantidad incluida.
is_requiredboolSi es obligatorio.
extra_prices_centsobjectMapa multi-moneda { <iso4217>: <centavos> } con el ajuste de precio del componente.
json
{
  "data": {
    "name": "Playera premium",
    "product_type": "variable",
    "prices_cents": { "mxn": 30000 },
    "option_types": [
      { "name": "color", "presentation": "Color", "position": 1,
        "values": [{ "name": "Rojo", "value": "red", "presentation": "Rojo", "position": 1 }] }
    ],
    "variants": [
      { "name": "Rojo / M", "sku": "PLY-R-M", "prices_cents": { "mxn": 32000 }, "options": { "color": "red", "size": "M" } }
    ]
  }
}

Listar productos

GET/api/v1/productsread-products

Lista paginada de los productos de tu empresa. Ordenada por created_at descendente (más nuevos primero). Para catálogos grandes (≥ 5 000 productos) usa cursores; ver la guía de paginación para detalles.

Query params

ParamDefaultDetalle
limit25Items por página (máx 100).
search (alias q)Búsqueda full-text/autocomplete sobre name, slug, sku y description. Devuelve hasta los 100 resultados más relevantes, luego paginados.
brand (alias brand_id)Filtra por marca. Un solo valor o lista separada por comas mezclando ObjectIds y slugs (ej. acme,5f...). Trae los productos de cualquiera de las marcas listadas. Slugs matchean el snapshot denormalizado del producto (sin lookup extra). Un id/slug desconocido no aporta resultados.
category (alias product_category_id)Filtra por categoría de catálogo. Un solo valor o lista separada por comas de ObjectIds y/o slugs (ej. comida,bebidas). Trae los productos de cualquiera de las categorías listadas. El filtro es jerárquico: filtrar por una categoría padre también trae los productos asignados a cualquiera de sus subcategorías (a cualquier profundidad); filtrar por una subcategoría no trae los productos del padre. Ej.: si el producto A está en 1.1 (hija de 1), category=1 y category=1.1 traen A; pero un producto B en 1 no aparece con category=1.1. Un id/slug desconocido no aporta resultados.
activetrueFiltra por visibilidad pública. Por default solo trae productos activos (is_active: true). active=false trae solo los inactivos; active=all trae ambos. Cualquier otro valor equivale al default (solo activos).
starting_afterCursor — id del último item de la página previa.
ending_beforeCursor — id del primer item de la página previa (retrocede).
include_totalfalseSi es true, agrega total y total_pages a meta. Cuenta todo el catálogo, ignora los filtros (costo extra).
include_filtered_totalfalseSi es true, agrega filtered_total y filtered_total_pages a meta con el conteo del resultado ya filtrado (search/q, brand, category, active). Acotado a 10000 (si lo supera, se satura ahí y filtered_total_capped viene en true); con search/q el tope es 100.
page1Legacy offset. Máx 200 — más profundo devuelve 400 offset_too_deep.

El meta siempre incluye has_more, next_cursor y previous_cursor. total/total_pages solo con include_total; filtered_total/filtered_total_pages (y filtered_total_capped) solo con include_filtered_total. Ver la guía de paginación para la diferencia entre ambos totales.

bash
# Primera página
curl 'https://developers.fi-nova.com/api/v1/products?limit=25' \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO'

# Siguiente página (usar next_cursor de la respuesta anterior)
curl 'https://developers.fi-nova.com/api/v1/products?limit=25&starting_after=65a0c0f1234567890abcdef0' \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO'

# Filtrar por categoría (slug) + marca, con conteo del resultado filtrado
curl 'https://developers.fi-nova.com/api/v1/products?category=comida,bebidas&brand=acme&include_filtered_total=true' \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO'

# Incluir también los productos inactivos (no visibles en el sitio)
curl 'https://developers.fi-nova.com/api/v1/products?active=all' \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO'
javascript
let cursor = null;
do {
  const url = new URL('https://developers.fi-nova.com/api/v1/products');
  url.searchParams.set('limit', '100');
  if (cursor) url.searchParams.set('starting_after', cursor);

  const res  = await fetch(url, { headers: { Authorization: 'Bearer finova_sk_TU_SECRETO' } });
  const body = await res.json();
  // ...do something with body.data...
  cursor = body.meta.has_more ? body.meta.next_cursor : null;
} while (cursor);
ruby
cursor = nil
loop do
  uri = URI('https://developers.fi-nova.com/api/v1/products')
  uri.query = URI.encode_www_form({ limit: 100, starting_after: cursor }.compact)
  req = Net::HTTP::Get.new(uri, 'Authorization' => 'Bearer finova_sk_TU_SECRETO')
  res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
  body = JSON.parse(res.body)
  # ...do something with body['data']...
  break unless body.dig('meta', 'has_more')
  cursor = body.dig('meta', 'next_cursor')
end

Obtener un producto

GET/api/v1/products/:idread-products

Devuelve un único producto. El segmento :id acepta el id (ObjectId), el slug o el sku del producto — se resuelven en ese orden y siempre dentro de tu empresa. Útil para URLs amigables (/catalog/lentes-premium) sin tener que listar y filtrar. Ver Identificar un recurso.

bash
curl https://developers.fi-nova.com/api/v1/products/lentes-premium \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO'

Si ningún identificador coincide (o pertenece a otra empresa), recibes 404 not_found. La respuesta incluye los campos de detalle (variants, option_types, components, inventory) además de los de la lista.


Crear un producto

POST/api/v1/productscreate-products

Campos aceptados en data

name, slug, sku, description, product_type, is_active, product_category_id, brand_id, gtin, mpn, condition, prices_cents (mapa multi-moneda { <iso4217>: <centavos> }), inventory_enabled, inventory_mode, taxable, tax_rate_percent, tags, un objeto anidado seo (ver El objeto SEO), el array custom_properties (ver Campos personalizados), y las colecciones anidadas variants, option_types y components (ver Variantes, opciones y componentes).

Para asignar (o reasignar) la categoría de catálogo de un producto, manda product_category_id con el id de una categoría de la misma empresa (ver Categorías de producto). Mándalo vacío (""/null) para quitar la categoría. Un product_category_id que no exista o pertenezca a otra empresa devuelve 422 invalid_product_category. El campo category_name está denormalizado y se recalcula solo a partir de product_category_id; mandarlo no tiene efecto (se conserva en la respuesta solo por compatibilidad).

Los campos company_id, owner_id se asignan automáticamente a partir de la API key autenticada. brand_name y brand_slug se sincronizan automáticamente desde el Brand referenciado por brand_id. Las imágenes (binarios) no se mandan en el JSON: súbelas con los endpoints de imagen.

bash
curl -X POST https://developers.fi-nova.com/api/v1/products \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: prod-import-row-42' \
  -d '{
    "data": {
      "name": "Lentes oftálmicos premium",
      "sku":  "LEN-PREM-001",
      "product_type": "simple",
      "prices_cents": { "mxn": 450000, "usd": 25000 },
      "is_active":    true,
      "taxable":      true,
      "tax_rate_percent": 16
    }
  }'
javascript
await fetch('https://developers.fi-nova.com/api/v1/products', {
  method: 'POST',
  headers: {
    Authorization:    'Bearer finova_sk_TU_SECRETO',
    'Content-Type':   'application/json',
    'Idempotency-Key': 'prod-import-row-42',
  },
  body: JSON.stringify({
    data: {
      name: 'Lentes oftálmicos premium',
      sku:  'LEN-PREM-001',
      product_type: 'simple',
      prices_cents: { mxn: 450000, usd: 25000 },
      is_active:    true,
      taxable:      true,
      tax_rate_percent: 16,
    },
  }),
});

Actualizar un producto

PATCH/api/v1/products/:idupdate-products

Acepta los mismos campos que create. Solo se actualizan los que mandes — los demás quedan intactos.

bash
curl -X PATCH https://developers.fi-nova.com/api/v1/products/65a0c0f1234567890abcdef0 \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO' \
  -H 'Content-Type: application/json' \
  -d '{ "data": { "prices_cents": { "mxn": 480000 } } }'

Eliminar un producto

DELETE/api/v1/products/:iddelete-products

Borra el producto. Devuelve 204 No Content. Los productos relacionados con ventas o movimientos de inventario existentes NO se pueden eliminar — recibirás 422 validation_failed y debes archivarlos desde la UI.


Imágenes

Las imágenes son binarios y se gestionan con endpoints dedicados (multipart/form-data), no en el JSON del producto. El campo del archivo se llama file. Tras subir, el producto reflejará image_url (y la entrada en images[]); las variantes reflejarán variants[].image_url.

Las URLs devueltas son firmadas y de corta duración — vuelve a leer el producto para refrescarlas.

Imagen principal del producto

POST/api/v1/products/:id/imageupdate-products
DELETE/api/v1/products/:id/imageupdate-products
bash
# Subir / reemplazar
curl -X POST https://developers.fi-nova.com/api/v1/products/65a0…/image \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO' \
  -F 'file=@./lentes.jpg'

# Eliminar
curl -X DELETE https://developers.fi-nova.com/api/v1/products/65a0…/image \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO'

Respuesta: { "data": { "id": "65a0…", "image_url": "https://…" } } (o image_url: null al eliminar).

Formatos aceptados: jpg, jpeg, png, webp, gif. Un archivo inválido devuelve 422 invalid_file; sin archivo, 422 missing_file.

Imagen de una variante

POST/api/v1/products/:id/variants/:variant_id/imageupdate-products
DELETE/api/v1/products/:id/variants/:variant_id/imageupdate-products

Igual que la imagen principal, pero apuntando a una variante existente. Si la variante no existe (o pertenece a otro producto), recibes 404 not_found. La imagen sigue a la variante por su id, así que se conserva al editar el producto.

bash
curl -X POST https://developers.fi-nova.com/api/v1/products/65a0…/variants/65c2…/image \
  -H 'Authorization: Bearer finova_sk_TU_SECRETO' \
  -F 'file=@./variante-roja.jpg'

Respuesta: { "data": { "id": "65a0…", "variant_id": "65c2…", "image_url": "https://…" } }.


Errores específicos

errorCuándo
validation_failed (422)El payload no pasa validaciones (precio negativo, SKU duplicado, etc.).
not_found (404)El id (o variant_id) no existe o pertenece a otra empresa.
invalid_product_category (422)El product_category_id no existe o pertenece a otra empresa.
missing_file (422)Endpoint de imagen sin archivo file.
invalid_file (422)Imagen con formato no permitido.
insufficient_scope (403)La API key no tiene el scope requerido por el endpoint.

Hecho con cuidado por Finova.