Saltar al contenido
Marketplace

Vendedores

Crea vendedores, modera sus productos y lee sus pedidos y comisiones.

Suma a Textiles Andinos como vendedor de tu marketplace, aprueba su Polo de algodón y lee el pedido y la comisión de una venta.

En un marketplace, cada vendedor tiene su catálogo, su stock y sus pedidos. Tu tienda también es un vendedor, el vendedor interno (isInternal: true). Un producto de un vendedor puede unirse a uno tuyo como oferta, y un carrito con productos de dos vendedores crea un pedido para cada uno, con un solo pago.

Requisitos

  • Una tienda de tipo marketplace.
  • Un token de Admin en ECOMIQ_TOKEN, con los permisos settings:create, settings:read, settings:update, catalog:read, catalog:update y order:read. Ver Inicio rápido.
  • Para las llamadas de Storefront, el slug de tu tienda en x-Store-Domain.

Crea el vendedor

Envía name. Si omites slug, se genera desde name; si envías ownerEmail, el dueño recibe una invitación, y si no, puedes invitarlo después. status es active por defecto y no depende de que acepte la invitación.

curl -X POST https://api.ecomiq.pe/api/v1/sellers \
  -H "Authorization: Bearer $ECOMIQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Textiles Andinos",
    "slug": "textiles-andinos",
    "countryCode": "PE",
    "currencyCode": "PEN",
    "legalName": "Textiles Andinos S.A.C.",
    "taxId": "20601234567",
    "commissionPercent": 12,
    "ownerEmail": "rosa.quispe@example.com",
    "ownerFirstName": "Rosa",
    "ownerLastName": "Quispe"
  }'
Respuesta (extracto)
{
  "id": "7204558912004325310",
  "storeId": "7204558912004325300",
  "name": "Textiles Andinos",
  "slug": "textiles-andinos",
  "countryCode": "PE",
  "currencyCode": "PEN",
  "commissionPercent": 12,
  "isInternal": false,
  "catalogSettings": {
    "publicationEnabled": true,
    "productApprovalPolicy": "manualReview",
    "promotionsEnabled": false
  },
  "legalInfo": {
    "isVerified": false,
    "taxId": "20601234567",
    "legalName": "Textiles Andinos S.A.C."
  },
  "status": "active",
  "createdOn": "2026-10-05T14:00:00Z"
}
CampoInicialQué controla
statusactiveactive, inactive o deleted.
commissionPercent0Comisión por defecto, de 0 a 100.
catalogSettings.productApprovalPolicymanualReviewmanualReview deja sus productos nuevos en draft.
catalogSettings.promotionsEnabledfalseSi se aplican las promociones del vendedor.
catalogSettings.publicationEnabledtrueSi sus productos van a los canales conectados de la tienda.
legalInfo.isVerifiedfalseVendedor verificado. Lo marca tu tienda.

El slug es único en la tienda.

Importa y exporta vendedores

POST /v1/sellers/imports recibe Excel (.xlsx), CSV, TSV o JSONL y responde 202 con una operación. Necesita settings:create y settings:update. Sigue el avance y descarga los errores por fila con GET /v1/operations/{id}. Con ?validateOnly=true solo valida. Estas cargas no envían invitaciones.

Cada fila declara action: create exige name y update exige id. Un slug que ya existe no convierte una creación en actualización. El país y la moneda de un vendedor nuevo pueden venir de la tienda.

action,id,name,slug,status,commission_percent
create,,Textiles Andinos,textiles-andinos,active,12
update,7204558912004325310,Textiles Andinos,,inactive,10

También acepta country_code, currency_code, description, phone, email_notification, legal_name, tax_id, legal_address, contact_person y contact_email. Una columna omitida conserva el valor; una celda vacía borra un campo de texto opcional. Los datos del dueño no van en el archivo.

POST /v1/sellers/exports acepta format (xlsx o csv), ids, search y statuses, y responde una operación con el archivo. Sin filtros exporta todo; con template: true genera una plantilla.

Para editar en hoja, POST /v1/sellers/spreadsheet recibe ids o filters: { search, statuses }, pageSize (hasta 200) y maxRows (hasta 1000), y devuelve id, totalCount y expiresAt. Lee las filas con GET /v1/sellers/spreadsheet/{id}?cursor=... durante una hora y guarda los cambios con POST /v1/sellers/imports. La hoja no incluye al vendedor interno.

PATCH /v1/sellers/{id} ajusta la revisión y las políticas:

  • name es obligatorio.
  • Cada bloque que envías, como catalogSettings, reemplaza el bloque completo; los que omites no cambian.
  • deliveryPolicy y privacyAndSecurityPolicy quedan en null si los omites.
