Sellers
Create sellers, moderate their products, and read their orders and commissions.
Add Textiles Andinos as a seller in your marketplace, approve their Polo de algodón, and read the order and commission for a sale.
In a marketplace, each seller has its own catalog, stock, and orders. Your
store is a seller too, the internal seller (isInternal: true). A seller's
product can be linked to one of yours as an offer, and a cart with products
from two sellers creates one order for each, with a single payment.
Requirements
- A marketplace store.
- An Admin token in
ECOMIQ_TOKENwith thesettings:create,settings:read,settings:update,catalog:read,catalog:update, andorder:readpermissions. See Quickstart. - For Storefront calls, your store slug in
x-Store-Domain.
Create the seller
Send name. If you omit slug, it's generated from name. If you send
ownerEmail, the owner gets an invitation; otherwise, you can invite them
later. status defaults to active and doesn't wait for the invitation to be
accepted.
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"
}'{
"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"
}| Field | Initial | What it controls |
|---|---|---|
status | active | active, inactive, or deleted. |
commissionPercent | 0 | Default commission, from 0 to 100. |
catalogSettings.productApprovalPolicy | manualReview | manualReview keeps the seller's new products in draft. |
catalogSettings.promotionsEnabled | false | Whether the seller's promotions apply. |
catalogSettings.publicationEnabled | true | Whether its products go to the store's connected channels. |
legalInfo.isVerified | false | Verified seller. Your store sets it. |
The slug is unique within the store.
Import and export sellers
POST / accepts Excel (.xlsx), CSV, TSV, or JSONL and
returns 202 with an operation. It requires settings:create and
settings:update. Track progress and download row errors with
GET /. With ?validateOnly=true, it only validates. These
imports don't send invitations.
Each row declares action: create requires name and update requires
id. An existing slug never turns a creation into an update. A new seller
can inherit the store's country and currency.
action,id,name,slug,status,commission_percent
create,,Textiles Andinos,textiles-andinos,active,12
update,7204558912004325310,Textiles Andinos,,inactive,10It also accepts country_code, currency_code, description, phone,
email_notification, legal_name, tax_id, legal_address,
contact_person, and contact_email. An omitted column keeps its value; an
empty cell clears an optional text field. Owner details don't go in the file.
POST / accepts format (xlsx or csv), ids, search,
and statuses, and returns an operation with the file. Without filters, it
exports everything; with template: true, it generates a template.
To edit in a spreadsheet, POST / takes ids or
filters: { search, statuses }, pageSize (up to 200), and maxRows (up to
1000), and returns id, totalCount, and expiresAt. Read the rows with
GET / for up to one hour and save
changes with POST /. The sheet excludes the internal
seller.
Limit their catalog
PATCH / sets review and policies:
nameis required.- Each block you send, such as
catalogSettings, replaces the whole block; blocks you omit don't change. deliveryPolicyandprivacyAndSecurityPolicybecomenullif you omit them.
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
}
}'Then limit their categories or brands with PUT /.
This example restricts them to the Polos category and its subcategories:
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
}
]
}'[
{
"id": "7204558912004325335",
"type": "category",
"categoryId": "7204558912004325330",
"brandId": null,
"includeChildrenCategories": true,
"createdOn": "2026-10-05T14:05:00Z",
"updatedOn": null
}
]Without scopes, the seller can use any category or brand. With scopes, every
product they create or edit must fall within one. PUT replaces the whole
list; "scopes": [] removes them. To offboard the seller, use
Delete a seller.
Set the commissions
PUT / replaces all of the seller's rules.
There's one rule per category and one per brand.
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
}
]
}'[
{
"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
}
]| Field | What it charges |
|---|---|
productCommissionPercent | Percentage of the discounted item amount, from 0 to 100. |
freightCommissionPercent | Percentage of the item's share of shipping. Optional. |
fixedFee | Fixed amount per order line, in the store currency. |
Each product uses the first rule that applies:
| Order | Rule | source |
|---|---|---|
| 1 | The seller's active rule for the product's brand. | brand |
| 2 | The seller's active rule for the category. The closest one wins. | category |
| 3 | commissionPercentage and commissionFixedFee of the category or its closest ancestor. | category |
| 4 | The seller's commissionPercent. | seller |
A category rule covers subcategories only with
includeChildrenCategories: true. The order stores the commission when it's
created.
Moderate the products
With manualReview, the seller's new products wait for your decision in
draft. List the queue with GET / (without
status, it returns pending) and decide in bulk.
# 1. List the seller's pending products
curl "https://api.ecomiq.pe/api/v1/sellers/received-products?status=pending&sellerId=7204558912004325310&limit=50" \
-H "Authorization: Bearer $ECOMIQ_TOKEN"
# 2. Approve them
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
}'{
"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
}{ "approved": 1, "rejected": 0 }status | What it includes |
|---|---|
pending | What the seller sent for review, with no quality issues and no correction request. |
issues | What the seller sent with quality issues, or a draft with a correction request. |
approved | active. |
rejected | inactive with a rejection reason. |
Each problem comes in issues:
issues | Cause |
|---|---|
minImages | It has fewer images than minImages. |
barcodeRequired | An active variant has no barcode. |
priceRequired | An active variant has a price of 0. |
correctionRequested | You requested a correction. |
Set the quality rules in the admin, under To approve → Quality rules.
| Operation | Effect | Limit |
|---|---|---|
POST / with approve | Moves to active. Requires zero quality issues. | 500 products |
POST / with reject | Moves to inactive and stores reason, which is required. | 500 products |
POST / | Moves back to draft with reason. Returns requestedCount. | 100 products |
POST / | Links the product to one of yours and activates it. | 1 product |
reason accepts up to 500 characters. After a correction request or a
rejection, the seller's edits don't change the status: approve it when it's
ready. With autoApprove, products skip review unless they have a quality
issue.
Sell it as an offer
match suggests one of your products with the same SKU, the same barcode, or a
similar name. To link them, send that productId as canonicalProductId to
Link a seller offer.
The target product must be active or outOfStock, belong to the internal
seller, and not be an offer itself.
Show the sellers
Storefront's GET / lists active sellers by name, without the
internal seller. In a store that isn't a marketplace, it returns 404.
An offer isn't listed on its own: it appears in sellerOffers on your store's
product.
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"[
{
"id": "7204558912004325310",
"name": "Textiles Andinos",
"slug": "textiles-andinos",
"logo": null,
"rating": { "average": 4.6, "totalReviews": 18 }
}
]{
"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 }
]
}
]
}Offers are sorted by price. To sell one, add an id from
sellerOffers[].variants to the cart.
| To show | Use |
|---|---|
| Profile and policies | GET / |
| A seller's products | GET / |
| The seller of each product | seller and sellerOfferCount in each search result |
The sellers filter takes slugs and includes products where the seller has an
offer.
Charge a mixed cart
The cart groups its items by seller and shipping profile, and each group becomes an order. Every group with items that ship needs its own shipping method. The buyer pays once.
This cart has one item from Mi tienda and one from Textiles Andinos. To build it, follow Headless store.
curl https://storefront.ecomiq.pe/v1/carts/<cart-token>/shipping-options \
-H "x-Store-Domain: mi-tienda"{
"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"
}
]
}
]
}Pick one method per group, with its sellerId or shippingProfileId. Repeat
the call for each group:
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"
}'Then check out:
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>" }'{
"orderId": "7204558912004325360",
"orderNumber": "ORD-2026-0101",
"orderGroup": "7204558912004325360",
"orderIds": ["7204558912004325360", "7204558912004325361"],
"payment": {
"paymentMethodCode": "<payment-method-code>",
"status": "pending",
"amount": 175.9
}
}orderId and orderNumber belong to the first order. Store orderGroup,
which ties together every order from the cart. The buyer sees a single purchase
in
List customer orders,
with its orderIds.
Read the orders by seller
GET / returns the group's orders with their
sellerId, and each item carries the commission applied. This example adds up
each seller's commission:
curl https://api.ecomiq.pe/api/v1/orders/group/7204558912004325360 \
-H "Authorization: Bearer $ECOMIQ_TOKEN"{
"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 adds the item commission, the shipping commission, and
fixedFee. Use these fields to calculate what you owe each seller; settlement
and payouts happen on your side.
Each order in the group has its own status and is fulfilled from its seller's active locations, with that seller's stock. See Fulfillment and delivery.
GET /includesv1/ orders sellerIdandsellerNamein each row and filters by seller withsellerIds.order.*events carrysellerIdandorderGroup. See Webhooks.
Errors
code | Status | What to do |
|---|---|---|
Seller.StoreTypeInvalid | 400 | The store isn't a marketplace. |
SellerScope.Denied | 400 | The product is outside the seller's categories or brands. |
Moderation.QualityRequired | 400 | Resolve the product's issues before approving it. |
ShippingMethods.GroupRequired | 400 | The cart has several groups: send sellerId or shippingProfileId. |
Orders.ShippingMethodRequired | 400 | A cart group has no shipping method. |
Seller.SlugExists | 409 | Another seller uses that slug: change it. |
Next steps
Last updated: