Ultima actualizare: 26 august 2026
Obține o cheie API
Autentifică-te cu un cont de comerciant, deschide Setări → Integrări, selectează fila Chei API și creează o cheie. Copiaz-o imediat: cheia completă este afișată o singură dată. Poți revoca cheile din aceeași pagină.
URL de bază și autentificare
https://a.ivo.md/v1/merchant-api
Trimite cheia la fiecare cerere folosind unul dintre headere:
X-API-Key: <CHEIA_API>
Authorization: Bearer <CHEIA_API>
Trimite întotdeauna Accept: application/json și Content-Type: application/json, cu excepția încărcării fișierelor. Fără headerul Accept, erorile de autentificare sunt returnate ca pagină HTML, nu ca JSON.
Structura răspunsului
| Situație | HTTP | Corp |
|---|---|---|
| Succes | 200 | Câmpurile endpoint-ului plus "status": "success". |
| Eroare tratată | 202, 403, 404, 409, 422, 500 | "status": "error", un message care poate fi procesat automat (codul erorii) și eventuale câmpuri suplimentare de context. |
| Eroare de autentificare | 403 | Apare înainte de rularea controllerului, deci nu are câmp status — doar {"message": "api_key_invalid"}. Coduri: api_key_missing, api_key_invalid, merchant_not_found, integration_disabled. |
| Limită de cereri | 429 | 120 de cereri pe minut per adresă IP. Fiecare răspuns conține X-RateLimit-Limit și X-RateLimit-Remaining. |
Important: într-un răspuns 200, câmpul status de nivel superior este întotdeauna șirul success — arată doar că cererea a fost acceptată, nimic mai mult. Endpoint-urile care au și procesare în curs o raportează într-un câmp propriu: sync_status la endpoint-urile de sincronizare și import_status la cele de import.
Un răspuns 202 este o structură de eroare al cărei message explică de ce răspunsul nu este încă gata: queued, processing sau pending_approval.
Verificarea conexiunii
GET /check
Validează cheia API și returnează identitatea comerciantului. Acesta este primul endpoint pe care îl apelezi când configurezi o integrare.
Intrare: nimic în afară de headerul cu cheia API.
{
"merchant_id": "<ID_COMERCIANT>",
"merchant_name": "Magazinul meu",
"status": "success"
}
| Câmp returnat | Tip | Semnificație |
|---|---|---|
merchant_id | string | Identificatorul IVO al comerciantului căruia îi aparține cheia. Salvează-l: nu se schimbă niciodată și identifică contul în solicitările de suport. |
merchant_name | string | Denumirea comerciantului afișată în IVO. |
status | string | Întotdeauna success. Confirmă că cheia este validă și nerevocată; nu este starea contului de comerciant. |
Puncte comerciale
Fiecare ofertă aparține unui punct comercial (magazin, depozit sau loc de ridicare). Folosește ID-ul returnat de aceste endpoint-uri drept merchant_point_id. Dacă există un singur punct în cont, sincronizarea îl selectează automat și poți omite câmpul.
GET /merchant-points
Returnează toate punctele comerciantului autentificat.
{
"points": [
{
"_id": "<ID_PUNCT>",
"name": "Magazin central",
"contact_person": "Ion Popescu",
"email": "[email protected]",
"phone": "+37360000000",
"street_id": "<ID_STRADA>",
"number": "12",
"city_id": "<ID_ORAS>",
"state_id": "<ID_RAION>",
"country": "MD",
"zip_code": "MD-2001",
"status": "approved",
"is_active": true
}
],
"status": "success"
}
| Câmp returnat | Tip | Semnificație |
|---|---|---|
points[]._id | string | ID-ul punctului. Aceasta este valoarea pe care o trimiți ca merchant_point_id. |
points[].name | string | Denumirea punctului. Poate fi trimisă și ca merchant_point în locul ID-ului; potrivirea este exactă, fără diferență între majuscule și minuscule. |
points[].contact_person, email, phone | string | Persoana de contact pentru curier și pentru suportul IVO la această locație. |
points[].street_id, number, block, entrance, floor, apartment, intercom, zip_code, city_id, state_id, country | string | Adresa de ridicare. ID-urile de localizare sunt identificatorii IVO pentru stradă, oraș și raion. |
points[].status | string | pending (așteaptă aprobarea IVO), approved sau rejected. Ofertele dintr-un punct care nu este approved rămân invizibile pe site. |
points[].is_active | boolean | Comutatorul comerciantului. Ofertele dintr-un punct inactiv rămân invizibile. |
points[].rejection_reason | string, null | Motivul respingerii punctului de către IVO, atunci când status este rejected. |
POST /merchant-points/store
Creează un punct. Este creat întotdeauna cu status: pending și is_active: true și rămâne invizibil pentru cumpărători până când IVO îl aprobă.
| Câmp de intrare | Tip | Semnificație |
|---|---|---|
name | string | Denumirea locației în sistemul tău și în panoul de comerciant. |
contact_person | string | Persoana pe care o caută curierul la ridicare. |
email, phone | string | Datele de contact pentru această locație. |
street_id, city_id, state_id | string | Identificatorii IVO de localizare pentru adresă. |
number, block, entrance, floor, apartment, intercom | string | Restul adresei, ca să ajungă curierul la ușa potrivită. |
zip_code, country | string | Codul poștal și codul de țară. |
Orice câmp din afara acestei liste este ignorat. Răspunsul este {"point": { … }, "status": "success"}, unde point este înregistrarea creată, inclusiv noul _id.
POST /merchant-points/update/{id}
Actualizează un punct care aparține comerciantului. {id} este ID-ul punctului. Acceptă toate câmpurile de creare plus is_active (boolean — setează-l pe false ca să scoți din vânzare tot stocul locației, fără să ștergi nimic). Returnează punctul actualizat. ID necunoscut: point_not_found (404).
POST /merchant-points/delete/{id}
Șterge un punct care aparține comerciantului. Returnează {"deleted": true, "status": "success"}. Înregistrarea este ștearsă logic, deci istoricul se păstrează, dar punctul nu mai poate fi folosit pentru oferte.
Actualizarea unei oferte existente
POST /product-offer/update
Actualizează prețul sau stocul unei oferte care există deja, fără a rula importul de produse. Este cel mai rapid și mai ieftin endpoint — folosește-l pentru actualizările curente de preț și stoc.
{
"merchant_internal_id": "PRODUS-123",
"merchant_point_id": "<ID_PUNCT>",
"price": 1999,
"currency": "MDL",
"availability": 5,
"availability_on_order": 0
}
| Câmp de intrare | Tip | Semnificație |
|---|---|---|
offer_id | string | ID-ul ofertei în IVO. Trimite acest câmp sau merchant_internal_id. Oferta trebuie să aparțină contului tău. |
merchant_internal_id | string | Identificatorul tău de produs (SKU), așa cum a fost trimis la crearea ofertei. Căutarea se face doar în contul tău. |
merchant_point_id | string | Folosit doar împreună cu merchant_internal_id: restrânge căutarea la un singur punct. Obligatoriu când același SKU există în mai multe puncte, altfel cererea eșuează cu merchant_internal_id_not_unique. |
price | number | Noul preț de vânzare, în moneda currency. O ofertă cu prețul 0 sau gol nu este niciodată afișată pe site. |
currency | string | Cod ISO 4217. Acceptate: MDL (implicit), EUR, USD, RON, UAH, RUB, GBP. Prețurile în altă monedă sunt convertite pentru afișare la cursul stocat de IVO. |
availability | integer | Unități aflate fizic în stoc la acest punct, care pot fi livrate imediat. |
availability_on_order | integer | Unități pe care le poți aduce la comandă (stoc de la furnizor). Menține produsul disponibil când availability este 0, cu un termen de livrare mai lung. |
Este obligatoriu cel puțin unul dintre câmpurile availability, availability_on_order, price sau currency; trimiterea doar a unui identificator eșuează cu no_fields_to_update. Câmpurile omise își păstrează valoarea curentă. Fiecare modificare este scrisă în istoricul de preț și stoc al ofertei.
{
"offer": {
"id": "<ID_OFERTĂ>",
"merchant_internal_id": "PRODUS-123",
"product_id": "<ID_PRODUS>",
"merchant_point_id": "<ID_PUNCT>",
"condition": "new",
"quality": null,
"price": 1999,
"currency": "MDL",
"availability": 5,
"availability_on_order": 0
},
"status": "success"
}
| Câmp returnat | Tip | Semnificație |
|---|---|---|
offer.id | string | ID-ul ofertei. Refolosește-l ca offer_id pentru a evita căutarea după SKU la apelurile următoare. |
offer.merchant_internal_id | string, null | SKU-ul tău, așa cum este stocat pe ofertă. |
offer.product_id | string | Produsul IVO (varianta) de care este atașată oferta. |
offer.merchant_point_id | string | Punctul în care este ținut stocul ofertei. |
offer.condition | string | new, used sau refurbished. |
offer.quality | string, null | Text liber care diferențiază mai multe oferte care nu sunt noi pentru același produs. |
offer.price, offer.currency, offer.availability, offer.availability_on_order | number / string / integer | Valorile stocate după actualizare. |
Erori: missing_identifier (422) — nu a fost trimis nici offer_id, nici merchant_internal_id; no_fields_to_update (422); offer_not_found (404) — oferta nu există sau aparține altui comerciant; merchant_internal_id_not_unique (409) — SKU-ul corespunde mai multor oferte, iar corpul conține count. Trimite merchant_point_id pentru a dezambiguiza.
Informații despre produs și ofertă
GET /product/{id}/info
Folosește ID-ul ofertei drept {id}, nu ID-ul produsului. Oferta trebuie să aparțină comerciantului autentificat.
{
"product": {
"id": "<ID_PRODUS_OFERTĂ>",
"root_product_id": "<ID_PRODUS_PRINCIPAL>",
"type": "variant",
"status": "active",
"name": {"ro": "Nume", "en": "Name", "ru": "Название"},
"slug": {"ro": "nume", "en": "name", "ru": "nazvanie"},
"url": "https://ivo.md/nume/p",
"urls": {"ro": "https://ivo.md/nume/p", "en": "https://ivo.md/en/name/p", "ru": "https://ivo.md/ru/nazvanie/p"}
},
"offer": {
"id": "<ID_OFERTĂ>",
"price": 1999,
"currency": "MDL",
"availability": 5,
"availability_on_order": 0
},
"history": [
{
"price": 2099,
"currency": "MDL",
"availability": 3,
"availability_on_order": 0,
"changed_at": "2026-08-20T11:04:35+03:00",
"source": "merchant_api"
}
],
"status": "success"
}
| Câmp returnat | Tip | Semnificație |
|---|---|---|
product.id | string | Produsul de care este atașată oferta. Pentru un produs cu variante, aceasta este varianta, nu produsul-părinte. |
product.root_product_id | string | Produsul principal (părinte). Mai multe variante îl împart, iar pagina publică îi aparține. |
product.type | string | main sau variant. |
product.status | string | Starea în catalog a produsului ofertei, de exemplu active sau draft. |
product.name | object | Denumirea din catalog pe limbi (ro, en, ru). Este scrisă de IVO, deci poate diferi de denumirea trimisă de tine. |
product.slug | object | Segmentul de URL pe fiecare limbă. |
product.url | string | URL-ul public în română — cel mai scurt link pe care îl poți da unui cumpărător. |
product.urls | object | URL-ul public pe fiecare limbă. |
offer.id, offer.price, offer.currency, offer.availability, offer.availability_on_order | — | Valorile curente ale ofertei, așa cum le stochează IVO în acest moment. |
history[] | array | Cel mult 100 de modificări de preț și stoc, cele mai recente primele. Fiecare intrare conține price, currency, availability, availability_on_order, changed_at (ISO 8601) și source — sistemul care a făcut modificarea (merchant_api, api_sync și așa mai departe). |
Erori: offer_not_found (404); product_not_accessible (403) — oferta aparține altui comerciant; product_not_found (404); pending_approval (202) — produsul principal nu este încă publicat, iar corpul conține product_id și product_status; product_slug_missing (422).
POST /product/info-by-sku
Același răspuns detaliat, găsit după SKU-ul tău în loc de un ID IVO. Folosește-l dacă nu stochezi identificatori IVO în sistemul tău.
{
"import_name": "sincronizare-zilnica",
"merchant_internal_id": "PRODUS-123"
}
| Câmp de intrare | Tip | Semnificație |
|---|---|---|
merchant_internal_id | string, obligatoriu | SKU-ul tău. Căutarea se face în rândurile importate ale contului tău. |
import_name | string, obligatoriu | Este validat ca obligatoriu, dar căutarea nu filtrează după el: un SKU este căutat în toate importurile tale. Trimite același nume folosit la /product/sync. |
În caz de succes, corpul este identic cu cel de la GET /product/{id}/info. Cât timp produsul încă parcurge fluxul de procesare, răspunsul este o structură de eroare:
| message | HTTP | Semnificație |
|---|---|---|
not_imported | 404 | Niciun rând importat nu conține acest SKU. Trimite mai întâi produsul prin /product/sync. |
queued | 202 | Rândul așteaptă să fie procesat. Reia interogarea. |
processing | 202 | Rândul este procesat chiar acum. Reia interogarea. |
pending_approval | 202 | Produsul există, dar nu este încă publicat. Nu ai nimic de făcut. |
| codul de eroare al rândului | 500 | Procesarea a eșuat. Corpul conține import_row_id, import_id, ai_product_id, ai_error și error. |
| starea ofertei din rând | 404 | Rândul s-a finalizat fără a produce o ofertă (de exemplu unauthorized_category). |
offer_deleted | 404 | Rândul indică o ofertă care nu mai există. |
Crearea sau sincronizarea unui produs
POST /product/sync
Creează un produs sau actualizează o ofertă existentă. Reutilizarea aceluiași import_name cu un merchant_internal_id stabil actualizează același rând în loc să creeze duplicate, deci endpoint-ul poate fi apelat repetat pentru același catalog.
{
"mode": "async",
"import_name": "sincronizare-zilnica",
"merchant_internal_id": "PRODUS-123",
"name": "Telefon Exemplu 256 GB Negru",
"price": 1999,
"currency": "MDL",
"availability": 5,
"availability_on_order": 0,
"merchant_point_id": "<ID_PUNCT>",
"brand": "Exemplu",
"ean": "5940000000000",
"description": "Descrierea produsului",
"images": ["https://example.com/produs.jpg"]
}
| Câmp de intrare | Tip | Semnificație |
|---|---|---|
price | number, obligatoriu | Prețul de vânzare, mai mare decât 0 (minimum 0.01). Trebuie să fie un număr simplu — 1999 sau 1999.00, nu "1 999,00". |
name | string, obligatoriu fără product_id | Denumirea completă a produsului. IVO o compară cu catalogul și creează produsul pe baza ei, deci include marca, modelul și atributele care îl disting (capacitate, culoare). O denumire prea vagă este respinsă cu eroarea de rând too_generic. |
product_id | string | ID-ul unui produs IVO existent. Ocolește complet identificarea în catalog și scrie doar oferta — calea cea mai rapidă atunci când știi deja produsul. Dacă acel produs are deja variante, trebuie să trimiți și offer_product_id. |
offer_product_id | string | Varianta produsului product_id de care se atașează oferta. Obligatorie când produsul principal are variante, pentru că IVO nu ghicește niciodată ce variantă ai pe stoc. |
merchant_internal_id | string | Identificatorul tău stabil de produs (SKU). Este cheia care leagă catalogul tău de IVO la fiecare apel ulterior. Recomandat insistent: fără el, rândurile sunt potrivite după un hash al întregii cereri. |
legacy_merchant_internal_id / legacy_merchant_internal_ids | string / array | Identificatorii sub care produsul era trimis anterior. Folosește-i când îți schimbi schema de SKU-uri, ca să fie reutilizate rândul și oferta existente în loc să se creeze un produs duplicat. |
import_name | string | Numele listei de import din care face parte produsul și cheia după care interoghezi starea. Este transformat în slug: spațiile și semnele de punctuație devin _ sau sunt eliminate, iar numele este tăiat la 64 de caractere ("Sincronizarea mea" → sincronizarea_mea). Dacă lipsește, devine default. Folosește un singur nume stabil per sursă. |
merchant_point_id / merchant_point | string | ID-ul punctului sau denumirea exactă a punctului. Dacă în cont există un singur punct, este selectat automat. |
availability | integer sau string | Stocul imediat. Textul este interpretat permisiv: "10 buc" → 10, "2-3" → 3, "in stoc"/"da" → 1, "out of stock" și orice valoare nerecunoscută → 0. Dacă nu trimiți nici availability, nici availability_on_order, stocul imediat este implicit 1. |
availability_on_order | integer sau string | Stocul disponibil la comandă, interpretat la fel. |
currency | string | Cod ISO 4217, implicit MDL. |
condition | string | new (implicit), used sau refurbished. Există o singură ofertă new per produs și punct; ofertele care nu sunt noi pot fi mai multe. |
quality | string | Text liber care diferențiază mai multe oferte care nu sunt noi pentru același produs, în același punct. |
brand | string | Denumirea mărcii. Ajută la identificare și este folosită atunci când produsul trebuie creat. |
ean, asin, jan | string | Coduri de bare și identificatori globali de produs. Cel mai puternic semnal de identificare — trimite-le când le ai. |
description | string | Descrierea produsului, folosită la identificare și, pentru un produs nou, ca material sursă. |
images (sau image) | array sau string | URL-urile imaginilor, prima fiind cea principală. IVO le descarcă; trebuie să fie accesibile public. |
weight, volume | number | Greutatea la expediere (grame) și volumul, folosite la calculul livrării. |
item_group_id, item_group_title, variant_option, variant_options | string / object | Indicii de grupare a variantelor: produsele cu același item_group_id sunt tratate ca variante ale aceluiași părinte, iar valorile opțiunilor spun ce le diferențiază (culoare, mărime). |
force_reprocess | boolean | true repornește rândul de la zero, renunțând la rezultatele anterioare de identificare. Folosește-l pentru a repara un rând potrivit greșit — nu la fiecare sincronizare, pentru că reia tot fluxul de identificare. |
mode | string | async (implicit) returnează imediat. sync ține conexiunea deschisă până se finalizează rândul, în limita stabilită pe server (implicit 300 de secunde), și returnează oricum dacă procesarea continuă. |
Orice alt câmp este stocat împreună cu rândul, dar este înțeles doar dacă denumirea lui corespunde unei coloane de import.
Răspunsuri
Toate trei sunt HTTP 200 cu "status": "success". Câmpurile prezente îți spun ce s-a întâmplat.
| Câmpuri returnate | Ce s-a întâmplat |
|---|---|
sync_status: "completed", offer_id, offer_product_id, message: "Offer saved (AI bypassed)" | Ai trimis product_id: oferta a fost scrisă direct, fără identificare și fără etapă de aprobare. |
sync_status: "completed", offer_id, offer_product_id, import_id, row_id și matched_by dacă a fost folosit un identificator vechi | A fost găsită și actualizată imediat o ofertă existentă cu acest merchant_internal_id. Acesta este răspunsul obișnuit pentru un produs deja aflat în catalog. |
sync_status: "processing", import_id, message: "Product creation started" | Un produs nou — sau redenumit semnificativ — a intrat în fluxul de import și aprobare. Interoghează /product-import/status sau /product/info-by-sku pentru rezultat. |
| Câmp returnat | Tip | Semnificație |
|---|---|---|
sync_status | string | completed — oferta există și nu a rămas nimic în așteptare. processing — produsul a fost pus la coadă și trebuie să interoghezi rezultatul. Acesta este câmpul după care ramifici logica, nu status. |
offer_id | string | Oferta creată sau actualizată. Salveaz-o: transformă actualizările ulterioare de preț și stoc într-un singur apel rapid. |
offer_product_id | string | Produsul IVO (varianta) de care atârnă oferta. |
import_id | string | Lista de import în care a fost înregistrat produsul — cea denumită de import_name. |
row_id | string | Rândul de import al acestui produs. |
matched_by | string | merchant_internal_id sau legacy_merchant_internal_id, dacă oferta a fost găsită prin unul dintre identificatorii vechi trimiși de tine. |
row_status | string | Doar în mode: sync, când timpul de așteptare a expirat: starea rândului în acel moment. |
Erori: invalid_product_id (422), product_not_found (404), offer_product_not_found (404), offer_product_invalid (422) — varianta nu aparține acelui produs principal, missing_offer_product_id (422), missing_merchant_point (422) — nu s-a putut determina niciun punct pe calea cu product_id, invalid_price (422), unauthorized_category (403) — contul tău nu este autorizat să vândă în acea categorie, integration_not_found / integration_disabled (403) — import_name denumește o integrare ștearsă sau dezactivată, și processing_failed (422) în mode: sync, cu error și import_id.
Sincronizarea mai multor produse
POST /product/sync-multiple
Între 1 și 100 de produse într-o cerere. Fiecare element din products acceptă exact câmpurile de la /product/sync, plus cele de mai jos. Acesta este endpoint-ul pe care construiești o sincronizare completă de catalog.
{
"mode": "async",
"import_name": "sincronizare-zilnica",
"image_base_url": "https://shop.example.com/images",
"products": [
{
"merchant_internal_id": "PRODUS-123",
"name": "Telefon Exemplu 256 GB Negru",
"price": 1999,
"availability_by_point": {
"<ID_PUNCT_1>": 5,
"<ID_PUNCT_2>": 2
}
}
]
}
| Câmp de lot | Tip | Semnificație |
|---|---|---|
products | array, obligatoriu | De la 1 la 100 de obiecte produs. Împarte un catalog mai mare în cereri succesive cu același import_name. |
import_name | string | Aceleași reguli ca la /product/sync și aceeași listă: cele două endpoint-uri folosesc același import când numele coincide. |
mode | string | async (implicit) sau sync. |
image_base_url | string (URL) | Prefixul adăugat înaintea căilor relative de imagine, ca un feed să poată trimite /catalog/x.jpg. Este stocat pe import și reutilizat la reîncercări. |
image_split_spaces | boolean | Tratează spațiile dintr-o valoare de imagine ca separatori între mai multe căi. |
image_split_commas | boolean | Tratează virgulele dintr-o valoare de imagine ca separatori între mai multe căi. |
integration_run_id | string, max 64 | Marchează toate rândurile unei rulări complete de catalog. Permite IVO să măsoare progresul față de totalul real al rulării, nu față de dimensiunea unui singur lot, și permite unei rulări noi să elimine stocul rămas de la configurația anterioară. |
| Câmp suplimentar per produs | Tip | Semnificație |
|---|---|---|
availability_by_point | object | Stoc pe puncte: {"<ID_PUNCT>": 5}. Trimite imaginea completă pentru acel SKU într-un singur element — ea înlocuiește instantaneul anterior. Produsul ajunge astfel pe un singur rând de import, nu pe câte unul pentru fiecare punct. |
availability_only | boolean | true transformă elementul într-o actualizare pură de stoc: sunt obligatorii doar merchant_internal_id și availability, iar name și price nu. Identificatorii necunoscuți sunt ignorați în loc să creeze produse — acesta este un flux de actualizare, nu o sursă de produse. |
force_reprocess | boolean | Ocolește calea rapidă a ofertei existente și repornește identificarea rândului. |
Răspuns: sync_status (completed dacă toate produsele erau deja actualizate, processing dacă au fost puse rânduri la coadă) și import_id, plus message atunci când a fost pusă la coadă procesare. Nu se returnează nimic pentru fiecare produs — citește rezultatele individuale din /product-import/status sau /product/info-by-sku. O cerere care nu trece validarea este respinsă în întregime cu validation_failed (422), împreună cu index-ul produsului problematic și errors; de asemenea invalid_product_payload (422) și products_required (422).
Încărcarea unui fișier de produse
POST /product-import/upload-and-import
Trimite un catalog întreg într-o singură cerere, exact ca la încărcarea din panoul de comerciant. Folosește multipart/form-data.
| Câmp de intrare | Tip | Semnificație |
|---|---|---|
file | fișier, obligatoriu | Fișierul de catalog. Extensii acceptate: XLSX, XLS, CSV, TSV, ODS, JSON și XML. |
mode | string | async (implicit) returnează imediat ce fișierul este pus la coadă. sync așteaptă finalizarea importului, implicit până la 300 de secunde. |
import_name | string | Nume opțional sub care este înregistrată încărcarea, transformat în slug ca peste tot. Trimite-l dacă vrei să interoghezi importul: GET /product-import/status îl găsește apoi după acest nume. Fără el, importul păstrează numele fișierului încărcat, iar interogarea se face după import_id (sau după exact acel nume de fișier). |
columns | array | Maparea coloanelor, câte o intrare pentru fiecare coloană a fișierului, în ordine. Folosește denumirile canonice: name, description, brand, ean, asin, jan, weight, volume, image, availability, availability_on_order, price, price_and_currency, currency, merchant_internal_id și ignore pentru coloanele de sărit. Mapează mai multe coloane la image pentru a importa mai multe imagini. Dacă columns lipsește, IVO detectează maparea din rândul de antet. |
| Câmp returnat | Tip | Semnificație |
|---|---|---|
import_id | string | Importul creat. Păstrează-l: cu el interoghezi endpoint-ul de stare. |
import_name | string | Numele sub care a fost înregistrat importul — import_name-ul tău după transformarea în slug sau numele fișierului încărcat. Interoghează exact cu această valoare. |
import_status | string | Starea reală a importului: pending, ready_to_process, processing, completed, completed_with_errors sau error. |
message | string | Import started successfully sau o notă că procesarea continuă, în mode: sync. |
import | object | Doar în mode: sync, când importul a ajuns într-o stare finală: înregistrarea completă a importului. |
Pentru sincronizarea recurentă folosește mai degrabă /product/sync-multiple: actualizează aceleași rânduri pe loc, raportează rezultatul pentru fiecare produs și nu necesită fișier.
Verificarea stării importului
GET /product-import/status
Raportează progresul oricărui import creat de tine — prin /product/sync, /product/sync-multiple sau /product-import/upload-and-import — și rezultatul pentru un produs din el.
GET /product-import/status?import_name=sincronizare-zilnica&merchant_internal_id=PRODUS-123
GET /product-import/status?import_id=<ID_IMPORT>
| Câmp de intrare | Tip | Semnificație |
|---|---|---|
import_id | string | Importul despre care se raportează, așa cum a fost returnat de orice apel de sincronizare sau de încărcare. Trimite acest câmp sau import_name; dacă lipsesc ambele, cererea eșuează cu missing_identifier (422). |
import_name | string | Numele listei de import. Este căutat atât transformat în slug (așa cum îl înregistrează sincronizarea), cât și exact așa cum a fost scris (așa cum îl înregistrează o încărcare), deci numele primit înapoi găsește întotdeauna importul. Trebuie să aparțină contului tău de comerciant. |
merchant_internal_id | string | Rândul cărui produs să fie raportat. Poate lipsi doar dacă importul conține exact un rând; la un import cu mai multe rânduri, omiterea lui eșuează cu merchant_internal_id_required (422). |
{
"import_id": "<ID_IMPORT>",
"import_name": "sincronizare_zilnica",
"import_status": "processing",
"error_type": null,
"processed_rows": 87,
"total_rows": 120,
"row_count": 120,
"row": {
"id": "<ID_RÂND>",
"row_number": 12,
"status": "completed",
"error": null,
"merchant_internal_id": "PRODUS-123",
"ai_product_id": "<ID_PRODUS_AI>",
"offer_product_id": "<ID_VARIANTĂ>",
"product_id": "<ID_PRODUS>",
"offer_id": "<ID_OFERTĂ>",
"product": {
"id": "<ID_VARIANTĂ>",
"root_product_id": "<ID_PRODUS_PRINCIPAL>",
"type": "variant",
"root_type": "main",
"status": "active",
"name": {"ro": "Nume", "en": "Name", "ru": "Название"},
"slug": {"ro": "nume", "en": "name", "ru": "nazvanie"},
"url": "https://ivo.md/nume/p",
"urls": {"ro": "https://ivo.md/nume/p"},
"has_public_url": true
},
"started_at": "2026-08-26T09:12:00+03:00",
"ended_at": "2026-08-26T09:12:41+03:00"
},
"status": "success"
}
| Câmp returnat | Tip | Semnificație |
|---|---|---|
import_id | string | Importul la care se rezolvă cererea. |
import_name | string | Numele sub care este înregistrat. |
import_status | string | Starea întregului import: pending, ready_to_process, processing, completed, completed_with_errors sau error. Aceasta este starea importului — câmpul status de nivel superior arată doar că cererea în sine a reușit. |
processed_rows / total_rows | integer | Progresul întregului import: rândurile ajunse în starea completed sau error, din totalul așteptat. Valorile egale înseamnă că importul s-a încheiat. |
row_count | integer | Câte rânduri conține importul în acest moment. |
error_type | string, null | Este setat când a eșuat importul în sine (de exemplu un fișier ilizibil), nu un rând individual. |
row.status | string | Starea produsului selectat: ready (la coadă), processing, completed sau error. Acesta este câmpul de interogat pentru un SKU. |
row.error | string, null | Motivul eșecului rândului, sub formă de cod procesabil automat — vezi codurile de rând de mai jos. |
row.merchant_internal_id | string, null | SKU-ul tău, așa cum este stocat pe rând. |
row.ai_product_id | string, null | Înregistrarea intermediară produsă în timpul construirii produsului. Utilă doar în solicitările de suport. |
row.product_id / row.offer_product_id | string, null | Produsul identificat și varianta de care se atașează oferta. |
row.offer_id | string, null | Oferta rezultată. Odată ce apare, actualizările ulterioare pot merge prin /product-offer/update. |
row.product | object, null | Informații publice despre produs: name și slug pe limbi, url și urls, starea din catalog status și has_public_url — false cât timp produsul nu are încă pagină publică. |
row.started_at / row.ended_at | datetime, null | Momentul în care a început și s-a încheiat procesarea rândului. |
status | string | Întotdeauna success — arată că cererea în sine a reușit. Starea importului este import_status. |
Erori: missing_identifier (422) — nu a fost trimis nici import_id, nici import_name, import_not_found (404), import_row_not_found (404), merchant_internal_id_required (422).
Când devine vizibilă o ofertă
Un apel reușit nu înseamnă automat un produs publicat. O ofertă apare pe ivo.md doar când toate condițiile de mai jos sunt îndeplinite:
- contul de comerciant este activ;
- punctul comercial este
approvedșiis_active; - produsul a trecut aprobarea IVO și are pagină publică;
priceexistă și este mai mare decât zero;availabilitysauavailability_on_ordereste mai mare decât zero.
Dacă un produs sincronizat nu apare, verifică aceste cinci condiții în ordine înainte de a deschide o solicitare de suport.
Coduri de eroare frecvente
| Cod | HTTP | Semnificație |
|---|---|---|
api_key_missing | 403 | Lipsesc atât headerul X-API-Key, cât și Authorization: Bearer. |
api_key_invalid | 403 | Cheie necunoscută sau revocată. |
merchant_not_found | 403 | Cheia este validă, dar contul de comerciant nu mai există. |
integration_disabled / integration_not_found | 403 | import_name denumește o integrare pe care comerciantul a dezactivat-o sau a șters-o. |
unauthorized_category | 403 | Contul tău nu este autorizat să vândă în acea categorie. |
product_not_accessible | 403 | Oferta aparține altui comerciant. |
offer_not_found, product_not_found, offer_product_not_found, point_not_found, import_not_found, import_row_not_found, not_imported, offer_deleted | 404 | Înregistrarea indicată nu există sau nu aparține contului tău. |
merchant_internal_id_not_unique | 409 | SKU-ul corespunde mai multor oferte. Adaugă merchant_point_id. |
missing_identifier, no_fields_to_update, invalid_price, invalid_product_id, missing_merchant_point, missing_offer_product_id, offer_product_invalid, merchant_internal_id_required, products_required, invalid_product_payload, validation_failed, product_slug_missing, processing_failed | 422 | Cererea este incompletă sau inconsecventă. validation_failed conține index și errors. |
queued, processing, pending_approval | 202 | Nu este o eroare: răspunsul nu este încă gata. Reia interogarea. |
Erorile la nivel de rând apar în row.error, nu ca stare HTTP: too_generic (denumirea nu identifică un produs concret), missing_name_value, missing_category, unauthorized_category, variant_not_found, duplicate, no_availability și missing_merchant_point.