curl -X PATCH https://api.ecomiq.pe/api/v1/sellers/7204558912004325310 \
  -H "Authorization: Bearer $ECOMIQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Textiles Andinos",
    "deliveryPolicy": "Despachamos en 48 horas hábiles a Lima Metropolitana.",
    "privacyAndSecurityPolicy": "Usamos tus datos solo para entregar tu pedido.",
    "catalogSettings": {
      "publicationEnabled": true,
      "productApprovalPolicy": "manualReview",
      "promotionsEnabled": true
    }
  }'

Luego limita sus categorías o marcas con PUT /v1/sellers/{sellerId}/scopes. Este ejemplo lo deja en la categoría Polos y sus subcategorías:

curl -X PUT https://api.ecomiq.pe/api/v1/sellers/7204558912004325310/scopes \
  -H "Authorization: Bearer $ECOMIQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "scopes": [
      {
        "type": "category",
        "categoryId": "7204558912004325330",
        "brandId": null,
        "includeChildrenCategories": true
      }
    ]
  }'
Respuesta de scopes
[
  {
    "id": "7204558912004325335",
    "type": "category",
    "categoryId": "7204558912004325330",
    "brandId": null,
    "includeChildrenCategories": true,
    "createdOn": "2026-10-05T14:05:00Z",
    "updatedOn": null
  }
]

Sin alcances, el vendedor puede usar cualquier categoría o marca. Con alcances, cada producto que crea o edita debe caer en uno. PUT reemplaza la lista completa; "scopes": [] los quita. Para dar de baja al vendedor, usa Eliminar vendedor.

Fija las comisiones

PUT /v1/sellers/{sellerId}/commissions reemplaza todas las reglas del vendedor. Cabe una regla por categoría y una por marca.

curl -X PUT https://api.ecomiq.pe/api/v1/sellers/7204558912004325310/commissions \
  -H "Authorization: Bearer $ECOMIQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "commissions": [
      {
        "target": "category",
        "categoryId": "7204558912004325330",
        "brandId": null,
        "includeChildrenCategories": true,
        "productCommissionPercent": 10,
        "freightCommissionPercent": 5,
        "fixedFee": 1.5,
        "isActive": true
      }
    ]
  }'
Respuesta
[
  {
    "id": "7204558912004325350",
    "target": "category",
    "categoryId": "7204558912004325330",
    "brandId": null,
    "includeChildrenCategories": true,
    "productCommissionPercent": 10,
    "freightCommissionPercent": 5,
    "fixedFee": 1.5,
    "isActive": true,
    "createdOn": "2026-10-05T14:10:00Z",
    "updatedOn": null
  }
]
CampoQué cobra
productCommissionPercentPorcentaje del monto del artículo con descuento, de 0 a 100.
freightCommissionPercentPorcentaje de la parte del envío del artículo. Opcional.
fixedFeeMonto fijo por línea del pedido, en la moneda de la tienda.

Cada producto usa la primera regla que aplica:

OrdenReglasource
1Regla activa del vendedor para la marca del producto.brand
2Regla activa del vendedor para la categoría. Gana la más cercana.category
3commissionPercentage y commissionFixedFee de la categoría o de su ancestro más cercano.category
4commissionPercent del vendedor.seller

Una regla de categoría cubre las subcategorías solo con includeChildrenCategories: true. El pedido guarda la comisión al crearse.

Modera los productos

Con manualReview, los productos nuevos del vendedor esperan tu decisión en draft. Lista la cola con GET /v1/sellers/received-products (sin status, trae los pending) y decide en lote.

# 1. Lista los pendientes del vendedor
curl "https://api.ecomiq.pe/api/v1/sellers/received-products?status=pending&sellerId=7204558912004325310&limit=50" \
  -H "Authorization: Bearer $ECOMIQ_TOKEN"

# 2. Aprueba los listos
curl -X POST https://api.ecomiq.pe/api/v1/catalog/products/moderation/decide \
  -H "Authorization: Bearer $ECOMIQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "productIds": ["7204558912004325320"],
    "action": "approve",
    "reason": null
  }'
Cola (extracto)
{
  "data": [
    {
      "id": "7204558912004325320",
      "sellerId": "7204558912004325310",
      "name": "Polo de algodón",
      "price": 59.9,
      "status": "pending",
      "issues": [],
      "reason": null,
      "match": {
        "productId": "7204558912004325302",
        "score": 1,
        "matchedBy": "name",
        "productName": "Polo de algodón"
      },
      "categoryName": "Polos",
      "variantCount": 1,
      "approvalPolicy": "manualReview"
    }
  ],
  "hasNextPage": false,
  "nextCursor": null,
  "totalCount": 1
}
Decisión
{ "approved": 1, "rejected": 0 }
statusQué incluye
pendingLo que el vendedor mandó a revisar, sin problemas de calidad ni corrección pedida.
issuesLo que el vendedor mandó con problemas de calidad, o un draft con corrección pedida.
approvedactive.
rejectedinactive con motivo de rechazo.

Cada problema llega en issues:

issuesCausa
minImagesTiene menos imágenes que minImages.
barcodeRequiredUna variante activa no tiene barcode.
priceRequiredUna variante activa tiene precio 0.
correctionRequestedPediste una corrección.

Las reglas de calidad se fijan en el admin, en Por aprobar → Reglas de calidad.

OperaciónEfectoLímite
POST /v1/catalog/products/moderation/decide con approvePasa a active. Exige cero problemas de calidad.500 productos
POST /v1/catalog/products/moderation/decide con rejectPasa a inactive y guarda reason, que es obligatorio.500 productos
POST /v1/sellers/received-products/request-correctionVuelve a draft con reason. Responde requestedCount.100 productos
POST /v1/catalog/products/{productId}/seller-offerUne el producto a uno tuyo y lo activa.1 producto

reason admite hasta 500 caracteres. Tras una corrección o un rechazo, las ediciones del vendedor no cambian el estado: apruébalo cuando esté listo. Con autoApprove, los productos no esperan revisión, salvo que tengan un problema de calidad.

Véndelo como oferta

match sugiere un producto tuyo con el mismo SKU, el mismo código de barras o un nombre parecido. Para unirlos, envía ese productId en canonicalProductId a Vincular oferta de vendedor. El producto destino debe estar active u outOfStock, ser del vendedor interno y no ser a su vez una oferta.

Muestra los vendedores

GET /v1/sellers de Storefront lista los vendedores activos por nombre, sin el vendedor interno. En una tienda que no es marketplace responde 404.

Una oferta no se lista sola: aparece en sellerOffers del producto de tu tienda.

curl https://storefront.ecomiq.pe/v1/sellers \
  -H "x-Store-Domain: mi-tienda"

curl https://storefront.ecomiq.pe/v1/products/polo-de-algodon \
  -H "x-Store-Domain: mi-tienda"
Vendedores
[
  {
    "id": "7204558912004325310",
    "name": "Textiles Andinos",
    "slug": "textiles-andinos",
    "logo": null,
    "rating": { "average": 4.6, "totalReviews": 18 }
  }
]
Producto (extracto)
{
  "id": "7204558912004325302",
  "name": "Polo de algodón",
  "slug": "polo-de-algodon",
  "seller": {
    "id": "7204558912004325305",
    "name": "Mi tienda",
    "slug": "mi-tienda"
  },
  "sellerOffers": [
    {
      "productId": "7204558912004325320",
      "seller": {
        "id": "7204558912004325310",
        "name": "Textiles Andinos",
        "slug": "textiles-andinos"
      },
      "price": 59.9,
      "compareAtPrice": null,
      "isAvailable": true,
      "totalInventory": 12,
      "variants": [
        { "id": "7204558912004325321", "sku": "TXA-POLO-001", "price": 59.9 }
      ]
    }
  ]
}

Las ofertas llegan ordenadas por precio. Para vender una, agrega al carrito un id de sellerOffers[].variants.

Para mostrarUsa
Perfil y políticasGET /v1/sellers/{slug}
Productos de un vendedorGET /v1/products?sellers=textiles-andinos
Vendedor de cada productoseller y sellerOfferCount en cada resultado de búsqueda

El filtro sellers recibe slugs e incluye los productos donde el vendedor tiene una oferta.

Cobra un carrito mixto

El carrito agrupa sus artículos por vendedor y perfil de envío, y cada grupo se convierte en un pedido. Cada grupo con artículos que se envían necesita su método de envío. El comprador paga una sola vez.

Este carrito tiene un artículo de Mi tienda y otro de Textiles Andinos. Para crearlo, sigue Tienda headless.

curl https://storefront.ecomiq.pe/v1/carts/<cart-token>/shipping-options \
  -H "x-Store-Domain: mi-tienda"
