Help center · Integrations
Integrate your inventory with Mercazul
Three ways to keep your catalog and stock in sync: REST API, manual CSV upload, and SFTP delivery. All three share the same data contract.
Integration channels
REST API
Manual CSV
Upload a CSV from your seller dashboard, validate rows on screen, and commit the import. Ideal for small catalogs or one-off loads.
Go to Products → ImportCSV over SFTP
The SFTP channel is live: host sftp.izzatissa.site, port 2022, SSH key authentication (Ed25519). Email [email protected] with your public key to get your account provisioned. Drop your CSVs into the inbox/ folder and fetch the per-file result report from reports/; jobs also show up in your dashboard import history.
1 · Authentication
Every request needs two headers: the platform publishable key (apikey) and a token for your seller account (Authorization: Bearer). Get the token with your email and password:
Base URL
https://zonalibre-api.izzatissa.sitePublishable key (apikey)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzgxMjMxMTA2LCJleHAiOjIwOTY1OTExMDZ9.dJ5raIZYJuIhurPUU_W6wxfvR-W7WeyxKb3YzDIkJr4curl -s 'https://zonalibre-api.izzatissa.site/auth/v1/token?grant_type=password' \
-H 'apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzgxMjMxMTA2LCJleHAiOjIwOTY1OTExMDZ9.dJ5raIZYJuIhurPUU_W6wxfvR-W7WeyxKb3YzDIkJr4' \
-H 'Content-Type: application/json' \
-d '{"email":"[email protected]","password":"<your-password>"}'The publishable key is public by design; real security is enforced by row-level access policies (RLS) tied to your user token.
2 · Sync your inventory via API
The main endpoint accepts batches of rows using the same contract as the CSV. Rows are upserted by SKU: a new SKU creates the product (it starts as a draft until it passes moderation) and an existing SKU updates the product and its stock.
curl -s 'https://zonalibre-api.izzatissa.site/rest/v1/rpc/seller_import_products' \
-H 'apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzgxMjMxMTA2LCJleHAiOjIwOTY1OTExMDZ9.dJ5raIZYJuIhurPUU_W6wxfvR-W7WeyxKb3YzDIkJr4' \
-H 'Authorization: Bearer <access_token>' \
-H 'Content-Type: application/json' \
-d '{
"p_filename": "api-sync-example",
"p_rows": [{
"sku": "WIDGET-001",
"name_es": "Widget industrial 10cm",
"name_en": "Industrial widget 10cm",
"description_es": "Widget de acero inoxidable.",
"description_en": "Stainless-steel widget.",
"category": "hardware",
"price": 12.50, "moq": 100, "stock": 5400, "currency": "USD"
}, {
"sku": "SHOE-CURVE-01",
"name_es": "Zapatilla running",
"name_en": "Running sneaker",
"description_es": "Caja surtida de zapatillas.",
"description_en": "Assorted sneaker box.",
"category": "footwear",
"price": 42.00, "moq": 1, "stock": 30, "currency": "USD",
"sell_unit": "both", "units_per_box": 12,
"size_breakdown": "38:1,39:2,40:3,41:3,42:2,43:1", "size_system": "EU"
}]
}'Check the history and per-row errors of your imports:
curl -s 'https://zonalibre-api.izzatissa.site/rest/v1/product_import_jobs?order=created_at.desc&limit=5' \
-H 'apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzgxMjMxMTA2LCJleHAiOjIwOTY1OTExMDZ9.dJ5raIZYJuIhurPUU_W6wxfvR-W7WeyxKb3YzDIkJr4' \
-H 'Authorization: Bearer <access_token>'3 · CSV contract (manual and SFTP)
The first 10 columns are required and appear in this exact order; the 4 box-composition columns are optional (you can omit them). First row is the header; UTF-8 encoding; comma separator; double quotes around values containing commas (e.g. the size_breakdown list).
| Column | Required | Rule |
|---|---|---|
sku | Yes | Unique product code. Upsert key within your catalog. |
name_es | Yes | Product name in Spanish. |
name_en | Yes | Product name in English. |
description_es | Yes | Description in Spanish. |
description_en | Yes | Description in English. |
category | Yes | Existing category name or slug (case-insensitive). Unknown categories reject the row. |
price | Yes | Unit price, number ≥ 0. |
moq | Yes | Minimum order quantity, integer ≥ 1. |
stock | Yes | Available stock, integer ≥ 0. Replaces the stored quantity. |
currency | Yes | 3-letter ISO 4217 code (e.g. USD). |
sell_unit | Optional | Selling unit: individual (loose), box (by the box), or both. Blank = individual. |
units_per_box | Optional | Units per box, integer ≥ 1. Required when sell_unit is box or both; must equal the sum of size_breakdown. |
size_breakdown | Optional | Box composition as a comma-separated "size:qty" list. Curve: "38:1,39:2,40:3"; single size: "40:24". Must be empty for individual products. |
size_system | Optional | Size system, free text (e.g. EU, US). Optional. |
Minimal example
sku,name_es,name_en,description_es,description_en,category,price,moq,stock,currency,sell_unit,units_per_box,size_breakdown,size_system
WIDGET-001,Widget industrial 10cm,Industrial widget 10cm,Widget de acero inoxidable.,Stainless-steel widget.,hardware,12.50,100,5400,USD,individual,,,
SHOE-CURVE-01,Zapatilla running,Running sneaker,Caja surtida de zapatillas.,Assorted sneaker box.,footwear,42.00,1,30,USD,both,12,"38:1,39:2,40:3,41:3,42:2,43:1",EUManual upload: seller dashboard → Products → Bulk import. You can also download the template and see your import history there.
4 · Helper prompts (copy-paste into your AI assistant)
These prompts embed the full contract so an AI assistant (Claude, ChatGPT…) can do the heavy lifting: map your inventory file to the right format, or write the sync script for you.
Prompt: convert my inventory file to the Mercazul CSV
You are helping me prepare a product CSV for the Mercazul B2B marketplace bulk import.
The CSV header row must start with these 10 required columns, in this exact order:
sku,name_es,name_en,description_es,description_en,category,price,moq,stock,currency
You may then append any of these 4 optional box-composition columns (by name, any order; omit them entirely for simple products):
sell_unit,units_per_box,size_breakdown,size_system
Field rules:
- sku (required): Unique product code. Upsert key within your catalog.
- name_es (required): Product name in Spanish.
- name_en (required): Product name in English.
- description_es (required): Description in Spanish.
- description_en (required): Description in English.
- category (required): Existing category name or slug (case-insensitive). Unknown categories reject the row.
- price (required): Unit price, number ≥ 0.
- moq (required): Minimum order quantity, integer ≥ 1.
- stock (required): Available stock, integer ≥ 0. Replaces the stored quantity.
- currency (required): 3-letter ISO 4217 code (e.g. USD).
- sell_unit (optional): Selling unit: individual (loose), box (by the box), or both. Blank = individual.
- units_per_box (optional): Units per box, integer ≥ 1. Required when sell_unit is box or both; must equal the sum of size_breakdown.
- size_breakdown (optional): Box composition as a comma-separated "size:qty" list. Curve: "38:1,39:2,40:3"; single size: "40:24". Must be empty for individual products.
- size_system (optional): Size system, free text (e.g. EU, US). Optional.
Additional rules:
- Rows are upserted by "sku": an unknown sku inserts a new product (it starts as a draft pending marketplace moderation); a known sku updates the existing product and replaces its stock.
- Both Spanish and English names/descriptions are required. If my source data only has one language, translate the missing one faithfully (no embellishment).
- "category" must match one of my marketplace categories; ask me for my category list if you need it.
- Box products: set sell_unit to box or both, units_per_box to the total pieces per box, and size_breakdown to a "size:qty" list (e.g. "38:1,39:2,40:3") whose quantities sum to units_per_box. Leave all 4 box columns blank for loose/individual products.
Here is a sample of my current inventory export (I will paste it below). Map it to the contract above, flag any rows that would fail validation and why, and output the final CSV in a code block.
MY DATA:
<paste your inventory export here>Prompt: generate my API sync script
You are helping me build an automated inventory sync against the Mercazul B2B marketplace API (Supabase/PostgREST).
Base URL: https://zonalibre-api.izzatissa.site
Auth: every request needs an "apikey" header (publishable key) plus "Authorization: Bearer <access_token>". The token comes from POST /auth/v1/token?grant_type=password with my seller email/password (JSON body: {"email":..., "password":...}); it expires in ~1 hour, so refresh or re-login as needed. Read credentials from environment variables — never hard-code them.
Main sync endpoint: POST /rest/v1/rpc/seller_import_products
Body: {"p_filename": "<label>", "p_rows": [ ...rows ]}
Each row has these fields (the first 10 required; the last 4 optional box-composition fields):
- sku (required): Unique product code. Upsert key within your catalog.
- name_es (required): Product name in Spanish.
- name_en (required): Product name in English.
- description_es (required): Description in Spanish.
- description_en (required): Description in English.
- category (required): Existing category name or slug (case-insensitive). Unknown categories reject the row.
- price (required): Unit price, number ≥ 0.
- moq (required): Minimum order quantity, integer ≥ 1.
- stock (required): Available stock, integer ≥ 0. Replaces the stored quantity.
- currency (required): 3-letter ISO 4217 code (e.g. USD).
- sell_unit (optional): Selling unit: individual (loose), box (by the box), or both. Blank = individual.
- units_per_box (optional): Units per box, integer ≥ 1. Required when sell_unit is box or both; must equal the sum of size_breakdown.
- size_breakdown (optional): Box composition as a comma-separated "size:qty" list. Curve: "38:1,39:2,40:3"; single size: "40:24". Must be empty for individual products.
- size_system (optional): Size system, free text (e.g. EU, US). Optional.
Rows are upserted by "sku". For products sold by the box, set sell_unit (box|both), units_per_box, and a "size:qty" size_breakdown whose quantities sum to units_per_box; leave those blank for individual products. The response includes job_id, inserted_count, updated_count and per-row error_rows — treat any error_rows as a partial failure and log them.
Job history: GET /rest/v1/product_import_jobs?order=created_at.desc&limit=10 (same auth headers).
Quick stock-only update: PATCH /rest/v1/products?sku=eq.<SKU> with a JSON body of changed fields, header "Prefer: return=representation".
My stack and source of truth for inventory: <describe yours — e.g. "a PostgreSQL ERP", "a Shopify store", "a nightly CSV export">
Write a production-quality sync script in <language of your choice> that reads my inventory, maps it to the row contract, pushes it in batches of ≤500 rows, verifies the job result, and exits non-zero on errors. Include a dry-run mode.
Full OpenAPI spec if you need it: the /openapi.yaml file on the marketplace domain.5 · Try the API live
The interactive reference (Swagger UI) lets you execute every endpoint from the browser: click “Authorize”, paste the apikey and your Bearer token, then use “Try it out”. Requests run against the real environment with your seller permissions.
Interactive API reference (Swagger)Good practice: never commit your password or tokens to repositories; use environment variables. Tokens expire in ~1 hour. New products go through moderation before becoming publicly visible.