Opciones de envío (extracto)
{
  "groups": [
    {
      "sellerId": "7204558912004325305",
      "sellerName": "Mi tienda",
      "shippingProfileId": null,
      "orderAmount": 89,
      "itemIds": ["7204558912004325391"],
      "rates": [
        {
          "shippingMethodId": "7204558912004325381",
          "rateId": "7204558912004325382",
          "name": "Envío regular",
          "type": "regular",
          "target": "automatic",
          "targetId": null,
          "price": 12,
          "currency": "PEN"
        }
      ]
    },
    {
      "sellerId": "7204558912004325310",
      "sellerName": "Textiles Andinos",
      "shippingProfileId": null,
      "orderAmount": 59.9,
      "itemIds": ["7204558912004325390"],
      "rates": [
        {
          "shippingMethodId": "7204558912004325383",
          "rateId": "7204558912004325384",
          "name": "Envío regular",
          "type": "regular",
          "target": "automatic",
          "targetId": null,
          "price": 15,
          "currency": "PEN"
        }
      ]
    }
  ]
}

Elige un método por grupo, con su sellerId o shippingProfileId. Repite la llamada con cada grupo:

curl -X PUT https://storefront.ecomiq.pe/v1/carts/<cart-token>/shipping-method \
  -H "x-Store-Domain: mi-tienda" \
  -H "Content-Type: application/json" \
  -d '{
    "sellerId": "7204558912004325310",
    "shippingProfileId": null,
    "shippingMethodId": "7204558912004325383",
    "rateId": "7204558912004325384",
    "target": "automatic"
  }'

Luego cobra el carrito:

curl -X POST https://storefront.ecomiq.pe/v1/carts/<cart-token>/checkout \
  -H "x-Store-Domain: mi-tienda" \
  -H "Content-Type: application/json" \
  -d '{ "paymentMethodCode": "<payment-method-code>" }'
Checkout (extracto)
{
  "orderId": "7204558912004325360",
  "orderNumber": "ORD-2026-0101",
  "orderGroup": "7204558912004325360",
  "orderIds": ["7204558912004325360", "7204558912004325361"],
  "payment": {
    "paymentMethodCode": "<payment-method-code>",
    "status": "pending",
    "amount": 175.9
  }
}

orderId y orderNumber son del primer pedido. Guarda orderGroup, que une todos los pedidos del carrito. El comprador ve una sola compra en Listar pedidos del cliente, con sus orderIds.

Lee los pedidos por vendedor

GET /v1/orders/group/{orderGroup} devuelve los pedidos del grupo con su sellerId, y cada artículo trae la comisión aplicada. Este ejemplo suma la comisión de cada vendedor:

curl https://api.ecomiq.pe/api/v1/orders/group/7204558912004325360 \
  -H "Authorization: Bearer $ECOMIQ_TOKEN"
Respuesta (extracto)
{
  "orderId": "7204558912004325360",
  "orderGroup": "7204558912004325360",
  "orderIds": ["7204558912004325360", "7204558912004325361"],
  "total": 175.9,
  "currencyCode": "PEN",
  "orders": [
    {
      "id": "7204558912004325360",
      "orderNumber": "ORD-2026-0101",
      "sellerId": "7204558912004325305",
      "status": "confirmed",
      "total": 101
    },
    {
      "id": "7204558912004325361",
      "orderNumber": "ORD-2026-0102",
      "sellerId": "7204558912004325310",
      "status": "confirmed",
      "total": 74.9,
      "items": [
        {
          "title": "Polo de algodón",
          "quantity": 1,
          "sellerId": "7204558912004325310",
          "sellerCommissionId": "7204558912004325350",
          "commissionSource": "category",
          "productCommissionPercent": 10,
          "freightCommissionPercent": 5,
          "fixedFee": 1.5,
          "commissionBaseAmount": 59.9,
          "productCommissionAmount": 5.99,
          "freightCommissionBaseAmount": 15,
          "freightCommissionAmount": 0.75,
          "commissionAmount": 8.24
        }
      ]
    }
  ]
}

commissionAmount suma la comisión del artículo, la del envío y fixedFee. Con estos campos calculas lo que debes a cada vendedor; la liquidación y el pago corren por tu cuenta.

Cada pedido del grupo tiene su propio estado y se prepara desde las ubicaciones activas de su vendedor, con su stock. Ver Preparación y entrega.

  • GET /v1/orders trae sellerId y sellerName en cada fila y filtra por vendedor con sellerIds.
  • Los eventos order.* traen sellerId y orderGroup. Ver Webhooks.

Errores

codeEstadoQué hacer
Seller.StoreTypeInvalid400La tienda no es un marketplace.
SellerScope.Denied400El producto está fuera de las categorías o marcas del vendedor.
Moderation.QualityRequired400Resuelve los issues del producto antes de aprobarlo.
ShippingMethods.GroupRequired400El carrito tiene varios grupos: envía sellerId o shippingProfileId.
Orders.ShippingMethodRequired400Un grupo del carrito no tiene método de envío.
Seller.SlugExists409Otro vendedor usa ese slug: cámbialo.

Siguientes pasos

Última actualización:

En esta página